Skip to content

Commit

Permalink
first pass at connect flow and grants api
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Aug 14, 2024
1 parent 203cfd2 commit 7fa2e52
Show file tree
Hide file tree
Showing 16 changed files with 9,367 additions and 4,705 deletions.
5 changes: 5 additions & 0 deletions .changeset/fuzzy-baboons-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web5/api": minor
---

Support impersonation using delegated grants for DWN record operations using WalletConnect
8 changes: 8 additions & 0 deletions .changeset/silly-poets-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@web5/agent": minor
"@web5/identity-agent": minor
"@web5/proxy-agent": minor
"@web5/user-agent": minor
---

Simplify support for Permission Grant logic within agent.
64 changes: 0 additions & 64 deletions packages/agent/src/dwn-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import type {

import { DwnInterface, dwnMessageConstructors } from './types/dwn.js';
import { blobToIsomorphicNodeReadable, getDwnServiceEndpointUrls, isRecordsWrite, webReadableToIsomorphicNodeReadable } from './utils.js';
import { DwnPermissionsUtil } from './dwn-permissions-util.js';

export type DwnMessageWithBlob<T extends DwnInterface> = {
message: DwnMessage[T];
Expand Down Expand Up @@ -456,69 +455,6 @@ export class AgentDwnApi {
* TODO: Create a `grants` API to handle creating permission requests, grants and revocations
* */

/**
* Performs a RecordsQuery for permission grants that match the given parameters.
*/
public async fetchGrants({ author, target, grantee, grantor }: {
/** author of the query message, defaults to grantee */
author?: string,
/** target of the query message, defaults to author */
target?: string,
grantor: string,
grantee: string
}): Promise<DataEncodedRecordsWriteMessage[]> {
// if no author is provided, use the grantee's DID
author ??= grantee;
// if no target is explicitly provided, use the author
target ??= author;

const { reply: grantsReply } = await this.processRequest({
author,
target,
messageType : DwnInterface.RecordsQuery,
messageParams : {
filter: {
author : grantor, // the author of the grant would be the grantor and the logical author of the message
recipient : grantee, // the recipient of the grant would be the grantee
...DwnPermissionsUtil.permissionsProtocolParams('grant')
}
}
});

if (grantsReply.status.code !== 200) {
throw new Error(`AgentDwnApi: Failed to fetch grants: ${grantsReply.status.detail}`);
}

return grantsReply.entries! as DataEncodedRecordsWriteMessage[];
};

/**
* Check whether a grant is revoked by reading the revocation record for a given grant recordId.
*/
public async isGrantRevoked(author:string, target: string, grantRecordId: string): Promise<boolean> {
const { reply: revocationReply } = await this.processRequest({
author,
target,
messageType : DwnInterface.RecordsRead,
messageParams : {
filter: {
parentId: grantRecordId,
...DwnPermissionsUtil.permissionsProtocolParams('revoke')
}
}
});

if (revocationReply.status.code === 404) {
// no revocation found, the grant is not revoked
return false;
} else if (revocationReply.status.code === 200) {
// a revocation was found, the grant is revoked
return true;
}

throw new Error(`AgentDwnApi: Failed to check if grant is revoked: ${revocationReply.status.detail}`);
}

public async createGrant({ grantedFrom, dateExpires, grantedTo, scope, delegated }:{
dateExpires: string,
grantedFrom: string,
Expand Down
19 changes: 19 additions & 0 deletions packages/agent/src/identity-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,4 +235,23 @@ export class AgentIdentityApi<TKeyManager extends AgentKeyManager = AgentKeyMana
// Delete the Identity from the Agent's Identity store.
await this._store.delete({ id: didUri, agent: this.agent, tenant });
}

/**
* Returns the connected Identity, if one is available.
*
* Accepts optional `connectedDid` parameter to filter the a specific connected identity,
* if none is provided the first connected identity is returned.
*/
public async connectedIdentity({ connectedDid }:{ connectedDid?: string } = {}): Promise<BearerIdentity | undefined> {
const identities = await this.list();
if (identities.length < 1) {
return undefined;
}

// If a specific connected DID is provided, return the first identity that matches it.
// Otherwise, return the first connected identity.
return connectedDid ?
identities.find(identity => identity.metadata.connectedDid === connectedDid) :
identities.find(identity => identity.metadata.connectedDid !== undefined);
}
}
1 change: 1 addition & 0 deletions packages/agent/src/types/dwn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ export {
DwnConstant,
Signer as DwnSigner,
DateSort as DwnDateSort,
DataEncodedRecordsWriteMessage as DwnDataEncodedRecordsWriteMessage,
PublicJwk as DwnPublicKeyJwk, // TODO: Remove once DWN SDK switches to Jwk from @web5/crypto
PaginationCursor as DwnPaginationCursor,
MessageSubscriptionHandler as DwnMessageSubscriptionHandler,
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/types/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface IdentityMetadata {
name: string;
tenant: string;
uri: string;
connectedDid?: string;
}

export interface PortableIdentity {
Expand Down
Loading

0 comments on commit 7fa2e52

Please sign in to comment.