From eccfdb7d39d3e981c9852f2bcf5505d79706ecdf Mon Sep 17 00:00:00 2001 From: double beep <38133098+double-beep@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:00:25 +0000 Subject: [PATCH] fix: always blacklist the regex that was watched, if possible --- src/chat.ts | 4 +-- src/index.ts | 33 ++++++++++++------ test/chat.spec.ts | 16 +++++---- test/dom_utils.spec.ts | 4 +-- test/domain_stats.spec.ts | 2 +- test/github.spec.ts | 12 +++---- test/index.spec.ts | 71 +++++++++++++++++++++++++------------- test/metasmoke.spec.ts | 15 ++++---- test/stackexchange.spec.ts | 4 +-- tsconfig.json | 2 +- 10 files changed, 100 insertions(+), 63 deletions(-) diff --git a/src/chat.ts b/src/chat.ts index 06ebd7c..cfb9578 100644 --- a/src/chat.ts +++ b/src/chat.ts @@ -86,8 +86,8 @@ function updateKeywordLists( try { const newRegex = new RegExp(regex, 'is'); - const compare = (regex: RegExp): boolean => - regex.source !== newRegex.source && regex.source !== `\\b${newRegex.source}\\b`; + const compare = (regexp: RegExp): boolean => + regexp.source !== newRegex.source && regexp.source !== `\\b${newRegex.source}\\b`; switch (action) { case 'watch': { diff --git a/src/index.ts b/src/index.ts index 37a6904..93ba16c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -106,16 +106,17 @@ export const helpers = { && Number(seHits) < 5; // not explicitly mentioned, but thought it's a good limit }, - // given a regexes array and a domain, find if the latter is matched by any items in the former - isCaught: (type: 'watch' | 'blacklist', domain: string): boolean => { + // find if given string exists in the watchlist/blacklist + // returns the last regex from that list which matches that string + isCaught: (type: 'watch' | 'blacklist', domain: string): RegExp | undefined => { const regexes = Domains[`${type}ed`]; - return regexes.some(regex => regex.test(domain)); + return regexes.findLast(regex => regex.test(domain)); }, - isWatched: (domain: string): boolean => helpers.isCaught('watch', domain), + isWatched: (domain: string): RegExp | undefined => helpers.isCaught('watch', domain), - isBlacklisted: (domain: string): boolean => helpers.isCaught('blacklist', domain), + isBlacklisted: (domain: string): boolean => Boolean(helpers.isCaught('blacklist', domain)), // get the id the domain li has - dots are replaced with dash getDomainId: (domainName: string): string => `fire-extra-${domainName.replace(/\./g, '-')}`, @@ -131,7 +132,13 @@ export const helpers = { }, // the tooltip text of !!/watch, !!/blacklist buttons - getButtonsText: (action: 'watch' | 'blacklist', term: string, done: boolean, domain?: string): string => { + getButtonsText: ( + action: 'watch' | 'blacklist', + term: string, + done: boolean, + domain?: string, + regex?: RegExp + ): string => { const command = action === 'watch' ? '!!/watch-' : '!!/blacklist-website-'; const alreadyDone = 'action already taken'; @@ -142,9 +149,15 @@ export const helpers = { .replace(/blogspot\.\w+(\.\w+)?$/, 'blogspot') // abc.blogspot.com => abc.blogspot .replace(/\./g, '\\.'); // escape dots + const replacement = regex?.source.slice(2, -2) + // fire-tooltip content is parsed as HTML + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>'); + return done ? alreadyDone - : `${command} ${watchValue}`; + : `${command} ${action === 'blacklist' && regex ? replacement : watchValue}`; }, // (?-i:) - case sensitive @@ -183,14 +196,14 @@ function updateEmojisInformation(term: string): void { const qualifiesForBlacklist = helpers.qualifiesForBlacklist(metasmokeStats, seResultCount); const watch = { - human: helpers.getActionDone('watched', isWatched), - tooltip: helpers.getButtonsText('watch', term, isWatched || isBlacklisted, domainName), + human: helpers.getActionDone('watched', Boolean(isWatched)), + tooltip: helpers.getButtonsText('watch', term, Boolean(isWatched) || isBlacklisted, domainName), suggested: qualifiesForWatch && !isWatched && !isBlacklisted, }; const blacklist = { human: helpers.getActionDone('blacklisted', isBlacklisted), - tooltip: helpers.getButtonsText('blacklist', term, isBlacklisted, domainName), + tooltip: helpers.getButtonsText('blacklist', term, isBlacklisted, domainName, isWatched), suggested: qualifiesForBlacklist && !isBlacklisted, }; diff --git a/test/chat.spec.ts b/test/chat.spec.ts index 6313bd0..7ebd200 100644 --- a/test/chat.spec.ts +++ b/test/chat.spec.ts @@ -15,8 +15,8 @@ function getRandomMessage( ): string { // linuxbuz\\.com is the (escaped domain) that's watched in the original message return original - .replace("Auto watch", `Auto ${action}`) - .replace("linuxbuz\\.com", escapedDomain); + .replace('Auto watch', `Auto ${action}`) + .replace('linuxbuz\\.com', escapedDomain); } async function getMessage(id: number): Promise { @@ -36,7 +36,7 @@ describe('chat helpers', function() { const messages = [ 'watch random-domain\\.com', - 'blacklist random-random-domain\\.com', + 'blacklist random-random-domain\\.com', 'unwatch random-domain\\.com', 'unblacklist tenderpublish', 'watch domain\\.with\\.a\\.few\\.dots\\.com', @@ -49,7 +49,7 @@ describe('chat helpers', function() { const actionType = messageSplit[0] as ChatMessageActions; const domain = messageSplit[1]; - const fullMessage = getRandomMessage(chatMessage, actionType, domain) + const fullMessage = getRandomMessage(chatMessage, actionType, domain); return new JSDOM(fullMessage).window.document; }) @@ -64,7 +64,8 @@ describe('chat helpers', function() { ); }); - const { isWatched, isBlacklisted } = helpers; + const isWatched = (domain: string): boolean => Boolean(helpers.isWatched(domain)); + const { isBlacklisted } = helpers; // random-domain.com was first watched, then unwatched and shouldn't be in the watchlist expect(isWatched('random-domain.com')).to.be.false; @@ -104,7 +105,8 @@ describe('chat helpers', function() { } ]; - const { isWatched, isBlacklisted } = helpers; + const isWatched = (domain: string): boolean => Boolean(helpers.isWatched(domain)); + const { isBlacklisted } = helpers; // Merge pull request #12085 expect(isBlacklisted('spam.com')).to.be.false; @@ -127,4 +129,4 @@ describe('chat helpers', function() { expect(Domains.pullRequests.find(pr => pr.id === 12085)).to.be.undefined; expect(Domains.pullRequests.find(pr => pr.id === 12080)).to.be.undefined; }); -}); \ No newline at end of file +}); diff --git a/test/dom_utils.spec.ts b/test/dom_utils.spec.ts index 75da328..1239809 100644 --- a/test/dom_utils.spec.ts +++ b/test/dom_utils.spec.ts @@ -19,7 +19,7 @@ describe('DOM utils', () => { // MS part expect(msPart.children[0].textContent).to.be.equal('MS'); expect(msPart.children[1].classList.contains('fire-extra-ms-stats')).to.be.true; - expect(msPart.children[1].children[0]?.classList.contains('fire-extra-wait')).to.be.true; + expect(msPart.children[1].children[0].classList.contains('fire-extra-wait')).to.be.true; // SE part expect(sePart.classList.contains('fire-extra-se-results')); @@ -93,6 +93,6 @@ describe('DOM utils', () => { expect(hitCountAnchor.innerHTML).to.be.equal('SE search'); // expect(hitCountAnchor.innerHTML).to.be.equal('SE: 10.5k'); - //expect(hitCountAnchor.getAttribute('fire-tooltip')).to.be.equal('10.5k hits on SE'); + // expect(hitCountAnchor.getAttribute('fire-tooltip')).to.be.equal('10.5k hits on SE'); }); }); diff --git a/test/domain_stats.spec.ts b/test/domain_stats.spec.ts index a64fd29..de455a4 100644 --- a/test/domain_stats.spec.ts +++ b/test/domain_stats.spec.ts @@ -79,4 +79,4 @@ describe('whitelisted domains and URL shorteners', () => { expect(isWhitelisted).to.be.false; }); }); -}); \ No newline at end of file +}); diff --git a/test/github.spec.ts b/test/github.spec.ts index 294ed4e..e60f7a7 100644 --- a/test/github.spec.ts +++ b/test/github.spec.ts @@ -7,15 +7,14 @@ import { getUpdatedPrInfo, parseApiResponse } from '../src/github'; -import jsdom from "jsdom"; +import jsdom from 'jsdom'; import { Domains } from '../src/domain_stats'; const { JSDOM } = jsdom; global.document = new JSDOM().window.document; -const watchSample = String.raw -`1494929269 tripleee thewellnesscorner\.com +const watchSample = String.raw`1494929269 tripleee thewellnesscorner\.com 1494929399 tripleee optisolbusiness\.com 1494997469 tripleee careinfo\.in 1494997580 tripleee carebaba\.com @@ -23,8 +22,7 @@ const watchSample = String.raw 1495002561 tripleee erozon 1495005325 tripleee onlinesupplementworld\.com 1495006487 tripleee ahealthadvisory\.com`; -const blacklistedSample = String.raw -`resolit\.us +const blacklistedSample = String.raw`resolit\.us techinpost\.com hackerscontent\.com hrsoftwaresolution\.com @@ -139,7 +137,7 @@ describe('github helpers', () => { validChatMessages.forEach(async message => { const content = new JSDOM(message).window.document; - const text = content.body?.innerHTML || ''; + const text = content.body.innerHTML || ''; const functionReturnValue = await getUpdatedPrInfo(text); expect(functionReturnValue).not.to.be.undefined; @@ -148,4 +146,4 @@ describe('github helpers', () => { const irrelevantMessage = 'This is an unrelated message about a pull request'; expect(await getUpdatedPrInfo(irrelevantMessage)).to.be.undefined; }); -}); \ No newline at end of file +}); diff --git a/test/index.spec.ts b/test/index.spec.ts index 84e0e43..956ec0d 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -6,15 +6,19 @@ describe('index helpers', () => { before(async () => await Domains.fetchAllDomainInformation()); it('should find if a domain with specific stats qualifies for watch', () => { - expect(helpers.qualifiesForWatch([1, 0, 0], '0')).to.be.true; - expect(helpers.qualifiesForWatch([5, 0, 0], '10')).to.be.false; - expect(helpers.qualifiesForWatch([1, 0, 1], '2')).to.be.false; + const { qualifiesForWatch: shouldWatch } = helpers; + + expect(shouldWatch([1, 0, 0], '0')).to.be.true; + expect(shouldWatch([5, 0, 0], '10')).to.be.false; + expect(shouldWatch([1, 0, 1], '2')).to.be.false; }); it('should find if a domain with specific stats qualifies for blacklist', () => { - expect(helpers.qualifiesForBlacklist([5, 0, 0], '4')).to.be.true; - expect(helpers.qualifiesForBlacklist([10, 0, 0], '5')).to.be.false; - expect(helpers.qualifiesForBlacklist([10, 2, 0], '4')).to.be.false; + const { qualifiesForBlacklist: shouldBlacklist } = helpers; + + expect(shouldBlacklist([5, 0, 0], '4')).to.be.true; + expect(shouldBlacklist([10, 0, 0], '5')).to.be.false; + expect(shouldBlacklist([10, 2, 0], '4')).to.be.false; }); it('should get the correct li id given a domain', () => { @@ -66,10 +70,11 @@ describe('index helpers', () => { const body = url.searchParams.get('body'); expect(body).to.be.equal(`(?i)speakatoo\\.com`); - }); + }).timeout(5000); it('should figure out if a domain is caught or not', () => { - const { isWatched, isBlacklisted } = helpers; + const isWatched = (domain: string): boolean => Boolean(helpers.isWatched(domain)); + const { isBlacklisted } = helpers; const validWatches = ['essayssos.com', 'trimfire', 'erozon', 'saleleads.net', 'SaleLeads.net']; const invalidWatches = ['non-existent-keyword', 'google.com']; @@ -107,47 +112,65 @@ describe('index helpers', () => { }); it('should correctly pluralise words', () => { - expect(helpers.pluralise('hit', 1)).to.be.equal('hit'); - expect(helpers.pluralise('hit', 0)).to.be.equal('hits'); - expect(helpers.pluralise('hit', 100)).to.be.equal('hits'); + const { pluralise } = helpers; + + expect(pluralise('hit', 1)).to.be.equal('hit'); + expect(pluralise('hit', 0)).to.be.equal('hits'); + expect(pluralise('hit', 100)).to.be.equal('hits'); }); it('should correctly fetch accurate tooltip texts for the emojis', () => { - expect(helpers.getActionDone('watched', true)).to.be.equal('watched: yes'); - expect(helpers.getActionDone('watched', false)).to.be.equal('watched: no'); + const { getActionDone } = helpers; - expect(helpers.getActionDone('blacklisted', true)).to.be.equal('blacklisted: yes'); - expect(helpers.getActionDone('blacklisted', false)).to.be.equal('blacklisted: no'); + expect(getActionDone('watched', true)).to.be.equal('watched: yes'); + expect(getActionDone('watched', false)).to.be.equal('watched: no'); + + expect(getActionDone('blacklisted', true)).to.be.equal('blacklisted: yes'); + expect(getActionDone('blacklisted', false)).to.be.equal('blacklisted: no'); }); it('should correctly fetch accurate tooltip texts for !!/watch and !!/blacklist', () => { - const watchedNoAction = helpers.getButtonsText('watch', 'example.com', true); - const blacklistedNoAction = helpers.getButtonsText('blacklist', 'example.com', true); + const { getButtonsText } = helpers; + + const watchedNoAction = getButtonsText('watch', 'example.com', true); + const blacklistedNoAction = getButtonsText('blacklist', 'example.com', true); - const watchExampleCom = helpers.getButtonsText('watch', 'example.com', false); - const blacklistManyDots = helpers.getButtonsText('blacklist', 'many.dots..com', false); + const watchExampleCom = getButtonsText('watch', 'example.com', false); + const blacklistManyDots = getButtonsText('blacklist', 'many.dots..com', false); expect(watchedNoAction).to.be.equal(blacklistedNoAction); expect(watchExampleCom).to.be.equal('!!/watch- example\\.com'); expect(blacklistManyDots).to.be.equal('!!/blacklist-website- many\\.dots\\.\\.com'); - const watchShortenerPath = helpers.getButtonsText('watch', 'FNEuyd', false, 'goo.gl'); + const watchShortenerPath = getButtonsText('watch', 'FNEuyd', false, 'goo.gl'); expect(watchShortenerPath).to.be.equal('!!/watch- (?-i:FNEuyd)(?#goo.gl)'); - const watchBlogspotCom = helpers.getButtonsText('watch', 'abc.blogspot.com', false); - const watchBlogspotDe = helpers.getButtonsText('watch', 'abc.blogspot.de', false); + const watchBlogspotCom = getButtonsText('watch', 'abc.blogspot.com', false); + const watchBlogspotDe = getButtonsText('watch', 'abc.blogspot.de', false); expect(watchBlogspotCom) .to.be.equal(watchBlogspotDe) .to.be.equal('!!/watch- abc\\.blogspot'); + + expect( + getButtonsText( + 'blacklist', + 'test.example.com', + false, + '', + /\bexample\.com(? { Object.entries( { '3vcWir3': ['bit.ly', '(?-i:3vcWir3)(?#bit.ly)'], - 'FNEuyd': ['goo.gl', '(?-i:FNEuyd)(?#goo.gl)'], - 'KdxEAt91D7k': ['youtu.be', '(?-i:KdxEAt91D7k)(?#youtu.be)'], + FNEuyd: ['goo.gl', '(?-i:FNEuyd)(?#goo.gl)'], + KdxEAt91D7k: ['youtu.be', '(?-i:KdxEAt91D7k)(?#youtu.be)'], // escape + '+jJyLwSpqLeAzNmFi': ['t.me', String.raw`(?-i:\+jJyLwSpqLeAzNmFi)(?#t.me)`], // don't escape / diff --git a/test/metasmoke.spec.ts b/test/metasmoke.spec.ts index 0d1336c..e6c6c3f 100644 --- a/test/metasmoke.spec.ts +++ b/test/metasmoke.spec.ts @@ -3,7 +3,7 @@ import { getAllDomainsFromPost, getMsSearchResults } from '../src/metasmoke'; -import jsdom from "jsdom"; +import jsdom from 'jsdom'; const { JSDOM } = jsdom; @@ -12,18 +12,18 @@ global.GM_xmlhttpRequest = ({ url, onload, onerror -}) => { +}): void => { fetch(url) .then(async response => { // @ts-ignore onload({ status: response.status, responseText: await response.text() - }) + }); }) - // @ts-ignore + // @ts-expect-error .catch(error => onerror(error)); -} +}; global.DOMParser = new JSDOM().window.DOMParser; describe('metasmoke helpers', () => { @@ -42,12 +42,13 @@ describe('metasmoke helpers', () => { this.timeout(10000); // due to calls to MS search const termEntries = Object.entries({ - 'LcZ2pm9XtXA': [3, 0, 0], - 'FNEuyd': [0, 1, 0], + LcZ2pm9XtXA: [3, 0, 0], + FNEuyd: [0, 1, 0], '3vcWir3': [1, 0, 0] }); for (const [term, expectedCounts] of termEntries) { + // eslint-disable-next-line no-await-in-loop const actualCounts = await getMsSearchResults(term); expect(actualCounts).deep.equal(expectedCounts); diff --git a/test/stackexchange.spec.ts b/test/stackexchange.spec.ts index fe27de2..caef037 100644 --- a/test/stackexchange.spec.ts +++ b/test/stackexchange.spec.ts @@ -4,7 +4,7 @@ import { getSeResultCount, getShortenedResultCount } from '../src/stackexchange'; -import jsdom from "jsdom"; +import jsdom from 'jsdom'; const { JSDOM } = jsdom; @@ -14,7 +14,7 @@ describe('stackexchange helpers', () => { it('should correctly get the correct Stack Exchange search URL', () => { const data = { 'example.com': 'https://stackexchange.com/search?q=url%3Aexample.com', - 'KdxEAt91D7k': 'https://stackexchange.com/search?q=KdxEAt91D7k' + KdxEAt91D7k: 'https://stackexchange.com/search?q=KdxEAt91D7k' }; Object diff --git a/tsconfig.json b/tsconfig.json index 352a142..41335cf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "strict": true, - "lib": ["DOM", "DOM.iterable", "es2020"], + "lib": ["DOM", "DOM.iterable", "esnext"], "target": "esnext", "module": "commonjs", "moduleResolution": "node",