Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

update contents util #104

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ensdomains/ensjs",
"version": "2.1.0",
"version": "2.2.0",
"description": "ens.js v2",
"main": "dist/index.js",
"repository": "ensdomains/ensjs",
Expand Down Expand Up @@ -41,17 +41,20 @@
"esm": "^3.2.22",
"ganache-cli": "^6.4.3",
"ganache-core": "^2.11.3",
"jest": "^26.4.2",
"jest": "^27.5.1",
"web3": "^1.7.0"
},
"dependencies": {
"@babel/runtime": "^7.4.4",
"@ensdomains/address-encoder": "^0.1.7",
"@ensdomains/content-hash": "^2.5.7",
"@ensdomains/ens": "0.4.5",
"@ensdomains/eth-ens-namehash": "^2.0.15",
"@ensdomains/resolver": "0.2.4",
"content-hash": "^2.5.2",
"eth-ens-namehash": "^2.0.8",
"ethers": "^5.0.13",
"js-sha3": "^0.8.0"
},
"jest": {
"setupFilesAfterEnv": ["<rootDir>/setup-jest.js"]
}
}
3 changes: 3 additions & 0 deletions setup-jest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { TextEncoder, TextDecoder } from 'util';
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
2 changes: 1 addition & 1 deletion src/__tests__/ens.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ describe('Blockchain tests', () => {
const content = await ens.name('abittooawesome.eth').getContent()
expect(content.contentType).toBe('contenthash')
expect(content.value).toBe(
'ipfs://QmTeW79w7QQ6Npa3b1d5tANreCDxF2iDaAPsDvW6KtLmfB'
'ipfs://bafybeico3uuyj3vphxpvbowchdwjlrlrh62awxscrnii7w7flu5z6fk77y'
)
})

Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ async function setContenthashWithResolver({
}) {
let encodedContenthash = content
if (parseInt(content, 16) !== 0) {
encodedContenthash = encodeContenthash(content)
const { encoded } = encodeContenthash(content)
encodedContenthash = encoded
}
const Resolver = getResolverContract({
address: resolverAddr,
Expand Down
95 changes: 61 additions & 34 deletions src/utils/contents.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
import contentHash from 'content-hash'
import { ethers } from 'ethers'
import bs58 from 'bs58'
const supportedCodecs = ['ipns-ns', 'ipfs-ns', 'swarm-ns', 'onion', 'onion3']
import contentHash from '@ensdomains/content-hash'
import { utils } from 'ethers'
const supportedCodecs = ['ipns-ns', 'ipfs-ns', 'swarm-ns', 'onion', 'onion3', 'skynet-ns', 'arweave-ns']

const utils = ethers.utils
function matchProtocol(text){
return text.match(/^(ipfs|sia|ipns|bzz|onion|onion3|arweave|ar):\/\/(.*)/)
|| text.match(/\/(ipfs)\/(.*)/)
|| text.match(/\/(ipns)\/(.*)/)
}

export function decodeContenthash(encoded) {
let decoded, protocolType, error
if(!encoded || encoded === '0x'){
return {}
}
if (encoded.error) {
return { protocolType: null, decoded: encoded.error }
}else if(encoded === false){
return { protocolType: null, decoded: 'invalid value' }
}
if (encoded) {
try {
decoded = contentHash.decode(encoded)
const codec = contentHash.getCodec(encoded)
if (codec === 'ipfs-ns') {
if (codec === 'ipfs-ns') {
protocolType = 'ipfs'
} else if (codec === 'ipns-ns') {
decoded = bs58.decode(decoded).slice(2).toString()
protocolType = 'ipns'
} else if (codec === 'swarm-ns') {
protocolType = 'bzz'
} else if (codec === 'onion') {
protocolType = 'onion'
} else if (codec === 'onion3') {
protocolType = 'onion3'
} else if (codec === 'skynet-ns') {
protocolType = 'sia'
} else if (codec === 'arweave-ns') {
protocolType = 'ar'
} else {
decoded = encoded
}
Expand All @@ -35,11 +46,8 @@ export function decodeContenthash(encoded) {
return { protocolType, decoded, error }
}

export function validateContent(encoded) {
return (
contentHash.isHashOfType(encoded, contentHash.Types.ipfs) ||
contentHash.isHashOfType(encoded, contentHash.Types.swarm)
)
export function validateContent(encoded){
return contentHash.isHashOfType(encoded, contentHash.Types.ipfs) || contentHash.isHashOfType(encoded, contentHash.Types.swarm)
}

export function isValidContenthash(encoded) {
Expand All @@ -51,53 +59,72 @@ export function isValidContenthash(encoded) {
}
}

export function getProtocolType(encoded) {
let protocolType, decoded
try {
let matched = matchProtocol(encoded)
if (matched) {
protocolType = matched[1]
decoded = matched[2]
}
return {
protocolType,
decoded
}
} catch (e) {
console.log(e)
}
}

export function encodeContenthash(text) {
let content, contentType
let encoded = false
let error
if (!!text) {
let matched =
text.match(/^(ipfs|ipns|bzz|onion|onion3):\/\/(.*)/) ||
text.match(/\/(ipfs)\/(.*)/) ||
text.match(/\/(ipns)\/(.*)/)
let matched = matchProtocol(text)
if (matched) {
contentType = matched[1]
content = matched[2]
}
try {
if (contentType === 'ipfs') {
if (content.length >= 4) {
encoded = '0x' + contentHash.encode('ipfs-ns', content)
if(content.length >= 4) {
encoded = '0x' + contentHash.encode('ipfs-ns', content);
}
} else if (contentType === 'ipns') {
let bs58content = bs58.encode(
Buffer.concat([
Buffer.from([0, content.length]),
Buffer.from(content),
])
)
encoded = '0x' + contentHash.encode('ipns-ns', bs58content)
encoded = '0x' + contentHash.encode('ipns-ns', content);
} else if (contentType === 'bzz') {
if (content.length >= 4) {
if(content.length >= 4) {
encoded = '0x' + contentHash.fromSwarm(content)
}
} else if (contentType === 'onion') {
if (content.length == 16) {
encoded = '0x' + contentHash.encode('onion', content)
}
if(content.length == 16) {
encoded = '0x' + contentHash.encode('onion', content);
}
} else if (contentType === 'onion3') {
if (content.length == 56) {
encoded = '0x' + contentHash.encode('onion3', content)
if(content.length == 56) {
encoded = '0x' + contentHash.encode('onion3', content);
}
} else if (contentType === 'sia'){
if(content.length == 46) {
encoded = '0x' + contentHash.encode('skynet-ns', content);
}
} else if (contentType === 'arweave' || contentType === 'ar'){
if(content.length == 43) {
encoded = '0x' + contentHash.encode('arweave-ns', content);
}
} else {
console.warn('Unsupported protocol or invalid value', {
contentType,
text,
text
})
}
} catch (err) {
console.warn('Error encoding content hash', { text, encoded })
const errorMessage = 'Error encoding content hash'
console.warn(errorMessage, { text, encoded })
error = errorMessage
//throw 'Error encoding content hash'
}
}
return encoded
return { encoded, error }
}
71 changes: 65 additions & 6 deletions src/utils/contents.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
describe('test contenthash utility functions for swarm', () => {
describe('encodeContentHash', () => {
test('encodeContentHash returns encoded hash for swarm protocol', () => {
const encodedContentHash = encodeContenthash(
const { encoded:encodedContentHash } = encodeContenthash(
'bzz://d1de9994b4d039f6548d191eb26786769f580809256b4685ef316805265ea162'
)

Expand All @@ -17,7 +17,7 @@ describe('test contenthash utility functions for swarm', () => {
})

test('encodeContentHash returns encoded hash for ipfs protocol', () => {
const encodedContentHash = encodeContenthash(
const { encoded:encodedContentHash } = encodeContenthash(
'ipfs://QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL'
)

Expand All @@ -27,7 +27,7 @@ describe('test contenthash utility functions for swarm', () => {
})

test('encodeContentHash returns encoded hash for ipfs protocol with /ipfs/ format', () => {
const encodedContentHash = encodeContenthash(
const { encoded:encodedContentHash } = encodeContenthash(
'/ipfs/QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL'
)

Expand All @@ -37,20 +37,48 @@ describe('test contenthash utility functions for swarm', () => {
})

test('encodeContentHash returns encoded hash for onion protocol', () => {
const encodedContentHash = encodeContenthash('onion://3g2upl4pq6kufc4m')
const { encoded:encodedContentHash } = encodeContenthash('onion://3g2upl4pq6kufc4m')

expect(encodedContentHash).toBe('0xbc0333673275706c347071366b756663346d')
})

test('encodeContentHash returns encoded hash for onion 3 protocol', () => {
const encodedContentHash = encodeContenthash(
const { encoded:encodedContentHash } = encodeContenthash(
'onion3://p53lf57qovyuvwsc6xnrppyply3vtqm7l6pcobkmyqsiofyeznfu5uqd'
)

expect(encodedContentHash).toBe(
'0xbd037035336c663537716f7679757677736336786e72707079706c79337674716d376c3670636f626b6d797173696f6679657a6e667535757164'
)
})

test('encodeContentHash returns encoded hash for sia skynet protocol', () => {
const { encoded:encodedContentHash } = encodeContenthash(
'sia://CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg'
)

expect(encodedContentHash).toBe(
'0x90b2c60508004007fd43b74149b31aacbbf2784e874d09b086bed15fd54cacff7120cce95372'
)
})
test('encodeContentHash returns encoded hash for arweave protocol (backward compatibility to arweave://)', () => {
const { encoded:encodedContentHash } = encodeContenthash(
'arweave://ys32Pt8uC7TrVxHdOLByOspfPEq2LO63wREHQIM9SJQ'
)

expect(encodedContentHash).toBe(
'0x90b2ca05cacdf63edf2e0bb4eb5711dd38b0723aca5f3c4ab62ceeb7c1110740833d4894'
)
})
test('encodeContentHash returns encoded hash for arweave protocol', () => {
const { encoded:encodedContentHash } = encodeContenthash(
'ar://ys32Pt8uC7TrVxHdOLByOspfPEq2LO63wREHQIM9SJQ'
)

expect(encodedContentHash).toBe(
'0x90b2ca05cacdf63edf2e0bb4eb5711dd38b0723aca5f3c4ab62ceeb7c1110740833d4894'
)
})
})

describe('decodeContentHash', () => {
Expand All @@ -72,7 +100,7 @@ describe('test contenthash utility functions for swarm', () => {
)

expect(decoded.decoded).toBe(
'QmaEBknbGT4bTQiQoe2VNgBJbRfygQGktnaW5TbuKixjYL'
'bafybeifqurebcya65zrw4b4idhozkx2tbxwtedl4rn7etc7abfmbapocne' // same hash but in cid v1 base32
)
expect(decoded.protocolType).toBe('ipfs')
expect(decoded.error).toBe(undefined)
Expand All @@ -99,6 +127,29 @@ describe('test contenthash utility functions for swarm', () => {
expect(decoded.protocolType).toBe('onion3')
expect(decoded.error).toBe(undefined)
})

test('decodeContentHash returns decoded contenthash for sia skynet protocol', () => {
const decoded = decodeContenthash(
'0x90b2c60508004007fd43b74149b31aacbbf2784e874d09b086bed15fd54cacff7120cce95372'
)

expect(decoded.decoded).toBe(
'CABAB_1Dt0FJsxqsu_J4TodNCbCGvtFf1Uys_3EgzOlTcg'
)
expect(decoded.protocolType).toBe('sia')
expect(decoded.error).toBe(undefined)
})
test('decodeContentHash returns decoded contenthash for arweave protocol', () => {
const decoded = decodeContenthash(
'0x90b2ca05cacdf63edf2e0bb4eb5711dd38b0723aca5f3c4ab62ceeb7c1110740833d4894'
)

expect(decoded.decoded).toBe(
'ys32Pt8uC7TrVxHdOLByOspfPEq2LO63wREHQIM9SJQ'
)
expect(decoded.protocolType).toBe('ar')
expect(decoded.error).toBe(undefined)
})
})

describe('isValidContent', () => {
Expand Down Expand Up @@ -132,6 +183,14 @@ describe('test contenthash utility functions for swarm', () => {
expect(valid).toBe(true)
})

test('isValidContent returns true for real contenthash for sia skynet', () => {
const valid = isValidContenthash(
'0x90b2c60508004007fd43b74149b31aacbbf2784e874d09b086bed15fd54cacff7120cce95372'
)

expect(valid).toBe(true)
})

test('isValidContent returns false for non hex', () => {
const valid = isValidContenthash(
'0xe40101fa011b20d1de9994b4d039f6548d191eb26786769f580809256b4685ef31680z'
Expand Down
2 changes: 1 addition & 1 deletion src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
decodeContenthash,
isValidContenthash,
} from './contents'
import { normalize } from 'eth-ens-namehash'
import { normalize } from '@ensdomains/eth-ens-namehash'
import { namehash } from './namehash'

//import { checkLabelHash } from '../updaters/preImageDB'
Expand Down
2 changes: 1 addition & 1 deletion src/utils/labelhash.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const sha3 = require('js-sha3').keccak_256
import { normalize } from 'eth-ens-namehash'
import { normalize } from '@ensdomains/eth-ens-namehash'

export function encodeLabelhash(hash) {
if (!hash.startsWith('0x')) {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/namehash.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { isEncodedLabelhash, decodeLabelhash } from './labelhash'
import { normalize } from 'eth-ens-namehash'
import { normalize } from '@ensdomains/eth-ens-namehash'
const sha3 = require('js-sha3').keccak_256

export function namehash(inputName) {
Expand Down
Loading