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/Model
diff options
context:
space:
mode:
Diffstat (limited to 'src/Model')
-rw-r--r--src/Model/AbstractModel.js109
-rw-r--r--src/Model/AbstractRevisionModel.js287
-rw-r--r--src/Model/CustomField/AbstractField.js95
-rw-r--r--src/Model/CustomField/DataField.js14
-rw-r--r--src/Model/CustomField/DefectField.js14
-rw-r--r--src/Model/CustomField/EmailField.js14
-rw-r--r--src/Model/CustomField/FileField.js14
-rw-r--r--src/Model/CustomField/SecretField.js14
-rw-r--r--src/Model/CustomField/TextField.js14
-rw-r--r--src/Model/CustomField/UrlField.js14
-rw-r--r--src/Model/Folder/EnhancedFolder.js70
-rw-r--r--src/Model/Folder/Folder.js119
-rw-r--r--src/Model/Password/EnhancedPassword.js130
-rw-r--r--src/Model/Password/Password.js232
-rw-r--r--src/Model/Server/Server.js80
-rw-r--r--src/Model/Session/Session.js87
-rw-r--r--src/Model/Setting/Setting.js179
-rw-r--r--src/Model/Tag/EnhancedTag.js38
-rw-r--r--src/Model/Tag/Tag.js45
19 files changed, 1569 insertions, 0 deletions
diff --git a/src/Model/AbstractModel.js b/src/Model/AbstractModel.js
new file mode 100644
index 0000000..8b75fe8
--- /dev/null
+++ b/src/Model/AbstractModel.js
@@ -0,0 +1,109 @@
+import UnknownPropertyError from '../Exception/UnknownPropertyError';
+
+export default class AbstractModel {
+
+ /**
+ * @param {Object} properties
+ * @param {Object} [data={}]
+ */
+ constructor(properties, data = {}) {
+ this._properties = properties;
+ this._originalData = {};
+ this._data = {};
+ this.setProperties(data);
+ this._originalData = {};
+ }
+
+ /**
+ *
+ * @param {String} property
+ * @return {boolean}
+ */
+ hasProperty(property) {
+ return this._properties.hasOwnProperty(property);
+ }
+
+ /**
+ * @param {String} property
+ *
+ * @return {*}
+ * @api
+ */
+ getProperty(property) {
+ if(!this.hasProperty(property)) {
+ throw new UnknownPropertyError(property, this);
+ }
+
+ if(!this._data.hasOwnProperty(property)) {
+ return undefined;
+ }
+
+ return this._data[property];
+ }
+
+ /**
+ * @param {String} property
+ * @param {*} value
+ *
+ * @return {this}
+ * @api
+ */
+ setProperty(property, value) {
+ if(!this.hasProperty(property)) {
+ throw new UnknownPropertyError(property, this);
+ }
+
+ this._originalData[property] = this._data[property];
+ this._data[property] = value;
+
+ return this;
+ }
+
+ /**
+ * @return {{}}
+ * @api
+ */
+ getProperties() {
+ let data = {};
+
+ for(let key in this._properties) {
+ if(!this._properties.hasOwnProperty(key)) continue;
+
+ data[key] = this.getProperty(key);
+ }
+
+ return data;
+ }
+
+ /**
+ * @param {Object} properties
+ *
+ * @return {this}
+ * @api
+ */
+ setProperties(properties) {
+ for(let key in properties) {
+ if(!properties.hasOwnProperty(key)) continue;
+
+ this.setProperty(key, properties[key]);
+ }
+
+ return this;
+ }
+
+ /**
+ * @return {Object}
+ */
+ getPropertyConfiguration() {
+ return this._properties;
+ }
+
+ /**
+ *
+ * @return {{}}
+ * @api
+ */
+ toJSON() {
+ return this.getProperties();
+ }
+} \ No newline at end of file
diff --git a/src/Model/AbstractRevisionModel.js b/src/Model/AbstractRevisionModel.js
new file mode 100644
index 0000000..b565f18
--- /dev/null
+++ b/src/Model/AbstractRevisionModel.js
@@ -0,0 +1,287 @@
+import AbstractModel from './AbstractModel';
+
+export default class AbstractRevisionModel extends AbstractModel {
+
+ constructor(properties, data) {
+ super(properties, data);
+ this._detailLevel = [];
+ }
+
+ /**
+ * @return {String[]}
+ */
+ getDetailLevel() {
+ return this._detailLevel;
+ }
+
+ /**
+ * @param {String[]} value
+ * @return {AbstractRevisionModel}
+ */
+ setDetailLevel(value) {
+ return this._detailLevel;
+ }
+
+ /**
+ * @return {String}
+ * @api
+ */
+ getId() {
+ return this.getProperty('id');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {this}
+ * @api
+ */
+ setId(value) {
+ return this.setProperty('id', value);
+ }
+
+ /**
+ * @return {string}
+ * @api
+ */
+ getRevision() {
+ return this.getProperty('revision');
+ }
+
+ /**
+ * @param {string} value
+ *
+ * @return {this}
+ * @api
+ */
+ setRevision(value) {
+ return this.setProperty('revision', value);
+ }
+
+ /**
+ * @return {string}
+ * @api
+ */
+ getCseType() {
+ return this.getProperty('cseType');
+ }
+
+ /**
+ * @param {string} value
+ *
+ * @return {this}
+ * @api
+ */
+ setCseType(value) {
+ return this.setProperty('cseType', value);
+ }
+
+ /**
+ * @return {string}
+ * @api
+ */
+ getCseKey() {
+ return this.getProperty('cseKey');
+ }
+
+ /**
+ *
+ * @param {string} value
+ * @return {this}
+ * @api
+ */
+ setCseKey(value) {
+ return this.setProperty('cseKey', value);
+ }
+
+ /**
+ * @return {string}
+ * @api
+ */
+ getSseType() {
+ return this.getProperty('sseType');
+ }
+
+ /**
+ * @param {string} value
+ *
+ * @return {this}
+ * @api
+ */
+ setSseType(value) {
+ return this.setProperty('sseType', value);
+ }
+
+ /**
+ * @return {string}
+ * @api
+ */
+ getClient() {
+ return this.getProperty('client');
+ }
+
+ /**
+ * @param {string} value
+ *
+ * @return {this}
+ * @api
+ */
+ setClient(value) {
+ return this.setProperty('client', value);
+ }
+
+ /**
+ * @return {Boolean}
+ * @api
+ */
+ isHidden() {
+ return this.getProperty('hidden');
+ }
+
+ /**
+ * @return {Boolean}
+ * @api
+ */
+ getHidden() {
+ return this.getProperty('hidden');
+ }
+
+ /**
+ * @param {Boolean} value
+ *
+ * @return {this}
+ * @api
+ */
+ setHidden(value) {
+ return this.setProperty('hidden', value);
+ }
+
+ /**
+ * @return {Boolean}
+ * @api
+ */
+ isTrashed() {
+ return this.getProperty('trashed');
+ }
+
+ /**
+ * @return {Boolean}
+ * @api
+ */
+ getTrashed() {
+ return this.getProperty('trashed');
+ }
+
+ /**
+ * @param {Boolean} value
+ *
+ * @return {this}
+ * @api
+ */
+ setTrashed(value) {
+ return this.setProperty('trashed', value);
+ }
+
+ /**
+ * @return {Boolean}
+ * @api
+ */
+ isFavorite() {
+ return this.getProperty('favorite');
+ }
+
+ /**
+ * @return {Boolean}
+ * @api
+ */
+ getFavorite() {
+ return this.getProperty('favorite');
+ }
+
+ /**
+ * @param {Boolean} value
+ *
+ * @return {this}
+ * @api
+ */
+ setFavorite(value) {
+ return this.setProperty('favorite', value);
+ }
+
+ /**
+ * @return {Date}
+ * @api
+ */
+ getEdited() {
+ return this.getProperty('edited');
+ }
+
+ /**
+ * @param {Date} value
+ *
+ * @return {this}
+ * @api
+ */
+ setEdited(value) {
+ return this.setProperty('edited', value);
+ }
+
+ /**
+ * @return {Date}
+ * @api
+ */
+ getCreated() {
+ return this.getProperty('created');
+ }
+
+ /**
+ * @param {Date} value
+ *
+ * @return {this}
+ * @api
+ */
+ setCreated(value) {
+ return this.setProperty('created', value);
+ }
+
+ /**
+ * @return {Date}
+ * @api
+ */
+ getUpdated() {
+ return this.getProperty('updated');
+ }
+
+ /**
+ * @param {Date} value
+ *
+ * @return {this}
+ * @api
+ */
+ setUpdated(value) {
+ return this.setProperty('updated', value);
+ }
+
+ /**
+ *
+ * @return {{}}
+ * @api
+ */
+ toJSON() {
+ let properties = this.getProperties();
+
+ if(properties.hasOwnProperty('created') && properties.created instanceof Date) {
+ properties.created = Math.floor(properties.created.getTime() / 1000);
+ }
+
+ if(properties.hasOwnProperty('edited') && properties.edited instanceof Date) {
+ properties.edited = Math.floor(properties.edited.getTime() / 1000);
+ }
+
+ if(properties.hasOwnProperty('updated') && properties.updated instanceof Date) {
+ properties.updated = Math.floor(properties.updated.getTime() / 1000);
+ }
+
+ return properties;
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/AbstractField.js b/src/Model/CustomField/AbstractField.js
new file mode 100644
index 0000000..d1576d7
--- /dev/null
+++ b/src/Model/CustomField/AbstractField.js
@@ -0,0 +1,95 @@
+import AbstractModel from '../AbstractModel';
+
+export default class AbstractField extends AbstractModel {
+
+ /**
+ * @param {String} value
+ */
+ set type(value) {
+ throw new Error('Type is not writeable')
+ }
+
+ /**
+ * @return {String}
+ */
+ get type() {
+ return this.getProperty('type');
+ }
+
+ /**
+ * @param {String} value
+ */
+ set label(value) {
+ this.setProperty('label', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ get label() {
+ return this.getProperty('label');
+ }
+
+ /**
+ * @param {String} value
+ */
+ set value(value) {
+ this.setProperty('value', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ get value() {
+ return this.getProperty('value');
+ }
+
+ /**
+ * @param {String} value
+ * @return {this}
+ */
+ setType(value) {
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getType() {
+ return this.getProperty('type');
+ }
+
+ /**
+ * @param {String} value
+ * @return {this}
+ */
+ setLabel(value) {
+ this.label = value;
+
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getLabel() {
+ return this.getProperty('label');
+ }
+
+ /**
+ * @param {String} value
+ * @return {this}
+ */
+ setValue(value) {
+ this.value = value;
+
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getValue() {
+ return this.getProperty('value');
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/DataField.js b/src/Model/CustomField/DataField.js
new file mode 100644
index 0000000..5e9ee01
--- /dev/null
+++ b/src/Model/CustomField/DataField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/DataField';
+
+export default class DataField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'data';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/DefectField.js b/src/Model/CustomField/DefectField.js
new file mode 100644
index 0000000..773f311
--- /dev/null
+++ b/src/Model/CustomField/DefectField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/TextField.json';
+
+export default class DefectField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'defect';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/EmailField.js b/src/Model/CustomField/EmailField.js
new file mode 100644
index 0000000..a2f9c35
--- /dev/null
+++ b/src/Model/CustomField/EmailField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/EmailField';
+
+export default class EmailField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'email';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/FileField.js b/src/Model/CustomField/FileField.js
new file mode 100644
index 0000000..9333742
--- /dev/null
+++ b/src/Model/CustomField/FileField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/FileField';
+
+export default class FileField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'file';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/SecretField.js b/src/Model/CustomField/SecretField.js
new file mode 100644
index 0000000..9c0e2a9
--- /dev/null
+++ b/src/Model/CustomField/SecretField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/SecretField';
+
+export default class SecretField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'secret';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/TextField.js b/src/Model/CustomField/TextField.js
new file mode 100644
index 0000000..8be3f8e
--- /dev/null
+++ b/src/Model/CustomField/TextField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/TextField';
+
+export default class TextField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'text';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/CustomField/UrlField.js b/src/Model/CustomField/UrlField.js
new file mode 100644
index 0000000..d572e5c
--- /dev/null
+++ b/src/Model/CustomField/UrlField.js
@@ -0,0 +1,14 @@
+import AbstractField from './AbstractField';
+import Properties from '../../Configuration/UrlField';
+
+export default class UrlField extends AbstractField {
+
+ /**
+ *
+ * @param {object} data
+ */
+ constructor(data) {
+ data.type = 'url';
+ super(Properties, data);
+ }
+} \ No newline at end of file
diff --git a/src/Model/Folder/EnhancedFolder.js b/src/Model/Folder/EnhancedFolder.js
new file mode 100644
index 0000000..cbc6d8f
--- /dev/null
+++ b/src/Model/Folder/EnhancedFolder.js
@@ -0,0 +1,70 @@
+import Folder from './Folder';
+
+export default class EnhancedFolder extends Folder {
+
+ /**
+ *
+ * @param {Object} [data={}]
+ * @param {BasicPasswordsClient} api
+ */
+ constructor(data = {}, api) {
+ super(data);
+ this._api = api;
+ }
+
+ /**
+ *
+ * @returns {Server}
+ */
+ getServer() {
+ return this._api.getServer();
+ }
+
+ /**
+ *
+ * @returns {Promise<FolderCollection>}
+ */
+ async fetchRevisions() {
+ if(this.getProperty('revisions') === undefined) {
+ await this._api.getFolderRepository().findById(this.getId(), 'revisions');
+ }
+
+ return this.getProperty('revisions');
+ }
+
+ /**
+ *
+ * @returns {Promise<PasswordCollection>}
+ */
+ async fetchPasswords() {
+ if(this.getProperty('passwords') === undefined) {
+ await this._api.getFolderRepository().findById(this.getId(), 'passwords');
+ }
+
+ return this.getProperty('passwords');
+ }
+
+ /**
+ *
+ * @returns {Promise<FolderCollection>}
+ */
+ async fetchFolders() {
+ if(this.getProperty('folders') === undefined) {
+ await this._api.getFolderRepository().findById(this.getId(), 'folders');
+ }
+
+ return this.getProperty('folders');
+ }
+
+ /**
+ *
+ * @returns {Promise<Folder>}
+ */
+ async fetchParent() {
+ if(this.getProperty('parent') === undefined) {
+ await this._api.getFolderRepository().findById(this.getId(), 'parent');
+ }
+
+ return this.getProperty('parent');
+ }
+} \ No newline at end of file
diff --git a/src/Model/Folder/Folder.js b/src/Model/Folder/Folder.js
new file mode 100644
index 0000000..46c4b76
--- /dev/null
+++ b/src/Model/Folder/Folder.js
@@ -0,0 +1,119 @@
+import Properties from '../../Configuration/Folder';
+import AbstractRevisionModel from '../AbstractRevisionModel';
+
+export default class Folder extends AbstractRevisionModel {
+
+ /**
+ *
+ * @param {Object} [data={}]
+ */
+ constructor(data = {}) {
+ super(Properties, data);
+ }
+
+ /**
+ * @return {String}
+ */
+ getLabel() {
+ return this.getProperty('label');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Folder}
+ */
+ setLabel(value) {
+ return this.setProperty('label', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getParentId() {
+ if(this._properties.hasOwnProperty('parent')) {
+ return this.getParent().getId();
+ }
+
+ return this.getProperty('parentId');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Folder}
+ */
+ setParentId(value) {
+ if(this._properties.hasOwnProperty('parent')) {
+ return this.setParent(null);
+ }
+
+ this.setProperty('parentId', value);
+
+ return this;
+ }
+
+ /**
+ * @return {Folder}
+ */
+ getParent() {
+ return this.getProperty('parent');
+ }
+
+ /**
+ * @param {Folder} value
+ *
+ * @return {Folder}
+ */
+ setParent(value) {
+ return this.setProperty('parent', value);
+ }
+
+ /**
+ * @return {(FolderCollection|null)}
+ */
+ getFolders() {
+ return this.getProperty('folders');
+ }
+
+ /**
+ * @param {(FolderCollection|null)} value
+ *
+ * @return {Folder}
+ */
+ setFolders(value) {
+ return this.setProperty('folders', value);
+ }
+
+ /**
+ * @return {(PasswordCollection|null)}
+ */
+ getPasswords() {
+ return this.getProperty('passwords');
+ }
+
+ /**
+ * @param {(PasswordCollection|null)} value
+ *
+ * @return {Folder}
+ */
+ setPasswords(value) {
+ return this.setProperty('passwords', value);
+ }
+
+ /**
+ * @return {(FolderCollection|null)}
+ */
+ getRevisions() {
+ return this.getProperty('revisions');
+ }
+
+ /**
+ * @param {(FolderCollection|null)} value
+ *
+ * @return {Folder}
+ */
+ setRevisions(value) {
+ return this.setProperty('revisions', value);
+ }
+} \ No newline at end of file
diff --git a/src/Model/Password/EnhancedPassword.js b/src/Model/Password/EnhancedPassword.js
new file mode 100644
index 0000000..9290910
--- /dev/null
+++ b/src/Model/Password/EnhancedPassword.js
@@ -0,0 +1,130 @@
+import Password from './Password';
+import Url from 'url-parse';
+
+export default class EnhancedPassword extends Password {
+
+ /**
+ *
+ * @param {BasicPasswordsClient} api
+ * @param {Object} [data={}]
+ */
+ constructor(data = {}, api) {
+ super(data);
+ this._api = api;
+ }
+
+ /**
+ *
+ * @returns {Server}
+ */
+ getServer() {
+ return this._api.getServer();
+ }
+
+ /**
+ *
+ * @param {Number} [size=32]
+ * @param {Boolean} [pathOnly=false]
+ * @return {String}
+ */
+ getFaviconUrl(size = 32, pathOnly = false) {
+ let host = 'default';
+
+ if(this.getUrl()) {
+ let url = Url(this.getUrl());
+
+ if(url.host.length !== 0) {
+ host = url.host;
+ }
+ }
+
+ if(pathOnly) return `1.0/service/favicon/${host}/${size}`;
+
+ return `${this.getServer().getApiUrl()}1.0/service/favicon/${host}/${size}`;
+ }
+
+ /**
+ *
+ * @param size
+ * @returns {Promise<Blob>}
+ */
+ async getFavicon(size = 32) {
+ let path = this.getFaviconUrl(size, true),
+ response = await this._api.getRequest().setPath(path).setResponseType('image/png').send();
+
+ return response.getData();
+ }
+
+ /**
+ *
+ * @param {(String|Number)} width
+ * @param {(String|Number)} height
+ * @param {String} view
+ * @param {Boolean} [pathOnly=false]
+ * @return {String}
+ */
+ getPreviewUrl(width = 640, height = '360...', view = 'desktop', pathOnly = false) {
+ let host = 'default';
+
+ if(this.getUrl()) {
+ let url = Url(this.getUrl());
+
+ if(url.host.length !== 0) {
+ host = url.host;
+ }
+ }
+
+ if(pathOnly) return `1.0/service/preview/${host}/${view}/${width}/${height}`;
+
+ return `${this.getServer().getApiUrl()}1.0/service/preview/${host}/${view}/${width}/${height}`;
+ }
+
+ /**
+ *
+ * @param {(String|Number)} width
+ * @param {(String|Number)} height
+ * @param {String} view
+ * @returns {Promise<Blob>}
+ */
+ async getPreview(width = 640, height = '360...', view) {
+ let path = this.getPreviewUrl(width, height, view, true),
+ response = await this._api.getRequest().setPath(path).setResponseType('image/jpeg').send();
+
+ return response.getData();
+ }
+
+ /**
+ *
+ * @returns {Promise<PasswordCollection>}
+ */
+ async fetchRevisions() {
+ }
+
+ /**
+ *
+ * @returns {Promise<Share>}
+ */
+ async fetchShare() {
+ }
+
+ /**
+ *
+ * @returns {Promise<ShareCollection>}
+ */
+ async fetchShares() {
+ }
+
+ /**
+ *
+ * @returns {Promise<TagCollection>}
+ */
+ async fetchTags() {
+ }
+
+ /**
+ *
+ * @returns {Promise<FolderCollection>}
+ */
+ async fetchFolder() {
+ }
+} \ No newline at end of file
diff --git a/src/Model/Password/Password.js b/src/Model/Password/Password.js
new file mode 100644
index 0000000..da2692f
--- /dev/null
+++ b/src/Model/Password/Password.js
@@ -0,0 +1,232 @@
+import Properties from '../../Configuration/Password';
+import AbstractRevisionModel from '../AbstractRevisionModel';
+
+export default class Password extends AbstractRevisionModel {
+
+ /**
+ *
+ * @param {Object} [data={}]
+ */
+ constructor(data = {}) {
+ super(Properties, data);
+ }
+
+ /**
+ * @return {String}
+ */
+ getLabel() {
+ return this.getProperty('label');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setLabel(value) {
+ return this.setProperty('label', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getUserName() {
+ return this.getProperty('username');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setUserName(value) {
+ return this.setProperty('username', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getPassword() {
+ return this.getProperty('password');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setPassword(value) {
+ return this.setProperty('password', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getUrl() {
+ return this.getProperty('url');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setUrl(value) {
+ return this.setProperty('url', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getNotes() {
+ return this.getProperty('notes');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setNotes(value) {
+ return this.setProperty('notes', value);
+ }
+
+ /**
+ * @return {CustomFieldCollection}
+ */
+ getCustomFields() {
+ return this.getProperty('customFields');
+ }
+
+ /**
+ * @param {CustomFieldCollection} value
+ * @return {Password}
+ */
+ setCustomFields(value) {
+ return this.setProperty('customFields', value);
+ }
+
+ /**
+ * @return {Number}
+ */
+ getStatus() {
+ return this.getProperty('status');
+ }
+
+ /**
+ * @param {Number} value
+ *
+ * @return {Password}
+ */
+ setStatus(value) {
+ return this.setProperty('status', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getStatusCode() {
+ return this.getProperty('statusCode');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setStatusCode(value) {
+ return this.setProperty('statusCode', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getHash() {
+ return this.getProperty('hash');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setHash(value) {
+ return this.setProperty('hash', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getFolder() {
+ return this.getProperty('folder');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Password}
+ */
+ setFolder(value) {
+ return this.setProperty('folder', value);
+ }
+
+ /**
+ * @return {(string|null)}
+ */
+ getShare() {
+ return this.getProperty('share');
+ }
+
+ /**
+ * @param {(string|null)} value
+ *
+ * @return {Password}
+ */
+ setShare(value) {
+ return this.setProperty('share', value);
+ }
+
+ /**
+ * @return {Boolean}
+ */
+ isShared() {
+ return this.getProperty('shared');
+ }
+
+ /**
+ * @return {Boolean}
+ */
+ getShared() {
+ return this.getProperty('shared');
+ }
+
+ /**
+ * @return {Boolean}
+ */
+ setShared(value) {
+ return this.setProperty('shared', value);
+ }
+
+ /**
+ * @return {Boolean}
+ */
+ isEditable() {
+ return this.getProperty('editable');
+ }
+
+ /**
+ * @return {Boolean}
+ */
+ getEditable() {
+ return this.getProperty('editable');
+ }
+
+ /**
+ * @param {Boolean} value
+ *
+ * @return {Password}
+ */
+ setEditable(value) {
+ return this.setProperty('editable', value);
+ }
+} \ No newline at end of file
diff --git a/src/Model/Server/Server.js b/src/Model/Server/Server.js
new file mode 100644
index 0000000..6c36ba3
--- /dev/null
+++ b/src/Model/Server/Server.js
@@ -0,0 +1,80 @@
+import ConfigruationError from '../../Exception/ConfigruationError';
+import Properties from '../../Configuration/Server';
+import AbstractModel from './../AbstractModel';
+import ObjectMerger from '../../Utility/ObjectMerger';
+
+export default class Server extends AbstractModel {
+
+ /**
+ *
+ * @param {Object} data
+ * @param {(Object|null)} [properties=null]
+ */
+ constructor(data = {}, properties = null) {
+ if(!data.hasOwnProperty('baseUrl') || data.baseUrl.substr(0, 5) !== 'https') {
+ throw new ConfigruationError('Base URL missing or invalid');
+ }
+
+ if(properties !== null) ObjectMerger.merge(Properties, properties);
+ super(Properties, data);
+ }
+
+ /**
+ * @return {String}
+ */
+ getBaseUrl() {
+ return this.getProperty('baseUrl');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Server}
+ */
+ setBaseUrl(value) {
+ if(value.substr(0, 5) !== 'https') {
+ throw new ConfigruationError('Base URL missing or invalid');
+ }
+
+ return this.setProperty('baseUrl', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getUser() {
+ return this.getProperty('user');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Server}
+ */
+ setUser(value) {
+ return this.setProperty('user', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getToken() {
+ return this.getProperty('token');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Server}
+ */
+ setToken(value) {
+ return this.setProperty('token', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getApiUrl() {
+ return `${this.getBaseUrl()}index.php/apps/passwords/api/`;
+ }
+} \ No newline at end of file
diff --git a/src/Model/Session/Session.js b/src/Model/Session/Session.js
new file mode 100644
index 0000000..1a2bcf4
--- /dev/null
+++ b/src/Model/Session/Session.js
@@ -0,0 +1,87 @@
+export default class Session {
+
+ constructor(user = null, token = null, id = null, authorized = false) {
+ this._user = user;
+ this._token = token;
+ this._id = id;
+ this._authorized = authorized;
+ }
+
+ /**
+ * @return {String}
+ */
+ getId() {
+ return this._id;
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Session}
+ */
+ setId(value) {
+ if(this._id !== value) {
+ this._authorized = false;
+ this._id = value;
+ }
+
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getUser() {
+ return this._user;
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Session}
+ */
+ setUser(value) {
+ this._user = value;
+
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getToken() {
+ return this._token;
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Session}
+ */
+ setToken(value) {
+ this._token = value;
+
+ return this;
+ }
+
+ /**
+ *
+ * @return {Boolean}
+ */
+ getAuthorized() {
+ return this._authorized;
+ }
+
+ /**
+ * @param {Boolean} value
+ *
+ * @return {Session}
+ */
+ setAuthorized(value) {
+ this._authorized = value;
+
+ return this;
+ }
+
+
+} \ No newline at end of file
diff --git a/src/Model/Setting/Setting.js b/src/Model/Setting/Setting.js
new file mode 100644
index 0000000..e790f89
--- /dev/null
+++ b/src/Model/Setting/Setting.js
@@ -0,0 +1,179 @@
+import InvalidScopeError from '../../Exception/InvalidScopeError';
+
+export default class Setting {
+
+ /**
+ * @return {String}
+ */
+ static get SCOPE_SERVER() {
+ return 'server';
+ }
+
+ /**
+ * @return {String}
+ */
+ static get SCOPE_USER() {
+ return 'user';
+ }
+
+ /**
+ * @return {String}
+ */
+ static get SCOPE_CLIENT() {
+ return 'client';
+ }
+
+ /**
+ * @return {String[]}
+ */
+ static get SCOPES() {
+ return [
+ this.SCOPE_USER,
+ this.SCOPE_SERVER,
+ this.SCOPE_CLIENT
+ ];
+ }
+
+ get id() {
+ return `${this.scope}.${this.value}`
+ }
+
+ /**
+ * @return {String}
+ */
+ get name() {
+ return this._name;
+ }
+
+ /**
+ * @param {String} value
+ */
+ set name(value) {
+ this._name = value;
+ }
+
+ /**
+ * @return {String}
+ */
+ get value() {
+ return this._value;
+ }
+
+ /**
+ * @param {String} value
+ */
+ set value(value) {
+ this._value = value;
+ }
+
+ /**
+ * @return {String}
+ */
+ get scope() {
+ return this._scope;
+ }
+
+ /**
+ * @param {String} value
+ */
+ set scope(value) {
+ this._checkScope(value);
+
+ this._scope = value;
+ }
+
+ /**
+ * @param {String} name
+ * @param {String} value
+ * @param {String} scope
+ */
+ constructor(name, value, scope = 'client') {
+ this._checkScope(scope);
+
+ this._name = name;
+ this._value = value;
+ this._scope = scope;
+ }
+
+ /**
+ * @return {String}
+ */
+ getId() {
+ return `${this.getScope()}.${this.getName()}`
+ }
+
+ /**
+ * @return {String}
+ */
+ getName() {
+ return this._name;
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Setting}
+ */
+ setName(value) {
+ this.name = value;
+
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getValue() {
+ return this._value;
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Setting}
+ */
+ setValue(value) {
+ this.value = value;
+
+ return this;
+ }
+
+ /**
+ * @return {String}
+ */
+ getScope() {
+ return this._scope;
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Setting}
+ */
+ setScope(value) {
+ this.scope = value;
+
+ return this;
+ }
+
+ /**
+ * @param {String} scope
+ * @private
+ */
+ _checkScope(scope) {
+ if(Setting.SCOPES.indexOf(scope) === -1) {
+ throw new InvalidScopeError(scope);
+ }
+ }
+
+ /**
+ * @return {{scope: String, name: String, value: String}}
+ */
+ toJSON() {
+ return {
+ scope: this._scope,
+ name : this._name,
+ value: this._value
+ };
+ }
+} \ No newline at end of file
diff --git a/src/Model/Tag/EnhancedTag.js b/src/Model/Tag/EnhancedTag.js
new file mode 100644
index 0000000..5d43371
--- /dev/null
+++ b/src/Model/Tag/EnhancedTag.js
@@ -0,0 +1,38 @@
+import Tag from './Tag';
+
+export default class EnhancedTag extends Tag {
+
+ /**
+ *
+ * @param {Object} [data={}]
+ * @param {BasicPasswordsClient} api
+ */
+ constructor(data = {}, api) {
+ super(data);
+ this._api = api;
+ }
+
+ /**
+ *
+ * @returns {Server}
+ */
+ getServer() {
+ return this._api.getServer();
+ }
+
+ /**
+ *
+ * @returns {Promise<TagCollection>}
+ */
+ async fetchRevisions() {
+
+ }
+
+ /**
+ *
+ * @returns {Promise<PasswordCollection>}
+ */
+ async fetchPasswords() {
+
+ }
+} \ No newline at end of file
diff --git a/src/Model/Tag/Tag.js b/src/Model/Tag/Tag.js
new file mode 100644
index 0000000..1cff8b7
--- /dev/null
+++ b/src/Model/Tag/Tag.js
@@ -0,0 +1,45 @@
+import Properties from '../../Configuration/Tag';
+import AbstractRevisionModel from '../AbstractRevisionModel';
+
+export default class Tag extends AbstractRevisionModel {
+
+ /**
+ *
+ * @param {Object} [data={}]
+ */
+ constructor(data = {}) {
+ super(Properties, data);
+ }
+
+ /**
+ * @return {String}
+ */
+ getLabel() {
+ return this.getProperty('label');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Tag}
+ */
+ setLabel(value) {
+ return this.setProperty('label', value);
+ }
+
+ /**
+ * @return {String}
+ */
+ getColor() {
+ return this.getProperty('color');
+ }
+
+ /**
+ * @param {String} value
+ *
+ * @return {Tag}
+ */
+ setColor(value) {
+ return this.setProperty('color', value);
+ }
+} \ No newline at end of file