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
path: root/src
diff options
context:
space:
mode:
authorMarius David Wieschollek <passwords.public@mdns.eu>2020-12-23 00:53:56 +0300
committerMarius David Wieschollek <passwords.public@mdns.eu>2020-12-23 00:53:56 +0300
commitd8e2ab26c60ed6ffee324711720d6b51ea70f718 (patch)
tree5fd548f6b9e2295bc8a457a2196409f0c6a5fc4c /src
parenta4f90d861516e5b7cc1779f6a6ad563585c85d98 (diff)
Improve encryption handling
Throw errors when encryption not ready on decrypt Allow session renew Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
Diffstat (limited to 'src')
-rw-r--r--src/Authorization/SessionAuthorization.js1
-rw-r--r--src/Client/BasicPasswordsClient.js49
-rw-r--r--src/Encryption/CSEv1Encryption.js26
-rw-r--r--src/Exception/Encryption/EncryptionNotEnabledError.js5
-rw-r--r--src/Exception/Encryption/InvalidObjectTypeError.js5
-rw-r--r--src/Exception/Encryption/UnsupportedEncryptionTypeError.js27
-rw-r--r--src/Exception/EncryptionTypeNotSupported.js29
-rw-r--r--src/Repositories/AbstractRepository.js44
-rw-r--r--src/main.js7
9 files changed, 109 insertions, 84 deletions
diff --git a/src/Authorization/SessionAuthorization.js b/src/Authorization/SessionAuthorization.js
index 9a84ef1..8b36bf1 100644
--- a/src/Authorization/SessionAuthorization.js
+++ b/src/Authorization/SessionAuthorization.js
@@ -1,4 +1,3 @@
-import PWDv1Challenge from './Challenge/PWDv1Challenge';
import CSEv1Keychain from '../Encryption/Keychain/CSEv1Keychain';
import AbstractToken from './Token/AbstractToken';
diff --git a/src/Client/BasicPasswordsClient.js b/src/Client/BasicPasswordsClient.js
index d5f1a84..f313211 100644
--- a/src/Client/BasicPasswordsClient.js
+++ b/src/Client/BasicPasswordsClient.js
@@ -14,10 +14,11 @@ export default class BasicPasswordsClient {
this._classes.setInstance('model.server', server);
this._classes.setInstance('api', this);
this._classes.setInstance('client', this);
+ this._classes.setInstance('classes', this._classes);
this._server = server;
- this._session = this._classes.getInstance('model.session', server.getUser(), server.getToken());
this._events = this._classes.getInstance('event.event');
+ this.renewSession();
}
/**
@@ -79,7 +80,7 @@ export default class BasicPasswordsClient {
*/
getRequest() {
/** @type {ApiRequest} **/
- let request = this.getClass('network.request', this, this._server.getApiUrl(), this.getSession());
+ let request = this._classes.getClass('network.request', this, this._server.getApiUrl(), this.getSession());
if(this._config.userAgent !== null) {
request.setUserAgent(this._config.userAgent);
}
@@ -91,9 +92,23 @@ export default class BasicPasswordsClient {
* @returns {Session}
*/
getSession() {
- return this._session
- .setUser(this._server.getUser())
- .setToken(this._server.getToken());
+ return this
+ ._session
+ .setUser(this._server.getUser())
+ .setToken(this._server.getToken());
+ }
+
+ /**
+ * Replaces the session with a blank one
+ *
+ * @returns {Session}
+ */
+ renewSession() {
+ this._session = this._classes.getClass('model.session', this._server.getUser(), this._server.getToken());
+ this._classes.setInstance('session', this._session);
+ this._classes.setInstance('model.session', this._session);
+ this._classes.setInstance('authorization.session', this._classes.getClass('authorization.session'));
+ return this._session;
}
/**
@@ -101,7 +116,7 @@ export default class BasicPasswordsClient {
* @returns {SessionAuthorization}
*/
getSessionAuthorization() {
- return this.getInstance('authorization.session');
+ return this._classes.getInstance('authorization.session');
}
/**
@@ -109,7 +124,7 @@ export default class BasicPasswordsClient {
* @returns {PasswordRepository}
*/
getPasswordRepository() {
- return this.getInstance('repository.password');
+ return this._classes.getInstance('repository.password');
}
/**
@@ -117,7 +132,7 @@ export default class BasicPasswordsClient {
* @returns {FolderRepository}
*/
getFolderRepository() {
- return this.getInstance('repository.folder');
+ return this._classes.getInstance('repository.folder');
}
/**
@@ -125,7 +140,7 @@ export default class BasicPasswordsClient {
* @returns {TagRepository}
*/
getTagRepository() {
- return this.getInstance('repository.tag');
+ return this._classes.getInstance('repository.tag');
}
/**
@@ -133,7 +148,7 @@ export default class BasicPasswordsClient {
* @returns {CSEv1Encryption}
*/
getCseV1Encryption() {
- return this.getInstance('encryption.csev1');
+ return this._classes.getInstance('encryption.csev1');
}
/**
@@ -147,16 +162,16 @@ export default class BasicPasswordsClient {
}
if(mode === 'none') {
- return this.getInstance('encryption.none');
+ return this._classes.getInstance('encryption.none');
}
if(mode === 'csev1') {
- return this.getInstance('encryption.csev1');
+ return this._classes.getInstance('encryption.csev1');
}
- let csev1 = this.getInstance('encryption.csev1');
+ let csev1 = this._classes.getInstance('encryption.csev1');
if(csev1.enabled()) return csev1;
- return this.getInstance('encryption.none');
+ return this._classes.getInstance('encryption.none');
}
/**
@@ -165,7 +180,7 @@ export default class BasicPasswordsClient {
* @return {*}
*/
getInstance(...parameters) {
- return this._classes.getInstance(...parameters)
+ return this._classes.getInstance(...parameters);
}
/**
@@ -174,7 +189,7 @@ export default class BasicPasswordsClient {
* @return {*}
*/
setInstance(...parameters) {
- return this._classes.setInstance(...parameters)
+ return this._classes.setInstance(...parameters);
}
/**
@@ -183,7 +198,7 @@ export default class BasicPasswordsClient {
* @return {*}
*/
getClass(...parameters) {
- return this._classes.getClass(...parameters)
+ return this._classes.getClass(...parameters);
}
/**
diff --git a/src/Encryption/CSEv1Encryption.js b/src/Encryption/CSEv1Encryption.js
index 9beb88c..efe772b 100644
--- a/src/Encryption/CSEv1Encryption.js
+++ b/src/Encryption/CSEv1Encryption.js
@@ -1,17 +1,20 @@
import sodium from 'libsodium-wrappers';
-import BooleanState from '../State/BooleanState';
export default class CSEv1Encryption {
- constructor() {
+ /**
+ * @param {BasicClassLoader} classLoader
+ */
+ constructor(classLoader) {
this.fields = {
password: ['url', 'label', 'notes', 'password', 'username', 'customFields'],
folder : ['label'],
tag : ['label', 'color']
};
- this._enabled = new BooleanState(false);
- this._ready = new BooleanState(false);
+ this._enabled = classLoader.getClass('state.boolean', false);
+ this._ready = classLoader.getClass('state.boolean', false);
this._keychain = null;
+ this._classLoader = classLoader;
sodium.ready.then(() => {this._ready.set(true);});
}
@@ -22,6 +25,7 @@ export default class CSEv1Encryption {
*/
async ready() {
await this._ready.awaitTrue() && await this._enabled.awaitTrue();
+ return true;
}
/**
@@ -29,7 +33,7 @@ export default class CSEv1Encryption {
* @returns {Boolean}
*/
enabled() {
- this._ready.get() && this._enabled.get();
+ return this._ready.get() && this._enabled.get();
}
/**
@@ -40,9 +44,8 @@ export default class CSEv1Encryption {
* @returns {Object}
*/
async encrypt(object, type) {
- // TODO custom errors here
- if(!this.fields.hasOwnProperty(type)) throw new Error('Invalid object type');
- await this.ready();
+ if(!this.fields.hasOwnProperty(type)) throw this._classLoader.getClass('exception.encryption.object');
+ if(!this.enabled()) throw this._classLoader.getClass('exception.encryption.enabled');
let fields = this.fields[type],
key = this._keychain.getCurrentKey();
@@ -69,10 +72,9 @@ export default class CSEv1Encryption {
* @returns {Object}
*/
async decrypt(object, type) {
- // TODO custom errors here
- if(!this.fields.hasOwnProperty(type)) throw new Error('Invalid object type');
- if(object.cseType !== 'CSEv1r1') throw new Error('Unsupported encryption type');
- await this.ready();
+ if(!this.fields.hasOwnProperty(type)) throw this._classLoader.getClass('exception.encryption.object');
+ if(object.cseType !== 'CSEv1r1') throw this._classLoader.getClass('exception.encryption.unsupported', object, 'CSEv1r1');
+ if(!this.enabled()) throw this._classLoader.getClass('exception.encryption.enabled');
let fields = this.fields[type],
key = this._keychain.getKey(object.cseKey);
diff --git a/src/Exception/Encryption/EncryptionNotEnabledError.js b/src/Exception/Encryption/EncryptionNotEnabledError.js
new file mode 100644
index 0000000..b31461c
--- /dev/null
+++ b/src/Exception/Encryption/EncryptionNotEnabledError.js
@@ -0,0 +1,5 @@
+export default class EncryptionNotEnabledError extends Error {
+ constructor() {
+ super(`CSE Encryption not enabled or ready`);
+ }
+} \ No newline at end of file
diff --git a/src/Exception/Encryption/InvalidObjectTypeError.js b/src/Exception/Encryption/InvalidObjectTypeError.js
new file mode 100644
index 0000000..de0d77b
--- /dev/null
+++ b/src/Exception/Encryption/InvalidObjectTypeError.js
@@ -0,0 +1,5 @@
+export default class InvalidObjectTypeError extends Error {
+ constructor(type) {
+ super(`Invalid Object Type "${type}"`);
+ }
+} \ No newline at end of file
diff --git a/src/Exception/Encryption/UnsupportedEncryptionTypeError.js b/src/Exception/Encryption/UnsupportedEncryptionTypeError.js
new file mode 100644
index 0000000..adef944
--- /dev/null
+++ b/src/Exception/Encryption/UnsupportedEncryptionTypeError.js
@@ -0,0 +1,27 @@
+export default class UnsupportedEncryptionTypeError extends Error {
+
+ /**
+ * @returns {String}
+ */
+ get supportedTypes() {
+ return this._supportedTypes;
+ }
+
+ /**
+ * @returns {Object}
+ */
+ get object() {
+ return this._object;
+ }
+
+ constructor(object, supportedTypes) {
+ if(Array.isArray(supportedTypes)) {
+ supportedTypes = supportedTypes.join(', ');
+ }
+
+ super(`Unsupported encryption type "${object.cseType}" in ${object.id}. Supported types are ${supportedTypes}.`);
+
+ this._object = object;
+ this._supportedTypes = supportedTypes;
+ }
+} \ No newline at end of file
diff --git a/src/Exception/EncryptionTypeNotSupported.js b/src/Exception/EncryptionTypeNotSupported.js
deleted file mode 100644
index aa1824d..0000000
--- a/src/Exception/EncryptionTypeNotSupported.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export default class EncryptionTypeNotSupported extends Error {
-
- /**
- *
- * @return {String}
- */
- get objectId() {
- return this._objectId;
- }
-
- /**
- *
- * @return {String}
- */
- get cseType() {
- return this._cseType;
- }
-
- /**
- *
- * @param {String} objectId
- * @param {String} cseType
- */
- constructor(objectId, cseType) {
- super(`The encryption type ${cseType} used for ${objectId} is not supported by this client`);
- this._objectId = objectId;
- this._cseType = cseType;
- }
-} \ No newline at end of file
diff --git a/src/Repositories/AbstractRepository.js b/src/Repositories/AbstractRepository.js
index ce14382..b947299 100644
--- a/src/Repositories/AbstractRepository.js
+++ b/src/Repositories/AbstractRepository.js
@@ -199,26 +199,30 @@ export default class AbstractRepository {
* @return {Promise<AbstractRevisionModel[]>}
* @private
*/
- async _dataToModels(data, detailLevel) {
- let promises = [],
- models = [];
-
- for(let element of data) {
- promises.push(new Promise((resolve) => {
- this._dataToModel(element, detailLevel)
- .then((model) => {
- models.push(model);
- resolve();
- })
- .catch((e) => {
- console.error(e, element);
- });
- }));
- }
+ _dataToModels(data, detailLevel) {
+ return new Promise(async (resolve, reject) => {
+ let promises = [],
+ models = [];
+
+ for(let element of data) {
+ promises.push(
+ new Promise(
+ (resolve) => {
+ this._dataToModel(element, detailLevel)
+ .then((model) => {
+ models.push(model);
+ resolve();
+ })
+ .catch(reject);
+ }
+ )
+ );
+ }
- await Promise.all(promises);
+ await Promise.all(promises);
- return models;
+ resolve(models);
+ });
}
/**
@@ -241,12 +245,12 @@ export default class AbstractRepository {
if(typeof detailLevel === 'string') {
detailLevel = detailLevel.trim().split('+');
}
- if(detailLevel===null || detailLevel.length === 0) return this.DEFAULT_DETAIL_LEVEL;
+ if(detailLevel === null || detailLevel.length === 0) return this.DEFAULT_DETAIL_LEVEL;
for(let level of detailLevel) {
if(this.AVAILABLE_DETAIL_LEVELS.indexOf(level) === -1) {
// @TODO custom error
- throw new Error('Unknown detail level '+level);
+ throw new Error('Unknown detail level ' + level);
}
}
diff --git a/src/main.js b/src/main.js
index 60a01ee..4f19add 100644
--- a/src/main.js
+++ b/src/main.js
@@ -12,10 +12,8 @@ import EnhancedTag from "./Model/Tag/EnhancedTag";
import Tag from "./Model/Tag/Tag";
import Server from "./Model/Server/Server";
-/** @deprecated **/
-const Api = PasswordsClient;
-
export default PasswordsClient;
+
export {
PasswordsClient,
BasicPasswordsClient,
@@ -29,6 +27,5 @@ export {
Password,
Folder,
Tag,
- Server,
- Api
+ Server
};