0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 18:22:50 +01:00

ircd:Ⓜ️ Add preliminary !@user:host "user's room" to database all things user.

This commit is contained in:
Jason Volk 2018-02-11 13:37:00 -08:00
parent 085776655c
commit 830a4b92a1
5 changed files with 127 additions and 87 deletions

View file

@ -199,29 +199,36 @@ ircd::m::init::bootstrap()
"database is empty. I will be bootstrapping it with initial events now..." "database is empty. I will be bootstrapping it with initial events now..."
); );
create(user::users, me.user_id);
me.activate();
create(my_room, me.user_id); create(my_room, me.user_id);
send(my_room, me.user_id, "m.room.name", "", send(my_room, me.user_id, "m.room.name", "",
{ {
{ "name", "IRCd's Room" } { "name", "IRCd's Room" }
}); });
send(my_room, me.user_id, "m.room.topic", "",
{
{ "topic", "The daemon's den." }
});
create(control, me.user_id); create(control, me.user_id);
join(control, me.user_id);
send(control, me.user_id, "m.room.name", "", send(control, me.user_id, "m.room.name", "",
{ {
{ "name", "Control Room" } { "name", "Control Room" }
}); });
create(user::accounts, me.user_id); send(user::users, me.user_id, "m.room.name", "",
join(user::accounts, me.user_id);
send(user::accounts, me.user_id, "m.room.name", "",
{ {
{ "name", "User Accounts" } { "name", "Users" }
}); });
create(user::sessions, me.user_id); create(user::tokens, me.user_id);
send(user::sessions, me.user_id, "m.room.name", "", send(user::tokens, me.user_id, "m.room.name", "",
{ {
{ "name", "User Sessions" } { "name", "User Tokens" }
}); });
create(filter::filters, me.user_id); create(filter::filters, me.user_id);
@ -253,15 +260,6 @@ ircd::m::join_ircd_room()
try try
{ {
join(my_room, me.user_id); join(my_room, me.user_id);
my_room.get([](const auto &event)
{
std::cout << "mr G: " << event << std::endl;
});
my_room.prev([](const auto &event)
{
std::cout << "mr P: " << event << std::endl;
});
} }
catch(const m::ALREADY_MEMBER &e) catch(const m::ALREADY_MEMBER &e)
{ {

View file

@ -11,51 +11,68 @@
#include <ircd/m/m.h> #include <ircd/m/m.h>
const ircd::m::room::id::buf const ircd::m::room::id::buf
accounts_room_id users_room_id
{ {
"accounts", ircd::my_host() "users", ircd::my_host()
}; };
ircd::m::room /// The users room is the database of all users. It primarily serves as an
ircd::m::user::accounts /// indexing mechanism and for top-level user related keys. Accounts
{ /// registered on this server will be among state events in this room.
accounts_room_id /// Users do not have access to this room, it is used internally.
};
const ircd::m::room::id::buf
sessions_room_id
{
"sessions", ircd::my_host()
};
ircd::m::room
ircd::m::user::sessions
{
sessions_room_id
};
/// Register the user by joining them to the accounts room.
/// ///
/// The content of the join event may store keys including the registration ircd::m::room
/// options. Once this call completes the join was successful and the user is ircd::m::user::users
/// registered, otherwise throws. {
users_room_id
};
/// The tokens room serves as a key-value lookup for various tokens to
/// users, etc. It primarily serves to store access tokens for users. This
/// is a separate room from the users room because in the future it may
/// have an optimized configuration as well as being more easily cleared.
///
const ircd::m::room::id::buf
tokens_room_id
{
"tokens", ircd::my_host()
};
ircd::m::room
ircd::m::user::tokens
{
tokens_room_id
};
bool
ircd::m::exists(const user::id &user_id)
{
return user::users.has("ircd.account", user_id);
}
/// Register the user by creating a room !@user:myhost and then setting a
/// an `ircd.account` state event in the `users` room.
///
/// Each of the registration options becomes a key'ed state event in the
/// user's room.
///
/// Once this call completes the registration was successful; otherwise
/// throws.
void void
ircd::m::user::activate(const json::members &contents) ircd::m::user::activate(const json::members &contents)
try try
{ {
json::iov content; const auto room_id{this->room_id()};
json::iov::push push[] m::room room
{ {
{ content, { "membership", "join" }}, create(room_id, me.user_id, "user")
}; };
size_t i(0); send(room, user_id, "ircd.account.options", "registration", contents);
json::iov::push _content[contents.size()]; send(users, me.user_id, "ircd.account", user_id,
for(const auto &member : contents) {
new (_content + i++) json::iov::push(content, member); { "active", true }
});
send(accounts, me.user_id, "ircd.user", user_id, content);
join(control, user_id);
} }
catch(const m::ALREADY_MEMBER &e) catch(const m::ALREADY_MEMBER &e)
{ {
@ -68,18 +85,7 @@ catch(const m::ALREADY_MEMBER &e)
void void
ircd::m::user::deactivate(const json::members &contents) ircd::m::user::deactivate(const json::members &contents)
{ {
json::iov content; //TODO: XXX
json::iov::push push[]
{
{ content, { "membership", "leave" }},
};
size_t i(0);
json::iov::push _content[contents.size()];
for(const auto &member : contents)
new (_content + i++) json::iov::push(content, member);
send(accounts, me.user_id, "ircd.user", user_id, content);
} }
void void
@ -87,10 +93,19 @@ ircd::m::user::password(const string_view &password)
try try
{ {
//TODO: ADD SALT //TODO: ADD SALT
char b64[64], hash[32]; const sha256::buf hash
sha256{hash, password}; {
const auto digest{b64encode_unpadded(b64, hash)}; sha256{password}
send(accounts, me.user_id, "ircd.password", user_id, };
char b64[64];
const auto digest
{
b64encode_unpadded(b64, hash)
};
const auto room_id{this->room_id()};
send(room_id, user_id, "ircd.password", user_id,
{ {
{ "sha256", digest } { "sha256", digest }
}); });
@ -108,22 +123,20 @@ ircd::m::user::is_password(const string_view &supplied_password)
const const
{ {
//TODO: ADD SALT //TODO: ADD SALT
char b64[64], hash[32]; const sha256::buf hash
sha256{hash, supplied_password}; {
sha256{supplied_password}
};
char b64[64];
const auto supplied_hash const auto supplied_hash
{ {
b64encode_unpadded(b64, hash) b64encode_unpadded(b64, hash)
}; };
static const string_view type{"ircd.password"};
const string_view &state_key{user_id};
const room room
{
accounts.room_id
};
bool ret{false}; bool ret{false};
room::state{room}.get(type, state_key, [&supplied_hash, &ret] const auto room_id{this->room_id()};
m::room{room_id}.get("ircd.password", user_id, [&supplied_hash, &ret]
(const m::event &event) (const m::event &event)
{ {
const json::object &content const json::object &content
@ -147,7 +160,7 @@ ircd::m::user::is_active()
const const
{ {
bool ret{false}; bool ret{false};
room::state{accounts}.get("ircd.user", user_id, [&ret] users.get(std::nothrow, "ircd.account", user_id, [&ret]
(const m::event &event) (const m::event &event)
{ {
const json::object &content const json::object &content
@ -155,8 +168,36 @@ const
at<"content"_>(event) at<"content"_>(event)
}; };
ret = unquote(content.at("membership")) == "join"; ret = content.at("active") == "true";
}); });
return ret; return ret;
} }
/// Generates a user-room ID into buffer; see room_id() overload.
ircd::m::id::room::buf
ircd::m::user::room_id()
const
{
assert(!empty(user_id));
return
{
user_id.local(), my_host()
};
}
/// Generates a room MXID of the following form: `!@user:host`
///
/// This is the "user's room" essentially serving as a database mechanism for
/// this specific user. This is for users on this server's host only.
///
ircd::m::id::room
ircd::m::user::room_id(const mutable_buffer &buf)
const
{
assert(!empty(user_id));
return
{
buf, user_id.local(), my_host()
};
}

View file

@ -148,10 +148,10 @@ try
const bool result const bool result
{ {
request.access_token && request.access_token &&
m::user::sessions.get(std::nothrow, "ircd.access_token"_sv, request.access_token, [&] m::user::tokens.get(std::nothrow, "ircd.access_token"_sv, request.access_token, [&request]
(const m::event &event) (const m::event &event)
{ {
// The user sent this access token to the sessions room. // The user sent this access token to the tokens room
request.user_id = m::user::id{at<"sender"_>(event)}; request.user_id = m::user::id{at<"sender"_>(event)};
}) })
}; };

View file

@ -82,10 +82,10 @@ post_login_password(client &client,
rand::string(token_dict, token_len, token_buf, sizeof(token_buf)) rand::string(token_dict, token_len, token_buf, sizeof(token_buf))
}; };
// Log the user in by issuing an event in the sessions room containing // Log the user in by issuing an event in the tokens room containing
// the generated token. When this call completes without throwing the // the generated token. When this call completes without throwing the
// access_token will be committed and the user will be logged in. // access_token will be committed and the user will be logged in.
m::send(m::user::sessions, user_id, "ircd.access_token", access_token, m::send(m::user::tokens, user_id, "ircd.access_token", access_token,
{ {
{ "ip", string(remote(client)) }, { "ip", string(remote(client)) },
{ "device", "unknown" }, { "device", "unknown" },

View file

@ -97,17 +97,18 @@ try
user_id user_id
}; };
// Activate the account. Underneath this will join the user to the room // Activate the account. Underneath this will create a special room
// !accounts:your.domain. If the user_id is already a member then this // for this user in the form of !@user:host and set a key in !users:host
// throws 409 Conflict; otherwise the user is registered after this call. // If the user_id is taken this throws 409 Conflict because those assets
// will already exist; otherwise the user is registered after this call.
user.activate( user.activate(
{ {
{ "bind_email", bind_email }, { "bind_email", bind_email },
}); });
// Set the password for the account. This issues an ircd.password state // Set the password for the account. This issues an ircd.password state
// event to the accounts room for the user. If this call completes the // event to the user's room. User will be able to login with
// user will be able to login with m.login.password // m.login.password
user.password(password); user.password(password);
// Send response to user // Send response to user