@microsoft/useragent-sdk
Version:
SDK for building decentralized identity wallets and enterprise agents.
169 lines • 8.98 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const SidetreeRegistrar_1 = require("../../src/registrars/SidetreeRegistrar");
const IdentifierDocument_1 = require("../../src/IdentifierDocument");
const Identifier_1 = require("../../src/Identifier");
const UserAgentError_1 = require("../../src/UserAgentError");
const UserAgentOptions_1 = require("../../src/UserAgentOptions");
const CryptoFactory_1 = require("../../src/crypto/plugin/CryptoFactory");
const KeyStoreInMemory_1 = require("../../src/crypto/keyStore/KeyStoreInMemory");
const OctKey_1 = require("../../src/crypto/keys/Oct/OctKey");
const SubtleCryptoNode_1 = require("../../src/crypto/plugin/SubtleCryptoNode");
const KeyContainer_1 = require("../../src/crypto/keys/KeyContainer");
let fetchMock;
// Add a document to the cache
const DOCUMENT = {
'@context': 'https://w3id.org/did/v1',
'id': 'did:test:identifier'
};
describe('SidetreeRegistrar', () => {
let options;
beforeAll(() => {
fetchMock = require('fetch-mock');
options = new UserAgentOptions_1.default();
options.cryptoOptions.signingAlgorithm = 'ES256K';
options.cryptoFactory = new CryptoFactory_1.default(new KeyStoreInMemory_1.default(), SubtleCryptoNode_1.default.getSubtleCrypto());
options.registrar = new SidetreeRegistrar_1.default('https://registrar.org', options);
});
afterEach(() => {
fetchMock.restore();
});
it('should throw because of missing options', async (done) => {
try {
await new SidetreeRegistrar_1.default('https://registrar.org/', {}).register(new IdentifierDocument_1.default(''), '');
fail('Failed to throw because of missing options');
}
catch (err) {
expect('options and options.keyStore need to be defined').toBe(err.message);
done();
}
});
it('should construct new instance of the SidetreeRegistrar', async () => {
let options = new UserAgentOptions_1.default();
options.timeoutInSeconds = 30;
options.keyStore = new KeyStoreInMemory_1.default();
const registrar = new SidetreeRegistrar_1.default('https://registrar.org/', options);
expect(registrar).toBeDefined();
expect(registrar.url).toEqual('https://registrar.org/');
});
it('should construct new instance of the SidetreeRegistrar appending trailing slash', async () => {
let options = new UserAgentOptions_1.default();
options.timeoutInSeconds = 30;
options.keyStore = new KeyStoreInMemory_1.default();
const registrar = new SidetreeRegistrar_1.default('https://registrar.org', options);
expect(registrar).toBeDefined();
expect(registrar.url).toEqual('https://registrar.org/');
});
it('should return a new identifier', async () => {
// Setup registration environment
const seed = new OctKey_1.default('ABDE');
await options.keyStore.save('masterSeed', new KeyContainer_1.default(seed));
let identifier = new Identifier_1.default('did:test:identifier', options);
fetchMock.mock((url, opts) => {
expect(url).toEqual('https://registrar.org/');
expect(opts).toBeDefined();
// Make sure the document has been passed
const body = JSON.parse(opts.body);
expect(body.header).toBeDefined();
// the header should be undefined. commented out for moment to get to identiverse - todo
//expect(body.protected).toBeUndefined();
expect(body.payload).toBeDefined();
expect(body.signature).toBeDefined();
return true;
}, new Promise(resolve => resolve(identifier)), { method: 'POST' });
identifier = await identifier.createLinkedIdentifier('did:ion:peer', true);
expect(identifier).toBeDefined();
});
it('should throw UserAgentError when fetch timeout threshold reached', async (done) => {
options.timeoutInSeconds = 1;
options.registrar = new SidetreeRegistrar_1.default('https://registrar.org/', options);
// Setup registration environment
const seed = new OctKey_1.default('ABDE');
await options.keyStore.save('masterSeed', new KeyContainer_1.default(seed));
const identifier = new Identifier_1.default('did:test:identifier', options);
// Set the mock timeout to be greater than the fetch configuration
// timeout to ensure that the fetch timeout works as expected.
const delay = new Promise((response, _) => setTimeout(response, 1000 * 10));
fetchMock.post('https://registrar.org/', delay.then((_) => 404));
// tslint:disable-next-line: no-floating-promises
identifier.createLinkedIdentifier('did:ion:peer', true)
.then(() => {
fail('No throw detected because of timeout.');
})
.catch((error) => {
expect(error).toBeDefined();
expect(error instanceof UserAgentError_1.default).toBeTruthy();
expect(error.message).toEqual(`Fetch timed out.`);
})
.finally(() => {
options.timeoutInSeconds = 30;
done();
});
});
it('should throw UserAgentError when error returned by registrar', async (done) => {
// Setup registration environment
const seed = new OctKey_1.default('ABDE');
await options.keyStore.save('masterSeed', new KeyContainer_1.default(seed));
const identifier = new Identifier_1.default('did:test:identifier', options);
fetchMock.post('https://registrar.org/', 404);
// tslint:disable-next-line: no-floating-promises
identifier.createLinkedIdentifier('did:ion:peer', true)
.then(() => {
fail('No throw detected because of 404.');
})
.catch((error) => {
expect(error).toBeDefined();
expect(error instanceof UserAgentError_1.default).toBeTruthy();
expect(error.message).toEqual('Failed to register the identifier document: Status 404');
})
.finally(done);
});
it('should throw UserAgentError when generating an identifier and no public key specified', async (done) => {
const registrar = new SidetreeRegistrar_1.default('https://registrar.org', options);
fetchMock.post('https://registrar.org/register', 404);
await registrar
.generateIdentifier(new IdentifierDocument_1.default(DOCUMENT))
.catch((error) => {
expect(error).toBeDefined();
expect(error instanceof UserAgentError_1.default).toBeTruthy();
expect(error.message).toEqual('At least one public key must be specified in the identifier document.');
})
.finally(done);
});
it('should return generated identifier', async () => {
const registrar = new SidetreeRegistrar_1.default('https://registrar.org', options);
const genesisDocument = Object.assign(DOCUMENT, {
publicKeys: [{
id: '#master',
type: 'Secp256k1VerificationKey2018',
publicKeyHex: '02f49802fb3e09c6dd43f19aa41293d1e0dad044b68cf81cf7079499edfd0aa9f1'
}]
});
const identifier = await registrar.generateIdentifier(new IdentifierDocument_1.default(genesisDocument));
expect(identifier).toBeDefined();
expect(identifier.id).toContain('did:ion');
});
it('should always return same identifier when provided same genesis document ', async () => {
const registrar = new SidetreeRegistrar_1.default('https://registrar.org', options);
const genesisDocument = Object.assign(DOCUMENT, {
publicKeys: [{
id: '#master',
type: 'Secp256k1VerificationKey2018',
publicKeyHex: '02f49802fb3e09c6dd43f19aa41293d1e0dad044b68cf81cf7079499edfd0aa9f1'
}]
});
let previousIdentifier = '';
for (let index = 0; index < 20; index++) {
const identifier = await registrar.generateIdentifier(new IdentifierDocument_1.default(genesisDocument));
if (index !== 0) {
expect(identifier.id).toEqual(previousIdentifier);
}
previousIdentifier = identifier.id;
}
});
});
//# sourceMappingURL=SidetreeRegistrar.spec.js.map