diff --git a/src/index.ts b/src/index.ts index 28de3ffe..eef1967f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,7 @@ * @author Robert McLeod <@robertdavid010> * @author Fabian Vogelsteller * @author Hugo Masclet <@Hugoo> + * @author Jean Cavallera <@CJ42> * @date 2020 */ @@ -30,12 +31,18 @@ import { convertIPFSGatewayUrl, generateSchemasFromDynamicKeys, duplicateMultiTypeERC725SchemaEntry, + getVerificationMethod, + isDataAuthentic, } from './lib/utils'; import { getSchema } from './lib/schemaParser'; import { isValidSignature } from './lib/isValidSignature'; -import { DEFAULT_GAS_VALUE } from './constants/constants'; +import { + DEFAULT_GAS_VALUE, + SUPPORTED_VERIFICATION_METHODS, + SUPPORTED_VERIFICATION_METHOD_STRINGS, +} from './constants/constants'; import { encodeKeyName, isDynamicKeyName } from './lib/encodeKeyName'; // Types @@ -87,7 +94,12 @@ export { }; export { ERC725Config, KeyValuePair, ProviderTypes } from './types'; -export { encodeData, encodeArrayKey } from './lib/utils'; +export { + encodeData, + encodeArrayKey, + getVerificationMethod, + isDataAuthentic, +} from './lib/utils'; export { decodeData } from './lib/decodeData'; export { encodeKeyName, isDynamicKeyName } from './lib/encodeKeyName'; export { decodeMappingKey } from './lib/decodeMappingKey'; @@ -684,27 +696,8 @@ export class ERC725 { return mapPermission(permission); } - encodeDataSourceWithHash( - verification: undefined | Verification, - dataSource: string, - ): string { - return encodeDataSourceWithHash(verification, dataSource); - } - - static encodeDataSourceWithHash( - verification: undefined | Verification, - dataSource: string, - ): string { - return encodeDataSourceWithHash(verification, dataSource); - } - - decodeDataSourceWithHash(value: string): URLDataWithHash { - return decodeDataSourceWithHash(value); - } - - static decodeDataSourceWithHash(value: string): URLDataWithHash { - return decodeDataSourceWithHash(value); - } + // Encoding methods + // ---------------- /** * @param type The valueType to encode the value as @@ -765,6 +758,65 @@ export class ERC725 { ): string | URLDataWithHash | number | boolean | null { return decodeValueContent(valueContent, value); } + + // External Data Source utilities (`VerifiableURI` and `JSONURI`) + // ---------------------------------------------------------------- + + encodeDataSourceWithHash( + verification: undefined | Verification, + dataSource: string, + ): string { + return encodeDataSourceWithHash(verification, dataSource); + } + + static encodeDataSourceWithHash( + verification: undefined | Verification, + dataSource: string, + ): string { + return encodeDataSourceWithHash(verification, dataSource); + } + + decodeDataSourceWithHash(value: string): URLDataWithHash { + return decodeDataSourceWithHash(value); + } + + static decodeDataSourceWithHash(value: string): URLDataWithHash { + return decodeDataSourceWithHash(value); + } + + static getVerificationMethod(nameOrSig: string): + | { + method: (data: string | object | Uint8Array | null) => string; + name: SUPPORTED_VERIFICATION_METHOD_STRINGS; + sig: SUPPORTED_VERIFICATION_METHODS; + } + | undefined { + return getVerificationMethod(nameOrSig); + } + + getVerificationMethod(nameOrSig: string): + | { + method: (data: string | object | Uint8Array | null) => string; + name: SUPPORTED_VERIFICATION_METHOD_STRINGS; + sig: SUPPORTED_VERIFICATION_METHODS; + } + | undefined { + return getVerificationMethod(nameOrSig); + } + + static isDataAuthentic( + data: string | Uint8Array, + verificationOptions: Verification, + ): boolean { + return isDataAuthentic(data, verificationOptions); + } + + isDataAuthentic( + data: string | Uint8Array, + verificationOptions: Verification, + ): boolean { + return isDataAuthentic(data, verificationOptions); + } } export default ERC725; diff --git a/src/lib/getDataFromExternalSources.test.ts b/src/lib/getDataFromExternalSources.test.ts index c8cd7659..b2d710e2 100644 --- a/src/lib/getDataFromExternalSources.test.ts +++ b/src/lib/getDataFromExternalSources.test.ts @@ -15,11 +15,13 @@ /* eslint-disable no-unused-expressions */ import { expect } from 'chai'; +import * as sinon from 'sinon'; import { ERC725JSONSchema } from '../types/ERC725JSONSchema'; import { getDataFromExternalSources } from './getDataFromExternalSources'; import { DecodeDataOutput } from '../types/decodeData'; +import { keccak256 } from 'web3-utils'; const IPFS_GATEWAY_MOCK = 'https://mock-ipfs.mock/ipfs/'; @@ -52,4 +54,51 @@ describe('getDataFromExternalSources', () => { ); }).to.not.throw(); }); + + it("should return the right data when the schema's valueContent is VerifiableURI", async () => { + const schema: ERC725JSONSchema = { + name: 'LSP3Profile', + key: '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', + keyType: 'Singleton', + valueType: 'bytes', + valueContent: 'VerifiableURI', + }; + + const jsonResult = { LSP3Profile: { name: 'Test', description: 'Cool' } }; + + const dataFromChain: DecodeDataOutput[] = [ + { + name: 'LSP3Profile', + key: '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', + value: { + verification: { + data: keccak256(JSON.stringify(jsonResult)), + method: 'keccak256(utf8)', + }, + url: 'ipfs://QmdMGUxuQsm1U9Qs8oJSn5PfY4B1apGG75YBRxQPybtRVm', + }, + }, + ]; + + const fetchStub = sinon.stub(global, 'fetch'); + try { + fetchStub.onCall(0).returns( + Promise.resolve( + new Response(JSON.stringify(jsonResult), { + headers: { 'content-type': 'application/json' }, + }), + ), + ); + + const [{ value: result }] = await getDataFromExternalSources( + [schema], + dataFromChain, + IPFS_GATEWAY_MOCK, + ); + + expect(result).to.deep.equal(jsonResult); + } finally { + fetchStub.restore(); + } + }); }); diff --git a/src/lib/getDataFromExternalSources.ts b/src/lib/getDataFromExternalSources.ts index 7c898417..f7bde427 100644 --- a/src/lib/getDataFromExternalSources.ts +++ b/src/lib/getDataFromExternalSources.ts @@ -129,12 +129,14 @@ export const getDataFromExternalSources = ( if (/^(\[.*\]|\{.*\})\s*$/s.test(key)) { const json = arrToBufArr(receivedData).toString(); const value = JSON.parse(json); + if (isDataAuthentic(value, urlDataWithHash.verification)) { return { ...dataEntry, value }; } if (isDataAuthentic(receivedData, urlDataWithHash.verification)) { return { ...dataEntry, value }; } + throw new Error('result did not correctly validate'); } } catch { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index e8e49baf..bb1ad658 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -47,6 +47,7 @@ import { SUPPORTED_VERIFICATION_METHODS, SUPPORTED_VERIFICATION_METHODS_LIST, COMPACT_BYTES_ARRAY_STRING, + SUPPORTED_VERIFICATION_METHOD_STRINGS, } from '../constants/constants'; import { decodeValueContent, @@ -524,7 +525,13 @@ export function encodeData( ); } -export function getVerificationMethod(nameOrSig: string) { +export function getVerificationMethod(nameOrSig: string): + | { + method: (data: string | object | Uint8Array | null) => string; + name: SUPPORTED_VERIFICATION_METHOD_STRINGS; + sig: SUPPORTED_VERIFICATION_METHODS; + } + | undefined { const verificationMethod = Object.values(HASH_METHODS).find( ({ name, sig }) => name === nameOrSig || sig === nameOrSig, );