0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-19 16:30:52 +01:00
construct/ircd/matrix.cc
2017-09-08 03:47:50 -07:00

304 lines
6.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.h>
ircd::m::session::session(const host_port &host_port)
:client{host_port}
{
}
ircd::json::object
ircd::m::session::operator()(parse::buffer &pb,
request &r)
{
parse::capstan pc
{
pb, read_closure(*this)
};
http::request
{
host(remote_addr(*this)),
r.method,
r.path,
r.query,
std::string(r),
write_closure(*this),
{
{ "Content-Type"s, "application/json"s }
}
};
http::code status;
json::object object;
http::response
{
pc,
nullptr,
[&pc, &status, &object](const http::response::head &head)
{
status = http::status(head.status);
object = http::response::content{pc, head};
}
};
if(status < 200 || status >= 300)
throw m::error(status, object);
return object;
}
///////////////////////////////////////////////////////////////////////////////
//
// m/id.h
//
ircd::m::id::id(const string_view &id)
:string_view{id}
,sigil{m::sigil(id)}
{
}
ircd::m::id::id(const enum sigil &sigil,
const string_view &id)
:string_view{id}
,sigil{sigil}
{
if(!valid())
throw INVALID_MXID("Not a valid '%s' mxid", reflect(sigil));
}
ircd::m::id::id(const enum sigil &sigil,
char *const &buf,
const size_t &max,
const string_view &id)
:string_view{buf}
,sigil{sigil}
{
strlcpy(buf, id, max);
}
ircd::m::id::id(const enum sigil &sigil,
char *const &buf,
const size_t &max,
const string_view &name,
const string_view &host)
:string_view{[&]() -> string_view
{
if(!max)
return {};
size_t len(0);
if(!startswith(name, sigil))
buf[len++] = char(sigil);
const auto has_sep
{
std::count(std::begin(name), std::end(name), ':')
};
if(!has_sep && host.empty())
{
len += strlcpy(buf + len, name, max - len);
}
else if(!has_sep && !host.empty())
{
len += fmt::snprintf(buf + len, max - len, "%s:%s",
name,
host);
}
else if(has_sep == 1 && !host.empty() && !split(name, ':').second.empty())
{
len += strlcpy(buf + len, name, max - len);
}
else if(has_sep && !host.empty())
{
throw INVALID_MXID("Not a valid '%s' mxid", reflect(sigil));
}
return { buf, len };
}()}
,sigil{sigil}
{
}
ircd::m::id::id(const enum sigil &sigil,
char *const &buf,
const size_t &max,
const generate_t &,
const string_view &host)
:string_view{[&]
{
char name[64]; switch(sigil)
{
case sigil::USER:
generate_random_prefixed(sigil::USER, "guest", name, sizeof(name));
break;
case sigil::ALIAS:
generate_random_prefixed(sigil::ALIAS, "", name, sizeof(name));
break;
default:
generate_random_timebased(sigil, name, sizeof(name));
break;
};
const size_t len
{
fmt::snprintf(buf, max, "%s:%s",
name,
host)
};
return string_view { buf, len };
}()}
,sigil{sigil}
{
}
bool
ircd::m::id::valid()
const
{
const auto parts(split(*this, ':'));
const auto &local(parts.first);
const auto &host(parts.second);
// this valid() requires a full canonical mxid with a host
if(host.empty())
return false;
// local requires a sigil plus at least one character
if(local.size() < 2)
return false;
// local requires the correct sigil type
if(!startswith(local, sigil))
return false;
return true;
}
bool
ircd::m::id::valid_local()
const
{
const auto parts(split(*this, ':'));
const auto &local(parts.first);
// local requires a sigil plus at least one character
if(local.size() < 2)
return false;
// local requires the correct sigil type
if(!startswith(local, sigil))
return false;
return true;
}
ircd::string_view
ircd::m::id::generate_random_prefixed(const enum sigil &sigil,
const string_view &prefix,
char *const &buf,
const size_t &max)
{
const uint32_t num(rand::integer());
const size_t len(fmt::snprintf(buf, max, "%c%s%u", char(sigil), prefix, num));
return { buf, len };
}
ircd::string_view
ircd::m::id::generate_random_timebased(const enum sigil &sigil,
char *const &buf,
const size_t &max)
{
const auto utime(microtime());
const size_t len(snprintf(buf, max, "%c%zd%06d", char(sigil), utime.first, utime.second));
return { buf, len };
}
enum ircd::m::id::sigil
ircd::m::sigil(const string_view &s)
try
{
return sigil(s.at(0));
}
catch(const std::out_of_range &e)
{
throw BAD_SIGIL("sigil undefined");
}
enum ircd::m::id::sigil
ircd::m::sigil(const char &c)
{
switch(c)
{
case '$': return id::EVENT;
case '@': return id::USER;
case '#': return id::ALIAS;
case '!': return id::ROOM;
}
throw BAD_SIGIL("'%c' is not a valid sigil", c);
}
const char *
ircd::m::reflect(const enum id::sigil &c)
{
switch(c)
{
case id::EVENT: return "EVENT";
case id::USER: return "USER";
case id::ALIAS: return "ALIAS";
case id::ROOM: return "ROOM";
}
return "?????";
}
bool
ircd::m::valid_sigil(const string_view &s)
try
{
return valid_sigil(s.at(0));
}
catch(const std::out_of_range &e)
{
return false;
}
bool
ircd::m::valid_sigil(const char &c)
{
switch(c)
{
case id::EVENT:
case id::USER:
case id::ALIAS:
case id::ROOM:
return true;
}
return false;
}