From 1c7526432e9f8fae1360d30bf8ad122591b28396 Mon Sep 17 00:00:00 2001 From: ItsOnlyBinary Date: Tue, 5 Sep 2023 15:13:52 +0100 Subject: [PATCH] Simplify --- src/commands/handlers/registration.js | 6 +- src/messagetags.js | 44 ------------- src/networkinfo.js | 40 ++++++++---- test/messagetags.js | 43 ------------- test/networkinfo.test.js | 92 ++++++++++++++++++++++++--- 5 files changed, 113 insertions(+), 112 deletions(-) diff --git a/src/commands/handlers/registration.js b/src/commands/handlers/registration.js index bbc0da88..209a4aa3 100644 --- a/src/commands/handlers/registration.js +++ b/src/commands/handlers/registration.js @@ -84,9 +84,9 @@ const handlers = { handler.network.options.CHANMODES = option[1].split(','); } else if (option[0] === 'CASEMAPPING') { handler.network.options.CASEMAPPING = option[1]; - // https://ircv3.net/specs/extensions/message-tags#rpl_isupport-tokens - } else if (option[0] === 'CLIENTTAGDENY' && handler.network.cap.isEnabled('message-tags')) { - handler.network.options.CLIENTTAGDENY = option[1].split(','); + } else if (option[0] === 'CLIENTTAGDENY') { + // https://ircv3.net/specs/extensions/message-tags#rpl_isupport-tokens + handler.network.options.CLIENTTAGDENY = option[1].split(',').filter((f) => !!f); } else if (option[0] === 'NETWORK') { handler.network.name = option[1]; } else if (option[0] === 'NAMESX' && !handler.network.cap.isEnabled('multi-prefix')) { diff --git a/src/messagetags.js b/src/messagetags.js index ecb34f2f..ae78cc15 100644 --- a/src/messagetags.js +++ b/src/messagetags.js @@ -6,8 +6,6 @@ module.exports.decodeValue = decodeValue; module.exports.encodeValue = encodeValue; module.exports.decode = decode; module.exports.encode = encode; -module.exports.parseDenylist = parseDenylist; -module.exports.isBlocked = isBlocked; const tokens_map = { '\\\\': '\\', @@ -70,45 +68,3 @@ function encode(tags, separator = ';') { return parts.join(separator); } - -// Parses a raw CLIENTTAGDENY= denylist -// into a { allBlockedByDefault: boolean, explicitlyAccepted: string[], explicitlyDenied: string[] } -// structure. -function parseDenylist(raw) { - const denylist = { - allBlockedByDefault: false, - explicitlyAccepted: [], - explicitlyDenied: [] - }; - const parts = raw.split(','); - - for (let idx = 0; idx < parts.length; idx++) { - const tag = parts[idx]; - if (tag === '') { - continue; - } - - if (tag === '*') { - denylist.allBlockedByDefault = true; - continue; - } - - if (tag[0] === '-') { - denylist.explicitlyAccepted.push(tag.slice(1)); - } else { - denylist.explicitlyDenied.push(tag); - } - } - - return denylist; -} - -// Takes a parsed denylist and returns whether tag is allowed -// according to current denial policies. -function isBlocked(denylist, tag) { - if (denylist.allBlockedByDefault) { - return !denylist.explicitlyAccepted.includes(tag); - } else { - return denylist.explicitlyDenied.includes(tag); - } -} diff --git a/src/networkinfo.js b/src/networkinfo.js index b9efcb3a..e759e144 100644 --- a/src/networkinfo.js +++ b/src/networkinfo.js @@ -26,7 +26,17 @@ function NetworkInfo() { { symbol: '%', mode: 'h' }, { symbol: '+', mode: 'v' } ], - CLIENTTAGDENY: [] + }; + + // Network capabilities + this.cap = { + negotiating: false, + requested: [], + enabled: [], + available: new Map(), + isEnabled: function(cap_name) { + return this.enabled.indexOf(cap_name) > -1; + } }; this.time_offsets = []; @@ -70,6 +80,23 @@ function NetworkInfo() { return this.options[support_name.toUpperCase()]; }; + this.supportsTag = function supportsTag(tag_name) { + if (!this.cap.isEnabled('message-tags')) { + return false; + } + + if (!this.options.CLIENTTAGDENY || this.options.CLIENTTAGDENY.length === 0) { + return true; + } + + const allowAll = this.options.CLIENTTAGDENY[0] !== '*'; + if (allowAll) { + return !this.options.CLIENTTAGDENY.some((tag) => tag === tag_name); + } + + return this.options.CLIENTTAGDENY.some((tag) => tag === `-${tag_name}`); + }; + this.isChannelName = function isChannelName(channel_name) { if (typeof channel_name !== 'string' || channel_name === '') { return false; @@ -103,15 +130,4 @@ function NetworkInfo() { target_group: target_group, }; }; - - // Network capabilities - this.cap = { - negotiating: false, - requested: [], - enabled: [], - available: new Map(), - isEnabled: function(cap_name) { - return this.enabled.indexOf(cap_name) > -1; - } - }; } diff --git a/test/messagetags.js b/test/messagetags.js index 597b4aae..745d2af4 100644 --- a/test/messagetags.js +++ b/test/messagetags.js @@ -8,49 +8,6 @@ const assert = chai.assert; chai.use(require('chai-subset')); describe('src/messagetags.js', function() { - describe('CLIENTTAGDENY= parsing', function() { - it('should parse CLIENTTAGDENY=', function() { - assert.deepEqual(MessageTags.parseDenylist(''), { - allBlockedByDefault: false, - explicitlyDenied: [], - explicitlyAccepted: [] - }); - }); - - it('should parse CLIENTTAGDENY=*,-a', function() { - assert.deepEqual(MessageTags.parseDenylist('*,-a'), { - allBlockedByDefault: true, - explicitlyAccepted: ['a'], - explicitlyDenied: [] - }); - }); - - it('should parse CLIENTTAGDENY=a,b', function() { - assert.deepEqual(MessageTags.parseDenylist('a,b'), { - allBlockedByDefault: false, - explicitlyAccepted: [], - explicitlyDenied: ['a', 'b'] - }); - }); - }); - - describe('CLIENTTAGDENY= logic', function() { - it('should block all tags (`b`) with * and no exception', function() { - assert.isTrue(MessageTags.isBlocked(MessageTags.parseDenylist('*'), 'b')); - }); - - it('should not block all tags with * and exceptions (`c`, `a`)', function() { - assert.isFalse(MessageTags.isBlocked(MessageTags.parseDenylist('*,-c,-a'), 'a')); - assert.isFalse(MessageTags.isBlocked(MessageTags.parseDenylist('*,-c,-a'), 'c')); - assert.isTrue(MessageTags.isBlocked(MessageTags.parseDenylist('*,-c,-a'), 'b')); - }); - - it('should block a specific tag if no * is present', function() { - assert.isTrue(MessageTags.isBlocked(MessageTags.parseDenylist('a'), 'a')); - assert.isFalse(MessageTags.isBlocked(MessageTags.parseDenylist('a'), 'b')); - }); - }); - describe('value encoding', function() { it('should decode characters to correct strings', function() { const plain = "Some people use IRC; others don't \\o/ Note: Use IRC\r\n"; diff --git a/test/networkinfo.test.js b/test/networkinfo.test.js index 6cc9e4ab..44a4254b 100644 --- a/test/networkinfo.test.js +++ b/test/networkinfo.test.js @@ -53,6 +53,28 @@ describe('src/networkinfo.js', function() { const results = names.map(name => client.network.isChannelName(name)); assert.deepEqual(results, [false, false, false, false, false, false]); }); + }); + + describe('CLIENTTAGDENY Support', function() { + it('should parse CLIENTTAGDENY=a,b,c as a list', function() { + const client = newMockClient(); + client.dispatch({ + command: '005', + params: ['nick', 'CLIENTTAGDENY=a,b,c'], + tags: [] + }); + assert.deepEqual(client.network.options.CLIENTTAGDENY, ['a', 'b', 'c']); + }); + + it('should parse CLIENTTAGDENY=*,-a,-b as a list', function() { + const client = newMockClient(); + client.dispatch({ + command: '005', + params: ['nick', 'CLIENTTAGDENY=*,-a,-b'], + tags: [] + }); + assert.deepEqual(client.network.options.CLIENTTAGDENY, ['*', '-a', '-b']); + }); it('should parse CLIENTTAGDENY= as a list', function() { const client = newMockClient(); @@ -61,27 +83,77 @@ describe('src/networkinfo.js', function() { params: ['nick', 'CLIENTTAGDENY='], tags: [] }); + assert.isArray(client.network.options.CLIENTTAGDENY); assert.isEmpty(client.network.options.CLIENTTAGDENY); }); - it('should parse CLIENTTAGDENY=*,-a,-b as a list', function() { + it('should be undefined when no CLIENTTAGDENY', function() { + const client = newMockClient(); + client.dispatch({ + command: '005', + params: ['nick', ''], + tags: [] + }); + assert.isUndefined(client.network.options.CLIENTTAGDENY); + }); + + it('should deny all when no message-tags CAP', function() { const client = newMockClient(); client.dispatch({ command: '005', params: ['nick', 'CLIENTTAGDENY=*,-a,-b'], tags: [] }); - assert.equal(client.network.options.CLIENTTAGDENY, ['*', '-a', '-b']); + assert.isFalse(client.network.supportsTag('a')); + assert.isFalse(client.network.supportsTag('b')); }); - }); - it('should parse CLIENTTAGDENY=a,b,c as a list', function() { - const client = newMockClient(); - client.dispatch({ - command: '005', - params: ['nick', 'CLIENTTAGDENY=a,b,c'], - tags: [] + it('should allow all when CLIENTTAGDENY=', function() { + const client = newMockClient(); + client.network.cap.enabled.push('message-tags'); + client.dispatch({ + command: '005', + params: ['nick', 'CLIENTTAGDENY='], + tags: [] + }); + assert.isTrue(client.network.supportsTag('a')); + assert.isTrue(client.network.supportsTag('b')); + }); + + it('should deny all when CLIENTTAGDENY=*', function() { + const client = newMockClient(); + client.network.cap.enabled.push('message-tags'); + client.dispatch({ + command: '005', + params: ['nick', 'CLIENTTAGDENY=*'], + tags: [] + }); + assert.isFalse(client.network.supportsTag('a')); + assert.isFalse(client.network.supportsTag('b')); + }); + + it('should allow a & deny b, c when CLIENTTAGDENY=*,-a', function() { + const client = newMockClient(); + client.network.cap.enabled.push('message-tags'); + client.dispatch({ + command: '005', + params: ['nick', 'CLIENTTAGDENY=*,-a'], + tags: [] + }); + assert.isTrue(client.network.supportsTag('a')); + assert.isFalse(client.network.supportsTag('b')); + }); + + it('should allow a & deny b when CLIENTTAGDENY=b', function() { + const client = newMockClient(); + client.network.cap.enabled.push('message-tags'); + client.dispatch({ + command: '005', + params: ['nick', 'CLIENTTAGDENY=b'], + tags: [] + }); + assert.isTrue(client.network.supportsTag('a')); + assert.isFalse(client.network.supportsTag('b')); }); - assert.equal(client.network.options.CLIENTTAGDENY, ['a', 'b', 'c']); }); });