mirror of
https://github.com/matrix-construct/construct
synced 2024-11-30 02:32:43 +01:00
199 lines
4.3 KiB
C++
199 lines
4.3 KiB
C++
|
/*
|
||
|
* Copyright (C) 2016 Charybdis Development Team
|
||
|
* Copyright (C) 2016 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.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#include <ircd/m/m.h>
|
||
|
|
||
|
//
|
||
|
// request
|
||
|
//
|
||
|
|
||
|
ircd::string_view
|
||
|
ircd::m::request::operator()(const mutable_buffer &out,
|
||
|
const vector_view<const http::header> &addl_headers)
|
||
|
const
|
||
|
{
|
||
|
const size_t addl_headers_size
|
||
|
{
|
||
|
std::min(addl_headers.size(), size_t(64UL))
|
||
|
};
|
||
|
|
||
|
size_t headers{1};
|
||
|
http::header header[headers + addl_headers_size]
|
||
|
{
|
||
|
{ "User-Agent", BRANDING_NAME " (IRCd " BRANDING_VERSION ")" },
|
||
|
};
|
||
|
|
||
|
for(size_t i(0); i < addl_headers_size; ++i)
|
||
|
header[headers++] = addl_headers.at(i);
|
||
|
|
||
|
thread_local char x_matrix[1_KiB];
|
||
|
if(startswith(at<"uri"_>(*this), "/_matrix/federation"))
|
||
|
{
|
||
|
const auto &sk{self::secret_key};
|
||
|
const auto &pkid{self::public_key_id};
|
||
|
header[headers++] =
|
||
|
{
|
||
|
"Authorization", generate(x_matrix, sk, pkid)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
static const string_view content_type
|
||
|
{
|
||
|
"application/json; charset=utf-8"_sv
|
||
|
};
|
||
|
|
||
|
const auto content_length
|
||
|
{
|
||
|
string_view(json::get<"content"_>(*this)).size()
|
||
|
};
|
||
|
|
||
|
stream_buffer sb{out};
|
||
|
http::request
|
||
|
{
|
||
|
sb,
|
||
|
at<"destination"_>(*this),
|
||
|
at<"method"_>(*this),
|
||
|
at<"uri"_>(*this),
|
||
|
content_length,
|
||
|
content_type,
|
||
|
{ header, headers }
|
||
|
};
|
||
|
|
||
|
return sb.completed();
|
||
|
}
|
||
|
|
||
|
ircd::string_view
|
||
|
ircd::m::request::generate(const mutable_buffer &out,
|
||
|
const ed25519::sk &sk,
|
||
|
const string_view &pkid)
|
||
|
const
|
||
|
{
|
||
|
const json::strung object
|
||
|
{
|
||
|
*this,
|
||
|
};
|
||
|
|
||
|
const ed25519::sig sig
|
||
|
{
|
||
|
self::secret_key.sign(const_buffer{object})
|
||
|
};
|
||
|
|
||
|
const auto &origin
|
||
|
{
|
||
|
unquote(string_view{at<"origin"_>(*this)})
|
||
|
};
|
||
|
|
||
|
thread_local char sigb64[1_KiB];
|
||
|
return fmt::sprintf
|
||
|
{
|
||
|
out, "X-Matrix origin=%s,key=\"%s\",sig=\"%s\"",
|
||
|
origin,
|
||
|
pkid,
|
||
|
b64encode_unpadded(sigb64, sig)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::request::verify(const string_view &key,
|
||
|
const string_view &sig)
|
||
|
const
|
||
|
{
|
||
|
const ed25519::sig _sig
|
||
|
{
|
||
|
[&sig](auto &buf)
|
||
|
{
|
||
|
b64decode(buf, sig);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const auto &origin
|
||
|
{
|
||
|
unquote(at<"origin"_>(*this))
|
||
|
};
|
||
|
|
||
|
const ed25519::pk pk
|
||
|
{
|
||
|
[&origin, &key](auto &buf)
|
||
|
{
|
||
|
m::keys::get(origin, key, [&buf]
|
||
|
(const string_view &key)
|
||
|
{
|
||
|
b64decode(buf, unquote(key));
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return verify(pk, _sig);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::request::verify(const ed25519::pk &pk,
|
||
|
const ed25519::sig &sig)
|
||
|
const
|
||
|
{
|
||
|
const json::strung object
|
||
|
{
|
||
|
*this
|
||
|
};
|
||
|
|
||
|
return verify(pk, sig, object);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
ircd::m::request::verify(const ed25519::pk &pk,
|
||
|
const ed25519::sig &sig,
|
||
|
const json::object &object)
|
||
|
{
|
||
|
return pk.verify(object, sig);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// x_matrix
|
||
|
//
|
||
|
|
||
|
ircd::m::request::x_matrix::x_matrix(const string_view &input)
|
||
|
{
|
||
|
string_view tokens[3];
|
||
|
if(ircd::tokens(split(input, ' ').second, ',', tokens) != 3)
|
||
|
throw std::out_of_range{"The x_matrix header is malformed"};
|
||
|
|
||
|
for(const auto &token : tokens)
|
||
|
{
|
||
|
const auto &kv{split(token, '=')};
|
||
|
const auto &val{unquote(kv.second)};
|
||
|
switch(hash(kv.first))
|
||
|
{
|
||
|
case hash("origin"): origin = val; break;
|
||
|
case hash("key"): key = val; break;
|
||
|
case hash("sig"): sig = val; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(empty(origin))
|
||
|
throw std::out_of_range{"The x_matrix header is missing 'origin='"};
|
||
|
|
||
|
if(empty(key))
|
||
|
throw std::out_of_range{"The x_matrix header is missing 'key='"};
|
||
|
|
||
|
if(empty(sig))
|
||
|
throw std::out_of_range{"The x_matrix header is missing 'sig='"};
|
||
|
}
|