Skip to content

Commit

Permalink
Add test fot prepare url
Browse files Browse the repository at this point in the history
  • Loading branch information
yariksav committed Jul 26, 2024
1 parent c54f692 commit 77a5c55
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 34 deletions.
9 changes: 8 additions & 1 deletion block-explorer-indexer/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
// You can add other configurations here as needed
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/libs/$1',
},
};

process.env = Object.assign(process.env, {
DEBUG: process.env.DEBUG || 'rootscan:*',
__JEST__: process.env.__JEST__ || true,
});
1 change: 1 addition & 0 deletions block-explorer-indexer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"express-session": "^1.18.0",
"helmet": "^7.1.0",
"ioredis": "^5.3.2",
"is-url": "^1.2.4",
"lodash": "^4.17.21",
"lru-cache": "^11.0.0",
"moment": "^2.30.1",
Expand Down
8 changes: 8 additions & 0 deletions block-explorer-indexer/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

32 changes: 5 additions & 27 deletions block-explorer-indexer/src/libs/nft-indexer/nft-token-data.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import ABIs from '@/constants/abi';
import { ethereumClient } from '@/rpc';
import { INftOwner, TNftTokenType } from '@/types';
import { prepareTokenMetadataUrl } from '@/utils/url-utils';
import { noop } from 'lodash';
import pLimit from 'p-limit';
import { Address, PublicClient, getAddress } from 'viem';

const limiter = pLimit(100);
const skipDomains = ['example.com', 'localhost'];
const skipDomainsRegex = new RegExp(skipDomains.map((domain) => `(${domain})`).join('|'), 'i');
const containsIpWithPortRegex = /(https?:\/\/)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(:\d+)?\/?[\w\\/.-]*\b/;
const isUrlCorrectRegex =
/(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/;

interface TokenMetadata {
image: string;
Expand Down Expand Up @@ -97,35 +93,17 @@ export class NftTokenData {
})
.catch(noop);
}
return prepareUrl(data);
console.log(data);
return prepareTokenMetadataUrl(data);
}

async fillNftsMetadata(nfts: INftOwner[]) {
const metadatas = await this.getBulkTokenMetadata(nfts);
nfts.forEach((nft, index) => {
nft.attributes = metadatas[index]?.attributes;
nft.image = prepareUrl(metadatas[index]?.image);
nft.animation_url = prepareUrl(metadatas[index]?.animation_url);
nft.image = prepareTokenMetadataUrl(metadatas[index]?.image);
nft.animation_url = prepareTokenMetadataUrl(metadatas[index]?.animation_url);
nft._metadataProcessed = nft.image ? true : undefined;
});
}
}

function prepareUrl(link: string | undefined): string | undefined {
if (!link) {
return;
}
link = link.trim();

if (link.toLowerCase().startsWith('ipfs://')) {
// See https://docs.ipfs.tech/quickstart/retrieve/#fetching-the-cid-with-an-ipfs-gateway
return link.replace(/^ipfs:\/\//i, 'https://ipfs.io/ipfs/');
}
if (!link.includes('://')) {
return `https://${link}`;
}
if (!isUrlCorrectRegex.test(link) || containsIpWithPortRegex.test(link) || skipDomainsRegex.test(link)) {
return;
}
return link;
}
49 changes: 49 additions & 0 deletions block-explorer-indexer/src/libs/utils/url-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { prepareTokenMetadataUrl } from './url-utils';

describe('UrlUtils', () => {
test('prepareTokenMetadataUrl: incorrect urls should skip', () => {
const badUrls = [
'https://1',
'https://42',
'https://1024',
undefined,
null,
'',
'null',
'null0',
'test123',
'https://test123',
'1',
'test1',
'true',
'example.com',
'localhost',
'https://localhost/x',
'0.0.0.0',
'0.0.0',
'0.0',
'0',
'https://192.168.1.1:30333',
];
for (const url of badUrls) {
expect(prepareTokenMetadataUrl(url as string)).toBe(undefined);
}
});

test('prepareTokenMetadataUrl: correct urls', () => {
const correctUrls = [
'https://rns-metadata.fly.dev/mainnet/0x44640D662A423d738D5ebF8B51E57AfC0f2cf4Df/34568736216980230572277344339278661393462213082217059465217671489155940463826',
'https://www.projecttempus.xyz/api/51300/token/77',
];
for (const url of correctUrls) {
expect(prepareTokenMetadataUrl(url as string)).toBe(url);
}
expect(prepareTokenMetadataUrl('projecttempus.xyz/api/51300/token/77')).toBe(
'https://projecttempus.xyz/api/51300/token/77',
);
});

test('prepareTokenMetadataUrl: ipfs urls', () => {
expect(prepareTokenMetadataUrl('ipfs://test')).toBe('https://ipfs.io/ipfs/test');
});
});
24 changes: 24 additions & 0 deletions block-explorer-indexer/src/libs/utils/url-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import isUrl from 'is-url';

const skipDomains = ['example.com', 'localhost', '0.0.0'];

Check failure

Code scanning / CodeQL

Missing regular expression anchor High

When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it.
const skipDomainsRegex = new RegExp(skipDomains.map((domain) => `(${domain})`).join('|'), 'i');
const containsIpWithPortRegex = /(https?:\/\/)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(:\d+)?\/?[\w\\/.-]*\b/;

export function prepareTokenMetadataUrl(link: string | undefined): string | undefined {
if (!link) {
return;
}
link = link.trim();

if (link.toLowerCase().startsWith('ipfs://')) {
// See https://docs.ipfs.tech/quickstart/retrieve/#fetching-the-cid-with-an-ipfs-gateway
link = link.replace(/^ipfs:\/\//i, 'https://ipfs.io/ipfs/');
}
if (!link.includes('://')) {
link = `https://${link}`;
}
if (!isUrl(link) || containsIpWithPortRegex.test(link) || skipDomainsRegex.test(link)) {
return;
}
return link;
}

0 comments on commit 77a5c55

Please sign in to comment.