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

[WIP] SyncEngine for specific protocols + delegate sync. #836

Merged
merged 17 commits into from
Aug 23, 2024
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
increase test coverage, remove duplicate tests and clean up connect m…
…ethod
LiranCohen committed Aug 23, 2024
commit 1adf942631eb4be95d757712e09d4230e98b256b
3 changes: 2 additions & 1 deletion audit-ci.json
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
"ip",
"mysql2",
"braces",
"GHSA-rv95-896h-c2vc"
"GHSA-rv95-896h-c2vc",
"GHSA-952p-6rrq-rcjv"
]
}
31 changes: 12 additions & 19 deletions packages/agent/src/sync-engine-level.ts
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ export class SyncEngineLevel implements SyncEngine {
permissionGrantId = messagesReadGrant.grant.id;
granteeDid = delegateDid;
} catch(error:any) {
console.log('SyncEngineLevel: Error fetching permission grant for delegate DID', error);
console.error('SyncEngineLevel: pull - Error fetching MessagesRead permission grant for delegate DID', error);
continue;
}
}
@@ -369,7 +369,7 @@ export class SyncEngineLevel implements SyncEngine {
// Note: It is critical that `watermark` precedes `messageCid` to ensure that when the sync
// jobs are pulled off the queue, they are lexographically sorted oldest to newest.
//
// `protocol` and `delegateDid` may be undefined, which is fine, its part of the key will be stored as the string undefined.
// `protocol` and `delegateDid` may be undefined, which is fine, its part of the key will be stored as an empty string.
// Later, when parsing the key, we will handle this case and return an actual undefined.
// This is information useful for subset and delegated sync.
return [did, delegateDid, dwnUrl, protocol, watermark, messageCid ].join('~');
@@ -379,9 +379,9 @@ export class SyncEngineLevel implements SyncEngine {
// The order is import here, see `generateKey` for more information.
const [did, delegateDidString, dwnUrl, protocolString, watermark, messageCid] = key.split('~');

// `protocol` or `delegateDid` may be parsed as an undefined string, so we need to handle that case and returned an actual undefined.
const protocol = protocolString === 'undefined' ? undefined : protocolString;
const delegateDid = delegateDidString === 'undefined' ? undefined : delegateDidString;
// `protocol` or `delegateDid` may be parsed as an empty string, so we need to handle that case and returned an actual undefined.
const protocol = protocolString === '' ? undefined : protocolString;
const delegateDid = delegateDidString === '' ? undefined : delegateDidString;
return { did, delegateDid, dwnUrl, watermark, messageCid, protocol };
}

@@ -394,23 +394,20 @@ export class SyncEngineLevel implements SyncEngine {
protocol?: string
}) {
let messagesReply = {} as MessagesQueryReply;

let permissionGrantId: string | undefined;
let granteeDid: string | undefined;
if (delegateDid) {
// fetch the grants for the delegate DID
try {
const messagesReadGrant = await this._cachedPermissionsApi.getPermission({
const messagesQueryGrant = await this._cachedPermissionsApi.getPermission({
connectedDid : did,
messageType : DwnInterface.MessagesQuery,
delegateDid,
protocol,
});

permissionGrantId = messagesReadGrant.grant.id;
granteeDid = delegateDid;
permissionGrantId = messagesQueryGrant.grant.id;
} catch(error:any) {
console.log('SyncEngineLevel: Error fetching permission grant for delegate DID', error);
console.error('SyncEngineLevel: Error fetching MessagesQuery permission grant for delegate DID', error);
return [];
}
}
@@ -424,7 +421,7 @@ export class SyncEngineLevel implements SyncEngine {
target : did,
author : did,
messageType : DwnInterface.MessagesQuery,
granteeDid,
granteeDid : delegateDid,
messageParams : { filters, cursor, permissionGrantId }
});

@@ -445,7 +442,7 @@ export class SyncEngineLevel implements SyncEngine {
author : did,
target : did,
messageType : DwnInterface.MessagesQuery,
granteeDid,
granteeDid : delegateDid,
messageParams : { filters, cursor, permissionGrantId }
});
messagesReply = messagesQueryDwnResponse.reply as MessagesQueryReply;
@@ -465,10 +462,7 @@ export class SyncEngineLevel implements SyncEngine {
protocol?: string;
messageCid: string;
}): Promise<{ message: GenericMessage, data?: Blob } | undefined> {

let permissionGrantId: string | undefined;
let granteeDid: string | undefined;

if (delegateDid) {
try {
const messagesReadGrant = await this._cachedPermissionsApi.getPermission({
@@ -479,9 +473,8 @@ export class SyncEngineLevel implements SyncEngine {
});

permissionGrantId = messagesReadGrant.grant.id;
granteeDid = delegateDid;
} catch(error:any) {
console.log('SyncEngineLevel: Error fetching permission grant for delegate DID', error);
console.error('SyncEngineLevel: push - Error fetching MessagesRead permission grant for delegate DID', error);
return;
}
}
@@ -490,7 +483,7 @@ export class SyncEngineLevel implements SyncEngine {
author : author,
target : author,
messageType : DwnInterface.MessagesRead,
granteeDid,
granteeDid : delegateDid,
messageParams : { messageCid, permissionGrantId }
});

48 changes: 46 additions & 2 deletions packages/agent/tests/dwn-api.spec.ts
Original file line number Diff line number Diff line change
@@ -11,13 +11,13 @@ import { expect } from 'chai';

import type { PortableIdentity } from '../src/types/identity.js';

import { DwnInterface } from '../src/types/dwn.js';
import { DwnInterface, DwnPermissionScope } from '../src/types/dwn.js';
import { BearerIdentity } from '../src/bearer-identity.js';
import emailProtocolDefinition from './fixtures/protocol-definitions/email.json' assert { type: 'json' };
import { PlatformAgentTestHarness } from '../src/test-harness.js';
import { TestAgent } from './utils/test-agent.js';
import { testDwnUrl } from './utils/test-config.js';
import { AgentDwnApi, isDwnMessage } from '../src/dwn-api.js';
import { AgentDwnApi, isDwnMessage, isMessagesPermissionScope, isRecordPermissionScope } from '../src/dwn-api.js';

// NOTE: @noble/secp256k1 requires globalThis.crypto polyfill for node.js <=18: https://github.com/paulmillr/noble-secp256k1/blob/main/README.md#usage
// Remove when we move off of node.js v18 to v20, earliest possible time would be Oct 2023: https://github.com/nodejs/release#release-schedule
@@ -1935,4 +1935,48 @@ describe('isDwnMessage', () => {
expect(isDwnMessage(DwnInterface.RecordsQuery, recordsWriteMessage)).to.be.false;
expect(isDwnMessage(DwnInterface.RecordsWrite, recordsQueryMessage)).to.be.false;
});
});

