Skip to content

Commit

Permalink
feat!: native DIDDocuments and proper DID resolution interface (#799)
Browse files Browse the repository at this point in the history
* Add base types for the compliant DIDs

* Add base types for the compliant DID resolution

* Add dereferencing

* Refactor of Did.utils and Did.chain

* Work on DID.signature

* Bit more mess here and there

* yarn check working fine

* did.resolve implemented

* DID resolver ok

* AccountLinks2.chain.ts

* Add resolveRepresentation to resolver

* Better DID resolver

* Resolver improvements

* Improve API surface to keep the same abstraction level

* First DID integration test passing!

* More DID integration tests uncommented

* More DID integration tests passing

* More DID integration tests

* All DID integration tests passing

* Refactoring

* Add utility function to add a verification method

* Minor refactoring

* Revert unwanted change

* Remove addKeypairAsVerificationMethod function

* Light DID unit tests passing

* Unit tests for light and full DID passing

* Minor changes to signing interfaces

* DIDSignature unit tests passing

* Halfway through the refactoring

* Better error messages

* Fix imports

* Refactoring

* First refactor

* Fix DID dereferencing and signature resolution

* Compiling!

* Compiling after applying stash

* Fix TestUtils

* verificationRelationship -> verificationRelationships

* Prepare ground for proper DID dereferencing

* Add support for query params in DID URLs

* Compiling again

* WIP dereferencing in tests

* Credential.spec.ts for legacy credential almost passing

* Did.signature.spec.ts working again

* Return minimal DID document when DID is deactivated or migrated

* Add test for legacy signature support

* Sr25519Signature2020.spec.ts test failing

* Key -> verification method renaming

* Key/service ID to URL

* More constants

* Fix yarn check

* Fix JSDocs

* Update tests

* Minor refinements

* Minor fixes

* Apply suggestion

* Push different yarn.lock

* Fix type import

* Fix integration test

* Fix integration test pt.2

* Update unit tests for DidResolver.spec.ts

* Half-way through new DidResolver unit tests

* Unit tests for DidResolver complete

* Replace buffer

* Apply suggestion

* Apply w3n suggestion

* export type

* Replace Buffer with Uint8Array

* Add multikey context

* Fix unit tests for linked signature suites

* Legacy support for document loader

* Make getStoreTxFromDidDocument only used in tests

* Use Object.fromEntries

* Refactor exportQueryParamsFromUri

* Use resolve instead of dereference

* Fixes

* Revert DidSignature renaming

* Rename URI to DID and keep DID URL
  • Loading branch information
ntn-x2 authored Oct 26, 2023
1 parent 1cf468f commit 801211d
Show file tree
Hide file tree
Showing 72 changed files with 3,770 additions and 2,880 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
*/

import type {
AssetDidUri,
AssetDid,
CTypeHash,
IDelegationNode,
IPublicCredentialInput,
IPublicCredential,
DidUri,
Did,
HexString,
} from '@kiltprotocol/types'
import type { ApiPromise } from '@polkadot/api'
Expand All @@ -29,11 +29,11 @@ import { fromChain as didFromChain } from '@kiltprotocol/did'
import { SDKErrors, cbor } from '@kiltprotocol/utils'

import { getIdForCredential } from './PublicCredential.js'
import { validateUri } from '../dids/index.js'
import { validateDid } from '../dids/index.js'

export interface EncodedPublicCredential {
ctypeHash: CTypeHash
subject: AssetDidUri
subject: AssetDid
claims: HexString
authorization: IDelegationNode['id'] | null
}
Expand Down Expand Up @@ -68,12 +68,12 @@ function credentialInputFromChain({
subject,
}: PublicCredentialsCredentialsCredential): IPublicCredentialInput {
const credentialSubject = subject.toUtf8()
validateUri(credentialSubject)
validateDid(credentialSubject)
return {
claims: cbor.decode(claims),
cTypeHash: ctypeHash.toHex(),
delegationId: authorization.unwrapOr(undefined)?.toHex() ?? null,
subject: credentialSubject as AssetDidUri,
subject: credentialSubject as AssetDid,
}
}

Expand All @@ -86,9 +86,9 @@ export interface PublicCredentialEntry {
*/
ctypeHash: HexString
/**
* DID URI of the attester.
* DID of the attester.
*/
attester: DidUri
attester: Did
/**
* Flag indicating whether the credential is currently revoked.
*/
Expand Down Expand Up @@ -244,13 +244,13 @@ export async function fetchCredentialFromChain(
/**
* Retrieves from the blockchain the [[IPublicCredential]]s that have been issued to the provided AssetDID.
*
* This is the **only** secure way for users to retrieve and verify all the credentials issued to a given [[AssetDidUri]].
* This is the **only** secure way for users to retrieve and verify all the credentials issued to a given [[AssetDid]].
*
* @param subject The AssetDID of the subject.
* @returns An array of [[IPublicCredential]] as the result of combining the on-chain information and the information present in the tx history.
*/
export async function fetchCredentialsFromChain(
subject: AssetDidUri
subject: AssetDid
): Promise<IPublicCredential[]> {
const api = ConfigService.get('api')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { ConfigService } from '@kiltprotocol/config'
import { CType } from '@kiltprotocol/core'
import * as Did from '@kiltprotocol/did'
import type {
AssetDidUri,
DidUri,
AssetDid,
Did as KiltDid,
IAssetClaim,
IClaimContents,
IPublicCredential,
Expand All @@ -39,7 +39,7 @@ const assetIdentifier =

// Build a public credential with fake attestation (i.e., attester, block number, revocation status) information.
function buildCredential(
assetDid: AssetDidUri,
assetDid: AssetDid,
contents: IClaimContents
): IPublicCredential {
const claim: IAssetClaim = {
Expand All @@ -48,7 +48,7 @@ function buildCredential(
subject: assetDid,
}
const credential = PublicCredential.fromClaim(claim)
const attester: DidUri = Did.getFullDidUri(devAlice.address)
const attester: KiltDid = Did.getFullDid(devAlice.address)
return {
...credential,
attester,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { AccountId } from '@polkadot/types/interfaces'
import type { PublicCredentialsCredentialsCredential } from '@kiltprotocol/augment-api'
import type {
HexString,
DidUri,
Did as KiltDid,
IAssetClaim,
ICType,
IDelegationNode,
Expand All @@ -30,15 +30,15 @@ import { toChain as publicCredentialToChain } from './PublicCredential.chain.js'
/**
* Calculates the ID of a [[IPublicCredentialInput]], to be used to retrieve the full credential content from the blockchain.
*
* The ID is formed by first concatenating the SCALE-encoded [[IPublicCredentialInput]] with the SCALE-encoded [[DidUri]] and then Blake2b hashing the result.
* The ID is formed by first concatenating the SCALE-encoded [[IPublicCredentialInput]] with the SCALE-encoded [[Did]] and then Blake2b hashing the result.
*
* @param credential The input credential object.
* @param attester The DID of the credential attester.
* @returns The credential ID.
*/
export function getIdForCredential(
credential: IPublicCredentialInput,
attester: DidUri
attester: KiltDid
): HexString {
const api = ConfigService.get('api')

Expand All @@ -62,7 +62,7 @@ function verifyClaimStructure(input: IAssetClaim | PartialAssetClaim): void {
throw new SDKErrors.CTypeHashMissingError()
}
if (input.subject) {
AssetDid.validateUri(input.subject)
AssetDid.validateDid(input.subject)
}
if (input.contents) {
Object.entries(input.contents).forEach(([key, value]) => {
Expand Down
28 changes: 14 additions & 14 deletions packages/asset-credentials/src/dids/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import type {
AssetDidUri,
AssetDid,
Caip19AssetId,
Caip19AssetInstance,
Caip19AssetNamespace,
Expand All @@ -22,7 +22,7 @@ const ASSET_DID_REGEX =
/^did:asset:(?<chainId>(?<chainNamespace>[-a-z0-9]{3,8}):(?<chainReference>[-a-zA-Z0-9]{1,32}))\.(?<assetId>(?<assetNamespace>[-a-z0-9]{3,8}):(?<assetReference>[-a-zA-Z0-9]{1,64})(:(?<assetInstance>[-a-zA-Z0-9]{1,78}))?)$/

type IAssetDidParsingResult = {
uri: AssetDidUri
did: AssetDid
chainId: Caip2ChainId
chainNamespace: Caip2ChainNamespace
chainReference: Caip2ChainReference
Expand All @@ -33,35 +33,35 @@ type IAssetDidParsingResult = {
}

/**
* Parses an AssetDID uri and returns the information contained within in a structured form.
* Parses an AssetDID and returns the information contained within in a structured form.
* @param assetDidUri An AssetDID uri as a string.
* @returns Object containing information extracted from the AssetDID uri.
* @param assetDid An AssetDID as a string.
* @returns Object containing information extracted from the AssetDID.
*/
export function parse(assetDidUri: AssetDidUri): IAssetDidParsingResult {
const matches = ASSET_DID_REGEX.exec(assetDidUri)?.groups
export function parse(assetDid: AssetDid): IAssetDidParsingResult {
const matches = ASSET_DID_REGEX.exec(assetDid)?.groups
if (!matches) {
throw new SDKErrors.InvalidDidFormatError(assetDidUri)
throw new SDKErrors.InvalidDidFormatError(assetDid)
}

const { chainId, assetId } = matches as Omit<IAssetDidParsingResult, 'uri'>
const { chainId, assetId } = matches as Omit<IAssetDidParsingResult, 'did'>

return {
...(matches as Omit<IAssetDidParsingResult, 'uri'>),
uri: `did:asset:${chainId}.${assetId}`,
...(matches as Omit<IAssetDidParsingResult, 'did'>),
did: `did:asset:${chainId}.${assetId}`,
}
}

/**
* Checks that a string (or other input) is a valid AssetDID uri.
* Checks that a string (or other input) is a valid AssetDID.
* Throws otherwise.
*
* @param input Arbitrary input.
*/
export function validateUri(input: unknown): void {
export function validateDid(input: unknown): void {
if (typeof input !== 'string') {
throw new TypeError(`Asset DID string expected, got ${typeof input}`)
}

parse(input as AssetDidUri)
parse(input as AssetDid)
}
4 changes: 2 additions & 2 deletions packages/core/src/attestation/Attestation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */

import { ConfigService } from '@kiltprotocol/config'
import type { CTypeHash, DidUri, IAttestation } from '@kiltprotocol/types'
import type { CTypeHash, Did, IAttestation } from '@kiltprotocol/types'
import { SDKErrors } from '@kiltprotocol/utils'

import { ApiMocks } from '../../../../tests/testUtils'
Expand All @@ -22,7 +22,7 @@ beforeAll(() => {
})

describe('Attestation', () => {
const identityAlice: DidUri =
const identityAlice: Did =
'did:kilt:4nwPAmtsK5toZfBM9WvmAe4Fa3LyZ3X3JHt7EUFfrcPPAZAm'

const cTypeHash: CTypeHash =
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/attestation/Attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {
IAttestation,
IDelegationHierarchyDetails,
ICredential,
DidUri,
Did as KiltDid,
} from '@kiltprotocol/types'
import { DataUtils, SDKErrors } from '@kiltprotocol/utils'
import * as Did from '@kiltprotocol/did'
Expand Down Expand Up @@ -49,7 +49,7 @@ export function verifyDataStructure(input: IAttestation): void {
if (!input.owner) {
throw new SDKErrors.OwnerMissingError()
}
Did.validateUri(input.owner, 'Did')
Did.validateDid(input.owner, 'Did')

if (typeof input.revoked !== 'boolean') {
throw new SDKErrors.RevokedTypeError()
Expand All @@ -65,7 +65,7 @@ export function verifyDataStructure(input: IAttestation): void {
*/
export function fromCredentialAndDid(
credential: ICredential,
attesterDid: DidUri
attesterDid: KiltDid
): IAttestation {
const attestation = {
claimHash: credential.rootHash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { encodeAddress, randomAsHex, randomAsU8a } from '@polkadot/util-crypto'
import { u8aToHex, u8aToU8a } from '@polkadot/util'

import { parse } from '@kiltprotocol/did'
import type { DidUri } from '@kiltprotocol/types'
import type { Did } from '@kiltprotocol/types'

import {
attestation,
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('proofs', () => {
})

it('checks delegation node owners', async () => {
const delegator: DidUri = `did:kilt:${encodeAddress(randomAsU8a(32), 38)}`
const delegator: Did = `did:kilt:${encodeAddress(randomAsU8a(32), 38)}`
const credentialWithDelegators: KiltCredentialV1 = {
...VC,
federatedTrustModel: VC.federatedTrustModel?.map((i) => {
Expand Down
16 changes: 8 additions & 8 deletions packages/core/src/credentialsV1/KiltAttestationProofV1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import type { IEventData, Signer } from '@polkadot/types/types'

import {
authorizeTx,
getFullDidUri,
validateUri,
getFullDid,
validateDid,
fromChain as didFromChain,
} from '@kiltprotocol/did'
import { JsonSchema, SDKErrors, Caip19 } from '@kiltprotocol/utils'
Expand All @@ -43,7 +43,7 @@ import type {
RuntimeCommonAuthorizationAuthorizationId,
} from '@kiltprotocol/augment-api'
import type {
DidUri,
Did,
ICType,
IDelegationNode,
KiltAddress,
Expand Down Expand Up @@ -220,7 +220,7 @@ async function verifyAttestedAt(
): Promise<{
verified: boolean
timestamp: number
attester: DidUri
attester: Did
cTypeId: ICType['$id']
delegationId: IDelegationNode['id'] | null
}> {
Expand Down Expand Up @@ -256,7 +256,7 @@ async function verifyAttestedAt(
Option<Hash> | Option<RuntimeCommonAuthorizationAuthorizationId>
] &
IEventData
const attester = getFullDidUri(encodeAddress(att.toU8a(), 38))
const attester = getFullDid(encodeAddress(att.toU8a(), 38))
const cTypeId = CType.hashToId(cTypeHash.toHex())
const delegationId = authorization.isSome
? (
Expand All @@ -276,7 +276,7 @@ async function verifyAttestedAt(
async function verifyAuthoritiesInHierarchy(
api: ApiPromise,
nodeId: Uint8Array | string,
delegators: Set<DidUri>
delegators: Set<Did>
): Promise<void> {
const node = (await api.query.delegation.delegationNodes(nodeId)).unwrapOr(
null
Expand Down Expand Up @@ -347,7 +347,7 @@ export async function verify(
validateCredentialStructure(credential)
const { nonTransferable, credentialStatus, credentialSubject, issuer } =
credential
validateUri(issuer, 'Did')
validateDid(issuer, 'Did')
await validateSubject(credential, opts)
// 4. check nonTransferable
if (nonTransferable !== true)
Expand Down Expand Up @@ -660,7 +660,7 @@ export type AttestationHandler = (
}>

export interface DidSigner {
did: DidUri
did: Did
signer: SignExtrinsicCallback
}

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/credentialsV1/KiltCredentialV1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { JsonSchema, SDKErrors } from '@kiltprotocol/utils'
import type {
ICType,
ICredential,
DidUri,
Did,
IDelegationNode,
} from '@kiltprotocol/types'

Expand Down Expand Up @@ -215,10 +215,10 @@ export function validateStructure(
}

interface CredentialInput {
subject: DidUri
subject: Did
claims: ICredential['claim']['contents']
cType: ICType['$id']
issuer: DidUri
issuer: Did
timestamp?: number
chainGenesisHash?: Uint8Array
claimHash?: ICredential['rootHash']
Expand Down
Loading

0 comments on commit 801211d

Please sign in to comment.