Skip to content

Commit

Permalink
Merge pull request #18 from VirgilSecurity/v0.3.0-alpha.1
Browse files Browse the repository at this point in the history
v0.3.0-alpha.1
  • Loading branch information
vadimavdeev authored Sep 5, 2019
2 parents 4dca1be + 33d89a5 commit 72bcc8d
Show file tree
Hide file tree
Showing 23 changed files with 242 additions and 233 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
APP_ID=APP_ID
API_KEY=API_KEY
API_KEY_ID=API_KEY_ID
API_URL=API_URL
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
<script src="https://unpkg.com/virgil-crypto@next/dist/browser.umd.js"></script>
<script src="https://unpkg.com/virgil-sdk/dist/virgil-sdk.browser.umd.min.js"></script>
<script src="https://unpkg.com/virgil-sdk@next/dist/virgil-sdk.browser.umd.js"></script>
```

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.
Expand Down
10 changes: 5 additions & 5 deletions example/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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...');
Expand Down
15 changes: 7 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -15,24 +15,23 @@
"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",
"@types/mocha": "^5.2.7",
"@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",
Expand All @@ -50,6 +49,6 @@
"typescript": "^3.5.1",
"uuid": "^3.3.2",
"virgil-crypto": "next",
"virgil-sdk": "^5.3.0"
"virgil-sdk": "next"
}
}
17 changes: 9 additions & 8 deletions src/CloudEntrySerializer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Buffer as NodeBuffer } from 'buffer';
import base64 from 'base-64';

import { CloudEntry } from './entities';
import { Meta } from './types';
Expand All @@ -11,11 +11,11 @@ interface SerializedCloudEntry {
meta?: Meta | null;
}

export function serialize(cloudEntries: Map<string, CloudEntry>): Buffer {
export function serialize(cloudEntries: Map<string, CloudEntry>) {
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),
Expand All @@ -27,19 +27,20 @@ export function serialize(cloudEntries: Map<string, CloudEntry>): Buffer {
delete entries[key].meta;
}
});
return NodeBuffer.from(JSON.stringify(entries));
return base64.encode(JSON.stringify(entries));
}

export function deserialize(data: Buffer): Map<string, CloudEntry> {
if (!data.byteLength) {
export function deserialize(data: string): Map<string, CloudEntry> {
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<Map<string, CloudEntry>>((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,
Expand Down
22 changes: 8 additions & 14 deletions src/CloudKeyStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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<CloudEntry> {
async storeEntry(name: string, data: string, meta?: Meta): Promise<CloudEntry> {
const [cloudEntry] = await this.storeEntries([{ name, data, meta }]);
return cloudEntry;
}

async updateEntry(name: string, data: Buffer, meta?: Meta): Promise<CloudEntry> {
async updateEntry(name: string, data: string, meta?: Meta): Promise<CloudEntry> {
this.throwUnlessSyncWasCalled();
this.throwUnlessCloudEntryExists(name);
const cloudEntry = CloudKeyStorage.createCloudEntry(
Expand Down Expand Up @@ -106,8 +100,8 @@ export default class CloudKeyStorage {
}

async updateRecipients(options: {
newPrivateKey?: VirgilPrivateKey;
newPublicKeys?: VirgilPublicKey | VirgilPublicKey[];
newPrivateKey?: IPrivateKey;
newPublicKeys?: IPublicKey | IPublicKey[];
}): Promise<void> {
this.throwUnlessSyncWasCalled();
const { newPrivateKey, newPublicKeys } = options;
Expand Down
2 changes: 1 addition & 1 deletion src/KeyEntryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function createKeyEntry(
cloudEntry: CloudEntry,
): {
name: string;
value: Buffer;
value: string;
meta: { [key: string]: string };
} {
return {
Expand Down
30 changes: 15 additions & 15 deletions src/KeyknoxManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
) {
Expand All @@ -37,7 +37,7 @@ export default class KeyknoxManager {
this.keyknoxClient = keyknoxClient || new KeyknoxClient();
}

async pushValue(value: Buffer, previousHash?: Buffer): Promise<DecryptedKeyknoxValue> {
async pushValue(value: string, previousHash?: string): Promise<DecryptedKeyknoxValue> {
const token = await this.accessTokenProvider.getToken({
service: this.SERVICE_NAME,
operation: 'put',
Expand Down Expand Up @@ -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<DecryptedKeyknoxValue> {
const { value, previousHash, newPrivateKey, newPublicKeys } = options;
if (!newPrivateKey && !newPublicKeys) {
Expand Down Expand Up @@ -109,12 +109,12 @@ export default class KeyknoxManager {
}

async updateRecipients(options: {
newPrivateKey?: VirgilPrivateKey;
newPublicKeys?: VirgilPublicKey | VirgilPublicKey[];
newPrivateKey?: IPrivateKey;
newPublicKeys?: IPublicKey | IPublicKey[];
}): Promise<DecryptedKeyknoxValue> {
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) {
Expand Down
20 changes: 10 additions & 10 deletions src/SyncKeyStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import KeyEntryStorageWrapper from './KeyEntryStorageWrapper';
import { createKeyEntry, extractDate } from './KeyEntryUtils';
import {
Meta,
VirgilCrypto,
VirgilPrivateKey,
VirgilPublicKey,
ICrypto,
IPrivateKey,
IPublicKey,
IAccessTokenProvider,
IKeyEntry,
IKeyEntryStorage,
Expand All @@ -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;
Expand All @@ -55,12 +55,12 @@ export default class SyncKeyStorage {
return Promise.all(storeRequests);
}

async storeEntry(name: string, data: Buffer, meta?: Meta): Promise<IKeyEntry> {
async storeEntry(name: string, data: string, meta?: Meta): Promise<IKeyEntry> {
const [keyEntry] = await this.storeEntries([{ name, data, meta }]);
return keyEntry;
}

async updateEntry(name: string, data: Buffer, meta?: Meta): Promise<void> {
async updateEntry(name: string, data: string, meta?: Meta): Promise<void> {
await this.throwUnlessKeyEntryExists(name);
const cloudEntry = await this.cloudKeyStorage.updateEntry(name, data, meta);
const keyEntry = createKeyEntry(cloudEntry);
Expand Down Expand Up @@ -96,8 +96,8 @@ export default class SyncKeyStorage {
}

async updateRecipients(options: {
newPrivateKey?: VirgilPrivateKey;
newPublicKeys?: VirgilPublicKey | VirgilPublicKey[];
newPrivateKey?: IPrivateKey;
newPublicKeys?: IPublicKey | IPublicKey[];
}): Promise<void> {
const { newPrivateKey, newPublicKeys } = options;
return this.cloudKeyStorage.updateRecipients({ newPrivateKey, newPublicKeys });
Expand Down
12 changes: 5 additions & 7 deletions src/__tests__/CloudEntrySerializer.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Buffer as NodeBuffer } from 'buffer';
import { expect } from 'chai';

import { serialize, deserialize } from '../CloudEntrySerializer';
Expand All @@ -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,
Expand All @@ -22,22 +21,21 @@ 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,
},
],
]);
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());
});
});
Loading

0 comments on commit 72bcc8d

Please sign in to comment.