feat: support for bzz.link cids when downloading files (#350)

* feat: detect and extract bzz.link cids into hash when downloading files

* test: add quite thorough testsuite
This commit is contained in:
Vojtech Simetka
2022-04-25 20:38:36 +05:00
committed by GitHub
parent a67be7a31e
commit 3784b29f14
4 changed files with 176 additions and 18 deletions
+138
View File
@@ -0,0 +1,138 @@
import { extractSwarmHash, extractSwarmCid, recognizeSwarmHash } from './index'
interface TestObject {
input: string
expectedOutput: string | undefined
}
const correctHashes: TestObject[] = [
// non-encrypted
{
input: 'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
expectedOutput: 'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input: 'http://gateway.org/bzz/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
expectedOutput: 'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input: 'https://gateway.org/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
expectedOutput: 'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input: 'http://gateway.org/bzz/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f/',
expectedOutput: 'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input: 'https://gateway.org/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f/',
expectedOutput: 'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
// encrypted
{
input:
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
expectedOutput:
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input:
'http://gateway.org/bzz/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
expectedOutput:
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input:
'https://gateway.org/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
expectedOutput:
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input:
'http://gateway.org/bzz/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f/',
expectedOutput:
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
{
input:
'https://gateway.org/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f/',
expectedOutput:
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fb7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3f',
},
]
const wrongHashes: string[] = [
// one character too long
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fa',
'http://gateway.org/bzz/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fa',
'https://gateway.org/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fa',
'http://gateway.org/bzz/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fa/',
'https://gateway.org/b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d3fa/',
// a bit shorter
'b7e53783114e4555384d7fd7154eb8c2e3f7c749c176dcb8f4015b08161b3d',
]
describe('extractSwarmHash', () => {
test('should correctly extract hash', () => {
correctHashes.forEach(({ input, expectedOutput }) => {
const hash = extractSwarmHash(input)
expect(hash).toBe(expectedOutput)
})
})
test('should not extract hash from incorrect inputs', () => {
wrongHashes.forEach(input => {
const hash = extractSwarmHash(input)
expect(hash).toBe(undefined)
})
})
})
const correctCids: TestObject[] = [
{
input: 'https://bah5acgza5afd34lfvo7sowxfjahj4ujeduxgg2ge5u3zo4kcjlzjzi23fhka.bzz.link',
expectedOutput: 'e80a3df165abbf275ae5480e9e51241d2e6368c4ed379771424af29ca35b29d4',
},
{
input: 'https://bah5acgza2lzgtqfztvn3xtnzhv7qvbmblljd7bi52l5jiueretcad55vookq.bzz.link',
expectedOutput: 'd2f269c0b99d5bbbcdb93d7f0a85815ad23f851dd2fa94509124c401f7b57395',
},
]
const wrongCids: string[] = [
'https://bah5acgza5afd34lfvo7sowxfjahj4ujeduxgg2ge5u3zo4kcjlzjzi23fhka.another.domain',
'http://bah5acgza2lzgtqfztvn3xtnzhv7qvbmblljd7bi52l5jiueretcad55vookq.bzz.link',
'https://not_cid.bzz.link',
'https://bah5acgza5afd34lfvo7sowxfjahj4ujeduxgg2ge5u3zo4kcjlzjzi23fhka.subdomain.bzz.link',
'https://bah5acgza5afd34lfvo7sowxfjahj4ujeduxgg2ge5u3zo4kcjlzjzi23fhka.subdomain.bzz.link',
'https://bah5acgza2lzgtqfztvn3xtnzhv7qvbmblljd7bi52l5jiueretcad55vook.bzz.link',
'https://aah5acgza2lzgtqfztvn3xtnzhv7qvbmblljd7bi52l5jiueretcad55vookq.bzz.link',
]
describe('extractSwarmCid', () => {
test('should correctly extract hash', () => {
correctCids.forEach(({ input, expectedOutput }) => {
const hash = extractSwarmCid(input)
expect(hash).toBe(expectedOutput)
})
})
test('should not extract cid from incorrect urls', () => {
wrongCids.forEach(url => {
const hash = extractSwarmCid(url)
expect(hash).toBe(undefined)
})
})
})
describe('recognizeSwarmHash', () => {
test('should correctly extract hash', () => {
;[...correctHashes, ...correctCids].forEach(({ input, expectedOutput }) => {
const hash = recognizeSwarmHash(input)
expect(hash).toBe(expectedOutput)
})
})
test('should not extract hash from incorrect inputs but instead return them', () => {
;[...wrongHashes, ...wrongCids].forEach(url => {
const hash = recognizeSwarmHash(url)
expect(hash).toBe(url)
})
})
})
+36 -3
View File
@@ -1,5 +1,7 @@
import { BigNumber } from 'bignumber.js'
import { Token } from '../models/Token'
import { decodeCid } from '@ethersphere/swarm-cid'
import { BZZ_LINK_DOMAIN } from '../constants'
/**
* Test if value is an integer
@@ -108,10 +110,41 @@ export function makeRetriablePromise<T>(fn: () => Promise<T>, maxRetries = 3, de
})
}
export function extractSwarmHash(string: string): string | null {
const matches = string.match(/[a-fA-F0-9]{64,128}/)
// Matches exactly 64 or 128 caracters alphanumeric characters that are surrounded by non-alpha num characters
const regexpMatchHash = /(?:^|[^a-f0-9]+)([a-f0-9]{64}|[a-f0-9]{128})(?:$|[^a-f0-9]+)/i
return (matches && matches[0]) || null
export function extractSwarmHash(string: string): string | undefined {
const matches = string.match(regexpMatchHash)
return (matches && matches[1]) || undefined
}
// Matches the CID from bzz-link subdomain
const regexpMatchCID = new RegExp(`https://(bah5acgza[a-z0-9]{52})\\.${BZZ_LINK_DOMAIN}`, 'i')
export function extractSwarmCid(s: string): string | undefined {
const matches = s.match(regexpMatchCID)
if (!matches || !matches[1]) {
return
}
const cid = matches[1]
try {
const decodeResult = decodeCid(cid)
if (!decodeResult.type) {
return
}
return decodeResult.reference
} catch (e) {
return
}
}
export function recognizeSwarmHash(value: string): string {
return extractSwarmHash(value) || extractSwarmCid(value) || value
}
export function uuidV4(): string {