Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.mdns.eu/nextcloud/passwords-client.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius David Wieschollek <passwords.public@mdns.eu>2024-01-01 20:37:57 +0300
committerMarius David Wieschollek <passwords.public@mdns.eu>2024-01-01 20:37:57 +0300
commit6e716981adeeade0a71414dbc445870614902a91 (patch)
tree8d6778ebd459ae3188e757318993d31de560a92a
parent183b9668fb9a38e578839fac96ca920205b44506 (diff)
Add legacy implementation compatibility layer
Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
-rw-r--r--.gitlab-ci.yml6
-rw-r--r--package-lock.json32
-rw-r--r--package.json8
-rw-r--r--src/Authorization/Challenge/PWDv1Challenge.js2
-rw-r--r--src/ClassLoader/EnhancedClassLoader.js4
-rw-r--r--src/Classes/Encryption.js436
-rw-r--r--src/Classes/EnhancedApi.js289
-rw-r--r--src/Classes/SimpleApi.js35
-rw-r--r--src/Client/BasicPasswordsClient.js12
-rw-r--r--src/Encryption/CSEv1Encryption.js7
-rw-r--r--src/Encryption/Keychain/CSEv1Keychain.js22
-rw-r--r--src/Model/CustomField/DataField.js2
-rw-r--r--src/Model/CustomField/EmailField.js2
-rw-r--r--src/Model/CustomField/FileField.js2
-rw-r--r--src/Model/CustomField/SecretField.js2
-rw-r--r--src/Model/CustomField/TextField.js2
-rw-r--r--src/Model/CustomField/UrlField.js2
-rw-r--r--src/Model/Folder/Folder.js2
-rw-r--r--src/Model/Password/Password.js2
-rw-r--r--src/Model/Server/Server.js2
-rw-r--r--src/Model/Tag/Tag.js2
-rw-r--r--src/http.js11
-rw-r--r--src/legacy.js7
23 files changed, 289 insertions, 602 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 13703dd..2d808d8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,7 +6,7 @@ image: node:13-alpine
Publish Alpha:
stage: publishing
script:
- - sed -i -e "s|.BUILD|-alpha.${CI_PIPELINE_ID}|g" ./package.json
+ - sed -i -e "s|-alpha1000|-alpha.${CI_PIPELINE_ID}|g" ./package.json
- npm publish --tag alpha
environment:
name: Alpha
@@ -16,7 +16,7 @@ Publish Alpha:
Publish Beta:
stage: publishing
script:
- - sed -i -e "s|.BUILD|-beta.${CI_PIPELINE_ID}|g" ./package.json
+ - sed -i -e "s|-alpha1000|-beta.${CI_PIPELINE_ID}|g" ./package.json
- npm publish --tag beta
environment:
name: Beta
@@ -26,7 +26,7 @@ Publish Beta:
Publish Release:
stage: publishing
script:
- - sed -i -e "s|.BUILD||g" ./package.json
+ - sed -i -e "s|-alpha1000||g" ./package.json
- npm publish --tag latest
environment:
name: Stable
diff --git a/package-lock.json b/package-lock.json
index e417efb..bd60a73 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,25 +1,26 @@
{
"name": "passwords-client",
- "version": "1.0.0.BUILD",
+ "version": "1.0.0-alpha1000",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "passwords-client",
- "version": "1.0.0.BUILD",
+ "version": "1.0.0-alpha1000",
"license": "ISC",
"dependencies": {
- "eventemitter3": "^4.0.7",
+ "eventemitter3": "^3.1.2",
"libsodium": "0.7.10",
"libsodium-wrappers": "0.7.10",
+ "process": "^0.11.10",
"url-parse": "^1.5.3",
"uuid": "^8.3.2"
}
},
"node_modules/eventemitter3": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
- "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
},
"node_modules/libsodium": {
"version": "0.7.10",
@@ -34,6 +35,14 @@
"libsodium": "^0.7.0"
}
},
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
@@ -64,9 +73,9 @@
},
"dependencies": {
"eventemitter3": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
- "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
},
"libsodium": {
"version": "0.7.10",
@@ -81,6 +90,11 @@
"libsodium": "^0.7.0"
}
},
+ "process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="
+ },
"querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
diff --git a/package.json b/package.json
index 7a3f6f6..a912978 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "passwords-client",
- "version": "1.0.0.BUILD",
+ "version": "1.0.0-alpha1000",
"description": "JS client library for the Nextcloud Passwords app",
"main": "src/main.js",
"exports": {
@@ -8,6 +8,8 @@
"./models": "./src/models.js",
"./errors": "./src/errors.js",
"./utility": "./src/utility.js",
+ "./http": "./src/http.js",
+ "./legacy": "./src/legacy.js",
"./passlink": "./src/PassLink/PassLink",
"./boolean-state": "./src/State/BooleanState.js",
"./event-emitter": "./src/Event/EventEmitter.js",
@@ -30,9 +32,11 @@
"url": "https://git.mdns.eu/nextcloud/passwords-client.git"
},
"dependencies": {
+ "eventemitter3": "^3.1.2",
"libsodium": "0.7.10",
"libsodium-wrappers": "0.7.10",
"url-parse": "^1.5.3",
- "uuid": "^8.3.2"
+ "uuid": "^8.3.2",
+ "process": "^0.11.10"
}
}
diff --git a/src/Authorization/Challenge/PWDv1Challenge.js b/src/Authorization/Challenge/PWDv1Challenge.js
index 13a3559..1ebca08 100644
--- a/src/Authorization/Challenge/PWDv1Challenge.js
+++ b/src/Authorization/Challenge/PWDv1Challenge.js
@@ -80,7 +80,7 @@ export default class PWDv1Challenge {
genericHashKey
);
- let passwordHashSalt = sodium.sodium(sodium.crypto_pwhash_SALTBYTES),
+ let passwordHashSalt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES),
passwordHash = sodium.crypto_pwhash(
sodium.crypto_box_SEEDBYTES,
genericHash,
diff --git a/src/ClassLoader/EnhancedClassLoader.js b/src/ClassLoader/EnhancedClassLoader.js
index cc4c667..c0dcf3f 100644
--- a/src/ClassLoader/EnhancedClassLoader.js
+++ b/src/ClassLoader/EnhancedClassLoader.js
@@ -2,6 +2,7 @@ import DefaultClassLoader from "./DefaultClassLoader";
import EnhancedPassword from "../Model/Password/EnhancedPassword";
import EnhancedFolder from "../Model/Folder/EnhancedFolder";
import EnhancedTag from "../Model/Tag/EnhancedTag";
+import EnhancedApi from "../Classes/EnhancedApi";
export default class EnhancedClassLoader extends DefaultClassLoader {
/**
@@ -15,6 +16,9 @@ export default class EnhancedClassLoader extends DefaultClassLoader {
classes['model.folder'] = (d) => { return new EnhancedFolder(d, this.getInstance('client')); };
classes['model.tag'] = (d) => { return new EnhancedTag(d, this.getInstance('client')); };
+ classes['legacy'] = () => { return new EnhancedApi(this.getInstance('client')); };
+
+
return classes;
}
} \ No newline at end of file
diff --git a/src/Classes/Encryption.js b/src/Classes/Encryption.js
deleted file mode 100644
index 3e310c7..0000000
--- a/src/Classes/Encryption.js
+++ /dev/null
@@ -1,436 +0,0 @@
-import sodium from 'libsodium-wrappers';
-
-export default class Encryption {
-
- constructor() {
- this.fields = {
- password: ['url', 'label', 'notes', 'password', 'username', 'customFields'],
- folder : ['label'],
- tag : ['label', 'color']
- };
- this._enabled = false;
- this._keys = {};
- this._current = '';
- this._legacyEncoding = false;
- this.ready();
- }
-
- /**
- *
- * @returns {Boolean}
- */
- get enabled() {
- return this._enabled;
- }
-
- /**
- *
- * @returns {Boolean}
- */
- get keys() {
- return Object.keys(this._keys);
- }
-
- // noinspection JSMethodCanBeStatic
- /**
- *
- * @returns {Promise<boolean>}
- */
- async ready() {
- await sodium.ready;
- }
-
- /**
- * Returns true if the user has base64 encoded properties
- *
- * @return {Boolean}
- */
- hasLegacyEncoding() {
- return this._legacyEncoding;
- }
-
- /**
- * Encrypts an object
- *
- * @param object
- * @param type
- * @returns {{_encrypted}|*}
- */
- encryptObject(object, type) {
- if(!this._enabled) throw new Error('Encryption not available');
- if(!this.fields.hasOwnProperty(type)) throw new Error('Invalid object type');
- if(object.hasOwnProperty('_encrypted') && object._encrypted) return object;
-
- let fields = this.fields[type],
- key = this._getKey(this._current);
-
- for(let i = 0; i < fields.length; i++) {
- let field = fields[i],
- data = object[field];
-
- if(data === null || data.length === 0) continue;
- object[field] = this.encryptString(data, key);
- }
-
- object.cseType = 'CSEv1r1';
- object.cseKey = this._current;
- object._encrypted = true;
-
- return object;
- }
-
- /**
- * Decrypts an object
- *
- * @param object
- * @param type
- * @returns {{_encrypted}|*}
- */
- decryptObject(object, type) {
- if(!this._enabled) throw new Error('Encryption not available');
- if(!this.fields.hasOwnProperty(type)) throw new Error('Invalid object type');
- if(object.cseType !== 'CSEv1r1') throw new Error('Unsupported encryption type');
- if(object.hasOwnProperty('_encrypted') && !object._encrypted) return object;
-
- let fields = this.fields[type],
- key = this._getKey(object.cseKey);
-
- for(let i = 0; i < fields.length; i++) {
- let field = fields[i],
- data = object[field];
-
- if(data === null || data.length === 0) continue;
- object[field] = this.decryptString(data, key);
- }
-
- object._encrypted = false;
-
- return object;
- }
-
- /**
- * Encrypts the message with the user defined password
- *
- * @param message
- * @param password
- * @returns {*}
- */
- encryptWithPassword(message, password) {
- let salt = this._generateRandom(sodium.crypto_pwhash_SALTBYTES),
- key = this._passwordToKey(password, salt),
- encrypted = this.encrypt(message, key);
-
- return sodium.to_hex(new Uint8Array([...salt, ...encrypted]));
- }
-
- /**
- * Decrypts the message with the user defined password
- *
- * @param message
- * @param password
- * @returns {*}
- */
- decryptWithPassword(message, password) {
- let encrypted = sodium.from_hex(message),
- salt = encrypted.slice(0, sodium.crypto_pwhash_SALTBYTES),
- text = encrypted.slice(sodium.crypto_pwhash_SALTBYTES),
- key = this._passwordToKey(password, salt);
-
- return sodium.to_string(this.decrypt(text, key));
- }
-
- /**
- * Encrypt the message with the given key and return a hex encoded string
- *
- * @param message
- * @param key
- * @returns {String}
- */
- encryptString(message, key) {
- return sodium.to_hex(this.encrypt(message, key));
- }
-
- /**
- * Encrypt the message with the given key
- *
- * @param message
- * @param key
- * @returns {Uint8Array}
- */
- encrypt(message, key) {
- let nonce = this._generateRandom(sodium.crypto_secretbox_NONCEBYTES);
-
- return new Uint8Array([...nonce, ...sodium.crypto_secretbox_easy(message, nonce, key)]);
- }
-
- /**
- * Decrypt the hex or base64 encoded message with the given key
- *
- * @param encodedString
- * @param key
- * @returns {String}
- */
- decryptString(encodedString, key) {
- try {
- let encryptedString = sodium.from_hex(encodedString);
- return sodium.to_string(this.decrypt(encryptedString, key));
- } catch(e) {
- let encryptedString = sodium.from_base64(encodedString);
- let result = sodium.to_string(this.decrypt(encryptedString, key));
- this._legacyEncoding = true;
- return result;
- }
- }
-
- // noinspection JSMethodCanBeStatic
- /**
- * Decrypt the message with the given key
- *
- * @param encrypted
- * @param key
- * @returns {Uint8Array}
- */
- decrypt(encrypted, key) {
- if(encrypted.length < sodium.crypto_secretbox_NONCEBYTES + sodium.crypto_secretbox_MACBYTES) throw new Error('Invalid encrypted text length');
-
- let nonce = encrypted.slice(0, sodium.crypto_secretbox_NONCEBYTES),
- ciphertext = encrypted.slice(sodium.crypto_secretbox_NONCEBYTES);
-
- return sodium.crypto_secretbox_open_easy(ciphertext, nonce, key);
- }
-
- // noinspection JSMethodCanBeStatic
- /**
- * Generate a challenge solution with the user provided password
- * and the server provided salts
- *
- * @param salts
- * @param password
- * @returns {String}
- */
- solveChallenge(password, salts) {
- if(password.length < 12) throw new Error('Password is too short');
- if(password.length > 128) throw new Error('Password is too long');
-
- let passwordSalt = sodium.from_hex(salts[0]),
- genericHashKey = sodium.from_hex(salts[1]),
- passwordHashSalt = sodium.from_hex(salts[2]),
- genericHash = sodium.crypto_generichash(
- sodium.crypto_generichash_BYTES_MAX,
- new Uint8Array([...sodium.from_string(password), ...passwordSalt]),
- genericHashKey
- );
-
- let passwordHash = sodium.crypto_pwhash(
- sodium.crypto_box_SEEDBYTES,
- genericHash,
- passwordHashSalt,
- sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
- sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
- sodium.crypto_pwhash_ALG_DEFAULT
- );
-
-
- return sodium.to_hex(passwordHash);
- }
-
- /**
- * Create the salts and the secret for the server
- * using the user provided password
- *
- * @param password
- * @returns {{salts: *[], secret: *}}
- */
- createChallenge(password) {
- if(password.length < 12) throw new Error('Password is too short');
- if(password.length > 128) throw new Error('Password is too long');
-
- let passwordSalt = this._generateRandom(256),
- genericHashKey = this._generateRandom(sodium.crypto_generichash_KEYBYTES_MAX),
- genericHash = sodium.crypto_generichash(
- sodium.crypto_generichash_BYTES_MAX,
- new Uint8Array([...sodium.from_string(password), ...passwordSalt]),
- genericHashKey
- );
-
- let passwordHashSalt = this._generateRandom(sodium.crypto_pwhash_SALTBYTES),
- passwordHash = sodium.crypto_pwhash(
- sodium.crypto_box_SEEDBYTES,
- genericHash,
- passwordHashSalt,
- sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
- sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
- sodium.crypto_pwhash_ALG_DEFAULT
- );
-
- return {
- salts : [
- sodium.to_hex(passwordSalt),
- sodium.to_hex(genericHashKey),
- sodium.to_hex(passwordHashSalt)
- ],
- secret: sodium.to_hex(passwordHash)
- };
- }
-
- /**
- * Decrypt and activate the keychain
- *
- * @param keychainText
- * @param password
- */
- setKeychain(keychainText, password) {
- let encrypted;
- try {
- encrypted = sodium.from_hex(keychainText);
- } catch(e) {
- encrypted = sodium.from_base64(keychainText);
- this._legacyEncoding = true;
- }
-
- let salt = encrypted.slice(0, sodium.crypto_pwhash_SALTBYTES),
- text = encrypted.slice(sodium.crypto_pwhash_SALTBYTES),
- key = this._passwordToKey(password, salt),
- keychain = JSON.parse(sodium.to_string(this.decrypt(text, key)));
-
- this._current = keychain.current;
- for(let id in keychain.keys) {
- if(keychain.keys.hasOwnProperty(id)) {
- this._keys[id] = sodium.from_hex(keychain.keys[id]);
- }
- }
-
- this._enabled = true;
- }
-
- /**
- * Remove the current keychain
- */
- unsetKeychain() {
- this._enabled = false;
- this._keys = {};
- this._current = '';
- }
-
- /**
- * Add a new key to the keychain and return the full keychain
- *
- * @param password
- * @param addKey
- * @returns {*}
- */
- getKeychain(password, addKey = false) {
- if(this._enabled === false) {
- this._keys = {};
- }
-
- if(addKey || this._current.length === 0) {
- this._current = this.getUuid();
- this._keys[this._current] = this._generateRandom(sodium.crypto_secretbox_KEYBYTES);
- this._enabled = true;
- }
-
- let keychain = {
- keys : {},
- current: this._current
- };
-
- for(let id in this._keys) {
- if(this._keys.hasOwnProperty(id)) {
- keychain.keys[id] = sodium.to_hex(this._keys[id]);
- }
- }
-
- let salt = this._generateRandom(sodium.crypto_pwhash_SALTBYTES),
- key = this._passwordToKey(password, salt),
- encrypted = this.encrypt(JSON.stringify(keychain), key);
-
- return sodium.to_hex(new Uint8Array([...salt, ...encrypted]));
- }
-
- /**
- * Create a uuidv4
- *
- * @returns {String}
- */
- getUuid() {
- return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
- (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
- );
- }
-
- /**
- *
- * @param uuid
- * @returns {Uint8Array}
- * @private
- */
- _getKey(uuid) {
- if(this._keys.hasOwnProperty(uuid)) {
- return this._keys[uuid];
- }
-
- throw new Error('Unknown CSE key id');
- }
-
- // noinspection JSMethodCanBeStatic
- /**
- *
- * @param password
- * @param salt
- * @returns {Uint8Array}
- * @private
- */
- _passwordToKey(password, salt) {
- return sodium.crypto_pwhash(
- sodium.crypto_box_SEEDBYTES,
- password,
- salt,
- sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
- sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
- sodium.crypto_pwhash_ALG_DEFAULT
- );
- }
-
- // noinspection JSMethodCanBeStatic
- /**
- *
- * @param length
- * @returns {Uint8Array}
- * @private
- */
- _generateRandom(length) {
- let array = new Uint8Array(length);
- window.crypto.getRandomValues(array);
-
- return array;
- }
-
- // noinspection JSMethodCanBeStatic
- /**
- * Generate a hash of the given text with the given algorithm
- *
- * @param value
- * @param algorithm
- * @returns {Promise<string>}
- */
- async getHash(value, algorithm = 'SHA-1') {
- if(['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'].indexOf(algorithm) !== -1) {
- let msgBuffer = new TextEncoder('utf-8').encode(value),
- hashBuffer = await
- crypto.subtle.digest(algorithm, msgBuffer);
- return sodium.to_hex(new Uint8Array(hashBuffer));
- } else if(algorithm.substr(0, 7) === 'BLAKE2b') {
- let bytes = sodium.crypto_generichash_BYTES_MAX;
- if(algorithm.indexOf('-') !== -1) {
- bytes = algorithm.split('-')[1];
- if(sodium.crypto_generichash_BYTES_MAX < bytes) bytes = sodium.crypto_generichash_BYTES_MAX;
- if(sodium.crypto_generichash_BYTES_MIN > bytes) bytes = sodium.crypto_generichash_BYTES_MIN;
- }
-
- return sodium.to_hex(sodium.crypto_generichash(bytes, sodium.from_string(value)));
- } else if(algorithm === 'Argon2') {
- return sodium.crypto_pwhash_str(value, sodium.crypto_pwhash_OPSLIMIT_MIN, sodium.crypto_pwhash_MEMLIMIT_MIN);
- }
- }
-} \ No newline at end of file
diff --git a/src/Classes/EnhancedApi.js b/src/Classes/EnhancedApi.js
index 7a8ddbd..370aeec 100644
--- a/src/Classes/EnhancedApi.js
+++ b/src/Classes/EnhancedApi.js
@@ -1,6 +1,5 @@
import Url from 'url-parse';
import SimpleApi from './SimpleApi';
-import Encryption from './Encryption';
import EventEmitter from 'eventemitter3';
export default class EnhancedApi extends SimpleApi {
@@ -11,7 +10,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Boolean}
*/
get isAuthorized() {
- return this._isAuthorized === true;
+ return this._client.isAuthorized();
}
/**
@@ -20,32 +19,24 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Boolean}
*/
get hasEncryption() {
- return this.config.encryption.enabled;
+ return this._client.getCseV1Encryption().enabled();
}
- /**
- *
- * @param props
- */
- constructor(props) {
- super(props);
-
- this._isAuthorized = false;
+ constructor() {
+ super();
}
/**
* Initialize the api object
*
- * @param config
+ * @param {BasicPasswordsClient} client
*/
- initialize(config = {}) {
- if(!config.baseUrl || config.baseUrl.substr(0, 5) !== 'https') throw new Error('Invalid Base URL given');
+ initialize(client, config = {}) {
+ config.baseUrl = client.getServer().getBaseUrl();
if(!config.folderIcon) config.folderIcon = `${config.baseUrl}core/img/filetypes/folder.svg`;
if(!config.apiUrl) config.apiUrl = `${config.baseUrl}index.php/apps/passwords/`;
if(!config.hashLength) config.hashLength = 40;
-
- if(!config.encryption) config.encryption = new Encryption();
if(!config.cseMode || ['none', 'CSEv1r1'].indexOf(config.cseMode) === -1) config.cseMode = 'none';
if(!config.device) {
@@ -63,7 +54,7 @@ export default class EnhancedApi extends SimpleApi {
if(d.oldSessionToken) this._resetAuthorisation();
});
- super.initialize(config);
+ super.initialize(config, client);
}
/**
@@ -76,10 +67,10 @@ export default class EnhancedApi extends SimpleApi {
*/
async getHash(value, algorithm = 'SHA-1', length = null) {
if(length === null) length = this.config.hashLength;
- let hash = await this.config.encryption.getHash(value, algorithm);
+ let hash = await this._client.getInstance('service.hash').getHash(value, algorithm);
- if(length !== 40) {
- return hash.substr(0, length);
+ if(length < hash.length) {
+ return hash.substring(0, length);
}
return hash;
@@ -93,22 +84,23 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async openSession(login) {
- let password = null;
+ /** @type {SessionAuthorization} **/
+ let authRequest = this._client.getClass('authorization.session');
+ await authRequest.load();
+ this._client.setInstance('authorization.session', authRequest);
+
if(login.hasOwnProperty('password')) {
- login.challenge = this.config.encryption.solveChallenge(login.password, login.salts);
- password = login.password;
- delete login.salts;
- delete login.password;
+ authRequest.getChallenge().setPassword(login.password);
}
- let result = await this._sendRequest('session.open', login);
- if(password !== null && result.hasOwnProperty('keys') && result.keys.hasOwnProperty('CSEv1r1')) {
- this.config.encryption.setKeychain(result.keys.CSEv1r1, password);
- }
+ if(login.hasOwnProperty('token')) {
+ let provider = Object.keys(login.token)[0];
- this._isAuthorized = true;
+ authRequest.setActiveToken(provider);
+ authRequest.getActiveToken().setToken(login.token[provider]);
+ }
- return result;
+ await authRequest.authorize();
}
/**
@@ -117,9 +109,8 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async closeSession() {
- let result = await super.closeSession();
this._resetAuthorisation();
- return result;
+ return true;
}
@@ -138,16 +129,32 @@ export default class EnhancedApi extends SimpleApi {
async setAccountChallenge(password, oldPassword = null) {
let oldSecret = null;
if(oldPassword !== null) {
- let oldChallenge = await super.getAccountChallenge();
- oldSecret = this.config.encryption.solveChallenge(oldPassword, oldChallenge.salts);
+ let oldChallengeData = await super.getAccountChallenge();
+ let challenge = this._client.getClass('challenge.pwdv1', oldChallengeData);
+ challenge.setPassword(oldPassword);
+ oldSecret = challenge.solve();
}
- let challenge = this.config.encryption.createChallenge(password);
+ let challenge = this._client.getClass('challenge.pwdv1', {});
+ challenge.setPassword(password);
+ let data = challenge.create();
- let result = await super.setAccountChallenge(challenge.secret, challenge.salts, oldSecret);
+ let result = await super.setAccountChallenge(data.secret, data.salts, oldSecret);
if(result.success) {
- let keychain = this.config.encryption.getKeychain(password, true);
- await super.setKeychain('CSEv1r1', keychain);
+ let keychain = this._client.getCseV1Encryption().getKeychain(),
+ initial = keychain === null;
+ if(initial) {
+ keychain = this._client.getClass('keychain.csev1', null, null);
+ }
+
+ keychain.setPassword(password);
+ keychain.update();
+
+ let data = keychain.export();
+ await super.setKeychain('CSEv1r1', data);
+ if(initial) {
+ this._client.getCseV1Encryption().setKeychain(keychain);
+ }
}
return result;
@@ -177,13 +184,18 @@ export default class EnhancedApi extends SimpleApi {
object.hash = await this.getHash(data.password);
if(!object.label) this._generatePasswordTitle(object);
- if(this.config.encryption.enabled && object.cseType !== 'none') {
- this.config.encryption.encryptObject(object, 'password');
+ if(!object._encrypted && this.hasEncryption && object.cseType !== 'none') {
+ let encryption = this._client.getCseV1Encryption();
+ object = await encryption.encrypt(object, 'password');
} else {
object.cseKey = '';
}
- return await super.createPassword(object);
+ let result = await super.createPassword(object);
+ object.id = result.id;
+ object.revison = result.revison;
+
+ return object;
}
/**
@@ -208,14 +220,18 @@ export default class EnhancedApi extends SimpleApi {
object.hash = await this.getHash(data.password);
if(!object.label) this._generatePasswordTitle(object);
- if(this.config.encryption.enabled && object.cseType !== 'none' && (!data.hasOwnProperty('shared') || !data.shared)) {
- this.config.encryption.encryptObject(object, 'password');
+ if(!object._encrypted && this.hasEncryption && object.cseType !== 'none') {
+ let encryption = this._client.getCseV1Encryption();
+ object = await encryption.encrypt(object, 'password');
} else {
- object.cseType = 'none';
object.cseKey = '';
}
- return await super.updatePassword(object);
+ let result = await super.updatePassword(object);
+ object.id = result.id;
+ object.revison = result.revison;
+
+ return object;
}
/**
@@ -226,7 +242,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async showPassword(id, detailLevel = 'model') {
- return this._processPassword(
+ return await this._processPassword(
await super.showPassword(id, detailLevel)
);
}
@@ -238,7 +254,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async listPasswords(detailLevel = 'model') {
- return this._processPasswordList(
+ return await this._processPasswordList(
await super.listPasswords(detailLevel)
);
}
@@ -251,7 +267,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async findPasswords(criteria = {}, detailLevel = 'model') {
- return this._processPasswordList(
+ return await this._processPasswordList(
await super.findPasswords(criteria, detailLevel)
);
}
@@ -267,7 +283,7 @@ export default class EnhancedApi extends SimpleApi {
* @param data
* @returns {Promise}
*/
- createFolder(data = {}) {
+ async createFolder(data = {}) {
let object = this._cloneObject(data);
try {
@@ -277,13 +293,18 @@ export default class EnhancedApi extends SimpleApi {
return this._createRejectedPromise(e);
}
- if(this.config.encryption.enabled && object.cseType !== 'none') {
- this.config.encryption.encryptObject(object, 'folder');
+ if(this.hasEncryption && object.cseType !== 'none') {
+ let encryption = this._client.getCseV1Encryption();
+ object = await encryption.encrypt(object, 'folder');
} else {
object.cseKey = '';
}
- return super.createFolder(object);
+ let result = await super.createFolder(object);
+ object.id = result.id;
+ object.revison = result.revison;
+
+ return object;
}
/**
@@ -293,7 +314,7 @@ export default class EnhancedApi extends SimpleApi {
* @param data
* @returns {Promise}
*/
- updateFolder(data = {}) {
+ async updateFolder(data = {}) {
if(!data.id) return this.createFolder(data);
let object = this._cloneObject(data);
@@ -304,13 +325,18 @@ export default class EnhancedApi extends SimpleApi {
return this._createRejectedPromise(e);
}
- if(this.config.encryption.enabled && object.cseType !== 'none') {
- this.config.encryption.encryptObject(object, 'folder');
+ if(this.hasEncryption && object.cseType !== 'none') {
+ let encryption = this._client.getCseV1Encryption();
+ object = await encryption.encrypt(object, 'folder');
} else {
object.cseKey = '';
}
- return super.updateFolder(object);
+ let result = await super.updateFolder(object);
+ object.id = result.id;
+ object.revison = result.revison;
+
+ return object;
}
/**
@@ -321,7 +347,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async showFolder(id, detailLevel = 'model') {
- return this._processFolder(
+ return await this._processFolder(
await super.showFolder(id, detailLevel)
);
}
@@ -333,7 +359,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async listFolders(detailLevel = 'model') {
- return this._processFolderList(
+ return await this._processFolderList(
await super.listFolders(detailLevel)
);
}
@@ -346,7 +372,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async findFolders(criteria = {}, detailLevel = 'model') {
- return this._processFolderList(
+ return await this._processFolderList(
await super.findFolders(criteria, detailLevel)
);
}
@@ -362,7 +388,7 @@ export default class EnhancedApi extends SimpleApi {
* @param data
* @returns {Promise}
*/
- createTag(data = {}) {
+ async createTag(data = {}) {
let object = this._cloneObject(data);
try {
@@ -372,13 +398,18 @@ export default class EnhancedApi extends SimpleApi {
return this._createRejectedPromise(e);
}
- if(this.config.encryption.enabled && object.cseType !== 'none') {
- this.config.encryption.encryptObject(object, 'tag');
+ if(this.hasEncryption && object.cseType !== 'none') {
+ let encryption = this._client.getCseV1Encryption();
+ object = await encryption.encrypt(object, 'tag');
} else {
object.cseKey = '';
}
- return super.createTag(object);
+ let result = await super.createTag(object);
+ object.id = result.id;
+ object.revison = result.revison;
+
+ return object;
}
/**
@@ -388,7 +419,7 @@ export default class EnhancedApi extends SimpleApi {
* @param data
* @returns {Promise}
*/
- updateTag(data = {}) {
+ async updateTag(data = {}) {
if(!data.id) return this.createTag(data);
let object = this._cloneObject(data);
@@ -399,13 +430,18 @@ export default class EnhancedApi extends SimpleApi {
return this._createRejectedPromise(e);
}
- if(this.config.encryption.enabled && object.cseType !== 'none') {
- this.config.encryption.encryptObject(object, 'tag');
+ if(this.hasEncryption && object.cseType !== 'none') {
+ let encryption = this._client.getCseV1Encryption();
+ object = await encryption.encrypt(object, 'tag');
} else {
object.cseKey = '';
}
- return super.updateTag(object);
+ let result = await super.updateTag(object);
+ object.id = result.id;
+ object.revison = result.revison;
+
+ return object;
}
/**
@@ -416,7 +452,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async showTag(id, detailLevel = 'model') {
- return this._processTag(
+ return await this._processTag(
await super.showTag(id, detailLevel)
);
}
@@ -428,7 +464,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async listTags(detailLevel = 'model') {
- return this._processTagList(
+ return await this._processTagList(
await super.listTags(detailLevel)
);
}
@@ -441,7 +477,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async findTags(criteria = {}, detailLevel = 'model') {
- return this._processTagList(
+ return await this._processTagList(
await super.findTags(criteria, detailLevel)
);
}
@@ -496,7 +532,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async showShare(id, detailLevel = 'model') {
- return this._processShare(
+ return await this._processShare(
await super.showShare(id, detailLevel)
);
}
@@ -508,7 +544,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async listShares(detailLevel = 'model') {
- return this._processShareList(
+ return await this._processShareList(
await super.listShares(detailLevel)
);
}
@@ -521,7 +557,7 @@ export default class EnhancedApi extends SimpleApi {
* @returns {Promise}
*/
async findShares(criteria = {}, detailLevel = 'model') {
- return this._processShareList(
+ return await this._processShareList(
await super.findShares(criteria, detailLevel)
);
}
@@ -846,14 +882,14 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param data
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processPasswordList(data) {
+ async _processPasswordList(data) {
let passwords = {};
for(let i = 0; i < data.length; i++) {
- let password = this._processPassword(data[i]);
+ let password = await this._processPassword(data[i]);
passwords[password.id] = password;
}
@@ -863,16 +899,16 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param password
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processPassword(password) {
- if(password.hasOwnProperty('cseType') && password.cseType !== 'none') {
- this.config.encryption.decryptObject(password, 'password');
- } else {
- password._encrypted = false;
+ async _processPassword(password) {
+ if(password.cseType === 'CSEv1r1' && password._encrypted !== false) {
+ let encryption = this._client.getCseV1Encryption();
+ password = await encryption.decrypt(password, 'password');
}
+ password._encrypted = false;
password.type = 'password';
if(password.url) {
let host = this.parseUrl(password.url, 'host'),
@@ -897,19 +933,19 @@ export default class EnhancedApi extends SimpleApi {
if(password.tags) {
- password.tags = this._processTagList(password.tags);
+ password.tags = await this._processTagList(password.tags);
}
if(password.revisions) {
- password.revisions = this._processPasswordList(password.revisions);
+ password.revisions = await this._processPasswordList(password.revisions);
}
if(typeof password.folder === 'object') {
- password.folder = this._processFolder(password.folder);
+ password.folder = await this._processFolder(password.folder);
}
if(password.share !== null && typeof password.share === 'object') {
- password.share = this._processShare(password.share);
+ password.share = await this._processShare(password.share);
}
if(Array.isArray(password.shares)) {
- password.shares = this._processShareList(password.shares);
+ password.shares = await this._processShareList(password.shares);
}
password.created = new Date(password.created * 1e3);
@@ -922,14 +958,14 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param data
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processFolderList(data) {
+ async _processFolderList(data) {
let folders = {};
for(let i = 0; i < data.length; i++) {
- let folder = this._processFolder(data[i]);
+ let folder = await this._processFolder(data[i]);
folders[folder.id] = folder;
}
@@ -939,29 +975,29 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param folder
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processFolder(folder) {
- if(folder.hasOwnProperty('cseType') && folder.cseType !== 'none') {
- this.config.encryption.decryptObject(folder, 'folder');
- } else {
- folder._encrypted = false;
+ async _processFolder(folder) {
+ if(folder.cseType === 'CSEv1r1' && folder._encrypted !== false) {
+ let encryption = this._client.getCseV1Encryption();
+ folder = await encryption.decrypt(folder, 'folder');
}
+ folder._encrypted = false;
folder.type = 'folder';
- folder.icon = this._config.folderIcon;
+ folder.icon = this.config.folderIcon;
if(folder.folders) {
- folder.folders = this._processFolderList(folder.folders);
+ folder.folders = await this._processFolderList(folder.folders);
}
if(folder.passwords) {
- folder.passwords = this._processPasswordList(folder.passwords);
+ folder.passwords = await this._processPasswordList(folder.passwords);
}
if(folder.revisions) {
- folder.revisions = this._processFolderList(folder.revisions);
+ folder.revisions = await this._processFolderList(folder.revisions);
}
if(typeof folder.parent !== 'string') {
- folder.parent = this._processFolder(folder.parent);
+ folder.parent = await this._processFolder(folder.parent);
}
folder.created = new Date(folder.created * 1e3);
@@ -974,14 +1010,14 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param data
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processTagList(data) {
+ async _processTagList(data) {
let tags = {};
for(let i = 0; i < data.length; i++) {
- let tag = this._processTag(data[i]);
+ let tag = await this._processTag(data[i]);
tags[tag.id] = tag;
}
@@ -991,22 +1027,22 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param tag
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processTag(tag) {
- if(tag.hasOwnProperty('cseType') && tag.cseType !== 'none') {
- this.config.encryption.decryptObject(tag, 'tag');
- } else {
- tag._encrypted = false;
+ async _processTag(tag) {
+ if(tag.cseType === 'CSEv1r1' && tag._encrypted !== false) {
+ let encryption = this._client.getCseV1Encryption();
+ tag = await encryption.decrypt(tag, 'tag');
}
+ tag._encrypted = false;
tag.type = 'tag';
if(tag.passwords) {
- tag.passwords = this._processPasswordList(tag.passwords);
+ tag.passwords = await this._processPasswordList(tag.passwords);
}
if(tag.revisions) {
- tag.revisions = this._processTagList(tag.revisions);
+ tag.revisions = await this._processTagList(tag.revisions);
}
tag.created = new Date(tag.created * 1e3);
tag.updated = new Date(tag.updated * 1e3);
@@ -1018,14 +1054,14 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param data
- * @returns {{}}
+ * @returns {Promise<{}>}
* @private
*/
- _processShareList(data) {
+ async _processShareList(data) {
let shares = {};
for(let i = 0; i < data.length; i++) {
- let share = this._processShare(data[i]);
+ let share = await this._processShare(data[i]);
shares[share.id] = share;
}
@@ -1035,14 +1071,14 @@ export default class EnhancedApi extends SimpleApi {
/**
*
* @param share
- * @returns {*}
+ * @returns {Promise<{}>}
* @private
*/
- _processShare(share) {
+ async _processShare(share) {
share.type = 'share';
if(typeof share.password !== 'string') {
- share.password = this._processPassword(share.password);
+ share.password = await this._processPassword(share.password);
}
share.created = new Date(share.created * 1e3);
@@ -1131,8 +1167,7 @@ export default class EnhancedApi extends SimpleApi {
* @private
*/
_resetAuthorisation() {
- this._isAuthorized = false;
- this.config.encryption.unsetKeychain();
+ this._client.closeSession();
}
@@ -1150,9 +1185,9 @@ export default class EnhancedApi extends SimpleApi {
cseDefault = 'none';
if(this.hasEncryption) {
- cseDefault = this.config.cseMode;
+ cseDefault = 'CSEv1r1';
cseTypes.push('CSEv1r1');
- cseKeys = this.config.encryption.keys;
+ cseKeys = this._client.getCseV1Encryption().getKeychain().listKeys();
cseKeys.push('');
}
@@ -1244,9 +1279,9 @@ export default class EnhancedApi extends SimpleApi {
cseDefault = 'none';
if(this.hasEncryption) {
- cseDefault = this.config.cseMode;
+ cseDefault = 'CSEv1r1';
cseTypes.push('CSEv1r1');
- cseKeys = this.config.encryption.keys;
+ cseKeys = this._client.getCseV1Encryption().getKeychain().listKeys();
cseKeys.push('');
}
@@ -1310,9 +1345,9 @@ export default class EnhancedApi extends SimpleApi {
cseDefault = 'none';
if(this.hasEncryption) {
- cseDefault = this.config.cseMode;
+ cseDefault = 'CSEv1r1';
cseTypes.push('CSEv1r1');
- cseKeys = this.config.encryption.keys;
+ cseKeys = this._client.getCseV1Encryption().getKeychain().listKeys();
cseKeys.push('');
}
diff --git a/src/Classes/SimpleApi.js b/src/Classes/SimpleApi.js
index b92d18c..407e22c 100644
--- a/src/Classes/SimpleApi.js
+++ b/src/Classes/SimpleApi.js
@@ -17,6 +17,7 @@ export default class SimpleApi {
* SimpleApi Constructor
*/
constructor() {
+ this._client = null;
this._config = {};
this._headers = {};
this._paths = {
@@ -73,6 +74,7 @@ export default class SimpleApi {
'service.favicon' : 'api/1.0/service/favicon/{domain}/{size}',
'service.preview' : 'api/1.0/service/preview/{domain}/{view}/{width}/{height}',
'service.password-change': 'api/1.0/service/password-change',
+ 'service.hashes' : 'api/1.0/service/hashes',
'cron.sharing' : 'cron/sharing',
'link.request' : 'link/connect/request',
'link.await' : 'link/connect/await',
@@ -95,23 +97,18 @@ export default class SimpleApi {
}
/**
- * @param config
+ * @param {Object} config
+ * @param {BasicPasswordsClient} client
*/
- initialize(config = {}) {
+ initialize(config, client) {
this._enabled = false;
+ this._client = client;
this._config = config;
if(config.apiUrl.substr(0, 5) !== 'https') throw new Error('HTTPS required for api');
this._headers = {};
if(config.headers) this._headers = config.headers;
- if(config.user !== null && config.password !== null) {
- this._headers.Authorization = `Basic ${btoa(`${config.user}:${config.password}`)}`;
- } else {
- // @TODO Use custom error here
- throw new Error('API username or password missing');
- }
-
this._enabled = true;
}
@@ -640,6 +637,14 @@ export default class SimpleApi {
return this._sendRequest('service.password-change', {domain});
}
+ /**
+ *
+ * @returns {Promise}
+ */
+ getHashes(range) {
+ return this._sendRequest('service.hashes', {range});
+ }
+
/**
* Account Management
@@ -796,6 +801,8 @@ export default class SimpleApi {
headers.append(header, this._headers[header]);
}
headers.append('Accept', dataType);
+ headers.append('Authorization', `Basic ${btoa(`${this._client.getServer().getUser()}:${this._client.getServer().getToken()}`)}`);
+ headers.append('x-api-session', this._client.getSession().getId());
let options = {method, headers, credentials: 'omit', redirect: 'error'};
if(data) {
@@ -825,7 +832,12 @@ export default class SimpleApi {
path = this._paths[path];
}
- path = this._config.apiUrl + path;
+ path = this._client.getServer().getApiUrl() + path;
+
+ if(path.indexOf('api/api') !== -1) {
+ path = path.replace('api/api', 'api');
+ }
+
return path;
}
@@ -866,8 +878,7 @@ export default class SimpleApi {
}
let oldSessionToken = this._config.sessionToken;
- this._config.sessionToken = sessionToken;
- this._headers['X-API-SESSION'] = sessionToken;
+ this._client.getSession().setId(sessionToken);
this._config.events.emit('api.session.token.changed', {sessionToken, oldSessionToken});
}
}
diff --git a/src/Client/BasicPasswordsClient.js b/src/Client/BasicPasswordsClient.js
index a0411e3..803b529 100644
--- a/src/Client/BasicPasswordsClient.js
+++ b/src/Client/BasicPasswordsClient.js
@@ -120,6 +120,18 @@ export default class BasicPasswordsClient {
/**
*
+ * @return {Session}
+ */
+ closeSession() {
+ this.getRequest()
+ .setPath('1.0/session/close')
+ .send();
+
+ return this.renewSession();
+ }
+
+ /**
+ *
* @returns {SessionAuthorization}
*/
getSessionAuthorization() {
diff --git a/src/Encryption/CSEv1Encryption.js b/src/Encryption/CSEv1Encryption.js
index 9005947..82c7753 100644
--- a/src/Encryption/CSEv1Encryption.js
+++ b/src/Encryption/CSEv1Encryption.js
@@ -165,6 +165,13 @@ export default class CSEv1Encryption {
}
/**
+ * @return {CSEv1Keychain}
+ */
+ getKeychain() {
+ return this._keychain;
+ }
+
+ /**
* Remove the current keychain
*/
unsetKeychain() {
diff --git a/src/Encryption/Keychain/CSEv1Keychain.js b/src/Encryption/Keychain/CSEv1Keychain.js
index 954bbd1..3944bb2 100644
--- a/src/Encryption/Keychain/CSEv1Keychain.js
+++ b/src/Encryption/Keychain/CSEv1Keychain.js
@@ -1,5 +1,4 @@
import sodium from 'libsodium-wrappers';
-import { v4 as uuid } from 'uuid';
export default class CSEv1Keychain {
@@ -57,6 +56,15 @@ export default class CSEv1Keychain {
}
/**
+ * Get a key by id
+ *
+ * @returns {String[]}
+ */
+ listKeys() {
+ return Object.keys(this._keys);
+ }
+
+ /**
* Get the current key
*
* @returns {String}
@@ -131,7 +139,7 @@ export default class CSEv1Keychain {
* Add a new key to the keychain and set it as current
*/
update() {
- let uuid = uuid();
+ let uuid = this._createUuid();
this._keys[uuid] = sodium.randombytes_buf(sodium.crypto_secretbox_KEYBYTES);
this._current = uuid;
this._enabled.set(true);
@@ -186,4 +194,14 @@ export default class CSEv1Keychain {
sodium.crypto_pwhash_ALG_DEFAULT
);
}
+ /**
+ * Create a uuidv4
+ *
+ * @returns {String}
+ */
+ _createUuid() {
+ return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
+ (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
+ );
+ }
} \ No newline at end of file
diff --git a/src/Model/CustomField/DataField.js b/src/Model/CustomField/DataField.js
index 5e9ee01..bb57428 100644
--- a/src/Model/CustomField/DataField.js
+++ b/src/Model/CustomField/DataField.js
@@ -1,5 +1,5 @@
import AbstractField from './AbstractField';
-import Properties from '../../Configuration/DataField';
+import Properties from '../../Configuration/DataField.json';
export default class DataField extends AbstractField {
diff --git a/src/Model/CustomField/EmailField.js b/src/Model/CustomField/EmailField.js
index a2f9c35..43066bc 100644
--- a/src/Model/CustomField/EmailField.js
+++ b/src/Model/CustomField/EmailField.js
@@ -1,5 +1,5 @@
import AbstractField from './AbstractField';
-import Properties from '../../Configuration/EmailField';
+import Properties from '../../Configuration/EmailField.json';
export default class EmailField extends AbstractField {
diff --git a/src/Model/CustomField/FileField.js b/src/Model/CustomField/FileField.js
index 9333742..e5e15f0 100644
--- a/src/Model/CustomField/FileField.js
+++ b/src/Model/CustomField/FileField.js
@@ -1,5 +1,5 @@
import AbstractField from './AbstractField';
-import Properties from '../../Configuration/FileField';
+import Properties from '../../Configuration/FileField.json';
export default class FileField extends AbstractField {
diff --git a/src/Model/CustomField/SecretField.js b/src/Model/CustomField/SecretField.js
index 9c0e2a9..bc67ed0 100644
--- a/src/Model/CustomField/SecretField.js
+++ b/src/Model/CustomField/SecretField.js
@@ -1,5 +1,5 @@
import AbstractField from './AbstractField';
-import Properties from '../../Configuration/SecretField';
+import Properties from '../../Configuration/SecretField.json';
export default class SecretField extends AbstractField {
diff --git a/src/Model/CustomField/TextField.js b/src/Model/CustomField/TextField.js
index 8be3f8e..fb16cf8 100644
--- a/src/Model/CustomField/TextField.js
+++ b/src/Model/CustomField/TextField.js
@@ -1,5 +1,5 @@
import AbstractField from './AbstractField';
-import Properties from '../../Configuration/TextField';
+import Properties from '../../Configuration/TextField.json';
export default class TextField extends AbstractField {
diff --git a/src/Model/CustomField/UrlField.js b/src/Model/CustomField/UrlField.js
index d572e5c..b8f3d16 100644
--- a/src/Model/CustomField/UrlField.js
+++ b/src/Model/CustomField/UrlField.js
@@ -1,5 +1,5 @@
import AbstractField from './AbstractField';
-import Properties from '../../Configuration/UrlField';
+import Properties from '../../Configuration/UrlField.json';
export default class UrlField extends AbstractField {
diff --git a/src/Model/Folder/Folder.js b/src/Model/Folder/Folder.js
index 531629e..e9d3b5a 100644
--- a/src/Model/Folder/Folder.js
+++ b/src/Model/Folder/Folder.js
@@ -1,4 +1,4 @@
-import Properties from '../../Configuration/Folder';
+import Properties from '../../Configuration/Folder.json';
import AbstractRevisionModel from '../AbstractRevisionModel';
export default class Folder extends AbstractRevisionModel {
diff --git a/src/Model/Password/Password.js b/src/Model/Password/Password.js
index 1a64a7d..199f999 100644
--- a/src/Model/Password/Password.js
+++ b/src/Model/Password/Password.js
@@ -1,4 +1,4 @@
-import Properties from '../../Configuration/Password';
+import Properties from '../../Configuration/Password.json';
import AbstractRevisionModel from '../AbstractRevisionModel';
export default class Password extends AbstractRevisionModel {
diff --git a/src/Model/Server/Server.js b/src/Model/Server/Server.js
index 792ac6b..cfce53a 100644
--- a/src/Model/Server/Server.js
+++ b/src/Model/Server/Server.js
@@ -1,5 +1,5 @@
import ConfigruationError from '../../Exception/ConfigruationError';
-import Properties from '../../Configuration/Server';
+import Properties from '../../Configuration/Server.json';
import AbstractModel from './../AbstractModel';
import ObjectMerger from '../../Utility/ObjectMerger';
diff --git a/src/Model/Tag/Tag.js b/src/Model/Tag/Tag.js
index b8f851e..a495bb3 100644
--- a/src/Model/Tag/Tag.js
+++ b/src/Model/Tag/Tag.js
@@ -1,4 +1,4 @@
-import Properties from '../../Configuration/Tag';
+import Properties from '../../Configuration/Tag.json';
import AbstractRevisionModel from '../AbstractRevisionModel';
export default class Tag extends AbstractRevisionModel {
diff --git a/src/http.js b/src/http.js
new file mode 100644
index 0000000..3d2b610
--- /dev/null
+++ b/src/http.js
@@ -0,0 +1,11 @@
+import ApiRequest from './Network/ApiRequest';
+import ApiResponse from './Network/ApiResponse';
+import HttpRequest from './Network/HttpRequest';
+import HttpResponse from './Network/HttpResponse';
+
+export {
+ ApiRequest,
+ ApiResponse,
+ HttpRequest,
+ HttpResponse
+} \ No newline at end of file
diff --git a/src/legacy.js b/src/legacy.js
new file mode 100644
index 0000000..0eb98c2
--- /dev/null
+++ b/src/legacy.js
@@ -0,0 +1,7 @@
+import EnhancedApi from "./Classes/EnhancedApi";
+import SimpleApi from "./Classes/SimpleApi";
+
+export {
+ EnhancedApi,
+ SimpleApi
+} \ No newline at end of file