diff --git a/src/LogProxy.ts b/src/LogProxy.ts index a6d14b7..47699e2 100644 --- a/src/LogProxy.ts +++ b/src/LogProxy.ts @@ -26,7 +26,7 @@ const levelToFn = { [LogLevel.ERROR.toString()]: LogService.error, }; -export async function logMessage(level: LogLevel, module: string, message: string | any, additionalRoomIds: string[] | string = null, isRecursive = false) { +export async function logMessage(level: LogLevel, module: string, message: string | any, additionalRoomIds: string[] | string | null = null, isRecursive = false) { if (!additionalRoomIds) additionalRoomIds = []; if (!Array.isArray(additionalRoomIds)) additionalRoomIds = [additionalRoomIds]; diff --git a/src/Mjolnir.ts b/src/Mjolnir.ts index 5f0766b..0aadcb8 100644 --- a/src/Mjolnir.ts +++ b/src/Mjolnir.ts @@ -153,7 +153,7 @@ export class Mjolnir { await logMessage(LogLevel.DEBUG, "Mjolnir@startup", "Loading protected rooms..."); await this.resyncJoinedRooms(false); try { - const data = await this.client.getAccountData(PROTECTED_ROOMS_EVENT_TYPE); + const data: Object|null = await this.client.getAccountData(PROTECTED_ROOMS_EVENT_TYPE); if (data && data['rooms']) { for (const roomId of data['rooms']) { this.protectedRooms[roomId] = Permalinks.forRoom(roomId); @@ -252,7 +252,7 @@ export class Mjolnir { private async getEnabledProtections() { let enabled: string[] = []; try { - const protections = await this.client.getAccountData(ENABLED_PROTECTIONS_EVENT_TYPE); + const protections: Object|null = await this.client.getAccountData(ENABLED_PROTECTIONS_EVENT_TYPE); if (protections && protections['enabled']) { for (const protection of protections['enabled']) { enabled.push(protection); @@ -296,7 +296,7 @@ export class Mjolnir { await this.client.setAccountData(ENABLED_PROTECTIONS_EVENT_TYPE, {enabled: existing}); } - public async watchList(roomRef: string): Promise { + public async watchList(roomRef: string): Promise { const joinedRooms = await this.client.getJoinedRooms(); const permalink = Permalinks.parseUrl(roomRef); if (!permalink.roomIdOrAlias) return null; @@ -321,12 +321,12 @@ export class Mjolnir { return list; } - public async unwatchList(roomRef: string): Promise { + public async unwatchList(roomRef: string): Promise { const permalink = Permalinks.parseUrl(roomRef); if (!permalink.roomIdOrAlias) return null; const roomId = await this.client.resolveRoom(permalink.roomIdOrAlias); - const list = this.banLists.find(b => b.roomId === roomId); + const list = this.banLists.find(b => b.roomId === roomId) || null; if (list) this.banLists.splice(this.banLists.indexOf(list), 1); await this.client.setAccountData(WATCHED_LISTS_EVENT_TYPE, { @@ -347,7 +347,7 @@ export class Mjolnir { this.applyUnprotectedRooms(); try { - const accountData = await this.client.getAccountData(WARN_UNPROTECTED_ROOM_EVENT_PREFIX + roomId); + const accountData: Object|null = await this.client.getAccountData(WARN_UNPROTECTED_ROOM_EVENT_PREFIX + roomId); if (accountData && accountData['warned']) return; // already warned } catch (e) { // Ignore - probably haven't warned about it yet @@ -595,7 +595,7 @@ export class Mjolnir { } } - private async printActionResult(errors: RoomUpdateError[], title: string = null, logAnyways = false) { + private async printActionResult(errors: RoomUpdateError[], title: string|null = null, logAnyways = false) { if (errors.length <= 0) return false; if (!logAnyways) { diff --git a/src/commands/ImportCommand.ts b/src/commands/ImportCommand.ts index 56f9646..e68ab3d 100644 --- a/src/commands/ImportCommand.ts +++ b/src/commands/ImportCommand.ts @@ -53,7 +53,10 @@ export async function execImportCommand(roomId: string, event: any, mjolnir: Mjo reason: reason, }; const stateKey = `rule:${ruleContent.entity}`; - await mjolnir.client.sendStateEvent(list.roomId, ruleTypeToStable(RULE_USER), stateKey, ruleContent); + let stableRule = ruleTypeToStable(RULE_USER); + if (stableRule) { + await mjolnir.client.sendStateEvent(list.roomId, stableRule, stateKey, ruleContent); + } importedRules++; } } else if (stateEvent['type'] === 'm.room.server_acl' && stateEvent['state_key'] === '') { @@ -71,7 +74,10 @@ export async function execImportCommand(roomId: string, event: any, mjolnir: Mjo reason: reason, }; const stateKey = `rule:${ruleContent.entity}`; - await mjolnir.client.sendStateEvent(list.roomId, ruleTypeToStable(RULE_SERVER), stateKey, ruleContent); + let stableRule = ruleTypeToStable(RULE_SERVER); + if (stableRule) { + await mjolnir.client.sendStateEvent(list.roomId, stableRule, stateKey, ruleContent); + } importedRules++; } } diff --git a/src/commands/RedactCommand.ts b/src/commands/RedactCommand.ts index e128db1..4896758 100644 --- a/src/commands/RedactCommand.ts +++ b/src/commands/RedactCommand.ts @@ -21,8 +21,8 @@ import { Permalinks } from "matrix-bot-sdk"; // !mjolnir redact [room alias] [limit] export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { const userId = parts[2]; - let roomAlias = null; - let limit = Number.parseInt(parts.length > 3 ? parts[3] : null, 10); // default to NaN for later + let roomAlias: string|null = null; + let limit = Number.parseInt(parts.length > 3 ? parts[3] : "", 10); // default to NaN for later if (parts.length > 3 && isNaN(limit)) { roomAlias = await mjolnir.client.resolveRoom(parts[3]); if (parts.length > 4) { diff --git a/src/commands/UnbanBanCommand.ts b/src/commands/UnbanBanCommand.ts index 3caa40b..7aa00d4 100644 --- a/src/commands/UnbanBanCommand.ts +++ b/src/commands/UnbanBanCommand.ts @@ -23,17 +23,17 @@ import { logMessage } from "../LogProxy"; import { DEFAULT_LIST_EVENT_TYPE } from "./SetDefaultBanListCommand"; interface Arguments { - list: BanList; + list: BanList | null; entity: string; - ruleType: string; + ruleType: string | null; reason: string; } // Exported for tests -export async function parseArguments(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]): Promise { +export async function parseArguments(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]): Promise { let defaultShortcode = null; try { - const data = await mjolnir.client.getAccountData(DEFAULT_LIST_EVENT_TYPE); + const data: Object = await mjolnir.client.getAccountData(DEFAULT_LIST_EVENT_TYPE); defaultShortcode = data['shortcode']; } catch (e) { LogService.warn("UnbanBanCommand", "Non-fatal error getting default ban list"); @@ -43,9 +43,9 @@ export async function parseArguments(roomId: string, event: any, mjolnir: Mjolni } let argumentIndex = 2; - let ruleType = null; - let entity = null; - let list = null; + let ruleType: string | null = null; + let entity: string | null = null; + let list: BanList | null = null; let force = false; while (argumentIndex < 7 && argumentIndex < parts.length) { const arg = parts[argumentIndex++]; @@ -62,7 +62,7 @@ export async function parseArguments(roomId: string, event: any, mjolnir: Mjolni else if (!ruleType) ruleType = RULE_SERVER; } else if (!list) { const foundList = mjolnir.lists.find(b => b.listShortcode.toLowerCase() === arg.toLowerCase()); - if (foundList) { + if (foundList !== undefined) { list = foundList; } } @@ -88,10 +88,10 @@ export async function parseArguments(roomId: string, event: any, mjolnir: Mjolni } if (!list) { - list = mjolnir.lists.find(b => b.listShortcode.toLowerCase() === defaultShortcode); + list = mjolnir.lists.find(b => b.listShortcode.toLowerCase() === defaultShortcode) || null; } - let replyMessage = null; + let replyMessage: string | null = null; if (!list) replyMessage = "No ban list matching that shortcode was found"; else if (!ruleType) replyMessage = "Please specify the type as either 'user', 'room', or 'server'"; else if (!entity) replyMessage = "No entity found"; @@ -128,7 +128,7 @@ export async function execBanCommand(roomId: string, event: any, mjolnir: Mjolni }; const stateKey = `rule:${bits.entity}`; - await mjolnir.client.sendStateEvent(bits.list.roomId, bits.ruleType, stateKey, ruleContent); + await mjolnir.client.sendStateEvent(bits.list!.roomId, bits.ruleType!, stateKey, ruleContent); await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅'); } @@ -140,14 +140,14 @@ export async function execUnbanCommand(roomId: string, event: any, mjolnir: Mjol const ruleContent = {}; // empty == clear/unban const stateKey = `rule:${bits.entity}`; - await mjolnir.client.sendStateEvent(bits.list.roomId, bits.ruleType, stateKey, ruleContent); + await mjolnir.client.sendStateEvent(bits.list!.roomId, bits.ruleType!, stateKey, ruleContent); - if (USER_RULE_TYPES.includes(bits.ruleType) && bits.reason === 'true') { + if (USER_RULE_TYPES.includes(bits.ruleType!) && bits.reason === 'true') { const rule = new MatrixGlob(bits.entity); await logMessage(LogLevel.INFO, "UnbanBanCommand", "Unbanning users that match glob: " + bits.entity); let unbannedSomeone = false; for (const protectedRoomId of Object.keys(mjolnir.protectedRooms)) { - const members = await mjolnir.client.getRoomMembers(protectedRoomId, null, ['ban'], null); + const members = await mjolnir.client.getRoomMembers(protectedRoomId, undefined, ['ban'], undefined); await logMessage(LogLevel.DEBUG, "UnbanBanCommand", `Found ${members.length} banned user(s)`); for (const member of members) { const victim = member.membershipFor; diff --git a/src/config.ts b/src/config.ts index 2a64285..749ed96 100644 --- a/src/config.ts +++ b/src/config.ts @@ -66,7 +66,7 @@ interface IConfig { * here as much as possible. */ RUNTIME: { - client: MatrixClient; + client?: MatrixClient; }; } @@ -116,7 +116,6 @@ const defaultConfig: IConfig = { // Needed to make the interface happy. RUNTIME: { - client: null, }, }; diff --git a/src/index.ts b/src/index.ts index 989545a..41da5f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,7 +32,7 @@ import { MembershipEvent } from "matrix-bot-sdk/lib/models/events/MembershipEven import * as htmlEscape from "escape-html"; import { Healthz } from "./health/healthz"; -config.RUNTIME = {client: null}; +config.RUNTIME = {}; LogService.setLogger(new RichConsoleLogger()); LogService.setLevel(LogLevel.fromString(config.logLevel, LogLevel.DEBUG)); diff --git a/src/models/BanList.ts b/src/models/BanList.ts index 877dd77..d25c6d8 100644 --- a/src/models/BanList.ts +++ b/src/models/BanList.ts @@ -28,7 +28,7 @@ export const ALL_RULE_TYPES = [...USER_RULE_TYPES, ...ROOM_RULE_TYPES, ...SERVER export const SHORTCODE_EVENT_TYPE = "org.matrix.mjolnir.shortcode"; -export function ruleTypeToStable(rule: string, unstable = true): string { +export function ruleTypeToStable(rule: string, unstable = true): string|null { if (USER_RULE_TYPES.includes(rule)) return unstable ? USER_RULE_TYPES[USER_RULE_TYPES.length - 1] : RULE_USER; if (ROOM_RULE_TYPES.includes(rule)) return unstable ? ROOM_RULE_TYPES[ROOM_RULE_TYPES.length - 1] : RULE_ROOM; if (SERVER_RULE_TYPES.includes(rule)) return unstable ? SERVER_RULE_TYPES[SERVER_RULE_TYPES.length - 1] : RULE_SERVER; @@ -37,7 +37,7 @@ export function ruleTypeToStable(rule: string, unstable = true): string { export default class BanList { private rules: ListRule[] = []; - private shortcode: string = null; + private shortcode: string|null = null; constructor(public readonly roomId: string, public readonly roomRef, private client: MatrixClient) { } @@ -85,7 +85,7 @@ export default class BanList { continue; } - let kind: string = null; + let kind: string|null = null; if (USER_RULE_TYPES.includes(event['type'])) { kind = RULE_USER; } else if (ROOM_RULE_TYPES.includes(event['type'])) { diff --git a/src/models/ListRule.ts b/src/models/ListRule.ts index a5a9066..faf9723 100644 --- a/src/models/ListRule.ts +++ b/src/models/ListRule.ts @@ -19,7 +19,7 @@ import { MatrixGlob } from "matrix-bot-sdk"; export const RECOMMENDATION_BAN = "m.ban"; export const RECOMMENDATION_BAN_TYPES = [RECOMMENDATION_BAN, "org.matrix.mjolnir.ban"]; -export function recommendationToStable(recommendation: string, unstable = true): string { +export function recommendationToStable(recommendation: string, unstable = true): string|null { if (RECOMMENDATION_BAN_TYPES.includes(recommendation)) return unstable ? RECOMMENDATION_BAN_TYPES[RECOMMENDATION_BAN_TYPES.length - 1] : RECOMMENDATION_BAN; return null; } diff --git a/src/utils.ts b/src/utils.ts index 1d78d7d..9acee00 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -150,7 +150,7 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string, let token = timeline['prev_batch'] || response['next_batch']; let bfMessages = {chunk: syncedMessages, end: token}; do { - const messages = []; + const messages: any[] = []; for (const event of (bfMessages['chunk'] || [])) { if (processed >= limit) return; // we're done even if we don't want to be processed++; @@ -199,7 +199,9 @@ export async function replaceRoomIdsWithPills(client: MatrixClient, text: string } const regexRoomId = new RegExp(escapeRegex(roomId), "g"); content.body = content.body.replace(regexRoomId, alias); - content.formatted_body = content.formatted_body.replace(regexRoomId, `${alias}`); + if (content.formatted_body) { + content.formatted_body = content.formatted_body.replace(regexRoomId, `${alias}`); + } } return content; diff --git a/tsconfig.json b/tsconfig.json index 0cfc74e..3e9b06f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "target": "es2015", "noImplicitAny": false, "sourceMap": true, + "strictNullChecks": true, "outDir": "./lib", "types": [ "node",