[ADD/WIP/UNTESTED] Start creating PDU for client events
Some checks failed
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled

This commit is contained in:
lda 2024-05-02 20:02:30 +02:00
parent d0a447a409
commit 001b4821fe
4 changed files with 312 additions and 0 deletions

14
.ycm_extra_conf.py Normal file
View file

@ -0,0 +1,14 @@
import os
import ycm_core
def Settings( **kwargs ):
return {
'flags': [
"-xc",
"-I", "src/include",
"-I", "Cytoplasm/include",
"-I", "build",
"-std=c99"
]
}

View file

@ -22,11 +22,16 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "Cytoplasm/Io.h"
#include "Cytoplasm/Stream.h"
#include <CanonicalJson.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Array.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Sha.h>
#include <stdio.h>
#include <string.h>
@ -159,3 +164,51 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
ArrayFree(keys);
return length;
}
static ssize_t
StringIoRead(void *cookie, void *buf, size_t count)
{
return -1; /* TODO: Consider reading properly */
}
static ssize_t
StringIoWrite(void *c, void *buf, size_t count)
{
char **str = c;
char *stringised = Malloc(count + 1);
char *new;
memcpy(stringised, buf, count);
new = StrConcat(2, *str, stringised);
Free(stringised);
if (*str)
{
Free(*str);
}
*str = new;
return count;
}
static const IoFunctions Functions = {
.read = StringIoRead,
.write = StringIoWrite,
.close = NULL,
.seek = NULL
};
char *
CanonicalJsonHash(HashMap *json)
{
char *string = NULL;
unsigned char *sha;
char *shastr;
Io *string_writer = IoCreate(&string, Functions);
Stream *io_stream = StreamIo(string_writer);
CanonicalJsonEncode(json, io_stream);
sha = Sha256(string);
shastr = ShaToHex(sha);
Free(string);
Free(sha);
StreamClose(io_stream);
return shastr;
}

View file

@ -23,13 +23,23 @@
* SOFTWARE.
*/
#include "Cytoplasm/Json.h"
#include "Cytoplasm/Stream.h"
#include "Parser.h"
#include <Room.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Util.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Db.h>
#include <Schema/RoomCreateRequest.h>
#include <Schema/PduV1.h>
#include <Schema/PduV3.h>
#include <CanonicalJson.h>
#include <Parser.h>
#include <State.h>
#include <stdlib.h>
@ -155,3 +165,228 @@ RoomStateGet(Room * room)
return NULL;
}
static bool
PopulateEventV1(Room * room, HashMap * event, PduV1 * pdu)
{
char *unused;
if (PduV1FromJson(event, pdu, &unused))
{
return true;
}
/* TODO: Create a PDU of our own, signed and everything.
* https://telodendria.io/blog/matrix-protocol-overview
* has some ideas on how this could be done(up until stage 5). */
pdu->sender =
StrDuplicate(JsonValueAsString(JsonGet(event, 1, "sender")));
pdu->auth_events = ArrayCreate();
pdu->origin_server_ts = UtilTsMillis();
pdu->content = JsonDuplicate(event); /* Copy the original JSON data */
/* TODO: Signature and alldat. */
return false;
}
static bool
PopulateEventV3(Room * room, HashMap * event, PduV3 *pdu)
{
char *unused;
if (PduV3FromJson(event, pdu, &unused))
{
return true;
}
/* TODO: Create a PDU of our own, signed and everything.
* https://telodendria.io/blog/matrix-protocol-overview
* has some ideas on how this could be done(up until stage 5). */
return false;
}
static AuthoriseCreateV1(PduV1 pdu)
{
bool ret = true;
CommonID sender = { 0 }, room_id = { 0 };
char *sender_serv = NULL, *id_serv = NULL;
if (ArraySize(pdu.auth_events) > 0)
{
ret = false;
goto finish;
}
if (!ParseCommonID(pdu.room_id, &room_id) ||
!ParseCommonID(pdu.sender, &sender))
{
ret = false;
goto finish;
}
sender_serv = ParserRecomposeServerPart(sender.server);
id_serv = ParserRecomposeServerPart(room_id.server);
if (!StrEquals(sender_serv, id_serv))
{
ret = false;
goto finish;
}
/* TODO: Check room_version as in step 1.3 */
if (!HashMapGet(pdu.content, "creator"))
{
ret = false;
goto finish;
}
finish:
if (sender_serv)
{
Free(sender_serv);
}
if (id_serv)
{
Free(id_serv);
}
CommonIDFree(sender);
CommonIDFree(room_id);
return ret;
}
static bool
AuthoriseEventV1(PduV1 pdu)
{
size_t i;
if (StrEquals(pdu.type, "m.room.create"))
{
return AuthoriseCreateV1(pdu);
}
/* TODO: Consider, everything else! */
for (i = 0; i < ArraySize(pdu.auth_events); i++)
{
char *event_id = ArrayGet(pdu.auth_events, i);
/* TODO: Fetch event there */
}
/* TODO */
return true;
}
static char *
RoomHashEvent(HashMap * pdu_json)
{
HashMap * copy = JsonDuplicate(pdu_json);
char *hash;
JsonValueFree(HashMapDelete(copy, "unsigned"));
JsonValueFree(HashMapDelete(copy, "signatures"));
JsonValueFree(HashMapDelete(copy, "hashes"));
hash = CanonicalJsonHash(copy);
JsonFree(copy);
return hash;
}
static char *
RoomHashEventV1(PduV1 pdu)
{
HashMap *json = PduV1ToJson(&pdu);
char *sha = RoomHashEvent(json);
JsonFree(json);
return sha;
}
static HashMap *
RoomEventSendV1(Room * room, HashMap * event)
{
PduV1 pdu = { 0 };
HashMap *pdu_object = NULL;
bool client_event;
HashMap *state = NULL;
client_event = PopulateEventV1(room, event, &pdu);
pdu_object = PduV1ToJson(&pdu);
state = StateResolve(room, pdu_object); /* Compute the state
* at that point for later. */
if (client_event)
{
char *event_id;
#define AddState(type, key) do \
{ \
event_id = StateGet(state, type, key); \
if (event_id) \
{ \
char *dup = StrDuplicate(event_id); \
ArrayAdd(pdu.auth_events, dup); \
} \
} \
while (0)
/*
* Implemented from
* https://spec.matrix.org/v1.7/server-server-api/
* #auth-events-selection */
AddState("m.room.create", "");
AddState("m.room.power_levels", "");
AddState("m.room.member", pdu.sender);
if (StrEquals(pdu.type, "m.room.member"))
{
char *target = pdu.state_key;
char *membership =
JsonValueAsString(JsonGet(pdu.content, 1, "membership"));
char *auth_via =
JsonValueAsString(
JsonGet(
pdu.content, 1, "join_authorised_via_users_server")
);
HashMap *inv =
JsonValueAsObject(
JsonGet(pdu.content, 1, "third_party_invite"));
if (target && !StrEquals(target, pdu.sender))
{
AddState("m.room.member", target);
}
if (StrEquals(membership, "join") ||
StrEquals(membership, "invite"))
{
AddState("m.room.join_rules", "");
}
if (StrEquals(membership, "invite") && inv)
{
char *token =
JsonValueAsString(JsonGet(inv, 2, "signed", "token"));
AddState("m.room.third_party_invite", token);
}
if (auth_via && room->version >= 8)
{
AddState("m.room.member", auth_via);
}
}
pdu.hashes.sha256 = RoomHashEventV1(pdu);
#undef AddState
}
/* TODO: Do a size check! */
finish:
if (state)
{
JsonFree(state);
}
if (pdu_object)
{
JsonFree(pdu_object);
}
PduV1Free(&pdu);
return NULL;
}
static HashMap *
RoomEventSendV3(Room * room, HashMap * event)
{
/* TODO */
return NULL;
}
HashMap *
RoomEventSend(Room * room, HashMap * event)
{
if (!room || !event)
{
return NULL;
}
if (room->version == 1)
{
/* Manage with PDUv1 */
return RoomEventSendV1(room, event);
}
/* Manage with PDUv3 otherwise */
return RoomEventSendV3(room, event);
}

View file

@ -79,6 +79,16 @@
*/
extern int CanonicalJsonEncode(HashMap *, Stream *);
/**
* Computes a JSON object encoded as Canonical JSON's SHA-256
* hash.
*
* This function returns a SHA-256 string stored on the heap,
* which will need to be freed with
* .Fn Free .
*/
extern char * CanonicalJsonHash(HashMap *);
/**
* Encode a JSON value following the rules of Canonical JSON.
* See the documentation for