describe('isRecordPermissionScope', () => {
it('asserts the type of RecordPermissionScope', async () => {
// messages read scope to test negative case
const messagesReadScope:DwnPermissionScope = {
interface : DwnInterfaceName.Messages,
method : DwnMethodName.Read
};

expect(isRecordPermissionScope(messagesReadScope)).to.be.false;

// records read scope to test positive case
const recordsReadScope:DwnPermissionScope = {
interface : DwnInterfaceName.Records,
method : DwnMethodName.Read,
protocol : 'https://schemas.xyz/example'
};

expect(isRecordPermissionScope(recordsReadScope)).to.be.true;
});
});

describe('isMessagesPermissionScope', () => {
it('asserts the type of RecordPermissionScope', async () => {

// records read scope to test negative case
const recordsReadScope:DwnPermissionScope = {
interface : DwnInterfaceName.Records,
method : DwnMethodName.Read,
protocol : 'https://schemas.xyz/example'
};

expect(isMessagesPermissionScope(recordsReadScope)).to.be.false;

// messages read scope to test positive case
const messagesReadScope:DwnPermissionScope = {
interface : DwnInterfaceName.Messages,
method : DwnMethodName.Read
};

expect(isMessagesPermissionScope(messagesReadScope)).to.be.true;

});
});
2 changes: 1 addition & 1 deletion packages/agent/tests/store-data.spec.ts
Original file line number Diff line number Diff line change
@@ -605,7 +605,7 @@ describe('AgentDataStore', () => {
expect.fail('Expected an error to be thrown');

} catch (error: any) {
expect(error.message).to.include(`Failed to write data to store for: test-1`);
expect(error.message).to.include(`Failed to write data to store for test-1`);
} finally {
dwnApiStub.restore();
}
Loading