From c66f9c885e0d09dbb64603d9a2ea11082695decd Mon Sep 17 00:00:00 2001 From: Nachtalb Date: Fri, 30 Apr 2021 23:53:57 +0200 Subject: [PATCH 01/58] Only scroll history when cursor is on first or last row Needs to be on first to go up and on last to go down --- client/components/ChatInput.vue | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/client/components/ChatInput.vue b/client/components/ChatInput.vue index d12b9405..35c68b7d 100644 --- a/client/components/ChatInput.vue +++ b/client/components/ChatInput.vue @@ -140,18 +140,28 @@ export default { return; } + const onRow = ( + this.$refs.input.value.slice(null, this.$refs.input.selectionStart).match(/\n/g) || + [] + ).length; + const totalRows = (this.$refs.input.value.match(/\n/g) || []).length; + const {channel} = this; if (channel.inputHistoryPosition === 0) { channel.inputHistory[channel.inputHistoryPosition] = channel.pendingMessage; } - if (key === "up") { + if (key === "up" && onRow === 0) { if (channel.inputHistoryPosition < channel.inputHistory.length - 1) { channel.inputHistoryPosition++; + } else { + return; } - } else if (channel.inputHistoryPosition > 0) { + } else if (key === "down" && channel.inputHistoryPosition > 0 && onRow === totalRows) { channel.inputHistoryPosition--; + } else { + return; } channel.pendingMessage = channel.inputHistory[channel.inputHistoryPosition]; From c5f6b4617fa03699b5e4c2628bd1ce57456c2fec Mon Sep 17 00:00:00 2001 From: Nachtalb Date: Sat, 1 May 2021 00:51:55 +0200 Subject: [PATCH 02/58] Preserve location on first and last line when scrolling through inputs --- client/components/ChatInput.vue | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/client/components/ChatInput.vue b/client/components/ChatInput.vue index 35c68b7d..49f4d6fb 100644 --- a/client/components/ChatInput.vue +++ b/client/components/ChatInput.vue @@ -140,11 +140,10 @@ export default { return; } - const onRow = ( - this.$refs.input.value.slice(null, this.$refs.input.selectionStart).match(/\n/g) || - [] - ).length; - const totalRows = (this.$refs.input.value.match(/\n/g) || []).length; + const oldValue = this.$refs.input.value; + const oldPosition = this.$refs.input.selectionStart; + const onRow = (oldValue.slice(null, oldPosition).match(/\n/g) || []).length; + const totalRows = (oldValue.match(/\n/g) || []).length; const {channel} = this; @@ -165,7 +164,29 @@ export default { } channel.pendingMessage = channel.inputHistory[channel.inputHistoryPosition]; - this.$refs.input.value = channel.pendingMessage; + const newValue = channel.pendingMessage; + this.$refs.input.value = newValue; + + let newPosition; + + if (key === "up") { + const lastIndexOfNewLine = newValue.lastIndexOf("\n"); + const lastLine = newValue.slice(null, lastIndexOfNewLine); + newPosition = + oldPosition > lastLine.length + ? newValue.length + : lastIndexOfNewLine + oldPosition + 1; + } else { + const lastPositionOnFirstLine = + newValue.indexOf("\n") === -1 ? newValue.length + 1 : newValue.indexOf("\n"); + const relativeRowPos = oldPosition - oldValue.lastIndexOf("\n") - 1; + newPosition = + relativeRowPos > lastPositionOnFirstLine + ? lastPositionOnFirstLine + : relativeRowPos; + } + + this.$refs.input.setSelectionRange(newPosition, newPosition); this.setInputSize(); return false; From 4dacaa46f37ac5a0b46076cf68e193e7eb5f2b39 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sat, 3 Jul 2021 03:50:22 +0000 Subject: [PATCH 03/58] Optimise modes based on ISUPPORT This will see the maximum allowed of modes that are allowed at once as sent in RPL_ISUPPORT and will send multiple batches while using /op, /voice, etc. This also fixes a minor issue where it would try sending an empty voice if it had an extra space on arguments (such as using '/voice ') --- src/plugins/inputs/mode.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/plugins/inputs/mode.js b/src/plugins/inputs/mode.js index 4598a566..a86f3e26 100644 --- a/src/plugins/inputs/mode.js +++ b/src/plugins/inputs/mode.js @@ -19,7 +19,9 @@ exports.input = function ({irc, nick}, chan, cmd, args) { return; } - if (args.length === 0) { + const target = args.filter((arg) => arg !== ""); + + if (target.length === 0) { chan.pushMessage( this, new Msg({ @@ -40,9 +42,13 @@ exports.input = function ({irc, nick}, chan, cmd, args) { devoice: "-v", }[cmd]; - args.forEach(function (target) { - irc.raw("MODE", chan.name, mode, target); - }); + const limit = parseInt(irc.network.supports("modes")) || 1; + + for (let i = 0; i < target.length; i += limit) { + const targets = target.slice(i, i + limit); + const amode = `${mode[0]}${mode[1].repeat(targets.length)}`; + irc.raw("MODE", chan.name, amode, ...targets); + } return; } From 6439afd5c6b51518af98728bb9eaee5a2137a8c3 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sat, 3 Jul 2021 15:27:08 +0000 Subject: [PATCH 04/58] Fix nick-less PRIVMSGs from servers --- src/plugins/irc-events/message.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/irc-events/message.js b/src/plugins/irc-events/message.js index e86fc9b7..4aeeed21 100644 --- a/src/plugins/irc-events/message.js +++ b/src/plugins/irc-events/message.js @@ -27,6 +27,12 @@ module.exports = function (irc, network) { }); irc.on("privmsg", function (data) { + // Some servers send messages without any nickname + if (!data.nick) { + data.from_server = true; + data.nick = data.hostname || network.host; + } + data.type = Msg.Type.MESSAGE; handleMessage(data); }); From 16177eb9f4a630c83e0c4fc241b2293ec4966d46 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sat, 3 Jul 2021 21:06:16 +0000 Subject: [PATCH 05/58] Move server nick code to handleMessage --- src/plugins/irc-events/message.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/plugins/irc-events/message.js b/src/plugins/irc-events/message.js index 4aeeed21..0d67ff61 100644 --- a/src/plugins/irc-events/message.js +++ b/src/plugins/irc-events/message.js @@ -11,12 +11,6 @@ module.exports = function (irc, network) { const client = this; irc.on("notice", function (data) { - // Some servers send notices without any nickname - if (!data.nick) { - data.from_server = true; - data.nick = data.hostname || network.host; - } - data.type = Msg.Type.NOTICE; handleMessage(data); }); @@ -27,12 +21,6 @@ module.exports = function (irc, network) { }); irc.on("privmsg", function (data) { - // Some servers send messages without any nickname - if (!data.nick) { - data.from_server = true; - data.nick = data.hostname || network.host; - } - data.type = Msg.Type.MESSAGE; handleMessage(data); }); @@ -50,6 +38,12 @@ module.exports = function (irc, network) { let showInActive = false; const self = data.nick === irc.user.nick; + // Some servers send messages without any nickname + if (!data.nick) { + data.from_server = true; + data.nick = data.hostname || network.host; + } + // Check if the sender is in our ignore list const shouldIgnore = !self && From e0e12c196049e6609a5ddd40f0b47edd627a8a66 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sat, 3 Jul 2021 21:20:28 +0000 Subject: [PATCH 06/58] Fix tests for mode shorthand commands --- src/plugins/inputs/mode.js | 2 +- test/commands/mode.js | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/plugins/inputs/mode.js b/src/plugins/inputs/mode.js index a86f3e26..9af07079 100644 --- a/src/plugins/inputs/mode.js +++ b/src/plugins/inputs/mode.js @@ -42,7 +42,7 @@ exports.input = function ({irc, nick}, chan, cmd, args) { devoice: "-v", }[cmd]; - const limit = parseInt(irc.network.supports("modes")) || 1; + const limit = parseInt(irc.network.supports("MODES")) || 1; for (let i = 0; i < target.length; i += limit) { const targets = target.slice(i, i + limit); diff --git a/test/commands/mode.js b/test/commands/mode.js index ab27a9a4..c85cafaf 100644 --- a/test/commands/mode.js +++ b/test/commands/mode.js @@ -20,6 +20,13 @@ describe("Commands", function () { lastCommand: null, nick: "xPaw", irc: { + network: { + supports(type) { + if (type.toUpperCase() === "MODES") { + return "4"; + } + }, + }, raw(...args) { testableNetwork.lastCommand = args.join(" "); }, @@ -82,9 +89,18 @@ describe("Commands", function () { ModeCommand.input(testableNetwork, channel, "devoice", ["xPaw"]); expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v xPaw"); - // Multiple arguments are supported, sent as separate commands - ModeCommand.input(testableNetwork, channel, "devoice", ["xPaw", "Max-P"]); - expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v Max-P"); + ModeCommand.input(testableNetwork, channel, "voice", ["xPaw", "Max-P"]); + expect(testableNetwork.lastCommand).to.equal("MODE #thelounge +vv xPaw Max-P"); + + // since the limit for modes on tests is 4, it should send two commands + ModeCommand.input(testableNetwork, channel, "devoice", [ + "xPaw", + "Max-P", + "hey", + "idk", + "thelounge", + ]); + expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v thelounge"); }); }); }); From 998f8d2beb7b3fe09d74203b003d2de654319355 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sat, 3 Jul 2021 23:50:51 +0000 Subject: [PATCH 07/58] Fix userlist's wrong position on mobile devices --- client/css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/client/css/style.css b/client/css/style.css index 16673295..30bceaaa 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -2635,6 +2635,7 @@ part/quit messages where we don't load previews (adds a blank line otherwise) */ right: 0; transform: translateX(180px); transition: transform 0.2s; + z-index: 1; } #viewport.userlist-open #chat .userlist { From 23f6886cc1a3b1932c9f9102a8a94c0fb3b674c3 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sun, 4 Jul 2021 01:01:45 +0000 Subject: [PATCH 08/58] Add test for ISUPPORT-less networks on /mode shorthands --- test/commands/mode.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/commands/mode.js b/test/commands/mode.js index c85cafaf..731dcc5e 100644 --- a/test/commands/mode.js +++ b/test/commands/mode.js @@ -33,6 +33,19 @@ describe("Commands", function () { }, }; + const testableNetworkNoSupports = Object.assign({}, testableNetwork, { + irc: { + network: { + supports() { + return null; + }, + }, + raw(...args) { + testableNetworkNoSupports.lastCommand = args.join(" "); + }, + }, + }); + it("should not mess with the given target", function () { const test = function (expected, args) { ModeCommand.input(testableNetwork, channel, "mode", Array.from(args)); @@ -88,7 +101,9 @@ describe("Commands", function () { ModeCommand.input(testableNetwork, channel, "devoice", ["xPaw"]); expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v xPaw"); + }); + it("should use ISUPPORT MODES on shorthand commands", function () { ModeCommand.input(testableNetwork, channel, "voice", ["xPaw", "Max-P"]); expect(testableNetwork.lastCommand).to.equal("MODE #thelounge +vv xPaw Max-P"); @@ -102,5 +117,13 @@ describe("Commands", function () { ]); expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v thelounge"); }); + + it("should fallback to default limit of 1 mode for shorthand commands", function () { + ModeCommand.input(testableNetworkNoSupports, channel, "voice", ["xPaw"]); + expect(testableNetworkNoSupports.lastCommand).to.equal("MODE #thelounge +v xPaw"); + + ModeCommand.input(testableNetworkNoSupports, channel, "devoice", ["xPaw", "Max-P"]); + expect(testableNetworkNoSupports.lastCommand).to.equal("MODE #thelounge -v Max-P"); + }); }); }); From 372d74db69a8f99b78c83eb07c0cdf3339ce3b44 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Sun, 4 Jul 2021 20:22:49 +0000 Subject: [PATCH 09/58] Add warning for HTTPS requirement on notifications --- client/components/Windows/Settings.vue | 9 +++++++++ client/js/store.js | 2 ++ 2 files changed, 11 insertions(+) diff --git a/client/components/Windows/Settings.vue b/client/components/Windows/Settings.vue index 898e1613..1c6e264f 100644 --- a/client/components/Windows/Settings.vue +++ b/client/components/Windows/Settings.vue @@ -306,6 +306,7 @@ @@ -316,6 +317,14 @@ > Warning: Notifications are not supported by your browser. +
+ Warning: Notifications are only supported over HTTPS + connections. +
Date: Tue, 6 Jul 2021 01:29:53 -0700 Subject: [PATCH 10/58] Update dependencies --- package.json | 8 +++--- yarn.lock | 69 ++++++++++++++++++++++++---------------------------- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 78140e01..27a5a8f7 100644 --- a/package.json +++ b/package.json @@ -49,13 +49,13 @@ "express": "4.17.1", "file-type": "16.2.0", "filenamify": "4.2.0", - "got": "11.8.1", + "got": "11.8.2", "irc-framework": "4.11.0", "is-utf8": "0.2.1", "ldapjs": "2.2.3", "linkify-it": "3.0.2", "lodash": "4.17.21", - "mime-types": "2.1.28", + "mime-types": "2.1.31", "node-forge": "0.10.0", "package-json": "6.5.0", "read": "1.0.7", @@ -85,12 +85,12 @@ "css-loader": "5.1.1", "cssnano": "4.1.11", "dayjs": "1.10.5", - "emoji-regex": "9.2.1", + "emoji-regex": "9.2.2", "eslint": "7.23.0", "eslint-config-prettier": "6.15.0", "eslint-plugin-vue": "7.5.0", "fuzzy": "0.1.3", - "husky": "4.3.5", + "husky": "4.3.8", "mini-css-extract-plugin": "1.3.6", "mocha": "8.2.1", "mousetrap": "1.6.5", diff --git a/yarn.lock b/yarn.lock index a926adac..0c39b605 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2822,10 +2822,10 @@ electron-to-chromium@^1.3.723: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.762.tgz#3fa4e3bcbda539b50e3aa23041627063a5cffe61" integrity sha512-LehWjRpfPcK8F1Lf/NZoAwWLWnjJVo0SZeQ9j/tvnBWYcT99qDqgo4raAfS2oTKZjPrR/jxruh85DGgDUmywEA== -emoji-regex@9.2.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.1.tgz#c9b25604256bb3428964bead3ab63069d736f7ee" - integrity sha512-117l1H6U4X3Krn+MrzYrL57d5H7siRHWraBs7s+LjRuFK7Fe7hJqnJ0skWlinqsycVLU5YAo6L8CsEYQ0V5prg== +emoji-regex@9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== emoji-regex@^7.0.1: version "7.0.3" @@ -3348,7 +3348,7 @@ find-cache-dir@^3.2.0, find-cache-dir@^3.3.1: make-dir "^3.0.2" pkg-dir "^4.1.0" -find-up@5.0.0: +find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -3371,12 +3371,12 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -find-versions@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" - integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== +find-versions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" + integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== dependencies: - semver-regex "^2.0.0" + semver-regex "^3.1.2" flat-cache@^3.0.4: version "3.0.4" @@ -3667,10 +3667,10 @@ gonzales-pe@^4.3.0: dependencies: minimist "^1.2.5" -got@11.8.1: - version "11.8.1" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d" - integrity sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q== +got@11.8.2: + version "11.8.2" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599" + integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" @@ -3929,18 +3929,18 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -husky@4.3.5: - version "4.3.5" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.5.tgz#ab8d2a0eb6b62fef2853ee3d442c927d89290902" - integrity sha512-E5S/1HMoDDaqsH8kDF5zeKEQbYqe3wL9zJDyqyYqc8I4vHBtAoxkDBGXox0lZ9RI+k5GyB728vZdmnM4bYap+g== +husky@4.3.8: + version "4.3.8" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" + integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== dependencies: chalk "^4.0.0" ci-info "^2.0.0" compare-versions "^3.6.0" cosmiconfig "^7.0.0" - find-versions "^3.2.0" + find-versions "^4.0.0" opencollective-postinstall "^2.0.2" - pkg-dir "^4.2.0" + pkg-dir "^5.0.0" please-upgrade-node "^3.2.0" slash "^3.0.0" which-pm-runs "^1.0.0" @@ -4975,24 +4975,12 @@ middleware-handler@^0.2.0: resolved "https://registry.yarnpkg.com/middleware-handler/-/middleware-handler-0.2.0.tgz#bf02af7e6b577c0230609b2ae58df0e446f3fd02" integrity sha1-vwKvfmtXfAIwYJsq5Y3w5Ebz/QI= -mime-db@1.45.0: - version "1.45.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" - integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== - mime-db@1.48.0: version "1.48.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== -mime-types@2.1.28: - version "2.1.28" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" - integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== - dependencies: - mime-db "1.45.0" - -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.28, mime-types@~2.1.19, mime-types@~2.1.24: +mime-types@2.1.31, mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.28, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.31" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== @@ -5834,6 +5822,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -7092,10 +7087,10 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -semver-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" - integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== +semver-regex@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.2.tgz#34b4c0d361eef262e07199dbef316d0f2ab11807" + integrity sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA== "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" From 11ba27d80907aa124d217d020780fdd1ed0897ac Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Tue, 6 Jul 2021 01:31:24 -0700 Subject: [PATCH 11/58] Update emoji map --- client/js/helpers/simplemap.json | 2 +- scripts/generate-emoji.js | 0 2 files changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 scripts/generate-emoji.js diff --git a/client/js/helpers/simplemap.json b/client/js/helpers/simplemap.json index 4b917733..b71c8819 100644 --- a/client/js/helpers/simplemap.json +++ b/client/js/helpers/simplemap.json @@ -1238,8 +1238,8 @@ "credit_card": "💳", "receipt": "🧾", "chart": "💹", - "email": "✉️", "envelope": "✉️", + "email": "📧", "e_mail": "📧", "incoming_envelope": "📨", "envelope_with_arrow": "📩", diff --git a/scripts/generate-emoji.js b/scripts/generate-emoji.js old mode 100644 new mode 100755 From d96704835a31407affefc4b1eed28302dc80b8a0 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Tue, 6 Jul 2021 15:48:01 +0000 Subject: [PATCH 12/58] Send all modes in case of no ISUPPORT --- src/plugins/inputs/mode.js | 2 +- test/commands/mode.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/inputs/mode.js b/src/plugins/inputs/mode.js index 9af07079..30f90531 100644 --- a/src/plugins/inputs/mode.js +++ b/src/plugins/inputs/mode.js @@ -42,7 +42,7 @@ exports.input = function ({irc, nick}, chan, cmd, args) { devoice: "-v", }[cmd]; - const limit = parseInt(irc.network.supports("MODES")) || 1; + const limit = parseInt(irc.network.supports("MODES")) || target.length; for (let i = 0; i < target.length; i += limit) { const targets = target.slice(i, i + limit); diff --git a/test/commands/mode.js b/test/commands/mode.js index 731dcc5e..a818135a 100644 --- a/test/commands/mode.js +++ b/test/commands/mode.js @@ -118,12 +118,14 @@ describe("Commands", function () { expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v thelounge"); }); - it("should fallback to default limit of 1 mode for shorthand commands", function () { + it("should fallback to all modes at once for shorthand commands", function () { ModeCommand.input(testableNetworkNoSupports, channel, "voice", ["xPaw"]); expect(testableNetworkNoSupports.lastCommand).to.equal("MODE #thelounge +v xPaw"); ModeCommand.input(testableNetworkNoSupports, channel, "devoice", ["xPaw", "Max-P"]); - expect(testableNetworkNoSupports.lastCommand).to.equal("MODE #thelounge -v Max-P"); + expect(testableNetworkNoSupports.lastCommand).to.equal( + "MODE #thelounge -vv xPaw Max-P" + ); }); }); }); From 35fcacb7675fbb35551a4122adfe670ecca40870 Mon Sep 17 00:00:00 2001 From: JeDaYoshi Date: Tue, 6 Jul 2021 18:15:37 +0000 Subject: [PATCH 13/58] Add firstCommand and do further checks on mode tests --- test/commands/mode.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/commands/mode.js b/test/commands/mode.js index a818135a..a6ea9bad 100644 --- a/test/commands/mode.js +++ b/test/commands/mode.js @@ -17,6 +17,7 @@ describe("Commands", function () { }); const testableNetwork = { + firstCommand: null, lastCommand: null, nick: "xPaw", irc: { @@ -28,6 +29,7 @@ describe("Commands", function () { }, }, raw(...args) { + testableNetwork.firstCommand = testableNetwork.lastCommand; testableNetwork.lastCommand = args.join(" "); }, }, @@ -41,6 +43,7 @@ describe("Commands", function () { }, }, raw(...args) { + testableNetworkNoSupports.firstCommand = testableNetworkNoSupports.lastCommand; testableNetworkNoSupports.lastCommand = args.join(" "); }, }, @@ -115,6 +118,9 @@ describe("Commands", function () { "idk", "thelounge", ]); + expect(testableNetwork.firstCommand).to.equal( + "MODE #thelounge -vvvv xPaw Max-P hey idk" + ); expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v thelounge"); }); From 8fcd079204f6c44cadf7fff95c00a44242a61c68 Mon Sep 17 00:00:00 2001 From: Reto Date: Wed, 21 Jul 2021 09:30:07 +0200 Subject: [PATCH 14/58] Properly track user modes for context menu (#4267) * properly track user modes for context menu The RPL_ISUPPORT response contains a PREFIX element, which not only tracks the prefix chars ("@", "+" etc) but also their corresponding mode chars (+O, +v) This commit changes the context menu to not rely on a hardcoded list but rather user the one given in the prefix response by the server. Co-authored-by: Max Leiter --- client/js/helpers/contextMenu.js | 52 ++++++++++++++++------------ client/js/helpers/parse.js | 2 +- src/models/network.js | 8 ++++- src/models/prefix.js | 33 ++++++++++++++++++ src/models/user.js | 8 ++--- src/plugins/irc-events/connection.js | 17 +++------ src/plugins/irc-events/mode.js | 2 +- src/plugins/irc-events/names.js | 2 +- test/models/chan.js | 4 +-- test/models/msg.js | 2 +- 10 files changed, 84 insertions(+), 46 deletions(-) create mode 100644 src/models/prefix.js diff --git a/client/js/helpers/contextMenu.js b/client/js/helpers/contextMenu.js index feadd15c..b17c3794 100644 --- a/client/js/helpers/contextMenu.js +++ b/client/js/helpers/contextMenu.js @@ -252,22 +252,30 @@ export function generateUserContextMenu($root, channel, network, user) { return items; } - // Names of the modes we are able to change - const modes = { - "~": ["owner", "q"], - "&": ["admin", "a"], - "@": ["operator", "o"], - "%": ["half-op", "h"], - "+": ["voice", "v"], + // Names of the standard modes we are able to change + const modeCharToName = { + "~": "owner", + "&": "admin", + "@": "operator", + "%": "half-op", + "+": "voice", }; - // Labels for the mode changes. For example .rev(['admin', 'a']) => 'Revoke admin (-a)' + // Labels for the mode changes. For example .rev({mode: "a", symbol: "&"}) => 'Revoke admin (-a)' const modeTextTemplate = { - revoke: (m) => `Revoke ${m[0]} (-${m[1]})`, - give: (m) => `Give ${m[0]} (+${m[1]})`, + revoke(m) { + const name = modeCharToName[m.symbol]; + const res = name ? `Revoke ${name} (-${m.mode})` : `Mode -${m.mode}`; + return res; + }, + give(m) { + const name = modeCharToName[m.symbol]; + const res = name ? `Give ${name} (+${m.mode})` : `Mode +${m.mode}`; + return res; + }, }; - const networkModes = network.serverOptions.PREFIX; + const networkModeSymbols = network.serverOptions.PREFIX.symbols; /** * Determine whether the prefix of mode p1 has access to perform actions on p2. @@ -284,38 +292,38 @@ export function generateUserContextMenu($root, channel, network, user) { function compare(p1, p2) { // The modes ~ and @ can perform actions on their own mode. The others on modes below. return "~@".indexOf(p1) > -1 - ? networkModes.indexOf(p1) <= networkModes.indexOf(p2) - : networkModes.indexOf(p1) < networkModes.indexOf(p2); + ? networkModeSymbols.indexOf(p1) <= networkModeSymbols.indexOf(p2) + : networkModeSymbols.indexOf(p1) < networkModeSymbols.indexOf(p2); } - networkModes.forEach((prefix) => { - if (!compare(currentChannelUser.modes[0], prefix)) { + network.serverOptions.PREFIX.prefix.forEach((mode) => { + if (!compare(currentChannelUser.modes[0], mode.symbol)) { // Our highest mode is below the current mode. Bail. return; } - if (!user.modes.includes(prefix)) { + if (!user.modes.includes(mode.symbol)) { // The target doesn't already have this mode, therefore we can set it. items.push({ - label: modeTextTemplate.give(modes[prefix]), + label: modeTextTemplate.give(mode), type: "item", class: "action-set-mode", action() { socket.emit("input", { target: channel.id, - text: "/mode +" + modes[prefix][1] + " " + user.nick, + text: "/mode +" + mode.mode + " " + user.nick, }); }, }); } else { items.push({ - label: modeTextTemplate.revoke(modes[prefix]), + label: modeTextTemplate.revoke(mode), type: "item", class: "action-revoke-mode", action() { socket.emit("input", { target: channel.id, - text: "/mode -" + modes[prefix][1] + " " + user.nick, + text: "/mode -" + mode.mode + " " + user.nick, }); }, }); @@ -323,9 +331,9 @@ export function generateUserContextMenu($root, channel, network, user) { }); // Determine if we are half-op or op depending on the network modes so we can kick. - if (!compare(networkModes.indexOf("%") > -1 ? "%" : "@", currentChannelUser.modes[0])) { + if (!compare(networkModeSymbols.indexOf("%") > -1 ? "%" : "@", currentChannelUser.modes[0])) { + // Check if the target user has no mode or a mode lower than ours. if (user.modes.length === 0 || compare(currentChannelUser.modes[0], user.modes[0])) { - // Check if the target user has no mode or a mode lower than ours. items.push({ label: "Kick", type: "item", diff --git a/client/js/helpers/parse.js b/client/js/helpers/parse.js index 9097d96f..675dd0b0 100644 --- a/client/js/helpers/parse.js +++ b/client/js/helpers/parse.js @@ -79,7 +79,7 @@ function parse(createElement, text, message = undefined, network = undefined) { // arrays of objects containing start and end markers, as well as metadata // depending on what was found (channel or link). const channelPrefixes = network ? network.serverOptions.CHANTYPES : ["#", "&"]; - const userModes = network ? network.serverOptions.PREFIX : ["!", "@", "%", "+"]; + const userModes = network?.serverOptions?.PREFIX.symbols || ["!", "@", "%", "+"]; const channelParts = findChannels(cleanText, channelPrefixes, userModes); const linkParts = findLinks(cleanText); const emojiParts = findEmoji(cleanText); diff --git a/src/models/network.js b/src/models/network.js index 13879fb2..20e58752 100644 --- a/src/models/network.js +++ b/src/models/network.js @@ -5,6 +5,7 @@ const {v4: uuidv4} = require("uuid"); const IrcFramework = require("irc-framework"); const Chan = require("./chan"); const Msg = require("./msg"); +const Prefix = require("./prefix"); const Helper = require("../helper"); const STSPolicies = require("../plugins/sts"); const ClientCertificate = require("../plugins/clientCertificate"); @@ -43,7 +44,12 @@ function Network(attr) { irc: null, serverOptions: { CHANTYPES: ["#", "&"], - PREFIX: ["!", "@", "%", "+"], + PREFIX: new Prefix([ + {symbol: "!", mode: "Y"}, + {symbol: "@", mode: "o"}, + {symbol: "%", mode: "h"}, + {symbol: "+", mode: "v"}, + ]), NETWORK: "", }, diff --git a/src/models/prefix.js b/src/models/prefix.js new file mode 100644 index 00000000..331efdff --- /dev/null +++ b/src/models/prefix.js @@ -0,0 +1,33 @@ +"use strict"; + +class Prefix { + constructor(prefix) { + this.prefix = prefix || []; // [{symbol: "@", mode: "o"}, ... ] + this.modeToSymbol = {}; + this.symbols = []; + this._update_internals(); + } + + _update_internals() { + // clean out the old cruft + this.modeToSymbol = {}; + this.symbols = []; + + const that = this; + this.prefix.forEach(function (p) { + that.modeToSymbol[p.mode] = p.symbol; + that.symbols.push(p.symbol); + }); + } + + update(prefix) { + this.prefix = prefix || []; + this._update_internals(); + } + + forEach(f) { + return this.prefix.forEach(f); + } +} + +module.exports = Prefix; diff --git a/src/models/user.js b/src/models/user.js index 591ebddd..dee1e9d0 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -4,7 +4,7 @@ const _ = require("lodash"); module.exports = User; -function User(attr, prefixLookup) { +function User(attr, prefix) { _.defaults(this, attr, { modes: [], away: "", @@ -18,12 +18,12 @@ function User(attr, prefixLookup) { }, }); - this.setModes(this.modes, prefixLookup); + this.setModes(this.modes, prefix); } -User.prototype.setModes = function (modes, prefixLookup) { +User.prototype.setModes = function (modes, prefix) { // irc-framework sets character mode, but The Lounge works with symbols - this.modes = modes.map((mode) => prefixLookup[mode]); + this.modes = modes.map((mode) => prefix.modeToSymbol[mode]); }; User.prototype.toJSON = function () { diff --git a/src/plugins/irc-events/connection.js b/src/plugins/irc-events/connection.js index 029eefc2..3ef3000a 100644 --- a/src/plugins/irc-events/connection.js +++ b/src/plugins/irc-events/connection.js @@ -63,10 +63,9 @@ module.exports = function (irc, network) { }); irc.on("socket connected", function () { - network.prefixLookup = {}; - irc.network.options.PREFIX.forEach(function (mode) { - network.prefixLookup[mode.mode] = mode.symbol; - }); + if (irc.network.options.PREFIX) { + network.serverOptions.PREFIX.update(irc.network.options.PREFIX); + } network.channels[0].pushMessage( client, @@ -197,20 +196,12 @@ module.exports = function (irc, network) { }); irc.on("server options", function (data) { - network.prefixLookup = {}; - - data.options.PREFIX.forEach((mode) => { - network.prefixLookup[mode.mode] = mode.symbol; - }); + network.serverOptions.PREFIX.update(data.options.PREFIX); if (data.options.CHANTYPES) { network.serverOptions.CHANTYPES = data.options.CHANTYPES; } - if (network.serverOptions.PREFIX) { - network.serverOptions.PREFIX = data.options.PREFIX.map((p) => p.symbol); - } - network.serverOptions.NETWORK = data.options.NETWORK; client.emit("network:options", { diff --git a/src/plugins/irc-events/mode.js b/src/plugins/irc-events/mode.js index b07f0954..9c9bf6b2 100644 --- a/src/plugins/irc-events/mode.js +++ b/src/plugins/irc-events/mode.js @@ -107,7 +107,7 @@ module.exports = function (irc, network) { return; } - const changedMode = network.prefixLookup[char]; + const changedMode = network.serverOptions.PREFIX.modeToSymbol[char]; if (!add) { _.pull(user.modes, changedMode); diff --git a/src/plugins/irc-events/names.js b/src/plugins/irc-events/names.js index 2e0a7db8..8368b281 100644 --- a/src/plugins/irc-events/names.js +++ b/src/plugins/irc-events/names.js @@ -14,7 +14,7 @@ module.exports = function (irc, network) { data.users.forEach((user) => { const newUser = chan.getUser(user.nick); - newUser.setModes(user.modes, network.prefixLookup); + newUser.setModes(user.modes, network.serverOptions.PREFIX); newUsers.set(user.nick.toLowerCase(), newUser); }); diff --git a/test/models/chan.js b/test/models/chan.js index 33ee41e5..613bece3 100644 --- a/test/models/chan.js +++ b/test/models/chan.js @@ -20,10 +20,10 @@ describe("Chan", function () { }, }; - const prefixLookup = {}; + const prefixLookup = {modeToSymbol: {}}; network.network.options.PREFIX.forEach((mode) => { - prefixLookup[mode.mode] = mode.symbol; + prefixLookup.modeToSymbol[mode.mode] = mode.symbol; }); describe("#findMessage(id)", function () { diff --git a/test/models/msg.js b/test/models/msg.js index 3c7d59b7..7690754a 100644 --- a/test/models/msg.js +++ b/test/models/msg.js @@ -8,7 +8,7 @@ const User = require("../../src/models/user"); describe("Msg", function () { ["from", "target"].forEach((prop) => { it(`should keep a copy of the original user in the \`${prop}\` property`, function () { - const prefixLookup = {a: "&", o: "@"}; + const prefixLookup = {modeToSymbol: {a: "&", o: "@"}}; const user = new User( { modes: ["o"], From beb5530c6518b759b473c6664a344cd729f78b30 Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Tue, 31 Aug 2021 12:27:43 -0700 Subject: [PATCH 15/58] Revert "Support animated webp images" (#4287) This reverts pull/4186. --- client/components/Windows/Settings.vue | 19 ++- client/js/settings.js | 2 +- client/js/store-settings.js | 9 -- client/js/upload.js | 42 ++++++- package.json | 1 - src/client.js | 5 - src/plugins/uploader.js | 76 +++--------- webpack.config.js | 1 - yarn.lock | 164 ++++--------------------- 9 files changed, 93 insertions(+), 226 deletions(-) diff --git a/client/components/Windows/Settings.vue b/client/components/Windows/Settings.vue index 1c6e264f..6847f705 100644 --- a/client/components/Windows/Settings.vue +++ b/client/components/Windows/Settings.vue @@ -248,11 +248,18 @@
@@ -367,7 +374,7 @@ Custom highlights