diff --git a/dnas/trusted/zomes/coordinator/trusted/src/gpg_key_dist.rs b/dnas/trusted/zomes/coordinator/trusted/src/gpg_key_dist.rs index 8b86ba5..cbaa395 100644 --- a/dnas/trusted/zomes/coordinator/trusted/src/gpg_key_dist.rs +++ b/dnas/trusted/zomes/coordinator/trusted/src/gpg_key_dist.rs @@ -55,8 +55,14 @@ pub struct SearchKeysRequest { pub query: String, } +#[derive(Serialize, Deserialize, Debug, Clone, SerializedBytes)] +pub struct SearchKeysResponse { + pub key: Record, + pub key_collection_count: usize, +} + #[hdk_extern] -pub fn search_keys(request: SearchKeysRequest) -> ExternResult> { +pub fn search_keys(request: SearchKeysRequest) -> ExternResult> { let mut links = get_links( GetLinksInputBuilder::try_new( make_base_hash(&request.query)?, @@ -87,9 +93,16 @@ pub fn search_keys(request: SearchKeysRequest) -> ExternResult> { .into_iter() .flat_map(|l| AnyDhtHash::try_from(l.target).ok()) { - match get(target, GetOptions::default())? { + match get(target.clone(), GetOptions::default())? { Some(r) => { - out.push(r); + let link_count = count_links(LinkQuery::new( + target, + LinkTypes::GpgKeyDistToKeyCollection.try_into_filter()?, + ))?; + out.push(SearchKeysResponse { + key: r, + key_collection_count: link_count, + }); } _ => { // Link target not found diff --git a/package-lock.json b/package-lock.json index b17f32b..e9f1c92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -682,18 +682,6 @@ "node": ">=6" } }, - "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz", - "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==", - "hasInstallScript": true, - "dependencies": { - "@fortawesome/fontawesome-common-types": "6.5.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@fortawesome/vue-fontawesome": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.6.tgz", @@ -6574,7 +6562,6 @@ "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-regular-svg-icons": "^6.5.1", - "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/vue-fontawesome": "^3.0.6", "@holochain/client": "^0.17.0-dev.3", "@msgpack/msgpack": "^2.8.0", diff --git a/tests/package.json b/tests/package.json index a4baf15..46442c6 100644 --- a/tests/package.json +++ b/tests/package.json @@ -2,7 +2,7 @@ "name": "tests", "private": true, "scripts": { - "test": "vitest run collection" + "test": "vitest run" }, "dependencies": { "@msgpack/msgpack": "^2.8.0", diff --git a/tests/src/trusted/trusted/gpg-key-dist.test.ts b/tests/src/trusted/trusted/gpg-key-dist.test.ts index 016df99..aa272d1 100644 --- a/tests/src/trusted/trusted/gpg-key-dist.test.ts +++ b/tests/src/trusted/trusted/gpg-key-dist.test.ts @@ -4,7 +4,7 @@ import { runScenario, dhtSync, CallableCell } from '@holochain/tryorama'; import { NewEntryAction, ActionHash, Record, AppBundleSource, fakeDnaHash, fakeActionHash, fakeAgentPubKey, fakeEntryHash } from '@holochain/client'; import { decode } from '@msgpack/msgpack'; -import { distributeGpgKey, sampleGpgKey } from './common.js'; +import { createKeyCollection, distributeGpgKey, sampleGpgKey } from './common.js'; test('Distribute GPG Key', async () => { await runScenario(async scenario => { @@ -33,7 +33,7 @@ test('Get my keys', async () => { // Bob gets the created GpgKey const keys: Record[] = await alice.cells[0].callZome({ zome_name: "trusted", - fn_name: "get_my_keys", + fn_name: "get_my_gpg_key_dists", payload: null, }); assert.equal(1, keys.length); @@ -57,7 +57,7 @@ test('Search for a key', async () => { await dhtSync([alice, bob], alice.cells[0].cell_id[0]); // Bob searches for Alice's GPG key - const keys: Record[] = await bob.cells[0].callZome({ + const responses: any[] = await bob.cells[0].callZome({ zome_name: "trusted", fn_name: "search_keys", payload: { @@ -65,9 +65,52 @@ test('Search for a key', async () => { query: "0B1D4843CA2F198CAC2F5C6A449D7AE5D2532CEF" }, }); - assert.equal(1, keys.length); - const decoded = (decode((keys[0].entry as any).Present.entry) as any); + assert.equal(1, responses.length); + const decoded = (decode((responses[0].key.entry as any).Present.entry) as any); assert.equal("Alice", decoded.name); assert.equal(sampleGpgKey().trim(), decoded.public_key); }); }); + +test('Search for a key which is in another agent collection', async () => { + await runScenario(async scenario => { + const testAppPath = process.cwd() + '/../workdir/hWOT.happ'; + const appSource = { appBundleSource: { path: testAppPath } }; + + const [alice, bob] = await scenario.addPlayersWithApps([appSource, appSource]); + + await scenario.shareAllAgents(); + + // Alice distributes a GPG key + const record: Record = await distributeGpgKey(alice.cells[0], sampleGpgKey()); + assert.ok(record); + + await dhtSync([alice, bob], alice.cells[0].cell_id[0]); + + // Bob creates a collection + await createKeyCollection(bob.cells[0], "a test"); + + // Bob links the GPG key to their key collection + await bob.cells[0].callZome({ + zome_name: "trusted", + fn_name: "link_gpg_key_to_key_collection", + payload: { + gpg_key_fingerprint: (decode((record.entry as any).Present.entry) as any).fingerprint, + key_collection_name: "a test", + }, + }); + + // Alice searches for their own key + const responses: any[] = await bob.cells[0].callZome({ + zome_name: "trusted", + fn_name: "search_keys", + payload: { + query: "0B1D4843CA2F198CAC2F5C6A449D7AE5D2532CEF" + }, + }); + assert.equal(1, responses.length); + const decoded = (decode((responses[0].key.entry as any).Present.entry) as any); + assert.equal("Alice", decoded.name); + assert.equal(1, responses[0].key_collection_count); + }); +});