mirror of
https://github.com/pezkuwichain/phishing.git
synced 2026-06-12 15:51:03 +00:00
List of known phishing addresses (for use in wallets) (#57)
* Add list of known addresses * Sorted * Add polkadot.express * typo * Add checkAddress & tests * Update comments * Return error * U8a cache
This commit is contained in:
@@ -14,7 +14,9 @@
|
||||
"homepage": "https://github.com/polkadot-js/common/tree/master/packages/phishing#readme",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"@polkadot/x-fetch": "^5.3.1"
|
||||
"@polkadot/util": "^5.3.2-6",
|
||||
"@polkadot/util-crypto": "^5.3.2-6",
|
||||
"@polkadot/x-fetch": "^5.3.2-6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020-2021 @polkadot/phishing authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { checkIfDenied } from '.';
|
||||
import { checkAddress, checkIfDenied } from '.';
|
||||
|
||||
describe('checkIfDenied', (): void => {
|
||||
it('returns false when host in list', async (): Promise<void> => {
|
||||
@@ -40,3 +40,23 @@ describe('checkIfDenied', (): void => {
|
||||
).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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
// Copyright 2020-2021 @polkadot/phishing authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { HostList } from './types';
|
||||
import type { AddressList, HostList } from './types';
|
||||
|
||||
import { u8aEq } from '@polkadot/util';
|
||||
import { decodeAddress } from '@polkadot/util-crypto';
|
||||
import { fetch } from '@polkadot/x-fetch';
|
||||
|
||||
// Equivalent to https://raw.githubusercontent.com/polkadot-js/phishing/master/all.json
|
||||
// Equivalent to https://raw.githubusercontent.com/polkadot-js/phishing/master/{address,all}.json
|
||||
const ADDRESS_JSON = 'https://polkadot.js.org/phishing/address.json';
|
||||
const ALL_JSON = 'https://polkadot.js.org/phishing/all.json';
|
||||
// 1 hour cache refresh
|
||||
const CACHE_TIMEOUT = 1 * 60 * 60 * 1000;
|
||||
const CACHE_TIMEOUT = 45 * 60 * 1000;
|
||||
|
||||
let cacheEnd = 0;
|
||||
let cacheList: HostList | null = null;
|
||||
let cacheAddrEnd = 0;
|
||||
let cacheAddrList: AddressList | null = null;
|
||||
let cacheAddrU8a: [string, Uint8Array[]][] | null = null;
|
||||
let cacheHostEnd = 0;
|
||||
let cacheHostList: HostList | null = null;
|
||||
|
||||
// gets the host-only part for a host
|
||||
function extractHost (path: string): string {
|
||||
@@ -20,21 +26,56 @@ function extractHost (path: string): string {
|
||||
.split('/')[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of known phishing addresses
|
||||
*/
|
||||
export async function retrieveAddrList (allowCached = true): Promise<AddressList> {
|
||||
const now = Date.now();
|
||||
|
||||
if (allowCached && cacheAddrList && (now < cacheAddrEnd)) {
|
||||
return cacheAddrList;
|
||||
}
|
||||
|
||||
const response = await fetch(ADDRESS_JSON);
|
||||
const list = (await response.json()) as AddressList;
|
||||
|
||||
cacheAddrEnd = now + CACHE_TIMEOUT;
|
||||
cacheAddrList = list;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
async function retrieveAddrU8a (allowCached = true): Promise<[string, Uint8Array[]][]> {
|
||||
const now = Date.now();
|
||||
|
||||
if (allowCached && cacheAddrU8a && (now < cacheAddrEnd)) {
|
||||
return cacheAddrU8a;
|
||||
}
|
||||
|
||||
const all = await retrieveAddrList(allowCached);
|
||||
|
||||
cacheAddrU8a = Object
|
||||
.entries(all)
|
||||
.map(([key, addresses]): [string, Uint8Array[]] => [key, addresses.map((a) => decodeAddress(a))]);
|
||||
|
||||
return cacheAddrU8a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve allow/deny from our list provider
|
||||
*/
|
||||
export async function retrieveHostList (allowCached = true): Promise<HostList> {
|
||||
const now = Date.now();
|
||||
|
||||
if (allowCached && cacheList && (now < cacheEnd)) {
|
||||
return cacheList;
|
||||
if (allowCached && cacheHostList && (now < cacheHostEnd)) {
|
||||
return cacheHostList;
|
||||
}
|
||||
|
||||
const response = await fetch(ALL_JSON);
|
||||
const list = (await response.json()) as HostList;
|
||||
|
||||
cacheEnd = now + CACHE_TIMEOUT;
|
||||
cacheList = list;
|
||||
cacheHostEnd = now + CACHE_TIMEOUT;
|
||||
cacheHostList = list;
|
||||
|
||||
return list;
|
||||
}
|
||||
@@ -58,9 +99,28 @@ export function checkHost (items: string[], host: string): boolean {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a host is in our deny list. Returns a string containing the phishing site if host is a
|
||||
* problematic one. Returns null if the address is not associated with phishing.
|
||||
*/
|
||||
export async function checkAddress (address: string | Uint8Array, allowCached = true): Promise<string | null> {
|
||||
try {
|
||||
const all = await retrieveAddrU8a(allowCached);
|
||||
const u8a = decodeAddress(address);
|
||||
const entry = all.find(([, all]) => all.some((a) => u8aEq(a, u8a))) || [null];
|
||||
|
||||
return entry[0];
|
||||
} catch (error) {
|
||||
console.error('Exception while checking address, assuming non-phishing');
|
||||
console.error(error);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a host is in our deny list. Returns true if host is a problematic one. Returns
|
||||
* true if the host provided is in our list of less-than-honest sites.
|
||||
* false if the host provided is not in our list of less-than-honest sites.
|
||||
*/
|
||||
export async function checkIfDenied (host: string, allowCached = true): Promise<boolean> {
|
||||
try {
|
||||
@@ -68,7 +128,7 @@ export async function checkIfDenied (host: string, allowCached = true): Promise<
|
||||
|
||||
return checkHost(deny, host);
|
||||
} catch (error) {
|
||||
console.error('Exception while checking host, assuming false');
|
||||
console.error('Exception while checking host, assuming non-phishing');
|
||||
console.error(error);
|
||||
|
||||
return false;
|
||||
|
||||
@@ -5,3 +5,5 @@ export interface HostList {
|
||||
allow: string[];
|
||||
deny: string[];
|
||||
}
|
||||
|
||||
export type AddressList = Record<string, string[]>;
|
||||
|
||||
Reference in New Issue
Block a user