Merge branch 'fix-minor-things'

This commit is contained in:
Henrik Hüttemann 2023-06-26 14:36:02 +02:00
commit d251cf658f
No known key found for this signature in database
GPG Key ID: 9F7BD10E0A8A111E
11 changed files with 454 additions and 292 deletions

View File

@ -1,2 +1,2 @@
REGISTRATION_SHARED_SECRET='look in your synapses homeserver.yaml'
EXCLUDED_USERS='rocket.cat' # Comma-separated list
EXCLUDED_USERS='rocket.cat' # Comma-separated list of usernames or IDs

314
package-lock.json generated
View File

@ -10,20 +10,20 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^1.4.0",
"dotenv": "^16.1.4",
"dotenv": "^16.3.1",
"n-readlines": "^1.0.1",
"reflect-metadata": "^0.1.13",
"sqlite3": "^5.1.6",
"typeorm": "^0.3.16",
"typeorm": "^0.3.17",
"winston": "^3.9.0"
},
"devDependencies": {
"@jest/globals": "^29.5.0",
"@types/n-readlines": "^1.0.3",
"@types/node": "^20.3.1",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.59.11",
"eslint": "^8.42.0",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
@ -714,9 +714,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
"version": "8.43.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz",
"integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -1301,9 +1301,9 @@
}
},
"node_modules/@sinonjs/fake-timers": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz",
"integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==",
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
"integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
"dev": true,
"dependencies": {
"@sinonjs/commons": "^3.0.0"
@ -1466,15 +1466,15 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz",
"integrity": "sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.0.tgz",
"integrity": "sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.59.11",
"@typescript-eslint/type-utils": "5.59.11",
"@typescript-eslint/utils": "5.59.11",
"@typescript-eslint/scope-manager": "5.60.0",
"@typescript-eslint/type-utils": "5.60.0",
"@typescript-eslint/utils": "5.60.0",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@ -1500,14 +1500,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.11.tgz",
"integrity": "sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.60.0.tgz",
"integrity": "sha512-jBONcBsDJ9UoTWrARkRRCgDz6wUggmH5RpQVlt7BimSwaTkTjwypGzKORXbR4/2Hqjk9hgwlon2rVQAjWNpkyQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.59.11",
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/typescript-estree": "5.59.11",
"@typescript-eslint/scope-manager": "5.60.0",
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/typescript-estree": "5.60.0",
"debug": "^4.3.4"
},
"engines": {
@ -1527,13 +1527,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz",
"integrity": "sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.60.0.tgz",
"integrity": "sha512-hakuzcxPwXi2ihf9WQu1BbRj1e/Pd8ZZwVTG9kfbxAMZstKz8/9OoexIwnmLzShtsdap5U/CoQGRCWlSuPbYxQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/visitor-keys": "5.59.11"
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/visitor-keys": "5.60.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -1544,13 +1544,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz",
"integrity": "sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.60.0.tgz",
"integrity": "sha512-X7NsRQddORMYRFH7FWo6sA9Y/zbJ8s1x1RIAtnlj6YprbToTiQnM6vxcMu7iYhdunmoC0rUWlca13D5DVHkK2g==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.59.11",
"@typescript-eslint/utils": "5.59.11",
"@typescript-eslint/typescript-estree": "5.60.0",
"@typescript-eslint/utils": "5.60.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@ -1571,9 +1571,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.11.tgz",
"integrity": "sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.60.0.tgz",
"integrity": "sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -1584,13 +1584,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz",
"integrity": "sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.0.tgz",
"integrity": "sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/visitor-keys": "5.59.11",
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/visitor-keys": "5.60.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -1611,17 +1611,17 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.11.tgz",
"integrity": "sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.60.0.tgz",
"integrity": "sha512-ba51uMqDtfLQ5+xHtwlO84vkdjrqNzOnqrnwbMHMRY8Tqeme8C2Q8Fc7LajfGR+e3/4LoYiWXUM6BpIIbHJ4hQ==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.59.11",
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/typescript-estree": "5.59.11",
"@typescript-eslint/scope-manager": "5.60.0",
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/typescript-estree": "5.60.0",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
},
@ -1637,12 +1637,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz",
"integrity": "sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.0.tgz",
"integrity": "sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/types": "5.60.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -1659,9 +1659,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"node_modules/acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
@ -2089,9 +2089,9 @@
}
},
"node_modules/browserslist": {
"version": "4.21.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz",
"integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==",
"version": "4.21.9",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
"dev": true,
"funding": [
{
@ -2108,8 +2108,8 @@
}
],
"dependencies": {
"caniuse-lite": "^1.0.30001502",
"electron-to-chromium": "^1.4.428",
"caniuse-lite": "^1.0.30001503",
"electron-to-chromium": "^1.4.431",
"node-releases": "^2.0.12",
"update-browserslist-db": "^1.0.11"
},
@ -2259,9 +2259,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001503",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
"version": "1.0.30001508",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001508.tgz",
"integrity": "sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==",
"dev": true,
"funding": [
{
@ -2772,9 +2772,9 @@
}
},
"node_modules/dotenv": {
"version": "16.1.4",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz",
"integrity": "sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw==",
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
"engines": {
"node": ">=12"
},
@ -2789,9 +2789,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.4.430",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.430.tgz",
"integrity": "sha512-FytjTbGwz///F+ToZ5XSeXbbSaXalsVRXsz2mHityI5gfxft7ieW3HqFLkU5V1aIrY42aflICqbmFoDxW10etg==",
"version": "1.4.440",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.440.tgz",
"integrity": "sha512-r6dCgNpRhPwiWlxbHzZQ/d9swfPaEJGi8ekqRBwQYaR3WmA5VkqQfBWSDDjuJU1ntO+W9tHx8OHV/96Q8e0dVw==",
"dev": true
},
"node_modules/emittery": {
@ -2961,15 +2961,15 @@
}
},
"node_modules/eslint": {
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
"version": "8.43.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz",
"integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.42.0",
"@eslint/js": "8.43.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -6462,9 +6462,9 @@
}
},
"node_modules/pirates": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
"dev": true,
"engines": {
"node": ">= 6"
@ -6942,9 +6942,9 @@
"optional": true
},
"node_modules/semver": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
"integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@ -7665,9 +7665,9 @@
}
},
"node_modules/typeorm": {
"version": "0.3.16",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.16.tgz",
"integrity": "sha512-wJ4Qy1oqRKNDdZiBTTaVMqwo/XxC52Q7uNPTjltPgLhvIW173bL6Iad0lhptMOsFlpixFPaUu3PNziaRBwX2Zw==",
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.17.tgz",
"integrity": "sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==",
"dependencies": {
"@sqltools/formatter": "^1.2.5",
"app-root-path": "^3.1.0",
@ -8749,9 +8749,9 @@
}
},
"@eslint/js": {
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
"version": "8.43.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz",
"integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==",
"dev": true
},
"@gar/promisify": {
@ -9217,9 +9217,9 @@
}
},
"@sinonjs/fake-timers": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz",
"integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==",
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
"integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^3.0.0"
@ -9379,15 +9379,15 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.11.tgz",
"integrity": "sha512-XxuOfTkCUiOSyBWIvHlUraLw/JT/6Io1365RO6ZuI88STKMavJZPNMU0lFcUTeQXEhHiv64CbxYxBNoDVSmghg==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.0.tgz",
"integrity": "sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg==",
"dev": true,
"requires": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.59.11",
"@typescript-eslint/type-utils": "5.59.11",
"@typescript-eslint/utils": "5.59.11",
"@typescript-eslint/scope-manager": "5.60.0",
"@typescript-eslint/type-utils": "5.60.0",
"@typescript-eslint/utils": "5.60.0",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@ -9397,53 +9397,53 @@
}
},
"@typescript-eslint/parser": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.11.tgz",
"integrity": "sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.60.0.tgz",
"integrity": "sha512-jBONcBsDJ9UoTWrARkRRCgDz6wUggmH5RpQVlt7BimSwaTkTjwypGzKORXbR4/2Hqjk9hgwlon2rVQAjWNpkyQ==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.59.11",
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/typescript-estree": "5.59.11",
"@typescript-eslint/scope-manager": "5.60.0",
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/typescript-estree": "5.60.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz",
"integrity": "sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.60.0.tgz",
"integrity": "sha512-hakuzcxPwXi2ihf9WQu1BbRj1e/Pd8ZZwVTG9kfbxAMZstKz8/9OoexIwnmLzShtsdap5U/CoQGRCWlSuPbYxQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/visitor-keys": "5.59.11"
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/visitor-keys": "5.60.0"
}
},
"@typescript-eslint/type-utils": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.11.tgz",
"integrity": "sha512-LZqVY8hMiVRF2a7/swmkStMYSoXMFlzL6sXV6U/2gL5cwnLWQgLEG8tjWPpaE4rMIdZ6VKWwcffPlo1jPfk43g==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.60.0.tgz",
"integrity": "sha512-X7NsRQddORMYRFH7FWo6sA9Y/zbJ8s1x1RIAtnlj6YprbToTiQnM6vxcMu7iYhdunmoC0rUWlca13D5DVHkK2g==",
"dev": true,
"requires": {
"@typescript-eslint/typescript-estree": "5.59.11",
"@typescript-eslint/utils": "5.59.11",
"@typescript-eslint/typescript-estree": "5.60.0",
"@typescript-eslint/utils": "5.60.0",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.11.tgz",
"integrity": "sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.60.0.tgz",
"integrity": "sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz",
"integrity": "sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.0.tgz",
"integrity": "sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/visitor-keys": "5.59.11",
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/visitor-keys": "5.60.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -9452,28 +9452,28 @@
}
},
"@typescript-eslint/utils": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.11.tgz",
"integrity": "sha512-didu2rHSOMUdJThLk4aZ1Or8IcO3HzCw/ZvEjTTIfjIrcdd5cvSIwwDy2AOlE7htSNp7QIZ10fLMyRCveesMLg==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.60.0.tgz",
"integrity": "sha512-ba51uMqDtfLQ5+xHtwlO84vkdjrqNzOnqrnwbMHMRY8Tqeme8C2Q8Fc7LajfGR+e3/4LoYiWXUM6BpIIbHJ4hQ==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.59.11",
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/typescript-estree": "5.59.11",
"@typescript-eslint/scope-manager": "5.60.0",
"@typescript-eslint/types": "5.60.0",
"@typescript-eslint/typescript-estree": "5.60.0",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.59.11",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz",
"integrity": "sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==",
"version": "5.60.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.0.tgz",
"integrity": "sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.59.11",
"@typescript-eslint/types": "5.60.0",
"eslint-visitor-keys": "^3.3.0"
}
},
@ -9483,9 +9483,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.9.0.tgz",
"integrity": "sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==",
"dev": true
},
"acorn-jsx": {
@ -9793,13 +9793,13 @@
}
},
"browserslist": {
"version": "4.21.8",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz",
"integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==",
"version": "4.21.9",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
"integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001502",
"electron-to-chromium": "^1.4.428",
"caniuse-lite": "^1.0.30001503",
"electron-to-chromium": "^1.4.431",
"node-releases": "^2.0.12",
"update-browserslist-db": "^1.0.11"
}
@ -9913,9 +9913,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001503",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz",
"integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==",
"version": "1.0.30001508",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001508.tgz",
"integrity": "sha512-sdQZOJdmt3GJs1UMNpCCCyeuS2IEGLXnHyAo9yIO5JJDjbjoVRij4M1qep6P6gFpptD1PqIYgzM+gwJbOi92mw==",
"dev": true
},
"chalk": {
@ -10293,9 +10293,9 @@
}
},
"dotenv": {
"version": "16.1.4",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.1.4.tgz",
"integrity": "sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw=="
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ=="
},
"eastasianwidth": {
"version": "0.2.0",
@ -10304,9 +10304,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.4.430",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.430.tgz",
"integrity": "sha512-FytjTbGwz///F+ToZ5XSeXbbSaXalsVRXsz2mHityI5gfxft7ieW3HqFLkU5V1aIrY42aflICqbmFoDxW10etg==",
"version": "1.4.440",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.440.tgz",
"integrity": "sha512-r6dCgNpRhPwiWlxbHzZQ/d9swfPaEJGi8ekqRBwQYaR3WmA5VkqQfBWSDDjuJU1ntO+W9tHx8OHV/96Q8e0dVw==",
"dev": true
},
"emittery": {
@ -10443,15 +10443,15 @@
"dev": true
},
"eslint": {
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
"version": "8.43.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz",
"integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.42.0",
"@eslint/js": "8.43.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -13009,9 +13009,9 @@
"dev": true
},
"pirates": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
"integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
"dev": true
},
"pkg-dir": {
@ -13331,9 +13331,9 @@
"optional": true
},
"semver": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz",
"integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==",
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"requires": {
"lru-cache": "^6.0.0"
},
@ -13865,9 +13865,9 @@
}
},
"typeorm": {
"version": "0.3.16",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.16.tgz",
"integrity": "sha512-wJ4Qy1oqRKNDdZiBTTaVMqwo/XxC52Q7uNPTjltPgLhvIW173bL6Iad0lhptMOsFlpixFPaUu3PNziaRBwX2Zw==",
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.17.tgz",
"integrity": "sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==",
"requires": {
"@sqltools/formatter": "^1.2.5",
"app-root-path": "^3.1.0",

View File

@ -31,9 +31,9 @@
"@jest/globals": "^29.5.0",
"@types/n-readlines": "^1.0.3",
"@types/node": "^20.3.1",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.59.11",
"eslint": "^8.42.0",
"@typescript-eslint/eslint-plugin": "^5.60.0",
"@typescript-eslint/parser": "^5.60.0",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-config-standard-with-typescript": "^34.0.1",
"eslint-plugin-import": "^2.27.5",
@ -48,11 +48,11 @@
},
"dependencies": {
"axios": "^1.4.0",
"dotenv": "^16.1.4",
"dotenv": "^16.3.1",
"n-readlines": "^1.0.1",
"reflect-metadata": "^0.1.13",
"sqlite3": "^5.1.6",
"typeorm": "^0.3.16",
"typeorm": "^0.3.17",
"winston": "^3.9.0"
}
}

