Compare commits

...

42 Commits

Author SHA1 Message Date
LDA e2d26c7f33 [ADD/WIP] Start /messages, sync timeouts, cleaning
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
This code _really_ isn't good. I've spotted some fun racing happen and
leak of some JSON(somehow?) without timeout, and I've been trying to
spend the last several days trying to fix that.

The good news is that, with some endpoint spoofing, you can actually
_try_ this with a Matrix client(dev.cinny.in for example).

I might consider rewriting this pastacode, considering the issues noted
above in favour of a better design, with less odds of this.
2024-06-14 23:30:35 +02:00
lda 97b1e4d723 [ADD/WIP] Push events into sync
The code is still ugly(still waiting for j2s to support some things
before I can actually get *somewhere* with the schemas, which is my main
complaint), and it's definitely not spec-compliant, but it now means you
can actually see diffs in rooms you joined from the timeline!
2024-06-09 11:46:44 +02:00
lda 046a04e495 [WIP] Start making (broken) /syncs
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
This code is *really* ugly. And it also doesn't handle timelines.
2024-06-09 03:20:09 +02:00
lda 00311f58dc [WIP] Start making bare-bones /sync reply schema.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-06-09 02:13:49 +02:00
lda a491a740d4 [ADD/WIP] Begin work on storing /sync diffs.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-06-09 01:43:16 +02:00
LDA bb3d15f2c9 [MOD/FIX] Update user list at the lowest level
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
I'll need to start defining a `diffs' system for sync. I have a decent
idea on how that could go(with 1 level of batching), but I'll need to
consider it some.
2024-06-08 18:37:54 +02:00
LDA 88610a3238 [ADD/WIP] Start basic work on getting room lists.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
I think I should actually update by "catching" events on-the-fly instead
of doing this.
2024-06-08 15:49:31 +02:00
LDA 9203ec1268 [MOD] Join rooms via alias
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-06-08 11:57:52 +02:00
LDA 9600d2ffb5 [FIX/WIP] Fix join rules
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
I'll still need to notify users that they're *in* the room, instead of
just poking at the state.

But this should allow users to send events to the same room.
2024-06-08 11:03:54 +02:00
lda 250d28b958 [UNTESTED/WIP] Room joins
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
Still have to test this.
2024-06-08 10:31:21 +02:00
lda 6ce63b01ce [ADD/WIP] Basic means to view a room event.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-06-08 09:34:27 +02:00
lda e268471dba [ADD/WIP] Start work to send messages
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
This commit *works*  but I don't quite like it.
2024-06-07 18:24:13 +02:00
LDA 39c4af8d4d [MOD/WIP] Start work for event sending
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-06-07 13:58:34 +02:00
lda b0c3d6ce31 [MOD/WIP] Move caching in the StateResolve func.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-06-06 23:25:46 +02:00
lda 3a2fec8a47 [MOD/TESTING] Begin storing the state at each event
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
This probably needs some cache evicting to avoid piling up large
states.
2024-06-06 16:02:43 +02:00
lda 604d6cf017 Merge remote-tracking branch 'refs/remotes/origin/roomwerk' into roomwerk
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
2024-06-04 13:47:15 +02:00
lda 21b015da2c [MOD/WIP] Fix double-free on PL checks 2024-06-04 13:45:12 +02:00
lda c1630247b1 [FIX/WIP] Fix bug where banned users could be invited.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
There seems to be another, much more annoying bug going down with
one of the servers I've tested on, but I don't know how to fix it
as of now.
2024-05-24 16:52:31 +02:00
lda 879e51c169 [ADD/WIP] Set is_direct field in room leaves
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
2024-05-21 11:17:57 +02:00
lda c22d628c86 [ADD/WIP] Start implementing invites.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
I'll need to add the direct flag somewhere in the room leaves.
Also, it seems like there's a giant bottleneck in my code...
2024-05-20 16:37:41 +02:00
lda 9dcaab0819 [ADD/FIX/WIP] Fix content hashing, respect creation_content.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
Oops, I *should* have known sha256 are stored as raw unpadded b64!base64!
2024-05-19 19:11:33 +02:00
lda cacc72bf84 [ADD/WIP] Basic preset code
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
I still need to find a solution to a problem related to j2s.
Right now I kind of want to have a way for users to send events
from the endpoints.
2024-05-19 15:17:56 +02:00
lda a99798a312 [ADD/WIP] Start abstracting aliasing 2024-05-19 00:30:28 +02:00
lda e3c57d8f05 [ADD/WIP] Basic alias system.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
NOTE: I *need* to write an Alias API(and also manage clashes proper.)
2024-05-18 21:24:30 +02:00
lda 7ee35fcc28 [MOD] Clamp depth
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-05-18 20:26:30 +02:00
lda 327730c2c6 [ADD/WIP] Basic PDU depth system.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
NOTE: This is *not* a good way to compute depth.
2024-05-18 20:17:54 +02:00
lda 5ca36396a2 Merge branch 'master' of https://git.telodendria.io/Telodendria/Telodendria into roomwerk
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-05-18 19:22:27 +02:00
lda e1d632b135 [ADD/WIP] Remove boundscheck on array sorts
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-05-18 17:11:29 +02:00
Jordan Bancino a8924b8437
Update Cytoplasm to v0.4.1. 2024-05-18 10:55:15 -04:00
lda ecb18dc7b2 [ADD/WIP] Added more events at init-time
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-05-18 16:39:51 +02:00
lda e36f4357ab [ADD/WIP] Start testing code
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
I think I'll manage PDU depth later(with an actual good way to handle
it properly(that is not just setting it to the max and calling it a
day.)
2024-05-17 23:57:32 +02:00
lda 1753c2188b [ADD/UNTESTED] Set ServerPart on room creation
Not tested as of now!
2024-05-17 13:52:25 +02:00
lda 9ffa37d7a7 [ADD/UNTESTED] Start implementing event sending
This is NOT perfect. This *will* need changes before it gets pushed.
2024-05-17 13:37:34 +02:00
lda 15b884b04a [ADD/UNTESTED] Barebones State Resolution V1
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
NOTE: It is probably NOT in an usable state. Even if it is, it should
not be PR'd into Telodendria right now.

