diff --git a/packages/did/src/did/details.ts b/packages/did/src/did/details.ts index 213cafe..c370cd2 100644 --- a/packages/did/src/did/details.ts +++ b/packages/did/src/did/details.ts @@ -15,6 +15,7 @@ import type { DidKeys, IDidDetails, KeyRelationship, SignedData } from '../types import { assert } from '@polkadot/util'; import { base58Encode } from '@zcloak/crypto'; +import { parseDid } from '@zcloak/did-resolver/parseDid'; import { DidKeyring } from './keyring'; @@ -34,6 +35,7 @@ export function typeTransform(type: KeypairType): VerificationMethodType { export abstract class DidDetails extends DidKeyring implements IDidDetails { public id: DidUrl; + public identifier: string; public controller: Set; public keyRelationship: Map; public authentication?: Set; @@ -56,6 +58,7 @@ export abstract class DidDetails extends DidKeyring implements IDidDetails { }: IDidDetails) { super(); this.id = id; + this.identifier = parseDid(id).identifier; this.controller = controller; this.keyRelationship = keyRelationship; this.authentication = authentication; diff --git a/packages/did/src/index.ts b/packages/did/src/index.ts index 3ddacdf..025b0d7 100644 --- a/packages/did/src/index.ts +++ b/packages/did/src/index.ts @@ -4,4 +4,6 @@ export * from './did'; export * as helpers from './did/helpers'; +export * as keys from './keys'; + export * from './hasher'; diff --git a/packages/did/src/keys/backup.spec.ts b/packages/did/src/keys/backup.spec.ts new file mode 100644 index 0000000..68778c8 --- /dev/null +++ b/packages/did/src/keys/backup.spec.ts @@ -0,0 +1,37 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { generateMnemonic } from '@zcloak/crypto'; +import { Keyring } from '@zcloak/keyring'; + +import { createEcdsaFromMnemonic } from '../did/helpers'; +import { backup, getEcdsaIdentifierPair } from './backup'; +import { DEFAULT_DID_KEYS_JSON_VERSION } from './defaults'; + +describe('Backup did', (): void => { + const keyring = new Keyring(); + + it('get ecdsa identifier pair', () => { + const mnemonic = generateMnemonic(12); + const did = createEcdsaFromMnemonic(mnemonic, keyring); + + expect(getEcdsaIdentifierPair(keyring, did)?.publicKey).toEqual( + keyring.createFromMnemonic(mnemonic, undefined, 'ecdsa').publicKey + ); + }); + + it('backup did', () => { + const mnemonic = generateMnemonic(12); + const did = createEcdsaFromMnemonic(mnemonic, keyring); + + expect(backup(keyring, did, '1234')).toMatchObject({ + didUrl: did.id, + version: DEFAULT_DID_KEYS_JSON_VERSION, + authentication: Array.from(did.authentication ?? []), + assertionMethod: Array.from(did.assertionMethod ?? []), + keyAgreement: Array.from(did.keyAgreement ?? []), + capabilityInvocation: Array.from(did.capabilityInvocation ?? []), + capabilityDelegation: Array.from(did.capabilityDelegation ?? []) + }); + }); +}); diff --git a/packages/did/src/keys/backup.ts b/packages/did/src/keys/backup.ts new file mode 100644 index 0000000..f4f2fd4 --- /dev/null +++ b/packages/did/src/keys/backup.ts @@ -0,0 +1,43 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { KeyringPair } from '@zcloak/keyring/types'; +import type { Did } from '../did'; +import type { DidKeys$Json } from './types'; + +import { assert } from '@polkadot/util'; + +import { ethereumEncode } from '@zcloak/crypto'; +import { Keyring } from '@zcloak/keyring'; + +import { DEFAULT_DID_KEYS_JSON_VERSION } from './defaults'; + +export function getEcdsaIdentifierPair(keyring: Keyring, did: Did): KeyringPair | undefined { + const identifierPair = keyring + .getPairs() + .find((pair) => ethereumEncode(pair.publicKey) === did.identifier); + + return identifierPair; +} + +export function backup(keyring: Keyring, did: Did, password: string): DidKeys$Json { + const identifierPair = getEcdsaIdentifierPair(keyring, did); + + assert(identifierPair, 'no identifier pair found'); + + return { + didUrl: did.id, + version: DEFAULT_DID_KEYS_JSON_VERSION, + identifierKey: identifierPair.toJson(password), + keys: Array.from(did.keyRelationship.values()).map(({ publicKey }) => { + const pair = did.getPair(publicKey); + + return pair.toJson(password); + }), + authentication: Array.from(did.authentication ?? []), + assertionMethod: Array.from(did.assertionMethod ?? []), + keyAgreement: Array.from(did.keyAgreement ?? []), + capabilityInvocation: Array.from(did.capabilityInvocation ?? []), + capabilityDelegation: Array.from(did.capabilityDelegation ?? []) + }; +} diff --git a/packages/did/src/keys/defaults.ts b/packages/did/src/keys/defaults.ts new file mode 100644 index 0000000..901bda1 --- /dev/null +++ b/packages/did/src/keys/defaults.ts @@ -0,0 +1,6 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { DidKeys$JsonVersion } from './types'; + +export const DEFAULT_DID_KEYS_JSON_VERSION: DidKeys$JsonVersion = '1'; diff --git a/packages/did/src/keys/index.ts b/packages/did/src/keys/index.ts new file mode 100644 index 0000000..d19c96f --- /dev/null +++ b/packages/did/src/keys/index.ts @@ -0,0 +1,5 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +export * from './backup'; +export * from './restore'; diff --git a/packages/did/src/keys/restore.spec.ts b/packages/did/src/keys/restore.spec.ts new file mode 100644 index 0000000..65ea92d --- /dev/null +++ b/packages/did/src/keys/restore.spec.ts @@ -0,0 +1,22 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import { generateMnemonic } from '@zcloak/crypto'; +import { Keyring } from '@zcloak/keyring'; + +import { createEcdsaFromMnemonic } from '../did/helpers'; +import { backup } from './backup'; +import { restore } from './restore'; + +describe('Restore did', (): void => { + const keyring = new Keyring(); + + it('backup did and restore', () => { + const mnemonic = generateMnemonic(12); + const did = createEcdsaFromMnemonic(mnemonic, keyring); + + const json = backup(keyring, did, '1234'); + + expect(restore(keyring, json, '1234')).toMatchObject(did); + }); +}); diff --git a/packages/did/src/keys/restore.ts b/packages/did/src/keys/restore.ts new file mode 100644 index 0000000..16fcabd --- /dev/null +++ b/packages/did/src/keys/restore.ts @@ -0,0 +1,47 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { DidUrl } from '@zcloak/did-resolver/types'; +import type { Keyring } from '@zcloak/keyring'; +import type { DidKeys$Json } from './types'; + +import { Did } from '../did'; +import { create } from '../did/helpers'; +import { IDidDetails, KeyRelationship } from '../types'; + +export function restore(keyring: Keyring, json: DidKeys$Json, password: string): Did { + const keyRelationship = new Map(); + + json.keys.forEach((key, index) => { + const pair = keyring.addFromJson(key); + + pair.unlock(password); + + const id: DidUrl = `${json.didUrl}#key-${index}`; + const controller: DidUrl[] = [`${json.didUrl}`]; + const publicKey = pair.publicKey; + + keyRelationship.set(id, { + id, + controller, + publicKey + }); + }); + const pair = keyring.addFromJson(json.identifierKey); + + pair.unlock(password); + + const details: IDidDetails = { + id: json.didUrl, + controller: new Set([json.didUrl]), + keyRelationship, + authentication: new Set(json.authentication), + assertionMethod: new Set(json.assertionMethod), + keyAgreement: new Set(json.keyAgreement), + capabilityInvocation: new Set(json.capabilityInvocation), + capabilityDelegation: new Set(json.capabilityDelegation), + service: new Map() + }; + + return create(details, keyring); +} diff --git a/packages/did/src/keys/types.ts b/packages/did/src/keys/types.ts new file mode 100644 index 0000000..4f16e62 --- /dev/null +++ b/packages/did/src/keys/types.ts @@ -0,0 +1,19 @@ +// Copyright 2021-2022 zcloak authors & contributors +// SPDX-License-Identifier: Apache-2.0 + +import type { DidUrl } from '@zcloak/did-resolver/types'; +import type { KeyringPair$Json } from '@zcloak/keyring/types'; + +export type DidKeys$JsonVersion = '1'; + +export interface DidKeys$Json { + didUrl: DidUrl; + version: DidKeys$JsonVersion; + identifierKey: KeyringPair$Json; + keys: KeyringPair$Json[]; + authentication: DidUrl[]; + assertionMethod: DidUrl[]; + keyAgreement: DidUrl[]; + capabilityInvocation: DidUrl[]; + capabilityDelegation: DidUrl[]; +} diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 364e6f3..c6987c5 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -1,15 +1,11 @@ { "extends": "./tsconfig.base.json", + "exclude": [ + "build/**/*", + "**/build/**/*" + ], "compilerOptions": { "baseUrl": "./packages", "composite": false - }, - "include": [ - "packages/**/src/**/*", - "packages/**/scripts/**/*", - "packages/**/test/**/*" - ], - "exclude": [ - "**/node_modules/**/*" - ] + } }