diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml deleted file mode 100644 index 2ad4d5c67..000000000 --- a/.buildkite/pipeline.yml +++ /dev/null @@ -1,53 +0,0 @@ -steps: - - label: ":eslint: Lint" - command: - - "npm install" - - "npm run lint" - plugins: - - docker#v3.0.1: - image: "node:12" - - - label: ":jasmine: Tests Node 10" - command: - - "npm install" - - "npm run build" - - "npm run test" - plugins: - - docker#v3.0.1: - image: "node:10" - - - label: ":jasmine: Tests Node 12" - command: - - "npm install" - - "npm run build" - - "npm run test" - plugins: - - docker#v3.0.1: - image: "node:12" - - - label: ":nodejs: 12 :postgres: 11 :mocha: Postgres Test" - plugins: - - docker-compose#v2.1.0: - run: testenv - config: - - .buildkite/docker-compose.postgres.yml - - - label: ":nyc: Coverage" - command: - - "npm install" - - "npm run build" - - "npm run ci-test" - plugins: - - docker#v3.0.1: - image: "node:12" - - # Borrowed from https://github.com/matrix-org/synapse/blob/master/.buildkite/pipeline.yml - - label: ":newspaper: Newsfile" - branches: "!master !develop !release-*" - command: - - "python3 -m pip install towncrier" - - "python3 -m towncrier.check --compare-with=origin/develop" - plugins: - - docker#v3.0.1: - image: "python:3.6" - propagate-environment: true \ No newline at end of file diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index d02481ac3..000000000 --- a/.dockerignore +++ /dev/null @@ -1,12 +0,0 @@ -.* # Dot files -config* -*.md -*.log* -node_modules/ -bin/ -changelog.d/ -.buildkite/ -hooks/ -spec/ -lib/ -scripts/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 022e4a1c5..d35888991 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,9 @@ WORKDIR /build RUN apt-get update && apt-get install -y git python3 libicu-dev build-essential -COPY . /build/ +COPY src/ /build/src/ +COPY types/ /build/types/ +COPY .eslintrc *json /build/ RUN npm ci RUN npm run build @@ -34,7 +36,7 @@ COPY --from=freebind /freebindfree/libfreebindfree.so /app/libfreebindfree.so COPY --from=builder /build/node_modules /app/node_modules COPY --from=builder /build/lib /app/lib -COPY app.js /app/ +COPY app.js config.schema.yml /app/ COPY docker /app/docker ENV LD_PRELOAD /app/libfreebindfree.so diff --git a/changelog.d/919.bugfix b/changelog.d/919.bugfix new file mode 100644 index 000000000..850f79912 --- /dev/null +++ b/changelog.d/919.bugfix @@ -0,0 +1 @@ +If a new DM room is created for a IRC user, discard the old room. diff --git a/changelog.d/920.bugfix b/changelog.d/920.bugfix new file mode 100644 index 000000000..00bfd900c --- /dev/null +++ b/changelog.d/920.bugfix @@ -0,0 +1 @@ +Fix missig config.schema.yml in the Docker image \ No newline at end of file diff --git a/changelog.d/921.bugfix b/changelog.d/921.bugfix new file mode 100644 index 000000000..cfe508130 --- /dev/null +++ b/changelog.d/921.bugfix @@ -0,0 +1 @@ +Stop trying to use sentry when config.sentry.enabled is false \ No newline at end of file diff --git a/changelog.d/925.bugfix b/changelog.d/925.bugfix new file mode 100644 index 000000000..2ffe8c81e --- /dev/null +++ b/changelog.d/925.bugfix @@ -0,0 +1 @@ +Improve reply matching logic for Matrix messages. diff --git a/changelog.d/931.misc b/changelog.d/931.misc new file mode 100644 index 000000000..974cb90f3 --- /dev/null +++ b/changelog.d/931.misc @@ -0,0 +1 @@ +Use Typescript 3.7 and fix build issues. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 0240aeb4b..565670c55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -296,9 +296,9 @@ } }, "@types/json-schema": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz", - "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", "dev": true }, "@types/mime": { @@ -374,37 +374,49 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.2.0.tgz", - "integrity": "sha512-rOodtI+IvaO8USa6ValYOrdWm9eQBgqwsY+B0PPiB+aSiK6p6Z4l9jLn/jI3z3WM4mkABAhKIqvGIBl0AFRaLQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.14.0.tgz", + "integrity": "sha512-sneOJ3Hu0m5whJiVIxGBZZZMxMJ7c0LhAJzeMJgHo+n5wFs+/6rSR/gl7crkdR2kNwfOOSdzdc0gMvatG4dX2Q==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.2.0", - "eslint-utils": "^1.4.2", + "@typescript-eslint/experimental-utils": "2.14.0", + "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", - "regexpp": "^2.0.1", + "regexpp": "^3.0.0", "tsutils": "^3.17.1" }, "dependencies": { - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { - "tslib": "^1.8.1" + "eslint-visitor-keys": "^1.1.0" } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true } } }, "@typescript-eslint/experimental-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.2.0.tgz", - "integrity": "sha512-IMhbewFs27Frd/ICHBRfIcsUCK213B8MsEUqvKFK14SDPjPR5JF6jgOGPlroybFTrGWpMvN5tMZdXAf+xcmxsA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.14.0.tgz", + "integrity": "sha512-KcyKS7G6IWnIgl3ZpyxyBCxhkBPV+0a5Jjy2g5HxlrbG2ZLQNFeneIBVXdaBCYOVjvGmGGFKom1kgiAY75SDeQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.2.0", + "@typescript-eslint/typescript-estree": "2.14.0", "eslint-scope": "^5.0.0" }, "dependencies": { @@ -421,14 +433,14 @@ } }, "@typescript-eslint/parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.2.0.tgz", - "integrity": "sha512-0mf893kj9L65O5sA7wP6EoYvTybefuRFavUNhT7w9kjhkdZodoViwVS+k3D+ZxKhvtL7xGtP/y/cNMJX9S8W4A==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.14.0.tgz", + "integrity": "sha512-haS+8D35fUydIs+zdSf4BxpOartb/DjrZ2IxQ5sR8zyGfd77uT9ZJZYF8+I0WPhzqHmfafUBx8MYpcp8pfaoSA==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.2.0", - "@typescript-eslint/typescript-estree": "2.2.0", + "@typescript-eslint/experimental-utils": "2.14.0", + "@typescript-eslint/typescript-estree": "2.14.0", "eslint-visitor-keys": "^1.1.0" }, "dependencies": { @@ -441,17 +453,55 @@ } }, "@typescript-eslint/typescript-estree": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.2.0.tgz", - "integrity": "sha512-9/6x23A3HwWWRjEQbuR24on5XIfVmV96cDpGR9671eJv1ebFKHj2sGVVAwkAVXR2UNuhY1NeKS2QMv5P8kQb2Q==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.14.0.tgz", + "integrity": "sha512-pnLpUcMNG7GfFFfNQbEX6f1aPa5fMnH2G9By+A1yovYI4VIOK2DzkaRuUlIkbagpAcrxQHLqovI1YWqEcXyRnA==", "dev": true, "requires": { - "glob": "^7.1.4", + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", "is-glob": "^4.0.1", "lodash.unescape": "4.0.1", - "semver": "^6.3.0" + "semver": "^6.3.0", + "tsutils": "^3.17.1" }, "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -4173,6 +4223,15 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -4210,9 +4269,9 @@ } }, "typescript": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", - "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz", + "integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index 55a584a4c..05f929853 100644 --- a/package.json +++ b/package.json @@ -48,21 +48,21 @@ "@sentry/node": "^5.9.0" }, "devDependencies": { + "@types/bluebird": "^3.5.27", "@types/express": "^4.17.2", "@types/extend": "^3.0.1", - "@types/bluebird": "^3.5.27", "@types/he": "^1.1.0", "@types/nedb": "^1.8.9", "@types/nopt": "^3.0.29", "@types/pg": "^7.11.1", "@types/sanitize-html": "^1.20.2", - "@typescript-eslint/eslint-plugin": "^2.2.0", - "@typescript-eslint/parser": "^2.2.0", + "@typescript-eslint/eslint-plugin": "^2.14.0", + "@typescript-eslint/parser": "^2.14.0", "eslint": "^5.16.0", "jasmine": "^3.1.0", "nyc": "^14.1.1", + "prom-client": "^11.5.3", "proxyquire": "^1.4.0", - "typescript": "^3.6.3", - "prom-client": "^11.5.3" + "typescript": "^3.7.3" } } diff --git a/src/bridge/AdminRoomHandler.ts b/src/bridge/AdminRoomHandler.ts index f1d4b4cc4..e4a5e0f7d 100644 --- a/src/bridge/AdminRoomHandler.ts +++ b/src/bridge/AdminRoomHandler.ts @@ -268,7 +268,7 @@ export class AdminRoomHandler { }); for (const r of matrixRooms) { const userMustJoin = ( - key || server.shouldSyncMembershipToIrc("incremental", r.getId()) + key ?? server.shouldSyncMembershipToIrc("incremental", r.getId()) ); if (!userMustJoin) { continue; @@ -283,7 +283,7 @@ export class AdminRoomHandler { for (let i = 0; i < matrixRooms.length; i++) { const m = matrixRooms[i]; const userMustJoin = ( - key || server.shouldSyncMembershipToIrc("incremental", m.getId()) + key ?? server.shouldSyncMembershipToIrc("incremental", m.getId()) ); if (userMustJoin) { // force join then break out (we only ever join once no matter how many diff --git a/src/bridge/IrcBridge.ts b/src/bridge/IrcBridge.ts index 226054385..f78f07bfd 100644 --- a/src/bridge/IrcBridge.ts +++ b/src/bridge/IrcBridge.ts @@ -80,7 +80,7 @@ export class IrcBridge { }); } // Dependency graph - this.matrixHandler = new MatrixHandler(this, this.config.matrixHandler); + this.matrixHandler = new MatrixHandler(this, this.config.matrixHandler || {}); if (!this.config.database && this.config.ircService.databaseUri) { log.warn("ircService.databaseUri is a deprecated config option." + "Please use the database configuration block"); diff --git a/src/bridge/MatrixHandler.ts b/src/bridge/MatrixHandler.ts index 83a71fa9e..4a9d3bb04 100644 --- a/src/bridge/MatrixHandler.ts +++ b/src/bridge/MatrixHandler.ts @@ -89,9 +89,7 @@ export class MatrixHandler { // maintain a list of room IDs which are being processed invite-wise. This is // required because invites are processed asyncly, so you could get invite->msg // and the message is processed before the room is created. - config = config || {} - this.eventCacheMaxSize = config.eventCacheSize === undefined ? - DEFAULT_EVENT_CACHE_SIZE : config.eventCacheSize; + this.eventCacheMaxSize = config.eventCacheSize ?? DEFAULT_EVENT_CACHE_SIZE; // The media URL to use to transform mxc:// URLs when handling m.room.[file|image]s this.mediaUrl = ircBridge.config.homeserver.media_url || ircBridge.config.homeserver.url; this.adminHandler = new AdminRoomHandler(ircBridge, this); @@ -1097,7 +1095,7 @@ export class MatrixHandler { private async textForReplyEvent(event: MatrixMessageEvent, replyEventId: string, ircRoom: IrcRoom): Promise<{formatted: string; reply: string}|null> { - const REPLY_REGEX = /> <(.*)>(.*)\n\n(.*)/; + const REPLY_REGEX = /> <(.*?)>(.*?)\n\n(.*)/; const REPLY_NAME_MAX_LENGTH = 12; const eventId = replyEventId; if (!event.content.body) { diff --git a/src/datastore/postgres/PgDataStore.ts b/src/datastore/postgres/PgDataStore.ts index e14c53abf..b079c864a 100644 --- a/src/datastore/postgres/PgDataStore.ts +++ b/src/datastore/postgres/PgDataStore.ts @@ -306,7 +306,14 @@ export class PgDataStore implements DataStore { } public async setPmRoom(ircRoom: IrcRoom, matrixRoom: MatrixRoom, userId: string, virtualUserId: string): Promise { - await this.pgPool.query("INSERT INTO pm_rooms VALUES ($1, $2, $3, $4, $5)", [ + await this.pgPool.query( + PgDataStore.BuildUpsertStatement("pm_rooms", "ON CONSTRAINT cons_pm_rooms_matrix_irc_unique", [ + "room_id", + "irc_domain", + "irc_nick", + "matrix_user_id", + "virtual_user_id", + ]), [ matrixRoom.getId(), ircRoom.getDomain(), ircRoom.getChannel(), diff --git a/src/irc/ClientPool.ts b/src/irc/ClientPool.ts index 935c1b58d..2a98234f3 100644 --- a/src/irc/ClientPool.ts +++ b/src/irc/ClientPool.ts @@ -348,7 +348,7 @@ export class ClientPool { return undefined; } const cli = this.virtualClients[server.domain].nicks[nick]; - if (!cli || cli.isDead()) { + if (cli?.isDead()) { return undefined; } return cli; diff --git a/src/irc/ConnectionInstance.ts b/src/irc/ConnectionInstance.ts index ab9c2701d..dd50f90f5 100644 --- a/src/irc/ConnectionInstance.ts +++ b/src/irc/ConnectionInstance.ts @@ -149,7 +149,7 @@ export class ConnectionInstance { return new Bluebird((resolve) => { // close the connection - this.client.disconnect(ircReason, () => {}); + this.client.disconnect(ircReason, () => { /* This is needed for tests */ }); // remove timers if (this.pingRateTimerId) { clearTimeout(this.pingRateTimerId); diff --git a/src/main.ts b/src/main.ts index 5ad5b5fbc..c92084fac 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,8 +22,16 @@ const log = logging.get("main"); http.globalAgent.maxSockets = 1000; https.globalAgent.maxSockets = 1000; -process.on("unhandledRejection", (reason?: Error) => { - log.error((reason ? reason.stack : undefined) || "No reason given"); +// eslint-disable-next-line @typescript-eslint/no-explicit-any +process.on("unhandledRejection", (reason: any) => { + let reasonStr = "No reason given"; + if (reason && reason.stack) { + reasonStr = reason.stack + } + else if (typeof(reason) === "string") { + reasonStr = reason; + } + log.error(reasonStr); }); const _toServer = (domain: string, serverConfig: any, homeserverDomain: string) => { @@ -68,7 +76,7 @@ export function generateRegistration(reg: AppServiceRegistration, config: Bridge } export async function runBridge(port: number, config: BridgeConfig, reg: AppServiceRegistration, isDBInMemory = false) { - if (config.sentry && config.sentry.dsn) { + if (config.sentry && config.sentry.enabled && config.sentry.dsn) { log.info("Sentry ENABLED"); Sentry.init({ dsn: config.sentry.dsn, diff --git a/src/models/IrcAction.ts b/src/models/IrcAction.ts index bc79f2a05..e90bab449 100644 --- a/src/models/IrcAction.ts +++ b/src/models/IrcAction.ts @@ -43,7 +43,7 @@ export class IrcAction { } if (matrixAction.htmlText) { const text = ircFormatting.htmlToIrc(matrixAction.htmlText); - const ircText = text !== null ? text : matrixAction.text; // fallback if needed. + const ircText = text ?? matrixAction.text; // fallback if needed. if (ircText === null) { throw Error("ircText is null"); } diff --git a/src/scripts/migrate-db-to-pgres.ts b/src/scripts/migrate-db-to-pgres.ts index 159f5622d..0ed542658 100644 --- a/src/scripts/migrate-db-to-pgres.ts +++ b/src/scripts/migrate-db-to-pgres.ts @@ -245,8 +245,6 @@ async function main() { log.info("Finished migration at %sms", Date.now() - time); } -main().then(() => { - -}).catch((ex) => { +main().catch((ex) => { log.error("Failed to run migration script: %s", ex); }) diff --git a/tsconfig.json b/tsconfig.json index a909c0d54..315a60161 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "composite": false, "strict": true, "esModuleInterop": true, + "strictNullChecks": true, "typeRoots": [ "./types" ]