Skip to content

Commit

Permalink
Allow for Reading public Records/Protocols when in a delegated state (#…
Browse files Browse the repository at this point in the history
…899)

* allow for reading/querying/subscribing to public records without explicit permissions when in a delegated state

* vulnerability patch using pnpm audit --fix
  • Loading branch information
LiranCohen authored Sep 11, 2024
1 parent 57803fa commit 9f0a128
Show file tree
Hide file tree
Showing 8 changed files with 623 additions and 103 deletions.
5 changes: 5 additions & 0 deletions .changeset/slow-pets-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web5/api": patch
---

Allow reading public records in delegate state even if no explicit grant exists.
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@
"elliptic@>=2.0.0 <=6.5.6": ">=6.5.7",
"elliptic@>=5.2.1 <=6.5.6": ">=6.5.7",
"micromatch@<4.0.8": ">=4.0.8",
"webpack@<5.94.0": ">=5.94.0"
"webpack@<5.94.0": ">=5.94.0",
"webpack@>=5.0.0-alpha.0 <5.94.0": ">=5.94.0",
"path-to-regexp@>=0.2.0 <8.0.0": ">=8.0.0",
"path-to-regexp@<0.1.10": ">=0.1.10",
"body-parser@<1.20.3": ">=1.20.3",
"send@<0.19.0": ">=0.19.0",
"serve-static@<1.16.0": ">=1.16.0",
"express@<4.20.0": ">=4.20.0"
}
}
}
118 changes: 76 additions & 42 deletions packages/api/src/dwn-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,20 +595,31 @@ export class DwnApi {
};

if (this.delegateDid) {
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
connectedDid : this.connectedDid,
delegateDid : this.delegateDid,
protocol : request.protocol,
delegate : true,
cached : true,
messageType : agentRequest.messageType
});

agentRequest.messageParams = {
...agentRequest.messageParams,
delegatedGrant
};
agentRequest.granteeDid = this.delegateDid;
// if we don't find a delegated grant, we will attempt to query signing as the delegated DID
// This is to allow the API caller to query public records without needing to impersonate the delegate.
//
// NOTE: When a read-only DwnApi is implemented, callers should use that instead when they don't have an explicit permission.
// This should fail if a permission is not found.
// TODO: https://github.com/TBD54566975/web5-js/issues/898
try {
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
connectedDid : this.connectedDid,
delegateDid : this.delegateDid,
protocol : request.protocol,
delegate : true,
cached : true,
messageType : agentRequest.messageType
});

agentRequest.messageParams = {
...agentRequest.messageParams,
delegatedGrant
};
agentRequest.granteeDid = this.delegateDid;
} catch(error:any) {
// set the author of the request to the delegate did
agentRequest.author = this.delegateDid;
}
}


Expand Down Expand Up @@ -674,20 +685,32 @@ export class DwnApi {
target : request.from || this.connectedDid
};
if (this.delegateDid) {
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
connectedDid : this.connectedDid,
delegateDid : this.delegateDid,
protocol : request.protocol,
delegate : true,
cached : true,
messageType : agentRequest.messageType
});

agentRequest.messageParams = {
...agentRequest.messageParams,
delegatedGrant
};
agentRequest.granteeDid = this.delegateDid;
// if we don't find a delegated grant, we will attempt to read signing as the delegated DID
// This is to allow the API caller to read public records without needing to impersonate the delegate.
//
// NOTE: When a read-only DwnApi is implemented, callers should use that instead when they don't have an explicit permission.
// This should fail if a permission is not found.
// TODO: https://github.com/TBD54566975/web5-js/issues/898

try {
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
connectedDid : this.connectedDid,
delegateDid : this.delegateDid,
protocol : request.protocol,
delegate : true,
cached : true,
messageType : agentRequest.messageType
});

agentRequest.messageParams = {
...agentRequest.messageParams,
delegatedGrant
};
agentRequest.granteeDid = this.delegateDid;
} catch(_error:any) {
// set the author of the request to the delegate did
agentRequest.author = this.delegateDid;
}
}

let agentResponse: DwnResponse<DwnInterface.RecordsRead>;
Expand Down Expand Up @@ -766,20 +789,31 @@ export class DwnApi {
};

if (this.delegateDid) {
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
connectedDid : this.connectedDid,
delegateDid : this.delegateDid,
protocol : request.protocol,
delegate : true,
cached : true,
messageType : agentRequest.messageType
});

agentRequest.messageParams = {
...agentRequest.messageParams,
delegatedGrant
};
agentRequest.granteeDid = this.delegateDid;
// if we don't find a delegated grant, we will attempt to subscribe signing as the delegated DID
// This is to allow the API caller to subscribe to public records without needing to impersonate the delegate.
//
// NOTE: When a read-only DwnApi is implemented, callers should use that instead when they don't have an explicit permission.
// This should fail if a permission is not found.
// TODO: https://github.com/TBD54566975/web5-js/issues/898
try {
const { message: delegatedGrant } = await this.permissionsApi.getPermissionForRequest({
connectedDid : this.connectedDid,
delegateDid : this.delegateDid,
protocol : request.protocol,
delegate : true,
cached : true,
messageType : agentRequest.messageType
});

agentRequest.messageParams = {
...agentRequest.messageParams,
delegatedGrant
};
agentRequest.granteeDid = this.delegateDid;
} catch(_error:any) {
// set the author of the request to the delegate did
agentRequest.author = this.delegateDid;
}
};

let agentResponse: DwnResponse<DwnInterface.RecordsSubscribe>;
Expand Down
39 changes: 25 additions & 14 deletions packages/api/src/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ export class Record implements RecordModel {
let requestOptions: ProcessDwnRequest<DwnInterface.RecordsWrite | DwnInterface.RecordsDelete>;
// Now that we've processed a potential initial write, we can process the current record state.
// If the record has been deleted, we need to send a delete request. Otherwise, we send a write request.
if(this.deleted) {
if (this.deleted) {
requestOptions = {
messageType : DwnInterface.RecordsDelete,
rawMessage : this.rawMessage,
Expand Down Expand Up @@ -1029,21 +1029,32 @@ export class Record implements RecordModel {
};

if (this._delegateDid) {
const { message: delegatedGrant } = await this._permissionsApi.getPermissionForRequest({
connectedDid : this._connectedDid,
delegateDid : this._delegateDid,
protocol : this.protocol,
delegate : true,
cached : true,
messageType : readRequest.messageType
});
// When reading the data as a delegate, if we don't find a grant we will attempt to read it with the delegate DID as the author.
// This allows users to read publicly available data without needing explicit grants.
//
// NOTE: When a read-only Record class is implemented, callers would have that returned instead when they don't have an explicit permission.
// This should fail if a permission is not found, although it should not happen in practice.
// TODO: https://github.com/TBD54566975/web5-js/issues/898
try {
const { message: delegatedGrant } = await this._permissionsApi.getPermissionForRequest({
connectedDid : this._connectedDid,
delegateDid : this._delegateDid,
protocol : this.protocol,
delegate : true,
cached : true,
messageType : readRequest.messageType
});

readRequest.messageParams = {
...readRequest.messageParams,
delegatedGrant
};
readRequest.messageParams = {
...readRequest.messageParams,
delegatedGrant
};

readRequest.granteeDid = this._delegateDid;
readRequest.granteeDid = this._delegateDid;
} catch(error) {
// If there is an error fetching the grant, we will attempt to read the data as the delegate.
readRequest.author = this._delegateDid;
}
}

const agentResponsePromise = isRemote ?
Expand Down
Loading

0 comments on commit 9f0a128

Please sign in to comment.