Compare commits
32 Commits
55a73624d2
...
dabc8b4304
Author | SHA1 | Date |
---|---|---|
Jason Volk | dabc8b4304 | |
Jason Volk | d80f29b65a | |
Jason Volk | 6c3420afbc | |
Jason Volk | 6072229dcc | |
Jason Volk | 956aa7682f | |
Jason Volk | 238cc10489 | |
Jason Volk | 1a032b28b7 | |
Jason Volk | f08b9e85cd | |
Jason Volk | 9ce44aadd5 | |
Jason Volk | 78d6e4ce03 | |
Jason Volk | 882629ab53 | |
Jason Volk | 8ade7c814e | |
Jason Volk | 4d5d99ab2c | |
Jason Volk | 502a03a8cf | |
Jason Volk | 1e42fa16a7 | |
Jason Volk | 0a151a3a90 | |
Jason Volk | fa46231e3a | |
Jason Volk | 336026dde6 | |
Jason Volk | d5df04a183 | |
Jason Volk | 080748f0af | |
Jason Volk | 321ea3d641 | |
Jason Volk | d41926bc6f | |
Jason Volk | 58476f59c3 | |
Jason Volk | 8dc50db2dc | |
Jason Volk | 2122412c6d | |
Jason Volk | 15cb6bfdca | |
Jason Volk | fa0365fa31 | |
Jason Volk | 02e09728a5 | |
Jason Volk | dc13381822 | |
Jason Volk | 22b9cf515c | |
Jason Volk | a10992b813 | |
Jason Volk | c77df219b5 |
|
@ -39,20 +39,7 @@ namespace ircd::json
|
|||
#include "strung.h"
|
||||
#include "tuple/tuple.h"
|
||||
#include "stack/stack.h"
|
||||
|
||||
// Convenience toolset for higher level operations.
|
||||
namespace ircd::json
|
||||
{
|
||||
strung append(const array &, const string_view &val);
|
||||
strung prepend(const array &, const string_view &val);
|
||||
|
||||
void merge(stack::object &out, const vector &);
|
||||
strung remove(const object &, const string_view &key);
|
||||
strung remove(const object &, const size_t &index);
|
||||
strung insert(const object &, const member &);
|
||||
strung replace(const object &, const member &);
|
||||
strung replace(const object &, const members &);
|
||||
}
|
||||
#include "tool.h"
|
||||
|
||||
// Exports to ircd::
|
||||
namespace ircd
|
||||
|
|
|
@ -41,6 +41,10 @@ struct ircd::json::stack::member
|
|||
member(stack &s, const string_view &name, const json::value &);
|
||||
template<class... T> member(object &po, const string_view &name, const json::tuple<T...> &t);
|
||||
template<class... T> member(stack &s, const string_view &name, const json::tuple<T...> &t);
|
||||
explicit member(object &, const json::object::member &);
|
||||
explicit member(stack &, const json::object::member &);
|
||||
explicit member(object &, const json::member &);
|
||||
explicit member(stack &, const json::member &);
|
||||
member() = default;
|
||||
member(const member &) = delete;
|
||||
member(member &&) noexcept;
|
||||
|
|
|
@ -105,28 +105,28 @@ template<>
|
|||
inline ircd::json::stack::array &
|
||||
ircd::json::stack::stack::top<ircd::json::stack::array>(stack &s)
|
||||
{
|
||||
return array::top(s);
|
||||
return array::top(s);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const ircd::json::stack::array &
|
||||
ircd::json::stack::stack::top<ircd::json::stack::array>(const stack &s)
|
||||
{
|
||||
return array::top(s);
|
||||
return array::top(s);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline ircd::json::stack::object &
|
||||
ircd::json::stack::stack::top<ircd::json::stack::object>(stack &s)
|
||||
{
|
||||
return object::top(s);
|
||||
return object::top(s);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const ircd::json::stack::object &
|
||||
ircd::json::stack::stack::top<ircd::json::stack::object>(const stack &s)
|
||||
{
|
||||
return object::top(s);
|
||||
return object::top(s);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2023 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.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_JSON_TOOL_H
|
||||
|
||||
// Convenience toolset for higher level operations.
|
||||
namespace ircd::json
|
||||
{
|
||||
strung append(const array &, const string_view &val);
|
||||
strung prepend(const array &, const string_view &val);
|
||||
|
||||
void merge(stack::object &out, const vector &);
|
||||
|
||||
strung remove(const object &, const string_view &key);
|
||||
strung remove(const object &, const size_t &index);
|
||||
|
||||
strung insert(const object &, const members &);
|
||||
strung insert(const object &, const member &);
|
||||
|
||||
strung replace(const object &, const members &);
|
||||
strung replace(const object &, const member &);
|
||||
}
|
||||
|
||||
inline ircd::json::strung
|
||||
ircd::json::replace(const object &s,
|
||||
const json::member &m)
|
||||
{
|
||||
return replace(s, json::members{m});
|
||||
}
|
||||
|
||||
inline ircd::json::strung
|
||||
ircd::json::insert(const object &s,
|
||||
const json::member &m)
|
||||
{
|
||||
return insert(s, json::members{m});
|
||||
}
|
|
@ -29,26 +29,18 @@ namespace ircd::json
|
|||
/// not use the strict overload.
|
||||
IRCD_OVERLOAD(strict)
|
||||
|
||||
// Determine the type
|
||||
enum type type(const string_view &);
|
||||
enum type type(const string_view &, std::nothrow_t);
|
||||
enum type type(const string_view &, strict_t);
|
||||
enum type type(const string_view &, strict_t, std::nothrow_t);
|
||||
|
||||
// Query if type
|
||||
bool type(const string_view &, const enum type &, strict_t);
|
||||
bool type(const string_view &, const enum type &);
|
||||
|
||||
// Utils
|
||||
string_view reflect(const enum type &);
|
||||
[[gnu::pure]] string_view reflect(const enum type) noexcept;
|
||||
|
||||
extern const string_view literal_null;
|
||||
extern const string_view literal_true;
|
||||
extern const string_view literal_false;
|
||||
extern const string_view empty_string;
|
||||
extern const string_view empty_object;
|
||||
extern const string_view empty_array;
|
||||
extern const int64_t undefined_number;
|
||||
// Determine the type w/ strict correctness (full scan)
|
||||
[[gnu::pure]] bool type(const string_view &, const enum type, strict_t) noexcept;
|
||||
[[gnu::pure]] enum type type(const string_view &, strict_t, std::nothrow_t) noexcept;
|
||||
enum type type(const string_view &, strict_t);
|
||||
|
||||
// Determine the type quickly
|
||||
[[gnu::pure]] bool type(const string_view &, const enum type) noexcept;
|
||||
[[gnu::pure]] enum type type(const string_view &, std::nothrow_t) noexcept;
|
||||
enum type type(const string_view &);
|
||||
}
|
||||
|
||||
enum ircd::json::type
|
||||
|
|
|
@ -36,7 +36,15 @@ namespace ircd::json
|
|||
void valid(const string_view &);
|
||||
std::string why(const string_view &);
|
||||
|
||||
struct stats extern stats;
|
||||
extern const string_view literal_null;
|
||||
extern const string_view literal_true;
|
||||
extern const string_view literal_false;
|
||||
extern const string_view empty_string;
|
||||
extern const string_view empty_object;
|
||||
extern const string_view empty_array;
|
||||
extern const int64_t undefined_number;
|
||||
|
||||
extern struct stats stats;
|
||||
}
|
||||
|
||||
/// Statistics counter access; unfortunately these cannot participate as
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace ircd::m
|
|||
#include "direct_to_device.h"
|
||||
#include "visible.h"
|
||||
#include "redacted.h"
|
||||
#include "replaced.h"
|
||||
#include "feds.h"
|
||||
#include "app.h"
|
||||
#include "bridge.h"
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2023 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.
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_M_REPLACED_H
|
||||
|
||||
namespace ircd::m
|
||||
{
|
||||
struct replaced;
|
||||
}
|
||||
|
||||
class ircd::m::replaced
|
||||
:public returns<event::idx>
|
||||
{
|
||||
m::relates relates;
|
||||
|
||||
public:
|
||||
IRCD_OVERLOAD(latest);
|
||||
|
||||
replaced(const event::idx &, latest_t);
|
||||
replaced(const event::idx &);
|
||||
|
||||
replaced(const event::id &, latest_t);
|
||||
replaced(const event::id &);
|
||||
|
||||
explicit replaced(const event &, latest_t);
|
||||
explicit replaced(const event &);
|
||||
};
|
||||
|
||||
inline
|
||||
ircd::m::replaced::replaced(const event &event)
|
||||
:replaced{event.event_id}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::m::replaced::replaced(const event &event,
|
||||
latest_t)
|
||||
:replaced{event.event_id, latest}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::m::replaced::replaced(const event::id &event_id)
|
||||
:replaced{index(std::nothrow, event_id)}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::m::replaced::replaced(const event::id &event_id,
|
||||
latest_t)
|
||||
:replaced{index(std::nothrow, event_id), latest}
|
||||
{}
|
||||
|
||||
inline
|
||||
ircd::m::replaced::replaced(const event::idx &event_idx)
|
||||
:relates
|
||||
{
|
||||
.refs = event_idx,
|
||||
.match_sender = true,
|
||||
}
|
||||
{
|
||||
this->returns::ret = relates.has("m.replace")? -1UL: 0UL;
|
||||
}
|
||||
|
||||
inline
|
||||
ircd::m::replaced::replaced(const event::idx &event_idx,
|
||||
latest_t)
|
||||
:relates
|
||||
{
|
||||
.refs = event_idx,
|
||||
.match_sender = true,
|
||||
}
|
||||
{
|
||||
this->returns::ret = relates.latest("m.replace");
|
||||
}
|
|
@ -31,6 +31,7 @@ namespace ircd::m
|
|||
bool exists(const id::room_alias &, const bool &remote = false);
|
||||
bool internal(const id::room &);
|
||||
bool federated(const id::room &);
|
||||
bool type(const id::room &, const string_view &);
|
||||
bool creator(const id::room &, const id::user &);
|
||||
bool contains(const id::room &, const event::idx &);
|
||||
bool membership(const room &, const id::user &, const string_view & = "join");
|
||||
|
|
|
@ -48,6 +48,9 @@ struct ircd::m::rooms::opts
|
|||
/// Room alias prefix search
|
||||
string_view room_alias;
|
||||
|
||||
/// Room type search
|
||||
string_view room_type;
|
||||
|
||||
/// user::rooms convenience
|
||||
id::user user_id;
|
||||
|
||||
|
|
|
@ -132,11 +132,11 @@ ircd::net::dns::tag::tag(const hostport &hp,
|
|||
{
|
||||
this->hp.host =
|
||||
{
|
||||
hostbuf, copy(hostbuf, hp.host)
|
||||
tolower(hostbuf, hp.host)
|
||||
};
|
||||
|
||||
this->hp.service =
|
||||
{
|
||||
servicebuf, copy(servicebuf, hp.service)
|
||||
tolower(servicebuf, hp.service)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -100,6 +100,10 @@ struct ircd::rest::opts
|
|||
/// receiving dynamic content. Supply an empty unique_buffer instance.
|
||||
unique_const_buffer *out {nullptr};
|
||||
|
||||
/// Optionally supply the temporary buffer for headers in/out in lieu of
|
||||
/// any internally allocated.
|
||||
mutable_buffer buf;
|
||||
|
||||
/// Timeout for the yielding/synchronous calls of this interface.
|
||||
seconds timeout {20s};
|
||||
|
||||
|
|
93
ircd/json.cc
93
ircd/json.cc
|
@ -604,11 +604,11 @@ ircd::json::replace(const object &s,
|
|||
{
|
||||
[](const json::members &r, const object::member &m)
|
||||
{
|
||||
return std::any_of(begin(r), end(r), [&m]
|
||||
(const json::member &r)
|
||||
{
|
||||
return string_view{r.first} == m.first;
|
||||
});
|
||||
for(const auto &[k, v] : r)
|
||||
if(string_view{k} == m.first)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -634,33 +634,9 @@ ircd::json::replace(const object &s,
|
|||
};
|
||||
}
|
||||
|
||||
ircd::json::strung
|
||||
ircd::json::replace(const object &s,
|
||||
const json::member &m_)
|
||||
{
|
||||
if(unlikely(!empty(s) && type(s) != type::OBJECT))
|
||||
throw type_error
|
||||
{
|
||||
"Cannot replace member into JSON of type %s",
|
||||
reflect(type(s))
|
||||
};
|
||||
|
||||
size_t mctr {0};
|
||||
auto &mb(member_buffer);
|
||||
for(const object::member &m : object{s})
|
||||
if(m.first != string_view{m_.first})
|
||||
mb.at(mctr++) = member{m};
|
||||
|
||||
mb.at(mctr++) = m_;
|
||||
return strung
|
||||
{
|
||||
mb.data(), mb.data() + mctr
|
||||
};
|
||||
}
|
||||
|
||||
ircd::json::strung
|
||||
ircd::json::insert(const object &s,
|
||||
const json::member &m)
|
||||
const json::members &m)
|
||||
{
|
||||
if(unlikely(!empty(s) && type(s) != type::OBJECT))
|
||||
throw type_error
|
||||
|
@ -674,7 +650,9 @@ ircd::json::insert(const object &s,
|
|||
for(const object::member &m : object{s})
|
||||
mb.at(mctr++) = member{m};
|
||||
|
||||
mb.at(mctr++) = m;
|
||||
for(const auto &_m : m)
|
||||
mb.at(mctr++) = _m;
|
||||
|
||||
return strung
|
||||
{
|
||||
mb.data(), mb.data() + mctr
|
||||
|
@ -1734,6 +1712,42 @@ ircd::json::stack::member::member(object &po,
|
|||
s->append(string_view{tmp, size_t(data(buf) - tmp)});
|
||||
}
|
||||
|
||||
ircd::json::stack::member::member(stack &s,
|
||||
const json::member &m)
|
||||
:member
|
||||
{
|
||||
stack::top<object>(s), m
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::json::stack::member::member(object &po,
|
||||
const json::member &m)
|
||||
:member
|
||||
{
|
||||
po, string_view{m.first}, m.second
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::json::stack::member::member(stack &s,
|
||||
const json::object::member &om)
|
||||
:member
|
||||
{
|
||||
stack::top<object>(s), om
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::json::stack::member::member(object &po,
|
||||
const json::object::member &om)
|
||||
:member
|
||||
{
|
||||
po, om.first, om.second
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::json::stack::member::member(stack &s,
|
||||
const string_view &name,
|
||||
const json::value &value)
|
||||
|
@ -4754,7 +4768,8 @@ namespace ircd::json::parser
|
|||
|
||||
bool
|
||||
ircd::json::type(const string_view &buf,
|
||||
const enum type &type)
|
||||
const enum type type)
|
||||
noexcept
|
||||
{
|
||||
const bool ret
|
||||
{
|
||||
|
@ -4780,6 +4795,7 @@ ircd::json::type(const string_view &buf)
|
|||
enum ircd::json::type
|
||||
ircd::json::type(const string_view &buf,
|
||||
std::nothrow_t)
|
||||
noexcept
|
||||
{
|
||||
enum type ret;
|
||||
if(!parser::parse(begin(buf), end(buf), parser::type_parse, ret))
|
||||
|
@ -4842,8 +4858,9 @@ namespace ircd::json::parser
|
|||
|
||||
bool
|
||||
ircd::json::type(const string_view &buf,
|
||||
const enum type &type,
|
||||
const enum type type,
|
||||
strict_t)
|
||||
noexcept
|
||||
{
|
||||
const bool ret
|
||||
{
|
||||
|
@ -4871,6 +4888,7 @@ enum ircd::json::type
|
|||
ircd::json::type(const string_view &buf,
|
||||
strict_t,
|
||||
std::nothrow_t)
|
||||
noexcept
|
||||
{
|
||||
enum type ret;
|
||||
if(!parser::parse(begin(buf), end(buf), parser::type_parse_strict, ret))
|
||||
|
@ -4880,7 +4898,8 @@ ircd::json::type(const string_view &buf,
|
|||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::json::reflect(const enum type &type)
|
||||
ircd::json::reflect(const enum type type)
|
||||
noexcept
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
|
@ -4891,8 +4910,6 @@ ircd::json::reflect(const enum type &type)
|
|||
case STRING: return "STRING";
|
||||
}
|
||||
|
||||
throw type_error
|
||||
{
|
||||
"Unknown type %x", uint(type)
|
||||
};
|
||||
assert(false);
|
||||
return "STRING";
|
||||
}
|
||||
|
|
40
ircd/rest.cc
40
ircd/rest.cc
|
@ -14,13 +14,25 @@ ircd::rest::request::request(const rfc3986::uri &uri,
|
|||
if(!opts.remote)
|
||||
opts.remote = net::hostport{uri};
|
||||
|
||||
const unique_mutable_buffer buf
|
||||
const bool need_alloc
|
||||
{
|
||||
empty(opts.sout.head) || empty(opts.sin.head)?
|
||||
16_KiB: 0_KiB
|
||||
empty(opts.buf)
|
||||
&& (empty(opts.sout.head) || empty(opts.sin.head))
|
||||
};
|
||||
|
||||
const unique_mutable_buffer _buf
|
||||
{
|
||||
need_alloc? 16_KiB: 0_KiB
|
||||
};
|
||||
|
||||
if(!empty(_buf))
|
||||
opts.buf = _buf;
|
||||
|
||||
window_buffer window
|
||||
{
|
||||
opts.buf
|
||||
};
|
||||
|
||||
window_buffer window{buf};
|
||||
if(empty(opts.sout.head))
|
||||
{
|
||||
assert(opts.remote);
|
||||
|
@ -80,13 +92,25 @@ ircd::rest::request::request(const mutable_buffer &out,
|
|||
if(!opts.remote)
|
||||
opts.remote = net::hostport{uri};
|
||||
|
||||
const unique_mutable_buffer buf
|
||||
const bool need_alloc
|
||||
{
|
||||
empty(opts.sout.head) || empty(opts.sin.head)?
|
||||
16_KiB: 0_KiB
|
||||
empty(opts.buf)
|
||||
&& (empty(opts.sout.head) || empty(opts.sin.head))
|
||||
};
|
||||
|
||||
const unique_mutable_buffer _buf
|
||||
{
|
||||
need_alloc? 16_KiB: 0_KiB
|
||||
};
|
||||
|
||||
if(!empty(_buf))
|
||||
opts.buf = _buf;
|
||||
|
||||
window_buffer window
|
||||
{
|
||||
opts.buf
|
||||
};
|
||||
|
||||
window_buffer window{buf};
|
||||
if(empty(opts.sout.head))
|
||||
{
|
||||
assert(opts.remote);
|
||||
|
|
15
matrix/id.cc
15
matrix/id.cc
|
@ -132,6 +132,13 @@ ircd::m::id::parser
|
|||
,"event_id version 4"
|
||||
};
|
||||
|
||||
// de-facto device id
|
||||
const rule<> device_id
|
||||
{
|
||||
device_sigil >> localpart
|
||||
,"device_id (de facto)"
|
||||
};
|
||||
|
||||
/// (Appendix 4.1) Server Name
|
||||
/// A homeserver is uniquely identified by its server name. This value
|
||||
/// is used in a number of identifiers, as described below. The server
|
||||
|
@ -159,6 +166,7 @@ ircd::m::id::parser
|
|||
(prefix >> ':' >> server_name)
|
||||
| event_id_v4
|
||||
| event_id_v3
|
||||
| device_id
|
||||
,"mxid"
|
||||
};
|
||||
|
||||
|
@ -584,7 +592,12 @@ ircd::m::id::id(const enum sigil &sigil,
|
|||
static const auto &dict{rand::dict::alnum};
|
||||
const mutable_buffer dst{tmp_buf[0], 10};
|
||||
name = rand::string(dst, dict);
|
||||
break;
|
||||
return fmt::sprintf
|
||||
{
|
||||
buf, "%c%s",
|
||||
char(sigil),
|
||||
name,
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
@ -132,8 +132,7 @@ ircd::m::module_names
|
|||
"client_keys_query",
|
||||
"client_keys_signatures_upload",
|
||||
"client_keys_device_signing_upload",
|
||||
"client_room_keys_version",
|
||||
"client_room_keys_keys",
|
||||
"client_room_keys",
|
||||
"client_presence",
|
||||
"client_groups",
|
||||
"client_joined_groups",
|
||||
|
@ -158,6 +157,7 @@ ircd::m::module_names
|
|||
"client_sync_account_data",
|
||||
"client_sync_device_lists",
|
||||
"client_sync_device_one_time_keys_count",
|
||||
"client_sync_device_unused_fallback_key_types",
|
||||
"client_sync_groups",
|
||||
"client_sync_presence",
|
||||
"client_sync_to_device",
|
||||
|
|
|
@ -892,6 +892,32 @@ ircd::m::join_rule(const room &room,
|
|||
return join_rule(buf, room) == rule;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::type(const room::id &room_id,
|
||||
const string_view &type_)
|
||||
{
|
||||
const m::room room
|
||||
{
|
||||
room_id
|
||||
};
|
||||
|
||||
const auto event_idx
|
||||
{
|
||||
room.get(std::nothrow, "m.room.create", "")
|
||||
};
|
||||
|
||||
return m::query(std::nothrow, event_idx, "content", false, [&type_]
|
||||
(const json::object &content)
|
||||
{
|
||||
const json::string &type
|
||||
{
|
||||
content.get("type")
|
||||
};
|
||||
|
||||
return type == type_;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::creator(const room::id &room_id,
|
||||
const user::id &user_id)
|
||||
|
|
|
@ -31,7 +31,7 @@ decltype(ircd::m::createroom::version_default)
|
|||
ircd::m::createroom::version_default
|
||||
{
|
||||
{ "name", "ircd.m.createroom.version_default" },
|
||||
{ "default", "5" },
|
||||
{ "default", "6" },
|
||||
};
|
||||
|
||||
decltype(ircd::m::createroom::spec_presets)
|
||||
|
|
|
@ -54,15 +54,14 @@ ircd::m::replace(room::message &msg,
|
|||
const event::idx &event_idx)
|
||||
{
|
||||
// Find the latest edit of this; otherwise stick with the original.
|
||||
const m::relates relates
|
||||
const m::replaced replaced
|
||||
{
|
||||
.refs = event_idx,
|
||||
.match_sender = true,
|
||||
event_idx, m::replaced::latest
|
||||
};
|
||||
|
||||
const event::idx replace_idx
|
||||
const event::idx &replace_idx
|
||||
{
|
||||
relates.latest("m.replace")
|
||||
replaced
|
||||
};
|
||||
|
||||
if(!replace_idx)
|
||||
|
|
|
@ -138,6 +138,10 @@ ircd::m::rooms::for_each(const opts &opts,
|
|||
if(!join_rule(room, opts.join_rule))
|
||||
return;
|
||||
|
||||
if(opts.room_type)
|
||||
if(!m::type(room_id, opts.room_type))
|
||||
return;
|
||||
|
||||
if(opts.server && opts.request_node_id && my_host(opts.server))
|
||||
if(!room::aliases(room_id).has_server(opts.server))
|
||||
return;
|
||||
|
|
|
@ -443,6 +443,7 @@ client_client_sync_groups_la_SOURCES = client/sync/groups.cc
|
|||
client_client_sync_to_device_la_SOURCES = client/sync/to_device.cc
|
||||
client_client_sync_device_lists_la_SOURCES = client/sync/device_lists.cc
|
||||
client_client_sync_device_one_time_keys_count_la_SOURCES = client/sync/device_one_time_keys_count.cc
|
||||
client_client_sync_device_unused_fallback_key_types_la_SOURCES = client/sync/device_unused_fallback_key_types.cc
|
||||
|
||||
client_module_LTLIBRARIES += \
|
||||
client/client_sync_account_data.la \
|
||||
|
@ -452,6 +453,7 @@ client_module_LTLIBRARIES += \
|
|||
client/client_sync_to_device.la \
|
||||
client/client_sync_device_lists.la \
|
||||
client/client_sync_device_one_time_keys_count.la \
|
||||
client/client_sync_device_unused_fallback_key_types.la \
|
||||
###
|
||||
|
||||
# client/sync/rooms/
|
||||
|
@ -506,12 +508,14 @@ client_module_LTLIBRARIES += \
|
|||
# client/room_keys/
|
||||
#
|
||||
|
||||
client_client_room_keys_version_la_SOURCES = client/room_keys/version.cc
|
||||
client_client_room_keys_keys_la_SOURCES = client/room_keys/keys.cc
|
||||
client_client_room_keys_la_SOURCES = \
|
||||
client/room_keys/keys.cc \
|
||||
client/room_keys/version.cc \
|
||||
client/room_keys/room_keys.cc \
|
||||
###
|
||||
|
||||
client_module_LTLIBRARIES += \
|
||||
client/client_room_keys_version.la \
|
||||
client/client_room_keys_keys.la \
|
||||
client/client_room_keys.la \
|
||||
###
|
||||
|
||||
#
|
||||
|
|
|
@ -51,6 +51,16 @@ ircd::m::client_capabilities::get(client &client,
|
|||
mods::loaded("client_account")
|
||||
};
|
||||
|
||||
const bool m_set_displayname__enabled
|
||||
{
|
||||
mods::loaded("client_profile")
|
||||
};
|
||||
|
||||
const bool m_set_avatar_url__enabled
|
||||
{
|
||||
mods::loaded("client_profile")
|
||||
};
|
||||
|
||||
const json::value default_room_version
|
||||
{
|
||||
string_view{m::createroom::version_default}, json::STRING
|
||||
|
@ -66,6 +76,14 @@ ircd::m::client_capabilities::get(client &client,
|
|||
{
|
||||
{ "enabled", m_change_password__enabled },
|
||||
}},
|
||||
{ "m.set_displayname", json::members
|
||||
{
|
||||
{ "enabled", m_set_displayname__enabled },
|
||||
}},
|
||||
{ "m.set_avatar_url", json::members
|
||||
{
|
||||
{ "enabled", m_set_avatar_url__enabled },
|
||||
}},
|
||||
{ "m.room_versions", json::members
|
||||
{
|
||||
{ "default", default_room_version },
|
||||
|
|
|
@ -274,6 +274,11 @@ _get_device(json::stack::object &obj,
|
|||
obj, "device_id", device_id
|
||||
};
|
||||
|
||||
json::stack::member
|
||||
{
|
||||
obj, "user_id", devices.user.user_id
|
||||
};
|
||||
|
||||
devices.get(std::nothrow, device_id, "display_name", [&obj]
|
||||
(const auto &, const string_view &value)
|
||||
{
|
||||
|
|
|
@ -43,34 +43,21 @@ ircd::m::resource::response
|
|||
ircd::m::post_keys_signatures_upload(client &client,
|
||||
const resource::request &request)
|
||||
{
|
||||
const m::device::id::buf device_id
|
||||
{
|
||||
m::user::tokens::device(request.access_token)
|
||||
};
|
||||
|
||||
const m::user::room user_room
|
||||
{
|
||||
request.user_id
|
||||
};
|
||||
|
||||
for(const auto &[_user_id, devices_keys_] : request)
|
||||
{
|
||||
if(!valid(m::id::USER, _user_id))
|
||||
continue;
|
||||
|
||||
if(_user_id != request.user_id)
|
||||
throw m::ACCESS_DENIED
|
||||
{
|
||||
"Uploading for user %s by %s not allowed or supported",
|
||||
_user_id,
|
||||
string_view{request.user_id},
|
||||
};
|
||||
|
||||
const m::user::id user_id
|
||||
{
|
||||
_user_id
|
||||
};
|
||||
|
||||
const m::user::room user_room
|
||||
{
|
||||
user_id
|
||||
};
|
||||
|
||||
const m::user::devices devices
|
||||
{
|
||||
user_id
|
||||
|
@ -88,22 +75,6 @@ ircd::m::post_keys_signatures_upload(client &client,
|
|||
device_keys_
|
||||
};
|
||||
|
||||
if(json::get<"device_id"_>(device_keys) != _device_id)
|
||||
throw m::BAD_REQUEST
|
||||
{
|
||||
"device_id '%s' does not match object property name '%s'",
|
||||
json::get<"device_id"_>(device_keys),
|
||||
_device_id,
|
||||
};
|
||||
|
||||
if((false) && _device_id != device_id) // is this the "cross-sign?" gotta find out!
|
||||
throw m::ACCESS_DENIED
|
||||
{
|
||||
"device_id '%s' does not match your current device_id '%s'",
|
||||
_device_id,
|
||||
string_view{device_id},
|
||||
};
|
||||
|
||||
const bool set
|
||||
{
|
||||
devices.set(_device_id, "signatures", device_keys_)
|
||||
|
|
|
@ -121,12 +121,6 @@ post__login_password(client &client,
|
|||
m::id::device::buf{m::id::generate, my_host()}
|
||||
};
|
||||
|
||||
if(!my(device_id))
|
||||
throw m::UNSUPPORTED
|
||||
{
|
||||
"Device ID's with foreign hostparts are not supported."
|
||||
};
|
||||
|
||||
char access_token_buf[32];
|
||||
const string_view access_token
|
||||
{
|
||||
|
|
|
@ -134,6 +134,7 @@ get__publicrooms(client &client,
|
|||
opts.lower_bound = true;
|
||||
opts.room_id = since;
|
||||
opts.request_user_id = request.user_id;
|
||||
opts.room_type = json::string{filter["room_type"]};
|
||||
if(m::valid(m::id::USER, search_term))
|
||||
opts.user_id = search_term;
|
||||
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#include "room_keys.h"
|
||||
|
||||
namespace ircd::m
|
||||
{
|
||||
static string_view make_state_key(const mutable_buffer &, const string_view &, const string_view &, const event::idx &);
|
||||
|
||||
static resource::response _get_room_keys_keys(client &, const resource::request &, const room::state &, const event::idx &, const string_view &, const string_view &);
|
||||
static void _get_room_keys_keys(client &, const resource::request &, const room::state &, const event::idx &, const string_view &, json::stack::object &);
|
||||
static resource::response get_room_keys_keys(client &, const resource::request &);
|
||||
|
@ -21,18 +21,14 @@ namespace ircd::m
|
|||
static resource::response put_room_keys_keys(client &, const resource::request &);
|
||||
extern resource::method room_keys_keys_put;
|
||||
|
||||
static event::id::buf delete_room_keys_key(client &, const resource::request &, const room &, const event::idx &);
|
||||
static event::id::buf delete_room_keys_key(client &, const resource::request &, const room &, const room::id &, const string_view &, const event::idx &);
|
||||
static resource::response delete_room_keys_keys(client &, const resource::request &);
|
||||
extern resource::method room_keys_keys_delete;
|
||||
|
||||
extern resource room_keys_keys;
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Client (undocumented) :e2e Room Keys Keys"
|
||||
};
|
||||
|
||||
decltype(ircd::m::room_keys_keys)
|
||||
ircd::m::room_keys_keys
|
||||
{
|
||||
|
@ -79,7 +75,7 @@ ircd::m::delete_room_keys_keys(client &client,
|
|||
|
||||
const event::idx version
|
||||
{
|
||||
request.query.at<event::idx>("version")
|
||||
request.query.get<event::idx>("version", 0)
|
||||
};
|
||||
|
||||
const m::user::room user_room
|
||||
|
@ -92,15 +88,104 @@ ircd::m::delete_room_keys_keys(client &client,
|
|||
user_room
|
||||
};
|
||||
|
||||
if(!room_id && !session_id)
|
||||
{
|
||||
state.for_each("ircd.room_keys.key", [&client, &request, &user_room, &version]
|
||||
(const string_view &, const string_view &state_key, const event::idx &event_idx)
|
||||
{
|
||||
const auto &[room_id, session_id, _version]
|
||||
{
|
||||
unmake_state_key(state_key)
|
||||
};
|
||||
|
||||
if(version && _version != lex_cast(version))
|
||||
return true;
|
||||
|
||||
delete_room_keys_key(client, request, user_room, event_idx);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
else if(!session_id)
|
||||
{
|
||||
state.for_each("ircd.room_keys.key", [&client, &request, &user_room, &version, &room_id]
|
||||
(const string_view &, const string_view &state_key, const event::idx &event_idx)
|
||||
{
|
||||
const auto &[_room_id, session_id, _version]
|
||||
{
|
||||
unmake_state_key(state_key)
|
||||
};
|
||||
|
||||
if(version && _version != lex_cast(version))
|
||||
return true;
|
||||
|
||||
if(_room_id != room_id)
|
||||
return true;
|
||||
|
||||
delete_room_keys_key(client, request, user_room, event_idx);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
else delete_room_keys_key(client, request, user_room, room_id, session_id, version);
|
||||
|
||||
const auto &[count, etag]
|
||||
{
|
||||
count_etag(state, version)
|
||||
};
|
||||
|
||||
const json::value _etag
|
||||
{
|
||||
lex_cast(etag), json::STRING
|
||||
};
|
||||
|
||||
return resource::response
|
||||
{
|
||||
client, json::members
|
||||
{
|
||||
{ "count", count },
|
||||
{ "etag", _etag },
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ircd::m::event::id::buf
|
||||
ircd::m::delete_room_keys_key(client &client,
|
||||
const resource::request &request,
|
||||
const room &user_room,
|
||||
const room::id &room_id,
|
||||
const string_view &session_id,
|
||||
const event::idx &version)
|
||||
{
|
||||
char state_key_buf[event::STATE_KEY_MAX_SIZE];
|
||||
const string_view state_key
|
||||
{
|
||||
make_state_key(state_key_buf, room_id, session_id, version)
|
||||
};
|
||||
|
||||
const room::state state
|
||||
{
|
||||
user_room
|
||||
};
|
||||
|
||||
const auto event_idx
|
||||
{
|
||||
state.get(std::nothrow, "ircd.room_keys.key", state_key)
|
||||
};
|
||||
|
||||
if(!event_idx)
|
||||
return {};
|
||||
|
||||
return delete_room_keys_key(client, request, user_room, event_idx);
|
||||
}
|
||||
|
||||
ircd::m::event::id::buf
|
||||
ircd::m::delete_room_keys_key(client &client,
|
||||
const resource::request &request,
|
||||
const room &user_room,
|
||||
const event::idx &event_idx)
|
||||
{
|
||||
const auto event_id
|
||||
{
|
||||
m::event_id(state.get("ircd.room_keys.key", state_key))
|
||||
m::event_id(event_idx)
|
||||
};
|
||||
|
||||
const auto redact_id
|
||||
|
@ -108,10 +193,7 @@ ircd::m::delete_room_keys_keys(client &client,
|
|||
m::redact(user_room, request.user_id, event_id, "deleted by client")
|
||||
};
|
||||
|
||||
return resource::response
|
||||
{
|
||||
client, http::OK
|
||||
};
|
||||
return redact_id;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -160,6 +242,16 @@ ircd::m::put_room_keys_keys(client &client,
|
|||
request.query.at<event::idx>("version")
|
||||
};
|
||||
|
||||
const m::user::room user_room
|
||||
{
|
||||
request.user_id
|
||||
};
|
||||
|
||||
const m::room::state state
|
||||
{
|
||||
user_room
|
||||
};
|
||||
|
||||
if(!room_id && !session_id)
|
||||
{
|
||||
const json::object &rooms
|
||||
|
@ -167,9 +259,16 @@ ircd::m::put_room_keys_keys(client &client,
|
|||
request["rooms"]
|
||||
};
|
||||
|
||||
for(const auto &[room_id, sessions] : rooms)
|
||||
for(const auto &[session_id, session] : json::object(sessions))
|
||||
for(const auto &[room_id, room_data] : rooms)
|
||||
{
|
||||
const json::object sessions
|
||||
{
|
||||
json::object(room_data)["sessions"]
|
||||
};
|
||||
|
||||
for(const auto &[session_id, session] : sessions)
|
||||
put_room_keys_keys_key(client, request, room_id, session_id, version, session);
|
||||
}
|
||||
}
|
||||
else if(!session_id)
|
||||
{
|
||||
|
@ -183,9 +282,23 @@ ircd::m::put_room_keys_keys(client &client,
|
|||
}
|
||||
else put_room_keys_keys_key(client, request, room_id, session_id, version, request);
|
||||
|
||||
const auto &[count, etag]
|
||||
{
|
||||
count_etag(state, version)
|
||||
};
|
||||
|
||||
const json::value _etag
|
||||
{
|
||||
lex_cast(etag), json::STRING
|
||||
};
|
||||
|
||||
return resource::response
|
||||
{
|
||||
client, http::OK
|
||||
client, json::members
|
||||
{
|
||||
{ "count", count },
|
||||
{ "etag", _etag },
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -320,12 +433,12 @@ ircd::m::get_room_keys_keys(client &client,
|
|||
state.for_each("ircd.room_keys.key", [&client, &request, &state, &version, &rooms, &last_room]
|
||||
(const string_view &, const string_view &state_key, const event::idx &)
|
||||
{
|
||||
const auto &room_id
|
||||
const auto &[room_id, _session_id, _version]
|
||||
{
|
||||
token(state_key, ":::", 0)
|
||||
unmake_state_key(state_key)
|
||||
};
|
||||
|
||||
if(!m::valid(id::ROOM, room_id))
|
||||
if(_version != lex_cast(version))
|
||||
return true;
|
||||
|
||||
if(room_id == last_room)
|
||||
|
@ -359,29 +472,28 @@ ircd::m::_get_room_keys_keys(client &client,
|
|||
state.for_each("ircd.room_keys.key", [&room_id, &version, &sessions]
|
||||
(const string_view &type, const string_view &state_key, const event::idx &event_idx)
|
||||
{
|
||||
string_view part[3]; const auto parts
|
||||
const auto &[_room_id, _session_id, _version]
|
||||
{
|
||||
tokens(state_key, ":::", part)
|
||||
unmake_state_key(state_key)
|
||||
};
|
||||
|
||||
const auto &_room_id{part[0]};
|
||||
const auto &_session_id{part[1]};
|
||||
const auto &_version{part[2]};
|
||||
if(!m::valid(id::ROOM, _room_id))
|
||||
return true;
|
||||
|
||||
if(_room_id != room_id)
|
||||
return true;
|
||||
|
||||
if(_version != lex_cast<event::idx>(version))
|
||||
if(_version != lex_cast(version))
|
||||
return true;
|
||||
|
||||
m::get(std::nothrow, event_idx, "content", [&sessions, &_session_id]
|
||||
const string_view &session_id
|
||||
{
|
||||
_session_id
|
||||
};
|
||||
|
||||
m::get(std::nothrow, event_idx, "content", [&sessions, &session_id]
|
||||
(const json::object &session)
|
||||
{
|
||||
json::stack::member
|
||||
{
|
||||
sessions, _session_id, session
|
||||
sessions, session_id, session
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -419,18 +531,3 @@ ircd::m::_get_room_keys_keys(client &client,
|
|||
|
||||
return {}; // responded from closure or thrown
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::make_state_key(const mutable_buffer &buf,
|
||||
const string_view &room_id,
|
||||
const string_view &session_id,
|
||||
const event::idx &version)
|
||||
{
|
||||
return fmt::sprintf
|
||||
{
|
||||
buf, "%s:::%s:::%u",
|
||||
room_id,
|
||||
session_id,
|
||||
version,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2023 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 "room_keys.h"
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Client :e2e Room Keys"
|
||||
};
|
||||
|
||||
std::tuple<int64_t, int64_t>
|
||||
ircd::m::count_etag(const room::state &state,
|
||||
const event::idx &version)
|
||||
{
|
||||
char version_buf[64];
|
||||
const auto version_str
|
||||
{
|
||||
lex_cast(version, version_buf)
|
||||
};
|
||||
|
||||
uint64_t count(0), etag(0);
|
||||
state.for_each("ircd.room_keys.key", [&]
|
||||
(const string_view &type, const string_view &state_key, const event::idx &event_idx)
|
||||
{
|
||||
const auto &[room_id, session_id, _version_str]
|
||||
{
|
||||
unmake_state_key(state_key)
|
||||
};
|
||||
|
||||
if(_version_str != version_str)
|
||||
return true;
|
||||
|
||||
etag += event_idx;
|
||||
count += 1;
|
||||
return true;
|
||||
});
|
||||
|
||||
return
|
||||
{
|
||||
int64_t(count),
|
||||
int64_t(etag),
|
||||
};
|
||||
}
|
||||
|
||||
std::tuple<ircd::string_view, ircd::string_view, ircd::string_view>
|
||||
ircd::m::unmake_state_key(const string_view &state_key)
|
||||
{
|
||||
assert(state_key);
|
||||
string_view part[3];
|
||||
const auto parts
|
||||
{
|
||||
tokens(state_key, ":::", part)
|
||||
};
|
||||
|
||||
assert(parts == 3);
|
||||
if(unlikely(!m::valid(id::ROOM, part[0])))
|
||||
part[0] = {};
|
||||
|
||||
if(unlikely(!lex_castable<ulong>(part[2])))
|
||||
part[2] = {};
|
||||
|
||||
return std::make_tuple
|
||||
(
|
||||
part[0], part[1], part[2]
|
||||
);
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
ircd::m::make_state_key(const mutable_buffer &buf,
|
||||
const string_view &room_id,
|
||||
const string_view &session_id,
|
||||
const event::idx &version)
|
||||
{
|
||||
assert(room_id);
|
||||
assert(m::valid(id::ROOM, room_id));
|
||||
assert(session_id);
|
||||
assert(session_id != "sessions");
|
||||
assert(version != 0);
|
||||
return fmt::sprintf
|
||||
{
|
||||
buf, "%s:::%s:::%u",
|
||||
room_id,
|
||||
session_id,
|
||||
version,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// The Construct
|
||||
//
|
||||
// Copyright (C) The Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2023 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.
|
||||
|
||||
#pragma GCC visibility push(hidden)
|
||||
namespace ircd::m
|
||||
{
|
||||
string_view make_state_key(const mutable_buffer &, const string_view &, const string_view &, const event::idx &);
|
||||
std::tuple<string_view, string_view, string_view> unmake_state_key(const string_view &);
|
||||
std::tuple<int64_t, int64_t> count_etag(const room::state &, const event::idx &version);
|
||||
}
|
||||
#pragma GCC visibility pop
|
|
@ -8,6 +8,8 @@
|
|||
// copyright notice and this permission notice is present in all copies. The
|
||||
// full license for this software is available in the LICENSE file.
|
||||
|
||||
#include "room_keys.h"
|
||||
|
||||
namespace ircd::m
|
||||
{
|
||||
static resource::response get_room_keys_version(client &, const resource::request &);
|
||||
|
@ -25,12 +27,6 @@ namespace ircd::m
|
|||
extern resource room_keys_version;
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Client (undocumented) :e2e Room Keys Version"
|
||||
};
|
||||
|
||||
decltype(ircd::m::room_keys_version)
|
||||
ircd::m::room_keys_version
|
||||
{
|
||||
|
@ -209,11 +205,6 @@ ircd::m::put_room_keys_version(client &client,
|
|||
event_idx,
|
||||
};
|
||||
|
||||
const auto event_id
|
||||
{
|
||||
m::event_id(event_idx)
|
||||
};
|
||||
|
||||
const json::string &algorithm
|
||||
{
|
||||
request["algorithm"]
|
||||
|
@ -224,13 +215,36 @@ ircd::m::put_room_keys_version(client &client,
|
|||
request["auth_data"]
|
||||
};
|
||||
|
||||
//
|
||||
// TODO: XXX
|
||||
//
|
||||
const auto event_id
|
||||
{
|
||||
m::event_id(event_idx)
|
||||
};
|
||||
|
||||
const json::member relates[]
|
||||
{
|
||||
{ "event_id", event_id },
|
||||
{ "rel_type", "m.replace" },
|
||||
};
|
||||
|
||||
const json::strung content
|
||||
{
|
||||
json::insert(request, json::members
|
||||
{
|
||||
{ "m.relates_to", relates }
|
||||
})
|
||||
};
|
||||
|
||||
const auto update_id
|
||||
{
|
||||
m::send(user_room, request.user_id, "ircd.room_keys.version", json::object
|
||||
{
|
||||
content
|
||||
})
|
||||
};
|
||||
|
||||
return resource::response
|
||||
{
|
||||
client, http::NOT_IMPLEMENTED
|
||||
client, http::OK
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -301,9 +315,36 @@ ircd::m::get_room_keys_version(client &client,
|
|||
"No version found.",
|
||||
};
|
||||
|
||||
m::get(event_idx, "content", [&client, &event_idx]
|
||||
const m::replaced latest_idx
|
||||
{
|
||||
event_idx, m::replaced::latest
|
||||
};
|
||||
|
||||
const event::idx version_idx
|
||||
{
|
||||
latest_idx?
|
||||
event::idx{latest_idx}:
|
||||
event_idx
|
||||
};
|
||||
|
||||
const m::room::state state
|
||||
{
|
||||
user_room
|
||||
};
|
||||
|
||||
m::get(version_idx, "content", [&client, &event_idx, &state]
|
||||
(const json::object &content)
|
||||
{
|
||||
const auto &[count, etag]
|
||||
{
|
||||
count_etag(state, event_idx)
|
||||
};
|
||||
|
||||
const json::value _etag
|
||||
{
|
||||
lex_cast(etag), json::STRING
|
||||
};
|
||||
|
||||
const json::value version
|
||||
{
|
||||
lex_cast(event_idx), json::STRING
|
||||
|
@ -313,9 +354,11 @@ ircd::m::get_room_keys_version(client &client,
|
|||
{
|
||||
client, json::members
|
||||
{
|
||||
{ "version", version },
|
||||
{ "algorithm", content["algorithm"] },
|
||||
{ "auth_data", content["auth_data"] },
|
||||
{ "count", count },
|
||||
{ "etag", _etag },
|
||||
{ "version", version },
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -41,6 +41,12 @@ ircd::m::sync::device_lists_linear(data &data)
|
|||
if(!startswith(json::get<"type"_>(event), "ircd.device"))
|
||||
return false;
|
||||
|
||||
if(startswith(json::get<"type"_>(event), "ircd.device.signing"))
|
||||
return false;
|
||||
|
||||
if(startswith(json::get<"type"_>(event), "ircd.device.one_time_key"))
|
||||
return false;
|
||||
|
||||
const m::user sender
|
||||
{
|
||||
m::user::id(json::get<"sender"_>(event))
|
||||
|
@ -56,7 +62,9 @@ ircd::m::sync::device_lists_linear(data &data)
|
|||
|
||||
const bool changed
|
||||
{
|
||||
mitsein.has(data.user, "join")
|
||||
false
|
||||
|| sender == data.user.user_id
|
||||
|| mitsein.has(data.user, "join")
|
||||
};
|
||||
|
||||
const bool left
|
||||
|
@ -67,6 +75,11 @@ ircd::m::sync::device_lists_linear(data &data)
|
|||
if(!changed && !left)
|
||||
return false;
|
||||
|
||||
json::stack::object device_lists
|
||||
{
|
||||
*data.out, "device_lists"
|
||||
};
|
||||
|
||||
json::stack::array array
|
||||
{
|
||||
*data.out, left? "left": "changed"
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// Matrix Construct
|
||||
//
|
||||
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
||||
// Copyright (C) 2016-2023 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::sync
|
||||
{
|
||||
static bool device_unused_fallback_key_types_polylog(data &);
|
||||
static bool device_unused_fallback_key_types_linear(data &);
|
||||
|
||||
extern item device_unused_fallback_key_types;
|
||||
}
|
||||
|
||||
ircd::mapi::header
|
||||
IRCD_MODULE
|
||||
{
|
||||
"Client Sync :Device Unused Fallback Key Types"
|
||||
};
|
||||
|
||||
decltype(ircd::m::sync::device_unused_fallback_key_types)
|
||||
ircd::m::sync::device_unused_fallback_key_types
|
||||
{
|
||||
"device_unused_fallback_key_types",
|
||||
device_unused_fallback_key_types_polylog,
|
||||
device_unused_fallback_key_types_linear
|
||||
};
|
||||
|
||||
bool
|
||||
ircd::m::sync::device_unused_fallback_key_types_linear(data &data)
|
||||
{
|
||||
if(!data.device_id)
|
||||
return false;
|
||||
|
||||
if(!data.event || !data.event->event_id)
|
||||
return false;
|
||||
|
||||
if(!startswith(json::get<"type"_>(*data.event), "ircd.device"))
|
||||
return false;
|
||||
|
||||
if(json::get<"room_id"_>(*data.event) != data.user_room)
|
||||
return false;
|
||||
|
||||
json::stack::array array
|
||||
{
|
||||
*data.out, "device_unused_fallback_key_types"
|
||||
};
|
||||
|
||||
array.append("signed_curve25519");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::sync::device_unused_fallback_key_types_polylog(data &data)
|
||||
{
|
||||
if(!data.device_id)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
|
@ -85,6 +85,7 @@ ircd::m::client_versions::versions_default
|
|||
" v1.3"
|
||||
" v1.4"
|
||||
" v1.5"
|
||||
" v1.6"
|
||||
};
|
||||
|
||||
/// Note this conf item doesn't persist to and from the database, which means
|
||||
|
@ -240,4 +241,13 @@ ircd::m::client_versions::append_unstable_features(client &client,
|
|||
bool(e2ee_forced_trusted_private)
|
||||
}
|
||||
};
|
||||
|
||||
// Supports filtering of /publicRooms by room type as per MSC3827
|
||||
json::stack::member
|
||||
{
|
||||
out, "org.matrix.msc3827.stable", json::value
|
||||
{
|
||||
true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11455,31 +11455,47 @@ console_cmd__room__count(opt &out, const string_view &line)
|
|||
bool
|
||||
console_cmd__room__events(opt &out, const string_view &line)
|
||||
{
|
||||
const params param{line, " ",
|
||||
const params param_any{line, " ",
|
||||
{
|
||||
"room_id", "depth|-limit", "order", "limit"
|
||||
}};
|
||||
|
||||
const params param_type{line, " ",
|
||||
{
|
||||
"room_id", "type", "depth|-limit", "order", "limit"
|
||||
}};
|
||||
|
||||
const bool use_type
|
||||
{
|
||||
param_type["type"] && !lex_castable<int64_t>(param_type["type"])
|
||||
};
|
||||
|
||||
// decide which argument overload to use
|
||||
const params ¶m
|
||||
{
|
||||
use_type? param_type : param_any
|
||||
};
|
||||
|
||||
const auto &room_id
|
||||
{
|
||||
m::room_id(param.at(0))
|
||||
m::room_id(param.at("room_id"))
|
||||
};
|
||||
|
||||
const int64_t depth
|
||||
{
|
||||
param.at<int64_t>(1, std::numeric_limits<int64_t>::max())
|
||||
param.at<int64_t>("depth|-limit", std::numeric_limits<int64_t>::max())
|
||||
};
|
||||
|
||||
const char order
|
||||
{
|
||||
param.at(2, "b"_sv).at(0)
|
||||
param.at("order", "b"_sv).at(0)
|
||||
};
|
||||
|
||||
ssize_t limit
|
||||
{
|
||||
depth < 0?
|
||||
std::abs(depth):
|
||||
param.at(3, ssize_t(32))
|
||||
param.at("depth|-limit", ssize_t(32))
|
||||
};
|
||||
|
||||
const m::room room
|
||||
|
@ -11493,15 +11509,21 @@ console_cmd__room__events(opt &out, const string_view &line)
|
|||
};
|
||||
|
||||
m::event::fetch event;
|
||||
for(; it && limit > 0; order == 'b'? --it : ++it, --limit)
|
||||
for(; it && limit > 0; order == 'b'? --it : ++it)
|
||||
{
|
||||
if(!seek(std::nothrow, event, it.event_idx()))
|
||||
continue;
|
||||
|
||||
if(use_type)
|
||||
if(!globular_imatch(param["type"])(json::get<"type"_>(event)))
|
||||
continue;
|
||||
|
||||
out
|
||||
<< std::left << std::setw(10) << it.event_idx() << " "
|
||||
<< pretty_oneline(event)
|
||||
<< std::endl;
|
||||
|
||||
--limit;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -13941,7 +13963,7 @@ console_cmd__user__tokens(opt &out, const string_view &line)
|
|||
{
|
||||
const params param{line, " ",
|
||||
{
|
||||
"user_id", "clear"
|
||||
"user_id"
|
||||
}};
|
||||
|
||||
const m::user user
|
||||
|
@ -13949,27 +13971,11 @@ console_cmd__user__tokens(opt &out, const string_view &line)
|
|||
param.at("user_id")
|
||||
};
|
||||
|
||||
const bool clear
|
||||
{
|
||||
param["clear"] == "clear"
|
||||
};
|
||||
|
||||
const m::user::tokens tokens
|
||||
{
|
||||
user
|
||||
};
|
||||
|
||||
if(clear)
|
||||
{
|
||||
const size_t count
|
||||
{
|
||||
tokens.del("Invalidated by administrator console.")
|
||||
};
|
||||
|
||||
out << "Invalidated " << count << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
tokens.for_each([&out]
|
||||
(const m::event::idx &event_idx, const string_view &token)
|
||||
{
|
||||
|
@ -14010,6 +14016,33 @@ console_cmd__user__tokens(opt &out, const string_view &line)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__user__tokens__clear(opt &out, const string_view &line)
|
||||
{
|
||||
const params param{line, " ",
|
||||
{
|
||||
"user_id"
|
||||
}};
|
||||
|
||||
const m::user user
|
||||
{
|
||||
param.at("user_id")
|
||||
};
|
||||
|
||||
const m::user::tokens tokens
|
||||
{
|
||||
user
|
||||
};
|
||||
|
||||
const size_t count
|
||||
{
|
||||
tokens.del("Invalidated by administrator console.")
|
||||
};
|
||||
|
||||
out << "Invalidated " << count << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__user__profile(opt &out, const string_view &line)
|
||||
{
|
||||
|
@ -14370,6 +14403,47 @@ console_cmd__user__devices(opt &out, const string_view &line)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__user__devices__delete(opt &out, const string_view &line)
|
||||
{
|
||||
const params param{line, " ",
|
||||
{
|
||||
"user_id", "device_id"
|
||||
}};
|
||||
|
||||
const m::user::id &user_id
|
||||
{
|
||||
param.at("user_id")
|
||||
};
|
||||
|
||||
const string_view &device_id
|
||||
{
|
||||
param.at("device_id", string_view{})
|
||||
};
|
||||
|
||||
const m::user::devices devices
|
||||
{
|
||||
user_id
|
||||
};
|
||||
|
||||
if(device_id)
|
||||
{
|
||||
devices.del(device_id);
|
||||
out << device_id << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
devices.for_each([&out, &devices]
|
||||
(const auto &event_idx, const string_view &device_id)
|
||||
{
|
||||
devices.del(device_id);
|
||||
out << device_id << std::endl;
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__user__devices__update(opt &out, const string_view &line)
|
||||
{
|
||||
|
@ -18195,7 +18269,7 @@ console_cmd__redact__last(opt &out, const string_view &line)
|
|||
<< redact_id
|
||||
<< " redacted "
|
||||
<< event_id
|
||||
;
|
||||
<< std::endl;
|
||||
|
||||
return --count > 0;
|
||||
|
||||
|
@ -18204,6 +18278,93 @@ console_cmd__redact__last(opt &out, const string_view &line)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
console_cmd__redact__state(opt &out, const string_view &line)
|
||||
{
|
||||
const params param{line, " ",
|
||||
{
|
||||
"room_id", "redactor", "type", "state_key"
|
||||
}};
|
||||
|
||||
const m::room::id::buf room_id
|
||||
{
|
||||
m::room_id(param.at("room_id"))
|
||||
};
|
||||
|
||||
const m::user::id redactor
|
||||
{
|
||||
param.at("redactor")
|
||||
};
|
||||
|
||||
const auto type
|
||||
{
|
||||
param["type"]
|
||||
};
|
||||
|
||||
const auto state_key
|
||||
{
|
||||
param["state_key"]
|
||||
};
|
||||
|
||||
const m::room room
|
||||
{
|
||||
room_id
|
||||
};
|
||||
|
||||
if(state_key)
|
||||
{
|
||||
const auto event_idx
|
||||
{
|
||||
room.get(type, state_key)
|
||||
};
|
||||
|
||||
const auto event_id
|
||||
{
|
||||
m::event_id(std::nothrow, event_idx)
|
||||
};
|
||||
|
||||
const auto redact_id
|
||||
{
|
||||
m::redact(room, redactor, event_id, "console")
|
||||
};
|
||||
|
||||
out
|
||||
<< redact_id
|
||||
<< " redacted "
|
||||
<< event_id
|
||||
<< std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
const m::room::state state
|
||||
{
|
||||
room
|
||||
};
|
||||
|
||||
state.for_each(type, [&out, &room, &redactor]
|
||||
(const auto &, const auto &state_key, const m::event::idx &event_idx)
|
||||
{
|
||||
const auto event_id
|
||||
{
|
||||
m::event_id(std::nothrow, event_idx)
|
||||
};
|
||||
|
||||
const auto redact_id
|
||||
{
|
||||
m::redact(room, redactor, event_id, "console")
|
||||
};
|
||||
|
||||
out
|
||||
<< redact_id
|
||||
<< " redacted "
|
||||
<< event_id
|
||||
<< std::endl;
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// well-known
|
||||
//
|
||||
|
|
|
@ -114,6 +114,7 @@ handle_get(client &client,
|
|||
opts.room_id = since;
|
||||
opts.search_term = search_term;
|
||||
opts.request_node_id = request.node_id;
|
||||
opts.room_type = json::string(filter["room_type"]);
|
||||
|
||||
size_t count{0};
|
||||
m::room::id::buf prev_batch_buf;
|
||||
|
|
|
@ -106,10 +106,27 @@ get__user_devices(client &client,
|
|||
{
|
||||
json::stack::member
|
||||
{
|
||||
response, "self_signing_keys", content
|
||||
response, "self_signing_key", content
|
||||
};
|
||||
});
|
||||
|
||||
if(my_host(request.node_id))
|
||||
{
|
||||
const auto user_event_idx
|
||||
{
|
||||
user_room.get(std::nothrow, "ircd.device.signing.user", "")
|
||||
};
|
||||
|
||||
m::get(std::nothrow, user_event_idx, "content", [&response]
|
||||
(const json::object &content)
|
||||
{
|
||||
json::stack::member
|
||||
{
|
||||
response, "user_signing_key", content
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
json::stack::array devices
|
||||
{
|
||||
response, "devices"
|
||||
|
|
|
@ -32,6 +32,11 @@ _query_user_device(client &,
|
|||
const string_view &device_id,
|
||||
json::stack::object &out);
|
||||
|
||||
static void
|
||||
_query_user_keys(client &,
|
||||
const m::resource::request &,
|
||||
json::stack &);
|
||||
|
||||
static void
|
||||
_query_self_keys(client &,
|
||||
const m::resource::request &,
|
||||
|
@ -72,6 +77,9 @@ post__user_keys_query(client &client,
|
|||
_query_device_keys(client, request, response);
|
||||
_query_master_keys(client, request, response);
|
||||
_query_self_keys(client, request, response);
|
||||
if(my_host(request.node_id))
|
||||
_query_user_keys(client, request, response);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -211,6 +219,49 @@ _query_self_keys(client &client,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
_query_user_keys(client &client,
|
||||
const m::resource::request &request,
|
||||
json::stack &out)
|
||||
{
|
||||
const json::object request_keys
|
||||
{
|
||||
request.at("device_keys")
|
||||
};
|
||||
|
||||
json::stack::object response_keys
|
||||
{
|
||||
out, "user_signing_keys"
|
||||
};
|
||||
|
||||
for(const auto &[user_id_, device_ids_] : request_keys)
|
||||
{
|
||||
const m::user::id &user_id
|
||||
{
|
||||
user_id_
|
||||
};
|
||||
|
||||
const m::user::room room
|
||||
{
|
||||
user_id
|
||||
};
|
||||
|
||||
const auto event_idx
|
||||
{
|
||||
room.get(std::nothrow, "ircd.device.signing.user", "")
|
||||
};
|
||||
|
||||
m::get(std::nothrow, event_idx, "content", [&response_keys, &user_id]
|
||||
(const json::object &content)
|
||||
{
|
||||
json::stack::member
|
||||
{
|
||||
response_keys, user_id, content
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_query_user_device(client &client,
|
||||
const m::resource::request &request,
|
||||
|
@ -226,14 +277,66 @@ _query_user_device(client &client,
|
|||
out, device_id
|
||||
};
|
||||
|
||||
devices.get(std::nothrow, device_id, "keys", [&device_id, &object]
|
||||
devices.get(std::nothrow, device_id, "keys", [&devices, &device_id, &object]
|
||||
(const auto &event_idx, const json::object &device_keys)
|
||||
{
|
||||
const auto &user_id
|
||||
{
|
||||
devices.user.user_id
|
||||
};
|
||||
|
||||
for(const auto &member : device_keys)
|
||||
if(member.first != "signatures")
|
||||
json::stack::member
|
||||
{
|
||||
object, member
|
||||
};
|
||||
|
||||
json::stack::object sigs
|
||||
{
|
||||
object, "signatures"
|
||||
};
|
||||
|
||||
json::stack::object user_sigs
|
||||
{
|
||||
sigs, user_id
|
||||
};
|
||||
|
||||
const json::object device_keys_sigs
|
||||
{
|
||||
device_keys["signatures"]
|
||||
};
|
||||
|
||||
const json::object device_keys_user_sigs
|
||||
{
|
||||
device_keys_sigs[user_id]
|
||||
};
|
||||
|
||||
for(const auto &member : device_keys_user_sigs)
|
||||
json::stack::member
|
||||
{
|
||||
object, member.first, member.second
|
||||
user_sigs, member
|
||||
};
|
||||
|
||||
devices.get(std::nothrow, device_id, "signatures", [&user_id, &user_sigs]
|
||||
(const auto &event_idx, const json::object &device_sigs)
|
||||
{
|
||||
const json::object device_sigs_sigs
|
||||
{
|
||||
device_sigs["signatures"]
|
||||
};
|
||||
|
||||
const json::object device_sigs_user_sigs
|
||||
{
|
||||
device_sigs_sigs[user_id]
|
||||
};
|
||||
|
||||
for(const auto &member : device_sigs_user_sigs)
|
||||
json::stack::member
|
||||
{
|
||||
user_sigs, member
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
devices.get(std::nothrow, device_id, "display_name", [&device_id, &object]
|
||||
|
|
Loading…
Reference in New Issue