Skip to content

Commit

Permalink
fix: consistent Encoding of attrValue on createRevokeAttributeHash (
Browse files Browse the repository at this point in the history
  • Loading branch information
radleylewis authored Jun 13, 2024
1 parent 8d8e249 commit 81363d0
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 9 deletions.
70 changes: 67 additions & 3 deletions src/__tests__/resolve.attribute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,70 @@ describe('attributes', () => {
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)
Expand Down Expand Up @@ -54,9 +118,9 @@ describe('attributes', () => {
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
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.
'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
)
Expand All @@ -75,7 +139,7 @@ describe('attributes', () => {
id: `${did}#delegate-1`,
type: 'Bls12381G2Key2020',
controller: did,
publicKeyHex: "7075626c6963206b6579206d6174657269616c2068657265",
publicKeyHex: '7075626c6963206b6579206d6174657269616c2068657265',
},
],
authentication: [`${did}#controller`],
Expand Down
19 changes: 13 additions & 6 deletions src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ export class EthrDidController {
this.did = publicKey ? `did:ethr:${networkString}${publicKey}` : `did:ethr:${networkString}${address}`
}

/**
* @returns the encoded attribute value in hex or utf8 bytes
* @param attrValue - the attribute value to encode (e.g. service endpoint, public key, etc.)
*
* @remarks The incoming attribute value may be a hex encoded key, or an utf8 encoded string (like service endpoints)
**/
encodeAttributeValue(attrValue: string | `0x${string}`): Uint8Array | `0x${string}` {
return isHexString(attrValue) ? attrValue : toUtf8Bytes(attrValue)
}

async getOwner(address: address, blockTag?: BlockTag): Promise<string> {
return this.contract.identityOwner(address, { blockTag })
}
Expand Down Expand Up @@ -295,10 +305,7 @@ export class EthrDidController {

async createSetAttributeHash(attrName: string, attrValue: string, exp: number) {
const paddedNonce = await this.getPaddedNonceCompatibility(true)

// The incoming attribute value may be a hex encoded key, or an utf8 encoded string (like service endpoints)
const encodedValue = isHexString(attrValue) ? attrValue : toUtf8Bytes(attrValue)

const encodedValue = this.encodeAttributeValue(attrValue)
const dataToHash = concat([
MESSAGE_PREFIX,
await this.contract.getAddress(),
Expand Down Expand Up @@ -359,13 +366,13 @@ export class EthrDidController {

async createRevokeAttributeHash(attrName: string, attrValue: string) {
const paddedNonce = await this.getPaddedNonceCompatibility(true)

const encodedValue = this.encodeAttributeValue(attrValue)
const dataToHash = concat([
MESSAGE_PREFIX,
await this.contract.getAddress(),
paddedNonce,
this.address,
getBytes(concat([toUtf8Bytes('revokeAttribute'), encodeBytes32String(attrName), toUtf8Bytes(attrValue)])),
getBytes(concat([toUtf8Bytes('revokeAttribute'), encodeBytes32String(attrName), encodedValue])),
])
return keccak256(dataToHash)
}
Expand Down

0 comments on commit 81363d0

Please sign in to comment.