From e4ded4b98dd6ec59f84bae05f71525ae85b2c243 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Wed, 20 Mar 2024 09:52:40 -0400 Subject: [PATCH 1/5] Renamed txn to operation --- gatekeeper-sdk.js | 16 ++--- gatekeeper.js | 146 ++++++++++++++++++++++----------------------- gatekeeper.test.js | 82 ++++++++++++------------- keychain-cli.js | 8 +-- keymaster.js | 30 +++++----- keymaster.test.js | 8 +-- server.js | 20 +++---- 7 files changed, 155 insertions(+), 155 deletions(-) diff --git a/gatekeeper-sdk.js b/gatekeeper-sdk.js index 7cf6cf27..5af52c37 100644 --- a/gatekeeper-sdk.js +++ b/gatekeeper-sdk.js @@ -27,9 +27,9 @@ export async function getVersion() { } } -export async function createDID(txn) { +export async function createDID(operation) { try { - const response = await axios.post(`${URL}/did/`, txn); + const response = await axios.post(`${URL}/did/`, operation); return response.data; } catch (error) { @@ -53,9 +53,9 @@ export async function resolveDID(did, asof = null) { } } -export async function updateDID(txn) { +export async function updateDID(operation) { try { - const response = await axios.post(`${URL}/did/${txn.did}`, txn); + const response = await axios.post(`${URL}/did/${operation.did}`, operation); return response.data; } catch (error) { @@ -63,9 +63,9 @@ export async function updateDID(txn) { } } -export async function deleteDID(txn) { +export async function deleteDID(operation) { try { - const response = await axios.delete(`${URL}/did/${txn.did}`, { data: txn }); + const response = await axios.delete(`${URL}/did/${operation.did}`, { data: operation }); return response.data; } catch (error) { @@ -83,9 +83,9 @@ export async function exportDID(did) { } } -export async function importDID(txns) { +export async function importDID(ops) { try { - const response = await axios.post(`${URL}/import/`, txns); + const response = await axios.post(`${URL}/import/`, ops); return response.data; } catch (error) { diff --git a/gatekeeper.js b/gatekeeper.js index b3203592..2b6912b3 100644 --- a/gatekeeper.js +++ b/gatekeeper.js @@ -74,14 +74,14 @@ export async function stop() { helia.stop(); } -function submitTxn(did, registry, txn, time, ordinal = 0) { +function submitTxn(did, registry, operation, time, ordinal = 0) { const db = loadDb(); const update = { time: time, ordinal: ordinal, did: did, - txn: txn, + operation: operation, }; if (!db.hasOwnProperty(registry)) { @@ -121,91 +121,91 @@ export async function anchorSeed(seed) { return did; } -export async function generateDID(txn) { - const did = await anchorSeed(txn); - const txns = await exportDID(did); +export async function generateDID(operation) { + const did = await anchorSeed(operation); + const ops = await exportDID(did); - if (txns.length === 0) { - submitTxn(did, txn.mdip.registry, txn, txn.created); + if (ops.length === 0) { + submitTxn(did, operation.mdip.registry, operation, operation.created); } return did; } -async function createAgent(txn) { - if (!txn.signature) { - throw "Invalid txn"; +async function createAgent(operation) { + if (!operation.signature) { + throw "Invalid operation"; } - if (!txn.publicJwk) { - throw "Invalid txn"; + if (!operation.publicJwk) { + throw "Invalid operation"; } - const txnCopy = JSON.parse(JSON.stringify(txn)); - delete txnCopy.signature; + const operationCopy = JSON.parse(JSON.stringify(operation)); + delete operationCopy.signature; - const msgHash = cipher.hashJSON(txnCopy); - const isValid = cipher.verifySig(msgHash, txn.signature.value, txn.publicJwk); + const msgHash = cipher.hashJSON(operationCopy); + const isValid = cipher.verifySig(msgHash, operation.signature.value, operation.publicJwk); if (!isValid) { - throw "Invalid txn"; + throw "Invalid operation"; } - return generateDID(txn); + return generateDID(operation); } -async function createAsset(txn) { - if (txn.controller !== txn.signature.signer) { - throw "Invalid txn"; +async function createAsset(operation) { + if (operation.controller !== operation.signature.signer) { + throw "Invalid operation"; } - const doc = await resolveDID(txn.signature.signer, txn.signature.signed); - const txnCopy = JSON.parse(JSON.stringify(txn)); - delete txnCopy.signature; - const msgHash = cipher.hashJSON(txnCopy); + const doc = await resolveDID(operation.signature.signer, operation.signature.signed); + const operationCopy = JSON.parse(JSON.stringify(operation)); + delete operationCopy.signature; + const msgHash = cipher.hashJSON(operationCopy); // TBD select the right key here, not just the first one const publicJwk = doc.didDocument.verificationMethod[0].publicKeyJwk; - const isValid = cipher.verifySig(msgHash, txn.signature.value, publicJwk); + const isValid = cipher.verifySig(msgHash, operation.signature.value, publicJwk); if (!isValid) { - throw "Invalid txn"; + throw "Invalid operation"; } - return generateDID(txn); + return generateDID(operation); } -export async function createDID(txn) { - if (txn?.op !== "create") { - throw "Invalid txn"; +export async function createDID(operation) { + if (operation?.type !== "create") { + throw "Invalid operation"; } - if (!txn.created) { + if (!operation.created) { // TBD ensure valid timestamp format - throw "Invalid txn"; + throw "Invalid operation"; } - if (!txn.mdip) { - throw "Invalid txn"; + if (!operation.mdip) { + throw "Invalid operation"; } - if (!validVersions.includes(txn.mdip.version)) { + if (!validVersions.includes(operation.mdip.version)) { throw `Valid versions include: ${validVersions}`; } - if (!validTypes.includes(txn.mdip.type)) { + if (!validTypes.includes(operation.mdip.type)) { throw `Valid types include: ${validTypes}`; } - if (!validRegistries.includes(txn.mdip.registry)) { + if (!validRegistries.includes(operation.mdip.registry)) { throw `Valid registries include: ${validRegistries}`; } - if (txn.mdip.type === 'agent') { - return createAgent(txn); + if (operation.mdip.type === 'agent') { + return createAgent(operation); } - if (txn.mdip.type === 'asset') { - return createAsset(txn); + if (operation.mdip.type === 'asset') { + return createAsset(operation); } throw "Unknown type"; @@ -299,19 +299,19 @@ async function generateDoc(did, asofTime) { return {}; // TBD unknown type error } -async function verifyUpdate(txn, doc) { +async function verifyUpdate(operation, doc) { if (!doc?.didDocument) { return false; } if (doc.didDocument.controller) { - const controllerDoc = await resolveDID(doc.didDocument.controller, txn.signature.signed); - return verifyUpdate(txn, controllerDoc); + const controllerDoc = await resolveDID(doc.didDocument.controller, operation.signature.signed); + return verifyUpdate(operation, controllerDoc); } if (doc.didDocument.verificationMethod) { - const jsonCopy = JSON.parse(JSON.stringify(txn)); + const jsonCopy = JSON.parse(JSON.stringify(operation)); const signature = jsonCopy.signature; delete jsonCopy.signature; @@ -357,19 +357,19 @@ export async function resolveDID(did, asOfTime = null, verify = false) { const updates = fetchUpdates(mdip.registry, did); - for (const { time, txn } of updates) { + for (const { time, operation } of updates) { if (asOfTime && new Date(time) > new Date(asOfTime)) { break; } - if (txn.op === 'create') { + if (operation.type === 'create') { // Proof-of-existence in the DID's registry continue; } const hash = cipher.hashJSON(doc); - if (hash !== txn.prev) { + if (hash !== operation.prev) { // hash mismatch // if (verify) { // throw "Invalid hash"; @@ -378,7 +378,7 @@ export async function resolveDID(did, asOfTime = null, verify = false) { // continue; } - const valid = await verifyUpdate(txn, doc); + const valid = await verifyUpdate(operation, doc); if (!valid) { if (verify) { @@ -388,17 +388,17 @@ export async function resolveDID(did, asOfTime = null, verify = false) { continue; } - if (txn.op === 'update') { + if (operation.type === 'update') { // Maintain mdip metadata across versions mdip = doc.didDocumentMetadata.mdip; - // TBD if registry change in txn.doc.didDocumentMetadata.mdip, - // fetch updates from new registry and search for same txn - doc = txn.doc; + // TBD if registry change in operation.doc.didDocumentMetadata.mdip, + // fetch updates from new registry and search for same operation + doc = operation.doc; doc.didDocumentMetadata.updated = time; doc.didDocumentMetadata.mdip = mdip; } - else if (txn.op === 'delete') { + else if (operation.type === 'delete') { doc.didDocument = {}; doc.didDocumentMetadata.deactivated = true; doc.didDocumentMetadata.data = null; // in case of asset @@ -409,17 +409,17 @@ export async function resolveDID(did, asOfTime = null, verify = false) { throw "Invalid operation"; } - console.error(`unknown op ${txn.op}`); + console.error(`unknown type ${operation.type}`); } } return doc; } -export async function updateDID(txn) { +export async function updateDID(operation) { try { - const doc = await resolveDID(txn.did); - const updateValid = await verifyUpdate(txn, doc); + const doc = await resolveDID(operation.did); + const updateValid = await verifyUpdate(operation, doc); if (!updateValid) { return false; @@ -428,7 +428,7 @@ export async function updateDID(txn) { const registry = doc.didDocumentMetadata.mdip.registry; // TBD figure out time for blockchain registries - submitTxn(txn.did, registry, txn, txn.signature.signed); + submitTxn(operation.did, registry, operation, operation.signature.signed); return true; } catch (error) { @@ -437,8 +437,8 @@ export async function updateDID(txn) { } } -export async function deleteDID(txn) { - return updateDID(txn); +export async function deleteDID(operation) { + return updateDID(operation); } export async function exportDID(did) { @@ -452,39 +452,39 @@ export async function exportDID(did) { return fetchUpdates(registry, did); } -export async function importDID(txns) { +export async function importDID(ops) { - if (!txns || !Array.isArray(txns) || txns.length < 1) { + if (!ops || !Array.isArray(ops) || ops.length < 1) { throw "Invalid import"; } - const create = txns[0]; + const create = ops[0]; const did = create.did; const current = await exportDID(did); if (current.length === 0) { - const check = await createDID(create.txn); + const check = await createDID(create.operation); if (did !== check) { throw "Invalid import"; } } else { - if (create.txn.signature.value !== current[0].txn.signature.value) { + if (create.operation.signature.value !== current[0].operation.signature.value) { throw "Invalid import"; } } - for (let i = 1; i < txns.length; i++) { + for (let i = 1; i < ops.length; i++) { if (i < current.length) { - // Verify previous update txns - if (txns[i].txn.signature.value !== current[i].txn.signature.value) { + // Verify previous update ops + if (ops[i].operation.signature.value !== current[i].operation.signature.value) { throw "Invalid import"; } } else { // Add new updates - const ok = await updateDID(txns[i].txn); + const ok = await updateDID(ops[i].operation); if (!ok) { throw "Invalid import"; @@ -503,9 +503,9 @@ export async function mergeBatch(batch) { let updated = 0; let failed = 0; - for (const txns of batch) { + for (const ops of batch) { try { - const diff = await importDID(txns); + const diff = await importDID(ops); if (diff > 0) { updated += 1; diff --git a/gatekeeper.test.js b/gatekeeper.test.js index 71fd8784..4ab878f9 100644 --- a/gatekeeper.test.js +++ b/gatekeeper.test.js @@ -17,11 +17,11 @@ describe('generateDid', () => { mockFs.restore(); }); - it('should create DID from txn', async () => { + it('should create DID from operation', async () => { mockFs({}); const mockTxn = { - op: "create", + type: "create", created: new Date().toISOString(), mdip: { registry: "mockRegistry" @@ -33,11 +33,11 @@ describe('generateDid', () => { expect(did.startsWith('did:mdip:')); }); - it('should create same DID from same txn with date included', async () => { + it('should create same DID from same operation with date included', async () => { mockFs({}); const mockTxn = { - op: "create", + type: "create", created: new Date().toISOString(), mdip: { registry: "mockRegistry" @@ -51,8 +51,8 @@ describe('generateDid', () => { }); async function createAgentTxn(keypair, version = 1, registry = 'hyperswarm') { - const txn = { - op: "create", + const operation = { + type: "create", created: new Date().toISOString(), mdip: { version: version, @@ -62,11 +62,11 @@ async function createAgentTxn(keypair, version = 1, registry = 'hyperswarm') { publicJwk: keypair.publicJwk, }; - const msgHash = cipher.hashJSON(txn); + const msgHash = cipher.hashJSON(operation); const signature = await cipher.signHash(msgHash, keypair.privateJwk); return { - ...txn, + ...operation, signature: { signed: new Date().toISOString(), hash: msgHash, @@ -79,18 +79,18 @@ async function createUpdateTxn(keypair, did, doc) { const current = await gatekeeper.resolveDID(did); const prev = cipher.hashJSON(current); - const txn = { - op: "update", + const operation = { + type: "update", did: did, doc: doc, prev: prev, }; - const msgHash = cipher.hashJSON(txn); + const msgHash = cipher.hashJSON(operation); const signature = await cipher.signHash(msgHash, keypair.privateJwk); const signed = { - ...txn, + ...operation, signature: { signer: did, created: new Date().toISOString(), @@ -104,7 +104,7 @@ async function createUpdateTxn(keypair, did, doc) { async function createAssetTxn(agent, keypair) { const dataAnchor = { - op: "create", + type: "create", created: new Date().toISOString(), mdip: { version: 1, @@ -135,7 +135,7 @@ describe('createDID', () => { mockFs.restore(); }); - it('should create DID from agent txn', async () => { + it('should create DID from agent operation', async () => { mockFs({}); const keypair = cipher.generateRandomJwk(); @@ -224,7 +224,7 @@ describe('createDID', () => { } }); - it('should create DID from asset txn', async () => { + it('should create DID from asset operation', async () => { mockFs({}); const keypair = cipher.generateRandomJwk(); @@ -252,18 +252,18 @@ describe('exportDID', () => { const agentTxn = await createAgentTxn(keypair); const did = await gatekeeper.createDID(agentTxn); - const txns = await gatekeeper.exportDID(did); + const ops = await gatekeeper.exportDID(did); - expect(txns.length).toBe(1); - expect(txns[0].did).toStrictEqual(did); - expect(txns[0].txn).toStrictEqual(agentTxn); + expect(ops.length).toBe(1); + expect(ops[0].did).toStrictEqual(did); + expect(ops[0].operation).toStrictEqual(agentTxn); }); it('should return empty array on an invalid DID', async () => { mockFs({}); - const txns = await gatekeeper.exportDID('mockDID'); - expect(txns).toStrictEqual([]); + const ops = await gatekeeper.exportDID('mockDID'); + expect(ops).toStrictEqual([]); }); }); @@ -279,9 +279,9 @@ describe('importDID', () => { const keypair = cipher.generateRandomJwk(); const agentTxn = await createAgentTxn(keypair); const did = await gatekeeper.createDID(agentTxn); - const txns = await gatekeeper.exportDID(did); + const ops = await gatekeeper.exportDID(did); - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); expect(imported).toBe(0); }); @@ -294,14 +294,14 @@ describe('importDID', () => { const agentDID = await gatekeeper.createDID(agentTxn); const assetTxn = await createAssetTxn(agentDID, keypair); const assetDID = await gatekeeper.createDID(assetTxn); - const txns = await gatekeeper.exportDID(assetDID); + const ops = await gatekeeper.exportDID(assetDID); - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); expect(imported).toBe(0); }); - it('should report 0 txns reported when DID exists', async () => { + it('should report 0 ops reported when DID exists', async () => { mockFs({}); const keypair = cipher.generateRandomJwk(); @@ -310,14 +310,14 @@ describe('importDID', () => { const doc = await gatekeeper.resolveDID(did); const updateTxn = await createUpdateTxn(keypair, did, doc); const ok = await gatekeeper.updateDID(updateTxn); - const txns = await gatekeeper.exportDID(did); + const ops = await gatekeeper.exportDID(did); - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); expect(imported).toBe(0); }); - it('should report 2 txns imported when DID deleted first', async () => { + it('should report 2 ops imported when DID deleted first', async () => { mockFs({}); const keypair = cipher.generateRandomJwk(); @@ -326,15 +326,15 @@ describe('importDID', () => { const doc = await gatekeeper.resolveDID(did); const updateTxn = await createUpdateTxn(keypair, did, doc); const ok = await gatekeeper.updateDID(updateTxn); - const txns = await gatekeeper.exportDID(did); + const ops = await gatekeeper.exportDID(did); fs.rmSync(gatekeeper.dbName); - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); expect(imported).toBe(2); }); - it('should report N+1 txns imported for N updates', async () => { + it('should report N+1 ops imported for N updates', async () => { mockFs({}); const keypair = cipher.generateRandomJwk(); @@ -349,12 +349,12 @@ describe('importDID', () => { const ok = await gatekeeper.updateDID(updateTxn); } - const txns = await gatekeeper.exportDID(did); + const ops = await gatekeeper.exportDID(did); fs.rmSync(gatekeeper.dbName); - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); - expect(imported).toBe(N+1); + expect(imported).toBe(N + 1); }); it('should resolve an imported DID', async () => { @@ -363,11 +363,11 @@ describe('importDID', () => { const keypair = cipher.generateRandomJwk(); const agentTxn = await createAgentTxn(keypair); const did = await gatekeeper.createDID(agentTxn); - const txns = await gatekeeper.exportDID(did); + const ops = await gatekeeper.exportDID(did); fs.rmSync(gatekeeper.dbName); - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); const doc = await gatekeeper.resolveDID(did); expect(doc.didDocument.id).toBe(did); @@ -381,12 +381,12 @@ describe('importDID', () => { const did1 = await gatekeeper.createDID(agentTxn1); const agentTxn2 = await createAgentTxn(keypair); const did2 = await gatekeeper.createDID(agentTxn2); - const txns = await gatekeeper.exportDID(did1); + const ops = await gatekeeper.exportDID(did1); - txns[0].did = did2; + ops[0].did = did2; try { - const imported = await gatekeeper.importDID(txns); + const imported = await gatekeeper.importDID(ops); throw 'Expected to throw an exception'; } catch (error) { expect(error).toBe('Invalid import'); @@ -433,7 +433,7 @@ describe('importDID', () => { const imported = await gatekeeper.importDID([1, 2, 3]); throw 'Expected to throw an exception'; } catch (error) { - expect(error).toBe('Invalid txn'); + expect(error).toBe('Invalid operation'); } }); }); diff --git a/keychain-cli.js b/keychain-cli.js index aee84070..c550144a 100644 --- a/keychain-cli.js +++ b/keychain-cli.js @@ -503,8 +503,8 @@ program .description('Export DID to file') .action(async (did) => { try { - const txns = await keymaster.exportDID(did); - console.log(JSON.stringify(txns, null, 4)); + const ops = await keymaster.exportDID(did); + console.log(JSON.stringify(ops, null, 4)); } catch (error) { console.error(error); @@ -517,8 +517,8 @@ program .action(async (file) => { try { const contents = fs.readFileSync(file).toString(); - const txns = JSON.parse(contents); - const did = await keymaster.importDID(txns); + const ops = JSON.parse(contents); + const did = await keymaster.importDID(ops); console.log(did); } catch (error) { diff --git a/keymaster.js b/keymaster.js index f3c5e14b..346bf7be 100644 --- a/keymaster.js +++ b/keymaster.js @@ -229,14 +229,14 @@ async function updateDID(did, doc) { const current = await resolveDID(did); const prev = cipher.hashJSON(current); - const txn = { - op: "update", + const operation = { + type: "update", did: did, doc: doc, prev: prev, }; - const signed = await addSignature(txn); + const signed = await addSignature(operation); return gatekeeper.updateDID(signed); } @@ -244,13 +244,13 @@ async function revokeDID(did) { const current = await resolveDID(did); const prev = cipher.hashJSON(current); - const txn = { - op: "delete", + const operation = { + type: "delete", did: did, prev: prev, }; - const signed = await addSignature(txn); + const signed = await addSignature(operation); return gatekeeper.deleteDID(signed); } @@ -308,8 +308,8 @@ export async function createId(name, registry = defaultRegistry) { const didkey = hdkey.derive(path); const keypair = cipher.generateJwk(didkey.privateKey); - const txn = { - op: "create", + const operation = { + type: "create", created: new Date().toISOString(), mdip: { version: 1, @@ -319,10 +319,10 @@ export async function createId(name, registry = defaultRegistry) { publicJwk: keypair.publicJwk, }; - const msgHash = cipher.hashJSON(txn); + const msgHash = cipher.hashJSON(operation); const signature = await cipher.signHash(msgHash, keypair.privateJwk); const signed = { - ...txn, + ...operation, signature: { signed: new Date().toISOString(), hash: msgHash, @@ -518,8 +518,8 @@ export async function createData(data, registry = defaultRegistry) { const id = getCurrentId(); - const txn = { - op: "create", + const operation = { + type: "create", created: new Date().toISOString(), mdip: { version: 1, @@ -530,7 +530,7 @@ export async function createData(data, registry = defaultRegistry) { data: data, }; - const signed = await addSignature(txn); + const signed = await addSignature(operation); const did = await gatekeeper.createDID(signed); addToOwned(did); @@ -798,6 +798,6 @@ export async function exportDID(did) { return gatekeeper.exportDID(lookupDID(did)); } -export async function importDID(txns) { - return gatekeeper.importDID(txns); +export async function importDID(ops) { + return gatekeeper.importDID(ops); } diff --git a/keymaster.test.js b/keymaster.test.js index f9e4afb8..5a9760ed 100644 --- a/keymaster.test.js +++ b/keymaster.test.js @@ -420,11 +420,11 @@ describe('rotateKeys', () => { await keymaster.rotateKeys(); } - const txns = await keymaster.exportDID(alice); + const ops = await keymaster.exportDID(alice); fs.rmSync(gatekeeper.dbName); - const imported = await keymaster.importDID(txns); + const imported = await keymaster.importDID(ops); expect(imported).toBe(rotations + 1); }); @@ -1078,12 +1078,12 @@ describe('revokeCredential', () => { const ok = await keymaster.revokeCredential(did); const userTxns = await keymaster.exportDID(userDid); - const txns = await keymaster.exportDID(did); + const ops = await keymaster.exportDID(did); fs.rmSync(gatekeeper.dbName); await keymaster.importDID(userTxns); - const imported = await keymaster.importDID(txns); + const imported = await keymaster.importDID(ops); expect(imported).toBe(2); }); diff --git a/server.js b/server.js index a752a6ac..d41f7c9a 100644 --- a/server.js +++ b/server.js @@ -23,8 +23,8 @@ v1router.get('/version', async (req, res) => { v1router.post('/did', async (req, res) => { try { - const txn = req.body; - const did = await gatekeeper.createDID(txn); + const operation = req.body; + const did = await gatekeeper.createDID(operation); res.json(did); } catch (error) { console.error(error); @@ -44,8 +44,8 @@ v1router.get('/did/:did', async (req, res) => { v1router.post('/did/:did', async (req, res) => { try { - const txn = req.body; - const ok = await gatekeeper.updateDID(txn); + const operation = req.body; + const ok = await gatekeeper.updateDID(operation); res.json(ok); } catch (error) { console.error(error); @@ -55,8 +55,8 @@ v1router.post('/did/:did', async (req, res) => { v1router.delete('/did/:did', async (req, res) => { try { - const txn = req.body; - const ok = await gatekeeper.deleteDID(txn); + const operation = req.body; + const ok = await gatekeeper.deleteDID(operation); res.json(ok); } catch (error) { console.error(error); @@ -66,8 +66,8 @@ v1router.delete('/did/:did', async (req, res) => { v1router.get('/export/:did', async (req, res) => { try { - const txns = await gatekeeper.exportDID(req.params.did); - res.json(txns); + const ops = await gatekeeper.exportDID(req.params.did); + res.json(ops); } catch (error) { console.error(error); res.status(500).send(error.toString()); @@ -76,8 +76,8 @@ v1router.get('/export/:did', async (req, res) => { v1router.post('/import', async (req, res) => { try { - const txns = req.body; - const did = await gatekeeper.importDID(txns); + const ops = req.body; + const did = await gatekeeper.importDID(ops); res.json(did); } catch (error) { console.error(error); From 43dac9a2ee9dccef052d608da56a2e2d909fd958 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Wed, 20 Mar 2024 12:25:25 -0400 Subject: [PATCH 2/5] Refactored verifyDb --- gatekeeper.js | 16 ++++++++++++++++ server.js | 14 ++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/gatekeeper.js b/gatekeeper.js index 2b6912b3..bfcd8217 100644 --- a/gatekeeper.js +++ b/gatekeeper.js @@ -34,6 +34,7 @@ export function writeDb(db) { export async function verifyDb() { const db = loadDb(); + const backup = JSON.parse(JSON.stringify(db)); if (!db.anchors) { return 0; @@ -52,9 +53,24 @@ export async function verifyDb() { catch (error) { console.log(`${n} ${did} ${error}`); invalid += 1; + + if (db.anchors[did]) { + const anchor = db.anchors[did]; + const registry = anchor.mdip.registry; + delete db[registry][did]; + delete db.anchors[did]; + } } } + if (invalid > 0) { + const today = new Date(); + const dateString = today.toISOString().split('T')[0]; + const backupName = `${dataFolder}/mdip.backup.${dateString}.json`; + fs.writeFileSync(backupName, JSON.stringify(backup, null, 4)); + writeDb(db); + } + return invalid; } diff --git a/server.js b/server.js index d41f7c9a..b24d1e86 100644 --- a/server.js +++ b/server.js @@ -127,15 +127,13 @@ const port = 3000; app.use('/api/v1', v1router); gatekeeper.verifyDb().then((invalid) => { - if (invalid === 0) { - app.listen(port, () => { - console.log(`Server is running on port ${port}`); - }); - } - else { - console.log(`${invalid} invalid DIDs in MDIP db`); - process.exit(); + if (invalid > 0) { + console.log(`${invalid} invalid DIDs removed from MDIP db`); } + + app.listen(port, () => { + console.log(`Server is running on port ${port}`); + }); }); process.on('uncaughtException', (error) => { From cd359de4afb621cbe9142a676fd7358cc466b37a Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Wed, 20 Mar 2024 12:45:21 -0400 Subject: [PATCH 3/5] Incremented protocol version --- hyperswarm-mediator.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hyperswarm-mediator.js b/hyperswarm-mediator.js index b5ec3b17..d1dd86cd 100644 --- a/hyperswarm-mediator.js +++ b/hyperswarm-mediator.js @@ -12,7 +12,7 @@ import config from './config.js'; import { EventEmitter } from 'events'; EventEmitter.defaultMaxListeners = 100; -const protocol = '/MDIP/v22.03.18'; +const protocol = '/MDIP/v22.03.20'; const swarm = new Hyperswarm(); const peerName = b4a.toString(swarm.keyPair.publicKey, 'hex'); @@ -202,8 +202,8 @@ const networkID = Buffer.from(hash).toString('hex'); const topic = b4a.from(networkID, 'hex'); async function start() { - console.log(`hyperswarm peer id: ${peerName}`); - console.log('joined topic:', b4a.toString(topic, 'hex')); + console.log(`hyperswarm peer id: ${shortName(peerName)}`); + console.log('joined topic:', shortName(b4a.toString(topic, 'hex'))); setInterval(async () => { try { From 7014337886af463d1a04758e95c734366fae0721 Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Wed, 20 Mar 2024 12:58:18 -0400 Subject: [PATCH 4/5] Restricted valid registries --- gatekeeper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gatekeeper.js b/gatekeeper.js index bfcd8217..033bb4f9 100644 --- a/gatekeeper.js +++ b/gatekeeper.js @@ -13,7 +13,7 @@ export const dbName = `${dataFolder}/mdip.json`; const validVersions = [1]; const validTypes = ['agent', 'asset']; -const validRegistries = ['peerbit', 'BTC', 'tBTC', 'local', 'hyperswarm']; +const validRegistries = ['local', 'hyperswarm']; export function loadDb() { if (fs.existsSync(dbName)) { From dd46eaee2a81694d3f0e601da32650c672e8f70d Mon Sep 17 00:00:00 2001 From: David McFadzean Date: Wed, 20 Mar 2024 13:53:05 -0400 Subject: [PATCH 5/5] Fix unit tests --- data/wallet.bak | 75 ++++++++++++++++++++++++++++++++++++++++++++++ gatekeeper.test.js | 39 +----------------------- keymaster.js | 2 +- keymaster.test.js | 16 +++++----- 4 files changed, 85 insertions(+), 47 deletions(-) create mode 100644 data/wallet.bak diff --git a/data/wallet.bak b/data/wallet.bak new file mode 100644 index 00000000..79227952 --- /dev/null +++ b/data/wallet.bak @@ -0,0 +1,75 @@ +{ + "seed": { + "mnemonic": "uUl9dUCmlRFDFRUhv7B2YWguG7jY-CaKRYOKj_98RWf10754kRjWby7As4xrCKbsuGV2nX-K1QeAOus7067qeIxFo35gtpdHiOitVWnxn0mHCtiH0PDpsXcKPFwTeI9jq5UEmevLF-B5yn7F2Qz8uXYQ0s-N", + "hdkey": { + "xpriv": "xprv9s21ZrQH143K38fwaCm1SeWdphFLhbUKbnwxdA1oEPsgavcn1nt2vLeRvkkfPy9RoQxCZXfmYNyP977QmpDR3GFK433bgBXSmaPRTBGPoyX", + "xpub": "xpub661MyMwAqRbcFckQgEJ1onTNNj5q74CAy1sZRYRQnjQfTiwvZLCHU8xun3UCVwkGc52yF9bZZbPXaMEpkKjRVuqLRTbCorkxfRmY4WXStK5" + } + }, + "counter": 8, + "ids": { + "David": { + "did": "did:mdip:z3v8AuabNBnymLADSwWpDJPdEhvt2kS5v7UXypjzPnkqfdnW6ri", + "account": 1, + "index": 0, + "owned": [ + "did:mdip:z3v8AuaYMHafTVzrykyRyXjWsTuByAYon8pA7W5iZZtXYBqkMV7", + "did:mdip:z3v8AuaYM272pA9GDrnawbjLmL65Hxc131e9Vt1EqteRHXZkk1J", + "did:mdip:z3v8AuadYk2AHM3oQdwj2d4J5VeG8wzShDkDeHJVXjnXS3Zg2qd", + "did:mdip:z3v8AuagpiowaGV48THePjz41zgqwdVp8x4ThXD34bL7NtUtrzU", + "did:mdip:z3v8AuaggWbYhN2oqwVQCYTeT3whCZyovrXtyPqC4uwwtB2GhN7", + "did:mdip:z3v8AuaYB9P3wMWFQ3nCEZsmEfWfZ9V6Gt1dbmguZfSkPieaEEH", + "did:mdip:z3v8Auaaj52QQxEDrW93xhUdisRxURN8soSrkHtF3P8iXiqWWj8", + "did:mdip:z3v8AuaZu9GYACZvkBBVfTUFPf8Nwe6VjC7eZEiKpb3JBTbSPmg", + "did:mdip:z3v8AuahQDpnHEPkHgbhKabjSbSH8Vi8fKhahCxDqZVRGhaS962" + ], + "held": [ + "did:mdip:z3v8AuaboMc8LJW7k1Rn23qjaJMoH6vMrfnU4ouprsSayy9QE4f" + ] + }, + "Alpha": { + "did": "did:mdip:z3v8AuackpFBm4kgetF7qYk88HvWthGY9VewyKqYDV5xogMNWVd", + "account": 1, + "index": 6, + "owned": [ + "did:mdip:z3v8AuaboMc8LJW7k1Rn23qjaJMoH6vMrfnU4ouprsSayy9QE4f", + "did:mdip:z3v8AuabiAPcUDB9zDc9HB8reUXfR4BorbbuDSCZP616NEYD6FN" + ] + }, + "Bubba": { + "did": "did:mdip:z3v8Auafr3xUZnciBuRiwpyifuot342JwBw4weCvvAohSncYx1t", + "account": 4, + "index": 2, + "owned": [ + "did:mdip:z3v8AuabyKpKraCMjveuxGbPeDGbg394ZvL4sa4v4HsDewMEGAH", + "did:mdip:z3v8AuaeJkyqtUZbK84rD18TcWycKHSsKoXLEk7Gvb6bTUsJ7LE", + "did:mdip:z3v8AuaeGum7MN7rDCUMPcC19DFwPNPMs233vQRHxD8anXEc4qG", + "did:mdip:z3v8Auaf8QrrFEaGxK2apUwBk9MbntxWgyqfXMHiQ9PV6CTr8kt", + "did:mdip:z3v8AuacTHXEtMfaNdkP2Y9P1YeVUeAQPTLhdCFUiPRskZc1jpi", + "did:mdip:z3v8AuababPKv4HGPpv9UYyHQZu5TnCYyR2H5DdALwb2aG29Wga", + "did:mdip:z3v8AuaTdLaYU9Apvyedk4XNwaFGU8voHtFGfijEjPsCtxtHBXL", + "did:mdip:z3v8AuagpnR5qtVgXp5FfwL5xtP1i7udRWoHVRN4xRJxbBop9sc", + "did:mdip:z3v8Auah2jBurFYwJUeDYgMsfdznNPxFytuLM8VnuEGsq5uzBhm", + "did:mdip:z3v8AuagKPzo4JzQR9HmTgL7k4tkJrnpnmNGLJmcPWe83JHmEnm", + "did:mdip:z3v8AuagoYAu9KSs3Uzmj2bSwocdydBJe7WV4DYFvXnjEokcVA3", + "did:mdip:z3v8AuaXRBuGV3cpXKghCixa1UuWvhz7JpXffqYR9M9jwMaD199", + "did:mdip:z3v8AuabPSrC1SxF3UC5X8WEzn3ZZr1T9pk8vP5sHczjUfQCn55" + ] + } + }, + "current": "Bubba", + "names": { + "social": "did:mdip:z3v8AuaYMHafTVzrykyRyXjWsTuByAYon8pA7W5iZZtXYBqkMV7", + "Alex": "did:mdip:z3v8AuajuYULXU4mxx3jWTaMFtiNNncLAJew3j85acdkr9P4XaW", + "Christian": "did:mdip:z3v8AuacJqNkwUrSRDcbvXWNWw3GPLksq2iGzC4EPmSBc7FuxGN", + "Vigas": "did:mdip:z3v8AuafCzChd82dqhgUW8v3gtQXGQcAUBjjmrrgoGE5h1LuhUA", + "twitter": "did:mdip:z3v8AuaboMc8LJW7k1Rn23qjaJMoH6vMrfnU4ouprsSayy9QE4f", + "me": "did:mdip:z3v8AuabNBnymLADSwWpDJPdEhvt2kS5v7UXypjzPnkqfdnW6ri", + "flaxscrip": "did:mdip:z3v8AuaeNsiAhhDjkDyHCVrwAo73NQsnTzX2UoziGPaegt5SHPR", + "email": "did:mdip:z3v8Auaaj52QQxEDrW93xhUdisRxURN8soSrkHtF3P8iXiqWWj8", + "ch1": "did:mdip:z3v8AuacTHXEtMfaNdkP2Y9P1YeVUeAQPTLhdCFUiPRskZc1jpi", + "ch2": "did:mdip:z3v8AuagKPzo4JzQR9HmTgL7k4tkJrnpnmNGLJmcPWe83JHmEnm", + "ch3": "did:mdip:z3v8AuabiAPcUDB9zDc9HB8reUXfR4BorbbuDSCZP616NEYD6FN", + "rsp3": "did:mdip:z3v8AuahQDpnHEPkHgbhKabjSbSH8Vi8fKhahCxDqZVRGhaS962" + } +} \ No newline at end of file diff --git a/gatekeeper.test.js b/gatekeeper.test.js index 4ab878f9..15214e0a 100644 --- a/gatekeeper.test.js +++ b/gatekeeper.test.js @@ -109,7 +109,7 @@ async function createAssetTxn(agent, keypair) { mdip: { version: 1, type: "asset", - registry: "BTC", + registry: "hyperswarm", }, controller: agent, data: "mockData", @@ -147,43 +147,6 @@ describe('createDID', () => { expect(did.startsWith('did:mdip:')); }); - it('should create DID for peerbit registry', async () => { - mockFs({}); - - const keypair = cipher.generateRandomJwk(); - const agentTxn = await createAgentTxn(keypair, 1, 'peerbit'); - - const did = await gatekeeper.createDID(agentTxn); - - expect(did.length).toBe(60); - expect(did.startsWith('did:mdip:')); - }); - - - it('should create DID for BTC registry', async () => { - mockFs({}); - - const keypair = cipher.generateRandomJwk(); - const agentTxn = await createAgentTxn(keypair, 1, 'BTC'); - - const did = await gatekeeper.createDID(agentTxn); - - expect(did.length).toBe(60); - expect(did.startsWith('did:mdip:')); - }); - - it('should create DID for tBTC registry', async () => { - mockFs({}); - - const keypair = cipher.generateRandomJwk(); - const agentTxn = await createAgentTxn(keypair, 1, 'tBTC'); - - const did = await gatekeeper.createDID(agentTxn); - - expect(did.length).toBe(60); - expect(did.startsWith('did:mdip:')); - }); - it('should create DID for local registry', async () => { mockFs({}); diff --git a/keymaster.js b/keymaster.js index 346bf7be..3de4f717 100644 --- a/keymaster.js +++ b/keymaster.js @@ -67,7 +67,7 @@ export function loadWallet() { return newWallet(); } -export async function backupWallet(registry = 'BTC') { +export async function backupWallet(registry = defaultRegistry) { const wallet = loadWallet(); const keypair = hdKeyPair(); const msg = JSON.stringify(wallet); diff --git a/keymaster.test.js b/keymaster.test.js index 5a9760ed..0d4f1790 100644 --- a/keymaster.test.js +++ b/keymaster.test.js @@ -1244,10 +1244,10 @@ describe('verifyResponse', () => { it('should demonstrate full workflow', async () => { mockFs({}); - const alice = await keymaster.createId('Alice', 'BTC'); - const bob = await keymaster.createId('Bob', 'tBTC'); - const carol = await keymaster.createId('Carol', 'peerbit'); - const victor = await keymaster.createId('Victor', 'peerbit'); + const alice = await keymaster.createId('Alice'); + const bob = await keymaster.createId('Bob'); + const carol = await keymaster.createId('Carol'); + const victor = await keymaster.createId('Victor'); keymaster.useId('Alice'); @@ -1257,8 +1257,8 @@ describe('verifyResponse', () => { const bc1 = await keymaster.bindCredential(credential1, carol); const bc2 = await keymaster.bindCredential(credential2, carol); - const vc1 = await keymaster.attestCredential(bc1, 'BTC'); - const vc2 = await keymaster.attestCredential(bc2, 'BTC'); + const vc1 = await keymaster.attestCredential(bc1); + const vc2 = await keymaster.attestCredential(bc2); keymaster.useId('Bob'); @@ -1268,8 +1268,8 @@ describe('verifyResponse', () => { const bc3 = await keymaster.bindCredential(credential3, carol); const bc4 = await keymaster.bindCredential(credential4, carol); - const vc3 = await keymaster.attestCredential(bc3, 'tBTC'); - const vc4 = await keymaster.attestCredential(bc4, 'tBTC'); + const vc3 = await keymaster.attestCredential(bc3); + const vc4 = await keymaster.attestCredential(bc4); keymaster.useId('Carol');