27
src/Entities.ts Normal file
View File

@ -0,0 +1,27 @@
export const enum Entity {
Users = 'users',
Rooms = 'rooms',
Messages = 'messages',
}
type EntityConfig = {
filename: string
mappingType: number
}
export const entities: {
[key in Entity]: EntityConfig
} = {
users: {
filename: 'users.json',
mappingType: 0,
},
rooms: {
filename: 'rocketchat_room.json',
mappingType: 1,
},
messages: {
filename: 'rocketchat_message.json',
mappingType: 2,
},
} as const

View File

@ -2,114 +2,31 @@ import dotenv from 'dotenv'
dotenv.config()
import lineByLine from 'n-readlines'
import 'reflect-metadata'
import { IdMapping } from './entity/IdMapping'
import { RcUser, createUser } from './handlers/users'
import { handle as handleRoom } from './handlers/rooms'
import { handle as handleUser } from './handlers/users'
import log from './helpers/logger'
import {
createMembership,
getMapping,
initStorage,
save,
} from './helpers/storage'
import { initStorage } from './helpers/storage'
import { whoami } from './helpers/synapse'
import { RcRoom, createRoom } from './handlers/rooms'
import { Entity, entities } from './Entities'
log.info('rocketchat2matrix starts.')
const enum Entities {
Users = 'users',
Rooms = 'rooms',
Messages = 'messages',
}
type EntityConfig = {
filename: string
mappingType: number
}
const entities: { [key in Entities]: EntityConfig } = {
users: {
filename: 'users.json',
mappingType: 0,
},
rooms: {
filename: 'rocketchat_room.json',
mappingType: 1,
},
messages: {
filename: 'rocketchat_message.json',
mappingType: 2,
},
}
async function loadRcExport(entity: Entities) {
async function loadRcExport(entity: Entity) {
const rl = new lineByLine(`./inputs/${entities[entity].filename}`)
let line: false | Buffer
while ((line = rl.next())) {
const item = JSON.parse(line.toString())
switch (entity) {
case Entities.Users:
const rcUser: RcUser = item
log.info(`Parsing user: ${rcUser.name}: ${rcUser._id}`)
// Check for exclusion
if (
rcUser.roles.some((e) => ['app', 'bot'].includes(e)) ||
(process.env.EXCLUDED_USERS || '').split(',').includes(rcUser._id)
) {
log.debug('User excluded. Skipping.')
break
}
let mapping = await getMapping(rcUser._id, entities[entity].mappingType)
if (mapping && mapping.matrixId) {
log.debug('Mapping exists:', mapping)
} else {
const matrixUser = await createUser(rcUser)
mapping = new IdMapping()
mapping.rcId = rcUser._id
mapping.matrixId = matrixUser.user_id
mapping.type = entities[entity].mappingType
mapping.accessToken = matrixUser.access_token
await save(mapping)
log.debug('Mapping added:', mapping)
// Add user to room mapping (specific to users)
await Promise.all(
rcUser.__rooms.map(async (rcRoomId: string) => {
await createMembership(rcRoomId, rcUser._id)
log.debug(`${rcUser.username} membership for ${rcRoomId} created`)
})
)
}
case Entity.Users:
await handleUser(item)
break
case Entities.Rooms:
const rcRoom: RcRoom = item
log.info(`Parsing room ${rcRoom.name || 'with ID: ' + rcRoom._id}`)
let roomMapping = await getMapping(
rcRoom._id,
entities[entity].mappingType
)
if (roomMapping && roomMapping.matrixId) {
log.debug('Mapping exists:', roomMapping)
} else {
const matrixRoom = await createRoom(rcRoom)
roomMapping = new IdMapping()
roomMapping.rcId = rcRoom._id
roomMapping.matrixId = matrixRoom.room_id
roomMapping.type = entities[entity].mappingType
await save(roomMapping)
log.debug('Mapping added:', roomMapping)
}
case Entity.Rooms:
await handleRoom(item)
break
case Entities.Messages:
case Entity.Messages:
log.debug(`Message: ${item.name}`)
break
@ -124,9 +41,9 @@ async function main() {
await whoami()
await initStorage()
log.info('Parsing users')
await loadRcExport(Entities.Users)
await loadRcExport(Entity.Users)
log.info('Parsing rooms')
await loadRcExport(Entities.Rooms)
await loadRcExport(Entity.Rooms)
log.info('Done.')
} catch (error) {
log.error(`Encountered an error while booting up: ${error}`, error)

View File

@ -6,15 +6,18 @@ import { SessionOptions } from '../helpers/synapse'
import {
MatrixRoomPresets,
MatrixRoomVisibility,
RcRoom,
RcRoomTypes,
acceptInvitation,
createMapping,
getCreator,
getFilteredMembers,
inviteMember,
mapRoom,
parseMemberships,
createDirectChatMemberships,
registerRoom,
} from './rooms'
import { Entity, entities } from '../Entities'
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
@ -110,10 +113,13 @@ test('getting creator', () => {
expect(getCreator(rcDirectChat)).toBe('aliceid')
expect(getCreator(rcPublicRoom)).toBe(roomCreator._id)
expect(getCreator(rcPrivateRoom)).toBe(roomCreator._id)
expect(getCreator({} as RcRoom)).toBe('')
})
test('creating memberships for direct chats', async () => {
await expect(parseMemberships(rcDirectChat)).resolves.toBe(undefined)
await expect(createDirectChatMemberships(rcDirectChat)).resolves.toBe(
undefined
)
expect(mockedStorage.createMembership).toHaveBeenCalledWith(
rcDirectChat._id,
rcDirectChat.uids[0]
@ -127,7 +133,11 @@ test('creating memberships for direct chats', async () => {
mockedStorage.createMembership.mockClear()
await expect(
parseMemberships({ ...rcDirectChat, _id: 'hoihoi', uids: ['hoi', 'hoi'] })
createDirectChatMemberships({
...rcDirectChat,
_id: 'hoihoi',
uids: ['hoi', 'hoi'],
})
).resolves.toBe(undefined)
expect(mockedStorage.createMembership).toHaveBeenCalledWith('hoihoi', 'hoi')
@ -168,7 +178,7 @@ test('accepting invitation by joining the room', async () => {
rcId: 'whatever',
matrixId: 'Neo',
accessToken: 'secretAuthToken',
type: 0,
type: entities[Entity.Users].mappingType,
},
room_id
)
@ -193,7 +203,7 @@ test('filtering members', async () => {
return {
rcId,
matrixId: `@${rcId}:matrix`,
type: type || 0,
type: type || entities[Entity.Users].mappingType,
accessToken: 'accessToken',
}
}
@ -206,7 +216,28 @@ test('filtering members', async () => {
mockMapping('existingUser'),
mockMapping('otherExistingUser'),
])
expect(mockedStorage.getMapping).toBeCalledWith('existingUser', 0)
expect(mockedStorage.getMapping).toBeCalledWith('otherExistingUser', 0)
expect(mockedStorage.getMapping).toBeCalledWith('excludedUser', 0)
expect(mockedStorage.getMapping).toBeCalledWith(
'existingUser',
entities[Entity.Users].mappingType
)
expect(mockedStorage.getMapping).toBeCalledWith(
'otherExistingUser',
entities[Entity.Users].mappingType
)
expect(mockedStorage.getMapping).toBeCalledWith(
'excludedUser',
entities[Entity.Users].mappingType
)
})
test('creating mapping', async () => {
await expect(
createMapping(rcPublicRoom._id, { ...mapRoom(rcPublicRoom), room_id })
).resolves.toBe(undefined)
expect(mockedStorage.save).toHaveBeenCalledWith({
rcId: rcPublicRoom._id,
matrixId: room_id,
type: entities[Entity.Rooms].mappingType,
accessToken: undefined,
} as IdMapping)
})

View File

@ -1,9 +1,12 @@
import { Entity, entities } from '../Entities'
import { IdMapping } from '../entity/IdMapping'
import log from '../helpers/logger'
import {
createMembership,
getMapping,
getMemberships,
getRoomId,
save,
} from '../helpers/storage'
import {
SessionOptions,
@ -101,7 +104,9 @@ export function getCreator(rcRoom: RcRoom): string {
}
}
export async function parseMemberships(rcRoom: RcRoom): Promise<void> {
export async function createDirectChatMemberships(
rcRoom: RcRoom
): Promise<void> {
if (rcRoom.t == RcRoomTypes.direct && rcRoom.uids) {
await Promise.all(
[...new Set(rcRoom.uids)] // Deduplicate users
@ -182,19 +187,45 @@ export async function getFilteredMembers(
return memberMappings
}
export async function createMapping(
rcId: string,
matrixRoom: MatrixRoom
): Promise<void> {
const roomMapping = new IdMapping()
roomMapping.rcId = rcId
roomMapping.matrixId = matrixRoom.room_id
roomMapping.type = entities[Entity.Rooms].mappingType
await save(roomMapping)
log.debug('Mapping added:', roomMapping)
}
export async function createRoom(rcRoom: RcRoom): Promise<MatrixRoom> {
const room: MatrixRoom = mapRoom(rcRoom)
const creatorId = getCreator(rcRoom)
await parseMemberships(rcRoom)
await createDirectChatMemberships(rcRoom)
const creatorSessionOptions = await getCreatorSessionOptions(creatorId)
log.debug('Creating room:', room)
room.room_id = await registerRoom(room, creatorSessionOptions)
const rcMemberIds = await getMemberships(rcRoom._id)
await handleMemberships(rcRoom._id, room, creatorId, creatorSessionOptions)
return room
}
async function handleMemberships(
rcRoomId: string,
room: MatrixRoom,
creatorId: string,
creatorSessionOptions: object | SessionOptions
) {
const rcMemberIds = await getMemberships(rcRoomId)
const memberMappings = await getFilteredMembers(rcMemberIds, creatorId)
log.info(
`Inviting members to room ${rcRoom._id}:`,
`Inviting members to room ${
room.room_alias_name || room.name || room.room_id
}:`,
memberMappings.map((mapping) => mapping.matrixId)
)
log.debug(
@ -214,6 +245,16 @@ export async function createRoom(rcRoom: RcRoom): Promise<MatrixRoom> {
await acceptInvitation(memberMapping, room.room_id || '')
})
)
return room
}
export async function handle(rcRoom: RcRoom): Promise<void> {
log.info(`Parsing room ${rcRoom.name || 'with ID: ' + rcRoom._id}`)
const matrixRoomId = await getRoomId(rcRoom._id)
if (matrixRoomId) {
log.debug(`Mapping exists: ${rcRoom._id} -> ${matrixRoomId}`)
} else {
const matrixRoom = await createRoom(rcRoom)
await createMapping(rcRoom._id, matrixRoom)
}
}

View File

@ -1,23 +1,32 @@
process.env.REGISTRATION_SHARED_SECRET = 'ThisIsSoSecretWow'
process.env.EXCLUDED_USERS = 'excludedUser1,excludedUser2'
import { expect, jest, test } from '@jest/globals'
import axios from 'axios'
import * as storage from '../helpers/storage'
import {
MatrixUser,
RcUser,
createMapping,
createUser,
generateHmac,
mapUser,
userIsExcluded,
} from '../handlers/users'
import { IdMapping } from '../entity/IdMapping'
import { Entity, entities } from '../Entities'
jest.mock('axios')
const mockedAxios = axios as jest.Mocked<typeof axios>
jest.mock('../helpers/storage')
const mockedStorage = storage as jest.Mocked<typeof storage>
const rcUser: RcUser = {
_id: 'testRc',
name: 'Tester McDelme',
username: 'testuser',
roles: ['user'],
__rooms: [],
__rooms: ['room0', 'room1'],
}
const matrixUser: MatrixUser = {
@ -29,15 +38,14 @@ const matrixUser: MatrixUser = {
}
const nonce = 'test-nonce'
const mac = 'be0537407ab3c82de908c5763185556e98a7211c'
test('mapping users', () => {
expect(mapUser(rcUser)).toStrictEqual(matrixUser)
})
test('generating correct hmac', () => {
expect(generateHmac({ ...matrixUser, nonce })).toStrictEqual(
'be0537407ab3c82de908c5763185556e98a7211c'
)
expect(generateHmac({ ...matrixUser, nonce })).toStrictEqual(mac)
})
test('creating users', async () => {
@ -57,12 +65,47 @@ test('creating users', async () => {
})
expect(mockedAxios.get).toHaveBeenCalledWith('/_synapse/admin/v1/register')
expect(mockedAxios.post).toHaveBeenCalled()
// The following test fails with an incorrect return value, for whatever reason.
// Probably because of mutated call logs in jest due to the `delete` or sth.
// expect(mockedAxios.post).toHaveBeenCalledWith('/_synapse/admin/v1/register', {
// ...matrixUser,
// nonce,
// mac: 'be0537407ab3c82de908c5763185556e98a7211c',
// })
expect(mockedAxios.post).toHaveBeenCalledWith('/_synapse/admin/v1/register', {
...matrixUser,
nonce,
mac,
})
expect(mockedStorage.createMembership).toHaveBeenCalledWith(
rcUser.__rooms[0],
rcUser._id
)
expect(mockedStorage.createMembership).toHaveBeenCalledWith(
rcUser.__rooms[1],
rcUser._id
)
expect(mockedStorage.createMembership).toHaveBeenCalledTimes(2)
})
test('users are excluded', () => {
expect(userIsExcluded(rcUser)).toBeFalsy()
expect(userIsExcluded({ ...rcUser, _id: 'excludedUser1' })).toBeTruthy()
expect(userIsExcluded({ ...rcUser, username: 'excludedUser2' })).toBeTruthy()
expect(userIsExcluded({ ...rcUser, roles: ['bot'] })).toBeTruthy()
expect(
userIsExcluded({ ...rcUser, roles: [...rcUser.__rooms, 'app'] })
).toBeTruthy()
expect(
userIsExcluded({
...rcUser,
_id: 'excludedUser2',
username: 'excludedUser1',
roles: [...rcUser.__rooms, 'app', 'bot'],
})
).toBeTruthy()
})
test('creating mapping', async () => {
await expect(createMapping(rcUser._id, matrixUser)).resolves.toBe(undefined)
expect(mockedStorage.save).toHaveBeenCalledWith({
rcId: rcUser._id,
matrixId: matrixUser.user_id,
type: entities[Entity.Users].mappingType,
accessToken: matrixUser.access_token,
} as IdMapping)
})

View File

@ -1,6 +1,9 @@
import { createHmac } from 'node:crypto'
import log from '../helpers/logger'
import { axios } from '../helpers/synapse'
import { createMembership, getUserId, save } from '../helpers/storage'
import { IdMapping } from '../entity/IdMapping'
import { Entity, entities } from '../Entities'
export type RcUser = {
_id: string
@ -64,17 +67,72 @@ async function registerUser(user: MatrixUser): Promise<AccessToken> {
return (await axios.post('/_synapse/admin/v1/register', user)).data
}
async function parseUserMemberships(rcUser: RcUser): Promise<void> {
await Promise.all(
rcUser.__rooms.map(async (rcRoomId: string) => {
await createMembership(rcRoomId, rcUser._id)
log.debug(`${rcUser.username} membership for ${rcRoomId} created`)
})
)
}
export function userIsExcluded(rcUser: RcUser): boolean {
const reasons: string[] = []
const excludedUsers = (process.env.EXCLUDED_USERS || '').split(',')
if (rcUser.roles.includes('app')) reasons.push('has role "app"')
if (rcUser.roles.includes('bot')) reasons.push('has role "bot"')
if (excludedUsers.includes(rcUser._id))
reasons.push(`id "${rcUser._id}" is on exclusion list`)
if (excludedUsers.includes(rcUser.username))
reasons.push(`username "${rcUser.username}" is on exclusion list`)
if (reasons.length > 0) {
log.debug(`User ${rcUser.name} is excluded: ${reasons.join(', ')}`)
return true
}
return false
}
export async function createMapping(
rcId: string,
matrixUser: MatrixUser
): Promise<void> {
const mapping = new IdMapping()
mapping.rcId = rcId
mapping.matrixId = matrixUser.user_id
mapping.type = entities[Entity.Users].mappingType
mapping.accessToken = matrixUser.access_token
await save(mapping)
log.debug('Mapping added:', mapping)
}
export async function createUser(rcUser: RcUser): Promise<MatrixUser> {
const user = mapUser(rcUser)
user.nonce = await getUserRegistrationNonce()
user.mac = generateHmac(user)
const accessToken = await registerUser(user)
const nonce = await getUserRegistrationNonce()
const mac = generateHmac({ ...user, nonce })
const accessToken = await registerUser({ ...user, nonce, mac })
user.user_id = accessToken.user_id
user.access_token = accessToken.access_token
log.info(`User ${rcUser.username} created:`, user)
delete user.nonce
delete user.mac
await parseUserMemberships(rcUser)
return user
}
export async function handle(rcUser: RcUser): Promise<void> {
log.info(`Parsing user: ${rcUser.name}: ${rcUser._id}`)
if (userIsExcluded(rcUser)) {
return undefined
}
const matrixId = await getUserId(rcUser._id)
if (matrixId) {
log.debug(`Mapping exists: ${rcUser._id} -> ${matrixId}`)
} else {
const matrixUser = await createUser(rcUser)
await createMapping(rcUser._id, matrixUser)
}
}

View File

@ -5,16 +5,20 @@ import {
getAccessToken,
getMapping,
getMemberships,
getMessageId,
getRoomId,
getUserId,
initStorage,
save,
} from './storage'
import { IdMapping } from '../entity/IdMapping'
import { Membership } from '../entity/Membership'
import { Entity, entities } from '../Entities'
const mapping = new IdMapping()
mapping.rcId = 'rcId'
mapping.matrixId = 'matrixId'
mapping.type = 0
mapping.type = entities[Entity.Users].mappingType
mapping.accessToken = 'accessToken'
const membership = new Membership()
@ -25,7 +29,7 @@ beforeAll(async () => {
await initStorage()
})
test('save mapping', async () => {
test('create mapping', async () => {
await expect(save(mapping)).resolves.toBe(undefined)
})
@ -60,3 +64,30 @@ test('get membership', async () => {
await expect(getMemberships('inexistent')).resolves.toStrictEqual([])
})
test('get member by id', async () => {
await expect(getUserId(mapping.rcId)).resolves.toBe(mapping.matrixId)
await expect(getUserId('inexistent')).resolves.toBeFalsy()
})
test('get room by id', async () => {
const room = new IdMapping()
room.rcId = 'rcRoom'
room.matrixId = 'matrixRoom'
room.type = entities[Entity.Rooms].mappingType
await save(room)
await expect(getRoomId(room.rcId)).resolves.toBe(room.matrixId)
await expect(getRoomId('inexistent')).resolves.toBeFalsy()
})
test('get message by id', async () => {
const message = new IdMapping()
message.rcId = 'rcMessage'
message.matrixId = 'matrixMessage'
message.type = entities[Entity.Messages].mappingType
await save(message)
await expect(getMessageId(message.rcId)).resolves.toBe(message.matrixId)
await expect(getMessageId('inexistent')).resolves.toBeFalsy()
})

View File

@ -1,6 +1,7 @@
import { DataSource } from 'typeorm'
import { IdMapping } from '../entity/IdMapping'
import { Membership } from '../entity/Membership'
import { Entity, entities } from '../Entities'
const AppDataSource = new DataSource({
type: 'sqlite',
@ -29,7 +30,7 @@ export async function save(entity: IdMapping | Membership): Promise<void> {
}
export async function getAccessToken(id: string): Promise<string | undefined> {
return (await getMapping(id, 0))?.accessToken
return (await getMapping(id, entities[Entity.Users].mappingType))?.accessToken
}
export async function createMembership(
@ -55,3 +56,16 @@ export async function getMemberships(rcRoomId: string): Promise<string[]> {
})
).map((entity) => entity.rcUserId)
}
export async function getUserId(rcId: string): Promise<string | undefined> {
return (await getMapping(rcId, entities[Entity.Users].mappingType))?.matrixId
}
export async function getRoomId(rcId: string): Promise<string | undefined> {
return (await getMapping(rcId, entities[Entity.Rooms].mappingType))?.matrixId
}
export async function getMessageId(rcId: string): Promise<string | undefined> {
return (await getMapping(rcId, entities[Entity.Messages].mappingType))
?.matrixId
}