From 59cbd8b22d38d1ce0f3b7be1aa0cfd191a31a56c Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 18 Aug 2024 16:11:12 +0200 Subject: [PATCH] [MOD] Hash-based name conflict resolution Still basic, but should prevent basic name issues. --- src/Commands/Plumb.c | 2 +- src/Main.c | 16 +++++-- src/MatrixEventHandler.c | 53 +++++++++++++++++------ src/Parsee/Data.c | 2 +- src/Parsee/User.c | 2 +- src/Routes/UserAck.c | 2 +- src/XMPP/Component.c | 5 ++- src/XMPP/MUC.c | 84 ++++++++++++++++++++++++++++++++++++ src/XMPP/Stanza.c | 86 ------------------------------------- src/XMPPThread/Stanzas/IQ.c | 2 +- src/include/XMPP.h | 2 +- 11 files changed, 147 insertions(+), 109 deletions(-) diff --git a/src/Commands/Plumb.c b/src/Commands/Plumb.c index d7b3ba0..e3c4ff3 100644 --- a/src/Commands/Plumb.c +++ b/src/Commands/Plumb.c @@ -62,7 +62,7 @@ CommandHead(CmdPlumb, cmd, argp) if (chat_id) { char *rev = StrConcat(2, muc, "/parsee"); - XMPPJoinMUC(args->data->jabber, "parsee", rev); + XMPPJoinMUC(args->data->jabber, "parsee", rev, false); Free(rev); } diff --git a/src/Main.c b/src/Main.c index ced6c59..017a115 100644 --- a/src/Main.c +++ b/src/Main.c @@ -101,15 +101,25 @@ Main(Array *args, HashMap *env) ParseeInitialiseOIDTable(); ParseeInitialiseHeadTable(); - Log(LOG_NOTICE, "Setting up local Matrix user..."); - ASRegisterUser(parsee_conf, parsee_conf->sender_localpart); - conf.port = parsee_conf->port; conf.threads = parsee_conf->http_threads; conf.maxConnections = conf.threads << 2; conf.handlerArgs = ParseeInitData(jabber); conf.handler = ParseeRequest; + Log(LOG_NOTICE, "Setting up local Matrix user..."); + if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart)) + { + char *parsee = ParseeMXID(conf.handlerArgs); + ASSetAvatar(parsee_conf, + parsee, + "mxc://tedomum.net/" + "7e228734ec8e792960bb5633e43f0cb845f709f61825130490034651136" + ); + ASSetName(parsee_conf, parsee, "Parsee bridge"); + Free(parsee); + } + Log(LOG_NOTICE, "Starting up local cronjobs..."); cron = CronCreate( 10 SECONDS ); CronEvery(cron, 5 MINUTES, ParseeCleanup, conf.handlerArgs); diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index cfd3ddf..8827245 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -11,6 +12,38 @@ #include #include +static void +JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) +{ + char *sender = GrabString(event, 1, "sender"); + + char *rev = StrConcat(3, muc, "/", name); + int nonce = 0; + + while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 20) + { + char *nonce_str = StrInt(nonce); + char *input = StrConcat(4, sender, name, data->id, nonce_str); + unsigned char *digest = Sha256(input); + char *hex = ShaToHex(digest); + + if (strlen(hex) >= 8) + { + hex[8] = '\0'; + } + + Free(rev); + rev = StrConcat(6, muc, "/", name, "[", hex, "]"); + nonce++; + + Free(nonce_str); + Free(digest); + Free(input); + Free(hex); + } + Free(rev); +} + static void ParseeMemberHandler(ParseeData *data, HashMap *event) { @@ -55,10 +88,10 @@ ParseeMemberHandler(ParseeData *data, HashMap *event) if (chat_id) { char *muc = ParseeGetMUCID(data, chat_id); - char *rev = StrConcat(2, muc, "/parsee"); + char *name = ASGetName(data->config, room_id, state_key); - XMPPJoinMUC(data->jabber, jid, rev); - Free(rev); + JoinMUC(data, event, jid, muc, name); + Free(name); Free(muc); /* TODO: XEP-0084 magic to advertise a new avatar if possible. */ @@ -162,8 +195,6 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) DbRef *room_data; HashMap *data_json; - XMPPComponent *jabber = data ? data->jabber : NULL; - bool direct = false; if (!data || !event || !from || !to) { @@ -194,7 +225,7 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } else { - char *matrix_name, *muc_join_as; + char *matrix_name; muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -208,18 +239,16 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) } matrix_name = ASGetName(data->config, room_id, matrix_sender); - muc_join_as = StrConcat(4, muc_id, "/", matrix_name, "[p]"); /* TODO: Manage name conflicts. That would have been an easy * task(try the original one, and use a counter if it fails), * but that'd involve modifying the rest of the code, which * I'm not doing at 01:39 ... */ - XMPPJoinMUC(jabber, *from, muc_join_as); + JoinMUC(data, event, *from, muc_id, matrix_name); *to = muc_id; Free(matrix_name); - Free(muc_join_as); } Free(chat_id); @@ -295,7 +324,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) } else { - char *name, *rev; + char *name; /* Try to find the chat ID */ muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) @@ -307,14 +336,12 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) * Is there a good way to check for that that isn't * just "await on join and try again?" */ name = ASGetName(data->config, id, m_sender); - rev = StrConcat(4, muc_id, "/", name, "[p]"); - XMPPJoinMUC(jabber, encoded_from, rev); + JoinMUC(data, event, encoded_from, muc_id, name); to = muc_id; Free(name); - Free(rev); } if (reply_id) { diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 855f401..489b6f2 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -780,7 +780,7 @@ ParseeManageBan(ParseeData *data, char *user, char *room) return false; } - ref = DbLock(data->db, 1, "global_bans"); + ref = DbLockIntent(data->db, DB_HINT_READONLY, 1, "global_bans"); j = DbJson(ref); while (HashMapIterate(j, &key, (void **) &val)) { diff --git a/src/Parsee/User.c b/src/Parsee/User.c index e1e2710..096530d 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -540,7 +540,7 @@ ParseeSendPresence(ParseeData *data) char *rev = StrConcat(2, muc, "/parsee"); /* Make a fake user join the MUC */ Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(data->jabber, "parsee", rev); + XMPPJoinMUC(data->jabber, "parsee", rev, false); Free(rev); } diff --git a/src/Routes/UserAck.c b/src/Routes/UserAck.c index 3db19b7..9bb17e2 100644 --- a/src/Routes/UserAck.c +++ b/src/Routes/UserAck.c @@ -130,7 +130,7 @@ RouteHead(RouteRoomAck, arr, argp) { char *rev = StrConcat(2, muc, "/parsee"); Log(LOG_NOTICE, "Sending presence to %s", rev); - XMPPJoinMUC(args->data->jabber, "parsee", rev); + XMPPJoinMUC(args->data->jabber, "parsee", rev, false); Free(rev); } diff --git a/src/XMPP/Component.c b/src/XMPP/Component.c index abf255c..aa518cd 100644 --- a/src/XMPP/Component.c +++ b/src/XMPP/Component.c @@ -199,8 +199,11 @@ XMPPEndCompStream(XMPPComponent *comp) { return; } - pthread_mutex_destroy(&comp->write_lock); + pthread_mutex_lock(&comp->write_lock); StreamClose(comp->stream); + comp->stream = NULL; + pthread_mutex_unlock(&comp->write_lock); + pthread_mutex_destroy(&comp->write_lock); Free(comp->host); Free(comp); } diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 2f29a38..832fdfe 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -167,3 +167,87 @@ XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) XMLFreeElement(stanza); Free(identifier); } +bool +XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care) +{ + XMLElement *presence, *x, *reply; + char *from, *id; + if (!comp || !fr || !muc) + { + return false; + } + + pthread_mutex_lock(&comp->write_lock); + + presence = XMLCreateTag("presence"); + x = XMLCreateTag("x"); + XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); + XMLAddAttr(presence, "to", muc); + XMLAddAttr(presence, "id", (id = StrRandom(8))); + XMLAddAttr(x, "xmlns", "http://jabber.org/protocol/muc"); + + XMLAddChild(presence, x); + XMPPAnnotatePresence(presence); + + XMLEncode(comp->stream, presence); + StreamFlush(comp->stream); + + XMLFreeElement(presence); + Free(from); + + pthread_mutex_unlock(&comp->write_lock); + + if (care && (reply = ParseeAwaitStanza(id, 500))) + { + bool exit_code = true; + + if (XMPPHasError(reply, "conflict")) + { + exit_code = false; + } + + XMLFreeElement(reply); + Free(id); + return exit_code; + } + Free(id); + return true; +} +void +XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) +{ + XMLElement *presence; + char *from, *id; + if (!comp || !fr || !muc) + { + return; + } + + pthread_mutex_lock(&comp->write_lock); + + presence = XMLCreateTag("presence"); + XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); + XMLAddAttr(presence, "to", muc); + XMLAddAttr(presence, "id", (id = StrRandom(8))); + XMLAddAttr(presence, "type", "unavailable"); + + if (reason) + { + XMLElement *status = XMLCreateTag("status"); + XMLElement *string = XMLCreateText(reason); + + XMLAddChild(status, string); + XMLAddChild(presence, status); + } + + XMPPAnnotatePresence(presence); + + XMLEncode(comp->stream, presence); + StreamFlush(comp->stream); + + XMLFreeElement(presence); + Free(from); + Free(id); + + pthread_mutex_unlock(&comp->write_lock); +} diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 5340633..0a42174 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -76,93 +76,7 @@ XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact) Free(from); Free(ident); } -void -XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) -{ - XMLElement *presence; - char *from, *id; - if (!comp || !fr || !muc) - { - return; - } - pthread_mutex_lock(&comp->write_lock); - - presence = XMLCreateTag("presence"); - XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); - XMLAddAttr(presence, "to", muc); - XMLAddAttr(presence, "id", (id = StrRandom(8))); - XMLAddAttr(presence, "type", "unavailable"); - - if (reason) - { - XMLElement *status = XMLCreateTag("status"); - XMLElement *string = XMLCreateText(reason); - - XMLAddChild(status, string); - XMLAddChild(presence, status); - } - - XMPPAnnotatePresence(presence); - - XMLEncode(comp->stream, presence); - StreamFlush(comp->stream); - - XMLFreeElement(presence); - Free(from); - Free(id); - - pthread_mutex_unlock(&comp->write_lock); -} - -bool -XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc) -{ - XMLElement *presence, *x, *reply; - char *from, *id; - if (!comp || !fr || !muc) - { - return false; - } - - pthread_mutex_lock(&comp->write_lock); - - presence = XMLCreateTag("presence"); - x = XMLCreateTag("x"); - XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host))); - XMLAddAttr(presence, "to", muc); - XMLAddAttr(presence, "id", (id = StrRandom(8))); - XMLAddAttr(x, "xmlns", "http://jabber.org/protocol/muc"); - - XMLAddChild(presence, x); - XMPPAnnotatePresence(presence); - - XMLEncode(comp->stream, presence); - StreamFlush(comp->stream); - - XMLFreeElement(presence); - Free(from); - - pthread_mutex_unlock(&comp->write_lock); - - /*if ((reply = ParseeAwaitStanza(id, 500))) - { - bool exit_code = true; - - if (XMPPHasError(reply, "conflict")) - { - Log(LOG_WARNING, "UNIMPLEMENTED NAMING CONFLICT."); - exit_code = false; - } - - XMLFreeElement(reply); - Free(id); - return exit_code; - }*/ - (void) reply; - Free(id); - return true; -} bool XMPPIsParseeStanza(XMLElement *stanza) { diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 5e0f151..069fba5 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -393,7 +393,7 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr) version = XMLCreateTag("version"); XMLAddChild(name, XMLCreateText(NAME)); - XMLAddChild(version, XMLCreateText(VERSION)); + XMLAddChild(version, XMLCreateText(VERSION "[" CODE "]")); } XMLAddChild(query, name); XMLAddChild(query, version); diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 07fea6a..4015847 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -30,7 +30,7 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port); extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); /* Makes a user join/leave a MUC */ -extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc); +extern bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, bool care); extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */