0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-12 19:49:19 +02:00
construct/ircd/m/user.cc

203 lines
4.1 KiB
C++

// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#include <ircd/m/m.h>
const ircd::m::room::id::buf
users_room_id
{
"users", ircd::my_host()
};
/// 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.
///
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
{
const auto room_id{this->room_id()};
m::room room
{
create(room_id, me.user_id, "user")
};
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)
{
throw m::error
{
http::CONFLICT, "M_USER_IN_USE", "The desired user ID is already in use."
};
}
void
ircd::m::user::deactivate(const json::members &contents)
{
//TODO: XXX
}
void
ircd::m::user::password(const string_view &password)
try
{
//TODO: ADD SALT
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 }
});
}
catch(const m::ALREADY_MEMBER &e)
{
throw m::error
{
http::CONFLICT, "M_USER_IN_USE", "The desired user ID is already in use."
};
}
bool
ircd::m::user::is_password(const string_view &supplied_password)
const
{
//TODO: ADD SALT
const sha256::buf hash
{
sha256{supplied_password}
};
char b64[64];
const auto supplied_hash
{
b64encode_unpadded(b64, hash)
};
bool ret{false};
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
{
json::at<"content"_>(event)
};
const auto &correct_hash
{
unquote(content.at("sha256"))
};
ret = supplied_hash == correct_hash;
});
return ret;
}
bool
ircd::m::user::is_active()
const
{
bool ret{false};
users.get(std::nothrow, "ircd.account", user_id, [&ret]
(const m::event &event)
{
const json::object &content
{
at<"content"_>(event)
};
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()
};
}