diff --git a/package.json b/package.json index 8921c2e2bbd61d3f0c1bb4a7ff75511384f68d8d..66093ca7af87515273ffc1efbe08f2d826c81736 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,7 @@ "usertool": "node ./build/tools/userClientTools.js", "directoryfix": "node ./build/tools/addRoomsToDirectory.js", "ghostfix": "node ./build/tools/ghostfix.js", - "chanfix": "node ./build/tools/chanfix.js", - "moveRoomStore": "node ./build/tools/moveRoomStoreToDb.js" + "chanfix": "node ./build/tools/chanfix.js" }, "repository": { "type": "git", diff --git a/src/bot.ts b/src/bot.ts index 1661b5ccf190ed4136ab19f6205b51ced1efa1cd..47fddc3b9e3ce2ecf0143bbe20c3740471363307 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -500,6 +500,9 @@ export class DiscordBot { throw Error("Room(s) not found."); } const entry = entries[0]; + if (!entry.remote) { + throw Error("Room had no remote component"); + } const guild = client.guilds.get(entry.remote!.get("discord_guild") as string); if (guild) { const channel = client.channels.get(entry.remote!.get("discord_channel") as string); diff --git a/src/db/roomstore.ts b/src/db/roomstore.ts index 0e4d3652f5f5331654aec8563993838b0eea9675..5d61937135217419ae2010e8d30406f534b56d41 100644 --- a/src/db/roomstore.ts +++ b/src/db/roomstore.ts @@ -19,6 +19,7 @@ import { IDatabaseConnector } from "./connector"; import * as uuid from "uuid/v4"; const log = new Log("DbRoomStore"); +const ROOM_ID_REGEX = /!([A-z]|_)+:(\d|[A-z]|-|\.|\:)+/; /** * A RoomStore compatible with @@ -122,7 +123,7 @@ export class DbRoomStore { const mxIdDifferent = matrixId !== row.matrix_id; const rmIdDifferent = remoteId !== row.remote_id; // Did the room ids change? - if (row.id && (mxIdDifferent || rmIdDifferent)) { + if (mxIdDifferent || rmIdDifferent) { if (matrixId) { this.entriesMatrixIdCache.delete(matrixId); } @@ -161,18 +162,23 @@ export class DbRoomStore { ); const res: IRoomStoreEntry[] = []; for (const entry of entries) { - const remoteId = entry.remote_id as string || ""; - const row = await this.db.Get( - "SELECT * FROM remote_room_data WHERE room_id = $rid", - {rid: remoteId}, - ); - if (!row) { continue; } + let remote: RemoteStoreRoom|null = null; + if (entry.remote_id) { + const remoteId = entry.remote_id as string; + const row = await this.db.Get( + "SELECT * FROM remote_room_data WHERE room_id = $remoteId", + {remoteId}, + ); + if (row) { + // tslint:disable-next-line no-any + remote = new RemoteStoreRoom(remoteId, row as any); + } + } res.push({ id: (entry.id as string), - matrix: matrixId ? new MatrixStoreRoom(matrixId) : null, - // tslint:disable-next-line no-any - remote: remoteId ? new RemoteStoreRoom(remoteId, row as any) : null, + matrix: new MatrixStoreRoom(matrixId), + remote, }); } if (res.length > 0) { @@ -182,24 +188,38 @@ export class DbRoomStore { } public async getEntriesByMatrixIds(matrixIds: string[]): Promise<IRoomStoreEntry[]> { + // Validate matrixIds to prevent injections. + matrixIds = matrixIds.filter((id) => { + if (!ROOM_ID_REGEX.exec(id)) { + log.warn(`${id} was excluded for not looking like a real roomID`); + return false; + } + return true; + }); const entries = await this.db.All( `SELECT * FROM room_entries WHERE matrix_id IN ('${matrixIds.join("','")}')`, ); const res: IRoomStoreEntry[] = []; for (const entry of entries) { + let remote: RemoteStoreRoom|null = null; const matrixId = entry.matrix_id as string || ""; - const remoteId = entry.remote_id as string || ""; - const row = await this.db.Get( - "SELECT * FROM remote_room_data WHERE room_id = $rid", - {rid: remoteId}, - ); - if (!row) { continue; } + const remoteId = entry.remote_id as string; + if (remoteId) { + const row = await this.db.Get( + "SELECT * FROM remote_room_data WHERE room_id = $rid", + {rid: remoteId}, + ); + if (row) { + // tslint:disable-next-line no-any + remote = new RemoteStoreRoom(remoteId, row as any); + } + } res.push({ id: (entry.id as string), matrix: matrixId ? new MatrixStoreRoom(matrixId) : null, // tslint:disable-next-line no-any - remote: remoteId ? new RemoteStoreRoom(remoteId, row as any) : null, + remote, }); } return res; @@ -255,20 +275,26 @@ export class DbRoomStore { } public async removeEntriesByMatrixRoomId(matrixId: string) { - await this.db.Run(`DELETE FROM room_entries WHERE matrix_id = $matrixId`, {matrixId}); - await this.db.Run(`DELETE FROM remote_room_data WHERE room_id = $matrixId`, {matrixId}); + const entries = (await this.db.All(`SELECT * room_entries WHERE matrix_id = $matrixId`, {matrixId})) || []; + entries.map((entry) => { + if (entry.remote_id) { + return this.removeEntriesByRemoteRoomId(entry.remote_id as string); + } else if (entry.matrix_id) { + return this.db.Run(`DELETE FROM room_entries WHERE matrix_id = $matrixId`, {matrixId: entry.matrix_id}); + } + }); } private async upsertRoom(room: RemoteStoreRoom) { + if (!room.data) { + throw new Error("Tried to upsert a room with undefined data"); + } + const existingRow = await this.db.Get( "SELECT * FROM remote_room_data WHERE room_id = $id", {id: room.roomId}, ); - if (!room.data) { - throw new Error("Tried to upsert a room with undefined data"); - } - const data = { discord_channel: room.data.discord_channel, discord_guild: room.data.discord_guild, @@ -309,7 +335,7 @@ export class DbRoomStore { return; } - const keysToUpdate = { }; + const keysToUpdate = { } as IRemoteRoomDataLazy; // New keys Object.keys(room.data).filter( @@ -336,7 +362,7 @@ export class DbRoomStore { { id: room.roomId, // tslint:disable-next-line no-any - ...keysToUpdate, + ...keysToUpdate as any, }); log.verbose("Upserted room " + room.roomId); } catch (ex) { diff --git a/src/provisioner.ts b/src/provisioner.ts index 31682a38905ca463e768374175b7c463187fb3bb..4f11e990752448678c6679f63183e0410d7e40bc 100644 --- a/src/provisioner.ts +++ b/src/provisioner.ts @@ -29,7 +29,7 @@ export class Provisioner { private pendingRequests: Map<string, (approved: boolean) => void> = new Map(); // [channelId]: resolver fn private roomStore: DbRoomStore; - public setStore(roomStore: DbRoomStore) { + constructor(roomStore: DbRoomStore) { this.roomStore = roomStore; }