Feeling a bit burnt out, so I'll take a break. Feel free to issue PRs to
this branch to clean/weed out some mistakes or bugs, since I only made
sure that it built.
2024-05-15 20:15:49 +02:00
lda 3066a0e8a8 [ADD/UNTESTED] Finalise powerlevels somewhat
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
Still too hacky for my taste...
2024-05-15 12:51:32 +02:00
lda 878b294030 [ADD/UNTESTED] (Nearly) implement 'invite' in auth
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
Almost because we don't verify the public key at all.
2024-05-15 10:12:07 +02:00
lda 6a69218479 [UNTESTED/ADD] Add more membership in auth rules
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
The only TODO left in this bit is `invite'.
2024-05-15 09:37:31 +02:00
lda aec71d8d32 [ADD/UNTESTED] Finalise step 5.2 of auth rules.
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
Next up is the invite membership(5.3).
2024-05-15 09:02:09 +02:00
lda 50759a3298 [UNTESTED/ADD] Finish barebones of auth rules
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-05-15 08:41:59 +02:00
lda 9bc36f324a [ADD/WIP/UNTESTED] Start verifying membership, tested hashing
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
2024-05-08 12:14:10 +02:00
lda 001b4821fe [ADD/WIP/UNTESTED] Start creating PDU for client events
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Has been cancelled Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Has been cancelled Details
2024-05-02 20:02:30 +02:00
lda d0a447a409 [WIP/ADD] Start basic room work
Compile Telodendria / Compile Telodendria (x86, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, alpine-v3.19) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, debian-v12.4) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, freebsd-v14.0) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, netbsd-v9.3) (push) Waiting to run Details
Compile Telodendria / Compile Telodendria (x86_64, openbsd-v7.4) (push) Waiting to run Details
2024-05-01 22:01:56 +02:00
28 changed files with 5492 additions and 51 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"
]
}

@ -1 +1 @@
Subproject commit 5d87da31cda74e6808eebca72e9475aabde86532
Subproject commit 346b912a0633cceac10780b8a103f6c89b5ba89f

View File

@ -16,6 +16,10 @@
"fields": {
"age": {
"type": "integer"
},
"next_events": {
"type": "[string]",
"required": false
}
}
},
@ -51,7 +55,8 @@
"required": true
},
"redacts": {
"type": "string"
"type": "string",
"required": false
},
"room_id": {
"type": "string",

112
Schema/SyncResponse.json Normal file
View File

@ -0,0 +1,112 @@
{
"guard": "TELODENDRIA_SCHEMA_SYNCRESPONSE_H",
"header": "Schema\/SyncResponse.h",
"types": {
"Event": {
"fields": {
"content": {
"type": "object",
"required": true
},
"type": {
"type": "string",
"required": true
}
},
"type": "struct"
},
"AccountData": {
"fields": {
"events": { "type": "[Event]" }
},
"type": "struct"
},
"InviteState": {
"fields": {
"events": { "type": "[StrippedStateEvent]" }
},
"type": "struct"
},
"States": {
"fields": {
"events": { "type": "[StrippedStateEvent]" }
},
"type": "struct"
},
"StrippedStateEvent": {
"fields": {
"content": {
"type": "object",
"required": true
},
"sender": {
"type": "string",
"required": true
},
"state_key": {
"type": "string",
"required": true
},
"type": {
"type": "string",
"required": true
}
},
"type": "struct"
},
"InvitedRooms": {
"fields": {
"invite_state": { "type": "InviteState" }
},
"type": "struct"
},
"ClientEventWithoutRoomID": {
"fields": {
"content": { "type": "object", "required": true },
"event_id": { "type": "string", "required": true },
"origin_server_ts": { "type": "integer", "required": true },
"sender": { "type": "string", "required": true },
"state_key": { "type": "string" },
"type": { "type": "string", "required": true }
},
"type": "struct"
},
"Timeline": {
"fields": {
"events": { "type": "[ClientEventWithoutRoomID]", "required": true },
"limited": { "type": "boolean" },
"prev_batch": { "type": "string" }
},
"type": "struct"
},
"JoinedRooms": {
"fields": {
"timeline": { "type": "Timeline" },
"state": { "type": "States" }
},
"type": "struct"
},
"Rooms": {
"fields": {
"invite": { "type": "object" },
"join": { "type": "object" }
},
"type": "struct"
},
"SyncResponse": {
"fields": {
"next_batch": {
"type": "string",
"required": true
},
"account_data": {
"type": "AccountData"
},
"rooms": {
"type": "Rooms"
}
},
"type": "struct"
}
}
}

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,55 @@ CanonicalJsonEncode(HashMap * object, Stream * out)
ArrayFree(keys);
return length;
}
static ssize_t
StringIoRead(void *cookie, void *buf, size_t count)
{
(void) cookie;
(void) buf;
(void) count;
return -1; /* TODO: Consider reading properly */
}
static ssize_t
StringIoWrite(void *c, void *buf, size_t count)
{
if (count > 0)
{
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
};
unsigned char *
CanonicalJsonHash(HashMap *json)
{
char *string = NULL;
unsigned char *sha;
Io *string_writer = IoCreate(&string, Functions);
Stream *io_stream = StreamIo(string_writer);
CanonicalJsonEncode(json, io_stream);
StreamFlush(io_stream);
sha = Sha256(string);
Free(string);
StreamClose(io_stream);
return sha;
}

View File

@ -86,6 +86,26 @@ SignalHandler(int signal)
}
}
/* TODO: Move this! */
static void
UsersClean(MatrixHttpHandlerArgs *args)
{
Db *db = args->db;
Array *arr = DbList(db, 1, "users");
size_t i;
for (i = 0; i < ArraySize(arr); i++)
{
char *id = ArrayGet(arr, i);
User *user = UserLock(db, id);
UserCleanTemporaryData(user);
UserUnlock(user);
}
DbListFree(arr);
}
typedef enum ArgFlag
{
ARG_VERSION = (1 << 0),
@ -147,6 +167,7 @@ start:
token = NULL;
memset(&matrixArgs, 0, sizeof(matrixArgs));
UserInitialisePushTable();
if (!LogConfigGlobal())
{
@ -513,10 +534,15 @@ start:
Log(LOG_DEBUG, "Registering jobs...");
CronEvery(cron, 30 * 60 * 1000, (JobFunc *) UiaCleanup, &matrixArgs);
CronEvery(cron, 5 * 60 * 1000, (JobFunc *) UsersClean, &matrixArgs);
Log(LOG_NOTICE, "Starting job scheduler...");
CronStart(cron);
/* We still call it anyways to be sure. */
Log(LOG_NOTICE, "Cleaning up user data...");
UsersClean(&matrixArgs);
Log(LOG_NOTICE, "Building routing tree...");
matrixArgs.router = RouterBuild();
if (!matrixArgs.router)
@ -583,6 +609,7 @@ start:
finish:
Log(LOG_NOTICE, "Shutting down...");
UserDestroyPushTable();
if (httpServers)
{
for (i = 0; i < ArraySize(httpServers); i++)

View File

@ -487,7 +487,7 @@ ParserRecomposeCommonID(CommonID id)
if (id.server.hostname)
{
char *server = ParserRecomposeServerPart(id.server);
char *tmp = StrConcat(4, "@", ret, ":", server);
char *tmp = StrConcat(3, ret, ":", server);
Free(ret);
Free(server);

2232
src/Room.c

File diff suppressed because it is too large Load Diff

View File

@ -76,11 +76,24 @@ RouterBuild(void)
R("/_matrix/client/v3/user/(.*)/filter", RouteFilter);
R("/_matrix/client/v3/user/(.*)/filter/(.*)", RouteFilter);
R("/_matrix/client/v3/rooms/(.*)/send/(.*)/(.*)", RouteSendEvent);
R("/_matrix/client/v3/rooms/(.*)/state/(.*)/(.*)", RouteSendState);
R("/_matrix/client/v3/rooms/(.*)/event/(.*)", RouteFetchEvent);
R("/_matrix/client/v3/rooms/(.*)/join", RouteJoinRoom);
R("/_matrix/client/v3/rooms/(.*)/messages", RouteMessages);
R("/_matrix/client/v3/join/(.*)", RouteJoinRoomAlias);
R("/_matrix/client/v3/joined_rooms", RouteJoinedRooms);
R("/_matrix/client/v3/createRoom", RouteCreateRoom);
R("/_matrix/client/v3/sync", RouteSync);
R("/_matrix/client/v3/directory/room/(.*)", RouteAliasDirectory);
R("/_matrix/client/v3/rooms/(.*)/aliases", RouteRoomAliases);
/* Telodendria Admin API Routes */
R("/_telodendria/admin/v1/(restart|shutdown|stats)", RouteProcControl);

View File

@ -23,11 +23,14 @@
* SOFTWARE.
*/
#include "Cytoplasm/Http.h"
#include <Routes.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Log.h>
#include <Schema/RoomCreateRequest.h>
#include <Room.h>
#include <User.h>
ROUTE_IMPL(RouteCreateRoom, path, argp)
{
@ -35,11 +38,21 @@ ROUTE_IMPL(RouteCreateRoom, path, argp)
HashMap *request = NULL;
HashMap *response;
RoomCreateRequest parsed;
Room *room = NULL;
Db *db = args->matrixArgs->db;
RoomCreateRequest parsed = { 0 };
User *user = NULL;
Config cfg;
ServerPart server;
char *token;
char *err;
(void) path;
ConfigLock(db, &cfg);
ParseServerPart(cfg.serverName, &server);
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{
err = "Unknown request method.";
@ -48,6 +61,18 @@ ROUTE_IMPL(RouteCreateRoom, path, argp)
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
return response;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
return MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
@ -55,7 +80,19 @@ ROUTE_IMPL(RouteCreateRoom, path, argp)
response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish;
}
/* j2s hack: Setting to a default value like that.
* It's definitely NOT good(you can't rely on enums to
* store values outside their limits in the C standard,
* and this line will need to be changed everytime the
* preset list is changed).
*
* I do believe a decent solution to this would be to
* add a 'default' type(maybe initialised to 0 so that
* memsets would work as intended), that *wouldn't* be
* returned by j2s itself.
* TODO. */
parsed.preset = ROOM_CREATE_PRIVATE + 1;
if (!RoomCreateRequestFromJson(request, &parsed, &err))
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
@ -67,9 +104,24 @@ ROUTE_IMPL(RouteCreateRoom, path, argp)
JsonFree(request);
request = NULL;
if (!(room = RoomCreate(db, user, &parsed, server)))
{
err = "Couldn't create room.";
/* Consider another error status. */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
response = HashMapCreate();
JsonSet(response, JsonValueString(RoomIdGet(room)), 1, "room_id");
finish:
JsonFree(request);
RoomUnlock(room);
UserUnlock(user);
ConfigUnlock(&cfg);
ServerPartFree(server);
RoomCreateRequestFree(&parsed);
return response;
}

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <Schema/Filter.h>
static char *
GetServerName(Db * db)
{
char *name;
Config config;
ConfigLock(db, &config);
if (!config.ok)
{
return NULL;
}
name = StrDuplicate(config.serverName);
ConfigUnlock(&config);
return name;
}
ROUTE_IMPL(RouteFetchEvent, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *event = NULL;
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
CommonID *id = NULL;
char *roomId = ArrayGet(path, 0);
char *eventId= ArrayGet(path, 1);
char *sender = NULL, *serverName = NULL;
Room *room = NULL;
char *err;
if (!roomId || !eventId)
{
/* Should be impossible */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
return MatrixErrorCreate(M_UNKNOWN, NULL);
}
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
serverName = GetServerName(db);
if (!serverName)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
id = UserIdParse(UserGetName(user), serverName);
id->sigil = '@';
sender = ParserRecomposeCommonID(*id);
/* TODO: Better auth(as in check m.room.history_visibility) */
room = RoomLock(db, roomId);
if (!RoomContainsUser(room, sender))
{
err = "User is not in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
event = RoomEventFetch(room, eventId);
response = RoomEventClientify(event);
JsonFree(event);
finish:
UserIdFree(id);
if (sender)
{
Free(sender);
}
if (serverName)
{
Free(serverName);
}
RoomUnlock(room);
UserUnlock(user);
return response;
}

View File

@ -189,7 +189,7 @@ ROUTE_IMPL(RouteFilter, path, argp)
DbJsonSet(ref, filterJson);
DbUnlock(db, ref);
Free(filterJson);
JsonFree(filterJson);
response = HashMapCreate();
HashMapSet(response, "filter_id", JsonValueString(filterId));

174
src/Routes/RouteJoinRoom.c Normal file
View File

@ -0,0 +1,174 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <Schema/Filter.h>
static char *
GetServerName(Db * db)
{
char *name;
Config config;
ConfigLock(db, &config);
if (!config.ok)
{
return NULL;
}
name = StrDuplicate(config.serverName);
ConfigUnlock(&config);
return name;
}
ROUTE_IMPL(RouteJoinRoom, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *request = NULL;
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
CommonID *id = NULL;
char *roomId = ArrayGet(path, 0);
char *sender = NULL, *serverName = NULL;
Room *room = NULL;
char *err;
if (!roomId)
{
/* Should be impossible */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
return MatrixErrorCreate(M_UNKNOWN, NULL);
}
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish;
}
serverName = GetServerName(db);
if (!serverName)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
id = UserIdParse(UserGetName(user), serverName);
id->sigil = '@';
sender = ParserRecomposeCommonID(*id);
room = RoomLock(db, roomId);
if (!room)
{
err = "Room ID does not exist.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNKNOWN, err);
goto finish;
}
if (RoomContainsUser(room, sender))
{
err = "User is already in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
if (!RoomCanJoin(room, sender))
{
err = "User cannot be in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
/* TODO: Custom reason parameter. */
if (!RoomJoin(room, user))
{
err = "User could not be the room due to unknown reasons.";
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, err);
goto finish;
}
response = HashMapCreate();
JsonSet(response, JsonValueString(roomId), 1, "room_id");
finish:
UserIdFree(id);
JsonFree(request);
if (sender)
{
Free(sender);
}
if (serverName)
{
Free(serverName);
}
RoomUnlock(room);
UserUnlock(user);
return response;
}

View File

@ -0,0 +1,194 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <Schema/Filter.h>
static char *
GetServerName(Db * db)
{
char *name;
Config config;
ConfigLock(db, &config);
if (!config.ok)
{
return NULL;
}
name = StrDuplicate(config.serverName);
ConfigUnlock(&config);
return name;
}
ROUTE_IMPL(RouteJoinRoomAlias, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *request = NULL;
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
CommonID *id = NULL;
char *roomId = ArrayGet(path, 0);
char *sender = NULL, *serverName = NULL;
Room *room = NULL;
char *err;
if (!roomId)
{
/* Should be impossible */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
return MatrixErrorCreate(M_UNKNOWN, NULL);
}
if (*roomId != '!')
{
roomId = RoomResolveAlias(db, roomId);
Log(LOG_NOTICE, "Here's my guess: %s", roomId);
}
else
{
roomId = StrDuplicate(roomId);
}
if (!roomId)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish;
}
serverName = GetServerName(db);
if (!serverName)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
Log(LOG_INFO, "Trying with token %s", token);
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
id = UserIdParse(UserGetName(user), serverName);
id->sigil = '@';
sender = ParserRecomposeCommonID(*id);
Log(LOG_INFO, "Now as %s", sender);
room = RoomLock(db, roomId);
if (!room)
{
err = "Room ID does not exist.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNKNOWN, err);
goto finish;
}
if (RoomContainsUser(room, sender))
{
err = "User is already in the room.";
Log(LOG_INFO, "qhar for %s", sender);
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
if (!RoomCanJoin(room, sender))
{
err = "User cannot be in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
/* TODO: Custom reason parameter. */
if (!RoomJoin(room, user))
{
err = "User could not be the room due to unknown reasons.";
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, err);
goto finish;
}
response = HashMapCreate();
JsonSet(response, JsonValueString(roomId), 1, "room_id");
finish:
Free(roomId);
UserIdFree(id);
JsonFree(request);
if (sender)
{
Free(sender);
}
if (serverName)
{
Free(serverName);
}
RoomUnlock(room);
UserUnlock(user);
return response;
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <Schema/Filter.h>
ROUTE_IMPL(RouteJoinedRooms, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
Array *rawRoomList;
Array *roomIds;
char *err;
size_t i;
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
rawRoomList = UserListJoins(user);
roomIds = ArrayCreate();
for (i = 0; i < ArraySize(rawRoomList); i++)
{
ArrayAdd(roomIds, JsonValueString(ArrayGet(rawRoomList, i)));
}
UserFreeList(rawRoomList);
response = HashMapCreate();
HashMapSet(response, "joined_rooms", JsonValueArray(roomIds));
(void) path;
finish:
UserUnlock(user);
return response;
}

178
src/Routes/RouteMessages.c Normal file
View File

@ -0,0 +1,178 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <stdlib.h>
#include <Schema/Filter.h>
static char *
GetServerName(Db * db)
{
char *name;
Config config;
ConfigLock(db, &config);
if (!config.ok)
{
return NULL;
}
name = StrDuplicate(config.serverName);
ConfigUnlock(&config);
return name;
}
ROUTE_IMPL(RouteMessages, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *params = HttpRequestParams(args->context);
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
char *roomId = ArrayGet(path, 0);
char *from = HashMapGet(params, "from");
char *limitStr = HashMapGet(params, "limit");
char *end = NULL;
char *sender = NULL;
char *serverName = NULL;
CommonID *id = NULL;
int limit = strtol(limitStr, NULL, 10);
Array *messages = NULL;
Room *room = NULL;
char *err;
if (!limit || limit < 0)
{
limit = 10;
}
if (!roomId)
{
/* Should be impossible */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
return MatrixErrorCreate(M_UNKNOWN, NULL);
}
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
serverName = GetServerName(db);
if (!serverName)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
id = UserIdParse(UserGetName(user), serverName);
id->sigil = '@';
sender = ParserRecomposeCommonID(*id);
room = RoomLock(db, roomId);
if (!RoomContainsUser(room, sender))
{
err = "User is not in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
RoomUnlock(room);
/* TODO: Filters, to, and friends */
messages = UserFetchMessages(user, limit, from, &end);
if (!messages)
{
Room *r = RoomLock(db, roomId);
Array *leaf = RoomPrevEventsGet(r);
HashMap *start = JsonValueAsObject(ArrayGet(leaf, 0));
char *startId = StrDuplicate(
JsonValueAsString(HashMapGet(start, "event_id"))
);
char *token = UserNewMessageToken(user, roomId, startId);
RoomUnlock(r);
messages = UserFetchMessages(user, limit, token, &end);
Free(token);
Free(startId);
}
response = HashMapCreate();
JsonSet(response, JsonValueArray(messages), 1, "chunk");
if (end)
{
JsonSet(response, JsonValueString(end), 1, "end");
Free(end);
}
UserFreeMessageToken(user, from);
finish:
UserUnlock(user);
UserIdFree(id);
if (sender)
{
Free(sender);
}
if (serverName)
{
Free(serverName);
}
return response;
}

129
src/Routes/RoutePushRules.c Normal file
View File

@ -0,0 +1,129 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Cytoplasm/HttpServer.h>
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <Schema/Filter.h>
ROUTE_IMPL(RoutePushRules, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
char *err;
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
response = HashMapCreate();
JsonSet(response, JsonValueObject(HashMapCreate()), 1, "global");
(void) path;
finish:
UserUnlock(user);
return response;
}
ROUTE_IMPL(RouteKeyQuery, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *request = NULL;
HashMap *response = NULL;
User *user = NULL;
char *token = NULL;
char *err;
if (HttpRequestMethodGet(args->context) != HTTP_POST)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish;
}
response = HashMapCreate();
(void) path;
finish:
JsonFree(request);
UserUnlock(user);
return response;
}

View File

@ -31,6 +31,7 @@
#include <Matrix.h>
#include <User.h>
#include <Room.h>
ROUTE_IMPL(RouteRoomAliases, path, argp)
{
@ -40,16 +41,15 @@ ROUTE_IMPL(RouteRoomAliases, path, argp)
char *msg;
HashMap *response = NULL;
HashMap *aliases = NULL;
HashMap *reversealias = NULL;
JsonValue *val;
Array *alias = NULL, *arr;
Db *db = args->matrixArgs->db;
DbRef *ref = NULL;
User *user = NULL;
size_t i;
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
msg = "Route only accepts GET.";
@ -81,11 +81,10 @@ ROUTE_IMPL(RouteRoomAliases, path, argp)
response = MatrixErrorCreate(M_FORBIDDEN, msg);
goto finish;
}
ref = DbLock(db, 1, "aliases");
aliases = DbJson(ref);
reversealias = JsonValueAsObject(JsonGet(aliases, 2, "id", roomId));
if (!reversealias)
alias = RoomReverseAlias(db, roomId);
if (!alias)
{
/* We do not know about the room ID. */
msg = "Unknown room ID.";
@ -93,12 +92,17 @@ ROUTE_IMPL(RouteRoomAliases, path, argp)
response = MatrixErrorCreate(M_INVALID_PARAM, msg);
goto finish;
}
arr = ArrayCreate();
for (i = 0; i < ArraySize(alias); i++)
{
char *str = ArrayGet(alias, i);
ArrayAdd(arr, JsonValueString(str));
}
response = HashMapCreate();
val = JsonGet(reversealias, 1, "aliases");
HashMapSet(response, "aliases", JsonValueDuplicate(val));
HashMapSet(response, "aliases", JsonValueArray(arr));
finish:
DbUnlock(db, ref);
RoomFreeReverse(alias);
UserUnlock(user);
return response;
}

290
src/Routes/RouteSendEvent.c Normal file
View File

@ -0,0 +1,290 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Routes.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <Schema/Filter.h>
static char *
GetServerName(Db * db)
{
char *name;
Config config;
ConfigLock(db, &config);
if (!config.ok)
{
return NULL;
}
name = StrDuplicate(config.serverName);
ConfigUnlock(&config);
return name;
}
ROUTE_IMPL(RouteSendEvent, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *request = NULL, *event = NULL;
HashMap *response = NULL, *filled = NULL;
User *user = NULL;
CommonID *id = NULL;
char *token = NULL;
char *serverName = NULL;
char *roomId = ArrayGet(path, 0);
char *eventType = ArrayGet(path, 1);
char *transId = ArrayGet(path, 2);
char *sender = NULL;
Room *room = NULL;
char *err;
if (!roomId || !eventType || !transId)
{
/* Should be impossible */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
return MatrixErrorCreate(M_UNKNOWN, NULL);
}
if (HttpRequestMethodGet(args->context) != HTTP_PUT)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
serverName = GetServerName(db);
if (!serverName)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
id = UserIdParse(UserGetName(user), serverName);
id->sigil = '@';
sender = ParserRecomposeCommonID(*id);
if ((response = UserGetTransaction(user, transId, "send")))
{
goto finish;
}
room = RoomLock(db, roomId);
if (!RoomContainsUser(room, sender))
{
err = "User is not in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
event = RoomEventCreate(sender, eventType, NULL, JsonDuplicate(request));
filled = RoomEventSend(room, event);
JsonFree(event);
if (!filled)
{
err = "User is not allowed to send event.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
response = HashMapCreate();
HashMapSet(
response, "event_id",
JsonValueDuplicate(HashMapGet(filled, "event_id"))
);
JsonFree(filled);
UserSetTransaction(user, transId, "send", response);
finish:
RoomUnlock(room);
Free(serverName);
if (sender)
{
Free(sender);
}
UserIdFree(id);
UserUnlock(user);
JsonFree(request);
return response;
}
ROUTE_IMPL(RouteSendState, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *request = NULL, *event = NULL;
HashMap *response = NULL, *filled = NULL;
User *user = NULL;
CommonID *id = NULL;
char *token = NULL;
char *serverName = NULL;
char *roomId = ArrayGet(path, 0);
char *eventType = ArrayGet(path, 1);
char *stateKey = ArrayGet(path, 2);
char *sender = NULL;
Room *room = NULL;
char *err;
if (!roomId || !eventType)
{
/* Should be impossible */
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
return MatrixErrorCreate(M_UNKNOWN, NULL);
}
if (HttpRequestMethodGet(args->context) != HTTP_PUT)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
serverName = GetServerName(db);
if (!serverName)
{
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN, NULL);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
request = JsonDecode(HttpServerStream(args->context));
if (!request)
{
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_NOT_JSON, NULL);
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
id = UserIdParse(UserGetName(user), serverName);
id->sigil = '@';
sender = ParserRecomposeCommonID(*id);
room = RoomLock(db, roomId);
if (!RoomContainsUser(room, sender))
{
err = "User is not in the room.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
Log(LOG_INFO, "State event (%s,%s) coming this way", eventType, stateKey);
event = RoomEventCreate(
sender,
eventType, stateKey ? stateKey : "",
JsonDuplicate(request)
);
filled = RoomEventSend(room, event);
Log(LOG_INFO, "State event (%s,%s) coming this way", eventType, stateKey);
JsonFree(event);
Log(LOG_INFO, "And thats freed!");
if (!filled)
{
err = "User is not allowed to send state.";
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_FORBIDDEN, err);
goto finish;
}
response = HashMapCreate();
HashMapSet(
response, "event_id",
JsonValueDuplicate(HashMapGet(filled, "event_id"))
);
JsonFree(filled);
finish:
RoomUnlock(room);
Free(serverName);
if (sender)
{
Free(sender);
}
UserIdFree(id);
UserUnlock(user);
JsonFree(request);
return response;
}

248
src/Routes/RouteSync.c Normal file
View File

@ -0,0 +1,248 @@
/*
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Cytoplasm/HttpServer.h>
#include <Routes.h>
#include <Schema/SyncResponse.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Util.h>
#include <Cytoplasm/Str.h>
#include <State.h>
#include <User.h>
#include <Room.h>
#include <string.h>
#include <stdlib.h>
static ClientEventWithoutRoomID
ClientfyEventSync(HashMap *pdu)
{
ClientEventWithoutRoomID ret = { 0 };
char *ignored;
ClientEventWithoutRoomIDFromJson(pdu, &ret, &ignored);
return ret;
}
static StrippedStateEvent
StripStateEventSync(HashMap *pdu)
{
StrippedStateEvent ret = { 0 };
char *ignored;
StrippedStateEventFromJson(pdu, &ret, &ignored);
return ret;
}
ROUTE_IMPL(RouteSync, path, argp)
{
RouteArgs *args = argp;
Db *db = args->matrixArgs->db;
HashMap *params = NULL;
HashMap *response = NULL;
SyncResponse sync = { 0 };
Array *invites;
Array *joins;
size_t i;
User *user = NULL;
char *token = NULL;
char *prevBatch = NULL;
char *nextBatch = NULL;
char *currBatch = NULL;
char *timeout = NULL;
char *err;
int timeoutDuration;
/* TODO: Respect `timeout', (and stop when something is
* pushed, maybe by 'polling' the database? sounds like
* a bad idea) */
if (HttpRequestMethodGet(args->context) != HTTP_GET)
{
err = "Unknown request method.";
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
response = MatrixErrorCreate(M_UNRECOGNIZED, err);
goto finish;
}
response = MatrixGetAccessToken(args->context, &token);
if (response)
{
goto finish;
}
user = UserAuthenticate(db, token);
if (!user)
{
HttpResponseStatus(args->context, HTTP_UNAUTHORIZED);
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
goto finish;
}
params = HttpRequestParams(args->context);
prevBatch = HashMapGet(params, "since");
timeout = HashMapGet(params, "timeout");
timeoutDuration = atoi(timeout);
if (!prevBatch)
{
prevBatch = NULL;
nextBatch = UserInitSyncDiff(user);
UserFillSyncDiff(user, nextBatch);
}
else if (timeout && timeoutDuration)
{
char *name = StrDuplicate(UserGetName(user));
int passed = 0;
UserUnlock(user);
/* TODO: Unlocking the user for other threads to notify us is not
* wise.
* Also, Telodendria will NOT reply to ^C while someone is executing
* a sync. */
while (passed < timeoutDuration)
{
if (UserGetNotification(name))
{
break;
}
UtilSleepMillis(100);
passed += 100;
}
Free(name);
user = UserAuthenticate(db, token);
}
currBatch = prevBatch ? prevBatch : nextBatch;
/* TODO: I only am manually parsing this because j2s does not support
* a hashmap of unknown keys pointing to a known type. */
sync.rooms.invite = HashMapCreate();
sync.rooms.join = HashMapCreate();
/* invites */
invites = UserGetInvites(user, currBatch);
for (i = 0; i < ArraySize(invites); i++)
{
char *roomId = ArrayGet(invites, i);
InvitedRooms invited = { 0 };
HashMap *invitedObject;
invited.invite_state.events = ArrayCreate();
invitedObject = InvitedRoomsToJson(&invited);
JsonSet(
sync.rooms.invite,
JsonValueObject(invitedObject),
1, roomId
);
InvitedRoomsFree(&invited);
}
UserFreeList(invites);
/* Joins */
joins = UserGetJoins(user, currBatch);
for (i = 0; i < ArraySize(joins); i++)
{
char *roomId = ArrayGet(joins, i);
Array *el = UserGetEvents(user, currBatch, roomId);
size_t j;
Room *r = RoomLock(db, roomId);
HashMap *state = StateCurrent(r);
char *firstEvent = NULL;
JoinedRooms joined = { 0 };
HashMap *joinedObj;
char *type, *key, *id;
joined.timeline.events = ArrayCreate();
for (j = 0; j < ArraySize(el); j++)
{
char *event = ArrayGet(el, j);
HashMap *e = RoomEventFetch(r, event);
ClientEventWithoutRoomID rc = ClientfyEventSync(e);
ClientEventWithoutRoomID *c = Malloc(sizeof(*c));
memcpy(c, &rc, sizeof(*c));
JsonFree(e);
if (j == 0)
{
firstEvent = c->event_id;
}
ArrayAdd(joined.timeline.events, c);
}
joined.timeline.prev_batch = UserNewMessageToken(
user, roomId, firstEvent
);
/* TODO: Don't shove the entire state.
* That's a recipe for disaster, especially on large rooms. */
joined.state.events = ArrayCreate();
while (StateIterate(state, &type, &key, (void **) &id))
{
HashMap *e = RoomEventFetch(r, id);
StrippedStateEvent rs = StripStateEventSync(e);
StrippedStateEvent *s = Malloc(sizeof(*s));
memcpy(s, &rs, sizeof(*s));
JsonFree(e);
ArrayAdd(joined.state.events, s);
Free(type);
Free(key);
}
StateFree(state);
RoomUnlock(r);
UserFreeList(el);
joinedObj = JoinedRoomsToJson(&joined);
HashMapSet(sync.rooms.join, roomId, JsonValueObject(joinedObj));
JoinedRoomsFree(&joined);
}
UserFreeList(joins);
if (prevBatch)
{
UserDropSync(user, prevBatch);
nextBatch = UserInitSyncDiff(user);
UserFillSyncDiff(user, nextBatch);
}
sync.next_batch = nextBatch;
response = SyncResponseToJson(&sync);
SyncResponseFree(&sync);
finish:
UserUnlock(user);
(void) path;
return response;
}

View File

@ -37,6 +37,9 @@ ROUTE_IMPL(RouteVersions, path, argp)
(void) argp;
#define DECLARE_SPEC_VERSION(x) ArrayAdd(versions, JsonValueString(x))
DECLARE_SPEC_VERSION("v1.0");
DECLARE_SPEC_VERSION("v1.1");
DECLARE_SPEC_VERSION("v1.2");
DECLARE_SPEC_VERSION("v1.3");
DECLARE_SPEC_VERSION("v1.4");

View File

@ -26,16 +26,208 @@
#include <State.h>
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Array.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Sha.h>
#include <string.h>
#include <Room.h>
#include <Event.h>
#include <Room.h>
static HashMap *
StateResolveV1(Array * states)
int
V1Cmp(void *a, void *b)
{
(void) states;
return NULL;
HashMap *e1 = a, *e2 = b;
int64_t depth1, depth2;
depth1 =
JsonValueAsInteger(JsonGet(e1, 1, "depth"));
depth2 =
JsonValueAsInteger(JsonGet(e2, 1, "depth"));
if (depth1 > depth2)
{
return 1;
}
else if (depth1 < depth2)
{
return -1;
}
else
{
char *e1id =
JsonValueAsString(JsonGet(e1, 1, "event_id"));
char *e2id =
JsonValueAsString(JsonGet(e2, 1, "event_id"));
unsigned char *sha1 = Sha1(e1id);
unsigned char *sha2 = Sha1(e2id);
char *str1 = ShaToHex(sha1);
char *str2 = ShaToHex(sha2);
int ret = strcmp(str1, str2) * -1;
Free(str1);
Free(str2);
Free(sha1);
Free(sha2);
/* Descending */
return ret;
}
}
static HashMap *
StateResolveV1(Room * room, Array * states)
{
HashMap *R = HashMapCreate();
HashMap *conflicts = HashMapCreate();
Array *events = NULL, *types = NULL, *conflicting = NULL;
size_t i;
ssize_t j;
char *type, *key, *event_id;
for (i = 0; i < ArraySize(states); i++)
{
HashMap *state = ArrayGet(states, i);
char *tuple;
while (HashMapIterate(state, &tuple, (void **) &event_id))
{
if (HashMapGet(R, tuple))
{
Array *arr;
HashMap *hm;
/* Conflicts! */
HashMapDelete(R, tuple);
arr = HashMapGet(conflicts, tuple);
if (!arr)
{
arr = ArrayCreate();
}
hm = RoomEventFetch(room, event_id);
ArrayAdd(arr, hm);
HashMapSet(conflicts, tuple, arr);
}
else
{
/* Add to R */
HashMapSet(R, tuple, StrDuplicate(event_id));
}
}
}
/* R and conflicts are now configured */
types = ArrayCreate();
ArrayAdd(types, "m.room.power_levels");
ArrayAdd(types, "m.room.join_rules");
ArrayAdd(types, "m.room.member");
for (i = 0; i < ArraySize(types); i++)
{
char *t = ArrayGet(types, i);
HashMap *first;
Array *state_keys;
events = ArrayCreate();
while (StateIterate(conflicts, &type, &key, (void **) &conflicting))
{
if (StrEquals(type, t))
{
for (j = 0; j < (ssize_t) ArraySize(conflicting); j++)
{
HashMap *event = ArrayGet(conflicting, j);
ArrayAdd(events, event);
}
}
Free(type);
Free(key);
}
ArraySort(events, V1Cmp);
/* Add first event. */
first = ArrayDelete(events, 0);
StateSet(
R,
JsonValueAsString(JsonGet(first, 1, "type")),
JsonValueAsString(JsonGet(first, 1, "state_key")),
JsonValueAsString(JsonGet(first, 1, "event_id")));
JsonFree(first);
for (j = 0; j < (ssize_t) ArraySize(events); j++)
{
HashMap *event = ArrayGet(events, j);
PduV1 pdu;
char *msg;
PduV1FromJson(event, &pdu, &msg);
if (RoomAuthoriseEventV1(room, pdu, R))
{
StateSet(R, pdu.type, pdu.state_key, pdu.event_id);
}
else
{
PduV1Free(&pdu);
JsonFree(event);
break;
}
(void) msg;
PduV1Free(&pdu);
JsonFree(event);
}
ArrayFree(events);
/* Delete all elements within a key. */
state_keys = ArrayCreate();
while (StateIterate(conflicts, &type, &key, (void **) &event_id))
{
if (StrEquals(type, t))
{
ArrayAdd(state_keys, key);
}
Free(type);
}
for (j = 0; j < (ssize_t) ArraySize(state_keys); j++)
{
char *state_key = ArrayGet(state_keys, j);
StateSet(conflicts, t, state_key, NULL);
Free(state_key);
}
ArrayFree(state_keys);
}
ArrayFree(types);
while (StateIterate(conflicts, &type, &key, (void **) &conflicting))
{
ArraySort(conflicting, V1Cmp);
for (j = ArraySize(conflicting) - 1; j >= 0; j--)
{
HashMap *event = ArrayGet(events, j);
PduV1 pdu;
char *msg;
PduV1FromJson(event, &pdu, &msg);
if (RoomAuthoriseEventV1(room, pdu, R))
{
StateSet(R, pdu.type, pdu.state_key, pdu.event_id);
PduV1Free(&pdu);
break;
}
(void) msg;
PduV1Free(&pdu);
}
Free(type);
Free(key);
}
while (HashMapIterate(conflicts, &type, (void **) &conflicting))
{
for (i = 0; i < ArraySize(conflicting); i++)
{
JsonFree(ArrayGet(conflicting, i));
}
ArrayFree(conflicting);
}
HashMapFree(conflicts);
return R;
}
static HashMap *
@ -45,6 +237,18 @@ StateResolveV2(Array * states)
return NULL;
}
static HashMap *
StateFromPrevs(Room *room, Array *states)
{
switch (RoomVersionGet(room))
{
case 1:
return StateResolveV1(room, states);
default:
return StateResolveV2(states);
}
}
HashMap *
StateResolve(Room * room, HashMap * event)
{
@ -53,36 +257,253 @@ StateResolve(Room * room, HashMap * event)
Array *prevEvents;
HashMap *ret_state;
char *room_id, *event_id;
Db *db;
if (!room || !event)
{
return NULL;
}
/* TODO: Return cached state if it exists */
db = RoomGetDB(room);
room_id = JsonValueAsString(HashMapGet(event, "room_id"));
event_id = JsonValueAsString(HashMapGet(event, "event_id"));
if (DbExists(db, 4, "rooms", room_id, "state", event_id))
{
DbRef *ref = DbLock(db, 4,
"rooms", room_id, "state", event_id
);
ret_state = StateDeserialise(DbJson(ref));
DbUnlock(db, ref);
if (ret_state)
{
return ret_state;
}
/* If a DB error stops us from getting an existing state,
* recompute it. */
}
states = ArrayCreate();
if (!states)
{
return NULL;
}
prevEvents = HashMapGet(event, "prev_events");
prevEvents = JsonValueAsArray(HashMapGet(event, "prev_events"));
for (i = 0; i < ArraySize(prevEvents); i++)
{
HashMap *prevEvent = ArrayGet(prevEvents, i);
HashMap *prevEvent =
RoomEventFetch(room, JsonValueAsString(ArrayGet(prevEvents, i)));
HashMap *state = StateResolve(room, prevEvent);
/* TODO: Apply prevEvent to state if it is a state event */
if (HashMapGet(prevEvent, "state_key"))
{
StateSet(
state,
JsonValueAsString(HashMapGet(prevEvent, "type")),
JsonValueAsString(HashMapGet(prevEvent, "state_key")),
JsonValueAsString(HashMapGet(prevEvent, "event_id")));
}
ArrayAdd(states, state);
JsonFree(prevEvent);
}
ret_state = StateFromPrevs(room, states);
for (i = 0; i < ArraySize(states); i++)
{
HashMap *state = ArrayGet(states, i);
StateFree(state);
}
ArrayFree(states);
if (ret_state)
{
HashMap *json = StateSerialise(ret_state);
DbRef *ref = DbCreate(db, 4, "rooms", room_id, "state", event_id);
DbJsonSet(ref, json);
JsonFree(json);
DbUnlock(db, ref);
}
return ret_state;
}
HashMap *
StateCurrent(Room *room)
{
Array *prevEvents;
Array *states;
size_t i;
HashMap *ret;
if (!room)
{
return NULL;
}
prevEvents = RoomPrevEventsGet(room);
states = ArrayCreate();
for (i = 0; i < ArraySize(prevEvents); i++)
{
HashMap *event =
JsonValueAsObject(ArrayGet(prevEvents, i));
HashMap *state = StateResolve(room, event);
if (HashMapGet(event, "state_key"))
{
StateSet(
state,
JsonValueAsString(HashMapGet(event, "type")),
JsonValueAsString(HashMapGet(event, "state_key")),
JsonValueAsString(HashMapGet(event, "event_id")));
}
ArrayAdd(states, state);
}
switch (RoomVersionGet(room))
ret = StateFromPrevs(room, states);
for (i = 0; i < ArraySize(states); i++)
{
case 1:
return StateResolveV1(states);
default:
return StateResolveV2(states);
HashMap *state = ArrayGet(states, i);
StateFree(state);
}
ArrayFree(states);
return ret;
}
bool StateIterate(HashMap *state, char **type, char **key, void **event)
{
char *tuple;
bool ret;
if (!state || !type || !key || !event)
{
return false;
}
ret = HashMapIterate(state, &tuple, event);
if (ret)
{
tuple = StrDuplicate(tuple);
*(strchr(tuple, ',')) = '\0';
*type = tuple;
*key = StrDuplicate(tuple + strlen(tuple) + 1);
}
return ret;
}
char *
StateGet(HashMap *state, char *type, char *key)
{
char *full_string;
char *ret;
if (!state || !type || !key)
{
return NULL;
}
full_string = StrConcat(3, type, ",", key);
ret = HashMapGet(state, full_string);
Free(full_string);
return ret;
}
void
StateSet(HashMap *state, char *type, char *key, char *event)
{
char *full_string, *old;
if (!state || !type || !key)
{
return;
}
full_string = StrConcat(3, type, ",", key);
old = HashMapDelete(state, full_string);
if (old)
{
Free(old);
}
if (event)
{
HashMapSet(state, full_string, StrDuplicate(event));
}
Free(full_string);
}
void
StateFree(HashMap *state)
{
char *full;
char *event_id;
if (!state)
{
return;
}
while (HashMapIterate(state, &full, (void **) &event_id))
{
Free(event_id);
}
HashMapFree(state);
}
HashMap *
StateDeserialise(HashMap *json_state)
{
HashMap *raw_state;
char *state_type;
JsonValue *state_keys;
if (!json_state)
{
return NULL;
}
raw_state = HashMapCreate();
while (HashMapIterate(json_state, &state_type, (void **) &state_keys))
{
HashMap *state_keys_obj = JsonValueAsObject(state_keys);
char *state_key;
JsonValue *event_id;
while (HashMapIterate(state_keys_obj, &state_key, (void **) &event_id))
{
char *eid_string = JsonValueAsString(event_id);
char *key_name = StrConcat(3, state_type, ",", state_key);
HashMapSet(raw_state, key_name, StrDuplicate(eid_string));
Free(key_name);
}
}
return raw_state;
}
HashMap *
StateSerialise(HashMap *rawState)
{
HashMap *returned;
char *type, *key, *event;
if (!rawState)
{
return NULL;
}
returned = HashMapCreate();
while (StateIterate(rawState, &type, &key, (void **) &event))
{
JsonSet(returned, JsonValueString(event), 2, type, key);
Free(type);
Free(key);
}
return returned;
}

View File

@ -22,16 +22,20 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <Cytoplasm/Db.h>
#include <User.h>
#include <Cytoplasm/Util.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Sha.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Log.h>
#include <Parser.h>
#include <Room.h>
#include <string.h>
#include <pthread.h>
struct User
{
@ -42,6 +46,9 @@ struct User
char *deviceId;
};
static pthread_mutex_t pushLock;
static HashMap *pushTable = NULL;
bool
UserValidate(char *localpart, char *domain)
{
@ -108,7 +115,7 @@ UserLock(Db * db, char *name)
User *user = NULL;
DbRef *ref = NULL;
if (!UserExists(db, name))
if (!name || !UserExists(db, name))
{
return NULL;
}
@ -172,16 +179,22 @@ bool
UserUnlock(User * user)
{
bool ret;
Db *db;
DbRef *ref;
if (!user)
{
return false;
}
db = user->db;
ref = user->ref;
Free(user->name);
Free(user->deviceId);
ret = DbUnlock(user->db, user->ref);
ret = DbUnlock(db, ref);
user->db = NULL;
user->ref = NULL;
Free(user);
return ret;
@ -232,6 +245,9 @@ UserCreate(Db * db, char *name, char *password)
HashMapSet(json, "createdOn", JsonValueInteger(ts));
HashMapSet(json, "deactivated", JsonValueBoolean(false));
HashMapSet(json, "invites", JsonValueObject(HashMapCreate()));
HashMapSet(json, "joins", JsonValueObject(HashMapCreate()));
return user;
}
@ -945,3 +961,736 @@ UserIdFree(CommonID * id)
Free(id);
}
}
HashMap *
UserGetTransaction(User *user, char *transaction, char *path)
{
HashMap *devices;
if (!user || !transaction || !path)
{
return NULL;
}
devices = JsonValueAsObject(
HashMapGet(UserGetDevices(user), UserGetDeviceId(user))
);
return JsonDuplicate(JsonValueAsObject(
JsonGet(devices, 3, "transactions", path, transaction)
));
}
void
UserSetTransaction(User *user, char *transaction, char *path, HashMap *resp)
{
HashMap *devices;
if (!user || !transaction || !path || !resp)
{
return;
}
devices = JsonValueAsObject(
HashMapGet(UserGetDevices(user), UserGetDeviceId(user))
);
/* Overwrite the transaction */
JsonValueFree(JsonSet(
devices, JsonValueObject(JsonDuplicate(resp)),
3, "transactions", path, transaction
));
}
void
UserAddInvite(User *user, char *roomId)
{
HashMap *data;
HashMap *invites;
if (!user || !roomId)
{
return;
}
data = DbJson(user->ref);
invites = JsonValueAsObject(HashMapGet(data, "invites"));
JsonFree(HashMapSet(invites, roomId, JsonValueNull()));
}
void
UserRemoveInvite(User *user, char *roomId)
{
HashMap *data;
HashMap *invites;
if (!user || !roomId)
{
return;
}
data = DbJson(user->ref);
invites = JsonValueAsObject(HashMapGet(data, "invites"));
JsonFree(HashMapDelete(invites, roomId));
}
Array *
UserListInvites(User *user)
{
Array *arr;
HashMap *data;
HashMap *invites;
size_t i;
if (!user)
{
return NULL;
}
data = DbJson(user->ref);
invites = JsonValueAsObject(HashMapGet(data, "invites"));
arr = HashMapKeys(invites);
for (i = 0; i < ArraySize(arr); i++)
{
ArraySet(arr, i, StrDuplicate(ArrayGet(arr, i)));
}
return arr;
}
void
UserAddJoin(User *user, char *roomId)
{
HashMap *data;
HashMap *joins;
if (!user || !roomId)
{
return;
}
data = DbJson(user->ref);
joins = JsonValueAsObject(HashMapGet(data, "joins"));
if (!HashMapGet(joins, roomId))
{
JsonFree(HashMapSet(joins, roomId, JsonValueNull()));
}
UserNotifyUser(user);
}
void
UserRemoveJoin(User *user, char *roomId)
{
HashMap *data;
HashMap *joins;
if (!user || !roomId)
{
return;
}
data = DbJson(user->ref);
joins = JsonValueAsObject(HashMapGet(data, "joins"));
JsonFree(HashMapDelete(joins, roomId));
UserNotifyUser(user);
}
Array *
UserListJoins(User *user)
{
Array *arr;
HashMap *data;
HashMap *joins;
size_t i;
if (!user)
{
return NULL;
}
data = DbJson(user->ref);
joins = JsonValueAsObject(HashMapGet(data, "joins"));
arr = HashMapKeys(joins);
for (i = 0; i < ArraySize(arr); i++)
{
ArraySet(arr, i, StrDuplicate(ArrayGet(arr, i)));
}
return arr;
}
void
UserFreeList(Array *arr)
{
size_t i;
if (!arr)
{
return;
}
for (i = 0; i < ArraySize(arr); i++)
{
Free(ArrayGet(arr, i));
}
ArrayFree(arr);
}
char *
UserInitSyncDiff(User *user)
{
char *nextBatch;
DbRef *syncRef;
HashMap *data;
if (!user)
{
return NULL;
}
nextBatch = StrRandom(16);
syncRef = DbCreate(user->db, 4, "users", user->name, "sync", nextBatch);
if (!syncRef)
{
Free(nextBatch);
return NULL;
}
data = DbJson(syncRef);
HashMapSet(data, "nextBatch", JsonValueString(nextBatch));
HashMapSet(data, "invites", JsonValueArray(ArrayCreate()));
HashMapSet(data, "leaves", JsonValueArray(ArrayCreate()));
HashMapSet(data, "joins", JsonValueObject(HashMapCreate()));
HashMapSet(data, "creation", JsonValueInteger(UtilTsMillis()));
DbUnlock(user->db, syncRef);
return nextBatch;
}
void
UserPushInviteSync(User *user, char *roomId)
{
DbRef *syncRef;
HashMap *data;
Array *entries;
Array *invites;
size_t i;
if (!user || !roomId)
{
return;
}
entries = DbList(user->db, 3, "users", user->name, "sync");
for (i = 0; i < ArraySize(entries); i++)
{
char *entry = ArrayGet(entries, i);
syncRef = DbLock(user->db, 4, "users", user->name, "sync", entry);
data = DbJson(syncRef);
invites = JsonValueAsArray(HashMapGet(data, "invites"));
ArrayAdd(invites, JsonValueString(roomId));
DbUnlock(user->db, syncRef);
}
DbListFree(entries);
UserNotifyUser(user);
}
void
UserPushJoinSync(User *user, char *roomId)
{
DbRef *syncRef;
HashMap *data;
Array *entries;
HashMap *join;
size_t i;
if (!user || !roomId)
{
return;
}
entries = DbList(user->db, 3, "users", user->name, "sync");
for (i = 0; i < ArraySize(entries); i++)
{
char *entry = ArrayGet(entries, i);
HashMap *joinEntry;
syncRef = DbLock(user->db, 4, "users", user->name, "sync", entry);
data = DbJson(syncRef);
join = JsonValueAsObject(HashMapGet(data, "joins"));
/* TODO */
joinEntry = HashMapCreate();
HashMapSet(joinEntry, "timeline", JsonValueArray(ArrayCreate()));
if (!HashMapGet(join, roomId))
{
JsonFree(HashMapSet(join, roomId, JsonValueObject(joinEntry)));
}
else
{
JsonFree(joinEntry);
}
DbUnlock(user->db, syncRef);
}
DbListFree(entries);
UserNotifyUser(user);
}
void
UserPushEvent(User *user, HashMap *event)
{
DbRef *syncRef;
HashMap *data;
Array *entries;
HashMap *join;
size_t i;
char *roomId, *eventId;
if (!user || !event)
{
return;
}
roomId = JsonValueAsString(HashMapGet(event, "room_id"));
eventId = JsonValueAsString(HashMapGet(event, "event_id"));
UserPushJoinSync(user, roomId);
entries = DbList(user->db, 3, "users", user->name, "sync");
for (i = 0; i < ArraySize(entries); i++)
{
char *entry = ArrayGet(entries, i);
HashMap *joinEntry;
Array *timeline;
syncRef = DbLock(user->db, 4, "users", user->name, "sync", entry);
data = DbJson(syncRef);
join = JsonValueAsObject(HashMapGet(data, "joins"));
joinEntry = JsonValueAsObject(HashMapGet(join, roomId));
timeline = JsonValueAsArray(HashMapGet(joinEntry, "timeline"));
ArrayAdd(timeline, JsonValueString(eventId));
DbUnlock(user->db, syncRef);
}
DbListFree(entries);
UserNotifyUser(user);
}
void
UserDropSync(User *user, char *batch)
{
if (!user || !batch)
{
return;
}
DbDelete(user->db, 4, "users", user->name, "sync", batch);
}
Array *
UserGetInvites(User *user, char *batch)
{
DbRef *syncRef;
HashMap *data;
Array *keys;
size_t i;
if (!user || !batch)
{
return NULL;
}
syncRef = DbLock(user->db, 4, "users", user->name, "sync", batch);
if (!syncRef)
{
return NULL;
}
data = DbJson(syncRef);
keys = ArrayDuplicate(JsonValueAsArray(HashMapGet(data, "invites")));
for (i = 0; i < ArraySize(keys); i++)
{
char *str = JsonValueAsString(ArrayGet(keys, i));
ArraySet(keys, i, StrDuplicate(str));
}
DbUnlock(user->db, syncRef);
return keys;
}
void
UserFillSyncDiff(User *user, char *batch)
{
Array *joins;
size_t i;
DbRef *syncRef;
if (!user || !batch)
{
return;
}
joins = UserListJoins(user);
syncRef = DbLock(
user->db, 4, "users", user->name, "sync", batch
);
for (i = 0; i < ArraySize(joins); i++)
{
char *roomId = ArrayGet(joins, i);
HashMap *joinEntry;
HashMap *data = DbJson(syncRef);
HashMap *join = JsonValueAsObject(HashMapGet(data, "joins"));
Array *timeline = ArrayCreate();
Room *r = RoomLock(user->db, roomId);
Array *prevs = RoomPrevEventsGet(r);
size_t j;
for (j = 0; j < ArraySize(prevs); j++)
{
HashMap *e = JsonValueAsObject(ArrayGet(prevs, j));
/* TODO: Backfill the user a 'lil more. */
ArrayAdd(timeline, JsonValueDuplicate(HashMapGet(e, "event_id")));
}
RoomUnlock(r);
joinEntry = HashMapCreate();
HashMapSet(joinEntry, "timeline", JsonValueArray(timeline));
if (!HashMapGet(join, roomId))
{
JsonFree(HashMapSet(join, roomId, JsonValueObject(joinEntry)));
}
else
{
JsonFree(joinEntry);
}
}
UserFreeList(joins);
DbUnlock(user->db, syncRef);
}
Array *
UserGetJoins(User *user, char *batch)
{
Db *db;
DbRef *syncRef;
HashMap *data;
Array *keys;
size_t i;
if (!user || !batch)
{
return NULL;
}
db = user->db;
syncRef = DbLock(db, 4, "users", user->name, "sync", batch);
if (!syncRef)
{
return NULL;
}
data = DbJson(syncRef);
keys = HashMapKeys(JsonValueAsObject(HashMapGet(data, "joins")));
for (i = 0; i < ArraySize(keys); i++)
{
char *str = ArrayGet(keys, i);
ArraySet(keys, i, StrDuplicate(str));
}
DbUnlock(db, syncRef);
return keys;
}
Array *
UserGetEvents(User *user, char *batch, char *roomId)
{
DbRef *syncRef;
HashMap *data;
HashMap *joins;
Array *keys, *ret;
size_t i;
if (!user || !batch || !roomId)
{
return NULL;
}
syncRef = DbLock(user->db, 4, "users", user->name, "sync", batch);
if (!syncRef)
{
return NULL;
}
data = DbJson(syncRef);
joins = JsonValueAsObject(JsonGet(data, 2, "joins", roomId));
keys = (JsonValueAsArray(HashMapGet(joins, "timeline")));
ret = ArrayCreate();
for (i = 0; i < ArraySize(keys); i++)
{
char *str = JsonValueAsString(ArrayGet(keys, i));
ArrayAdd(ret, StrDuplicate(str));
}
DbUnlock(user->db, syncRef);
return ret;
}
char *
UserNewMessageToken(User *user, char *room, char *event)
{
DbRef *messageRef;
HashMap *json;
char *messageToken;
if (!user || !room || !event)
{
return NULL;
}
messageToken = StrRandom(16);
messageRef = DbCreate(user->db,
4, "users", user->name, "msg", messageToken
);
json = DbJson(messageRef);
HashMapSet(json, "room", JsonValueString(room));
HashMapSet(json, "from", JsonValueString(event));
DbUnlock(user->db, messageRef);
return messageToken;
}
Array *
UserFetchMessages(User *user, int n, char *token, char **next)
{
Array *messages = NULL;
Array *nexts = NULL;
DbRef *messageRef;
HashMap *json;
Room *room;
char *roomId;
size_t i;
bool limited = false;
bool dir = false;
if (!user || !token || n == 0)
{
return NULL;
}
if (n < 0)
{
n = -n;
dir = true;
}
messageRef = DbLock(user->db,
4, "users", user->name, "msg", token
);
json = DbJson(messageRef);
if (!messageRef)
{
/* Regenerate a new one */
return NULL;
}
roomId = JsonValueAsString(HashMapGet(json, "room"));
room = RoomLock(user->db, roomId);
/* TODO (very important): CHECK IF THE USER IS ABLE TO SEE
* HISTORY. THROUGHOUT THE STEPS HERE. */
if (!room)
{
DbUnlock(user->db, messageRef);
return NULL;
}
nexts = ArrayCreate();
messages = ArrayCreate();
/* A stack of elements to deal with the DAG. */
ArrayAdd(nexts,
StrDuplicate(JsonValueAsString(HashMapGet(json, "from")))
);
for (i = 0; i < (size_t) n && ArraySize(nexts); i++)
{
char *curr = ArrayDelete(nexts, ArraySize(nexts) - 1);
HashMap *event = RoomEventFetch(room, curr);
Array *prevEvents;
size_t j;
Free(curr);
/* Push event into our message list. */
ArrayAdd(messages, event);
prevEvents = JsonValueAsArray(HashMapGet(event, "prev_events"));
if (dir)
{
HashMap *unsign = JsonValueAsObject(HashMapGet(event, "unsigned"));
/* prevEvents is now nextEvents */
prevEvents = JsonValueAsArray(HashMapGet(unsign, "next_events"));
}
for (j = 0; j < ArraySize(prevEvents); j++)
{
char *prevEvent = JsonValueAsString(ArrayGet(prevEvents, j));
ArrayAdd(nexts, StrDuplicate(prevEvent));
}
if (ArraySize(prevEvents) == 0)
{
limited = true;
}
}
for (i = 0; i < ArraySize(nexts); i++)
{
Free(ArrayGet(nexts, i));
}
ArrayFree(nexts);
RoomUnlock(room);
if (next && !limited)
{
HashMap *lastMessage = ArrayGet(messages, ArraySize(messages) - 1);
char *eId = JsonValueAsString(HashMapGet(lastMessage, "event_id"));
*next = UserNewMessageToken(user, roomId, eId);
}
DbUnlock(user->db, messageRef);
for (i = 0; i < ArraySize(messages); i++)
{
HashMap *e = ArrayGet(messages, i);
ArraySet(messages, i, JsonValueObject(e));
}
return messages;
}
void
UserFreeMessageToken(User *user, char *token)
{
if (!user || !token)
{
return;
}
DbDelete(user->db,
4, "users", user->name, "msg", token
);
}
void
UserCleanTemporaryData(User *user)
{
Array *list;
size_t i;
if (!user)
{
return;
}
list = DbList(user->db, 3, "users", user->name, "msg");
for (i = 0; i < ArraySize(list); i++)
{
char *token = ArrayGet(list, i);
UserFreeMessageToken(user, token);
}
DbListFree(list);
list = DbList(user->db, 3, "users", user->name, "sync");
for (i = 0; i < ArraySize(list); i++)
{
char *token = ArrayGet(list, i);
if (UserIsSyncOld(user, token))
{
UserDropSync(user, token);
}
}
DbListFree(list);
}
bool
UserIsSyncOld(User *user, char *token)
{
DbRef *ref;
HashMap *map;
int64_t dt;
if (!user || !token)
{
return false;
}
ref = DbLock(user->db, 4, "users", user->name, "sync", token);
map = DbJson(ref);
dt = UtilTsMillis() - JsonValueAsInteger(HashMapGet(map, "creation"));
DbUnlock(user->db, ref);
return dt > (5 * 60 * 1000); /* 5-minutes of timeout. */
}
bool
UserSyncExists(User *user, char *sync)
{
if (!user || !sync)
{
return false;
}
return DbLock(user->db, 4, "users", user->name, "sync", sync);
}
extern void
UserInitialisePushTable(void)
{
if (pushTable)
{
return;
}
pthread_mutex_init(&pushLock, NULL);
pthread_mutex_lock(&pushLock);
pushTable = HashMapCreate();
pthread_mutex_unlock(&pushLock);
}
void
UserNotifyUser(User *user)
{
if (!user || !pushTable)
{
return;
}
pthread_mutex_lock(&pushLock);
HashMapSet(pushTable, user->name, user->name);
pthread_mutex_unlock(&pushLock);
}
bool
UserGetNotification(char *user)
{
bool ret;
if (!user || !pushTable)
{
return false;
}
pthread_mutex_lock(&pushLock);
ret = !!HashMapGet(pushTable, user);
HashMapDelete(pushTable, user);
pthread_mutex_unlock(&pushLock);
return ret;
}
void
UserDestroyPushTable(void)
{
if (!pushTable)
{
return;
}
pthread_mutex_lock(&pushLock);
HashMapFree(pushTable);
pushTable = NULL;
pthread_mutex_unlock(&pushLock);
pthread_mutex_destroy(&pushLock);
}

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 hexstream stored on the heap,
* which will need to be freed with
* .Fn Free .
*/
extern unsigned char * CanonicalJsonHash(HashMap *);
/**
* Encode a JSON value following the rules of Canonical JSON.
* See the documentation for

View File

@ -41,6 +41,10 @@
#include <Cytoplasm/Db.h>
#include <Schema/RoomCreateRequest.h>
#include <Schema/PduV1.h>
#include <Parser.h>
#include <User.h>
/**
* The functions in this API operate on an opaque structure.
@ -51,7 +55,7 @@ typedef struct Room Room;
* Create a new room in the given database using the given
* RoomCreateRequest.
*/
extern Room * RoomCreate(Db *, RoomCreateRequest *);
extern Room * RoomCreate(Db *, User *, RoomCreateRequest *, ServerPart);
/**
* Lock the existing room in the specified database,
@ -63,6 +67,11 @@ extern Room * RoomCreate(Db *, RoomCreateRequest *);
*/
extern Room * RoomLock(Db *, char *);
/**
* Returns the database structure a room is tied to.
*/
extern Db * RoomGetDB(Room *);
/**
* Unlock a room handle, returning it to the database.
* This function returns the result of calling
@ -96,6 +105,13 @@ extern int RoomVersionGet(Room *);
* client events.
*/
extern HashMap * RoomStateGet(Room *);
/**
* Resolves the room's state before a specific point,
* (with the event hashmap taking priority),
* like
* .Fn RoomStateGet .
*/
extern HashMap * RoomStateGetID(Room *, char *);
/**
* Get a list of the most recent events in the
@ -128,4 +144,94 @@ extern int RoomPrevEventsSet(Room *, Array *);
*/
extern HashMap * RoomEventSend(Room *, HashMap *);
/**
* Sends an invite to a user in a room, and tries
* to notify such user of it.
*/
extern void RoomSendInvite(User *, bool, char *, Room *);
/**
* Fetch a single event's PDU in a room into an
* hashmap, given an event ID, from the database
* if possible, or otherwise fetched from a remote
* homeserver participating in the room.
*/
extern HashMap * RoomEventFetch(Room *, char *);
/**
* Strips all the fields not required in a
* Matrix ClientEvent from a PDU object.
*/
extern HashMap * RoomEventClientify(HashMap *);
/**
* Verifies whenever an event(as a PDUv1) is
* authorised by a room.
*/
extern bool RoomAuthoriseEventV1(Room *, PduV1, HashMap *);
/**
* Gets the room's creator as a ServerPart. This value should
* not be freed, as it lives alongside the room itself
*/
extern ServerPart RoomGetCreator(Room *);
/**
* Puts a PDUv1 into the event list, while updating the leaf
* list.
*/
extern bool RoomAddEventV1(Room *, PduV1);
/**
* Creates a barebones JSON object to be sent to
* .Fn RoomEventFetch .
*/
extern HashMap * RoomEventCreate(char *, char *, char *, HashMap *);
/**
* Computes an approximation of the PDU depth by looking at
* the leaves stored in the room data.
*/
extern uint64_t RoomGetDepth(Room *);
/**
* Tries to find an alias from room alias to an ID stored
* on the heap, or NULL if it does not exist.
*/
extern char * RoomResolveAlias(Db *, char *);
/**
* Tries to resolve a list of aliases from a room ID into
* an array of strings stored on the heap.
*/
extern Array * RoomReverseAlias(Db *, char *);
/**
* Frees the array returned by
* .Fn RoomReverseAlias .
*/
extern void RoomFreeReverse(Array *);
/**
* Checks whenever a room contains a specific user.
*/
extern bool RoomContainsUser(Room *, char *);
/**
* Checks whenever an user can join a specific room,
* given it's permissions.
*/
extern bool RoomCanJoin(Room *, char *);
/**
* Makes a local user join a room, and returns true if
* the room was joined.
*/
extern bool RoomJoin(Room *, User *);
/**
* Adds or overwrites a room alias.
*/
extern void RoomAddAlias(Db *, char *, char *, char *, char *);
#endif /* TELODENDRIA_ROOM_H */

View File

@ -100,6 +100,14 @@ ROUTE(RouteConfig);
ROUTE(RoutePrivileges);
ROUTE(RouteCreateRoom);
ROUTE(RouteSendEvent);
ROUTE(RouteSendState);
ROUTE(RouteJoinRoom);
ROUTE(RouteJoinRoomAlias);
ROUTE(RouteFetchEvent);
ROUTE(RouteJoinedRooms);
ROUTE(RouteSync);
ROUTE(RouteMessages);
ROUTE(RouteAliasDirectory);
ROUTE(RouteRoomAliases);
@ -107,7 +115,6 @@ ROUTE(RouteRoomAliases);
ROUTE(RouteAdminDeactivate);
ROUTE(RouteAdminTokens);
#undef ROUTE
#endif

View File

@ -47,11 +47,45 @@ extern char *StateGet(HashMap *, char *, char *);
/**
* Set a state tuple to a value.
*/
extern char *StateSet(HashMap *, char *, char *, char *);
extern void StateSet(HashMap *, char *, char *, char *);
/**
* Iterates through a statemap, with (type, key) -> event.
* The type and keys are stored on the heap, and will need
* to be freed.
* This function behaves like
* .Fn HashMapIterate .
*/
extern bool StateIterate(HashMap *, char **, char **, void **);
/**
* Compute the room state before the specified event was sent.
*/
extern HashMap * StateResolve(Room *, HashMap *);
/**
* Computes the current state from the room's leaves.
*/
extern HashMap * StateCurrent(Room *);
/**
* Frees an entire state table from the heap.
*/
extern void StateFree(HashMap *);
/**
* Deserialises a state map from JSON to the internal format
* used by this API.
*
* The returned value is independent from the JSON format,
* and should be freed with
* .Fn StateFree .
*/
extern HashMap * StateDeserialise(HashMap *);
/**
* Serialises a state map from the internal format to JSON
* used for the database, for example
*/
extern HashMap * StateSerialise(HashMap *);
#endif /* TELODENDRIA_STATE_H */

View File

@ -91,6 +91,7 @@ typedef struct UserLoginInfo
char *refreshToken;
} UserLoginInfo;
/**
* Take a localpart and domain as separate parameters and validate them
* against the rules of the Matrix specification. The reasion the
@ -303,9 +304,181 @@ extern int UserDecodePrivilege(const char *);
*/
extern CommonID * UserIdParse(char *, char *);
/**
* Gets the reply sent to the user from a transaction ID, and an opaque
* ""path"" ID, which is unique per route.
*/
extern HashMap * UserGetTransaction(User *, char *, char *);
/**
* Stores a transaction for a path with a given response JSON.
*/
extern void UserSetTransaction(User *, char *, char *, HashMap *);
/**
* Puts a room (indexed by room ID) in a user's invite list.
*/
extern void UserAddInvite(User *, char *);
/**
* Removes a room from the user's invite list.
*/
extern void UserRemoveInvite(User *, char *);
/**
* Lists all the rooms a user is invited to into an array of
* strings(room ID) to be freed by
* .Fn UserFreeInvites .
*/
extern Array * UserListInvites(User *);
/**
* Puts a room (indexed by room ID) in a user's join list.
*/
extern void UserAddJoin(User *, char *);
/**
* Removes a room from the user's join list.
*/
extern void UserRemoveJoin(User *, char *);
/**
* Lists all the rooms a user has joined into an array of
* strings(room ID) to be freed by
* .Fn UserFreeJoins .
*/
extern Array * UserListJoins(User *);
/**
* Frees a join/invite list as created by
* .Fn UserListJoins
* or
* .Fn UserListInvites .
*/
extern void UserFreeList(Array *);
/**
* Frees the user's common ID and the memory allocated for it.
*/
extern void UserIdFree(CommonID *);
/**
* Initialises a sync diff table, and returns a next_batch parameter,
* which is stored on the heap.
*/
extern char * UserInitSyncDiff(User *);
/**
* Fills a sync table with initial sync information
*/
extern void UserFillSyncDiff(User *, char *);
/**
* Pushes an invite onto all sync diff tables.
*/
extern void UserPushInviteSync(User *, char *);
/**
* Pushes a join onto all sync diff tables.
*/
extern void UserPushJoinSync(User *, char *);
/**
* Pushes an event (ID) into every diff table of a user.
*/
extern void UserPushEvent(User *, HashMap *);
/**
* Shows the invite list(as a room ID table) for an user
* and a specified diff table, to be freed by
* .Fn UserFreeList .
*/
extern Array * UserGetInvites(User *, char *);
/**
* Shows a list of rooms for an user and a specified diff
* table, to be freed by
* .Fn UserFreeList .
*/
extern Array * UserGetJoins(User *, char *);
/**
* Get a list of event IDs for a diff table(and room ID),
* to be freed by
* .Fn UserFreeList .
*/
extern Array * UserGetEvents(User *, char *, char *);
/**
* Drops a sync diff, denoted by it's previous batch ID, if it
* exists.
*/
extern void UserDropSync(User *, char *);
/**
* Verifies if the 'sync' data is considered old, and can be
* reasonably removed from the database.
*/
extern bool UserIsSyncOld(User *, char *);
/**
* Verifies if a sync diff exists.
*/
extern bool UserSyncExists(User *, char *);
/**
* Creates a new "message token" start from a room and event ID,
* given a specified direction(with false<=>'b' and true<=>'f')
* to be used by /messages.
*/
extern char * UserNewMessageToken(User *, char *, char *);
/**
* Grabs events from a message token(with the correct direction)
* into an array of HashMaps(which store PDU objects).
* If the string pointer is not NULL, this function sets its
* value to a new message token(which is stored on the heap),
* if and only if, there are any new events to retrieve.
*
* If the counter is negative, then it is treated as a 'f',
* otherwise, it is treated as 'b'.
*/
extern Array * UserFetchMessages(User *, int, char *, char **);
/**
* Deletes a "message token".
*/
extern void UserFreeMessageToken(User *, char *);
/**
* Deletes temporary data about a specific user.
*/
extern void UserCleanTemporaryData(User *);
/**
* Initialise a temporary sync table to signal any /sync changes.
* This should be paired with a call to
* .Fn UserDestroyPushTable .
*/
extern void UserInitialisePushTable(void);
/**
* Notifies the user of a sync update.
*/
extern void UserNotifyUser(User *);
/**
* Verifies if the user has been notified, and if it is, then
* removes the notification
*/
extern bool UserGetNotification(char *);
/**
* Destroys the temporary push table created by
* .Fn UserInitialisePushTable .
*/
extern void UserDestroyPushTable(void);
#endif /* TELODENDRIA_USER_H */