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..."
|
"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)
|
||||||
{
|
{
|
||||||
|
|
165
ircd/m/user.cc
165
ircd/m/user.cc
|
@ -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()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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)};
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -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" },
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue