0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-27 07:54:05 +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..."
);
create(user::users, me.user_id);
me.activate();
create(my_room, me.user_id);
send(my_room, me.user_id, "m.room.name", "",
{
{ "name", "IRCd's Room" }
});
send(my_room, me.user_id, "m.room.topic", "",
{
{ "topic", "The daemon's den." }
});
create(control, me.user_id);
join(control, me.user_id);
send(control, me.user_id, "m.room.name", "",
{
{ "name", "Control Room" }
});
create(user::accounts, me.user_id);
join(user::accounts, me.user_id);
send(user::accounts, me.user_id, "m.room.name", "",
send(user::users, me.user_id, "m.room.name", "",
{
{ "name", "User Accounts" }
{ "name", "Users" }
});
create(user::sessions, me.user_id);
send(user::sessions, me.user_id, "m.room.name", "",
create(user::tokens, me.user_id);
send(user::tokens, me.user_id, "m.room.name", "",
{
{ "name", "User Sessions" }
{ "name", "User Tokens" }
});
create(filter::filters, me.user_id);
@ -253,15 +260,6 @@ ircd::m::join_ircd_room()
try
{
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)
{

View file

@ -11,51 +11,68 @@
#include <ircd/m/m.h>
const ircd::m::room::id::buf
accounts_room_id
users_room_id
{
"accounts", ircd::my_host()
"users", ircd::my_host()
};
ircd::m::room
ircd::m::user::accounts
{
accounts_room_id
};
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 users room is the database of all users. It primarily serves as an
/// indexing mechanism and for top-level user related keys. Accounts
/// registered on this server will be among state events in this room.
/// Users do not have access to this room, it is used internally.
///
/// The content of the join event may store keys including the registration
/// options. Once this call completes the join was successful and the user is
/// registered, otherwise throws.
ircd::m::room
ircd::m::user::users
{
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
ircd::m::user::activate(const json::members &contents)
try
{
json::iov content;
json::iov::push push[]
const auto room_id{this->room_id()};
m::room room
{
{ content, { "membership", "join" }},
create(room_id, me.user_id, "user")
};
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);
join(control, user_id);
send(room, user_id, "ircd.account.options", "registration", contents);
send(users, me.user_id, "ircd.account", user_id,
{
{ "active", true }
});
}
catch(const m::ALREADY_MEMBER &e)
{
@ -68,18 +85,7 @@ catch(const m::ALREADY_MEMBER &e)
void
ircd::m::user::deactivate(const json::members &contents)
{
json::iov content;
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);
//TODO: XXX
}
void
@ -87,10 +93,19 @@ ircd::m::user::password(const string_view &password)
try
{
//TODO: ADD SALT
char b64[64], hash[32];
sha256{hash, password};
const auto digest{b64encode_unpadded(b64, hash)};
send(accounts, me.user_id, "ircd.password", user_id,
const sha256::buf hash
{
sha256{password}
};
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 }
});
@ -108,22 +123,20 @@ ircd::m::user::is_password(const string_view &supplied_password)
const
{
//TODO: ADD SALT
char b64[64], hash[32];
sha256{hash, supplied_password};
const sha256::buf hash
{
sha256{supplied_password}
};
char b64[64];
const auto supplied_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};
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 json::object &content
@ -147,7 +160,7 @@ ircd::m::user::is_active()
const
{
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 json::object &content
@ -155,8 +168,36 @@ const
at<"content"_>(event)
};
ret = unquote(content.at("membership")) == "join";
ret = content.at("active") == "true";
});
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
{
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)
{
// 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)};
})
};

View file

@ -82,10 +82,10 @@ post_login_password(client &client,
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
// 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)) },
{ "device", "unknown" },

View file

@ -97,17 +97,18 @@ try
user_id
};
// Activate the account. Underneath this will join the user to the room
// !accounts:your.domain. If the user_id is already a member then this
// throws 409 Conflict; otherwise the user is registered after this call.
// Activate the account. Underneath this will create a special room
// for this user in the form of !@user:host and set a key in !users:host
// 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(
{
{ "bind_email", bind_email },
});
// 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
// user will be able to login with m.login.password
// event to the user's room. User will be able to login with
// m.login.password
user.password(password);
// Send response to user