mirror of
https://github.com/matrix-construct/construct
synced 2024-11-27 09:12:36 +01:00
190 lines
3.9 KiB
C++
190 lines
3.9 KiB
C++
// The Construct
|
|
//
|
|
// Copyright (C) The Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2020 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.
|
|
|
|
namespace ircd::m
|
|
{
|
|
static resource::response handle_key_query_get(client &, const resource::request &);
|
|
extern resource::method key_query_get;
|
|
|
|
static resource::response handle_key_query_post(client &, const resource::request &);
|
|
extern resource::method key_query_post;
|
|
|
|
extern resource key_query_resource;
|
|
}
|
|
|
|
ircd::mapi::header
|
|
IRCD_MODULE
|
|
{
|
|
"Federation 3.3.2 :Querying Keys Through Another Server"
|
|
};
|
|
|
|
decltype(ircd::m::key_query_resource)
|
|
ircd::m::key_query_resource
|
|
{
|
|
"/_matrix/key/v2/query/",
|
|
{
|
|
"federation 3.3.2",
|
|
resource::DIRECTORY,
|
|
}
|
|
};
|
|
|
|
decltype(ircd::m::key_query_post)
|
|
ircd::m::key_query_post
|
|
{
|
|
key_query_resource, "POST", handle_key_query_post
|
|
};
|
|
|
|
ircd::m::resource::response
|
|
ircd::m::handle_key_query_post(client &client,
|
|
const m::resource::request &request)
|
|
{
|
|
const json::object &server_keys_request
|
|
{
|
|
request["server_keys"]
|
|
};
|
|
|
|
resource::response::chunked response
|
|
{
|
|
client, http::OK
|
|
};
|
|
|
|
json::stack out
|
|
{
|
|
response.buf, response.flusher()
|
|
};
|
|
|
|
json::stack::object top{out};
|
|
json::stack::array server_keys_out
|
|
{
|
|
top, "server_keys"
|
|
};
|
|
|
|
for(const auto &[server_name, requests] : server_keys_request)
|
|
{
|
|
if(empty(json::object(requests)))
|
|
{
|
|
keys::cache::for_each(server_name, [&server_keys_out]
|
|
(const m::keys &keys)
|
|
{
|
|
server_keys_out.append(keys.source);
|
|
return true;
|
|
});
|
|
|
|
continue;
|
|
}
|
|
|
|
for(const auto &[key_id, criteria] : json::object(requests))
|
|
{
|
|
const time_t &minimum_valid_until_ts
|
|
{
|
|
json::object(criteria).get<time_t>("minimum_valid_until_ts", ircd::time<milliseconds>())
|
|
};
|
|
|
|
keys::cache::get(server_name, key_id, [&server_keys_out, &minimum_valid_until_ts]
|
|
(const m::keys &keys)
|
|
{
|
|
// Condition ignored to match synapse behavior.
|
|
if((false) && json::get<"valid_until_ts"_>(keys) < minimum_valid_until_ts)
|
|
return;
|
|
|
|
server_keys_out.append(keys.source);
|
|
});
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
decltype(ircd::m::key_query_get)
|
|
ircd::m::key_query_get
|
|
{
|
|
key_query_resource, "GET", handle_key_query_get
|
|
};
|
|
|
|
ircd::m::resource::response
|
|
ircd::m::handle_key_query_get(client &client,
|
|
const m::resource::request &request)
|
|
{
|
|
if(request.parv.size() < 1)
|
|
throw m::NEED_MORE_PARAMS
|
|
{
|
|
"serverName path parameter required"
|
|
};
|
|
|
|
char server_name_buf[rfc3986::DOMAIN_BUFSIZE];
|
|
const auto server_name
|
|
{
|
|
url::decode(server_name_buf, request.parv[0])
|
|
};
|
|
|
|
char key_id_buf[64];
|
|
const auto key_id
|
|
{
|
|
request.parv.size() > 1?
|
|
url::decode(key_id_buf, request.parv[1]):
|
|
string_view{}
|
|
};
|
|
|
|
const time_t minimum_valid_until_ts
|
|
{
|
|
request.query.get<time_t>("minimum_valid_until_ts", ircd::time<milliseconds>())
|
|
};
|
|
|
|
if(key_id)
|
|
{
|
|
const auto respond{[&client]
|
|
(const json::object &keys)
|
|
{
|
|
resource::response
|
|
{
|
|
client, keys
|
|
};
|
|
}};
|
|
|
|
if(!keys::cache::get(server_name, key_id, respond))
|
|
throw m::NOT_FOUND
|
|
{
|
|
"Key '%s' from server '%s' is not cached by this server",
|
|
key_id,
|
|
server_name,
|
|
};
|
|
|
|
return {}; // responded from closure
|
|
}
|
|
|
|
resource::response::chunked response
|
|
{
|
|
client, http::OK
|
|
};
|
|
|
|
json::stack out
|
|
{
|
|
response.buf, response.flusher()
|
|
};
|
|
|
|
json::stack::object top{out};
|
|
json::stack::array server_keys
|
|
{
|
|
top, "server_keys"
|
|
};
|
|
|
|
keys::cache::for_each(server_name, [&server_keys, &minimum_valid_until_ts]
|
|
(const m::keys &keys)
|
|
{
|
|
// Condition ignored to match synapse behavior.
|
|
if((false) && json::get<"valid_until_ts"_>(keys) < minimum_valid_until_ts)
|
|
return true;
|
|
|
|
server_keys.append(keys.source);
|
|
return true;
|
|
});
|
|
|
|
return {};
|
|
}
|