Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
nitro-neal committed Jul 19, 2024
2 parents 1a47b9b + 57ac130 commit fdb87b5
Show file tree
Hide file tree
Showing 67 changed files with 1,777 additions and 485 deletions.
8 changes: 0 additions & 8 deletions .changeset/dirty-days-flash.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/eighty-spoons-cross.md

This file was deleted.

13 changes: 0 additions & 13 deletions .changeset/famous-otters-kick.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/grumpy-carpets-buy.md

This file was deleted.

8 changes: 0 additions & 8 deletions .changeset/lemon-islands-provide.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/rare-garlics-kneel.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/silly-cherries-grow.md

This file was deleted.

8 changes: 0 additions & 8 deletions .changeset/tidy-wasps-smell.md

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"@changesets/cli": "^2.27.5",
"@npmcli/package-json": "5.0.0",
"@typescript-eslint/eslint-plugin": "7.9.0",
"@web5/dwn-server": "0.4.0",
"@web5/dwn-server": "0.4.3",
"audit-ci": "^7.0.1",
"eslint-plugin-mocha": "10.4.3",
"npkill": "0.11.3"
Expand Down
6 changes: 4 additions & 2 deletions packages/agent/.c8rc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
"tests/compiled/**/src/index.js",
"tests/compiled/**/src/types.js",
"tests/compiled/**/src/types/**",
"tests/compiled/**/src/prototyping/clients/*-types.js"
"tests/compiled/**/src/prototyping/clients/*-types.js",
"tests/compiled/**/src/prototyping/**/types/**"
],
"reporter": [
"cobertura",
"html",
"text"
]
}
}
31 changes: 31 additions & 0 deletions packages/agent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
# @web5/agent

## 0.4.1

### Patch Changes

