forked from Telodendria/Telodendria
Compare commits
No commits in common. "1e097ff895cc8770d4b57bf7993f74e2f48dc66e" and "1fee47a6280174445b8ec90605b55eac6e957199" have entirely different histories.
1e097ff895
...
1fee47a628
5 changed files with 41 additions and 162 deletions
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"header": "Schema\/AdminDeactivate.h",
|
|
||||||
"types": {
|
|
||||||
"DeactivateRequest": {
|
|
||||||
"fields": {
|
|
||||||
"reason": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"guard": "TELODENDRIA_SCHEMA_ADMINDEACTIVATE_H"
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
{
|
|
||||||
"header": "Schema\/RequestToken.h",
|
|
||||||
"types": {
|
|
||||||
"RequestToken": {
|
|
||||||
"fields": {
|
|
||||||
"client_secret": { "type": "string" },
|
|
||||||
"send_attempt": { "type": "integer" },
|
|
||||||
"next_link": { "type": "string" },
|
|
||||||
"id_access_token": { "type": "string" },
|
|
||||||
"id_server": { "type": "string" },
|
|
||||||
|
|
||||||
"email": { "type": "string" },
|
|
||||||
|
|
||||||
"country": { "type": "string" },
|
|
||||||
"phone_number": { "type": "string" }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"guard": "TELODENDRIA_SCHEMA_REQUESTTOKEN_H"
|
|
||||||
}
|
|
|
@ -39,71 +39,12 @@ Telodendria that Conduit lacks.
|
||||||
|
|
||||||
### Small Dependency Chain
|
### Small Dependency Chain
|
||||||
|
|
||||||
Conduit's dependency chain is quite large. What this means is that
|
**TODO:** See #30.
|
||||||
Conduit depends on a lot of code that it does not control, making it
|
|
||||||
vulnerable to supply chain attacks. A problem with Rust Crates
|
|
||||||
is that they are developer-published, so they don't go through any sort
|
|
||||||
of auditing process like a Debian package would, for example.
|
|
||||||
If any one of the dependencies is
|
|
||||||
hijacked or otherwise compromised, then Conduit itself is compromised
|
|
||||||
and it is likely that this would go unnoticed for quite a while. While
|
|
||||||
one could argue that this is extremely unlikely to happen, sometimes you
|
|
||||||
just don't want to take that risk, especially not if you're deploying a
|
|
||||||
Matrix homeserver, likely for the purpose of secure, private chat.
|
|
||||||
|
|
||||||
Telodendria doesn't pull in any packages from developer repositories, so
|
|
||||||
the risk of supply chain attacks is much lower. It
|
|
||||||
only uses its own code and code provided by the operating system it is running
|
|
||||||
on, which has been vetted by a large number of developers and can be trusted
|
|
||||||
due to the sheer scope of an operating system. A supply chain attack against
|
|
||||||
Telodendria would be a supply chain attack against the entire operating system;
|
|
||||||
at that point, end users have much bigger problems.
|
|
||||||
|
|
||||||
Minimal dependencies doesn't only mitigate supply chain attacks. It also makes
|
|
||||||
maintenance much easier. Telodendria can spend more time writing code than
|
|
||||||
Conduit because Conduit developers have to ensure dependencies stay up to date and
|
|
||||||
when they inevitably break things, Conduit must pause development to fix those.
|
|
||||||
Telodendria doesn't suffer from this problem: because most of the code is developed
|
|
||||||
along side of Telodendria, it can remain as stable or become as volatile as the
|
|
||||||
developers choose. Additionally, because Telodendria is so low-level, the code on
|
|
||||||
which it depends is extremely unlikely to be changed in any significant way,
|
|
||||||
since so many other programs depend on that code.
|
|
||||||
|
|
||||||
### Standardized
|
### Standardized
|
||||||
|
|
||||||
Conduit is written in Rust, which has no formal standard. This makes it less than
|
**TODO:** See #30.
|
||||||
ideal for long-lived software projects, because it changes frequently and often
|
|
||||||
breaks existing code. Telodendria is written in C, a stable, mature, and standardized
|
|
||||||
language that will always compile the same code the same way, making it more
|
|
||||||
portable and sustainable for the future because we don't ever have to worry about
|
|
||||||
upgrading our toolchain—using standard tools built into most operating systems
|
|
||||||
will suffice.
|
|
||||||
|
|
||||||
Because the language in which Telodendria is written never changes, Telodendria can
|
|
||||||
continually optimize and improve the code, instead of having to fix breaking changes.
|
|
||||||
This ensures that Telodendria's code will last. Rust code becomes obsolete with in a
|
|
||||||
few years at best—programs written in Rust last year probably won't compile or run
|
|
||||||
properly on the latest Rust toolchain. Telodendria, on the other hand, is written in C89,
|
|
||||||
which compiled and ran the same way in 1989 as it does today and will continue to for the
|
|
||||||
foreseeable future.
|
|
||||||
|
|
||||||
### Fast Compile Times
|
|
||||||
|
|
||||||
Rust is well-known for taking an extremely long time to compile moderately-sized
|
|
||||||
programs. Since a Matrix homeserver is such a large project, the compile times would
|
|
||||||
be prohibitively large for rapid development. By writing Telodendria in C, we can take
|
|
||||||
advantage of decades worth of compiler optimizations and speed improvements, resulting
|
|
||||||
in extremely fast builds.
|
|
||||||
|
|
||||||
### Portable
|
### Portable
|
||||||
|
|
||||||
One does not typically think of C as more portable than something like Rust, but
|
**TODO:** See #30.
|
||||||
Telodendria is written in such a way that it is. Rust relies on LLVM, which doesn't
|
|
||||||
support some strange or exotic architectures in the same way that a specialized C
|
|
||||||
compiler for those architectures will. This allows users to run Telodendria on the
|
|
||||||
hardware of their choice, even if that hardware is so strange that the modern world
|
|
||||||
has totally left it behind.
|
|
||||||
|
|
||||||
Telodendria doesn't just aim at being lightweight and portable, it aims to empower
|
|
||||||
people to use common hardware that they already have, even if it is typically thought
|
|
||||||
of as underpowered.
|
|
||||||
|
|
|
@ -28,8 +28,7 @@
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
#include <User.h>
|
#include <User.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
#include <Schema/AdminDeactivate.h>
|
|
||||||
|
|
||||||
ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +38,6 @@ ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
||||||
|
|
||||||
JsonValue *val;
|
JsonValue *val;
|
||||||
char *reason = "Deactivated by admin";
|
char *reason = "Deactivated by admin";
|
||||||
char *err;
|
|
||||||
char *removedLocalpart = ArrayGet(path, 0);
|
char *removedLocalpart = ArrayGet(path, 0);
|
||||||
char *token;
|
char *token;
|
||||||
|
|
||||||
|
@ -50,8 +48,6 @@ ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
||||||
|
|
||||||
HttpRequestMethod method = HttpRequestMethodGet(args->context);
|
HttpRequestMethod method = HttpRequestMethodGet(args->context);
|
||||||
|
|
||||||
DeactivateRequest deactReq;
|
|
||||||
|
|
||||||
if ((method != HTTP_DELETE) && (method != HTTP_PUT))
|
if ((method != HTTP_DELETE) && (method != HTTP_PUT))
|
||||||
{
|
{
|
||||||
char * msg = "Route only supports DELETE and PUT as for now.";
|
char * msg = "Route only supports DELETE and PUT as for now.";
|
||||||
|
@ -67,10 +63,10 @@ ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
return MatrixErrorCreate(M_NOT_JSON, NULL);
|
return MatrixErrorCreate(M_NOT_JSON, NULL);
|
||||||
}
|
}
|
||||||
if (!DeactivateRequestFromJson(request, &deactReq, &err))
|
val = HashMapGet(request, "reason");
|
||||||
|
if (val && JsonValueType(val) == JSON_STRING)
|
||||||
{
|
{
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
reason = JsonValueAsString(val);
|
||||||
return MatrixErrorCreate(M_BAD_JSON, err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +100,7 @@ ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
|
|
||||||
JsonSet(response, JsonValueString(removedLocalpart), 1, "user");
|
JsonSet(response, JsonValueString(removedLocalpart), 1, "user");
|
||||||
JsonSet(response, JsonValueString(deactReq.reason), 1, "reason");
|
JsonSet(response, JsonValueString(reason), 1, "reason");
|
||||||
JsonSet(response, JsonValueString(UserGetName(user)), 1, "banned_by");
|
JsonSet(response, JsonValueString(UserGetName(user)), 1, "banned_by");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -116,7 +112,6 @@ ROUTE_IMPL(RouteAdminDeactivate, path, argp)
|
||||||
finish:
|
finish:
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
UserUnlock(removed);
|
UserUnlock(removed);
|
||||||
DeactivateRequestFree(&deactReq);
|
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,31 +26,14 @@
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
#include <Cytoplasm/Json.h>
|
#include <Cytoplasm/Json.h>
|
||||||
|
|
||||||
#include <Schema/RequestToken.h>
|
|
||||||
|
|
||||||
ROUTE_IMPL(RouteRequestToken, path, argp)
|
ROUTE_IMPL(RouteRequestToken, path, argp)
|
||||||
{
|
{
|
||||||
RouteArgs *args = argp;
|
RouteArgs *args = argp;
|
||||||
char *type = ArrayGet(path, 0);
|
char *type = ArrayGet(path, 0);
|
||||||
HashMap *request;
|
HashMap *request;
|
||||||
HashMap *response;
|
HashMap *response;
|
||||||
|
JsonValue *val;
|
||||||
char *msg;
|
char *str;
|
||||||
|
|
||||||
RequestToken reqTok;
|
|
||||||
|
|
||||||
Int64 minusOne = Int64Neg(Int64Create(0, 1));
|
|
||||||
|
|
||||||
reqTok.client_secret = NULL;
|
|
||||||
reqTok.next_link = NULL;
|
|
||||||
reqTok.id_access_token = NULL;
|
|
||||||
reqTok.id_server = NULL;
|
|
||||||
|
|
||||||
reqTok.email = NULL;
|
|
||||||
reqTok.country = NULL;
|
|
||||||
reqTok.phone_number = NULL;
|
|
||||||
|
|
||||||
reqTok.send_attempt = minusOne;
|
|
||||||
|
|
||||||
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
||||||
{
|
{
|
||||||
|
@ -65,92 +48,87 @@ ROUTE_IMPL(RouteRequestToken, path, argp)
|
||||||
return MatrixErrorCreate(M_NOT_JSON, NULL);
|
return MatrixErrorCreate(M_NOT_JSON, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!RequestTokenFromJson(request, &reqTok, &msg))
|
val = HashMapGet(request, "client_secret");
|
||||||
|
if (!val || JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reqTok.client_secret)
|
str = JsonValueAsString(val);
|
||||||
|
if (strlen(str) > 255 || StrBlank(str))
|
||||||
{
|
{
|
||||||
msg = "'client_secret' is not set";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(reqTok.client_secret) > 255 || StrBlank(reqTok.client_secret))
|
val = HashMapGet(request, "send_attempt");
|
||||||
|
if (!val || JsonValueType(val) != JSON_INTEGER)
|
||||||
{
|
{
|
||||||
msg = "'client_secret' is blank or too long";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Int64Eq(reqTok.send_attempt, minusOne))
|
val = HashMapGet(request, "next_link");
|
||||||
|
if (val && JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
msg = "Invalid or inexistent 'send_attempt'";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reqTok.next_link)
|
val = HashMapGet(request, "id_access_token");
|
||||||
|
if (val && JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
msg = "'next_link' is not set";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
if (!reqTok.id_access_token)
|
|
||||||
|
val = HashMapGet(request, "id_server");
|
||||||
|
if (val && JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
msg = "'id_access_token' is not set";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
if (!reqTok.id_server)
|
|
||||||
{
|
|
||||||
msg = "'id_server' is not set";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StrEquals(type, "email"))
|
if (StrEquals(type, "email"))
|
||||||
{
|
{
|
||||||
if (!reqTok.email)
|
val = HashMapGet(request, "email");
|
||||||
|
if (val && JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
msg = "Type is set to 'email' yet none was set";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (StrEquals(type, "msisdn"))
|
else if (StrEquals(type, "msisdn"))
|
||||||
{
|
{
|
||||||
if (!reqTok.country)
|
val = HashMapGet(request, "country");
|
||||||
|
if (val && JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
msg = "Type is set to 'msisdn' yet no country is set";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(reqTok.country) != 2)
|
str = JsonValueAsString(val);
|
||||||
|
if (strlen(str) != 2)
|
||||||
{
|
{
|
||||||
msg = "Invalid country tag, length must be 2";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reqTok.phone_number)
|
val = HashMapGet(request, "phone_number");
|
||||||
|
if (val && JsonValueType(val) != JSON_STRING)
|
||||||
{
|
{
|
||||||
msg = "Type is set to 'msisdn' yet phone_number is unset";
|
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
response = MatrixErrorCreate(M_BAD_JSON, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue