0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-02 10:08:56 +02:00

modules/client/keys/upload: Properly implement one_time_keys upload. (Fixes #9)

This commit is contained in:
Jason Volk 2019-08-08 22:44:54 -07:00
parent ab8771aae3
commit 8bce90fbf3
5 changed files with 146 additions and 83 deletions

View file

@ -120,9 +120,11 @@ struct ircd::m::device
using closure = std::function<void (const string_view &)>;
using closure_bool = std::function<bool (const string_view &)>;
// util
static bool access_token_to_id(const string_view &token, const closure &); //nothrow
static id::buf access_token_to_id(const string_view &token);
// primary interface
static bool for_each(const user &, const closure_bool &); // each device_id
static bool for_each(const user &, const string_view &id, const closure_bool &); // each property
static bool get(std::nothrow_t, const user &, const string_view &id, const string_view &prop, const closure &);
@ -133,6 +135,9 @@ struct ircd::m::device
static bool set(const user &, const string_view &id, const string_view &prop, const string_view &val);
static bool set(const user &, const device &);
// composite interface
static std::map<std::string, long> count_one_time_keys(const user &, const string_view &);
using super_type::tuple;
using super_type::operator=;
};

View file

@ -281,7 +281,7 @@ ircd::m::module_names
"client_keys_changes",
"client_keys_claim",
"client_keys_query",
//"client_keys_upload",
"client_keys_upload",
"client_login",
"client_logout",
"client_notifications",

View file

@ -16,6 +16,12 @@ upload_device_keys(client &,
const m::device::id &,
const m::device_keys &);
static void
upload_one_time_keys(client &,
const resource::request &,
const m::device::id &,
const json::object &);
static resource::response
post__keys_upload(client &client,
const resource::request &request);
@ -91,72 +97,81 @@ post__keys_upload(client &client,
request["one_time_keys"]
};
if(request["one_time_keys"] && size(one_time_keys))
m::device::set(request.user_id, device_id, "one_time_keys", one_time_keys);
size_t buf_est(64);
std::map<string_view, long, std::less<>> counts;
for(const auto &[ident_, object] : one_time_keys)
{
const auto &[algorithm, ident]
{
split(ident_, ':')
};
if(empty(algorithm) || empty(ident))
continue;
const json::string &key
{
json::object(object).get("key")
};
const json::object &signatures
{
json::object(object).get("signatures")
};
auto it(counts.lower_bound(algorithm));
if(it == end(counts) || it->first != algorithm)
{
it = counts.emplace_hint(it, algorithm, 0L);
buf_est += size(algorithm) + 32;
}
auto &count(it->second);
++count;
}
if(!empty(one_time_keys))
upload_one_time_keys(client, request, device_id, one_time_keys);
const unique_buffer<mutable_buffer> buf
{
buf_est * 2
32_KiB
};
json::stack out{buf};
json::stack::object top{out};
json::stack::object one_time_key_counts
{
json::stack::object top{out};
json::stack::object one_time_key_counts
top, "one_time_key_counts"
};
const auto counts
{
m::device::count_one_time_keys(request.user_id, device_id)
};
for(const auto &[algorithm, count] : counts)
json::stack::member
{
top, "one_time_key_counts"
one_time_key_counts, algorithm, json::value{count}
};
for(const auto &[algorithm, count] : counts)
{
json::stack::member
{
one_time_key_counts, algorithm, json::value{count}
};
}
}
// Prevents an infinite loop due to a race in riot
sleep(seconds(5));
one_time_key_counts.~object();
top.~object();
return resource::response
{
client, json::object(out.completed())
client, json::object
{
out.completed()
}
};
}
void
upload_one_time_keys(client &client,
const resource::request &request,
const m::device::id &device_id,
const json::object &one_time_keys)
{
for(const auto &[ident, object] : one_time_keys)
{
const auto &[algorithm, name]
{
split(ident, ':')
};
if(empty(algorithm) || empty(name))
continue;
char state_key_buf[128]
{
"one_time_key|"
};
const string_view state_key
{
strlcat(state_key_buf, ident)
};
m::device::set(request.user_id, device_id, state_key, object);
log::debug
{
m::log, "Received one_time_key:%s for %s on %s",
ident,
string_view{device_id},
string_view{request.user_id},
};
}
}
void
upload_device_keys(client &client,
const resource::request &request,

View file

@ -14,8 +14,15 @@ IRCD_MODULE
"Client Sync :Device One Time Keys Count"
};
namespace ircd::m
{
std::map<std::string, long>
count_one_time_keys(const m::user::id &, const m::device::id &);
}
namespace ircd::m::sync
{
static bool _device_one_time_keys_count(data &);
static bool device_one_time_keys_count_polylog(data &);
static bool device_one_time_keys_count_linear(data &);
@ -36,7 +43,24 @@ ircd::m::sync::device_one_time_keys_count_linear(data &data)
if(!data.device_id)
return false;
return device_one_time_keys_count_polylog(data);
if(!data.event || !data.event->event_id)
return false;
if(!startswith(json::get<"type"_>(*data.event), "ircd.device.one_time_key"))
return false;
if(json::get<"state_key"_>(*data.event) != data.device_id)
return false;
if(json::get<"room_id"_>(*data.event) != data.user_room);
return false;
const json::object &one_time_keys
{
json::get<"content"_>(*data.event)
};
return _device_one_time_keys_count(data);
}
bool
@ -45,42 +69,22 @@ ircd::m::sync::device_one_time_keys_count_polylog(data &data)
if(!data.device_id)
return false;
const auto event_idx
{
data.user_room.get(std::nothrow, "ircd.device_one_time_keys", data.device_id)
};
if(!apropos(data, event_idx))
return false;
std::map<string_view, long, std::less<>> counts;
m::device::get(data.user, data.device_id, "one_time_keys", [&counts]
(const string_view &one_time_keys)
{
if(json::type(one_time_keys) != json::OBJECT)
return;
for(const auto &[ident_, object] : json::object(one_time_keys))
{
const auto &[algorithm, ident]
{
split(ident_, ':')
};
auto it(counts.lower_bound(algorithm));
if(it == end(counts) || it->first != algorithm)
it = counts.emplace_hint(it, algorithm, 0L);
auto &count(it->second);
++count;
}
});
return _device_one_time_keys_count(data);
}
bool
ircd::m::sync::_device_one_time_keys_count(data &data)
{
json::stack::object one_time_keys_count
{
*data.out, "device_one_time_keys_count"
};
const auto counts
{
m::device::count_one_time_keys(data.user, data.device_id)
};
for(const auto &[algorithm, count] : counts)
json::stack::member
{

View file

@ -20,6 +20,45 @@ IRCD_MODULE
"Matrix device library; modular components."
};
std::map<std::string, long>
IRCD_MODULE_EXPORT
ircd::m::device::count_one_time_keys(const user &user,
const string_view &device_id)
{
std::map<std::string, long> ret;
for_each(user, device_id, [&ret]
(const string_view &type)
{
if(!startswith(type, "one_time_key|"))
return true;
const auto &[prefix, ident]
{
split(type, '|')
};
const auto &[algorithm, name]
{
split(ident, ':')
};
assert(prefix == "one_time_key");
assert(!empty(algorithm));
assert(!empty(ident));
assert(!empty(name));
auto it(ret.lower_bound(algorithm));
if(it == end(ret) || it->first != algorithm)
it = ret.emplace_hint(it, algorithm, 0L);
auto &count(it->second);
++count;
return true;
});
return ret;
}
bool
IRCD_MODULE_EXPORT
ircd::m::device::set(const m::user &user,