Skip to content

Commit

Permalink
review comments for delegateDid, update dwn-server to latest
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Aug 8, 2024
1 parent 6979b50 commit 0cd1698
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 70 deletions.
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.3",
"@web5/dwn-server": "0.4.5",
"audit-ci": "^7.0.1",
"eslint-plugin-mocha": "10.4.3",
"npkill": "0.11.3"
Expand Down
48 changes: 24 additions & 24 deletions packages/api/src/dwn-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ export class DwnApi {
private connectedDid: string;

/** (optional) The DID of the signer when signing with permissions */
private delegatedDid?: string;
private delegateDid?: string;

/** cache for fetching permissions */
private cachedPermissions: TtlCache<string, DwnDataEncodedRecordsWriteMessage[]> = new TtlCache({ ttl: 60 * 1000 });

constructor(options: { agent: Web5Agent, connectedDid: string, delegatedDid?: string }) {
constructor(options: { agent: Web5Agent, connectedDid: string, delegateDid?: string }) {
this.agent = options.agent;
this.connectedDid = options.connectedDid;
this.delegatedDid = options.delegatedDid;
this.delegateDid = options.delegateDid;
}

/**
Expand All @@ -260,7 +260,7 @@ export class DwnApi {
protocol: string,
}
}) : Promise<DwnDataEncodedRecordsWriteMessage> => {
if(!this.delegatedDid) {
if(!this.delegateDid) {
throw new Error('AgentDwnApi: Cannot find connected grants without a signer DID');
}

Expand All @@ -269,7 +269,7 @@ export class DwnApi {
// get the delegate grants that match the messageParams and are associated with the connectedDid as the grantor
const delegateGrant = await DwnPermissionsUtil.matchGrantFromArray(
this.connectedDid,
this.delegatedDid,
this.delegateDid,
messageParams,
permissions,
true
Expand All @@ -288,24 +288,24 @@ export class DwnApi {
* (optionally) Caches the results for the given parameters to avoid redundant queries.
*/
fetchConnectedGrants: async (cached: boolean = true): Promise<DwnDataEncodedRecordsWriteMessage[]> => {
if (!this.delegatedDid) {
if (!this.delegateDid) {
throw new Error('AgentDwnApi: Cannot fetch grants without a signer DID');
}

const cacheKey = [ this.delegatedDid, this.connectedDid ].join('~');
const cacheKey = [ this.delegateDid, this.connectedDid ].join('~');
const cachedGrants = cached ? this.cachedPermissions.get(cacheKey) : undefined;
if (cachedGrants) {
return cachedGrants;
}

const { reply: grantsReply } = await this.agent.processDwnRequest({
author : this.delegatedDid,
target : this.delegatedDid,
author : this.delegateDid,
target : this.delegateDid,
messageType : DwnInterface.RecordsQuery,
messageParams : {
filter: {
author : this.connectedDid, // the author of the grant would be the grantor and the logical author of the message
recipient : this.delegatedDid, // the recipient of the grant would be the grantee
recipient : this.delegateDid, // the recipient of the grant would be the grantee
...DwnPermissionsUtil.permissionsProtocolParams('grant')
}
}
Expand All @@ -319,7 +319,7 @@ export class DwnApi {
for (const entry of grantsReply.entries! as DwnDataEncodedRecordsWriteMessage[]) {
// check if the grant is revoked, we set the target to the grantor since the grantor is the author of the revocation
// the revocations should come in through sync, and are checked against the local DWN
if(await this.grants.isGrantRevoked(this.delegatedDid, this.connectedDid, entry.recordId)) {
if(await this.grants.isGrantRevoked(this.delegateDid, this.connectedDid, entry.recordId)) {
// grant is revoked do not return it in the grants list
continue;
}
Expand Down Expand Up @@ -367,7 +367,7 @@ export class DwnApi {
* Grants cache is cleared after processing.
*/
processConnectedGrantsAsOwner: async (grants: DwnDataEncodedRecordsWriteMessage[]): Promise<void> => {
if(!this.delegatedDid) {
if(!this.delegateDid) {
throw new Error('AgentDwnApi: Cannot process grants without a signer DID');
}

Expand All @@ -377,8 +377,8 @@ export class DwnApi {
delete grantMessage['encodedData'];

const { reply } = await this.agent.processDwnRequest({
author : this.delegatedDid,
target : this.delegatedDid,
author : this.delegateDid,
target : this.delegateDid,
signAsOwner : true,
messageType : DwnInterface.RecordsWrite,
rawMessage : grantMessage,
Expand All @@ -389,8 +389,8 @@ export class DwnApi {
// if any of the grants fail, delete the other grants and throw an error
for (const grant of grants) {
const { reply } = await this.agent.processDwnRequest({
author : this.delegatedDid,
target : this.delegatedDid,
author : this.delegateDid,
target : this.delegateDid,
messageType : DwnInterface.RecordsDelete,
messageParams : {
recordId: grant.recordId
Expand Down Expand Up @@ -536,7 +536,7 @@ export class DwnApi {
target : request.from || this.connectedDid
};

if (this.delegatedDid) {
if (this.delegateDid) {
// if an app is scoped down to a specific protocolPath or contextId, it must include those filters in the read request
const delegatedGrant = await this.grants.findConnectedPermissionGrant({
messageParams: {
Expand All @@ -547,7 +547,7 @@ export class DwnApi {

// set the required delegated grant and grantee DID for the read operation
agentRequest.messageParams.delegatedGrant = delegatedGrant;
agentRequest.granteeDid = this.delegatedDid;
agentRequest.granteeDid = this.delegateDid;
}

let agentResponse: DwnResponse<DwnInterface.RecordsDelete>;
Expand Down Expand Up @@ -583,7 +583,7 @@ export class DwnApi {
target : request.from || this.connectedDid
};

if (this.delegatedDid) {
if (this.delegateDid) {
// if an app is scoped down to a specific protocolPath or contextId, it must include those filters in the read request
const delegatedGrant = await this.grants.findConnectedPermissionGrant({
messageParams: {
Expand All @@ -594,7 +594,7 @@ export class DwnApi {

// set the required delegated grant and grantee DID for the read operation
agentRequest.messageParams.delegatedGrant = delegatedGrant;
agentRequest.granteeDid = this.delegatedDid;
agentRequest.granteeDid = this.delegateDid;
}


Expand Down Expand Up @@ -659,7 +659,7 @@ export class DwnApi {
target : request.from || this.connectedDid
};

if (this.delegatedDid) {
if (this.delegateDid) {
// if an app is scoped down to a specific protocolPath or contextId, it must include those filters in the read request
const delegatedGrant = await this.grants.findConnectedPermissionGrant({
messageParams: {
Expand All @@ -670,7 +670,7 @@ export class DwnApi {

// set the required delegated grant and grantee DID for the read operation
agentRequest.messageParams.delegatedGrant = delegatedGrant;
agentRequest.granteeDid = this.delegatedDid;
agentRequest.granteeDid = this.delegateDid;
}

let agentResponse: DwnResponse<DwnInterface.RecordsRead>;
Expand Down Expand Up @@ -738,7 +738,7 @@ export class DwnApi {
};

// if impersonation is enabled, fetch the delegated grant to use with the write operation
if (this.delegatedDid) {
if (this.delegateDid) {
const delegatedGrant = await this.grants.findConnectedPermissionGrant({
messageParams: {
messageType : DwnInterface.RecordsWrite,
Expand All @@ -748,7 +748,7 @@ export class DwnApi {

// set the required delegated grant and grantee DID for the write operation
dwnRequestParams.messageParams.delegatedGrant = delegatedGrant;
dwnRequestParams.granteeDid = this.delegatedDid;
dwnRequestParams.granteeDid = this.delegateDid;
};

const agentResponse = await this.agent.processDwnRequest(dwnRequestParams);
Expand Down
18 changes: 9 additions & 9 deletions packages/api/src/web5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export type Web5ConnectResult = {
did: string;

/** The DID that is used to sign messages on behalf of the connectedDID */
delegatedDid?: string;
delegateDid?: string;

/**
* The first time a Web5 agent is initialized, the recovery phrase that was used to generate the
Expand All @@ -208,7 +208,7 @@ export type Web5Params = {
connectedDid: string;

/** The DID that will be signing Web5 messages using grants from the connectedDid */
delegatedDid?: string;
delegateDid?: string;
};

/**
Expand All @@ -231,10 +231,10 @@ export class Web5 {
/** Exposed instance to the VC APIs, allow users to issue, present and verify VCs */
vc: VcApi;

constructor({ agent, connectedDid, delegatedDid }: Web5Params) {
constructor({ agent, connectedDid, delegateDid }: Web5Params) {
this.agent = agent;
this.did = new DidApi({ agent, connectedDid });
this.dwn = new DwnApi({ agent, connectedDid, delegatedDid });
this.dwn = new DwnApi({ agent, connectedDid, delegateDid });
this.vc = new VcApi({ agent, connectedDid });
}

Expand All @@ -252,7 +252,7 @@ export class Web5 {
static async connect({
agent, agentVault, connectedDid, password, recoveryPhrase, sync, techPreview, didCreateOptions, registration, walletConnectOptions
}: Web5ConnectOptions = {}): Promise<Web5ConnectResult> {
let delegatedDid: string | undefined;
let delegateDid: string | undefined;
if (agent === undefined) {
// A custom Web5Agent implementation was not specified, so use default managed user agent.
const userAgent = await Web5UserAgent.create({ agentVault });
Expand Down Expand Up @@ -308,7 +308,7 @@ export class Web5 {
// Process the incoming delegated grants in the UserAgent as the owner of the signing delegatedDID
// this will allow the delegated DID to fetch the grants in order to use them when selecting a grant to sign a record/message with
// If any of the grants fail to process, they are all rolled back and this will throw an error causing the identity to be cleaned up
const dwnApi = new DwnApi({ agent, connectedDid, delegatedDid: delegateDid.uri });
const dwnApi = new DwnApi({ agent, connectedDid, delegateDid: delegateDid.uri });
await dwnApi.grants.processConnectedGrantsAsOwner(delegateGrants);
} catch (error:any) {
// clean up the DID and Identity if import fails and throw
Expand Down Expand Up @@ -369,7 +369,7 @@ export class Web5 {
// If the stored identity has a connected DID, use it as the connected DID, otherwise use the identity's DID.
connectedDid = identity.metadata.connectedDid ?? identity.did.uri;
// If the stored identity has a connected DID, use the identity DID as the delegated DID, otherwise it is undefined.
delegatedDid = identity.metadata.connectedDid ? identity.did.uri : undefined;
delegateDid = identity.metadata.connectedDid ? identity.did.uri : undefined;
if (registration !== undefined) {
// If a registration object is passed, we attempt to register the AgentDID and the ConnectedDID with the DWN endpoints provided
const serviceEndpointNodes = techPreview?.dwnEndpoints ?? didCreateOptions?.dwnEndpoints;
Expand Down Expand Up @@ -412,9 +412,9 @@ export class Web5 {
}
}

const web5 = new Web5({ agent, connectedDid, delegatedDid });
const web5 = new Web5({ agent, connectedDid, delegateDid });

return { web5, did: connectedDid, delegatedDid, recoveryPhrase };
return { web5, did: connectedDid, delegateDid, recoveryPhrase };
}

/**
Expand Down
14 changes: 7 additions & 7 deletions packages/api/tests/dwn-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1373,7 +1373,7 @@ describe('DwnApi', () => {
describe('grants.fetchConnectedGrants()', () => {
it('throws if no signerDID is set', async () => {
// make sure signerDID is undefined
dwnAlice['delegatedDid'] = undefined;
dwnAlice['delegateDid'] = undefined;
try {
await dwnAlice.grants.fetchConnectedGrants();
expect.fail('Error was not thrown');
Expand All @@ -1391,7 +1391,7 @@ describe('DwnApi', () => {
});

// set the device identity as the signerDID
dwnAlice['delegatedDid'] = aliceDeviceX.did.uri;
dwnAlice['delegateDid'] = aliceDeviceX.did.uri;

const recordsWriteGrant = await testHarness.agent.dwn.createGrant({
grantedFrom : aliceDid.uri,
Expand Down Expand Up @@ -1505,7 +1505,7 @@ describe('DwnApi', () => {
});

// set the device identity as the signerDID, this normally happens when the identity is connected
dwnAlice['delegatedDid'] = aliceDeviceX.did.uri;
dwnAlice['delegateDid'] = aliceDeviceX.did.uri;

const recordsWriteGrant = await testHarness.agent.dwn.createGrant({
grantedFrom : aliceDid.uri,
Expand Down Expand Up @@ -1560,7 +1560,7 @@ describe('DwnApi', () => {

it('should throw if the grant query returns anything other than a 200', async () => {
// setting a signerDID, otherwise fetchConnectedGrants will throw
dwnAlice['delegatedDid'] = 'did:example:123';
dwnAlice['delegateDid'] = 'did:example:123';

// return empty array if grant query returns something other than a 200
sinon.stub(testHarness.agent, 'processDwnRequest').resolves({ messageCid: '', reply: { status: { code: 400, detail: 'unknown error' } } });
Expand All @@ -1582,7 +1582,7 @@ describe('DwnApi', () => {
});

// set the device identity as the signerDID for alice, this normally happens during a connect flow
dwnAlice['delegatedDid'] = aliceDeviceX.did.uri;
dwnAlice['delegateDid'] = aliceDeviceX.did.uri;

const recordsWriteGrant = await testHarness.agent.dwn.createGrant({
grantedFrom : aliceDid.uri,
Expand Down Expand Up @@ -1675,7 +1675,7 @@ describe('DwnApi', () => {
describe('grants.findConnectedPermissionGrant', () => {
it('throws if no signerDID is set', async () => {
// make sure signerDID is undefined
dwnAlice['delegatedDid'] = undefined;
dwnAlice['delegateDid'] = undefined;
try {
await dwnAlice.grants.findConnectedPermissionGrant({
messageParams: {
Expand All @@ -1693,7 +1693,7 @@ describe('DwnApi', () => {
describe('grants.processConnectedGrantsAsOwner', () => {
it('throws if no signerDID is set', async () => {
// make sure signerDID is undefined
dwnAlice['delegatedDid'] = undefined;
dwnAlice['delegateDid'] = undefined;
try {
await dwnAlice.grants.processConnectedGrantsAsOwner([]);
expect.fail('Error was not thrown');
Expand Down
14 changes: 7 additions & 7 deletions packages/api/tests/web5.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ describe('Web5', () => {
sinon.stub(Web5UserAgent, 'create').resolves(appTestHarness.agent as Web5UserAgent);

// connect to the app, the options don't matter because we're stubbing the initClient method
const { web5, did, delegatedDid } = await Web5.connect({
const { web5, did, delegateDid } = await Web5.connect({
walletConnectOptions: {
connectServerUrl : 'https://connect.example.com',
pinCapture : async () => { return '1234'; },
Expand All @@ -161,9 +161,9 @@ describe('Web5', () => {
});
expect(web5).to.exist;
expect(did).to.exist;
expect(delegatedDid).to.exist;
expect(delegateDid).to.exist;
expect(did).to.equal(alice.did.uri);
expect(delegatedDid).to.equal(app.uri);
expect(delegateDid).to.equal(app.uri);

// in lieu of sync, we will process the grants and protocol definition on the local connected agent
const { reply: localProtocolReply } = await web5.agent.processDwnRequest({
Expand Down Expand Up @@ -205,7 +205,7 @@ describe('Web5', () => {
// test that the logical author is the connected DID and the signer is the impersonator DID
expect(writeResult.record.author).to.equal(did);
const writeSigner = Jws.getSignerDid(writeResult.record.authorization.signature.signatures[0]);
expect(writeSigner).to.equal(delegatedDid);
expect(writeSigner).to.equal(delegateDid);

const readResult = await web5.dwn.records.read({
protocol : protocol.protocol,
Expand All @@ -218,7 +218,7 @@ describe('Web5', () => {
// test that the logical author is the connected DID and the signer is the impersonator DID
expect(readResult.record.author).to.equal(did);
const readSigner = Jws.getSignerDid(readResult.record.authorization.signature.signatures[0]);
expect(readSigner).to.equal(delegatedDid);
expect(readSigner).to.equal(delegateDid);

// attempt to query or delete, should fail because we did not grant query permissions
try {
Expand Down Expand Up @@ -296,9 +296,9 @@ describe('Web5', () => {
expect(queryResult.records).to.have.lengthOf(0); // record has been deleted

// connecting a 2nd time will return the same connectedDID and delegatedDID
const { did: did2, delegatedDid: delegatedDid2 } = await Web5.connect();
const { did: did2, delegateDid: delegateDid2 } = await Web5.connect();
expect(did2).to.equal(did);
expect(delegatedDid2).to.equal(delegatedDid);
expect(delegateDid2).to.equal(delegateDid);

// Close the app test harness storage.
await appTestHarness.clearStorage();
Expand Down
2 changes: 1 addition & 1 deletion packages/dev-env/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ version: "3.98"
services:
dwn-server:
container_name: dwn-server
image: ghcr.io/tbd54566975/dwn-server:dwn-sdk-0.4.4
image: ghcr.io/tbd54566975/dwn-server:0.4.5
ports:
- "3000:3000"
Loading

0 comments on commit 0cd1698

Please sign in to comment.