Skip to content

Commit

Permalink
Merge pull request #242 from transmute-industries/feat/multiple-did-d…
Browse files Browse the repository at this point in the history
…ocuments-per-wallet

Allow to have multiple did documents for one wallet
  • Loading branch information
gjgd committed Feb 1, 2019
2 parents bb86ac6 + 4c2c06a commit de8e36b
Show file tree
Hide file tree
Showing 15 changed files with 86 additions and 49 deletions.
2 changes: 1 addition & 1 deletion packages/transmute-did/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@transmute/transmute-did",
"version": "1.1.4",
"version": "1.1.7",
"description": "",
"main": "./src/index.js",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ describe('EcdsaKoblitzSignature2016', () => {
tags: ['EcdsaKoblitzSignature2016'],
notes: 'created for testing purposes',
did: {
primaryKeyOf: did,
publicKey: true,
authentication: true,
publicKeyType: 'publicKeyHex',
Expand Down Expand Up @@ -132,7 +131,7 @@ describe('EcdsaKoblitzSignature2016', () => {
});
} catch (e) {
expect(e.message).toBe(
'No primary key was found',
'Creator key is not present in resolved DID Document. Catch this error and consider the key revoked.',
);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ describe('OpenPgpSignature2019', () => {
tags: ['OpenPgpSignature2019', 'PROPOSAL'],
notes: 'created for testing purposes',
did: {
primaryKeyOf: did,
publicKey: true,
authentication: true,
publicKeyType: 'publicKeyPem',
Expand Down Expand Up @@ -129,7 +128,7 @@ describe('OpenPgpSignature2019', () => {
});
} catch (e) {
expect(e.message).toBe(
'No primary key was found',
'Creator key is not present in resolved DID Document. Catch this error and consider the key revoked.',
);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ describe('RsaSignature2017', () => {
tags: ['RsaSignature2017', 'Mastodon'],
notes: 'created for testing purposes',
did: {
primaryKeyOf: did,
publicKey: true,
authentication: true,
publicKeyType: 'publicKeyPem',
Expand Down Expand Up @@ -109,7 +108,7 @@ describe('RsaSignature2017', () => {
});
} catch (e) {
expect(e.message).toBe(
'No primary key was found',
'Creator key is not present in resolved DID Document. Catch this error and consider the key revoked.',
);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const setup = async () => {
tags: ['OpenPGP.js', 'macbook pro'],
notes: 'created for testing purposes',
did: {
primaryKeyOf: did,
publicKey: true,
authentication: true,
publicKeyType: 'publicKeyPem',
Expand Down Expand Up @@ -91,7 +90,6 @@ describe('didRevocation', () => {
tags: ['OpenPGP.js', 'macbook pro'],
notes: 'created for testing purposes',
did: {
primaryKeyOf: did,
publicKey: true,
authentication: true,
publicKeyType: 'publicKeyPem',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
],
"notes": "created for testing purposes",
"did": {
"primaryKeyOf": "did:test:A",
"publicKey": true,
"authentication": true,
"publicKeyType": "publicKeyPem",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
],
"notes": "created for testing purposes",
"did": {
"primaryKeyOf": "did:test:B",
"publicKey": true,
"authentication": true,
"publicKeyType": "publicKeyPem",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
],
"notes": "created for testing purposes",
"did": {
"primaryKeyOf": "did:test:C",
"publicKey": true,
"authentication": true,
"publicKeyType": "publicKeyPem",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
],
"notes": "created for testing purposes",
"did": {
"primaryKeyOf": "did:test:D",
"publicKey": true,
"authentication": true,
"publicKeyType": "publicKeyPem",
Expand Down
1 change: 1 addition & 0 deletions packages/transmute-did/src/lib/misc/__tests__/misc.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const openpgpExtensions = require('../../cryptoSuites/openpgpExtensions');
const sodiumExtensions = require('../../cryptoSuites/sodiumExtensions');

describe('misc', () => {
// TODO: refactor that
describe('publicKeysToDIDDocument', () => {
let didDocument;
let primaryPublicKey;
Expand Down
1 change: 1 addition & 0 deletions packages/transmute-did/src/lib/misc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const publicKeyToTransmuteDID = ({ publicKey }) => `did:tst:0x${keccak256(public
* @param {String} libSodiumPublicEncryptionKey libsodium public key in hex
* @returns {Object} a DID Document
*/
// TODO: refactor that. Potentially remove this code?
const publicKeysToDIDDocument = ({
primaryPublicKey,
pgpPublicKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const orbitDBKID = '5c51560bcef78d176b726a00b27ad3ef533ae39ef3d0f514392c79988c40

const passphrase = 'yolo';
const did = 'did:test:0x123';
const did2 = 'did:test:0x456';

const fullWallet = JSON.parse(fs.readFileSync(fullWalletPath).toString());

Expand All @@ -28,4 +29,5 @@ module.exports = {
orbitDBKID,
passphrase,
did,
did2,
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
"version": "openpgp@^4.0.1",
"tags": [
"OpenPGP.js",
"macbook pro"
"macbook pro",
"wallet2"
],
"notes": "created for testing purposes",
"did": {
"primaryKeyOf": "did:test:0x123",
"publicKey": true,
"authentication": true,
"publicKeyType": "publicKeyPem",
Expand All @@ -35,7 +35,8 @@
"meta": {
"version": "elliptic@^6.4.1",
"tags": [
"Ethereum"
"Ethereum",
"wallet1"
],
"notes": "Ethereum keypair",
"did": {
Expand Down Expand Up @@ -79,7 +80,8 @@
"version": "elliptic@^6.4.1",
"tags": [
"OrbitDB",
"macbook pro"
"macbook pro",
"wallet1"
],
"notes": "created for testing purposes",
"did": {
Expand All @@ -102,7 +104,8 @@
"version": "libsodium-wrappers@^0.7.3",
"tags": [
"signing key",
"macbook pro"
"macbook pro",
"wallet2"
],
"notes": "created for testing purposes",
"did": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
orbitDBKID,
passphrase,
did,
did2,
} = require('./__fixtures__/testParams');

const proofSet = [
Expand Down Expand Up @@ -63,8 +64,9 @@ describe('toDIDDocument', () => {
proofSet: [{ kid: constructDIDPublicKeyID(did, openPGPKID), password: passphrase }],
});
expect(doc).toBeDefined();
const primaryKid = doc.data.publicKey[0].id.split('kid=')[1];
expect(primaryKid).toBe(openPGPKID);
const kids = doc.data.publicKey
.map(key => key.id.split('kid=')[1]);
expect(kids).toContain(openPGPKID);

fs.writeFileSync(openpgpDIDDocPath, stringify(doc, null, 2));
});
Expand All @@ -91,15 +93,48 @@ describe('toDIDDocument', () => {
});

it('supports exporting a did document for an ethereum keypair', async () => {
delete wallet.data.keystore[openPGPKID].meta.did.primaryKeyOf;
wallet.data.keystore[ethereumKID].meta.did.primaryKeyOf = 'did:test:0x123';
const doc = await wallet.toDIDDocument({
did,
proofSet: [{ kid: constructDIDPublicKeyID(did, ethereumKID), password: passphrase }],
});
expect(doc).toBeDefined();
const primaryKid = doc.data.publicKey[0].id.split('kid=')[1];
expect(primaryKid).toBe(ethereumKID);
wallet.data.keystore[openPGPKID].meta.did.primaryKeyOf = 'did:test:0x123';
const kids = doc.data.publicKey
.map(key => key.id.split('kid=')[1]);
expect(kids).toContain(ethereumKID);
});
});

describe('toDIDDocumentByTag', () => {
let wallet;

beforeAll(async () => {
wallet = new TransmuteDIDWallet(JSON.parse(fs.readFileSync(fullWalletPath).toString()));
});

it('supports exporting a did document by chosing the keys by tag', async () => {
const doc = await wallet.toDIDDocumentByTag({
did: did2,
tag: 'wallet1',
});
expect(doc).toBeDefined();
const kids = doc.data.publicKey
.map(key => key.id.split('kid=')[1]);
expect(kids).toContain(ethereumKID);
expect(kids).toContain(orbitDBKID);
// This one does not have the 'wallet1' tag
expect(kids).not.toContain('4c22585330c9150c3e61ffc668963ec0e841c14396e638561312bc518c371b6a');
});

it('supports exporting a different did document by chosing the keys by tag from the same wallet', async () => {
const doc = await wallet.toDIDDocumentByTag({
did,
tag: 'wallet2',
});
expect(doc).toBeDefined();
const kids = doc.data.publicKey
.map(key => key.id.split('kid=')[1]);
expect(kids).toContain(openPGPKID);
expect(kids).toContain(libsodiumKID);
expect(kids).toHaveLength(2);
});
});
52 changes: 28 additions & 24 deletions packages/transmute-did/src/lib/wallet/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,14 @@ const {
// eslint-disable-next-line
const { sha3_256 } = require('js-sha3');

const getPrimaryKidForDid = (did, keystore) => {
const primaryKeys = Object.values(keystore)
.filter(key => key.meta && key.meta.did && key.meta.did.primaryKeyOf === did);
if (primaryKeys.length > 1) {
throw new Error('More than one primary key was found');
}
if (primaryKeys.length < 1) {
throw new Error('No primary key was found');
}
return primaryKeys[0].kid;
};

const constructPublicKeysProperty = (did, keystore) => {
const primaryKID = getPrimaryKidForDid(did, keystore);
const orderedPublicKeys = Object.values(keystore)
.filter(key => key.meta && key.meta.did && key.meta.did.publicKey)
// Primary key first
.sort((key1, key2) => {
if (key1.kid === primaryKID) {
return -1;
}
if (key2.kid === primaryKID) {
return 1;
}
return 0;
})
.map((key) => {
const publicKey = {
// TODO: this id should be constructed outside of this file
// and the way it is constructed should be a function of the
// did method used
id: constructDIDPublicKeyID(did, key.kid),
type: key.meta.did.signatureType,
owner: did,
Expand All @@ -63,6 +43,7 @@ const constructPublicKeysProperty = (did, keystore) => {
};

const constructAuthenticationProperty = (did, keystore) => {
// TODO: refactor
const allPublicKeys = _.values(keystore);
const onlyAuthentricationKeys = _.filter(
allPublicKeys,
Expand Down Expand Up @@ -103,6 +84,7 @@ class TransmuteDIDWallet {
type,
meta,
};
return kid;
}

async encrypt(passphrase) {
Expand Down Expand Up @@ -201,6 +183,29 @@ class TransmuteDIDWallet {
});
}

async toDIDDocumentByTag({ did, tag }) {
const filteredKeystore = Object.values(this.data.keystore)
.filter(key => key.meta.tags.includes(tag))
.reduce((acc, key) => Object.assign(acc, {
[key.kid]: key,
}), {});
const publicKey = await constructPublicKeysProperty(did, filteredKeystore);
const authentication = await constructAuthenticationProperty(did, filteredKeystore);

const doc = {
'@context': 'https://w3id.org/did/v1',
id: did,
publicKey,
authentication,
};

return {
schema: schema.schemaToURI(schema.schemas.didDocument),
data: doc,
};
}

// TODO: refactor (should be renamed and restructured)
async toDIDDocument({ did, proofSet, cacheLocal }) {
const publicKey = await constructPublicKeysProperty(did, this.data.keystore);
const authentication = await constructAuthenticationProperty(did, this.data.keystore);
Expand Down Expand Up @@ -240,5 +245,4 @@ module.exports = {
TransmuteDIDWallet,
createWallet,
constructDIDPublicKeyID,
getPrimaryKidForDid,
};

0 comments on commit de8e36b

Please sign in to comment.