Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for Reading public Records/Protocols when in a delegated state #899

Merged
merged 3 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading