Skip to content

Commit

Permalink
feat: track signing keys independently (#194)
Browse files Browse the repository at this point in the history
* fix: remove references to Buffer

* fix: track additions to assertionMethod

fixes #184

BREAKING CHANGE: the keys in the `verificationMethod` array are no longer all referenced in the `assertionMethod` array. Only authentication (`sigAuth`) or signing keys (`veriKey`) are added.
  • Loading branch information
mirceanis committed Nov 8, 2023
1 parent e21f7a2 commit cc44100
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 32 deletions.
3 changes: 1 addition & 2 deletions src/__tests__/resolve.attribute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,7 @@ describe('attributes', () => {
},
],
authentication: [`${did}#controller`],
// This is a bug. Encryption keys should not be added to assertionMethod See #184
assertionMethod: [`${did}#controller`, `${did}#delegate-1`],
assertionMethod: [`${did}#controller`],
keyAgreement: [`${did}#delegate-1`],
})
})
Expand Down
33 changes: 17 additions & 16 deletions src/controller.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import {
Signer,
Contract,
Addressable,
AddressLike,
BlockTag,
JsonRpcProvider,
Provider,
TransactionReceipt,
getBytes,
concat,
toBeHex,
Contract,
encodeBytes32String,
getBytes,
hexlify,
isHexString,
zeroPadValue,
toUtf8Bytes,
JsonRpcProvider,
keccak256,
encodeBytes32String,
Overrides,
AddressLike,
Addressable,
Provider,
Signer,
toBeHex,
toUtf8Bytes,
TransactionReceipt,
zeroPadValue,
} from 'ethers'
import { getContractForNetwork } from './configuration'
import {
Expand Down Expand Up @@ -285,7 +286,7 @@ export class EthrDidController {
...options,
}
attrName = attrName.startsWith('0x') ? attrName : stringToBytes32(attrName)
attrValue = attrValue.startsWith('0x') ? attrValue : '0x' + Buffer.from(attrValue, 'utf-8').toString('hex')
attrValue = attrValue.startsWith('0x') ? attrValue : hexlify(toUtf8Bytes(attrValue))
const contract = await this.attachContract(overrides.from ?? undefined)
delete overrides.from
const setAttrTx = await contract.setAttribute(this.address, attrName, attrValue, exp, overrides)
Expand Down Expand Up @@ -326,7 +327,7 @@ export class EthrDidController {
...options,
}
attrName = attrName.startsWith('0x') ? attrName : stringToBytes32(attrName)
attrValue = attrValue.startsWith('0x') ? attrValue : '0x' + Buffer.from(attrValue, 'utf-8').toString('hex')
attrValue = attrValue.startsWith('0x') ? attrValue : hexlify(toUtf8Bytes(attrValue))
const contract = await this.attachContract(overrides.from ?? undefined)
delete overrides.from
const setAttrTx = await contract.setAttributeSigned(
Expand All @@ -349,7 +350,7 @@ export class EthrDidController {
...options,
}
attrName = attrName.startsWith('0x') ? attrName : stringToBytes32(attrName)
attrValue = attrValue.startsWith('0x') ? attrValue : '0x' + Buffer.from(attrValue, 'utf-8').toString('hex')
attrValue = attrValue.startsWith('0x') ? attrValue : hexlify(toUtf8Bytes(attrValue))
const contract = await this.attachContract(overrides.from ?? undefined)
delete overrides.from
const revokeAttributeTX = await contract.revokeAttribute(this.address, attrName, attrValue, overrides)
Expand Down Expand Up @@ -398,7 +399,7 @@ export class EthrDidController {
...options,
}
attrName = attrName.startsWith('0x') ? attrName : stringToBytes32(attrName)
attrValue = attrValue.startsWith('0x') ? attrValue : '0x' + Buffer.from(attrValue, 'utf-8').toString('hex')
attrValue = attrValue.startsWith('0x') ? attrValue : hexlify(toUtf8Bytes(attrValue))
const contract = await this.attachContract(overrides.from ?? undefined)
delete overrides.from
const revokeAttributeTX = await contract.revokeAttributeSigned(
Expand Down
9 changes: 4 additions & 5 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { VerificationMethod } from 'did-resolver'
import { computeAddress, getAddress } from 'ethers'
import { computeAddress, getAddress, toUtf8Bytes, toUtf8String, zeroPadBytes } from 'ethers'

export const identifierMatcher = /^(.*)?(0x[0-9a-fA-F]{40}|0x[0-9a-fA-F]{66})$/
export const nullAddress = '0x0000000000000000000000000000000000000000'
Expand Down Expand Up @@ -95,13 +95,12 @@ export function strip0x(input: string): string {
}

export function bytes32toString(input: bytes32 | Uint8Array): string {
const buff: Buffer = typeof input === 'string' ? Buffer.from(input.slice(2), 'hex') : Buffer.from(input)
return buff.toString('utf8').replace(/\0+$/, '')
return toUtf8String(input).replace(/\0+$/, '')
}

export function stringToBytes32(str: string): string {
const buffStr = '0x' + Buffer.from(str).slice(0, 32).toString('hex')
return buffStr + '0'.repeat(66 - buffStr.length)
const bytes = toUtf8Bytes(str)
return zeroPadBytes(bytes.slice(0, 32), 32)
}

export function interpretIdentifier(identifier: string): { address: string; publicKey?: string; network?: string } {
Expand Down
28 changes: 19 additions & 9 deletions src/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BlockTag, encodeBase58 } from 'ethers'
import { BlockTag, encodeBase58, encodeBase64, toUtf8String } from 'ethers'
import { ConfigurationOptions, ConfiguredNetworks, configureResolverWithNetworks } from './configuration'
import {
DIDDocument,
Expand Down Expand Up @@ -123,7 +123,7 @@ export class EthrDidResolver {
let controller = address

const authentication = [`${did}#controller`]
// const keyAgreement: string[] = []
const assertionMethod = [`${did}#controller`]

let versionId = 0
let nextVersionId = Number.POSITIVE_INFINITY
Expand All @@ -133,6 +133,7 @@ export class EthrDidResolver {
let endpoint = ''
const auth: Record<string, string> = {}
const keyAgreementRefs: Record<string, string> = {}
const signingRefs: Record<string, string> = {}
const pks: Record<string, VerificationMethod> = {}
const services: Record<string, Service> = {}
if (typeof blockHeight === 'string') {
Expand Down Expand Up @@ -162,6 +163,7 @@ export class EthrDidResolver {
switch (delegateType) {
case 'sigAuth':
auth[eventIndex] = `${did}#delegate-${delegateCount}`
signingRefs[eventIndex] = `${did}#delegate-${delegateCount}`
// eslint-disable-next-line no-fallthrough
case 'veriKey':
pks[eventIndex] = {
Expand All @@ -170,6 +172,7 @@ export class EthrDidResolver {
controller: did,
blockchainAccountId: `eip155:${chainId}:${currentEvent.delegate}`,
}
signingRefs[eventIndex] = `${did}#delegate-${delegateCount}`
break
}
} else if (event._eventName === eventNames.DIDAttributeChanged) {
Expand Down Expand Up @@ -197,38 +200,43 @@ export class EthrDidResolver {
pk.publicKeyHex = strip0x(currentEvent.value)
break
case 'base64':
pk.publicKeyBase64 = Buffer.from(currentEvent.value.slice(2), 'hex').toString('base64')
pk.publicKeyBase64 = encodeBase64(currentEvent.value)
break
case 'base58':
pk.publicKeyBase58 = encodeBase58(Buffer.from(currentEvent.value.slice(2), 'hex'))
pk.publicKeyBase58 = encodeBase58(currentEvent.value)
break
case 'pem':
pk.publicKeyPem = Buffer.from(currentEvent.value.slice(2), 'hex').toString()
pk.publicKeyPem = toUtf8String(currentEvent.value)
break
default:
pk.value = strip0x(currentEvent.value)
}
pks[eventIndex] = pk
if (match[4] === 'sigAuth') {
auth[eventIndex] = pk.id
signingRefs[eventIndex] = pk.id
} else if (match[4] === 'enc') {
keyAgreementRefs[eventIndex] = pk.id
} else {
signingRefs[eventIndex] = pk.id
}
break
}
case 'svc':
case 'svc': {
serviceCount++
const encodedService = toUtf8String(currentEvent.value)
try {
endpoint = JSON.parse(Buffer.from(currentEvent.value.slice(2), 'hex').toString())
endpoint = JSON.parse(encodedService)
} catch {
endpoint = Buffer.from(currentEvent.value.slice(2), 'hex').toString()
endpoint = encodedService
}
services[eventIndex] = {
id: `${did}#service-${serviceCount}`,
type: algorithm,
serviceEndpoint: endpoint,
}
break
}
}
}
}
Expand All @@ -253,6 +261,7 @@ export class EthrDidResolver {
serviceCount++
}
delete auth[eventIndex]
delete signingRefs[eventIndex]
delete pks[eventIndex]
delete services[eventIndex]
}
Expand All @@ -275,20 +284,21 @@ export class EthrDidResolver {
publicKeyHex: strip0x(controllerKey),
})
authentication.push(`${did}#controllerKey`)
assertionMethod.push(`${did}#controllerKey`)
}

const didDocument: DIDDocument = {
...baseDIDDocument,
verificationMethod: publicKeys.concat(Object.values(pks)),
authentication: authentication.concat(Object.values(auth)),
assertionMethod: assertionMethod.concat(Object.values(signingRefs)),
}
if (Object.values(services).length > 0) {
didDocument.service = Object.values(services)
}
if (Object.values(keyAgreementRefs).length > 0) {
didDocument.keyAgreement = Object.values(keyAgreementRefs)
}
didDocument.assertionMethod = [...(didDocument.verificationMethod?.map((pk) => pk.id) || [])]

return deactivated
? {
Expand Down

0 comments on commit cc44100

Please sign in to comment.