From 66dd3c5c39bb37f8af82c0e6b4d67d40b3ef2b2c Mon Sep 17 00:00:00 2001 From: Serhii Nanovskyi Date: Thu, 5 Sep 2019 15:12:20 +0300 Subject: [PATCH 1/6] Update --- package.json | 12 ++--- src/CloudEntrySerializer.ts | 17 +++---- src/CloudKeyStorage.ts | 22 ++++----- src/KeyEntryUtils.ts | 2 +- src/KeyknoxManager.ts | 30 ++++++------ src/SyncKeyStorage.ts | 20 ++++---- src/__tests__/CloudEntrySerializer.test.ts | 12 ++--- src/__tests__/CloudKeyStorage.test.ts | 19 ++++---- src/__tests__/KeyEntryStorageWrapper.test.ts | 41 ++++++++-------- src/__tests__/KeyEntryUtils.test.ts | 9 ++-- src/__tests__/KeyknoxManager.test.ts | 49 ++++++++++---------- src/__tests__/SyncKeyStorage.test.ts | 43 +++++++++-------- src/clients/IKeyknoxClient.ts | 6 +-- src/clients/KeyknoxClient.ts | 22 ++++----- src/clients/__tests__/KeyknoxClient.test.ts | 42 ++++++++--------- src/cryptos/IKeyknoxCrypto.ts | 6 +-- src/cryptos/KeyknoxCrypto.ts | 43 +++++++++++------ src/cryptos/__tests__/KeyknoxCrypto.test.ts | 17 +++---- src/entities.ts | 10 ++-- src/types.ts | 12 +++-- 20 files changed, 218 insertions(+), 216 deletions(-) diff --git a/package.json b/package.json index 319d841..d7db65a 100644 --- a/package.json +++ b/package.json @@ -15,16 +15,16 @@ "lint": "eslint 'src/**/*.ts'", "test": "mocha -t 0 -r setup-mocha -r ts-node/register src/**/*.test.ts", "build": "rollup -c", - "clean": "rimraf .rpt2_cache .virgil_key_entries dist", - "prepare": "npm run clean && npm run build" + "clean": "rimraf .rpt2_cache .virgil_key_entries dist" }, "dependencies": { + "@types/base-64": "^0.1.3", + "@virgilsecurity/crypto-types": "^0.1.3", "axios": "^0.19.0", - "buffer": "^5.2.1" + "base-64": "^0.1.0" }, "peerDependencies": { - "@virgilsecurity/base-crypto": "^0.1.0", - "virgil-sdk": "^5.3.0" + "virgil-sdk": "next" }, "devDependencies": { "@types/chai": "^4.1.7", @@ -50,6 +50,6 @@ "typescript": "^3.5.1", "uuid": "^3.3.2", "virgil-crypto": "next", - "virgil-sdk": "^5.3.0" + "virgil-sdk": "next" } } diff --git a/src/CloudEntrySerializer.ts b/src/CloudEntrySerializer.ts index ea5e52c..3e53d18 100644 --- a/src/CloudEntrySerializer.ts +++ b/src/CloudEntrySerializer.ts @@ -1,4 +1,4 @@ -import { Buffer as NodeBuffer } from 'buffer'; +import base64 from 'base-64'; import { CloudEntry } from './entities'; import { Meta } from './types'; @@ -11,11 +11,11 @@ interface SerializedCloudEntry { meta?: Meta | null; } -export function serialize(cloudEntries: Map): Buffer { +export function serialize(cloudEntries: Map) { const entries: { [key: string]: SerializedCloudEntry } = {}; cloudEntries.forEach((value, key) => { entries[key] = { - data: value.data.toString('base64'), + data: value.data, meta: value.meta, // eslint-disable-next-line @typescript-eslint/camelcase creation_date: Number(value.creationDate), @@ -27,19 +27,20 @@ export function serialize(cloudEntries: Map): Buffer { delete entries[key].meta; } }); - return NodeBuffer.from(JSON.stringify(entries)); + return base64.encode(JSON.stringify(entries)); } -export function deserialize(data: Buffer): Map { - if (!data.byteLength) { +export function deserialize(data: string): Map { + const myData = base64.decode(data); + if (!myData.length) { return new Map(); } - const serializedEntries: { [key: string]: SerializedCloudEntry } = JSON.parse(data.toString()); + const serializedEntries: { [key: string]: SerializedCloudEntry } = JSON.parse(myData); return Object.keys(serializedEntries).reduce>((result, key) => { const serializedEntry = serializedEntries[key]; result.set(key, { name: serializedEntry.name, - data: NodeBuffer.from(serializedEntry.data, 'base64'), + data: serializedEntry.data, creationDate: new Date(serializedEntry.creation_date), modificationDate: new Date(serializedEntry.modification_date), meta: typeof serializedEntry.meta === 'undefined' ? null : serializedEntry.meta, diff --git a/src/CloudKeyStorage.ts b/src/CloudKeyStorage.ts index d8d14a7..fc5ee14 100644 --- a/src/CloudKeyStorage.ts +++ b/src/CloudKeyStorage.ts @@ -7,13 +7,7 @@ import { } from './errors'; import KeyknoxManager from './KeyknoxManager'; import { serialize, deserialize } from './CloudEntrySerializer'; -import { - Meta, - VirgilCrypto, - VirgilPrivateKey, - VirgilPublicKey, - IAccessTokenProvider, -} from './types'; +import { Meta, ICrypto, IPrivateKey, IPublicKey, IAccessTokenProvider } from './types'; export default class CloudKeyStorage { private readonly keyknoxManager: KeyknoxManager; @@ -28,9 +22,9 @@ export default class CloudKeyStorage { static create(options: { accessTokenProvider: IAccessTokenProvider; - privateKey: VirgilPrivateKey; - publicKeys: VirgilPublicKey | VirgilPublicKey[]; - virgilCrypto: VirgilCrypto; + privateKey: IPrivateKey; + publicKeys: IPublicKey | IPublicKey[]; + virgilCrypto: ICrypto; }): CloudKeyStorage { const keyknoxManager = new KeyknoxManager( options.accessTokenProvider, @@ -52,12 +46,12 @@ export default class CloudKeyStorage { return keyEntries.map(keyEntry => this.cache.get(keyEntry.name)!); } - async storeEntry(name: string, data: Buffer, meta?: Meta): Promise { + async storeEntry(name: string, data: string, meta?: Meta): Promise { const [cloudEntry] = await this.storeEntries([{ name, data, meta }]); return cloudEntry; } - async updateEntry(name: string, data: Buffer, meta?: Meta): Promise { + async updateEntry(name: string, data: string, meta?: Meta): Promise { this.throwUnlessSyncWasCalled(); this.throwUnlessCloudEntryExists(name); const cloudEntry = CloudKeyStorage.createCloudEntry( @@ -106,8 +100,8 @@ export default class CloudKeyStorage { } async updateRecipients(options: { - newPrivateKey?: VirgilPrivateKey; - newPublicKeys?: VirgilPublicKey | VirgilPublicKey[]; + newPrivateKey?: IPrivateKey; + newPublicKeys?: IPublicKey | IPublicKey[]; }): Promise { this.throwUnlessSyncWasCalled(); const { newPrivateKey, newPublicKeys } = options; diff --git a/src/KeyEntryUtils.ts b/src/KeyEntryUtils.ts index eaa5253..0e3921e 100644 --- a/src/KeyEntryUtils.ts +++ b/src/KeyEntryUtils.ts @@ -8,7 +8,7 @@ export function createKeyEntry( cloudEntry: CloudEntry, ): { name: string; - value: Buffer; + value: string; meta: { [key: string]: string }; } { return { diff --git a/src/KeyknoxManager.ts b/src/KeyknoxManager.ts index 83138ed..be78942 100644 --- a/src/KeyknoxManager.ts +++ b/src/KeyknoxManager.ts @@ -2,31 +2,31 @@ import IKeyknoxClient from './clients/IKeyknoxClient'; import KeyknoxClient from './clients/KeyknoxClient'; import IKeyknoxCrypto from './cryptos/IKeyknoxCrypto'; import { DecryptedKeyknoxValue } from './entities'; -import { VirgilPrivateKey, VirgilPublicKey, IAccessTokenProvider } from './types'; +import { IPrivateKey, IPublicKey, IAccessTokenProvider } from './types'; export default class KeyknoxManager { private readonly SERVICE_NAME = 'keyknox'; private readonly accessTokenProvider: IAccessTokenProvider; - private myPrivateKey: VirgilPrivateKey; - private myPublicKeys: VirgilPublicKey | VirgilPublicKey[]; + private myPrivateKey: IPrivateKey; + private myPublicKeys: IPublicKey | IPublicKey[]; private readonly keyknoxClient: IKeyknoxClient; private readonly keyknoxCrypto: IKeyknoxCrypto; - get privateKey(): VirgilPrivateKey { + get privateKey(): IPrivateKey { return this.myPrivateKey; } - get publicKeys(): VirgilPublicKey | VirgilPublicKey[] { + get publicKeys(): IPublicKey | IPublicKey[] { return this.myPublicKeys; } constructor( accessTokenProvider: IAccessTokenProvider, - privateKey: VirgilPrivateKey, - publicKeys: VirgilPublicKey | VirgilPublicKey[], + privateKey: IPrivateKey, + publicKeys: IPublicKey | IPublicKey[], keyknoxCrypto: IKeyknoxCrypto, keyknoxClient?: IKeyknoxClient, ) { @@ -37,7 +37,7 @@ export default class KeyknoxManager { this.keyknoxClient = keyknoxClient || new KeyknoxClient(); } - async pushValue(value: Buffer, previousHash?: Buffer): Promise { + async pushValue(value: string, previousHash?: string): Promise { const token = await this.accessTokenProvider.getToken({ service: this.SERVICE_NAME, operation: 'put', @@ -74,10 +74,10 @@ export default class KeyknoxManager { } async updateValue(options: { - value: Buffer; - previousHash: Buffer; - newPrivateKey?: VirgilPrivateKey; - newPublicKeys?: VirgilPublicKey | VirgilPublicKey[]; + value: string; + previousHash: string; + newPrivateKey?: IPrivateKey; + newPublicKeys?: IPublicKey | IPublicKey[]; }): Promise { const { value, previousHash, newPrivateKey, newPublicKeys } = options; if (!newPrivateKey && !newPublicKeys) { @@ -109,12 +109,12 @@ export default class KeyknoxManager { } async updateRecipients(options: { - newPrivateKey?: VirgilPrivateKey; - newPublicKeys?: VirgilPublicKey | VirgilPublicKey[]; + newPrivateKey?: IPrivateKey; + newPublicKeys?: IPublicKey | IPublicKey[]; }): Promise { const { newPrivateKey, newPublicKeys } = options; const decryptedKeyknoxValue = await this.pullValue(); - if (!decryptedKeyknoxValue.meta.byteLength && !decryptedKeyknoxValue.value.byteLength) { + if (!decryptedKeyknoxValue.meta.length && !decryptedKeyknoxValue.value.length) { return decryptedKeyknoxValue; } if (newPrivateKey) { diff --git a/src/SyncKeyStorage.ts b/src/SyncKeyStorage.ts index ab92a50..67433a9 100644 --- a/src/SyncKeyStorage.ts +++ b/src/SyncKeyStorage.ts @@ -5,9 +5,9 @@ import KeyEntryStorageWrapper from './KeyEntryStorageWrapper'; import { createKeyEntry, extractDate } from './KeyEntryUtils'; import { Meta, - VirgilCrypto, - VirgilPrivateKey, - VirgilPublicKey, + ICrypto, + IPrivateKey, + IPublicKey, IAccessTokenProvider, IKeyEntry, IKeyEntryStorage, @@ -29,9 +29,9 @@ export default class SyncKeyStorage { static create(options: { identity: string; accessTokenProvider: IAccessTokenProvider; - privateKey: VirgilPrivateKey; - publicKeys: VirgilPublicKey | VirgilPublicKey[]; - virgilCrypto: VirgilCrypto; + privateKey: IPrivateKey; + publicKeys: IPublicKey | IPublicKey[]; + virgilCrypto: ICrypto; keyEntryStorage: IKeyEntryStorage; }): SyncKeyStorage { const { virgilCrypto, identity, accessTokenProvider, privateKey, publicKeys } = options; @@ -55,12 +55,12 @@ export default class SyncKeyStorage { return Promise.all(storeRequests); } - async storeEntry(name: string, data: Buffer, meta?: Meta): Promise { + async storeEntry(name: string, data: string, meta?: Meta): Promise { const [keyEntry] = await this.storeEntries([{ name, data, meta }]); return keyEntry; } - async updateEntry(name: string, data: Buffer, meta?: Meta): Promise { + async updateEntry(name: string, data: string, meta?: Meta): Promise { await this.throwUnlessKeyEntryExists(name); const cloudEntry = await this.cloudKeyStorage.updateEntry(name, data, meta); const keyEntry = createKeyEntry(cloudEntry); @@ -96,8 +96,8 @@ export default class SyncKeyStorage { } async updateRecipients(options: { - newPrivateKey?: VirgilPrivateKey; - newPublicKeys?: VirgilPublicKey | VirgilPublicKey[]; + newPrivateKey?: IPrivateKey; + newPublicKeys?: IPublicKey | IPublicKey[]; }): Promise { const { newPrivateKey, newPublicKeys } = options; return this.cloudKeyStorage.updateRecipients({ newPrivateKey, newPublicKeys }); diff --git a/src/__tests__/CloudEntrySerializer.test.ts b/src/__tests__/CloudEntrySerializer.test.ts index feb2448..6955662 100644 --- a/src/__tests__/CloudEntrySerializer.test.ts +++ b/src/__tests__/CloudEntrySerializer.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import { serialize, deserialize } from '../CloudEntrySerializer'; @@ -12,7 +11,7 @@ describe('CloudEntrySerializer', () => { cloudData.kName1, { name: cloudData.kName1, - data: NodeBuffer.from(cloudData.kData1, 'base64'), + data: cloudData.kData1, creationDate: new Date(cloudData.kCreationDate1), modificationDate: new Date(cloudData.kModificationDate1), meta: cloudData.kMeta1, @@ -22,7 +21,7 @@ describe('CloudEntrySerializer', () => { cloudData.kName2, { name: cloudData.kName2, - data: NodeBuffer.from(cloudData.kData2, 'base64'), + data: cloudData.kData2, creationDate: new Date(cloudData.kCreationDate2), modificationDate: new Date(cloudData.kModificationDate2), meta: cloudData.kMeta2, @@ -30,14 +29,13 @@ describe('CloudEntrySerializer', () => { ], ]); const serialized1 = serialize(cloudEntries); - const expectedSerialized1 = NodeBuffer.from(cloudData.kExpectedResult, 'base64'); - expect(serialized1.equals(expectedSerialized1)).to.be.true; - const deserialized = deserialize(expectedSerialized1); + expect(serialized1).to.equal(cloudData.kExpectedResult); + const deserialized = deserialize(cloudData.kExpectedResult); expect(deserialized).to.eql(cloudEntries); }); it('KTC-18', () => { - const result = deserialize(NodeBuffer.alloc(0)); + const result = deserialize(''); expect(result).to.eql(new Map()); }); }); diff --git a/src/__tests__/CloudKeyStorage.test.ts b/src/__tests__/CloudKeyStorage.test.ts index 9668c12..c4860a4 100644 --- a/src/__tests__/CloudKeyStorage.test.ts +++ b/src/__tests__/CloudKeyStorage.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import uuid from 'uuid/v4'; @@ -26,8 +25,8 @@ function generateKeyEntries(amount: number): KeyEntry[] { for (let i = 0; i < amount; i += 1) { keyEntries.push({ name: uuid(), - data: NodeBuffer.from(`data${i}`), - meta: { meta: `meta${i}` }, + data: 'ZGF0YQ==', + meta: { meta: 'meta' }, }); } return keyEntries; @@ -79,12 +78,12 @@ describe('CloudKeyStorage', () => { await cloudKeyStorage.storeEntry(keyEntry.name, keyEntry.data, keyEntry.meta); let cloudEntry = cloudKeyStorage.retrieveEntry(keyEntry.name); expect(cloudEntry.name).to.equal(keyEntry.name); - expect(cloudEntry.data.equals(keyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(keyEntry.data); expect(cloudEntry.meta).to.eql(keyEntry.meta); await cloudKeyStorage.retrieveCloudEntries(); cloudEntry = cloudKeyStorage.retrieveEntry(keyEntry.name); expect(cloudEntry.name).to.equal(keyEntry.name); - expect(cloudEntry.data.equals(keyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(keyEntry.data); expect(cloudEntry.meta).to.eql(keyEntry.meta); }); @@ -104,7 +103,7 @@ describe('CloudKeyStorage', () => { cloudEntries.forEach(cloudEntry => { const keyEntry = keyEntries[cloudEntry.name]; expect(keyEntry).not.to.be.undefined; - expect(cloudEntry.data.equals(keyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(keyEntry.data); expect(cloudEntry.meta).to.eql(keyEntry.meta); }); } @@ -183,7 +182,7 @@ describe('CloudKeyStorage', () => { const keyEntries = generateKeyEntries(10); const updatedKeyEntry = { ...keyEntries[0], - data: NodeBuffer.from('newData'), + data: 'bmV3RGF0YQ==', meta: { meta: 'newMeta' }, }; await cloudKeyStorage.retrieveCloudEntries(); @@ -195,12 +194,12 @@ describe('CloudKeyStorage', () => { ); let cloudEntry = cloudKeyStorage.retrieveEntry(updatedKeyEntry.name); expect(cloudEntry.name).to.equal(updatedKeyEntry.name); - expect(cloudEntry.data.equals(updatedKeyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(updatedKeyEntry.data); expect(cloudEntry.meta).to.eql(updatedKeyEntry.meta); await cloudKeyStorage.retrieveCloudEntries(); cloudEntry = cloudKeyStorage.retrieveEntry(updatedKeyEntry.name); expect(cloudEntry.name).to.equal(updatedKeyEntry.name); - expect(cloudEntry.data.equals(updatedKeyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(updatedKeyEntry.data); expect(cloudEntry.meta).to.eql(updatedKeyEntry.meta); }); @@ -289,7 +288,7 @@ describe('CloudKeyStorage', () => { new KeyknoxCrypto(virgilCrypto), ); cloudKeyStorage = new CloudKeyStorage(keyknoxManager); - await keyknoxManager.pushValue(NodeBuffer.from(uuid())); + await keyknoxManager.pushValue(uuid()); await cloudKeyStorage.deleteAllEntries(); await cloudKeyStorage.retrieveCloudEntries(); let entries = cloudKeyStorage.retrieveAllEntries(); diff --git a/src/__tests__/KeyEntryStorageWrapper.test.ts b/src/__tests__/KeyEntryStorageWrapper.test.ts index 5109a1f..08e9da1 100644 --- a/src/__tests__/KeyEntryStorageWrapper.test.ts +++ b/src/__tests__/KeyEntryStorageWrapper.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import { join } from 'path'; @@ -19,7 +18,7 @@ describe('KeyEntryStorageWrapper', () => { describe('save', () => { it('stores entry in `KeyEntryStorage`', async () => { - await keyEntryStorageWrapper.save({ name: 'name', value: NodeBuffer.from('value') }); + await keyEntryStorageWrapper.save({ name: 'name', value: 'dmFsdWU=' }); const keyEntries = await keyEntryStorage.list(); expect(keyEntries).to.have.length(1); }); @@ -27,13 +26,13 @@ describe('KeyEntryStorageWrapper', () => { it('stores correct values in `KeyEntryStorage`', async () => { const keyEntry = await keyEntryStorageWrapper.save({ name: 'name', - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', meta: { key: 'value', }, }); const [storedKeyEntry] = await keyEntryStorage.list(); - expect(storedKeyEntry.value.equals(keyEntry.value)).to.be.true; + expect(storedKeyEntry.value).to.equal(keyEntry.value); expect(storedKeyEntry.meta).to.eql(keyEntry.meta); expect(storedKeyEntry.creationDate).to.eql(keyEntry.creationDate); expect(storedKeyEntry.modificationDate).to.eql(keyEntry.modificationDate); @@ -42,11 +41,11 @@ describe('KeyEntryStorageWrapper', () => { it('stores entries in separate namespace', async () => { const params1 = { name: 'name', - value: NodeBuffer.from('value1'), + value: 'dmFsdWUx', }; const params2 = { name: params1.name, - value: NodeBuffer.from('value2'), + value: 'dmFsdWUy', }; await keyEntryStorage.save(params1); await keyEntryStorageWrapper.save(params2); @@ -59,7 +58,7 @@ describe('KeyEntryStorageWrapper', () => { it('returns an `IKeyEntry` object if entry exists', async () => { const params = { name: 'name', - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', }; await keyEntryStorageWrapper.save(params); const keyEntry = await keyEntryStorageWrapper.load(params.name); @@ -69,7 +68,7 @@ describe('KeyEntryStorageWrapper', () => { it('returns an `IKeyEntry` object with correct values', async () => { const params = { name: 'name', - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', meta: { key: 'value', }, @@ -77,7 +76,7 @@ describe('KeyEntryStorageWrapper', () => { await keyEntryStorageWrapper.save(params); const keyEntry = await keyEntryStorageWrapper.load(params.name); expect(keyEntry!.name).to.equal(params.name); - expect(keyEntry!.value.equals(params.value)).to.be.true; + expect(keyEntry!.value).to.equal(params.value); expect(keyEntry!.meta).to.eql(params.meta); }); @@ -91,7 +90,7 @@ describe('KeyEntryStorageWrapper', () => { it('returns `true` if entry exists', async () => { const params = { name: 'name', - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', }; await keyEntryStorageWrapper.save(params); const result = await keyEntryStorageWrapper.exists(params.name); @@ -108,11 +107,11 @@ describe('KeyEntryStorageWrapper', () => { it('should not remove entries created outside of `KeyEntryStorageWrapper`', async () => { const params1 = { name: 'name', - value: NodeBuffer.from('value1'), + value: 'dmFsdWUx', }; const params2 = { name: params1.name, - value: NodeBuffer.from('value2'), + value: 'dmFsdWUy', }; await keyEntryStorage.save(params1); await keyEntryStorageWrapper.save(params2); @@ -124,9 +123,9 @@ describe('KeyEntryStorageWrapper', () => { describe('list', () => { it('returns entries except ones created outside of `KeyEntryStorageWrapper`', async () => { - await keyEntryStorage.save({ name: 'name', value: NodeBuffer.from('value') }); - await keyEntryStorageWrapper.save({ name: 'name1', value: NodeBuffer.from('value1') }); - await keyEntryStorageWrapper.save({ name: 'name2', value: NodeBuffer.from('value2') }); + await keyEntryStorage.save({ name: 'name', value: 'dmFsdWU=' }); + await keyEntryStorageWrapper.save({ name: 'name1', value: 'dmFsdWUx' }); + await keyEntryStorageWrapper.save({ name: 'name2', value: 'dmFsdWUy' }); const keyEntries = await keyEntryStorageWrapper.list(); expect(keyEntries).to.have.length(2); }); @@ -136,11 +135,11 @@ describe('KeyEntryStorageWrapper', () => { it('updates existing entry', async () => { const params1 = { name: 'name', - value: NodeBuffer.from('value1'), + value: 'dmFsdWUx', }; const params2 = { name: params1.name, - value: NodeBuffer.from('value2'), + value: 'dmFsdWUy', meta: { key: 'value', }, @@ -148,16 +147,16 @@ describe('KeyEntryStorageWrapper', () => { await keyEntryStorageWrapper.save(params1); const keyEntry = await keyEntryStorageWrapper.update(params2); expect(keyEntry.name).to.equal(params1.name); - expect(keyEntry.value.equals(params2.value)).to.be.true; + expect(keyEntry.value).to.equal(params2.value); expect(keyEntry.meta).to.eql(params2.meta); }); }); describe('clear', () => { it('deletes entries except ones created outside of `KeyEntryStorageWrapper`', async () => { - await keyEntryStorage.save({ name: 'name', value: NodeBuffer.from('value') }); - await keyEntryStorageWrapper.save({ name: 'name1', value: NodeBuffer.from('value1') }); - await keyEntryStorageWrapper.save({ name: 'name2', value: NodeBuffer.from('value2') }); + await keyEntryStorage.save({ name: 'name', value: 'dmFsdWU=' }); + await keyEntryStorageWrapper.save({ name: 'name1', value: 'dmFsdWUx' }); + await keyEntryStorageWrapper.save({ name: 'name2', value: 'dmFsdWUy' }); await keyEntryStorageWrapper.clear(); const keyEntries = await keyEntryStorage.list(); expect(keyEntries).to.have.length(1); diff --git a/src/__tests__/KeyEntryUtils.test.ts b/src/__tests__/KeyEntryUtils.test.ts index ccbf341..0f087f2 100644 --- a/src/__tests__/KeyEntryUtils.test.ts +++ b/src/__tests__/KeyEntryUtils.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import { @@ -24,14 +23,14 @@ describe('KeyEntryUtils', () => { it('returns `IKeyEntry`', () => { const cloudEntry = { name: 'name', - data: NodeBuffer.from('data'), + data: 'ZGF0YQ==', creationDate: new Date(), modificationDate: new Date(), meta: { meta: 'meta' }, }; const keyEntry = createKeyEntry(cloudEntry); expect(keyEntry.name).to.equal(cloudEntry.name); - expect(keyEntry.value.equals(cloudEntry.data)).to.be.true; + expect(keyEntry.value).to.equal(cloudEntry.data); expect(keyEntry.meta).to.eql({ ...cloudEntry.meta, [creationDateKey]: dateToStringValue, @@ -44,7 +43,7 @@ describe('KeyEntryUtils', () => { it('throws it `meta` not found', () => { const keyEntry = { name: 'name', - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', creationDate: new Date(), modificationDate: new Date(), }; @@ -57,7 +56,7 @@ describe('KeyEntryUtils', () => { const date2 = new Date(1); const keyEntry = { name: 'name', - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', meta: { [creationDateKey]: date1.toISOString(), [modificationDateKey]: date2.toISOString(), diff --git a/src/__tests__/KeyknoxManager.test.ts b/src/__tests__/KeyknoxManager.test.ts index 8d24f4a..a4b3d1a 100644 --- a/src/__tests__/KeyknoxManager.test.ts +++ b/src/__tests__/KeyknoxManager.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import uuid from 'uuid/v4'; @@ -78,34 +77,34 @@ describe('KeyknoxManager', () => { }); it('KTC-6', async () => { - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; const decryptedKeyknoxValue = await keyknoxManager.pushValue(value); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); }); it('KTC-7', async () => { - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; await keyknoxManager.pushValue(value); const decryptedKeyknoxValue = await keyknoxManager.pullValue(); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); }); it('KTC-8', async () => { const decryptedKeyknoxValue = await keyknoxManager.pullValue(); - expect(decryptedKeyknoxValue.meta.byteLength).to.equal(0); - expect(decryptedKeyknoxValue.value.byteLength).to.equal(0); + expect(decryptedKeyknoxValue.meta.length).to.equal(0); + expect(decryptedKeyknoxValue.value.length).to.equal(0); expect(decryptedKeyknoxValue.version).to.equal('1.0'); }); it('KTC-9', async () => { const identity = uuid(); - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; const keyPairs = generateKeyPairs(50); let publicKeys = getPublicKeys(keyPairs, 0, 25); const keyknoxManager1 = createKeyknoxManager(keyPairs[0].privateKey, publicKeys, identity); await keyknoxManager1.pushValue(value); const decryptedKeyknoxValue = await keyknoxManager1.pullValue(); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).equal(value); publicKeys = getPublicKeys(keyPairs, 25, 50); const keyknoxManager2 = createKeyknoxManager(keyPairs[0].privateKey, publicKeys, identity); try { @@ -117,18 +116,18 @@ describe('KeyknoxManager', () => { it('KTC-10', async () => { const identity = uuid(); - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; const keyPairs = generateKeyPairs(50); let privateKey = keyPairs[getRandomInRange(0, 25)].privateKey; const publicKeys = getPublicKeys(keyPairs, 0, 25); const keyknoxManager1 = createKeyknoxManager(privateKey, publicKeys, identity); await keyknoxManager1.pushValue(value); let decryptedKeyknoxValue = await keyknoxManager1.pullValue(); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); privateKey = keyPairs[getRandomInRange(0, 25)].privateKey; const keyknoxManager2 = createKeyknoxManager(privateKey, publicKeys, identity); decryptedKeyknoxValue = await keyknoxManager2.pullValue(); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); privateKey = keyPairs[getRandomInRange(25, 50)].privateKey; const keyknoxManager3 = createKeyknoxManager(privateKey, publicKeys, identity); try { @@ -140,7 +139,7 @@ describe('KeyknoxManager', () => { it('KTC-11', async () => { const identity = uuid(); - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; const keyPairs = generateKeyPairs(50); let privateKey = keyPairs[getRandomInRange(0, 25)].privateKey; let publicKeys = getPublicKeys(keyPairs, 0, 25); @@ -155,11 +154,11 @@ describe('KeyknoxManager', () => { }); expect(keyknoxManager2.privateKey).to.equal(privateKey); expect(keyknoxManager2.publicKeys).to.equal(publicKeys); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); privateKey = keyPairs[getRandomInRange(25, 50)].privateKey; const keyknoxManager3 = createKeyknoxManager(privateKey, publicKeys, identity); decryptedKeyknoxValue = await keyknoxManager3.pullValue(); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); privateKey = keyPairs[getRandomInRange(0, 25)].privateKey; const keyknoxManager4 = createKeyknoxManager(privateKey, publicKeys, identity); try { @@ -179,8 +178,8 @@ describe('KeyknoxManager', () => { it('KTC-12', async () => { const identity = uuid(); - const value = NodeBuffer.from('value'); - const updatedValue = NodeBuffer.from('updatedValue'); + const value = 'dmFsdWUK'; + const updatedValue = 'dXBkYXRlZFZhbHVl'; const keyPairs = generateKeyPairs(50); let privateKey = keyPairs[getRandomInRange(0, 25)].privateKey; let publicKeys = getPublicKeys(keyPairs, 0, 25); @@ -197,11 +196,11 @@ describe('KeyknoxManager', () => { }); expect(keyknoxManager2.privateKey).to.equal(privateKey); expect(keyknoxManager2.publicKeys).to.equal(publicKeys); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); privateKey = keyPairs[getRandomInRange(25, 50)].privateKey; const keyknoxManager3 = createKeyknoxManager(privateKey, publicKeys, identity); decryptedKeyknoxValue = await keyknoxManager3.pullValue(); - expect(decryptedKeyknoxValue.value.equals(value)).to.be.true; + expect(decryptedKeyknoxValue.value).to.equal(value); privateKey = keyPairs[getRandomInRange(0, 25)].privateKey; const keyknoxManager4 = createKeyknoxManager(privateKey, publicKeys, identity); try { @@ -230,13 +229,13 @@ describe('KeyknoxManager', () => { newPrivateKey: privateKey, newPublicKeys: publicKeys, }); - expect(decryptedKeyknoxValue.meta.byteLength).to.equal(0); - expect(decryptedKeyknoxValue.value.byteLength).to.equal(0); + expect(decryptedKeyknoxValue.meta.length).to.equal(0); + expect(decryptedKeyknoxValue.value.length).to.equal(0); expect(decryptedKeyknoxValue.version).to.equal('1.0'); }); it('KTC-14', async () => { - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; await keyknoxManager.pushValue(value); const decryptedKeyknoxValue = await keyknoxManager.resetValue(); expect(decryptedKeyknoxValue.version).to.equal('2.0'); @@ -244,7 +243,7 @@ describe('KeyknoxManager', () => { it('KTC-15', async () => { const identity = uuid(); - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; const [keyPair1, keyPair2] = generateKeyPairs(2); const keyknoxManager1 = createKeyknoxManager(keyPair1.privateKey, keyPair1.publicKey, identity); const keyknoxManager2 = createKeyknoxManager(keyPair2.privateKey, keyPair2.publicKey, identity); @@ -276,7 +275,7 @@ describe('KeyknoxManager', () => { new KeyknoxCrypto(virgilCrypto), keyknoxClient, ); - const value = NodeBuffer.from('value'); + const value = 'dmFsdWUK'; await keyknoxManager.pushValue(value); const token = await accessTokenProvider.getToken({ service: 'keyknox', operation: 'get' }); const encryptedKeyknoxValue = await keyknoxClient.pullValue(token.toString()); @@ -286,6 +285,6 @@ describe('KeyknoxManager', () => { keyPair.privateKey, keyPair.publicKey, ); - expect(decryptedData.equals(value)).to.be.true; + expect(decryptedData.toString('base64')).to.equal(value); }); }); diff --git a/src/__tests__/SyncKeyStorage.test.ts b/src/__tests__/SyncKeyStorage.test.ts index 2d9351f..d988e3d 100644 --- a/src/__tests__/SyncKeyStorage.test.ts +++ b/src/__tests__/SyncKeyStorage.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import { join } from 'path'; @@ -21,7 +20,7 @@ import SyncKeyStorage from '../SyncKeyStorage'; function generateKeyEntries(amount: number): KeyEntry[] { const keyEntries = []; for (let i = 0; i < amount; i += 1) { - keyEntries.push({ name: uuid(), data: NodeBuffer.from('data') }); + keyEntries.push({ name: uuid(), data: 'ZGF0YQ==' }); } return keyEntries; } @@ -67,7 +66,7 @@ describe('SyncKeyStorage', () => { it('KTC-29', async () => { function compare(storedKeyEntry: IKeyEntry, keyEntry: KeyEntry): void { expect(storedKeyEntry.name).to.equal(keyEntry.name); - expect(storedKeyEntry.value.equals(keyEntry.data)).to.be.true; + expect(storedKeyEntry.value).to.equal(keyEntry.data); } const keyEntries = generateKeyEntries(2); @@ -112,7 +111,7 @@ describe('SyncKeyStorage', () => { expect(storedKeyEntries).to.have.length(1); compare(storedKeyEntry1, keyEntry2); - const updatedEntry = { name: keyEntry2.name, data: NodeBuffer.from('newData') }; + const updatedEntry = { name: keyEntry2.name, data: 'bmV3RGF0YQ==' }; await cloudKeyStorage.updateEntry(updatedEntry.name, updatedEntry.data); await syncKeyStorage.sync(); storedKeyEntries = await keyEntryStorageWrapper.list(); @@ -134,11 +133,11 @@ describe('SyncKeyStorage', () => { const cloudEntry = cloudKeyStorage.retrieveEntry(keyEntry.name); const storageKeyEntry = await keyEntryStorageWrapper.load(keyEntry.name); expect(entry.name).to.equal(keyEntry.name); - expect(entry.value.equals(keyEntry.data)).to.be.true; + expect(entry.value).to.equal(keyEntry.data); expect(cloudEntry.name).to.equal(keyEntry.name); - expect(cloudEntry.data.equals(keyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(keyEntry.data); expect(storageKeyEntry!.name).to.equal(keyEntry.name); - expect(storageKeyEntry!.value.equals(keyEntry.data)).to.be.true; + expect(storageKeyEntry!.value).to.equal(keyEntry.data); }); it('KTC-31', async () => { @@ -157,7 +156,7 @@ describe('SyncKeyStorage', () => { it('KTC-32', async () => { const [keyEntry] = generateKeyEntries(1); - const newData = NodeBuffer.from('newData'); + const newData = 'bmV3RGF0YQ=='; await syncKeyStorage.sync(); await syncKeyStorage.storeEntry(keyEntry.name, keyEntry.data); await syncKeyStorage.updateEntry(keyEntry.name, newData); @@ -165,11 +164,11 @@ describe('SyncKeyStorage', () => { const cloudEntry = cloudKeyStorage.retrieveEntry(keyEntry.name); const storageKeyEntry = await keyEntryStorageWrapper.load(keyEntry.name); expect(entry.name).to.equal(keyEntry.name); - expect(entry.value.equals(newData)).to.be.true; + expect(entry.value).to.equal(newData); expect(cloudEntry.name).to.equal(keyEntry.name); - expect(cloudEntry.data.equals(newData)).to.be.true; + expect(cloudEntry.data).to.equal(newData); expect(storageKeyEntry!.name).to.equal(keyEntry.name); - expect(storageKeyEntry!.value.equals(newData)).to.be.true; + expect(storageKeyEntry!.value).to.equal(newData); }); it('KTC-33', async () => { @@ -202,19 +201,19 @@ describe('SyncKeyStorage', () => { entries.forEach(keyEntry => { const myKeyEntry = keyEntriesMap[keyEntry.name]; expect(keyEntry.name).to.equal(myKeyEntry.name); - expect(keyEntry.value.equals(myKeyEntry.data)).to.be.true; + expect(keyEntry.value).to.equal(myKeyEntry.data); }); expect(cloudEntries).to.have.length(totalEntries); cloudEntries.forEach(cloudEntry => { const myKeyEntry = keyEntriesMap[cloudEntry.name]; expect(cloudEntry.name).to.equal(myKeyEntry.name); - expect(cloudEntry.data.equals(myKeyEntry.data)).to.be.true; + expect(cloudEntry.data).to.equal(myKeyEntry.data); }); expect(storageKeyEntries).to.have.length(totalEntries); storageKeyEntries.forEach(keyEntry => { const myKeyEntry = keyEntriesMap[keyEntry.name]; expect(keyEntry.name).to.equal(myKeyEntry.name); - expect(keyEntry.value.equals(myKeyEntry.data)).to.be.true; + expect(keyEntry.value).to.equal(myKeyEntry.data); }); }); @@ -228,11 +227,11 @@ describe('SyncKeyStorage', () => { const cloudEntry = cloudKeyStorage.retrieveEntry(keyEntry3.name); const storageKeyEntry = await keyEntryStorageWrapper.load(keyEntry3.name); expect(keyEntry.name).to.equal(keyEntry3.name); - expect(keyEntry.value.equals(keyEntry3.data)).to.be.true; + expect(keyEntry.value).to.equal(keyEntry3.data); expect(cloudEntry.name).to.equal(keyEntry3.name); - expect(cloudEntry.data.equals(keyEntry3.data)).to.be.true; + expect(cloudEntry.data).to.equal(keyEntry3.data); expect(storageKeyEntry!.name).to.equal(keyEntry3.name); - expect(storageKeyEntry!.value.equals(keyEntry3.data)).to.be.true; + expect(storageKeyEntry!.value).to.equal(keyEntry3.data); }); it('KTC-36', async () => { @@ -241,7 +240,7 @@ describe('SyncKeyStorage', () => { await syncKeyStorage.storeEntries(keyEntries); const myKeyEntries = keyEntries.map(keyEntry => ({ name: keyEntry.name, - value: NodeBuffer.from('value'), + value: 'dmFsdWU=', })); const [keyEntry1, keyEntry2] = myKeyEntries; const myKeyEntriesMap = { @@ -257,10 +256,10 @@ describe('SyncKeyStorage', () => { expect(entries).to.have.length(2); let entry = myKeyEntriesMap[entry1.name]; expect(entry1.name).to.equal(entry.name); - expect(entry1.value.equals(entry.value)).to.be.true; + expect(entry1.value).to.equal(entry.value); entry = myKeyEntriesMap[entry2.name]; expect(entry2.name).to.equal(entry.name); - expect(entry2.value.equals(entry.value)).to.be.true; + expect(entry2.value).to.equal(entry.value); }); it('KTC-37', async () => { @@ -298,7 +297,7 @@ describe('SyncKeyStorage', () => { }); it('KTC-40', async () => { - const keyEntry = { name: uuid(), value: NodeBuffer.from('value') }; + const keyEntry = { name: uuid(), value: 'dmFsdWU=' }; await keyEntryStorageWrapper.save(keyEntry); try { await syncKeyStorage.deleteEntry(keyEntry.name); @@ -329,7 +328,7 @@ describe('SyncKeyStorage', () => { const entry = await syncKeyStorage.retrieveEntry(keyEntry.name); expect(entry).not.to.be.undefined; try { - await syncKeyStorage.updateEntry(keyEntry.name, NodeBuffer.from('newData')); + await syncKeyStorage.updateEntry(keyEntry.name, 'bmV3RGF0YQ=='); } catch (error) { expect(error).to.be.instanceOf(CloudKeyStorageOutOfSyncError); } diff --git a/src/clients/IKeyknoxClient.ts b/src/clients/IKeyknoxClient.ts index ce79091..ae7849d 100644 --- a/src/clients/IKeyknoxClient.ts +++ b/src/clients/IKeyknoxClient.ts @@ -3,10 +3,10 @@ import { EncryptedKeyknoxValue, DecryptedKeyknoxValue } from '../entities'; // eslint-disable-next-line @typescript-eslint/interface-name-prefix export default interface IKeyknoxClient { pushValue( - meta: Buffer, - value: Buffer, + meta: string, + value: string, token: string, - previousHash?: Buffer, + previousHash?: string, ): Promise; pullValue(token: string): Promise; diff --git a/src/clients/KeyknoxClient.ts b/src/clients/KeyknoxClient.ts index 478d969..5535208 100644 --- a/src/clients/KeyknoxClient.ts +++ b/src/clients/KeyknoxClient.ts @@ -1,8 +1,8 @@ -import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'; -import { Buffer as NodeBuffer } from 'buffer'; +import axios, { AxiosResponse } from 'axios'; import { EncryptedKeyknoxValue, DecryptedKeyknoxValue, KeyknoxValue } from '../entities'; import { KeyknoxClientError } from '../errors'; +import { AxiosInstance, AxiosError, AxiosRequestConfig } from '../types'; import IKeyknoxClient from './IKeyknoxClient'; interface KeyknoxData { @@ -24,14 +24,14 @@ export default class KeyknoxClient implements IKeyknoxClient { } async pushValue( - meta: Buffer, - value: Buffer, + meta: string, + value: string, token: string, - previousHash?: Buffer, + previousHash?: string, ): Promise { const payload = { - meta: meta.toString('base64'), - value: value.toString('base64'), + meta, + value, }; const config: AxiosRequestConfig = { headers: { @@ -39,7 +39,7 @@ export default class KeyknoxClient implements IKeyknoxClient { }, }; if (previousHash) { - config.headers['Virgil-Keyknox-Previous-Hash'] = previousHash.toString('base64'); + config.headers['Virgil-Keyknox-Previous-Hash'] = previousHash; } const response = await this.axios.put('/keyknox/v1', payload, config); return KeyknoxClient.getKeyknoxValue(response); @@ -68,10 +68,10 @@ export default class KeyknoxClient implements IKeyknoxClient { private static getKeyknoxValue(response: AxiosResponse): KeyknoxValue { const { data, headers } = response; return { - meta: NodeBuffer.from(data.meta, 'base64'), - value: NodeBuffer.from(data.value, 'base64'), + meta: data.meta, + value: data.value, version: data.version, - keyknoxHash: NodeBuffer.from(headers['virgil-keyknox-hash'], 'base64'), + keyknoxHash: headers['virgil-keyknox-hash'], }; } diff --git a/src/clients/__tests__/KeyknoxClient.test.ts b/src/clients/__tests__/KeyknoxClient.test.ts index fff15fd..168efd1 100644 --- a/src/clients/__tests__/KeyknoxClient.test.ts +++ b/src/clients/__tests__/KeyknoxClient.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import { initCrypto, VirgilCrypto, VirgilAccessTokenSigner } from 'virgil-crypto'; @@ -33,57 +32,56 @@ describe('KeyknoxClient', () => { }); it('KTC-1', async () => { - const value = NodeBuffer.from('value'); - const meta = NodeBuffer.from('meta'); + const value = 'dmFsdWU='; + const meta = 'bWV0YQ=='; const token = jwt.toString(); const response1 = await client.pushValue(meta, value, token); const response2 = await client.pullValue(token); - expect(response1.meta.equals(meta)).to.be.true; - expect(response1.value.equals(value)).to.be.true; + expect(response1.meta).to.equal(meta); + expect(response1.value).to.equal(value); expect(response1.version).to.equal('1.0'); expect(response1.keyknoxHash).not.to.be.undefined; - expect(response2.meta.equals(meta)).to.be.true; - expect(response2.value.equals(value)).to.be.true; + expect(response2.meta).to.equal(meta); + expect(response2.value).to.equal(value); expect(response2.version).to.equal('1.0'); - expect(response2.keyknoxHash.equals(response1.keyknoxHash)).to.be.true; + expect(response2.keyknoxHash).to.equal(response1.keyknoxHash); }); it('KTC-2', async () => { - const value1 = NodeBuffer.from('value1'); - const meta1 = NodeBuffer.from('meta1'); - const value2 = NodeBuffer.from('value2'); - const meta2 = NodeBuffer.from('meta2'); + const value1 = 'dmFsdWUx'; + const meta1 = 'bWV0YTE='; + const value2 = 'dmFsdWUy'; + const meta2 = 'bWV0YTI='; const token = jwt.toString(); const response1 = await client.pushValue(meta1, value1, token); const response2 = await client.pushValue(meta2, value2, token, response1.keyknoxHash); - expect(response2.meta.equals(meta2)).to.be.true; - expect(response2.value.equals(value2)).to.be.true; + expect(response2.meta).to.equal(meta2); + expect(response2.value).to.equal(value2); expect(response2.version).to.equal('2.0'); expect(response2.keyknoxHash).not.to.be.undefined; }); it('KTC-3', async () => { const response = await client.pullValue(jwt.toString()); - expect(response.meta.byteLength).to.equal(0); - expect(response.value.byteLength).to.equal(0); + expect(response.meta.length).to.equal(0); expect(response.version).to.equal('1.0'); }); it('KTC-4', async () => { - const value1 = NodeBuffer.from('value1'); - const meta1 = NodeBuffer.from('meta1'); + const value1 = 'dmFsdWUx'; + const meta1 = 'bWV0YTE='; const token = jwt.toString(); await client.pushValue(meta1, value1, token); const response2 = await client.resetValue(token); - expect(response2.meta.byteLength).to.equal(0); - expect(response2.value.byteLength).to.equal(0); + expect(response2.meta.length).to.equal(0); + expect(response2.value.length).to.equal(0); expect(response2.version).to.equal('2.0'); }); it('KTC-5', async () => { const response = await client.resetValue(jwt.toString()); - expect(response.meta.byteLength).to.equal(0); - expect(response.value.byteLength).to.equal(0); + expect(response.meta.length).to.equal(0); + expect(response.value.length).to.equal(0); expect(response.version).to.equal('1.0'); }); }); diff --git a/src/cryptos/IKeyknoxCrypto.ts b/src/cryptos/IKeyknoxCrypto.ts index 7de46b5..a13cd24 100644 --- a/src/cryptos/IKeyknoxCrypto.ts +++ b/src/cryptos/IKeyknoxCrypto.ts @@ -10,11 +10,11 @@ export default interface IKeyknoxCrypto { ): DecryptedKeyknoxValue; encrypt( - data: Buffer, + data: string, privateKey: IPrivateKey, publicKeys: IPublicKey | IPublicKey[], ): { - encryptedData: Buffer; - metadata: Buffer; + encryptedData: string; + metadata: string; }; } diff --git a/src/cryptos/KeyknoxCrypto.ts b/src/cryptos/KeyknoxCrypto.ts index b8809ea..4b52998 100644 --- a/src/cryptos/KeyknoxCrypto.ts +++ b/src/cryptos/KeyknoxCrypto.ts @@ -1,41 +1,54 @@ import { EncryptedKeyknoxValue, DecryptedKeyknoxValue } from '../entities'; -import { VirgilCrypto, VirgilPrivateKey, VirgilPublicKey } from '../types'; +import { ICrypto, IPrivateKey, IPublicKey } from '../types'; import IKeyknoxCrypto from './IKeyknoxCrypto'; export default class KeyknoxCrypto implements IKeyknoxCrypto { - private readonly crypto: VirgilCrypto; + private readonly crypto: ICrypto; - constructor(crypto: VirgilCrypto) { + constructor(crypto: ICrypto) { this.crypto = crypto; } decrypt( encryptedKeyknoxValue: EncryptedKeyknoxValue, - privateKey: VirgilPrivateKey, - publicKeys: VirgilPublicKey | VirgilPublicKey[], + privateKey: IPrivateKey, + publicKeys: IPublicKey | IPublicKey[], ): DecryptedKeyknoxValue { const { value, meta } = encryptedKeyknoxValue; - if (!value.byteLength || !meta.byteLength) { - if (value.byteLength || meta.byteLength) { + if (!value.length || !meta.length) { + if (value.length || meta.length) { throw new TypeError("'EncryptedKeyknoxValue' is invalid"); } return encryptedKeyknoxValue; } - const decrypted = this.crypto.decryptThenVerifyDetached(value, meta, privateKey, publicKeys); + const decrypted = this.crypto.decryptThenVerifyDetached( + { value: value, encoding: 'base64' }, + { value: meta, encoding: 'base64' }, + privateKey, + publicKeys, + ); return { ...encryptedKeyknoxValue, - value: decrypted, + value: decrypted.toString('base64'), }; } encrypt( - data: Buffer, - privateKey: VirgilPrivateKey, - publicKeys: VirgilPublicKey | VirgilPublicKey[], + data: string, + privateKey: IPrivateKey, + publicKeys: IPublicKey | IPublicKey[], ): { - encryptedData: Buffer; - metadata: Buffer; + encryptedData: string; + metadata: string; } { - return this.crypto.signThenEncryptDetached(data, privateKey, publicKeys); + const { metadata, encryptedData } = this.crypto.signThenEncryptDetached( + { value: data, encoding: 'base64' }, + privateKey, + publicKeys, + ); + return { + metadata: metadata.toString('base64'), + encryptedData: encryptedData.toString('base64'), + }; } } diff --git a/src/cryptos/__tests__/KeyknoxCrypto.test.ts b/src/cryptos/__tests__/KeyknoxCrypto.test.ts index 88bc0db..8016856 100644 --- a/src/cryptos/__tests__/KeyknoxCrypto.test.ts +++ b/src/cryptos/__tests__/KeyknoxCrypto.test.ts @@ -1,4 +1,3 @@ -import { Buffer as NodeBuffer } from 'buffer'; import { expect } from 'chai'; import { initCrypto, VirgilCrypto } from 'virgil-crypto'; @@ -19,23 +18,25 @@ describe('KeyknoxCrypto', () => { }); it('encrypts and decrypts successfully', () => { - const data = NodeBuffer.from('data'); + const data = 'ZGF0YQ=='; + const version = '1.0'; + const keyknoxHash = 'a2V5a25veEhhc2g='; const { privateKey, publicKey } = virgilCrypto.generateKeys(); const { encryptedData, metadata } = keyknoxCrypto.encrypt(data, privateKey, publicKey); const encryptedKeyknoxValue = { + version, + keyknoxHash, meta: metadata, value: encryptedData, - version: '1.0', - keyknoxHash: NodeBuffer.from('keyknoxHash'), }; const decryptedKeyknoxValue = keyknoxCrypto.decrypt( encryptedKeyknoxValue, privateKey, publicKey, ); - expect(decryptedKeyknoxValue.meta.equals(encryptedKeyknoxValue.meta)).to.be.true; - expect(decryptedKeyknoxValue.value.equals(data)).to.be.true; - expect(decryptedKeyknoxValue.version).to.equal('1.0'); - expect(decryptedKeyknoxValue.keyknoxHash.equals(encryptedKeyknoxValue.keyknoxHash)).to.be.true; + expect(decryptedKeyknoxValue.meta).to.equal(encryptedKeyknoxValue.meta); + expect(decryptedKeyknoxValue.value).to.equal(data); + expect(decryptedKeyknoxValue.version).to.equal(encryptedKeyknoxValue.version); + expect(decryptedKeyknoxValue.keyknoxHash).to.equal(encryptedKeyknoxValue.keyknoxHash); }); }); diff --git a/src/entities.ts b/src/entities.ts index 24d705b..d35d56a 100644 --- a/src/entities.ts +++ b/src/entities.ts @@ -1,10 +1,10 @@ import { Meta } from './types'; export interface KeyknoxValue { - meta: Buffer; - value: Buffer; + meta: string; + value: string; version: string; - keyknoxHash: Buffer; + keyknoxHash: string; } // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -15,7 +15,7 @@ export interface EncryptedKeyknoxValue extends KeyknoxValue {} export interface CloudEntry { name: string; - data: Buffer; + data: string; creationDate: Date; modificationDate: Date; meta: Meta; @@ -23,6 +23,6 @@ export interface CloudEntry { export interface KeyEntry { name: string; - data: Buffer; + data: string; meta?: Meta; } diff --git a/src/types.ts b/src/types.ts index 2e7af8a..b738441 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,10 +1,12 @@ export type Meta = { [key: string]: string } | null; -export type IPrivateKey = import('virgil-crypto').IPrivateKey; -export type IPublicKey = import('virgil-crypto').IPublicKey; -export type VirgilCrypto = import('virgil-crypto').VirgilCrypto; -export type VirgilPrivateKey = import('virgil-crypto').VirgilPrivateKey; -export type VirgilPublicKey = import('virgil-crypto').VirgilPublicKey; +export type AxiosInstance = import('axios').AxiosInstance; +export type AxiosError = import('axios').AxiosError; +export type AxiosRequestConfig = import('axios').AxiosRequestConfig; + +export type ICrypto = import('@virgilsecurity/crypto-types').ICrypto; +export type IPrivateKey = import('@virgilsecurity/crypto-types').IPrivateKey; +export type IPublicKey = import('@virgilsecurity/crypto-types').IPublicKey; export type IAccessTokenProvider = import('virgil-sdk').IAccessTokenProvider; export type IKeyEntry = import('virgil-sdk').IKeyEntry; From f2066b768db8785d94a230b7a15473ba56417fcd Mon Sep 17 00:00:00 2001 From: Serhii Nanovskyi Date: Thu, 5 Sep 2019 15:14:34 +0300 Subject: [PATCH 2/6] Update example --- example/client.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/example/client.js b/example/client.js index 7816e9a..d021cbb 100644 --- a/example/client.js +++ b/example/client.js @@ -54,21 +54,21 @@ initCrypto().then(() => { .then(allEntries => { console.log('all entries:', allEntries); console.log('storing new entry...'); - return syncKeyStorage.storeEntry('entry', Buffer.from('data')); + return syncKeyStorage.storeEntry('entry', 'ZGF0YQ=='); }) .then(storedEntry => { console.log('stored entry:', storedEntry); console.log('storing new entries...'); return syncKeyStorage.storeEntries([ - { name: 'entry1', data: Buffer.from('data1') }, - { name: 'entry2', data: Buffer.from('data2') }, - { name: 'entry3', data: Buffer.from('data3') }, + { name: 'entry1', data: 'ZGF0YTE=' }, + { name: 'entry2', data: 'ZGF0YTI=' }, + { name: 'entry3', data: 'ZGF0YTM=' }, ]); }) .then(storedEntries => { console.log('stored entries:', storedEntries); console.log('updating entry1...'); - return syncKeyStorage.updateEntry('entry1', Buffer.from('data1Updated')); + return syncKeyStorage.updateEntry('entry1', 'ZGF0YTFVcGRhdGVk'); }) .then(() => { console.log('entry1 updated...'); From 7e27af0842eef6d9bd8037e17a3d07a23cf02d4f Mon Sep 17 00:00:00 2001 From: Serhii Nanovskyi Date: Thu, 5 Sep 2019 15:16:30 +0300 Subject: [PATCH 3/6] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c88d651..5360c99 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,9 @@ npm install @virgilsecurity/keyknox@next You will also need to install `virgil-crypto` and `virgil-sdk` from npm. ```sh -npm install virgil-crypto@next virgil-sdk +npm install virgil-crypto@next virgil-sdk@next ``` -> Note that minimum supported version of `virgil-crypto` is `4.0.0-alpha.0` and minimum supported version of `virgil-sdk` is `5.3.0`. +> Note that minimum supported version of `virgil-crypto` is `4.0.0-alpha.0` and minimum supported version of `virgil-sdk` is `6.0.0-alpha.0`. ### In browser via `script` tag You will need to add `@virgilsecurity/keyknox` script. @@ -43,7 +43,7 @@ You will need to add `@virgilsecurity/keyknox` script. You will also need to add `virgil-crypto` and `virgil-sdk` scripts. ```html - + ``` Now you can use global variables `Keyknox`, `Virgil` and `VirgilCrypto` as namespace objects, containing all of `@virgilsecurity/keyknox`, `virgil-sdk` and `virgil-crypto` exports as properties. From 29389ee043de69259f30915800fc0f06ac37d44a Mon Sep 17 00:00:00 2001 From: Serhii Nanovskyi Date: Thu, 5 Sep 2019 15:17:39 +0300 Subject: [PATCH 4/6] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7db65a..18648f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@virgilsecurity/keyknox", - "version": "0.3.0-alpha.0", + "version": "0.3.0-alpha.1", "description": "Keyknox SDK allows developers to communicate with Virgil Keyknox Service to upload, download, and synchronize encrypted sensitive data (private keys) between different devices.", "main": "./dist/keyknox.cjs.js", "module": "./dist/keyknox.es.js", From b7852856806bb9fd6304e6581e8b5ee5bde211f7 Mon Sep 17 00:00:00 2001 From: Serhii Nanovskyi Date: Thu, 5 Sep 2019 15:55:37 +0300 Subject: [PATCH 5/6] Fix --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 18648f9..3dae323 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "@types/uuid": "^3.4.4", "@typescript-eslint/eslint-plugin": "^1.11.0", "@typescript-eslint/parser": "^1.11.0", - "@virgilsecurity/base-crypto": "^0.1.0", "chai": "^4.2.0", "dotenv": "^8.0.0", "eslint": "^5.3.0", From 33d89a53abce72f06dcdda904b255f0311ff0c0d Mon Sep 17 00:00:00 2001 From: Serhii Nanovskyi Date: Thu, 5 Sep 2019 16:04:52 +0300 Subject: [PATCH 6/6] Use API_URL environment variable in tests --- .env.example | 1 + src/__tests__/CloudKeyStorage.test.ts | 14 +++++++++----- src/__tests__/KeyknoxManager.test.ts | 3 ++- src/__tests__/SyncKeyStorage.test.ts | 2 ++ src/clients/__tests__/KeyknoxClient.test.ts | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 48056d3..445bda0 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ APP_ID=APP_ID API_KEY=API_KEY API_KEY_ID=API_KEY_ID +API_URL=API_URL diff --git a/src/__tests__/CloudKeyStorage.test.ts b/src/__tests__/CloudKeyStorage.test.ts index c4860a4..6f5e88a 100644 --- a/src/__tests__/CloudKeyStorage.test.ts +++ b/src/__tests__/CloudKeyStorage.test.ts @@ -10,6 +10,7 @@ import { } from 'virgil-crypto'; import { JwtGenerator, GeneratorJwtProvider } from 'virgil-sdk'; +import KeyknoxClient from '../clients/KeyknoxClient'; import KeyknoxCrypto from '../cryptos/KeyknoxCrypto'; import { CloudKeyStorageOutOfSyncError, @@ -59,12 +60,14 @@ describe('CloudKeyStorage', () => { }); accessTokenProvider = new GeneratorJwtProvider(jwtGenerator, undefined, uuid()); keyPair = virgilCrypto.generateKeys(); - cloudKeyStorage = CloudKeyStorage.create({ + const keyknoxManager = new KeyknoxManager( accessTokenProvider, - virgilCrypto, - privateKey: keyPair.privateKey, - publicKeys: keyPair.publicKey, - }); + keyPair.privateKey, + keyPair.publicKey, + new KeyknoxCrypto(virgilCrypto), + new KeyknoxClient(process.env.API_URL), + ); + cloudKeyStorage = new CloudKeyStorage(keyknoxManager); }); it('KTC-19', async () => { @@ -286,6 +289,7 @@ describe('CloudKeyStorage', () => { keyPair.privateKey, keyPair.publicKey, new KeyknoxCrypto(virgilCrypto), + new KeyknoxClient(process.env.API_URL), ); cloudKeyStorage = new CloudKeyStorage(keyknoxManager); await keyknoxManager.pushValue(uuid()); diff --git a/src/__tests__/KeyknoxManager.test.ts b/src/__tests__/KeyknoxManager.test.ts index a4b3d1a..f51644d 100644 --- a/src/__tests__/KeyknoxManager.test.ts +++ b/src/__tests__/KeyknoxManager.test.ts @@ -52,6 +52,7 @@ describe('KeyknoxManager', () => { privateKey, publicKey, new KeyknoxCrypto(virgilCrypto), + new KeyknoxClient(process.env.API_URL), ); } @@ -267,7 +268,7 @@ describe('KeyknoxManager', () => { }); const accessTokenProvider = new GeneratorJwtProvider(jwtGenerator, undefined, uuid()); const [keyPair] = generateKeyPairs(1); - const keyknoxClient = new KeyknoxClient(); + const keyknoxClient = new KeyknoxClient(process.env.API_URL); const keyknoxManager = new KeyknoxManager( accessTokenProvider, keyPair.privateKey, diff --git a/src/__tests__/SyncKeyStorage.test.ts b/src/__tests__/SyncKeyStorage.test.ts index d988e3d..224ffa8 100644 --- a/src/__tests__/SyncKeyStorage.test.ts +++ b/src/__tests__/SyncKeyStorage.test.ts @@ -5,6 +5,7 @@ import uuid from 'uuid/v4'; import { initCrypto, VirgilCrypto, VirgilAccessTokenSigner } from 'virgil-crypto'; import { IKeyEntry, KeyEntryStorage, JwtGenerator, GeneratorJwtProvider } from 'virgil-sdk'; +import KeyknoxClient from '../clients/KeyknoxClient'; import KeyknoxCrypto from '../cryptos/KeyknoxCrypto'; import CloudKeyStorage from '../CloudKeyStorage'; import { KeyEntry } from '../entities'; @@ -57,6 +58,7 @@ describe('SyncKeyStorage', () => { keyPair.privateKey, keyPair.publicKey, new KeyknoxCrypto(virgilCrypto), + new KeyknoxClient(process.env.API_URL), ); cloudKeyStorage = new CloudKeyStorage(keyknoxManager); keyEntryStorageWrapper = new KeyEntryStorageWrapper(identity, keyEntryStorage); diff --git a/src/clients/__tests__/KeyknoxClient.test.ts b/src/clients/__tests__/KeyknoxClient.test.ts index 168efd1..286cf36 100644 --- a/src/clients/__tests__/KeyknoxClient.test.ts +++ b/src/clients/__tests__/KeyknoxClient.test.ts @@ -15,7 +15,7 @@ describe('KeyknoxClient', () => { }); beforeEach(() => { - client = new KeyknoxClient(); + client = new KeyknoxClient(process.env.API_URL); const virgilCrypto = new VirgilCrypto(); const virgilAccessTokenSigner = new VirgilAccessTokenSigner(virgilCrypto); const apiKey = virgilCrypto.importPrivateKey({