diff --git a/src/bot.ts b/src/bot.ts index c30495f014b24c0b4046dcfe03f4df9c612bcf57..8810553f19cc72d0c51fed1ad4509f8f61e3b0e9 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -4,7 +4,7 @@ import { DiscordStore } from "./store"; import { DbEmoji } from "./db/dbdataemoji"; import { DbEvent } from "./db/dbdataevent"; import { MatrixUser, RemoteUser, Bridge, Entry, Intent } from "matrix-appservice-bridge"; -import { Util } from "./util"; +import { Util, IMatrixEvent } from "./util"; import { MessageProcessor, MessageProcessorOpts, MessageProcessorMatrixResult } from "./messageprocessor"; import { MatrixEventProcessor, MatrixEventProcessorOpts } from "./matrixeventprocessor"; import { PresenceHandler } from "./presencehandler"; @@ -28,6 +28,18 @@ class ChannelLookupResult { public botUser: boolean; } +interface IThirdPartyLookupField { + channel_id: string; + channel_name: string; + guild_id: string; +} + +interface IThirdPartyLookup { + alias: string; + fields: IThirdPartyLookupField; + protocol: string; +} + export class DiscordBot { private config: DiscordBridgeConfig; private clientFactory: DiscordClientFactory; @@ -170,7 +182,7 @@ export class DiscordBot { return this.bot.guilds.array(); } - public ThirdpartySearchForChannels(guildId: string, channelName: string): any[] { + public ThirdpartySearchForChannels(guildId: string, channelName: string): IThirdPartyLookup[] { if (channelName.startsWith("#")) { channelName = channelName.substr(1); } @@ -187,7 +199,7 @@ export class DiscordBot { guild_id: guild.id, }, protocol: "discord", - }; + } as IThirdPartyLookup; }); } else { log.info("Tried to do a third party lookup for a channel, but the guild did not exist"); @@ -221,7 +233,7 @@ export class DiscordBot { } } - public async ProcessMatrixStateEvent(event: any): Promise<void> { + public async ProcessMatrixStateEvent(event: IMatrixEvent): Promise<void> { log.verbose(`Got state event from ${event.room_id} ${event.type}`); const channel = await this.GetChannelFromRoomId(event.room_id) as Discord.TextChannel; const msg = this.mxEventProcessor.StateEventToMessage(event, channel); @@ -244,7 +256,7 @@ export class DiscordBot { }); } - public async ProcessMatrixMsgEvent(event: any, guildId: string, channelId: string): Promise<null> { + public async ProcessMatrixMsgEvent(event: IMatrixEvent, guildId: string, channelId: string): Promise<null> { const mxClient = this.bridge.getClientFactory().getClientAs(); log.verbose(`Looking up ${guildId}_${channelId}`); const result = await this.LookupRoom(guildId, channelId, event.sender); @@ -295,7 +307,7 @@ export class DiscordBot { embeds: embedSet.replyEmbed ? [embedSet.replyEmbed] : undefined, files: opts.file ? [opts.file] : undefined, username: embed.author.name, - } as any); + } as Discord.WebhookMessageOptions); } else { if (embedSet.replyEmbed) { embed.addField("Replying to", embedSet.replyEmbed.author.name); @@ -324,7 +336,7 @@ export class DiscordBot { return; } - public async ProcessMatrixRedact(event: any) { + public async ProcessMatrixRedact(event: IMatrixEvent) { if (this.config.bridge.disableDeletionForwarding) { return; } diff --git a/src/clientfactory.ts b/src/clientfactory.ts index b29d7c83b22b92014be64e1666b74507ea433fcf..adb3bb8eb17eee1368464617239f4dc84c10be49 100644 --- a/src/clientfactory.ts +++ b/src/clientfactory.ts @@ -1,8 +1,9 @@ import { DiscordBridgeConfigAuth } from "./config"; import { DiscordStore } from "./store"; -import { Client } from "discord.js"; +import * as Discord from "discord.js"; import * as Bluebird from "bluebird"; import { Log } from "./log"; +import * as Matrix from "matrix-js-sdk"; const log = new Log("ClientFactory"); @@ -11,8 +12,8 @@ const READY_TIMEOUT = 5000; export class DiscordClientFactory { private config: DiscordBridgeConfigAuth; private store: DiscordStore; - private botClient: any; - private clients: Map<string, any>; + private botClient: Matrix.Client; + private clients: Map<string, Matrix.Client>; constructor(store: DiscordStore, config?: DiscordBridgeConfigAuth) { this.config = config; this.clients = new Map(); @@ -25,7 +26,7 @@ export class DiscordClientFactory { } // We just need to make sure we have a bearer token. // Create a new Bot client. - this.botClient = Bluebird.promisifyAll(new Client({ + this.botClient = Bluebird.promisifyAll(new Discord.Client({ fetchAllMembers: true, messageCacheLifetime: 5, sync: true, @@ -40,7 +41,7 @@ export class DiscordClientFactory { } public async getDiscordId(token: string): Promise<string> { - const client = new Client({ + const client = new Discord.Client({ fetchAllMembers: false, messageCacheLifetime: 5, sync: false, @@ -58,7 +59,7 @@ export class DiscordClientFactory { }); } - public async getClient(userId: string = null): Promise<any> { + public async getClient(userId: string = null): Promise<Matrix.Client> { if (userId == null) { return this.botClient; } @@ -72,7 +73,7 @@ export class DiscordClientFactory { } // TODO: Select a profile based on preference, not the first one. const token = await this.store.get_token(discordIds[0]); - const client = Bluebird.promisifyAll(new Client({ + const client = Bluebird.promisifyAll(new Discord.Client({ fetchAllMembers: true, messageCacheLifetime: 5, sync: true, diff --git a/src/config.ts b/src/config.ts index e6ec2628cf2673e8fe18e5d10cf15cf7abefa488..031a7ee69c7eaedffb049678ae9eb0629a2573ad 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,6 +13,7 @@ export class DiscordBridgeConfig { * @param _config Config keys * @param configLayer Private parameter */ + // tslint:disable-next-line no-any public ApplyConfig(newConfig: {[key: string]: any}, configLayer: any = this) { Object.keys(newConfig).forEach((key) => { if ( typeof(configLayer[key]) === "object" && diff --git a/src/log.ts b/src/log.ts index 410fb5bf98413020b4587b2def61e4044416e2a6..8a895ded8caaf20c9af707bddc8cd9598c47c6a6 100644 --- a/src/log.ts +++ b/src/log.ts @@ -81,6 +81,7 @@ export class Log { maxSize: config.maxSize, }; + // tslint:disable-next-line no-any return new (transports as any).DailyRotateFile(opts); } @@ -88,26 +89,32 @@ export class Log { constructor(private module: string) { } + // tslint:disable-next-line no-any public error(...msg: any[]) { this.log("error", msg); } + // tslint:disable-next-line no-any public warn(...msg: any[]) { this.log("warn", msg); } + // tslint:disable-next-line no-any public info(...msg: any[]) { this.log("info", msg); } + // tslint:disable-next-line no-any public verbose(...msg: any[]) { this.log("verbose", msg); } + // tslint:disable-next-line no-any public silly(...msg: any[]) { this.log("silly", msg); } + // tslint:disable-next-line no-any private log(level: string, msg: any[]) { if (Log.logger === null) { // We've not configured the logger yet, so create a basic one. diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts index 9d42108cb73f8b623b7f23812230c12417113622..8991490ad175a48bc343c7e6f73db1236e6be645 100644 --- a/src/matrixeventprocessor.ts +++ b/src/matrixeventprocessor.ts @@ -3,10 +3,11 @@ import { MessageProcessorOpts, MessageProcessor } from "./messageprocessor"; import { DiscordBot } from "./bot"; import { DiscordBridgeConfig } from "./config"; import * as escapeStringRegexp from "escape-string-regexp"; -import { Util } from "./util"; +import { Util, IMatrixEvent, IMatrixEventContent } from "./util"; import * as path from "path"; import * as mime from "mime"; -import { MatrixUser } from "matrix-appservice-bridge"; +import { MatrixUser, Bridge } from "matrix-appservice-bridge"; +import * as Matrix from "matrix-js-sdk"; import { Log } from "./log"; const log = new Log("MatrixEventProcessor"); @@ -21,7 +22,7 @@ const DISCORD_AVATAR_HEIGHT = 128; export class MatrixEventProcessorOpts { constructor( readonly config: DiscordBridgeConfig, - readonly bridge: any, + readonly bridge: Bridge, readonly discord: DiscordBot, ) { @@ -35,7 +36,7 @@ export interface IMatrixEventProcessorResult { export class MatrixEventProcessor { private config: DiscordBridgeConfig; - private bridge: any; + private bridge: Bridge; private discord: DiscordBot; constructor(opts: MatrixEventProcessorOpts) { @@ -44,7 +45,7 @@ export class MatrixEventProcessor { this.discord = opts.discord; } - public StateEventToMessage(event: any, channel: Discord.TextChannel): string { + public StateEventToMessage(event: IMatrixEvent, channel: Discord.TextChannel): string { const SUPPORTED_EVENTS = ["m.room.member", "m.room.name", "m.room.topic"]; if (!SUPPORTED_EVENTS.includes(event.type)) { log.verbose(`${event.event_id} ${event.type} is not displayable.`); @@ -83,7 +84,7 @@ export class MatrixEventProcessor { } public async EventToEmbed( - event: any, profile: any|null, channel: Discord.TextChannel, + event: IMatrixEvent, profile: IMatrixEvent|null, channel: Discord.TextChannel, ): Promise<IMatrixEventProcessorResult> { let body = this.config.bridge.disableDiscordMentions ? event.content.body : this.FindMentionsInPlainBody( @@ -170,7 +171,7 @@ export class MatrixEventProcessor { return content; } - public async HandleAttachment(event: any, mxClient: any): Promise<string|Discord.FileOptions> { + public async HandleAttachment(event: IMatrixEvent, mxClient: Matrix.Client): Promise<string|Discord.FileOptions> { const hasAttachment = [ "m.image", "m.audio", @@ -211,7 +212,7 @@ export class MatrixEventProcessor { return `[${name}](${url})`; } - public async GetEmbedForReply(event: any): Promise<[Discord.RichEmbed, string]|undefined> { + public async GetEmbedForReply(event: IMatrixEvent): Promise<[Discord.RichEmbed, string]|undefined> { const relatesTo = event.content["m.relates_to"]; let eventId = null; if (relatesTo && relatesTo["m.in_reply_to"]) { @@ -249,7 +250,7 @@ export class MatrixEventProcessor { return [embed, reponseText]; } - private async SetEmbedAuthor(embed: Discord.RichEmbed, sender: string, profile?: any) { + private async SetEmbedAuthor(embed: Discord.RichEmbed, sender: string, profile?: IMatrixEvent) { const intent = this.bridge.getIntent(); let displayName = sender; let avatarUrl; @@ -300,7 +301,7 @@ export class MatrixEventProcessor { ); } - private GetFilenameForMediaEvent(content: any): string { + private GetFilenameForMediaEvent(content: IMatrixEventContent): string { if (content.body) { if (path.extname(content.body) !== "") { return content.body; diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts index c0defadd6ca44b704df67dcb4d45baa612f800b8..265cba163435c074677ad9ca310b0a2b1be9c759 100644 --- a/src/matrixroomhandler.ts +++ b/src/matrixroomhandler.ts @@ -6,12 +6,15 @@ import { thirdPartyProtocolResult, thirdPartyUserResult, thirdPartyLocationResult, + BridgeContext, + ProvisionedRoom, + Intent, } from "matrix-appservice-bridge"; import { DiscordBridgeConfig } from "./config"; import * as Discord from "discord.js"; import * as Bluebird from "bluebird"; -import { Util, ICommandActions, ICommandParameters } from "./util"; +import { Util, ICommandActions, ICommandParameters, IMatrixEvent } from "./util"; import { Provisioner } from "./provisioner"; import { Log } from "./log"; const log = new Log("MatrixRoomHandler"); @@ -103,35 +106,41 @@ export class MatrixRoomHandler { await Promise.all(promiseList); } - public async OnEvent(request, context): Promise<any> { + public async OnEvent(request, context): Promise<void> { const event = request.getData(); if (event.unsigned.age > AGE_LIMIT) { log.warn(`Skipping event due to age ${event.unsigned.age} > ${AGE_LIMIT}`); throw new Error("Event too old"); } if (event.type === "m.room.member" && event.content.membership === "invite") { - return this.HandleInvite(event); + await this.HandleInvite(event); + return; } else if (event.type === "m.room.member" && event.content.membership === "join") { if (this.bridge.getBot().isRemoteUser(event.state_key)) { - return this.discord.UserSyncroniser.OnMemberState(event, USERSYNC_STATE_DELAY_MS); + await this.discord.UserSyncroniser.OnMemberState(event, USERSYNC_STATE_DELAY_MS); } else { - return this.discord.ProcessMatrixStateEvent(event); + await this.discord.ProcessMatrixStateEvent(event); } + return; } else if (["m.room.member", "m.room.name", "m.room.topic"].includes(event.type)) { - return this.discord.ProcessMatrixStateEvent(event); + await this.discord.ProcessMatrixStateEvent(event); + return; } else if (event.type === "m.room.redaction" && context.rooms.remote) { - return this.discord.ProcessMatrixRedact(event); + await this.discord.ProcessMatrixRedact(event); + return; } else if (event.type === "m.room.message" || event.type === "m.sticker") { log.verbose(`Got ${event.type} event`); const isBotCommand = event.type === "m.room.message" && event.content.body && event.content.body.startsWith("!discord"); if (isBotCommand) { - return this.ProcessCommand(event, context); + await this.ProcessCommand(event, context); + return; } else if (context.rooms.remote) { const srvChanPair = context.rooms.remote.roomId.substr("_discord".length).split("_", ROOM_NAME_PARTS); try { - return this.discord.ProcessMatrixMsgEvent(event, srvChanPair[0], srvChanPair[1]); + await this.discord.ProcessMatrixMsgEvent(event, srvChanPair[0], srvChanPair[1]); + return; } catch (err) { log.warn("There was an error sending a matrix event", err); return; @@ -139,7 +148,8 @@ export class MatrixRoomHandler { } } else if (event.type === "m.room.encryption" && context.rooms.remote) { try { - return this.HandleEncryptionWarning(event.room_id); + await this.HandleEncryptionWarning(event.room_id); + return; } catch (err) { throw new Error(`Failed to handle encrypted room, ${err}`); } @@ -168,7 +178,7 @@ export class MatrixRoomHandler { await this.bridge.getRoomStore().removeEntriesByMatrixRoomId(roomId); } - public async HandleInvite(event: any) { + public async HandleInvite(event: IMatrixEvent) { log.info("Received invite for " + event.state_key + " in room " + event.room_id); if (event.state_key === this.botUserId) { log.info("Accepting invite for bridge bot"); @@ -179,7 +189,7 @@ export class MatrixRoomHandler { } } - public async ProcessCommand(event: any, context: any) { + public async ProcessCommand(event: IMatrixEvent, context: BridgeContext) { const intent = this.bridge.getIntent(); if (!(await this.isBotInRoom(event.room_id))) { log.warn(`Bot is not in ${event.room_id}. Ignoring command`); @@ -328,7 +338,7 @@ export class MatrixRoomHandler { } } - public async OnAliasQuery(alias: string, aliasLocalpart: string): Promise<any> { + public async OnAliasQuery(alias: string, aliasLocalpart: string): Promise<ProvisionedRoom> { log.info("Got request for #", aliasLocalpart); const srvChanPair = aliasLocalpart.substr("_discord_".length).split("_", ROOM_NAME_PARTS); if (srvChanPair.length < ROOM_NAME_PARTS || srvChanPair[0] === "" || srvChanPair[1] === "") { @@ -389,6 +399,7 @@ export class MatrixRoomHandler { }; } + // tslint:disable-next-line no-any public async tpGetLocation(protocol: string, fields: any): Promise<thirdPartyLocationResult[]> { log.info("Got location request ", protocol, fields); const chans = this.discord.ThirdpartySearchForChannels(fields.guild_id, fields.channel_name); @@ -399,6 +410,7 @@ export class MatrixRoomHandler { throw {err: "Unsupported", code: HTTP_UNSUPPORTED}; } + // tslint:disable-next-line no-any public async tpGetUser(protocol: string, fields: any): Promise<thirdPartyUserResult[]> { log.info("Got user request ", protocol, fields); throw {err: "Unsupported", code: HTTP_UNSUPPORTED}; @@ -453,7 +465,7 @@ export class MatrixRoomHandler { let replyHelpMessage = "Available Commands:\n"; for (const actionKey of Object.keys(actions)) { const action = actions[actionKey]; - if (!msg.member.hasPermission(action.permission as any)) { + if (!msg.member.hasPermission(action.permission as Discord.PermissionResolvable)) { continue; } replyHelpMessage += " - `!matrix " + actionKey; @@ -476,7 +488,7 @@ export class MatrixRoomHandler { return; } - if (!msg.member.hasPermission(actions[command].permission as any)) { + if (!msg.member.hasPermission(actions[command].permission as Discord.PermissionResolvable)) { await msg.channel.send("**ERROR:** insufficiant permissions to use this matrix command"); return; } @@ -519,7 +531,7 @@ export class MatrixRoomHandler { }; } - private async joinRoom(intent: any, roomIdOrAlias: string): Promise<void> { + private async joinRoom(intent: Intent, roomIdOrAlias: string): Promise<void> { let currentSchedule = JOIN_ROOM_SCHEDULE[0]; const doJoin = async () => { await Util.DelayedPromise(currentSchedule); @@ -549,7 +561,7 @@ export class MatrixRoomHandler { } } - private createMatrixRoom(channel: Discord.TextChannel, alias: string) { + private createMatrixRoom(channel: Discord.TextChannel, alias: string): ProvisionedRoom { const remote = new RemoteRoom(`discord_${channel.guild.id}_${channel.id}`); remote.set("discord_type", "text"); remote.set("discord_guild", channel.guild.id); @@ -573,7 +585,7 @@ export class MatrixRoomHandler { return { creationOpts, remote, - }; + } as ProvisionedRoom; } private async isBotInRoom(roomId: string): Promise<boolean> { diff --git a/src/presencehandler.ts b/src/presencehandler.ts index aa77d962e9091e45f309b95a7946aac6e22c9d33..9c6d94657ea2947997cf2353b74a0ac44c657798 100644 --- a/src/presencehandler.ts +++ b/src/presencehandler.ts @@ -10,6 +10,11 @@ export class PresenceHandlerStatus { public ShouldDrop: boolean = false; } +interface IMatrixPresence { + presence?: string; + status_msg?: string; +} + export class PresenceHandler { private readonly bot: DiscordBot; private presenceQueue: User[]; @@ -106,7 +111,7 @@ export class PresenceHandler { private async setMatrixPresence(user: User, status: PresenceHandlerStatus) { const intent = this.bot.GetIntentFromDiscordMember(user); - const statusObj: any = {presence: status.Presence}; + const statusObj: IMatrixPresence = {presence: status.Presence}; if (status.StatusMsg) { statusObj.status_msg = status.StatusMsg; } diff --git a/src/provisioner.ts b/src/provisioner.ts index 0e20175e686a01434aaa439e690ae7c7efe62ad9..1a43db0940894338df80aabdc0da0a0ab398fe31 100644 --- a/src/provisioner.ts +++ b/src/provisioner.ts @@ -32,7 +32,7 @@ export class Provisioner { return this.bridge.getRoomStore().removeEntriesByRemoteRoomId(remoteRoom.getId()); } - public async AskBridgePermission(channel: Discord.TextChannel, requestor: string): Promise<any> { + public async AskBridgePermission(channel: Discord.TextChannel, requestor: string): Promise<void> { const channelId = channel.guild.id + "/" + channel.id; let responded = false; diff --git a/src/usersyncroniser.ts b/src/usersyncroniser.ts index af3d7c781b6745d6e6b704318b14dd2b71d0b59f..89ff6ab6c7bf6f5d55778d6c2219d52539e55b80 100644 --- a/src/usersyncroniser.ts +++ b/src/usersyncroniser.ts @@ -1,6 +1,6 @@ import { User, GuildMember, GuildChannel } from "discord.js"; import { DiscordBot } from "./bot"; -import { Util } from "./util"; +import { Util, IMatrixEvent } from "./util"; import { MatrixUser, RemoteUser, Bridge, Entry, UserBridgeStore } from "matrix-appservice-bridge"; import { DiscordBridgeConfig } from "./config"; import * as Bluebird from "bluebird"; @@ -59,14 +59,14 @@ export class UserSyncroniser { public static readonly ERR_NEWER_EVENT = "newer_state_event_arrived"; // roomId+userId => ev - public userStateHold: Map<string, any>; + public userStateHold: Map<string, IMatrixEvent>; private userStore: UserBridgeStore; constructor( private bridge: Bridge, private config: DiscordBridgeConfig, private discord: DiscordBot) { this.userStore = this.bridge.getUserStore(); - this.userStateHold = new Map<string, any>(); + this.userStateHold = new Map<string, IMatrixEvent>(); } /** @@ -276,7 +276,7 @@ export class UserSyncroniser { ); } - public async UpdateStateForGuilds(remoteUser: any) { + public async UpdateStateForGuilds(remoteUser: RemoteUser) { const id = remoteUser.getId(); log.info(`Got update for ${id}.`); @@ -295,7 +295,7 @@ export class UserSyncroniser { }); } - public async OnMemberState(ev: any, delayMs: number = 0): Promise<string> { + public async OnMemberState(ev: IMatrixEvent, delayMs: number = 0): Promise<string> { // Avoid tripping over multiple state events. if (await this.memberStateLock(ev, delayMs) === false) { // We're igorning this update because we have a newer one. @@ -328,7 +328,7 @@ export class UserSyncroniser { return this.ApplyStateToRoom(state, roomId, member.guild.id); } - private async memberStateLock(ev: any, delayMs: number = -1): Promise<boolean> { + private async memberStateLock(ev: IMatrixEvent, delayMs: number = -1): Promise<boolean> { const userStateKey = `${ev.room_id}${ev.state_key}`; if (this.userStateHold.has(userStateKey)) { const oldEv = this.userStateHold.get(userStateKey); diff --git a/src/util.ts b/src/util.ts index 43050c846d130d3d5aca7cc65e12e0d74c071f53..09afd905e946514e02828c2f2be5742537d82699 100644 --- a/src/util.ts +++ b/src/util.ts @@ -4,6 +4,7 @@ import { Intent } from "matrix-appservice-bridge"; import { Buffer } from "buffer"; import * as mime from "mime"; import { Permissions } from "discord.js"; +import { DiscordBridgeConfig } from "./config"; const HTTP_OK = 200; @@ -14,7 +15,7 @@ export interface ICommandAction { params: string[]; description?: string; permission?: string; - run(params: any): Promise<any>; + run(params: any): Promise<any>; // tslint:disable-line no-any } export interface ICommandActions { @@ -23,13 +24,40 @@ export interface ICommandActions { export interface ICommandParameter { description?: string; - get(param: string): Promise<any>; + get(param: string): Promise<any>; // tslint:disable-line no-any } export interface ICommandParameters { [index: string]: ICommandParameter; } +export interface IMatrixEventContent { + body?: string; + info?: any; // tslint:disable-line no-any + name?: string; + topic?: string; + membership?: string; + msgtype?: string; + url?: string; + displayname?: string; + "m.relates_to"?: any; // tslint:disable-line no-any +} + +export interface IMatrixEvent { + event_id: string; + state_key: string; + type: string; + sender: string; + room_id: string; + membership?: string; + avatar_url?: string; + displayname?: string; + redacts?: string; + content?: IMatrixEventContent; + unsigned?: any; // tslint:disable-line no-any + origin_server_ts?: number; +} + export class Util { /** * downloadFile - This function will take a URL and store the resulting data into @@ -128,13 +156,13 @@ export class Util { * @param {number} duration The number of milliseconds to wait * @returns {Promise<any>} The promise */ - public static async DelayedPromise(duration: number): Promise<any> { - return new Promise<any>((resolve, reject) => { + public static async DelayedPromise(duration: number): Promise<void> { + return new Promise<void>((resolve, reject) => { setTimeout(resolve, duration); }); } - public static GetBotLink(config: any): string { + public static GetBotLink(config: DiscordBridgeConfig): string { /* tslint:disable:no-bitwise */ const perms = Permissions.FLAGS.READ_MESSAGES | Permissions.FLAGS.SEND_MESSAGES | diff --git a/test/test_matrixeventprocessor.ts b/test/test_matrixeventprocessor.ts index 861e164b77862a5a7c966191454da9cb96d30aa9..fd030fccc64ef971a9eb44d710df497f39dfc8bd 100644 --- a/test/test_matrixeventprocessor.ts +++ b/test/test_matrixeventprocessor.ts @@ -9,10 +9,11 @@ import { MockGuild } from "./mocks/guild"; import { MockCollection } from "./mocks/collection"; import { MockMember } from "./mocks/member"; import { MockEmoji } from "./mocks/emoji"; -import {MatrixEventProcessor, MatrixEventProcessorOpts} from "../src/matrixeventprocessor"; -import {DiscordBridgeConfig} from "../src/config"; -import {MessageProcessor, MessageProcessorOpts} from "../src/messageprocessor"; -import {MockChannel} from "./mocks/channel"; +import { MatrixEventProcessor, MatrixEventProcessorOpts } from "../src/matrixeventprocessor"; +import { DiscordBridgeConfig } from "../src/config"; +import { MessageProcessor, MessageProcessorOpts } from "../src/messageprocessor"; +import { MockChannel } from "./mocks/channel"; +import { IMatrixEvent } from "../src/util"; // we are a test file and thus need those /* tslint:disable:no-unused-expression max-file-line-count no-any */ @@ -142,7 +143,7 @@ describe("MatrixEventProcessor", () => { const event = { sender: "@user:localhost", type: "m.room.nonexistant", - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, undefined); @@ -152,7 +153,7 @@ describe("MatrixEventProcessor", () => { const event = { sender: "@botuser:localhost", type: "m.room.member", - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, undefined); @@ -165,7 +166,7 @@ describe("MatrixEventProcessor", () => { }, sender: "@user:localhost", type: "m.room.name", - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` set the name to `Test Name` on Matrix."); @@ -178,7 +179,7 @@ describe("MatrixEventProcessor", () => { }, sender: "@user:localhost", type: "m.room.topic", - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` set the topic to `Test Topic` on Matrix."); @@ -192,7 +193,7 @@ describe("MatrixEventProcessor", () => { sender: "@user:localhost", type: "m.room.member", unsigned: {}, - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` joined the room on Matrix."); @@ -207,7 +208,7 @@ describe("MatrixEventProcessor", () => { state_key: "@user2:localhost", type: "m.room.member", unsigned: {}, - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` invited `@user2:localhost` to the room on Matrix."); @@ -222,7 +223,7 @@ describe("MatrixEventProcessor", () => { state_key: "@user2:localhost", type: "m.room.member", unsigned: {}, - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` kicked `@user2:localhost` from the room on Matrix."); @@ -237,7 +238,7 @@ describe("MatrixEventProcessor", () => { state_key: "@user:localhost", type: "m.room.member", unsigned: {}, - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` left the room on Matrix."); @@ -252,7 +253,7 @@ describe("MatrixEventProcessor", () => { state_key: "@user2:localhost", type: "m.room.member", unsigned: {}, - }; + } as IMatrixEvent; const channel = new MockChannel("123456"); const msg = processor.StateEventToMessage(event, channel as any); Chai.assert.equal(msg, "`@user:localhost` banned `@user2:localhost` from the room on Matrix."); @@ -266,11 +267,11 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@test:localhost", - }, + } as IMatrixEvent, { avatar_url: "mxc://localhost/avatarurl", displayname: "Test User", - }, mockChannel as any); + } as IMatrixEvent, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "Test User"); Chai.assert.equal(author.icon_url, "https://localhost/avatarurl"); @@ -284,8 +285,9 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@test:localhost", - }, { - displayname: "Test User"}, mockChannel as any); + } as IMatrixEvent, { + displayname: "Test User", + } as IMatrixEvent, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "Test User"); Chai.assert.isUndefined(author.icon_url); @@ -299,7 +301,7 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@test:localhost", - }, null, mockChannel as any); + } as IMatrixEvent, null, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "@test:localhost"); Chai.assert.isUndefined(author.icon_url); @@ -313,8 +315,9 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@test:localhost", - }, { - displayname: "t"}, mockChannel as any); + } as IMatrixEvent, { + displayname: "t", + } as IMatrixEvent, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "@test:localhost"); }); @@ -326,9 +329,9 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@test:localhost", - }, { + } as IMatrixEvent, { displayname: "this is a very very long displayname that should be capped", - }, mockChannel as any); + } as IMatrixEvent, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "@test:localhost"); }); @@ -340,7 +343,7 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@testwithalottosayaboutitselfthatwillgoonandonandonandon:localhost", - }, null, mockChannel as any); + } as IMatrixEvent, null, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "@testwithalottosayaboutitselftha"); }); @@ -352,7 +355,9 @@ describe("MatrixEventProcessor", () => { body: "testcontent", }, sender: "@test:localhost", - }, {avatar_url: "mxc://localhost/test"}, mockChannel as any); + } as IMatrixEvent, { + avatar_url: "mxc://localhost/test", + } as IMatrixEvent, mockChannel as any); const author = embeds.messageEmbed.author; Chai.assert.equal(author.name, "@test:localhost"); Chai.assert.equal(author.icon_url, "https://localhost/test"); @@ -366,7 +371,9 @@ describe("MatrixEventProcessor", () => { body: "@testuser2 Hello!", }, sender: "@test:localhost", - }, {avatar_url: "test"}, mockChannel as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannel as any); Chai.assert.equal(embeds.messageEmbed.description, "<@!12345> Hello!"); }); @@ -377,7 +384,9 @@ describe("MatrixEventProcessor", () => { body: "@testuser2 Hello!", }, sender: "@test:localhost", - }, {avatar_url: "test"}, mockChannel as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannel as any); Chai.assert.equal(embeds.messageEmbed.description, "@testuser2 Hello!"); }); @@ -388,7 +397,9 @@ describe("MatrixEventProcessor", () => { body: "@everyone Hello!", }, sender: "@test:localhost", - }, {avatar_url: "test"}, mockChannel as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannel as any); Chai.assert.equal(embeds.messageEmbed.description, "@ everyone Hello!"); }); @@ -399,7 +410,9 @@ describe("MatrixEventProcessor", () => { body: "@here Hello!", }, sender: "@test:localhost", - }, {avatar_url: "test"}, mockChannel as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannel as any); Chai.assert.equal(embeds.messageEmbed.description, "@ here Hello!"); }); @@ -417,7 +430,9 @@ describe("MatrixEventProcessor", () => { body: "I like :supercake:", }, sender: "@test:localhost", - }, {avatar_url: "test"}, mockChannelEmojis as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannelEmojis as any); Chai.assert.equal( embeds.messageEmbed.description, "I like <:supercake:123>", @@ -438,7 +453,9 @@ describe("MatrixEventProcessor", () => { body: "I like :lamecake:", }, sender: "@test:localhost", - }, {avatar_url: "test"}, mockChannelEmojis as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannelEmojis as any); Chai.assert.equal( embeds.messageEmbed.description, "I like :lamecake:", @@ -452,9 +469,9 @@ describe("MatrixEventProcessor", () => { msgtype: "m.emote", }, sender: "@test:localhost", - }, { + } as IMatrixEvent, { displayname: "displayname", - }, mockChannel as any); + } as IMatrixEvent, mockChannel as any); Chai.assert.equal( embeds.messageEmbed.description, "*displayname likes puppies*", @@ -469,7 +486,9 @@ describe("MatrixEventProcessor", () => { }, sender: "@test:localhost", type: "m.sticker", - }, {avatar_url: "test"}, mockChannel as any); + } as IMatrixEvent, { + avatar_url: "test", + } as IMatrixEvent, mockChannel as any); Chai.assert.equal(embeds.messageEmbed.description, ""); }); }); @@ -587,7 +606,7 @@ describe("MatrixEventProcessor", () => { content: { msgtype: "m.text", }, - }, mxClient)).to.eventually.eq(""); + } as IMatrixEvent, mxClient)).to.eventually.eq(""); }); it("message without an info", () => { const processor = createMatrixEventProcessor(); @@ -597,7 +616,7 @@ describe("MatrixEventProcessor", () => { msgtype: "m.video", url: "mxc://localhost/200", }, - }, mxClient)).to.eventually.satisfy((attachment) => { + } as IMatrixEvent, mxClient)).to.eventually.satisfy((attachment) => { expect(attachment.name).to.eq("filename.webm"); expect(attachment.attachment.length).to.eq(SMALL_FILE); return true; @@ -612,7 +631,7 @@ describe("MatrixEventProcessor", () => { }, msgtype: "m.video", }, - }, mxClient)).to.eventually.eq(""); + } as IMatrixEvent, mxClient)).to.eventually.eq(""); }); it("message with a large info.size", () => { const LARGE_FILE = 8000000; @@ -626,7 +645,8 @@ describe("MatrixEventProcessor", () => { msgtype: "m.video", url: "mxc://localhost/8000000", }, - }, mxClient)).to.eventually.eq("[filename.webm](https://localhost/8000000)"); + } as IMatrixEvent, mxClient)) + .to.eventually.eq("[filename.webm](https://localhost/8000000)"); }); it("message with a small info.size", () => { const processor = createMatrixEventProcessor(); @@ -639,7 +659,7 @@ describe("MatrixEventProcessor", () => { msgtype: "m.video", url: "mxc://localhost/200", }, - }, mxClient)).to.eventually.satisfy((attachment) => { + } as IMatrixEvent, mxClient)).to.eventually.satisfy((attachment) => { expect(attachment.name).to.eq("filename.webm"); expect(attachment.attachment.length).to.eq(SMALL_FILE); return true; @@ -656,7 +676,7 @@ describe("MatrixEventProcessor", () => { msgtype: "m.video", url: "mxc://localhost/8000000", }, - }, mxClient)).to.eventually.eq("[filename.webm](https://localhost/8000000)"); + } as IMatrixEvent, mxClient)).to.eventually.eq("[filename.webm](https://localhost/8000000)"); }); it("Should handle stickers.", () => { const processor = createMatrixEventProcessor(); @@ -670,7 +690,7 @@ describe("MatrixEventProcessor", () => { }, sender: "@test:localhost", type: "m.sticker", - }, mxClient)).to.eventually.satisfy((attachment) => { + } as IMatrixEvent, mxClient)).to.eventually.satisfy((attachment) => { expect(attachment.name).to.eq("Bunnies.png"); return true; }); @@ -685,7 +705,7 @@ describe("MatrixEventProcessor", () => { }, sender: "@test:localhost", type: "m.room.message", - }); + } as IMatrixEvent); expect(result).to.be.undefined; }); it("should handle replies without a fallback", async () => { @@ -701,7 +721,7 @@ describe("MatrixEventProcessor", () => { }, sender: "@test:localhost", type: "m.room.message", - }); + } as IMatrixEvent); expect(result[0].description).to.be.equal("Hello!"); expect(result[0].author.name).to.be.equal("Doggo!"); expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com"); @@ -723,7 +743,7 @@ This is where the reply goes`, }, sender: "@test:localhost", type: "m.room.message", - }); + } as IMatrixEvent); expect(result[0].description).to.be.equal("Reply with unknown content"); expect(result[0].author.name).to.be.equal("Unknown"); expect(result[0].author.icon_url).to.be.undefined; @@ -745,7 +765,7 @@ This is where the reply goes`, }, sender: "@test:localhost", type: "m.room.message", - }); + } as IMatrixEvent); expect(result[0].description).to.be.equal("Hello!"); expect(result[0].author.name).to.be.equal("Doggo!"); expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com"); @@ -767,7 +787,7 @@ This is the second reply`, }, sender: "@test:localhost", type: "m.room.message", - }); + } as IMatrixEvent); expect(result[0].description).to.be.equal("This is the first reply"); expect(result[0].author.name).to.be.equal("Doggo!"); expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com"); @@ -789,7 +809,7 @@ This is the reply`, }, sender: "@test:localhost", type: "m.room.message", - }); + } as IMatrixEvent); expect(result[0].description).to.be.equal("Reply with unknown content"); expect(result[0].author.name).to.be.equal("Doggo!"); expect(result[0].author.icon_url).to.be.equal("https://fakeurl.com"); diff --git a/test/test_matrixroomhandler.ts b/test/test_matrixroomhandler.ts index f96baa87c6a59d4c1a88d5aee4b5765ef951e88e..789b58943a992f146e8af2126ef9422027c27036 100644 --- a/test/test_matrixroomhandler.ts +++ b/test/test_matrixroomhandler.ts @@ -41,6 +41,8 @@ let USERSKICKED = 0; let USERSBANNED = 0; let USERSUNBANNED = 0; let MESSAGESENT: any = {}; +let USERSYNC_HANDLED = false; +let MESSAGE_PROCCESS = ""; function buildRequest(eventData) { if (eventData.unsigned === undefined) { @@ -56,6 +58,8 @@ function createRH(opts: any = {}) { USERSKICKED = 0; USERSBANNED = 0; USERSUNBANNED = 0; + USERSYNC_HANDLED = false; + MESSAGE_PROCCESS = ""; const bridge = { getBot: () => { return { @@ -86,7 +90,9 @@ function createRH(opts: any = {}) { }; const us = { EnsureJoin: async () => { }, - OnMemberState: async () => "user_sync_handled", + OnMemberState: async () => { + USERSYNC_HANDLED = true; + }, OnUpdateUser: async () => { }, }; const cs = { @@ -126,9 +132,15 @@ function createRH(opts: any = {}) { const channel = new MockChannel(); return {channel, botUser: true }; }, - ProcessMatrixMsgEvent: async () => "processed", - ProcessMatrixRedact: async () => "redacted", - ProcessMatrixStateEvent: async () => "stateevent", + ProcessMatrixMsgEvent: async () => { + MESSAGE_PROCCESS = "processed"; + }, + ProcessMatrixRedact: async () => { + MESSAGE_PROCCESS = "redacted"; + }, + ProcessMatrixStateEvent: async () => { + MESSAGE_PROCCESS = "stateevent"; + }, ThirdpartySearchForChannels: () => { return []; }, @@ -206,37 +218,48 @@ describe("MatrixRoomHandler", () => { type: "m.potato", unsigned: {age: AGE}}), null)).to.be.rejectedWith("Event not processed by bridge"); }); - it("should handle invites", () => { + it("should handle invites", async () => { const handler = createRH(); - handler.HandleInvite = async (ev) => "invited"; - return expect(handler.OnEvent(buildRequest({ + let invited = false; + handler.HandleInvite = async (ev) => { + invited = true; + }; + await handler.OnEvent(buildRequest({ content: {membership: "invite"}, - type: "m.room.member"}), null)).to.eventually.equal("invited"); + type: "m.room.member"}), null); + expect(invited).to.be.true; }); - it("should handle own state updates", () => { + it("should handle own state updates", async () => { const handler = createRH(); - return expect(handler.OnEvent(buildRequest({ + await handler.OnEvent(buildRequest({ content: {membership: "join"}, state_key: "@_discord_12345:localhost", - type: "m.room.member"}), null)).to.eventually.equal("user_sync_handled"); + type: "m.room.member"}), null); + expect(USERSYNC_HANDLED).to.be.true; }); - it("should pass other member types to state event", () => { + it("should pass other member types to state event", async () => { const handler = createRH(); - handler.HandleInvite = async (ev) => "invited"; - return expect(handler.OnEvent(buildRequest({ + let invited = false; + handler.HandleInvite = async (ev) => { + invited = true; + }; + handler.OnEvent(buildRequest({ content: {membership: "join"}, state_key: "@bacon:localhost", - type: "m.room.member"}), null)).to.eventually.equal("stateevent"); + type: "m.room.member"}), null); + expect(invited).to.be.false; + expect(MESSAGE_PROCCESS).equals("stateevent"); }); - it("should handle redactions with existing rooms", () => { + it("should handle redactions with existing rooms", async () => { const handler = createRH(); const context = { rooms: { remote: true, }, }; - return expect(handler.OnEvent(buildRequest({ - type: "m.room.redaction"}), context)).to.eventually.equal("redacted"); + await handler.OnEvent(buildRequest({ + type: "m.room.redaction"}), context); + expect(MESSAGE_PROCCESS).equals("redacted"); }); it("should ignore redactions with no linked room", () => { const handler = createRH(); @@ -248,7 +271,7 @@ describe("MatrixRoomHandler", () => { return expect(handler.OnEvent(buildRequest({ type: "m.room.redaction"}), context)).to.be.rejectedWith("Event not processed by bridge"); }); - it("should process regular messages", () => { + it("should process regular messages", async () => { const handler = createRH(); const context = { rooms: { @@ -257,10 +280,11 @@ describe("MatrixRoomHandler", () => { }, }, }; - return expect(handler.OnEvent(buildRequest({ + await handler.OnEvent(buildRequest({ content: {body: "abc"}, type: "m.room.message", - }), context)).to.eventually.equal("processed"); + }), context); + expect(MESSAGE_PROCCESS).equals("processed"); }); it("should alert if encryption is turned on", () => { const handler = createRH(); @@ -276,13 +300,17 @@ describe("MatrixRoomHandler", () => { type: "m.room.encryption", }), context)).to.eventually.be.fulfilled; }); - it("should process !discord commands", () => { + it("should process !discord commands", async () => { const handler = createRH(); - handler.ProcessCommand = async (ev) => "processedcmd"; - return expect(handler.OnEvent(buildRequest({ + let processedcmd = false; + handler.ProcessCommand = async (ev) => { + processedcmd = true; + }; + await handler.OnEvent(buildRequest({ content: {body: "!discord cmd"}, type: "m.room.message", - }), null)).to.eventually.equal("processedcmd"); + }), null); + expect(processedcmd).to.be.true; }); it("should ignore regular messages with no linked room", () => { const handler = createRH(); @@ -296,7 +324,7 @@ describe("MatrixRoomHandler", () => { type: "m.room.message", }), context)).to.be.rejectedWith("Event not processed by bridge"); }); - it("should process stickers", () => { + it("should process stickers", async () => { const handler = createRH(); const context = { rooms: { @@ -305,13 +333,14 @@ describe("MatrixRoomHandler", () => { }, }, }; - return expect(handler.OnEvent(buildRequest({ + await handler.OnEvent(buildRequest({ content: { body: "abc", url: "mxc://abc", }, type: "m.sticker", - }), context)).to.eventually.equal("processed"); + }), context); + expect(MESSAGE_PROCCESS).equals("processed"); }); }); describe("HandleInvite", () => { diff --git a/test/test_usersyncroniser.ts b/test/test_usersyncroniser.ts index b349475152d1aab8d9738ecc1421f2a80f95eab3..b8febd30713183283daa2656a0aedc0549d6f9a2 100644 --- a/test/test_usersyncroniser.ts +++ b/test/test_usersyncroniser.ts @@ -8,6 +8,7 @@ import * as Proxyquire from "proxyquire"; import {MockMember} from "./mocks/member"; import {MockGuild} from "./mocks/guild"; import { MockChannel } from "./mocks/channel"; +import { IMatrixEvent } from "../src/util"; // we are a test file and thus need those /* tslint:disable:no-unused-expression max-file-line-count no-any */ @@ -511,46 +512,46 @@ describe("UserSyncroniser", () => { }); describe("OnMemberState", () => { it("will update state for rooms", async () => { - const userSync = CreateUserSync([new RemoteUser("123456")]); - return userSync.OnMemberState({ - content: { + const userSync = CreateUserSync([new RemoteUser("123456")]); + return userSync.OnMemberState({ + content: { - }, - room_id: "!found:localhost", - state_key: "123456", - }, 0).then(() => { - expect(SEV_COUNT).to.equal(1); - }); + }, + room_id: "!found:localhost", + state_key: "123456", + } as IMatrixEvent, 0).then(() => { + expect(SEV_COUNT).to.equal(1); + }); }); it("will not update state for a unknown user", async () => { - const userSync = CreateUserSync([]); - return expect(userSync.OnMemberState({ - content: { + const userSync = CreateUserSync([]); + return expect(userSync.OnMemberState({ + content: { - }, - room_id: "!abcdef:localhost", - state_key: "123456", - }, 0)).to.eventually.equal(UserSyncroniser.ERR_USER_NOT_FOUND); + }, + room_id: "!abcdef:localhost", + state_key: "123456", + } as IMatrixEvent, 0)).to.eventually.equal(UserSyncroniser.ERR_USER_NOT_FOUND); }); it("will not update state for a unknown room", async () => { const userSync = CreateUserSync([new RemoteUser("123456")]); return expect(userSync.OnMemberState({ - content: { + content: { - }, - room_id: "!notfound:localhost", - state_key: "123456", - }, 0)).to.eventually.equal(UserSyncroniser.ERR_CHANNEL_MEMBER_NOT_FOUND); + }, + room_id: "!notfound:localhost", + state_key: "123456", + } as IMatrixEvent, 0)).to.eventually.equal(UserSyncroniser.ERR_CHANNEL_MEMBER_NOT_FOUND); }); it("will not update state for a member not found in the channel", async () => { const userSync = CreateUserSync([new RemoteUser("111222")]); return expect(userSync.OnMemberState({ - content: { + content: { - }, - room_id: "!found:localhost", - state_key: "111222", - }, 0)).to.eventually.equal(UserSyncroniser.ERR_CHANNEL_MEMBER_NOT_FOUND); + }, + room_id: "!found:localhost", + state_key: "111222", + } as IMatrixEvent, 0)).to.eventually.equal(UserSyncroniser.ERR_CHANNEL_MEMBER_NOT_FOUND); }); it("will not process old events", async () => { const DELAY_MS = 250; @@ -562,35 +563,36 @@ describe("UserSyncroniser", () => { origin_server_ts: 10000, room_id: "!found:localhost", state_key: "123456", - }, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 1 Failed"), + } as IMatrixEvent, DELAY_MS)) + .to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 1 Failed"), expect(userSync.OnMemberState({ content: { }, event_id: "QuiteOld:localhost", origin_server_ts: 7000, room_id: "!found:localhost", state_key: "123456", - }, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 2 Failed"), + } as IMatrixEvent, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 2 Failed"), expect(userSync.OnMemberState({ content: { }, event_id: "FreshEnough:localhost", origin_server_ts: 3000, room_id: "!found:localhost", state_key: "123456", - }, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 3 Failed"), + } as IMatrixEvent, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 3 Failed"), expect(userSync.OnMemberState({ content: { }, event_id: "GettingOnABit:localhost", origin_server_ts: 4000, room_id: "!found:localhost", state_key: "123456", - }, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 4 Failed"), + } as IMatrixEvent, DELAY_MS)).to.eventually.equal(UserSyncroniser.ERR_NEWER_EVENT, "State 4 Failed"), expect(userSync.OnMemberState({ content: { }, event_id: "FreshOutTheOven:localhost", origin_server_ts: 100, room_id: "!found:localhost", state_key: "123456", - }, DELAY_MS)).to.eventually.be.fulfilled, + } as IMatrixEvent, DELAY_MS)).to.eventually.be.fulfilled, ]); }); });