Compare commits

..

No commits in common. "1e097ff895cc8770d4b57bf7993f74e2f48dc66e" and "1fee47a6280174445b8ec90605b55eac6e957199" have entirely different histories.

5 changed files with 41 additions and 162 deletions

View file

@ -1,14 +0,0 @@
{
"header": "Schema\/AdminDeactivate.h",
"types": {
"DeactivateRequest": {
"fields": {
"reason": {
"type": "string"
}
},
"type": "struct"
}
},
"guard": "TELODENDRIA_SCHEMA_ADMINDEACTIVATE_H"
}

View file

@ -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"
}

View file

@ -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.

View file

@ -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;
} }

View file

@ -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;
} }
} }