- [#765](https://github.com/TBD54566975/web5-js/pull/765) [`8baa679`](https://github.com/TBD54566975/web5-js/commit/8baa679ae496c9052025b11d435c48390579be47) Thanks [@thehenrytsai](https://github.com/thehenrytsai)! - Added DWN Registrar utility class

- [#770](https://github.com/TBD54566975/web5-js/pull/770) [`f71ce8a`](https://github.com/TBD54566975/web5-js/commit/f71ce8a6b9b10dfb1a627a9fe0d7473a453422e0) Thanks [@LiranCohen](https://github.com/LiranCohen)! - Upgrade `dwn-sdk-js` and `dwn-server`

## 0.4.0

### Minor Changes

- [#736](https://github.com/TBD54566975/web5-js/pull/736) [`89f239d`](https://github.com/TBD54566975/web5-js/commit/89f239d1338a71ce700ac1efaef124035a5363c9) Thanks [@LiranCohen](https://github.com/LiranCohen)! - Migrate `Events` interface to `Messages` interface for sync

- [#743](https://github.com/TBD54566975/web5-js/pull/743) [`44604a4`](https://github.com/TBD54566975/web5-js/commit/44604a4edacdbfa09f0427f782ac49a34a9d9d2b) Thanks [@LiranCohen](https://github.com/LiranCohen)! - Protocol driven identity, key and did storage

### Patch Changes

- [#739](https://github.com/TBD54566975/web5-js/pull/739) [`5b0c61a`](https://github.com/TBD54566975/web5-js/commit/5b0c61ab548dfe7258592cc7fb924fabc80f7be1) Thanks [@LiranCohen](https://github.com/LiranCohen)! - Sync accounts for 404 from a conflicting RecordsDelete message

- [#694](https://github.com/TBD54566975/web5-js/pull/694) [`cc3aa58`](https://github.com/TBD54566975/web5-js/commit/cc3aa58069dd5465834b32174e3f840ddf782d60) Thanks [@thehenrytsai](https://github.com/thehenrytsai)! - Dependency updates.

- [#744](https://github.com/TBD54566975/web5-js/pull/744) [`1708050`](https://github.com/TBD54566975/web5-js/commit/1708050fa2cbcdd9861ef289bb306505c8671194) Thanks [@LiranCohen](https://github.com/LiranCohen)! - Add ability to delete IdentityMetadata, PortableDid, and Jwk from Dwn Stores in Agent

- [#738](https://github.com/TBD54566975/web5-js/pull/738) [`bc54d0c`](https://github.com/TBD54566975/web5-js/commit/bc54d0c82d9665d60b4fa6bba11f7ef3e24497a4) Thanks [@LiranCohen](https://github.com/LiranCohen)! - Remove Duplicate Methods used in sync & Fix sync bug where only RecordsWrite were being pulled from the remote

- Updated dependencies [[`cc3aa58`](https://github.com/TBD54566975/web5-js/commit/cc3aa58069dd5465834b32174e3f840ddf782d60)]:
- @web5/common@1.0.2
- @web5/crypto@1.0.2
- @web5/dids@1.1.2

## 0.3.8

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/agent/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@web5/agent",
"version": "0.3.8",
"version": "0.4.1",
"type": "module",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
Expand Down Expand Up @@ -71,7 +71,7 @@
"dependencies": {
"@noble/ciphers": "0.4.1",
"@scure/bip39": "1.2.2",
"@tbd54566975/dwn-sdk-js": "0.4.0",
"@tbd54566975/dwn-sdk-js": "0.4.4",
"@web5/common": "1.0.0",
"@web5/crypto": "1.0.0",
"@web5/dids": "1.1.0",
Expand Down
33 changes: 33 additions & 0 deletions packages/agent/src/did-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,39 @@ export class AgentDidApi<TKeyManager extends AgentKeyManager = AgentKeyManager>
return bearerDid;
}

public async delete({ didUri, tenant, deleteKey = true }: {
didUri: string;
tenant?: string;
deleteKey?: boolean;
}): Promise<void> {
const portableDid = await this._store.get({ id: didUri, agent: this.agent, tenant, useCache: false });
if(!portableDid) {
throw new Error('AgentDidApi: Could not delete, DID not found');
}

// Delete the data before deleting the associated keys.
await this._store.delete({ id: didUri, agent: this.agent, tenant });

if (deleteKey) {
// Delete the keys associated with the DID
// TODO: this could be made a static method on `BearerDid` class
await this.deleteKeys({ portableDid });
}
}

public async deleteKeys({ portableDid }: {
portableDid: PortableDid;
}): Promise<void> {
for (const verificationMethod of portableDid.document.verificationMethod || []) {
if (!verificationMethod.publicKeyJwk) {
continue;
}
// Compute the key URI of the verification method's public key.
const keyUri = await this.agent.keyManager.getKeyUri({ key: verificationMethod.publicKeyJwk });
await this.agent.keyManager.deleteKey({ keyUri });
}
}

public async processRequest<T extends DidInterface>(
request: DidRequest<T>
): Promise<DidResponse<T>> {
Expand Down
127 changes: 127 additions & 0 deletions packages/agent/src/dwn-registrar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { Sha256, utils } from '@web5/crypto';
import { concatenateUrl } from './utils.js';
import { Convert } from '@web5/common';

/**
* A client for registering tenants with a DWN.
*/
export class DwnRegistrar {
/**
* Registers a new tenant with the given DWN.
* NOTE: Assumes the user has already accepted the terms of service.
* NOTE: Currently the DWN Server from `dwn-server` does not require user signature.
* TODO: bring in types from `dwn-server`.
*/
public static async registerTenant(dwnEndpoint: string, did: string): Promise<void> {

const registrationEndpoint = concatenateUrl(dwnEndpoint, 'registration');
const termsOfUseEndpoint = concatenateUrl(registrationEndpoint, 'terms-of-service');
const proofOfWorkEndpoint = concatenateUrl(registrationEndpoint, 'proof-of-work');

// fetch the terms-of-service
const termsOfServiceGetResponse = await fetch(termsOfUseEndpoint, {
method: 'GET',
});

if (termsOfServiceGetResponse.status !== 200) {
const statusCode = termsOfServiceGetResponse.status;
const statusText = termsOfServiceGetResponse.statusText;
const errorText = await termsOfServiceGetResponse.text();
throw new Error(`Failed fetching terms-of-service: ${statusCode} ${statusText}: ${errorText}`);
}
const termsOfServiceFetched = await termsOfServiceGetResponse.text();

// fetch the proof-of-work challenge
const proofOfWorkChallengeGetResponse = await fetch(proofOfWorkEndpoint, {
method: 'GET',
});
const { challengeNonce, maximumAllowedHashValue} = await proofOfWorkChallengeGetResponse.json();

// create registration data based on the hash of the terms-of-service and the DID
const registrationData = {
did,
termsOfServiceHash: await DwnRegistrar.hashAsHexString(termsOfServiceFetched),
};

// compute the proof-of-work response nonce based on the the proof-of-work challenge and the registration data.
const responseNonce = await DwnRegistrar.findQualifiedResponseNonce({
challengeNonce,
maximumAllowedHashValue,
requestData: JSON.stringify(registrationData),
});

// send the registration request to the server
const registrationRequest = {
registrationData,
proofOfWork: {
challengeNonce,
responseNonce,
},
};

const registrationResponse = await fetch(registrationEndpoint, {
method : 'POST',
headers : { 'Content-Type': 'application/json' },
body : JSON.stringify(registrationRequest),
});

if (registrationResponse.status !== 200) {
const statusCode = registrationResponse.status;
const statusText = registrationResponse.statusText;
const errorText = await registrationResponse.text();
throw new Error(`Registration failed: ${statusCode} ${statusText}: ${errorText}`);
}
}

/**
* Computes the SHA-256 hash of the given array of strings.
*/
public static async hashAsHexString(input: string): Promise<string> {
const hashAsBytes = await Sha256.digest({ data: Convert.string(input).toUint8Array()});
const hashAsHex = Convert.uint8Array(hashAsBytes).toHex();
return hashAsHex;
}

/**
* Finds a response nonce that qualifies the difficulty requirement for the given proof-of-work challenge and request data.
*/
public static async findQualifiedResponseNonce(input: {
maximumAllowedHashValue: string;
challengeNonce: string;
requestData: string;
}): Promise<string> {
const startTime = Date.now();

const { maximumAllowedHashValue, challengeNonce, requestData } = input;
const maximumAllowedHashValueAsBigInt = BigInt(`0x${maximumAllowedHashValue}`);

let iterations = 1;
let responseNonce;
let qualifiedSolutionNonceFound = false;
do {
responseNonce = await this.generateNonce();
const computedHash = await DwnRegistrar.hashAsHexString(challengeNonce + responseNonce + requestData);
const computedHashAsBigInt = BigInt(`0x${computedHash}`);

qualifiedSolutionNonceFound = computedHashAsBigInt <= maximumAllowedHashValueAsBigInt;

iterations++;
} while (!qualifiedSolutionNonceFound);

// Log final/successful iteration.
console.log(
`iterations: ${iterations}, time lapsed: ${Date.now() - startTime} ms`,
);

return responseNonce;
}

/**
* Generates 32 random bytes expressed as a HEX string.
*/
public static async generateNonce(): Promise<string> {
const randomBytes = utils.randomBytes(32);
const hexString = await Convert.uint8Array(randomBytes).toHex().toUpperCase();
return hexString;
}
}
14 changes: 14 additions & 0 deletions packages/agent/src/identity-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,18 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana

return identity;
}

public async delete({ didUri, tenant }:{
didUri: string;
tenant?: string;
}): Promise<void> {
// Attempt to retrieve the Identity from the Agent's Identity store.
const storedIdentity = await this._store.get({ id: didUri, agent: this.agent, tenant, useCache: true });
if (!storedIdentity) {
throw new Error(`AgentIdentityApi: Failed to purge due to Identity not found: ${didUri}`);
}

// Delete the Identity from the Agent's Identity store.
await this._store.delete({ id: didUri, agent: this.agent, tenant });
}
}
1 change: 1 addition & 0 deletions packages/agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './bearer-identity.js';
export * from './crypto-api.js';
export * from './did-api.js';
export * from './dwn-api.js';
export * from './dwn-registrar.js';
export * from './hd-identity-vault.js';
export * from './identity-api.js';
export * from './local-key-manager.js';
Expand Down
10 changes: 10 additions & 0 deletions packages/agent/src/local-key-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,16 @@ export class LocalKeyManager implements AgentKeyManager {
return wrappedKeyBytes;
}

public async deleteKey({ keyUri }:{ keyUri: KeyIdentifier }): Promise<void> {
// Get the private key from the key store.
const jwk = await this._keyStore.get({ id: keyUri, agent: this.agent, useCache: true });
if (!jwk) {
throw new Error(`Key not found: ${keyUri}`);
}

await this._keyStore.delete({ id: keyUri, agent: this.agent });
}

/**
* Retrieves an algorithm implementation instance based on the provided algorithm name.
*
Expand Down
13 changes: 13 additions & 0 deletions packages/agent/src/prototyping/crypto/types/key-io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,17 @@ export interface KeyImporter<ImportKeyInput, ImportKeyOutput = void> {
* @returns A Promise resolving to the key identifier of the imported key.
*/
importKey(params: ImportKeyInput): Promise<ImportKeyOutput>;
}

export interface KeyDeleter<DeleteKeyInput> {
/**
* Deletes a cryptographic key.
*
* @remarks
* The `deleteKey()` method of the {@link KeyDeleter | `KeyDeleter`} interface deletes a cryptographic
* key from the key store.
*
* @param params - The parameters for the key deletion operation.
*/
deleteKey(params: DeleteKeyInput): Promise<void>;
}
5 changes: 5 additions & 0 deletions packages/agent/src/prototyping/crypto/types/params-kms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,9 @@ export interface KmsWrapKeyParams {

/** An object defining the algorithm-specific parameters for encrypting the `unwrappedKey`. */
encryptParams?: unknown
}

export interface KmsDeleteKeyParams {
/** Identifier for the key to be deleted in the KMS. */
keyUri: KeyIdentifier;
}
Loading

0 comments on commit fdb87b5

Please sign in to comment.