UNPKG

ethr-did-resolver

Version:
589 lines (561 loc) 22 kB
import { Contract, ethers, hexlify, toUtf8Bytes } from 'ethers' import { Resolvable } from 'did-resolver' import { GanacheProvider } from '@ethers-ext/provider-ganache' import { EthrDidController } from '../controller' import { deployRegistry, randomAccount, sleep } from './testUtils' import { stringToBytes32 } from '../helpers' jest.setTimeout(30000) describe('attributes', () => { let registryContract: Contract, didResolver: Resolvable, provider: GanacheProvider beforeAll(async () => { const reg = await deployRegistry() registryContract = reg.registryContract didResolver = reg.didResolver provider = reg.provider }) describe('invoking createSetAttributeHash', () => { it('sets the "encodedValue" to the passed hex encoded string (e.g. a public key)', async () => { expect.assertions(3) const { address: identity, signer } = await randomAccount(provider) const { pubKey: attrValue } = await randomAccount(provider) const attrName = 'did/pub/Secp256k1/veriKey' const controller = new EthrDidController(identity, registryContract, signer) const encodeAttributeValueSpy = jest.spyOn(controller, 'encodeAttributeValue') const ttl = 11111 await controller.createSetAttributeHash(attrName, attrValue, ttl) expect(encodeAttributeValueSpy).toHaveBeenCalledWith(attrValue) expect(encodeAttributeValueSpy).toHaveBeenCalledTimes(1) expect(encodeAttributeValueSpy).toHaveReturnedWith(attrValue) }) it('sets the "encodedValue" to a bytes encoded version of the passed attribute value (e.g. a service endpoint)', async () => { expect.assertions(3) const { address: identity, signer } = await randomAccount(provider) const attrValue = 'https://hubs.uport.me/service-endpoints-are-not-hex' const attrName = 'did/pub/Secp256k1/veriKey' const controller = new EthrDidController(identity, registryContract, signer) const encodeAttributeValueSpy = jest.spyOn(controller, 'encodeAttributeValue') const ttl = 11111 await controller.createSetAttributeHash(attrName, attrValue, ttl) expect(encodeAttributeValueSpy).toHaveBeenCalledWith(attrValue) expect(encodeAttributeValueSpy).toHaveBeenCalledTimes(1) const expectedEncodedValue = toUtf8Bytes(attrValue) expect(encodeAttributeValueSpy).toHaveReturnedWith(expectedEncodedValue) }) }) describe('invoking createRevokeAttributeHash', () => { beforeEach(() => { jest.clearAllMocks() }) it('sets the "encodedValue" to the passed hex encoded string (e.g. a public key)', async () => { expect.assertions(3) const { address: identity, signer } = await randomAccount(provider) const { pubKey: attrValue } = await randomAccount(provider) const attrName = 'did/pub/Secp256k1/veriKey' const controller = new EthrDidController(identity, registryContract, signer) const encodeAttributeValueSpy = jest.spyOn(controller, 'encodeAttributeValue') await controller.createRevokeAttributeHash(attrName, attrValue) expect(encodeAttributeValueSpy).toHaveBeenCalledWith(attrValue) expect(encodeAttributeValueSpy).toHaveBeenCalledTimes(1) expect(encodeAttributeValueSpy).toHaveReturnedWith(attrValue) }) it('sets the "encodedValue" to a bytes encoded version of the passed attribute value (e.g. a service endpoint)', async () => { expect.assertions(3) const { address: identity, signer } = await randomAccount(provider) const attrValue = 'https://hubs.uport.me/service-endpoints-are-not-hex' const attrName = 'did/pub/Secp256k1/veriKey' const controller = new EthrDidController(identity, registryContract, signer) const encodeAttributeValueSpy = jest.spyOn(controller, 'encodeAttributeValue') await controller.createRevokeAttributeHash(attrName, attrValue) expect(encodeAttributeValueSpy).toHaveBeenCalledWith(attrValue) expect(encodeAttributeValueSpy).toHaveBeenCalledTimes(1) const expectedEncodedValue = toUtf8Bytes(attrValue) expect(encodeAttributeValueSpy).toHaveReturnedWith(expectedEncodedValue) }) }) describe('add public keys', () => { it('add EcdsaSecp256k1VerificationKey2019 signing key', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const { pubKey } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/Secp256k1/veriKey', pubKey, 86401 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'EcdsaSecp256k1VerificationKey2019', controller: did, publicKeyHex: pubKey.slice(2), }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) }) it('add Bls12381G2Key2020 assertion key', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const pubKey = hexlify(toUtf8Bytes('public key material here')) // encodes to 0x7075626c6963206b6579206d6174657269616c2068657265 in base16 await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/Bls12381G2Key2020', // attrName must fit into 32 bytes. Anything extra will be truncated. pubKey, // There's no limit on the size of the public key material 86401 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'Bls12381G2Key2020', controller: did, publicKeyHex: '7075626c6963206b6579206d6174657269616c2068657265', }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) }) it('add Ed25519VerificationKey2018 authentication key', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const { pubKey } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/Ed25519/sigAuth/base64', pubKey, 86402 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'Ed25519VerificationKey2018', controller: did, publicKeyBase64: ethers.encodeBase64(pubKey), }, ], authentication: [`${did}#controller`, `${did}#delegate-1`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) }) it('add RSAVerificationKey2018 signing key', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/RSA/veriKey/pem', '-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n', 86403 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'RSAVerificationKey2018', controller: did, publicKeyPem: '-----BEGIN PUBLIC KEY...END PUBLIC KEY-----\r\n', }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) }) it('add X25519KeyAgreementKey2019 encryption key', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const pubKeyBase64 = 'MCowBQYDK2VuAyEAEYVXd3/7B4d0NxpSsA/tdVYdz5deYcR1U+ZkphdmEFI=' await new EthrDidController(did, registryContract, signer).setAttribute( 'did/pub/X25519/enc/base64', ethers.hexlify(ethers.decodeBase64(pubKeyBase64)), 86404 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'X25519KeyAgreementKey2019', controller: did, publicKeyBase64: pubKeyBase64, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], keyAgreement: [`${did}#delegate-1`], }) }) it('add an imaginary key type', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const imaginaryKey = '0x1234567890' await new EthrDidController(did, registryContract, signer).setAttribute( 'did/pub/ImaginaryKey2023/veriKey', imaginaryKey, 86404 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'ImaginaryKey2023', controller: did, publicKeyHex: imaginaryKey.slice(2), }, ], authentication: [`${did}#controller`], // This is a bug. Encryption keys should not be added to assertionMethod See #184 assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) }) }) describe('add service endpoints', () => { it('resolves document', async () => { expect.assertions(1) const { address: identity, shortDID: did, signer } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( stringToBytes32('did/svc/HubService'), 'https://hubs.uport.me', 86405 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], service: [ { id: `${did}#service-1`, type: 'HubService', serviceEndpoint: 'https://hubs.uport.me', }, ], }) }) }) describe('add expanded service endpoints', () => { it('resolves document', async () => { expect.assertions(2) const { address: identity, shortDID: did, signer } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( stringToBytes32('did/svc/HubService'), JSON.stringify({ uri: 'https://hubs.uport.me', transportType: 'http' }), 86405 ) const { didDocument } = await didResolver.resolve(did) expect(didDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [expect.anything()], assertionMethod: [expect.anything()], service: [ { id: `${did}#service-1`, type: 'HubService', serviceEndpoint: { uri: 'https://hubs.uport.me', transportType: 'http' }, }, ], }) await new EthrDidController(identity, registryContract, signer).setAttribute( stringToBytes32('did/svc/HubService'), JSON.stringify([ { uri: 'https://hubs.uport.me', transportType: 'http' }, { uri: 'libp2p.star/123', transportType: 'libp2p' }, ]), 86405 ) const { didDocument: updatedDidDocument } = await didResolver.resolve(did) expect(updatedDidDocument).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [expect.anything()], authentication: [expect.anything()], assertionMethod: [expect.anything()], service: [ { id: `${did}#service-1`, type: 'HubService', serviceEndpoint: { uri: 'https://hubs.uport.me', transportType: 'http' }, }, { id: `${did}#service-2`, type: 'HubService', serviceEndpoint: [ { uri: 'https://hubs.uport.me', transportType: 'http' }, { uri: 'libp2p.star/123', transportType: 'libp2p' }, ], }, ], }) }) }) describe('revoke attributes', () => { it('revoke EcdsaSecp256k1VerificationKey2019 signing key', async () => { expect.assertions(2) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const { pubKey } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/Secp256k1/veriKey', pubKey, 86401 ) const { didDocument: didDocumentBefore } = await didResolver.resolve(did) expect(didDocumentBefore).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'EcdsaSecp256k1VerificationKey2019', controller: did, publicKeyHex: pubKey.slice(2), }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) await new EthrDidController(identity, registryContract, signer).revokeAttribute( 'did/pub/Secp256k1/veriKey', pubKey ) const { didDocument: didDocumentAfter } = await didResolver.resolve(did) expect(didDocumentAfter).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], }) }) it('revokes Ed25519VerificationKey2018 authentication key', async () => { expect.assertions(2) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const { pubKey } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/Ed25519/sigAuth/base64', pubKey, 86402 ) const { didDocument: didDocumentBefore } = await didResolver.resolve(did) expect(didDocumentBefore).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'Ed25519VerificationKey2018', controller: did, publicKeyBase64: ethers.encodeBase64(pubKey), }, ], authentication: [`${did}#controller`, `${did}#delegate-1`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) await new EthrDidController(identity, registryContract, signer).revokeAttribute( 'did/pub/Ed25519/sigAuth/base64', pubKey ) const { didDocument: didDocumentAfter } = await didResolver.resolve(did) expect(didDocumentAfter).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], }) }) it('revokes service endpoint', async () => { expect.assertions(2) const { address: identity, shortDID: did, signer } = await randomAccount(provider) await new EthrDidController(identity, registryContract, signer).setAttribute( stringToBytes32('did/svc/HubService'), 'https://hubs.uport.me', 86405 ) const { didDocument: didDocumentBefore } = await didResolver.resolve(did) expect(didDocumentBefore).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], service: [ { id: `${did}#service-1`, type: 'HubService', serviceEndpoint: 'https://hubs.uport.me', }, ], }) await new EthrDidController(identity, registryContract, signer).revokeAttribute( stringToBytes32('did/svc/HubService'), 'https://hubs.uport.me' ) const { didDocument: didDocumentAfter } = await didResolver.resolve(did) expect(didDocumentAfter).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], }) }) it('expires key automatically', async () => { expect.assertions(2) const { address: identity, shortDID: did, signer } = await randomAccount(provider) const { pubKey } = await randomAccount(provider) const validitySeconds = 2 await new EthrDidController(identity, registryContract, signer).setAttribute( 'did/pub/Ed25519/sigAuth', pubKey, validitySeconds ) const { didDocument: didDocumentBefore } = await didResolver.resolve(did) expect(didDocumentBefore).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, { id: `${did}#delegate-1`, type: 'Ed25519VerificationKey2018', controller: did, publicKeyHex: pubKey.slice(2), }, ], authentication: [`${did}#controller`, `${did}#delegate-1`], assertionMethod: [`${did}#controller`, `${did}#delegate-1`], }) await sleep((validitySeconds + 1) * 1000) const { didDocument: didDocumentAfter } = await didResolver.resolve(did) expect(didDocumentAfter).toEqual({ '@context': expect.anything(), id: did, verificationMethod: [ { id: `${did}#controller`, type: 'EcdsaSecp256k1RecoveryMethod2020', controller: did, blockchainAccountId: `eip155:1337:${identity}`, }, ], authentication: [`${did}#controller`], assertionMethod: [`${did}#controller`], }) }) }) })