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>2020-12-27 20:43:01 +0300
committerMarius David Wieschollek <passwords.public@mdns.eu>2020-12-27 20:43:01 +0300
commita9311b7569fe54008bbdb376a7a5845608d250b9 (patch)
tree83767c833517c7dfafc70ab8e19fe1b31e186994
parent39f832d056b3e386d8934ca2e2840abde83f377d (diff)
Fix issues with encrypted object creation
Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
-rw-r--r--src/ClassLoader/DefaultClassLoader.js2
-rw-r--r--src/Collection/AbstractCollection.js4
-rw-r--r--src/Converter/AbstractConverter.js2
-rw-r--r--src/Converter/PasswordConverter.js17
-rw-r--r--src/Encryption/CSEv1Encryption.js12
-rw-r--r--src/Services/HashService.js100
-rw-r--r--src/Services/ModelService.js2
7 files changed, 127 insertions, 12 deletions
diff --git a/src/ClassLoader/DefaultClassLoader.js b/src/ClassLoader/DefaultClassLoader.js
index 5cc8bf0..18c5dbd 100644
--- a/src/ClassLoader/DefaultClassLoader.js
+++ b/src/ClassLoader/DefaultClassLoader.js
@@ -63,6 +63,7 @@ import ChallengeTypeNotSupported from "../Exception/ChallengeTypeNotSupported";
import ConfigurationError from "../Exception/ConfigruationError";
import MissingEncryptionKeyError from "../Exception/Encryption/MissingEncryptionKeyError";
import InvalidEncryptedTextLength from "../Exception/Encryption/InvalidEncryptedTextLength";
+import HashService from "../Services/HashService";
export default class DefaultClassLoader extends BasicClassLoader {
@@ -119,6 +120,7 @@ export default class DefaultClassLoader extends BasicClassLoader {
'keychain.csev1': (k, p) => { return new CSEv1Keychain(this.getInstance('classes'), k, p); },
+ 'service.hash' : () => { return new HashService(this.getInstance('classes')); },
'service.model' : () => { return new ModelService(this.getInstance('classes')); },
'service.password': () => { return new PasswordService(this.getInstance('client')); },
diff --git a/src/Collection/AbstractCollection.js b/src/Collection/AbstractCollection.js
index 41acbd5..d7de25c 100644
--- a/src/Collection/AbstractCollection.js
+++ b/src/Collection/AbstractCollection.js
@@ -138,7 +138,7 @@ export default class AbstractCollection {
}
/**
- * @return {String[]}
+ * @return {Object}
*/
toJSON() {
let json = [];
@@ -147,7 +147,7 @@ export default class AbstractCollection {
json.push(this._converter.toObject(element));
}
- return JSON.stringify(json);
+ return json;
}
[Symbol.iterator]() {
diff --git a/src/Converter/AbstractConverter.js b/src/Converter/AbstractConverter.js
index 0622aa7..3b471bf 100644
--- a/src/Converter/AbstractConverter.js
+++ b/src/Converter/AbstractConverter.js
@@ -89,7 +89,7 @@ export default class AbstractConverter {
* @api
*/
async toEncryptedData(model) {
- let data = this.toObject(model);
+ let data = await this.toObject(model);
if(data.cseType === 'none') {
return await this._api.getInstance('encryption.none').encrypt(data, this._type);
diff --git a/src/Converter/PasswordConverter.js b/src/Converter/PasswordConverter.js
index 2874ebf..13e16e5 100644
--- a/src/Converter/PasswordConverter.js
+++ b/src/Converter/PasswordConverter.js
@@ -8,8 +8,9 @@ export default class PasswordConverter extends AbstractConverter {
*/
constructor(api) {
super(api, 'password');
- /** @type CustomFieldConverter **/
+ /** @type {CustomFieldConverter} **/
this._customFieldConverter = this._api.getInstance('converter.field');
+ this._hashService = /** @type {HashService} **/ this._api.getInstance('service.hash');
}
/**
@@ -37,4 +38,18 @@ export default class PasswordConverter extends AbstractConverter {
return this._api.getClass(`model.${this._type}`, clone, this._api);
}
+
+ /**
+ *
+ * @param {(Password|AbstractRevisionModel)} model
+ * @returns {Promise<void>}
+ */
+ async toObject(model) {
+ let data = super.toObject(model);
+
+ data.customFields = this._customFieldConverter.toJSON(model.getCustomFields());
+ data.hash = await this._hashService.getHash(model.getPassword(), this._hashService.HASH_SHA_1);
+
+ return data;
+ }
} \ No newline at end of file
diff --git a/src/Encryption/CSEv1Encryption.js b/src/Encryption/CSEv1Encryption.js
index 06e5891..10e29a9 100644
--- a/src/Encryption/CSEv1Encryption.js
+++ b/src/Encryption/CSEv1Encryption.js
@@ -49,11 +49,10 @@ export default class CSEv1Encryption {
let fields = this.fields[type],
key = this._keychain.getCurrentKey();
- for(let i = 0; i < fields.length; i++) {
- let field = fields[i],
- data = object[field];
+ for(let field of fields) {
+ let data = object[field];
- if(data === null || data.length === 0) continue;
+ if(data === null || data === undefined || data.length === 0) continue;
object[field] = this._encryptString(data, key);
}
@@ -78,9 +77,8 @@ export default class CSEv1Encryption {
let fields = this.fields[type],
key = this._keychain.getKey(object.cseKey);
- for(let i = 0; i < fields.length; i++) {
- let field = fields[i],
- data = object[field];
+ for(let field of fields) {
+ let data = object[field];
if(data === null || data.length === 0) continue;
object[field] = this._decryptString(data, key);
diff --git a/src/Services/HashService.js b/src/Services/HashService.js
new file mode 100644
index 0000000..7942ae7
--- /dev/null
+++ b/src/Services/HashService.js
@@ -0,0 +1,100 @@
+import sodium from "libsodium-wrappers";
+
+export default class HashService {
+
+ get HASH_SHA_1() {
+ return 'SHA-1';
+ }
+
+ get HASH_SHA_256() {
+ return 'SHA-256';
+ }
+
+ get HASH_SHA_384() {
+ return 'SHA-384';
+ }
+
+ get HASH_SHA_512() {
+ return 'SHA-512';
+ }
+
+ get HASH_BLAKE2B() {
+ return 'BLAKE2b';
+ }
+
+ get HASH_BLAKE2B_224() {
+ return 'BLAKE2b-224';
+ }
+
+ get HASH_BLAKE2B_256() {
+ return 'BLAKE2b-256';
+ }
+
+ get HASH_BLAKE2B_384() {
+ return 'BLAKE2b-384';
+ }
+
+ get HASH_BLAKE2B_512() {
+ return 'BLAKE2b-512';
+ }
+
+ get HASH_ARGON2() {
+ return 'Argon2';
+ }
+
+ constructor(classLoader) {
+ this._ready = classLoader.getClass('state.boolean', false);
+
+ sodium.ready.then(() => {this._ready.set(true);});
+ }
+
+ /**
+ * Generate a hash of the given value with the given algorithm
+ *
+ * @param {String} value
+ * @param {String} [algorithm=SHA-1]
+ * @returns {Promise<string>}
+ */
+ async getHash(value, algorithm = 'SHA-1') {
+ await this._ready.awaitTrue();
+
+ if([this.HASH_SHA_1, this.HASH_SHA_256, this.HASH_SHA_384, this.HASH_SHA_512].indexOf(algorithm) !== -1) {
+ return await this._makeShaHash(value, algorithm);
+ } else if(algorithm.substr(0, 7) === this.HASH_BLAKE2B) {
+ return this._makeBlake2bHash(algorithm, value);
+ } else if(algorithm === this.HASH_ARGON2) {
+ return sodium.crypto_pwhash_str(value, sodium.crypto_pwhash_OPSLIMIT_MIN, sodium.crypto_pwhash_MEMLIMIT_MIN);
+ }
+ }
+
+ /**
+ *
+ * @param {String} value
+ * @param {String} algorithm
+ * @returns {Promise<String>}
+ * @private
+ */
+ async _makeShaHash(value, algorithm) {
+ let msgBuffer = new TextEncoder('utf-8').encode(value),
+ hashBuffer = await crypto.subtle.digest(algorithm, msgBuffer);
+
+ return sodium.to_hex(new Uint8Array(hashBuffer));
+ }
+
+ /**
+ * @param {String} algorithm
+ * @param {String} value
+ * @returns {String}
+ * @private
+ */
+ _makeBlake2bHash(algorithm, value) {
+ 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)));
+ }
+} \ No newline at end of file
diff --git a/src/Services/ModelService.js b/src/Services/ModelService.js
index 395255e..211b44d 100644
--- a/src/Services/ModelService.js
+++ b/src/Services/ModelService.js
@@ -22,6 +22,7 @@ export default class ModelService {
addModel(type, model) {
this._cache.set(`${type}.${model.getId()}`, model);
+ this._cache.set(`${type}.${model.getId()}.${model.getRevision()}`, model);
// @TODO update related models
}
@@ -254,7 +255,6 @@ export default class ModelService {
_mergeStandardProperties(model, newModel, excludeProperties) {
if(model.getRevision() === newModel.getRevision()) {
model.setUpdated(newModel.getUpdated());
- return;
}
excludeProperties.push('id, revisions')