Re-add Jest, revert ava (#1779)

* Re-add Jest (env node)

* Revert "Switch to ava as a test runner (#1778)"

This reverts commit 5aa2b3c096.
This commit is contained in:
Jaco
2022-07-08 13:17:48 +02:00
committed by GitHub
parent ce0c54e9ba
commit eaf3121696
11 changed files with 257 additions and 1067 deletions
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
const config = require('@polkadot/dev/config/jest.cjs');
module.exports = {
...config,
moduleNameMapper: {},
testTimeout: 2 * 60 * 1000
};
-6
View File
@@ -1,6 +0,0 @@
// Copyright 2017-2022 @polkadot/apps authors & contributors
// SPDX-License-Identifier: Apache-2.0
const { fetch } = require('@polkadot/x-fetch/node');
global.fetch = fetch;
+4 -6
View File
@@ -32,11 +32,10 @@
"clean": "polkadot-dev-clean-build",
"deno": "yarn polkadot-dev-deno-map && yarn build && deno check --import-map=import_map.json mod.ts",
"lint": "polkadot-dev-run-lint",
"phishing:addrcheck": "ava packages/phishing/src/addrcheck.spec.ts",
"phishing:crosscheck": "ava packages/phishing/src/crosscheck.spec.ts",
"phishing:addrcheck": "NODE_OPTIONS=--experimental-vm-modules polkadot-dev-run-test --runInBand --detectOpenHandles packages/phishing/src/addrcheck",
"phishing:crosscheck": "NODE_OPTIONS=--experimental-vm-modules polkadot-dev-run-test --runInBand --detectOpenHandles packages/phishing/src/crosscheck",
"postinstall": "polkadot-dev-yarn-only",
"test": "ava --match '!CI*'",
"test:one": "yarn test"
"test": "NODE_OPTIONS=--experimental-vm-modules polkadot-dev-run-test --coverage --runInBand --detectOpenHandles --testPathIgnorePatterns addrcheck --testPathIgnorePatterns crosscheck"
},
"dependencies": {
"@pinata/sdk": "^1.1.26",
@@ -45,8 +44,7 @@
"devDependencies": {
"@babel/core": "^7.18.6",
"@polkadot/dev": "^0.67.63",
"ava": "^4.3.0",
"ts-node": "^10.8.2"
"@types/jest": "^28.1.4"
},
"resolutions": {
"typescript": "^4.7.4"
-1
View File
@@ -27,7 +27,6 @@
},
"devDependencies": {
"@types/js-yaml": "^4.0.5",
"ava": "^4.3.0",
"js-yaml": "^4.1.0"
}
}
+81 -73
View File
@@ -1,7 +1,6 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import test from 'ava';
import fs from 'fs';
import { decodeAddress } from '@polkadot/util-crypto';
@@ -34,81 +33,90 @@ const TOP_LEVEL = [
'zapto.org'
];
test('has no malformed addresses', (t): void => {
const invalids = Object
.entries(addresses)
.map(([url, addrs]): [string, string[]] => {
return [url, addrs.filter((a) => {
try {
return decodeAddress(a).length !== 32;
} catch (error) {
console.error(url, (error as Error).message);
describe('added addresses', (): void => {
it('has no malformed addresses', (): void => {
const invalids = Object
.entries(addresses)
.map(([url, addrs]): [string, string[]] => {
return [url, addrs.filter((a) => {
try {
return decodeAddress(a).length !== 32;
} catch (error) {
console.error(url, (error as Error).message);
return true;
}
})];
})
.filter(([, addrs]) => addrs.length)
.map(([url, addrs]) => `${url}: ${addrs.join(', ')}`);
return true;
}
})];
})
.filter(([, addrs]) => addrs.length);
t.deepEqual(invalids, []);
});
test('has no entries on the known addresses list', (t): void => {
const added = Object
.values(addresses)
.reduce<string[]>((all, addrs) => all.concat(addrs), []);
const dupes = Object
.entries(allowed)
.reduce<[string, string][]>((all, [site, addrs]) => all.concat(addrs.map((a) => [site, a])), [])
.filter(([, a]) => added.includes(a));
t.deepEqual(dupes, []);
});
test('has no entries for allowed top-level domains', (t): void => {
const invalids = all.deny.filter((u) =>
TOP_LEVEL.some((t) =>
t.startsWith('*.')
? (u.endsWith(t.substring(1)) || u === t.substring(2))
: u === t
)
);
t.deepEqual(invalids, []);
});
test('has no malformed domain-only entries', (t): void => {
const invalids = all.deny.filter((u) =>
u.includes('/') || // don't allow paths
u.includes('?') || // don't allow query params
u.includes(' ') || // no spaces
!u.includes('.') // need at least a domain
);
t.deepEqual(invalids, []);
});
test('has no urls starting with www. (domain-only inclusions)', (t): void => {
const invalids = all.deny.filter((u) =>
u.startsWith('www.')
);
t.deepEqual(invalids, []);
});
test('has no duplicate entries', (t): void => {
const checks: string[] = [];
const dupes = all.deny.reduce<string[]>((dupes, url) => {
if (!checks.includes(url)) {
checks.push(url);
} else {
dupes.push(url);
if (invalids.length) {
throw new Error(`Invalid ss58 checksum addresses found: ${invalids.map(([url, addrs]) => `\n\t${url}: ${addrs.join(', ')}`).join('')}`);
}
});
return dupes;
}, []);
it('has no entries on the known addresses list', (): void => {
const added = Object
.values(addresses)
.reduce<string[]>((all, addrs) => all.concat(addrs), []);
const dupes = Object
.entries(allowed)
.reduce<[string, string][]>((all, [site, addrs]) => all.concat(addrs.map((a) => [site, a])), [])
.filter(([, a]) => added.includes(a));
t.deepEqual(process.env.CI_LOG ? dupes : [], []);
expect(dupes).toEqual([]);
});
});
describe('added urls', (): void => {
it('has no entries for allowed top-level domains', (): void => {
const invalids = all.deny.filter((u) =>
TOP_LEVEL.some((t) =>
t.startsWith('*.')
? (u.endsWith(t.substring(1)) || u === t.substring(2))
: u === t
)
);
expect(invalids).toEqual([]);
});
it('has no malformed domain-only entries', (): void => {
const invalids = all.deny.filter((u) =>
u.includes('/') || // don't allow paths
u.includes('?') || // don't allow query params
u.includes(' ') || // no spaces
!u.includes('.') // need at least a domain
);
expect(invalids).toEqual([]);
});
it('has no urls starting with www. (domain-only inclusions)', (): void => {
const invalids = all.deny.filter((u) =>
u.startsWith('www.')
);
expect(invalids).toEqual([]);
});
it('has no duplicate entries', (): void => {
const checks: string[] = [];
const dupes = all.deny.reduce<string[]>((dupes, url) => {
if (!checks.includes(url)) {
checks.push(url);
} else {
dupes.push(url);
}
return dupes;
}, []);
expect(
process.env.CI_LOG
? []
: dupes
).toEqual([]);
});
});
+37 -34
View File
@@ -1,7 +1,6 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import test from 'ava';
import fs from 'fs';
import { decodeAddress } from '@polkadot/util-crypto';
@@ -158,42 +157,46 @@ function checkAll (): Promise<[string, string[]][]> {
]);
}
test('CI: has all known addresses', async (t): Promise<void> => {
t.timeout(2 * 60 * 1000);
const _results = await checkAll();
const results = _results.map(([url, addrs]): [string, string[]] => {
return [url, addrs.filter((a) => {
try {
return decodeAddress(a).length === 32;
} catch (error) {
console.error(url, (error as Error).message);
return false;
}
})];
describe('addrcheck', (): void => {
beforeAll((): void => {
jest.setTimeout(2 * 60 * 1000);
});
const all = Object.values(ourAddrList).reduce((all: string[], addrs: string[]): string[] => {
all.push(...addrs);
return all;
}, []);
const listEmpty = results.filter(([, found]) => !found.length).map(([site]) => site);
const mapFound = results.filter(([, found]) => found.length).reduce((all, [site, found]) => ({ ...all, [site]: found }), {});
const mapMiss = results
.map(([site, found]): [string, string[]] => [site, found.filter((a) => !all.includes(a))])
.filter(([, found]) => found.length)
.reduce((all: Record<string, string[]>, [site, found]) => ({
...all,
[site]: (all[site] || []).concat(found)
}), {});
const sites = Object.keys(mapMiss);
it('has all known addresses', async (): Promise<void> => {
const _results = await checkAll();
const results = _results.map(([url, addrs]): [string, string[]] => {
return [url, addrs.filter((a) => {
try {
return decodeAddress(a).length === 32;
} catch (error) {
console.error(url, (error as Error).message);
console.log('Sites with no results\n', JSON.stringify(listEmpty, null, 2));
console.log('Addresses found\n', JSON.stringify(mapFound, null, 2));
console.log('Addresses missing\n', JSON.stringify(mapMiss, null, 2));
return false;
}
})];
});
const all = Object.values(ourAddrList).reduce((all: string[], addrs: string[]): string[] => {
all.push(...addrs);
sites.length && process.env.CI_LOG && fs.appendFileSync('./.github/addrcheck.md', `\n\n${sites.length} urls with missing entries found at ${new Date().toUTCString()}:\n\n${TICKS}\n${JSON.stringify(mapMiss, null, 2)}\n${TICKS}\n`);
return all;
}, []);
const listEmpty = results.filter(([, found]) => !found.length).map(([site]) => site);
const mapFound = results.filter(([, found]) => found.length).reduce((all, [site, found]) => ({ ...all, [site]: found }), {});
const mapMiss = results
.map(([site, found]): [string, string[]] => [site, found.filter((a) => !all.includes(a))])
.filter(([, found]) => found.length)
.reduce((all: Record<string, string[]>, [site, found]) => ({
...all,
[site]: (all[site] || []).concat(found)
}), {});
const sites = Object.keys(mapMiss);
t.deepEqual(sites, []);
console.log('Sites with no results\n', JSON.stringify(listEmpty, null, 2));
console.log('Addresses found\n', JSON.stringify(mapFound, null, 2));
console.log('Addresses missing\n', JSON.stringify(mapMiss, null, 2));
sites.length && process.env.CI_LOG && fs.appendFileSync('./.github/addrcheck.md', `\n\n${sites.length} urls with missing entries found at ${new Date().toUTCString()}:\n\n${TICKS}\n${JSON.stringify(mapMiss, null, 2)}\n${TICKS}\n`);
expect(sites).toEqual([]);
});
});
@@ -1,24 +0,0 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import test from 'ava';
import { checkAddress } from '.';
test('returns null if the address is not found', async (t): Promise<void> => {
t.true(
await checkAddress('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY') === null
);
});
test('returns the site when the address is found', async (t): Promise<void> => {
t.true(
await checkAddress('14Vxs7UB9FqfQ53wwTJUBAJThs5N7b3bg89HscRU6eBqrFhQ') === 'polkadot.center'
);
});
test('returns the site even if the ss58 is different', async (t): Promise<void> => {
t.true(
await checkAddress('5FkmzcdNekhdSA7j4teSSyHGUnKT8bzNBFvVVeZSGmbSpYHH') === 'polkadots.network'
);
});
@@ -1,48 +0,0 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import test from 'ava';
import { checkIfDenied } from '.';
test('returns false when host is not listed', async (t): Promise<void> => {
t.false(
await checkIfDenied('polkadot.network')
);
});
test('returns false when host is not listed (with protocol)', async (t): Promise<void> => {
t.false(
await checkIfDenied('https://polkadot.network')
);
});
test('returns true when host in list', async (t): Promise<void> => {
t.true(
await checkIfDenied('polkawallets.site')
);
});
test('returns true when host in list (www-prefix)', async (t): Promise<void> => {
t.true(
await checkIfDenied('www.polkadotfund.com')
);
});
test('returns true when host in list (protocol)', async (t): Promise<void> => {
t.true(
await checkIfDenied('https://polkawallets.site')
);
});
test('returns true when host in list (protocol + path)', async (t): Promise<void> => {
t.true(
await checkIfDenied('https://polkawallets.site/something/index.html')
);
});
test('returns true in list (protocol + path + #)', async (t): Promise<void> => {
t.true(
await checkIfDenied('https://robonomics-network-xrt.cyberfi-tech-rewards-programs-claims-erc20-token.com/myetherwallet/access-my-wallet/#/input-privatekey-mnemonic-phrase-claim-bonus')
);
});
+33 -32
View File
@@ -1,7 +1,6 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import test from 'ava';
import fs from 'fs';
import { load as yamlParse } from 'js-yaml';
@@ -25,8 +24,9 @@ const TICKS = '```';
const ourSiteList = JSON.parse(fs.readFileSync('all.json', 'utf-8')) as { allow: string[]; deny: string[] };
function log (check: boolean, site: string, missing: unknown): void {
!check && process.env.CI_LOG && fs.appendFileSync('./.github/crosscheck.md', `
function assertAndLog (check: boolean, site: string, missing: unknown): void {
if (!check) {
process.env.CI_LOG && fs.appendFileSync('./.github/crosscheck.md', `
Missing entries found from ${site}:
@@ -34,6 +34,9 @@ ${TICKS}
${JSON.stringify(missing, null, 2)}
${TICKS}
`);
throw new Error(site);
}
}
function matchName (_url: string): boolean {
@@ -45,39 +48,37 @@ function matchName (_url: string): boolean {
const CRYPTODB = 'https://raw.githubusercontent.com/CryptoScamDB/blacklist/master/data/urls.yaml';
const ETHPHISH = 'https://raw.githubusercontent.com/MetaMask/eth-phishing-detect/master/src/config.json';
const ours: string[] = ourSiteList.deny;
describe('crosscheck', (): void => {
const ours: string[] = ourSiteList.deny;
test('CI: has all the relevant entries from CryptoScamDb', async (t): Promise<void> => {
t.timeout(120000);
beforeAll((): void => {
jest.setTimeout(120000);
});
const raw = await fetch(CRYPTODB).then((r) => r.text());
it('has all the relevant entries from CryptoScamDb', async (): Promise<void> => {
const raw = await fetch(CRYPTODB).then((r) => r.text());
// this is a hack, the text slipped in upstream
const scamDb = yamlParse(raw.replace('∂ç', '')) as CryptoScamEntry[];
const filtered = scamDb.filter(({ name, subcategory }) => matchName(subcategory) || matchName(name));
const missing = filtered.filter(({ url }) =>
!ours.includes(url.replace(/https:\/\/|http:\/\//, '').split('/')[0])
);
// this is a hack, the text slipped in upstream
const scamDb = yamlParse(raw.replace('∂ç', '')) as CryptoScamEntry[];
const filtered = scamDb.filter(({ name, subcategory }) => matchName(subcategory) || matchName(name));
const missing = filtered.filter(({ url }) =>
!ours.includes(url.replace(/https:\/\/|http:\/\//, '').split('/')[0])
);
// console.log('CryptoScamDb found\n', JSON.stringify(filtered, null, 2));
// console.log('CryptoScamDb missing\n', JSON.stringify(missing, null, 2));
console.log('CryptoScamDb found\n', JSON.stringify(filtered, null, 2));
console.log('CryptoScamDb missing\n', JSON.stringify(missing, null, 2));
log(missing.length === 0, 'CryptoScamDB', missing);
assertAndLog(missing.length === 0, 'CryptoScamDB', missing);
});
t.true(missing.length === 0);
});
test('CI: has polkadot/kusama entries from eth-phishing-detect', async (t): Promise<void> => {
t.timeout(120000);
const ethDb = await fetch(ETHPHISH).then<EthPhishing>((r) => r.json());
const filtered = ethDb.blacklist.filter((url) => matchName(url));
const missing = filtered.filter((url) => !ours.includes(url));
// console.log('eth-phishing-detect found\n', JSON.stringify(filtered, null, 2));
// console.log('eth-phishing-detect missing\n', JSON.stringify(missing, null, 2));
log(missing.length === 0, 'eth-phishing-detect', missing);
t.true(missing.length === 0);
it('has polkadot/kusama entries from eth-phishing-detect', async (): Promise<void> => {
const ethDb = await fetch(ETHPHISH).then<EthPhishing>((r) => r.json());
const filtered = ethDb.blacklist.filter((url) => matchName(url));
const missing = filtered.filter((url) => !ours.includes(url));
console.log('eth-phishing-detect found\n', JSON.stringify(filtered, null, 2));
console.log('eth-phishing-detect missing\n', JSON.stringify(missing, null, 2));
assertAndLog(missing.length === 0, 'eth-phishing-detect', missing);
});
});
+70
View File
@@ -0,0 +1,70 @@
// Copyright 2020-2022 @polkadot/phishing authors & contributors
// SPDX-License-Identifier: Apache-2.0
import { checkAddress, checkIfDenied } from '.';
// *sigh* Jest breaks yet again...
describe('checkIfDenied', (): void => {
it('returns false when host is not listed', async (): Promise<void> => {
expect(
await checkIfDenied('polkadot.network')
).toEqual(false);
});
it('returns false when host is not listed (with protocol)', async (): Promise<void> => {
expect(
await checkIfDenied('https://polkadot.network')
).toEqual(false);
});
it('returns true when host in list', async (): Promise<void> => {
expect(
await checkIfDenied('polkawallets.site')
).toEqual(true);
});
it('returns true when host in list (www-prefix)', async (): Promise<void> => {
expect(
await checkIfDenied('www.polkadotfund.com')
).toEqual(true);
});
it('returns true when host in list (protocol)', async (): Promise<void> => {
expect(
await checkIfDenied('https://polkawallets.site')
).toEqual(true);
});
it('returns true when host in list (protocol + path)', async (): Promise<void> => {
expect(
await checkIfDenied('https://polkawallets.site/something/index.html')
).toEqual(true);
});
it('returns true in list (protocol + path + #)', async (): Promise<void> => {
expect(
await checkIfDenied('https://robonomics-network-xrt.cyberfi-tech-rewards-programs-claims-erc20-token.com/myetherwallet/access-my-wallet/#/input-privatekey-mnemonic-phrase-claim-bonus')
).toEqual(true);
});
});
describe('checkAddress', (): void => {
it('returns null if the address is not found', async (): Promise<void> => {
expect(
await checkAddress('5GNJqTPyNqANBkUVMN1LPPrxXnFouWXoe2wNSmmEoLctxiZY')
).toEqual(null);
});
it('returns the site when the address is found', async (): Promise<void> => {
expect(
await checkAddress('14Vxs7UB9FqfQ53wwTJUBAJThs5N7b3bg89HscRU6eBqrFhQ')
).toEqual('polkadot.center');
});
it('returns the site even if the ss58 is different', async (): Promise<void> => {
expect(
await checkAddress('5FkmzcdNekhdSA7j4teSSyHGUnKT8bzNBFvVVeZSGmbSpYHH')
).toEqual('polkadots.network');
});
});
+22 -843
View File
File diff suppressed because it is too large Load Diff