mirror of
https://github.com/matrix-construct/construct
synced 2025-01-13 16:33:53 +01:00
modules/client/keys/upload: Properly implement one_time_keys upload. (Fixes #9)
This commit is contained in:
parent
ab8771aae3
commit
8bce90fbf3
5 changed files with 146 additions and 83 deletions
|
@ -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=;
|
||||
};
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue