diff --git a/src/AS.c b/src/AS.c index 40c41d2..9177389 100644 --- a/src/AS.c +++ b/src/AS.c @@ -24,7 +24,6 @@ ASVerifyRequest(ParseeHttpArg *arg) if (!authorisation || strncmp(authorisation, "Bearer ", 7)) { - Log(LOG_INFO, "Bad auth %s", authorisation); HttpResponseStatus(arg->ctx, HTTP_FORBIDDEN); ret = MatrixCreateError("M_MISSING_TOKEN", "No 'hs_token' given in."); goto end; @@ -42,7 +41,7 @@ end: } void -ASAuthenticateRequest(ParseeConfig *data, HttpClientContext *ctx) +ASAuthenticateRequest(const ParseeConfig *data, HttpClientContext *ctx) { char *bearer; if (!data || !ctx) @@ -55,7 +54,7 @@ ASAuthenticateRequest(ParseeConfig *data, HttpClientContext *ctx) Free(bearer); } bool -ASRegisterUser(ParseeConfig *conf, char *user) +ASRegisterUser(const ParseeConfig *conf, char *user) { HttpClientContext *ctx = NULL; HashMap *json = NULL; @@ -100,7 +99,6 @@ ASPing(const ParseeConfig *conf) return; } - Log(LOG_NOTICE, "Pinging..."); path = StrConcat(3, "/_matrix/client/v1/appservice/", "Parsee%20XMPP", @@ -118,14 +116,13 @@ ASPing(const ParseeConfig *conf) JsonFree(json); } void -ASJoin(ParseeConfig *conf, char *id, char *masquerade) +ASJoin(const ParseeConfig *conf, char *id, char *masquerade) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path; if (!conf || !id || !masquerade) { - Log(LOG_ERR, "Bad values %p %p", conf, id); return; } @@ -134,7 +131,6 @@ ASJoin(ParseeConfig *conf, char *id, char *masquerade) "user_id=", masquerade ); - Log(LOG_INFO, "%s", path); ctx = ParseeCreateRequest( conf, HTTP_POST, path @@ -148,40 +144,29 @@ ASJoin(ParseeConfig *conf, char *id, char *masquerade) JsonFree(json); } void -ASSend(ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) +ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) { HttpClientContext *ctx = NULL; - HashMap *json = NULL, *params_obj; - Stream *s; char *path, *params; char *txn; - if (!conf || !id || !type || !c) + if (!conf || !id || !type || !user || !c) { return; } txn = StrRandom(16); - params_obj = HashMapCreate(); - if (user) - { - HashMapSet(params_obj, "user_id", user); - } - params = HttpParamEncode(params_obj); - HashMapFree(params_obj); - path = StrConcat(8, + path = StrConcat(9, "/_matrix/client/v3/rooms/", id, "/send/", type, "/", txn, "?", - params + "user_id=", user ); - Log(LOG_INFO, "Sending %s", path); - Free(params); Free(txn); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); - json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); - Log(LOG_INFO, "%d", ParseeSetRequestJSON(ctx, c)); + ParseeSetRequestJSON(ctx, c); + HttpClientContextFree(ctx); JsonFree(c); } diff --git a/src/HttParsee.c b/src/HttParsee.c index f3ee005..d6fd86b 100644 --- a/src/HttParsee.c +++ b/src/HttParsee.c @@ -61,7 +61,7 @@ ParseeRequest(HttpServerContext *ctx, void *argp) } HttpClientContext * -ParseeCreateRequest(ParseeConfig *conf, HttpRequestMethod meth, char *path) +ParseeCreateRequest(const ParseeConfig *conf, HttpRequestMethod meth, char *path) { HttpClientContext *ctx; if (!conf || !path) diff --git a/src/Main.c b/src/Main.c index 13867a8..929f80b 100644 --- a/src/Main.c +++ b/src/Main.c @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -10,6 +11,7 @@ #include static HttpServer *server = NULL; +static pthread_t xmpp_thr; static void SignalHandler(int signal) { @@ -26,6 +28,7 @@ SignalHandler(int signal) return; } HttpServerStop(server); + pthread_cancel(xmpp_thr); break; } } @@ -59,7 +62,6 @@ Main(void) parsee_conf->shared_comp_secret ); } - Log(LOG_INFO, "HS token: %s", parsee_conf->hs_token); ASRegisterUser(parsee_conf, parsee_conf->sender_localpart); @@ -70,6 +72,12 @@ Main(void) conf.handlerArgs = ParseeInitData(jabber); conf.handler = ParseeRequest; + if (pthread_create(&xmpp_thr, NULL, ParseeXMPPThread, conf.handlerArgs)) + { + Log(LOG_ERR, "Couldn't start XMPP listener thread."); + /* TODO: Die */ + } + sigAction.sa_handler = SignalHandler; sigfillset(&sigAction.sa_mask); sigAction.sa_flags = SA_RESTART; diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 116d65f..bd28394 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -15,6 +15,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) char *state_key = GrabString(event, 1, "state_key"); char *membership = GrabString(event, 2, "content", "membership"); char *room_id = GrabString(event, 1, "room_id"); + char *sender = GrabString(event, 1, "sender"); const ParseeConfig *conf = data->config; Log(LOG_INFO, "Membership '%s'->'%s'", state_key, membership); @@ -23,28 +24,22 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) DbRef *ref; HashMap *json; char *jid; - Log(LOG_INFO, "Looks like %s was invited to %s", - state_key, - room_id - ); ASJoin(conf, room_id, state_key); - ref = DbCreate(data->db, 3, "rooms", room_id, "data"); - json = DbJson(ref); - Log(LOG_INFO, "Grabbing JID"); jid = ParseeDecodeLocalJID(conf, state_key); - Log(LOG_INFO, "JID: %s", jid); - + ref = DbCreate(data->db, 3, "rooms", room_id, "data"); + json = DbJson(ref); HashMapSet(json, "is_direct", JsonValueBoolean(true)); HashMapSet(json, "xmpp_user", JsonValueString(jid)); + DbUnlock(data->db, ref); + ParseePushDMRoom(data, sender, jid, room_id); /* Pretend everything is a dm, ignoring is_direct */ if (jid) { Free(jid); } - DbUnlock(data->db, ref); } } static void @@ -59,9 +54,16 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *id = GrabString(event, 1, "room_id"); char *sender = GrabString(event, 1, "sender"); + if (ParseeIsPuppet(data->config, sender)) + { + Log(LOG_INFO, "Do not bridge the puppet"); + return; + } + ref = DbLock(data->db, 3, "rooms", id, "data"); json = DbJson(ref); + if (JsonValueAsBoolean(HashMapGet(json, "is_direct"))) { char *user = GrabString(json, 1, "xmpp_user"); @@ -85,11 +87,6 @@ ParseeEventHandler(ParseeData *data, HashMap *event) return; } - Log(LOG_INFO, "Event by '%s', with type '%s'", - JsonValueAsString(HashMapGet(event, "sender")), - JsonValueAsString(HashMapGet(event, "type")) - ); - event_type = GrabString(event, 1, "type"); if (StrEquals(event_type, "m.room.member")) { diff --git a/src/ParseeUser.c b/src/ParseeUser.c index 949f5a1..2df2e3b 100644 --- a/src/ParseeUser.c +++ b/src/ParseeUser.c @@ -1,9 +1,13 @@ #include #include +#include #include -#include +#include + #include +#include +#include bool ParseeIsPuppet(const ParseeConfig *conf, char *user) @@ -99,6 +103,54 @@ ParseeDecodeLocalJID(const ParseeConfig *c, char *mxid) /* Until the ':', data_start now is an encoded JID */ return DecodeJID(data_start, ':'); } + +char * +ParseeEncodeJID(const ParseeConfig *c, char *jid) +{ + char *ret, *tmp; + size_t i; + if (!c || !jid) + { + return NULL; + } + + ret = StrConcat(2, c->namespace_base, "_l_"); + for (i = 0; i < strlen(jid); i++) + { + const char *HEX = "0123456789abcdef"; + char cpy = jid[i]; + char cs[4] = { 0 }; + cs[0] = cpy; + if (*cs == '/') + { + /* RID: Break everything and die. */ + break; + } + if (islower(*cs) || isalpha(*cs) || *cs == '_' || + *cs == '=' || *cs == '-' || *cs == '/' || + *cs == '+' || *cs == '.') + { + tmp = ret; + ret = StrConcat(2, ret, cs); + Free(tmp); + continue; + } + + /* Hex encode everything */ + cs[0] = '='; + cs[1] = HEX[(cpy >> 4) & 0xF]; + cs[2] = HEX[(cpy >> 0) & 0xF]; + tmp = ret; + ret = StrConcat(2, ret, cs); + Free(tmp); + } + tmp = ret; + ret = StrConcat(4, "@", ret, ":", c->homeserver_host); + Free(tmp); + + return ret; +} + char * ParseeGetLocal(char *mxid) { @@ -129,6 +181,8 @@ ParseeGetLocal(char *mxid) return cpy; } + +/* TODO: More robust system */ char * ParseeEncodeMXID(char *mxid) { @@ -155,3 +209,119 @@ ParseeEncodeMXID(char *mxid) return ret; } +char * +ParseeDecodeMXID(char *mxid) +{ + char *ret; + size_t i; + if (!mxid) + { + return NULL; + } + ret = Malloc(strlen(mxid) + 1); + for (i = 0; i < strlen(mxid) + 1; i++) + { + char src = mxid[i]; + if (src == '%') + { + src = '@'; + } + else if (src == '=') + { + src = ':'; + } + else if (src == '@') + { + ret[i] = '\0'; + break; + } + ret[i] = src; + } + + return ret; +} +char * +ParseeGetDMID(char *mxid, char *jid) +{ + char *concat, *sha; + unsigned char *raw; + if (!mxid || !jid) + { + return NULL; + } + + jid = ParseeTrimJID(jid); + concat = StrConcat(2, mxid, jid); + raw = Sha1(concat); + sha = ShaToHex(raw); + + Free(concat); + Free(raw); + Free(jid); + + return sha; +} +char * +ParseeFindDMRoom(ParseeData *data, char *mxid, char *jid) +{ + DbRef *ref; + HashMap *j; + char *room, *dmid; + if (!data || !mxid || !jid) + { + return NULL; + } + dmid = ParseeGetDMID(mxid, jid); + ref = DbLock(data->db, 2, "users", dmid); + j = DbJson(ref); + + room = StrDuplicate(JsonValueAsString(HashMapGet(j, "room"))); + + DbUnlock(data->db, ref); + Free(dmid); + return room; +} + +void +ParseePushDMRoom(ParseeData *d, char *mxid, char *jid, char *r) +{ + DbRef *ref; + HashMap *j; + char *dmid; + if (!d || !mxid || !jid || !r) + { + return; + } + dmid = ParseeGetDMID(mxid, jid); + ref = DbCreate(d->db, 2, "users", dmid); + j = DbJson(ref); + + HashMapSet(j, "room", JsonValueString(r)); + + DbUnlock(d->db, ref); + Free(dmid); + return; +} + +char * +ParseeTrimJID(char *jid) +{ + char *ret; + size_t i; + if (!jid) + { + return NULL; + } + + ret = StrDuplicate(jid); + for (i = 0; i < strlen(ret); i++) + { + if (ret[i] == '/') + { + ret[i] = '\0'; + break; + } + } + + return ret; +} diff --git a/src/Routes/Transactions.c b/src/Routes/Transactions.c index b527218..7987f50 100644 --- a/src/Routes/Transactions.c +++ b/src/Routes/Transactions.c @@ -13,11 +13,9 @@ RouteHead(RouteTxns, arr, argp) Array *events; size_t i; - Log(LOG_INFO, "Caught one!"); response = ASVerifyRequest(args); if (response) { - Log(LOG_INFO, ":("); goto end; } if (HttpRequestMethodGet(args->ctx) != HTTP_PUT) @@ -30,7 +28,6 @@ RouteHead(RouteTxns, arr, argp) goto end; } - Log(LOG_INFO, "Caught a decent one!"); RequestJSON(); /* TODO: Do a thing with these. */ @@ -44,7 +41,6 @@ RouteHead(RouteTxns, arr, argp) /* TODO: Store TXN ID somewhere so that we can commit * "Epic Matrix Idempotency" */ - Log(LOG_INFO, "OK!"); response = HashMapCreate(); end: JsonFree(request); diff --git a/src/XML/Parser.c b/src/XML/Parser.c index 988c2bd..99405b8 100644 --- a/src/XML/Parser.c +++ b/src/XML/Parser.c @@ -1,9 +1,5 @@ #include -#include - -/* TODO: The rest of all that. */ - XMLElement * XMLDecode(Stream *stream, bool autofree) { @@ -27,12 +23,12 @@ XMLDecode(Stream *stream, bool autofree) stack = ArrayCreate(); while ((event = XMLCrank(lexer)) && (!ret || ArraySize(stack))) { + bool flag = false; switch (event->type) { case XML_LEXER_STARTELEM: /* Create a new element that will populated. */ top = XMLCreateTag(event->element); - Log(LOG_INFO, "<%s>", top->name); XMLAddChild(peek(), top); while (HashMapIterate(event->attrs, &key, (void **) &val)) { @@ -50,7 +46,6 @@ XMLDecode(Stream *stream, bool autofree) /* Create a new element that will populated. */ top = XMLCreateTag(event->element); XMLAddChild(peek(), top); - Log(LOG_INFO, "<%s />", top->name); while (HashMapIterate(event->attrs, &key, (void **) &val)) { XMLAddAttr(top, key, val); @@ -65,11 +60,25 @@ XMLDecode(Stream *stream, bool autofree) /* Fallthrough */ case XML_LEXER_ENDELEM: /* Pop out an element out of the DOM. */ - Log(LOG_INFO, ""); pop(); + if (!ArraySize(stack)) + { + XMLFreeEvent(event); + event = NULL; + flag = true; + break; + } + break; + case XML_LEXER_DATA: + top = XMLCreateText(event->data); + XMLAddChild(peek(), top); break; default: break; } + if (flag) + { + break; + } XMLFreeEvent(event); event = NULL; } diff --git a/src/XML/SAX.c b/src/XML/SAX.c index 56d6b94..2a12fa1 100644 --- a/src/XML/SAX.c +++ b/src/XML/SAX.c @@ -658,8 +658,6 @@ XMLParseAttQuote(XMLexer *lexer) point = XMLInitialiseBuffer(lexer); - /* TODO: My Prosody is actually trolling me. - * GIVE ME A FUCKING STREAM ID YOU RETARD. */ while ((c = XMLGetc(lexer))) { if (!IsNormalQ(c)) diff --git a/src/XMPPThread.c b/src/XMPPThread.c new file mode 100644 index 0000000..1fedc4d --- /dev/null +++ b/src/XMPPThread.c @@ -0,0 +1,75 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include + +void * +ParseeXMPPThread(void *argp) +{ + ParseeData *args = argp; + XMPPComponent *jabber = args->jabber; + XMLElement *stanza = NULL; + while (true) + { + /* TODO: pthread cancelation points */ + XMLElement *body = NULL; + XMLElement *data = NULL; + char *to, *room, *from, *from_matrix; + + /* Decoding XML is blocking, which will cause memory issues when we + * want to murder this thread. + * We could ping the server, and die on a "response" stanza, however. + */ + stanza = XMLDecode(jabber->stream, false); + if (!stanza) + { + ASSend( + args->config, "!jdHnoKgHCm51ujbw:ari.lt", "_parsee_bridge", + "m.room.message", MatrixCreateNotice("Hi.") + ); + continue; + } + if (StrEquals(stanza->name, "message")) + { + size_t i; + for (i = 0; i < ArraySize(stanza->children); i++) + { + XMLElement *child = ArrayGet(stanza->children, i); + if (StrEquals(child->name, "body")) + { + body = child; + break; + } + } + if (!body) + { + XMLFreeElement(stanza); + continue; + } + to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); + from = HashMapGet(stanza->attrs, "from"); + from_matrix = ParseeEncodeJID(args->config, from); + room = ParseeFindDMRoom(args, to, from); + data = ArrayGet(body->children, 0); + + /* TODO: Manage that out. $[to] corresponds to a Matrix + * user, which we need to find the */ + ASSend( + args->config, room, from_matrix, + "m.room.message", MatrixCreateNotice(data->data) + ); + Free(from_matrix); + Free(room); + Free(to); + } + XMLFreeElement(stanza); + } + + return NULL; +} diff --git a/src/include/AS.h b/src/include/AS.h index f480f47..6f82822 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -13,21 +13,21 @@ extern HashMap * ASVerifyRequest(ParseeHttpArg *); /* Authenticates a request with the correct as_token. * It does not send the request, however. */ -extern void ASAuthenticateRequest(ParseeConfig *, HttpClientContext *); +extern void ASAuthenticateRequest(const ParseeConfig *, HttpClientContext *); /* Registers an user through the Application Service API. Returns * true if the user was created. */ -extern bool ASRegisterUser(ParseeConfig *, char *); +extern bool ASRegisterUser(const ParseeConfig *, char *); /* Pings the homeserver to get attention. */ extern void ASPing(const ParseeConfig *); /* Joins a room from an ID and a given user we want to masquerade * as. */ -extern void ASJoin(ParseeConfig *, char *, char *); +extern void ASJoin(const ParseeConfig *, char *, char *); /* Sends a message event with a specific type and body. * Said body is freed during the function's execution. */ -extern void ASSend(ParseeConfig *, char *, char *, char *, HashMap *); +extern void ASSend(const ParseeConfig *, char *, char *, char *, HashMap *); #endif diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 0b4c92c..36ca8dd 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -62,10 +62,7 @@ extern void ParseeConfigFree(void); extern ParseeData * ParseeInitData(XMPPComponent *); extern void ParseeFreeData(ParseeData *); -/* HTTP server handler for Parsee, takes in a config. */ -extern void ParseeRequest(HttpServerContext *, void *); - -extern HttpClientContext * ParseeCreateRequest(ParseeConfig *, HttpRequestMethod, char *); +extern HttpClientContext * ParseeCreateRequest(const ParseeConfig *, HttpRequestMethod, char *); /* Sends headers, and writes the JSON object. */ extern HttpStatus ParseeSetRequestJSON(HttpClientContext *, HashMap *); @@ -79,9 +76,36 @@ extern bool ParseeIsPuppet(const ParseeConfig *, char *); /* Decodes a local JID for a user into a string. */ extern char * ParseeDecodeLocalJID(const ParseeConfig *, char *); +/* Encodes a JID into a Parsee localpart */ +extern char * ParseeEncodeJID(const ParseeConfig *, char *); + /* Gets the localpart of a MXID */ extern char * ParseeGetLocal(char *); /* Encodes an MXID to a valid Jabber ID head */ extern char * ParseeEncodeMXID(char *); + +/* Decodes a Jabber ID head into a valid MXID */ +extern char * ParseeDecodeMXID(char *); + + +/* HTTP server handler for Parsee, takes in a config. */ +extern void ParseeRequest(HttpServerContext *, void *); + +/* A pthread callback used for listening to a component */ +extern void * ParseeXMPPThread(void *data); + + +/* Finds the room a DM is associated to, from a Matrix user and a Jabber + * ID. */ +extern char * ParseeFindDMRoom(ParseeData *data, char *mxid, char *jid); + +/* Gets a DM ID from a Matrix and Jabber user */ +extern char * ParseeGetDMID(char *mxid, char *jid); + +/* Creates a DM mapping in the database */ +extern void ParseePushDMRoom(ParseeData *, char *mxid, char *jid, char *r); + +/* Trims the component from a JID */ +extern char * ParseeTrimJID(char *jid); #endif