From f70d0aad8bece788b37297989fd7b1f527417692 Mon Sep 17 00:00:00 2001 From: 7PH Date: Mon, 29 Jul 2024 01:58:57 +0200 Subject: [PATCH 1/9] Add optional welcome message --- README.md | 4 +++ app/script/setup.sh | 5 ++++ app/server/plugins/core/CorePluginGroup.ts | 2 ++ .../plugins/core/global/WelcomePlugin.ts | 27 +++++++++++++++++++ app/server/skychat/Config.ts | 9 +++++++ app/template/welcome.txt.template | 1 + 6 files changed, 48 insertions(+) create mode 100644 app/server/plugins/core/global/WelcomePlugin.ts create mode 100644 app/template/welcome.txt.template diff --git a/README.md b/README.md index 80c3810a..d60e6a65 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,10 @@ The `config/preferences.json` file specifies application preferences. The availa `minRightForMessageHistory` defines who can quote old messages and navigate room old history. +### Customize the welcome message + +By default, guests are welcomes with a welcome message that you can change in `config/welcome.txt`. If you remove this file, there won't be a welcome message anymore. + ### Customize guest names `config/guestnames.txt` is the pool of non-logged usernames. diff --git a/app/script/setup.sh b/app/script/setup.sh index f22a9ff3..f0458df4 100644 --- a/app/script/setup.sh +++ b/app/script/setup.sh @@ -61,3 +61,8 @@ fi if [[ ! -e config/fakemessages.txt ]]; then cp app/template/fakemessages.txt.template config/fakemessages.txt; fi + +# Initialize welcome.txt.template +if [[ ! -e config/welcome.txt.template ]]; then + cp app/template/welcome.txt.template config/welcome.txt; +fi diff --git a/app/server/plugins/core/CorePluginGroup.ts b/app/server/plugins/core/CorePluginGroup.ts index 85e05abe..bc25c49e 100644 --- a/app/server/plugins/core/CorePluginGroup.ts +++ b/app/server/plugins/core/CorePluginGroup.ts @@ -20,6 +20,7 @@ import { ReactionPlugin } from './global/ReactionPlugin.js'; import { SetRightPlugin } from './global/SetRightPlugin.js'; import { StickerPlugin } from './global/StickerPlugin.js'; import { VoidPlugin } from './global/VoidPlugin.js'; +import { WelcomePlugin } from './global/WelcomePlugin.js'; import { XpTickerPlugin } from './global/XpTickerPlugin.js'; import { HelpPlugin } from './room/HelpPlugin.js'; import { MentionPlugin } from './room/MentionPlugin.js'; @@ -64,6 +65,7 @@ export class CorePluginGroup extends PluginGroup { SetRightPlugin, StickerPlugin, VoidPlugin, + WelcomePlugin, XpTickerPlugin, ]; } diff --git a/app/server/plugins/core/global/WelcomePlugin.ts b/app/server/plugins/core/global/WelcomePlugin.ts new file mode 100644 index 00000000..d2c552d2 --- /dev/null +++ b/app/server/plugins/core/global/WelcomePlugin.ts @@ -0,0 +1,27 @@ +import { Config } from '../../../skychat/Config.js'; +import { Connection } from '../../../skychat/Connection.js'; +import { UserController } from '../../../skychat/UserController.js'; +import { GlobalPlugin } from '../../GlobalPlugin.js'; + +export class WelcomePlugin extends GlobalPlugin { + static readonly commandName = 'welcome'; + + readonly callable = false; + + async run() { + throw new Error('Method not implemented.'); + } + + async onNewConnection(connection: Connection) { + const message = Config.WELCOME_MESSAGE; + if (!message) { + return; + } + + if (connection.session.user.id > 0) { + return; + } + + connection.send('message', UserController.createNeutralMessage({ content: message, room: connection.roomId, id: 0 }).sanitized()); + } +} diff --git a/app/server/skychat/Config.ts b/app/server/skychat/Config.ts index 1015bfc3..541fa0c9 100644 --- a/app/server/skychat/Config.ts +++ b/app/server/skychat/Config.ts @@ -45,6 +45,8 @@ export class Config { public static FAKE_MESSAGES: string[] = []; + public static WELCOME_MESSAGE: string | null = null; + public static getRandomGuestName(): string { const index = Math.floor(Math.random() * Config.GUEST_NAMES.length); return Config.GUEST_NAMES[index]; @@ -84,6 +86,13 @@ export class Config { Logging.warn('No fake messages found (fakemessages.txt file is empty). Using a single empty fake message.'); Config.GUEST_NAMES.push(''); } + // Load welcome message + try { + Config.WELCOME_MESSAGE = fs.readFileSync('config/welcome.txt').toString().trim(); + } catch (e) { + Logging.info('No welcome message found (welcome.txt file is missing). Will not display a welcome message.'); + Config.WELCOME_MESSAGE = null; + } // Load preferences.json Config.PREFERENCES = JSON.parse(fs.readFileSync('config/preferences.json').toString()); const keys: string[] = [ diff --git a/app/template/welcome.txt.template b/app/template/welcome.txt.template new file mode 100644 index 00000000..87993bc8 --- /dev/null +++ b/app/template/welcome.txt.template @@ -0,0 +1 @@ +Welcome on the SkyChat! From ef20b13abeb7f94556f59756a616f4e42215d0ac Mon Sep 17 00:00:00 2001 From: 7PH Date: Mon, 29 Jul 2024 23:11:11 +0200 Subject: [PATCH 2/9] Fix BanPlugin crashing the SkyChat --- app/server/plugins/core/global/BanPlugin.ts | 2 +- app/server/skychat/PluginManager.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/server/plugins/core/global/BanPlugin.ts b/app/server/plugins/core/global/BanPlugin.ts index b02b7570..e17b6e71 100644 --- a/app/server/plugins/core/global/BanPlugin.ts +++ b/app/server/plugins/core/global/BanPlugin.ts @@ -181,7 +181,7 @@ export class BanPlugin extends GlobalPlugin { // If access ban, just close connection if (this.isBanned(connection, BAN_TYPES.ACCESS)) { connection.close(Connection.CLOSE_KICKED, 'You have been disconnected'); - throw new Error(); + return '/void'; } // If shadow banned if (this.isBanned(connection, BAN_TYPES.SHADOW)) { diff --git a/app/server/skychat/PluginManager.ts b/app/server/skychat/PluginManager.ts index 5fde4dff..a043f205 100644 --- a/app/server/skychat/PluginManager.ts +++ b/app/server/skychat/PluginManager.ts @@ -63,7 +63,7 @@ export class PluginManager { private async onConnectionMessage(connection: Connection, payload: string): Promise { try { // Handle default command (/message) - if (payload[0] !== '/') { + if (!payload.startsWith('/')) { payload = '/message ' + payload; } From 1bd3d82fdd99c678baba453042be89aac6c00c7b Mon Sep 17 00:00:00 2001 From: 7PH Date: Tue, 30 Jul 2024 00:38:48 +0200 Subject: [PATCH 3/9] Add min right to mention users --- README.md | 1 + app/server/plugins/core/room/MentionPlugin.ts | 7 ++++++- app/server/skychat/Config.ts | 6 ++++-- app/template/preferences.json.template | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d60e6a65..e3e3a7ba 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ The `config/preferences.json` file specifies application preferences. The availa | minRightForPublicMessages | number | -1 | Min. right to send public messages | | minRightForPrivateMessages | number | -1 | Min. right to send private messages | | minRightForMessageQuoting | number | -1 | Min. right to quote messages | +| minRightForUserMention | number | -1 | Min. right to mention users | | minRightForShortTermMessageHistory | number | -1 | Min. right to access short term room message history | | minRightForMessageHistory | number | -1 | Min. right to access full room message history | | minRightForUserModeration | number | 'op' | Min. right to ban, kick and access user ips | diff --git a/app/server/plugins/core/room/MentionPlugin.ts b/app/server/plugins/core/room/MentionPlugin.ts index 06f1ec02..4332e713 100644 --- a/app/server/plugins/core/room/MentionPlugin.ts +++ b/app/server/plugins/core/room/MentionPlugin.ts @@ -1,3 +1,4 @@ +import { Config } from '../../../skychat/Config.js'; import { Connection } from '../../../skychat/Connection.js'; import { Message } from '../../../skychat/Message.js'; import { Session } from '../../../skychat/Session.js'; @@ -13,6 +14,10 @@ export class MentionPlugin extends RoomPlugin { // Intercept quotes in messages public async onBeforeMessageBroadcastHook(message: Message, connection: Connection) { + if (connection.session.user.right < Config.PREFERENCES.minRightForUserMention) { + return message; + } + const mentions = message.content.match(/@[a-zA-Z0-9-_]+/g); // Note quote detected @@ -42,7 +47,7 @@ export class MentionPlugin extends RoomPlugin { continue; } // Skip if in a room where the mentioned user is not allowed - if (!connection.room || !connection.room.accepts(session)) { + if (!connection.room?.accepts(session)) { continue; } session.send('mention', { diff --git a/app/server/skychat/Config.ts b/app/server/skychat/Config.ts index 541fa0c9..d436f21b 100644 --- a/app/server/skychat/Config.ts +++ b/app/server/skychat/Config.ts @@ -5,6 +5,7 @@ export type Preferences = { minRightForPublicMessages: number; minRightForPrivateMessages: number; minRightForMessageQuoting: number; + minRightForUserMention: number; minRightForShortTermMessageHistory: number; minRightForMessageHistory: number; minRightForUserModeration: number | 'op'; @@ -96,10 +97,11 @@ export class Config { // Load preferences.json Config.PREFERENCES = JSON.parse(fs.readFileSync('config/preferences.json').toString()); const keys: string[] = [ - 'minRightForPrivateMessages', - 'minRightForMessageQuoting', 'minRightForShortTermMessageHistory', 'minRightForMessageHistory', + 'minRightForPrivateMessages', + 'minRightForMessageQuoting', + 'minRightForUserMention', 'minRightForUserModeration', 'minRightForSetRight', 'minRightForAudioRecording', diff --git a/app/template/preferences.json.template b/app/template/preferences.json.template index 362f111c..42897974 100644 --- a/app/template/preferences.json.template +++ b/app/template/preferences.json.template @@ -4,6 +4,7 @@ "minRightForPublicMessages": -1, "minRightForPrivateMessages": -1, "minRightForMessageQuoting": -1, + "minRightForUserMention": -1, "minRightForUserModeration": "op", "minRightForSetRight": "op", "minRightForAudioRecording": -1, From f40fa2d44417edf560e84b445ef67d578f6c3068 Mon Sep 17 00:00:00 2001 From: 7PH Date: Wed, 7 Aug 2024 11:05:23 +0200 Subject: [PATCH 4/9] Add debug logs for event parse error --- app/server/skychat/Connection.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/server/skychat/Connection.ts b/app/server/skychat/Connection.ts index 95c14ba9..4dc4baba 100644 --- a/app/server/skychat/Connection.ts +++ b/app/server/skychat/Connection.ts @@ -149,7 +149,8 @@ export class Connection extends EventEmitter implements IBroadcaster { // Check that the event name is valid and is registered if (typeof eventName !== 'string') { - throw new Error('Event could not be parsed'); + Logging.error(`Event could not be parsed: "${eventName}" from event "${dataAsString}"`); + throw new Error(`Event could not be parsed: "${eventName}"`); } if (!Connection.ACCEPTED_EVENTS.includes(eventName)) { From ac81e51e333934036251f95dbe481b5f626dab9c Mon Sep 17 00:00:00 2001 From: 7PH Date: Sat, 10 Aug 2024 02:00:28 +0200 Subject: [PATCH 5/9] Adjust rate limit values --- app/server/skychat/AuthBridge.ts | 4 ++-- app/server/skychat/Connection.ts | 8 +------- app/server/skychat/HttpServer.ts | 4 ++-- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/app/server/skychat/AuthBridge.ts b/app/server/skychat/AuthBridge.ts index cede143c..62230f2a 100644 --- a/app/server/skychat/AuthBridge.ts +++ b/app/server/skychat/AuthBridge.ts @@ -36,9 +36,9 @@ export class AuthBridge extends EventEmitter { static readonly MAX_REGISTER_PER_HOUR = 1; - static readonly MAX_LOGIN_PER_MINUTE = 10; + static readonly MAX_LOGIN_PER_MINUTE = 20; - static readonly MAX_GUEST_PER_MINUTE = 8; + static readonly MAX_GUEST_PER_MINUTE = 20; static readonly MAX_TOKEN_AUTH_PER_MINUTE = 20; diff --git a/app/server/skychat/Connection.ts b/app/server/skychat/Connection.ts index 4dc4baba..7f5a9fc8 100644 --- a/app/server/skychat/Connection.ts +++ b/app/server/skychat/Connection.ts @@ -13,16 +13,10 @@ import { Session } from './Session.js'; * A client represents an open connection to the server */ export class Connection extends EventEmitter implements IBroadcaster { - static readonly PING_INTERVAL_MS = 10 * 1000; - // TODO: This limit is also used for the AudioRecorderPlugin, so we currently have to keep it high. The audio limit should be different. static readonly MAX_RECEIVED_BYTES_PER_10_SEC = 1024 * 400; - static readonly MAX_EVENTS_PER_SEC = 16; - - static readonly MAXIMUM_MISSED_PING = 1; - - static readonly CLOSE_PING_TIMEOUT = 4504; + static readonly MAX_EVENTS_PER_SEC = 30; static readonly CLOSE_KICKED = 4403; diff --git a/app/server/skychat/HttpServer.ts b/app/server/skychat/HttpServer.ts index bb01621c..1035f47c 100644 --- a/app/server/skychat/HttpServer.ts +++ b/app/server/skychat/HttpServer.ts @@ -25,7 +25,7 @@ export type ConnectionUpgradeEvent = { export class HttpServer extends EventEmitter { public static readonly UPLOADED_FILE_REGEXP: RegExp = new RegExp('^' + Config.LOCATION + '/uploads/all/([-\\/._a-zA-Z0-9]+)$'); - static readonly MAX_UPGRADES_PER_SECOND = 3; + static readonly MAX_UPGRADES_PER_SECOND = 4; static readonly MAX_UPGRADES_PER_MINUTE = 20; @@ -39,7 +39,7 @@ export class HttpServer extends EventEmitter { private readonly wsCreateSecLimiter: RateLimiterMemory = new RateLimiterMemory({ points: HttpServer.MAX_UPGRADES_PER_SECOND, - duration: 60, + duration: 1, }); private readonly wsCreateMinLimiter: RateLimiterMemory = new RateLimiterMemory({ From 5d0874a8a17c27639624c9379f30ae5a7a71d395 Mon Sep 17 00:00:00 2001 From: 7PH Date: Sat, 10 Aug 2024 02:10:21 +0200 Subject: [PATCH 6/9] Implement db-autoconnect script --- app/script/debug-db.sh | 7 +++++++ app/script/{log.sh => debug-log.sh} | 2 ++ 2 files changed, 9 insertions(+) create mode 100644 app/script/debug-db.sh rename app/script/{log.sh => debug-log.sh} (90%) diff --git a/app/script/debug-db.sh b/app/script/debug-db.sh new file mode 100644 index 00000000..19ccf366 --- /dev/null +++ b/app/script/debug-db.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +source .env + +DOCKER_CONTAINER_ID=$(docker ps | grep skychat_db | awk '{print $1}') + +docker exec -it "$DOCKER_CONTAINER_ID" /usr/local/bin/psql "--user=$POSTGRES_USER" "$POSTGRES_DB" diff --git a/app/script/log.sh b/app/script/debug-log.sh similarity index 90% rename from app/script/log.sh rename to app/script/debug-log.sh index 206b1b4a..5b3f3c0e 100644 --- a/app/script/log.sh +++ b/app/script/debug-log.sh @@ -1,2 +1,4 @@ +#!/bin/bash + # Log web server docker container logs -n 1000 -f $(docker container list | grep skychat_app | cut -d' ' -f1) | pino-pretty From 91f233985f1494ab5292b5106bb93bc14765c12e Mon Sep 17 00:00:00 2001 From: 7PH Date: Sat, 10 Aug 2024 02:34:23 +0200 Subject: [PATCH 7/9] Add logs for any sent command --- app/server/skychat/PluginManager.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/server/skychat/PluginManager.ts b/app/server/skychat/PluginManager.ts index a043f205..e7c0d766 100644 --- a/app/server/skychat/PluginManager.ts +++ b/app/server/skychat/PluginManager.ts @@ -2,6 +2,7 @@ import { GlobalPlugin } from '../plugins/GlobalPlugin.js'; import { globalPluginGroup } from '../plugins/GlobalPluginGroup.js'; import { ConnectionAcceptedEvent } from './AuthBridge.js'; import { Connection } from './Connection.js'; +import { Logging } from './Logging.js'; import { MessageFormatter } from './MessageFormatter.js'; import { RoomManager } from './RoomManager.js'; @@ -67,6 +68,8 @@ export class PluginManager { payload = '/message ' + payload; } + Logging.info(`Command received: ${connection.session.identifier} ${payload.split(' ')[0]} (length: ${payload.length})`); + payload = await this.executeNewMessageHook(payload, connection); // Parse command name and message content From 66343a375190b0466dbc01ce773fda36c13dccb9 Mon Sep 17 00:00:00 2001 From: 7PH Date: Sun, 11 Aug 2024 00:42:24 +0200 Subject: [PATCH 8/9] Fix mention plugin crashes --- app/server/plugins/core/room/MentionPlugin.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/server/plugins/core/room/MentionPlugin.ts b/app/server/plugins/core/room/MentionPlugin.ts index 4332e713..87f67a31 100644 --- a/app/server/plugins/core/room/MentionPlugin.ts +++ b/app/server/plugins/core/room/MentionPlugin.ts @@ -13,7 +13,12 @@ export class MentionPlugin extends RoomPlugin { async run(): Promise {} // Intercept quotes in messages - public async onBeforeMessageBroadcastHook(message: Message, connection: Connection) { + public async onBeforeMessageBroadcastHook(message: Message, connection?: Connection) { + // It is currently not possible to mention an user if there's not connection the mention originates from + if (!connection) { + return message; + } + if (connection.session.user.right < Config.PREFERENCES.minRightForUserMention) { return message; } From 5763282a120d4080d55bca3f1e953b469f785013 Mon Sep 17 00:00:00 2001 From: 7PH Date: Sun, 11 Aug 2024 19:57:22 +0200 Subject: [PATCH 9/9] Fix CI docker build --- .github/workflows/build-docker.yml | 42 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index b3a05efe..02dbd7d8 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -1,26 +1,26 @@ name: Docker build CI on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] + push: + branches: ['master'] + pull_request: + branches: ['master'] jobs: - build: - runs-on: ubuntu-latest - strategy: - matrix: - node-version: [14.x, 16.x, 18.x] - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm run setup - - run: echo $USER; id -u $USER; id -g $USER - - run: cp .github/workflows/.env.github .env - - run: docker-compose up -d + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [14.x, 16.x, 18.x] + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm ci + - run: npm run setup + - run: echo $USER; id -u $USER; id -g $USER + - run: cp .github/workflows/.env.github .env + - run: docker compose up -d