Skip to content

Commit

Permalink
Merge pull request #179 from KeychainMDIP/175-group-current-id
Browse files Browse the repository at this point in the history
Refactored updateDID and revokeDID
  • Loading branch information
macterra authored Jun 7, 2024
2 parents 8d1f41b + a287bf9 commit 29b573d
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 21 deletions.
50 changes: 32 additions & 18 deletions keymaster-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,26 +206,38 @@ export function setCurrentId(name) {
}
}

function fetchId(name) {
function fetchId(id) {
const wallet = loadWallet();
let id = null;
let idInfo = null;

if (name) {
id = wallet.ids[name];
if (id) {
if (id.startsWith('did')) {
for (const name of Object.keys(wallet.ids)) {
const info = wallet.ids[name];

if (!id) {
throw "Unknown ID";
if (info.did === id) {
idInfo = info;
break;
}
}
}
else {
idInfo = wallet.ids[id];
}
}
else {
id = wallet.ids[wallet.current];
idInfo = wallet.ids[wallet.current];

if (!id) {
if (!idInfo) {
throw "No current ID";
}
}

return id;
if (!idInfo) {
throw "Unknown ID";
}

return idInfo;
}

function hdKeyPair() {
Expand Down Expand Up @@ -306,10 +318,10 @@ export async function decryptJSON(did) {
return JSON.parse(plaintext);
}

export async function addSignature(obj, name = null) {
export async function addSignature(obj, controller = null) {
// Fetches current ID if name is missing
const id = fetchId(name);
const keypair = fetchKeyPair(name);
const id = fetchId(controller);
const keypair = fetchKeyPair(controller);

try {
const msgHash = cipher.hashJSON(obj);
Expand Down Expand Up @@ -357,7 +369,7 @@ export async function verifySignature(obj) {
}
}

async function updateDID(did, doc, name = null) {
export async function updateDID(did, doc) {
const current = await resolveDID(did);
const prev = cipher.hashJSON(current);

Expand All @@ -368,12 +380,12 @@ async function updateDID(did, doc, name = null) {
prev: prev,
};

// Will sign with current ID if name is missing
const signed = await addSignature(operation, name);
const controller = current.didDocument.controller || current.didDocument.id;
const signed = await addSignature(operation, controller);
return gatekeeper.updateDID(signed);
}

async function revokeDID(did) {
export async function revokeDID(did) {
const current = await resolveDID(did);
const prev = cipher.hashJSON(current);

Expand All @@ -383,7 +395,8 @@ async function revokeDID(did) {
prev: prev,
};

const signed = await addSignature(operation);
const controller = current.didDocument.controller || current.didDocument.id;
const signed = await addSignature(operation, controller);
return gatekeeper.deleteDID(signed);
}

Expand Down Expand Up @@ -533,7 +546,7 @@ export async function backupId(name = null) {
const vaultDid = await createAsset({ backup: backup }, registry, name);

doc.didDocumentData.vault = vaultDid;
const ok = await updateDID(id.did, doc, name);
const ok = await updateDID(id.did, doc);

return ok;
}
Expand Down Expand Up @@ -681,6 +694,7 @@ export async function createAsset(data, registry = defaultRegistry, name = null)
const signed = await addSignature(operation, name);
const did = await gatekeeper.createDID(signed);

// TBD skip if registry is hyperswarm?
addToOwned(did);
return did;
}
Expand Down
118 changes: 115 additions & 3 deletions keymaster.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,111 @@ describe('createAsset', () => {
});
});

describe('updateDID', () => {

afterEach(() => {
mockFs.restore();
});

it('should update an asset DID', async () => {
mockFs({});

await keymaster.createId('Bob');
const mockAnchor = { name: 'mockAnchor' };
const dataDid = await keymaster.createAsset(mockAnchor);
const doc = await keymaster.resolveDID(dataDid);

const dataUpdated = { name: 'updated' };
doc.didDocumentData = dataUpdated;

const ok = await keymaster.updateDID(dataDid, doc);
const doc2 = await keymaster.resolveDID(dataDid);

expect(ok).toBe(true);
expect(doc2.didDocumentData).toStrictEqual(dataUpdated);
expect(doc2.didDocumentMetadata.version).toBe(2);
});

it('should update an asset DID when current ID is not owner ID', async () => {
mockFs({});

const bob = await keymaster.createId('Bob');
await keymaster.createId('Alice');

keymaster.setCurrentId('Bob');

const mockAnchor = { name: 'mockAnchor' };
const dataDid = await keymaster.createAsset(mockAnchor);
const doc = await keymaster.resolveDID(dataDid);

const dataUpdated = { name: 'updated' };
doc.didDocumentData = dataUpdated;

keymaster.setCurrentId('Alice');

const ok = await keymaster.updateDID(dataDid, doc);
const doc2 = await keymaster.resolveDID(dataDid);

expect(ok).toBe(true);
expect(doc2.didDocument.controller).toBe(bob);
expect(doc2.didDocumentData).toStrictEqual(dataUpdated);
expect(doc2.didDocumentMetadata.version).toBe(2);
});
});

describe('revokeDID', () => {

afterEach(() => {
mockFs.restore();
});

it('should revoke an asset DID', async () => {
mockFs({});

await keymaster.createId('Bob');
const mockAnchor = { name: 'mockAnchor' };
const dataDid = await keymaster.createAsset(mockAnchor);
const doc = await keymaster.resolveDID(dataDid);

const dataUpdated = { name: 'updated' };
doc.didDocumentData = dataUpdated;

const ok = await keymaster.revokeDID(dataDid, doc);
const doc2 = await keymaster.resolveDID(dataDid);

expect(ok).toBe(true);
expect(doc2.didDocument).toStrictEqual({});
expect(doc2.didDocumentData).toStrictEqual({});
expect(doc2.didDocumentMetadata.deactivated).toBe(true);
});

it('should revoke an asset DID when current ID is not owner ID', async () => {
mockFs({});

await keymaster.createId('Bob');
await keymaster.createId('Alice');

keymaster.setCurrentId('Bob');

const mockAnchor = { name: 'mockAnchor' };
const dataDid = await keymaster.createAsset(mockAnchor);
const doc = await keymaster.resolveDID(dataDid);

const dataUpdated = { name: 'updated' };
doc.didDocumentData = dataUpdated;

keymaster.setCurrentId('Alice');

const ok = await keymaster.revokeDID(dataDid, doc);
const doc2 = await keymaster.resolveDID(dataDid);

expect(ok).toBe(true);
expect(doc2.didDocument).toStrictEqual({});
expect(doc2.didDocumentData).toStrictEqual({});
expect(doc2.didDocumentMetadata.deactivated).toBe(true);
});
});

function generateRandomString(length) {
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
Expand Down Expand Up @@ -1138,7 +1243,7 @@ describe('revokeCredential', () => {
expect(ok2).toBe(false);
});

it('should return false if user does not control verifiable credential', async () => {
it('should throw exception if user does not control verifiable credential', async () => {
mockFs({});

await keymaster.createId('Alice');
Expand All @@ -1151,9 +1256,16 @@ describe('revokeCredential', () => {
const did = await keymaster.issueCredential(boundCredential);

keymaster.setCurrentId('Bob');
keymaster.removeId('Alice');

try {
await keymaster.revokeCredential(did);
throw ('Expected to throw an exception');
}
catch (error) {
expect(error).toBe('Unknown ID');
}

const ok = await keymaster.revokeCredential(did);
expect(ok).toBe(false);
});

it('should import a revoked credential', async () => {
Expand Down

0 comments on commit 29b573d

Please sign in to comment.