#include #include #include #include #include #include #include #include HashMap * ASVerifyRequest(ParseeHttpArg *arg) { HashMap *ret = NULL; HashMap *params; char *authorisation; if (!arg) { return NULL; } params = HttpRequestHeaders(arg->ctx); authorisation = HashMapGet(params, "authorization"); if (!authorisation || strncmp(authorisation, "Bearer ", 7)) { HttpResponseStatus(arg->ctx, HTTP_FORBIDDEN); ret = MatrixCreateError("M_MISSING_TOKEN", "No 'hs_token' given in."); goto end; } authorisation += 7; if (!StrEquals(authorisation, arg->data->config->hs_token)) { HttpResponseStatus(arg->ctx, HTTP_FORBIDDEN); ret = MatrixCreateError("M_FORBIDDEN","Incorrect authorisation given"); goto end; } end: return ret; } void ASAuthenticateRequest(const ParseeConfig *data, HttpClientContext *ctx) { char *bearer; if (!data || !ctx) { return; } bearer = StrConcat(2, "Bearer ", data->as_token); HttpRequestHeader(ctx, "Authorization", bearer); Free(bearer); } bool ASRegisterUser(const ParseeConfig *conf, char *user) { HttpClientContext *ctx = NULL; HashMap *json = NULL; HttpStatus status; if (!conf || !user) { return false; } /* Create user. We don't actually care about the value as we can * masquerade, as long as it exists. */ ctx = ParseeCreateRequest( conf, HTTP_POST, "/_matrix/client/v3/register" ); json = HashMapCreate(); HashMapSet(json,"type",JsonValueString("m.login.application_service")); user = ParseeGetLocal(user); HashMapSet(json,"username",JsonValueString(user)); ASAuthenticateRequest(conf, ctx); status = ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); Free(user); return status == HTTP_OK; } void ASPing(const ParseeConfig *conf) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path; if (!conf) { return; } path = StrConcat(3, "/_matrix/client/v1/appservice/", "Parsee%20XMPP", "/ping" ); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); } void ASInvite(const ParseeConfig *conf, char *id, char *invited) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path, *bridge; if (!conf || !id || !invited) { return; } bridge = StrConcat(4, "@", conf->sender_localpart, ":", conf->homeserver_host ); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/invite", "?user_id=", bridge ); Free(bridge); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(invited)); HashMapSet(json, "reason", JsonValueString("Pass over.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); } void ASBan(const ParseeConfig *conf, char *id, char *banned) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path, *bridge; if (!conf || !id || !banned) { return; } bridge = StrConcat(4, "@", conf->sender_localpart, ":", conf->homeserver_host ); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/ban", "?user_id=", bridge ); Free(bridge); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(banned)); HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); } void ASKick(const ParseeConfig *conf, char *id, char *banned) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path, *bridge; if (!conf || !id || !banned) { return; } bridge = StrConcat(4, "@", conf->sender_localpart, ":", conf->homeserver_host ); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/kick", "?user_id=", bridge ); Free(bridge); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); HashMapSet(json, "user_id", JsonValueString(banned)); HashMapSet(json, "reason", JsonValueString("Parsee felt jealous.")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); } char * ASJoin(const ParseeConfig *conf, char *id, char *masquerade) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path, *ret; if (!conf || !id) { return NULL; } if (!masquerade) { char *raw = StrConcat(4, "@", conf->sender_localpart, ":", conf->homeserver_host ); masquerade = HttpUrlEncode(raw); Free(raw); } else { masquerade = HttpUrlEncode(masquerade); } id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/join/", id, "?", "user_id=", masquerade ); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); JsonFree(json); json = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate(GrabString(json, 1, "room_id")); JsonFree(json); HttpClientContextFree(ctx); Free(masquerade); Free(id); return ret; } void ASLeave(const ParseeConfig *conf, char *id, char *masquerade) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path; if (!conf || !id) { return; } if (!masquerade) { char *raw = StrConcat(4, "@", conf->sender_localpart, ":", conf->homeserver_host ); masquerade = HttpUrlEncode(raw); Free(raw); } else { masquerade = HttpUrlEncode(masquerade); } id = HttpUrlEncode(id); path = StrConcat(5, "/_matrix/client/v3/rooms/", id, "/leave?", "user_id=", masquerade ); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); JsonFree(json); HttpClientContextFree(ctx); Free(masquerade); Free(id); } void ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *state) { HttpClientContext *ctx = NULL; char *path; if (!conf || !id || !type || !mask || !state) { JsonFree(state); return; } path = StrConcat(9, "/_matrix/client/v3/rooms/", id, "/state/", type, "/", key, "?", "user_id=", mask ); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, state); HttpClientContextFree(ctx); JsonFree(state); } char * ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) { HttpClientContext *ctx = NULL; char *path; char *txn, *ret; HashMap *reply; if (!conf || !id || !type || !user || !c) { JsonFree(c); return NULL; } txn = StrRandom(16); path = StrConcat(9, "/_matrix/client/v3/rooms/", id, "/send/", type, "/", txn, "?", "user_id=", user ); Free(txn); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, c); reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); JsonFree(reply); HttpClientContextFree(ctx); JsonFree(c); return ret; } char * ASCreateRoom(const ParseeConfig *conf, char *by, char *alias) { HttpClientContext *ctx = NULL; HashMap *json = NULL; char *path, *id; if (!conf || !by) { return NULL; } path = StrConcat(3, "/_matrix/client/v3/createRoom", "?user_id=", by ); ctx = ParseeCreateRequest( conf, HTTP_POST, path ); Free(path); json = HashMapCreate(); if (alias) { char *trimmed = StrDuplicate(alias); if (*alias == '#') { char *tmp, cb[2] = { 0 }; alias++; Free(trimmed); trimmed = NULL; while (*alias && *alias != ':') { cb[0] = *alias; tmp = trimmed; trimmed = StrConcat(2, trimmed, cb); Free(tmp); alias ++; } } HashMapSet(json, "room_alias_name", JsonValueString(trimmed)); Free(trimmed); } HashMapSet(json, "visibility", JsonValueString("public")); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); JsonFree(json); json = JsonDecode(HttpClientStream(ctx)); id = StrDuplicate(JsonValueAsString(HashMapGet(json, "room_id"))); HttpClientContextFree(ctx); JsonFree(json); return id; } void ASSetAvatar(const ParseeConfig *conf, char *user, char *mxc) { HttpClientContext *ctx = NULL; HashMap *json; char *path; if (!conf || !user || !mxc) { return; } user = HttpUrlEncode(user); path = StrConcat(6, "/_matrix/client/v3/profile/", user, "/avatar_url", "?", "user_id=", user ); json = HashMapCreate(); HashMapSet(json, "avatar_url", JsonValueString(mxc)); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); Free(user); } void ASSetName(const ParseeConfig *conf, char *user, char *name) { HttpClientContext *ctx = NULL; HashMap *json; char *path; if (!conf || !user || !name) { return; } user = HttpUrlEncode(user); path = StrConcat(6, "/_matrix/client/v3/profile/", user, "/displayname", "?", "user_id=", user ); json = HashMapCreate(); HashMapSet(json, "displayname", JsonValueString(name)); ctx = ParseeCreateRequest(conf, HTTP_PUT, path); Free(path); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, json); HttpClientContextFree(ctx); JsonFree(json); Free(user); } HashMap * ASFind(const ParseeConfig *c, char *room, char *event) { HttpClientContext *ctx = NULL; HashMap *json; char *path, *user; if (!c || !room || !event) { return NULL; } user = StrConcat(4, "@", c->sender_localpart, ":", c->homeserver_host); path = StrConcat(7, "/_matrix/client/v3/rooms/", room, "/event/", event, "?", "user_id=", user ); ctx = ParseeCreateRequest(c, HTTP_GET, path); Free(path); ASAuthenticateRequest(c, ctx); HttpRequestSendHeaders(ctx); HttpRequestSend(ctx); json = JsonDecode(HttpClientStream(ctx)); HttpClientContextFree(ctx); Free(user); return json; } char * ASGetName(const ParseeConfig *c, char *room, char *user) { HttpClientContext *ctx; HashMap *reply; char *path, *ret; char *u2 = user; if (!c || !user) { return NULL; } if (!room) { user = HttpUrlEncode(user); path = StrConcat(3, "/_matrix/client/v3/profile/", user, "/displayname" ); ctx = ParseeCreateRequest(c, HTTP_GET, path); Free(user); ASAuthenticateRequest(c, ctx); HttpRequestSendHeaders(ctx); HttpRequestSend(ctx); reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate( JsonValueAsString(HashMapGet(reply, "displayname")) ); HttpClientContextFree(ctx); JsonFree(reply); Free(path); if (!ret) { ret = StrDuplicate(u2); } return ret; } user = HttpUrlEncode(user); room = HttpUrlEncode(room); path = StrConcat(4, "/_matrix/client/v3/rooms/", room, "/state/m.room.member/", user ); ctx = ParseeCreateRequest(c, HTTP_GET, path); Free(user); Free(room); ASAuthenticateRequest(c, ctx); HttpRequestSendHeaders(ctx); HttpRequestSend(ctx); reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate( JsonValueAsString(HashMapGet(reply, "displayname")) ); HttpClientContextFree(ctx); JsonFree(reply); Free(path); if (!ret) { ret = StrDuplicate(u2); } return ret; } HashMap * ASGetPL(const ParseeConfig *c, char *room) { char *path; HttpClientContext *ctx; HashMap *reply; if (!c || !room) { return NULL; } room = HttpUrlEncode(room); path = StrConcat(4, "/_matrix/client/v3/rooms/", room, "/state/m.room.power_levels/", "" ); ctx = ParseeCreateRequest(c, HTTP_GET, path); Free(room); ASAuthenticateRequest(c, ctx); HttpRequestSendHeaders(ctx); HttpRequestSend(ctx); reply = JsonDecode(HttpClientStream(ctx)); HttpClientContextFree(ctx); Free(path); return reply; } void ASSetPL(const ParseeConfig *conf, char *id, HashMap *m) { char *user; if (!conf || !id || !m) { return; } user = StrConcat(4, "@",conf->sender_localpart, ":",conf->homeserver_host ); ASSetState(conf, id, "m.room.power_levels", "", user, m); Free(user); } char * ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime) { char *size_str, *path, *ret, *user; int i; HttpClientContext *ctx; HashMap *reply; if (!c || !from) { return NULL; } size_str = StrInt(size); user = StrConcat(4, "@",c->sender_localpart,":",c->homeserver_host); path = StrConcat(2, "/_matrix/media/v3/upload?user_id=", user ); ctx = ParseeCreateRequest(c, HTTP_POST, path); ASAuthenticateRequest(c, ctx); if (size) { HttpRequestHeader(ctx, "Content-Length", size_str); } if (mime) { HttpRequestHeader(ctx, "Content-Type", mime); } HttpRequestSendHeaders(ctx); for (i = 0; i < size; i++) { int ch = StreamGetc(from); if (ch == EOF) { break; } StreamPutc(HttpClientStream(ctx), ch); } HttpRequestSend(ctx); reply = JsonDecode(HttpClientStream(ctx)); ret = StrDuplicate( JsonValueAsString(HashMapGet(reply, "content_uri")) ); if (!ret) { JsonEncode(reply, StreamStdout(), JSON_PRETTY); StreamFlush(StreamStdout()); Log(LOG_INFO, "Less obvious upload fail"); } HttpClientContextFree(ctx); JsonFree(reply); Free(size_str); Free(path); Free(user); return ret; } char * ASReupload(const ParseeConfig *c, char *from, char **mime) { Uri *uri; HttpClientContext *ctx; unsigned short port; int size = 0, flags = HTTP_FLAG_NONE; char *ret, *content_len; if (!c || !from) { return NULL; } uri = UriParse(from); if (!uri) { return NULL; } if (uri->port) { port = uri->port; } else if (StrEquals(uri->proto, "https")) { port = 443; } else { port = 80; } if (StrEquals(uri->proto, "https")) { flags |= HTTP_FLAG_TLS; } ctx = HttpRequest( HTTP_GET, flags, port, uri->host, uri->path ); HttpRequestSendHeaders(ctx); HttpRequestSend(ctx); if (mime) { *mime = HashMapGet(HttpResponseHeaders(ctx), "content-type"); *mime = StrDuplicate(*mime); } content_len = HashMapGet(HttpResponseHeaders(ctx), "content-length"); if (content_len) { size = strtol(content_len, NULL, 10); } ret = ASUpload(c, HttpClientStream(ctx), size, mime ? *mime : NULL); HttpClientContextFree(ctx); UriFree(uri); return ret; } void ASType(const ParseeConfig *c, char *user, char *room, bool status) { HttpClientContext *ctx = NULL; HashMap *json; char *path; if (!c || !user || !room) { return; } user = HttpUrlEncode(user); path = StrConcat(6, "/_matrix/client/v3/rooms/", room, "/typing/", user, "?user_id=", user ); json = HashMapCreate(); HashMapSet(json, "typing", JsonValueBoolean(status)); HashMapSet(json, "timeout", JsonValueBoolean(1 MINUTES)); ctx = ParseeCreateRequest(c, HTTP_PUT, path); Free(path); ASAuthenticateRequest(c, ctx); ParseeSetRequestJSON(ctx, json); JsonFree(json); HttpClientContextFree(ctx); Free(user); } void ASPresence(const ParseeConfig *c, char *user, char *room, char *ev) { HttpClientContext *ctx = NULL; HashMap *json; char *path; if (!c || !user || !room || !ev) { return; } user = HttpUrlEncode(user); room = HttpUrlEncode(room); ev = HttpUrlEncode(ev); path = StrConcat(6, "/_matrix/client/v3/rooms/", room, "/receipt/m.read/", ev, "?user_id=", user ); json = HashMapCreate(); ctx = ParseeCreateRequest(c, HTTP_POST, path); Free(path); ASAuthenticateRequest(c, ctx); ParseeSetRequestJSON(ctx, json); JsonFree(json); HttpClientContextFree(ctx); Free(user); Free(room); Free(ev); } HashMap * ASGetUserConfig(const ParseeConfig *c, char *user, char *key) { HttpClientContext *ctx = NULL; HashMap *json; char *path; if (!c || !key) { return NULL; } if (!user) { char *raw = StrConcat(4, "@", c->sender_localpart, ":", c->homeserver_host ); user = HttpUrlEncode(raw); Free(raw); } else { user = HttpUrlEncode(user); } path = StrConcat(7, "/_matrix/client/v3/user/", user, "/account_data/", key, "?", "user_id=", user ); ctx = ParseeCreateRequest(c, HTTP_GET, path); Free(path); ASAuthenticateRequest(c, ctx); HttpRequestSendHeaders(ctx); HttpRequestSend(ctx); json = JsonDecode(HttpClientStream(ctx)); HttpClientContextFree(ctx); Free(user); return json; } void ASSetUserConfig(const ParseeConfig *c, char *user, char *key, HashMap *map) { HttpClientContext *ctx = NULL; char *path; if (!c || !key || !map) { JsonFree(map); return; } if (!user) { char *raw = StrConcat(4, "@", c->sender_localpart, ":", c->homeserver_host ); user = HttpUrlEncode(raw); Free(raw); } else { user = HttpUrlEncode(user); } path = StrConcat(7, "/_matrix/client/v3/user/", user, "/account_data/", key, "?", "user_id=", user ); ctx = ParseeCreateRequest(c, HTTP_PUT, path); Free(path); ASAuthenticateRequest(c, ctx); ParseeSetRequestJSON(ctx, map); HttpClientContextFree(ctx); Free(user); JsonFree(map); return; } void ASRedact(const ParseeConfig *c, char *room, char *user, char *e_id) { HttpClientContext *ctx = NULL; HashMap *request; char *path, *txn; if (!c || !room || !e_id) { return; } if (!user) { char *raw = StrConcat(4, "@", c->sender_localpart, ":", c->homeserver_host ); user = HttpUrlEncode(raw); Free(raw); } else { user = HttpUrlEncode(user); } room = HttpUrlEncode(room); e_id = HttpUrlEncode(e_id); txn = StrRandom(16); path = StrConcat(9, "/_matrix/client/v3/rooms/", room, "/redact/", e_id, "/", txn, "?", "user_id=", user ); request = HashMapCreate(); ctx = ParseeCreateRequest(c, HTTP_PUT, path); Free(path); ASAuthenticateRequest(c, ctx); ParseeSetRequestJSON(ctx, request); JsonFree(request); HttpClientContextFree(ctx); Free(user); Free(room); Free(e_id); Free(txn); return; }