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:
parent
085776655c
commit
830a4b92a1
5 changed files with 127 additions and 87 deletions
30
ircd/m/m.cc
30
ircd/m/m.cc
|
@ -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)
|
||||
{
|
||||
|
|
165
ircd/m/user.cc
165
ircd/m/user.cc
|
@ -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()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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)};
|
||||
})
|
||||
};
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue