2018-02-11 20:43:38 +01:00
|
|
|
// 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
|
2018-02-11 22:37:00 +01:00
|
|
|
users_room_id
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
"users", ircd::my_host()
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
2018-02-11 22:37:00 +01:00
|
|
|
/// 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.
|
|
|
|
///
|
2018-02-11 20:43:38 +01:00
|
|
|
ircd::m::room
|
2018-02-11 22:37:00 +01:00
|
|
|
ircd::m::user::users
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
users_room_id
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
2018-02-11 22:37:00 +01:00
|
|
|
/// 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.
|
|
|
|
///
|
2018-02-11 20:43:38 +01:00
|
|
|
const ircd::m::room::id::buf
|
2018-02-11 22:37:00 +01:00
|
|
|
tokens_room_id
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
"tokens", ircd::my_host()
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
ircd::m::room
|
2018-02-11 22:37:00 +01:00
|
|
|
ircd::m::user::tokens
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
tokens_room_id
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
2018-02-11 22:37:00 +01:00
|
|
|
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.
|
2018-02-11 20:43:38 +01:00
|
|
|
///
|
2018-02-11 22:37:00 +01:00
|
|
|
/// Once this call completes the registration was successful; otherwise
|
|
|
|
/// throws.
|
2018-02-11 20:43:38 +01:00
|
|
|
void
|
|
|
|
ircd::m::user::activate(const json::members &contents)
|
|
|
|
try
|
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
const auto room_id{this->room_id()};
|
|
|
|
m::room room
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
create(room_id, me.user_id, "user")
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
2018-02-11 22:37:00 +01:00
|
|
|
send(room, user_id, "ircd.account.options", "registration", contents);
|
|
|
|
send(users, me.user_id, "ircd.account", user_id,
|
|
|
|
{
|
|
|
|
{ "active", true }
|
|
|
|
});
|
2018-02-11 20:43:38 +01:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
//TODO: XXX
|
2018-02-11 20:43:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ircd::m::user::password(const string_view &password)
|
|
|
|
try
|
|
|
|
{
|
|
|
|
//TODO: ADD SALT
|
2018-02-11 22:37:00 +01:00
|
|
|
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,
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
|
|
|
{ "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
|
2018-02-11 22:37:00 +01:00
|
|
|
const sha256::buf hash
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
sha256{supplied_password}
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
2018-02-11 22:37:00 +01:00
|
|
|
char b64[64];
|
|
|
|
const auto supplied_hash
|
2018-02-11 20:43:38 +01:00
|
|
|
{
|
2018-02-11 22:37:00 +01:00
|
|
|
b64encode_unpadded(b64, hash)
|
2018-02-11 20:43:38 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
bool ret{false};
|
2018-02-11 22:37:00 +01:00
|
|
|
const auto room_id{this->room_id()};
|
|
|
|
m::room{room_id}.get("ircd.password", user_id, [&supplied_hash, &ret]
|
2018-02-11 20:43:38 +01:00
|
|
|
(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};
|
2018-02-11 22:37:00 +01:00
|
|
|
users.get(std::nothrow, "ircd.account", user_id, [&ret]
|
2018-02-11 20:43:38 +01:00
|
|
|
(const m::event &event)
|
|
|
|
{
|
|
|
|
const json::object &content
|
|
|
|
{
|
|
|
|
at<"content"_>(event)
|
|
|
|
};
|
|
|
|
|
2018-02-11 22:37:00 +01:00
|
|
|
ret = content.at("active") == "true";
|
2018-02-11 20:43:38 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2018-02-11 22:37:00 +01:00
|
|
|
|
|
|
|
/// 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()
|
|
|
|
};
|
|
|
|
}
|
2018-02-15 22:05:00 +01:00
|
|
|
|
|
|
|
ircd::string_view
|
|
|
|
ircd::m::user::gen_access_token(const mutable_buffer &buf)
|
|
|
|
{
|
|
|
|
static const size_t token_max{32};
|
|
|
|
static const auto &token_dict{rand::dict::alpha};
|
|
|
|
|
|
|
|
const mutable_buffer out
|
|
|
|
{
|
|
|
|
data(buf), std::min(token_max, size(buf))
|
|
|
|
};
|
|
|
|
|
|
|
|
return rand::string(token_dict, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
ircd::string_view
|
|
|
|
ircd::m::user::gen_password_hash(const mutable_buffer &out,
|
|
|
|
const string_view &supplied_password)
|
|
|
|
{
|
|
|
|
//TODO: ADD SALT
|
|
|
|
const sha256::buf hash
|
|
|
|
{
|
|
|
|
sha256{supplied_password}
|
|
|
|
};
|
|
|
|
|
|
|
|
return b64encode_unpadded(out, hash);
|
|
|
|
}
|
2018-02-15 22:08:10 +01:00
|
|
|
|
|
|
|
//
|
|
|
|
// user::room
|
|
|
|
//
|
|
|
|
|
|
|
|
ircd::m::user::room::room(const m::user::id &user_id)
|
|
|
|
:room{m::user{user_id}}
|
|
|
|
{}
|
|
|
|
|
|
|
|
ircd::m::user::room::room(const m::user &user)
|
|
|
|
:user{user}
|
|
|
|
,room_id{user.room_id()}
|
|
|
|
{
|
|
|
|
static_cast<m::room &>(*this) = room_id;
|
|
|
|
}
|