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

github.com/marius-wieschollek/passwords-webextension.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius David Wieschollek <passwords.public@mdns.eu>2021-11-28 22:29:10 +0300
committerMarius David Wieschollek <passwords.public@mdns.eu>2021-11-28 22:29:10 +0300
commit06e881e4073eede08478c1b8b550efaf956091ba (patch)
treefefaab012801303ca235e383d537d4d308d0acaf
parent2fe313b2a838df1fca64c9d83ee77d9efa571101 (diff)
Fix issues with new custom fields creation
Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
-rw-r--r--src/vue/Components/Password/CustomProperty.vue59
-rw-r--r--src/vue/Components/Password/View.vue160
2 files changed, 109 insertions, 110 deletions
diff --git a/src/vue/Components/Password/CustomProperty.vue b/src/vue/Components/Password/CustomProperty.vue
index c84f690..1fca9e0 100644
--- a/src/vue/Components/Password/CustomProperty.vue
+++ b/src/vue/Components/Password/CustomProperty.vue
@@ -91,10 +91,7 @@
showField() {
if(this.type === 'file') return false;
if(this.type === 'data' && !this.value.startsWith('ext:field/')) return false;
- if(this.editable || this.value !== '') {
- return true;
- }
- return false;
+ return this.editable || this.value !== '';
},
classList() {
let result = "password-view-customproperty";
@@ -115,24 +112,30 @@
}
return 'text';
},
+ labelMaxLength() {
+ return 368 - this.value.length;
+ },
+ valueMaxLength() {
+ return 368 - this.value.length;
+ },
labelErrorText() {
- return LocalisationService.translate(['PasswordEditMaxAllowedCharacter', this.getMaxLength('label', this.label.length)]);
+ return LocalisationService.translate(['PasswordEditValidationMaxLength', this.labelMaxLength]);
},
valueErrorText() {
if(!this.validateUrl()) {
- return LocalisationService.translate('PasswordEditInvalidValue');
+ return LocalisationService.translate('PasswordEditValidationInvalidValue');
}
if(!this.validateEmail()) {
- return LocalisationService.translate('PasswordEditInvalidValue');
+ return LocalisationService.translate('PasswordEditValidationInvalidValue');
}
- return LocalisationService.translate(['PasswordEditMaxAllowedCharacter', this.getMaxLength(this.type, this.value.length)]);
+ return LocalisationService.translate(['PasswordEditValidationMaxLength', this.valueMaxLength]);
}
},
methods: {
copy() {
if(this.editable) return;
- var type = (this.type === "secret" ? "password":"text");
+ let type = (this.type === "secret" ? "password":"text");
let data = this.value;
MessageService.send({type: 'clipboard.write', payload: {type: type, value: data}}).catch(ErrorManager.catch);
@@ -151,38 +154,20 @@
}
return this.field.label;
},
- validateUrl(url) {
+ validateUrl() {
if(this.type !== "url") return true;
- var urlRegex = /^(https?|ftps?|ssh):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
- var uncRegex = /^\\\\([^\\:\|\[\]\/";<>+=,?* _]+)\\([\u0020-\u0021\u0023-\u0029\u002D-\u002E\u0030-\u0039\u0040-\u005A\u005E-\u007B\u007E-\u00FF]{1,80})(((?:\\[\u0020-\u0021\u0023-\u0029\u002D-\u002E\u0030-\u0039\u0040-\u005A\u005E-\u007B\u007E-\u00FF]{1,255})+?|)(?:\\((?:[\u0020-\u0021\u0023-\u0029\u002B-\u002E\u0030-\u0039\u003B\u003D\u0040-\u005B\u005D-\u007B]{1,255}){1}(?:\:(?=[\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]|\:)(?:([\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]+(?!\:)|[\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]*)(?:\:([\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]+)|))|)))|)$/;
+ let urlRegex = /^(https?|ftps?|ssh):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
+ let uncRegex = /^\\\\([^\\:\|\[\]\/";<>+=,?* _]+)\\([\u0020-\u0021\u0023-\u0029\u002D-\u002E\u0030-\u0039\u0040-\u005A\u005E-\u007B\u007E-\u00FF]{1,80})(((?:\\[\u0020-\u0021\u0023-\u0029\u002D-\u002E\u0030-\u0039\u0040-\u005A\u005E-\u007B\u007E-\u00FF]{1,255})+?|)(?:\\((?:[\u0020-\u0021\u0023-\u0029\u002B-\u002E\u0030-\u0039\u003B\u003D\u0040-\u005B\u005D-\u007B]{1,255}){1}(?:\:(?=[\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]|\:)(?:([\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]+(?!\:)|[\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]*)(?:\:([\u0001-\u002E\u0030-\u0039\u003B-\u005B\u005D-\u00FF]+)|))|)))|)$/;
- if(urlRegex.test(this.value) || uncRegex.test(this.value)) {
- return true;
- }
- return false;
+ return urlRegex.test(this.value) || uncRegex.test(this.value);
},
validateEmail() {
if(this.type !== "email") return true;
- const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- return re.test(String(this.value).toLowerCase());
- },
- getMaxLength(type, length) {
- switch(type) {
- case 'secret':
- var typeLength = 256;
- break;
- case 'label':
- var typeLength = 48;
- break;
- default:
- var typeLength = 320;
- }
- var maxAllowedField = typeLength - length;
- maxAllowedField = (maxAllowedField < this.maxLength ? maxAllowedField:this.maxLength);
- return maxAllowedField + length;
+ const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ return emailRegex.test(String(this.value).toLowerCase());
},
updateLabel() {
- if(this.getMaxLength('label', this.label.length) >= this.label.length) {
+ if(this.labelMaxLength >= this.label.length) {
this.labelError = false;
this.field.label = this.label;
return true;
@@ -192,7 +177,7 @@
},
updateValue() {
if(this.validateEmail() && this.validateUrl()) {
- if(this.getMaxLength(this.type, this.value.length) >= this.value.length) {
+ if(this.valueMaxLength >= this.value.length) {
this.valueError = false;
}
this.field.value = this.value;
@@ -210,12 +195,11 @@
this.field.type = this.type;
}
- this.$emit('updateField');
+ this.$emit('updated', this.field);
this.$emit('error', this.field, false);
} else {
this.$emit('error', this.field, true);
}
-
}
},
@@ -238,7 +222,6 @@
}
}
}
-
};
</script>
diff --git a/src/vue/Components/Password/View.vue b/src/vue/Components/Password/View.vue
index 4ac4a15..9842872 100644
--- a/src/vue/Components/Password/View.vue
+++ b/src/vue/Components/Password/View.vue
@@ -17,9 +17,9 @@
<custom-property :field="field"
:editable="isEditMode"
v-for="field in customFields"
- :key="field.label"
- v-on:updateField="updateCustomField"
+ :key="field.id"
v-on:error="handleValidationError"
+ v-on:updated="handleFieldUpdate"
:maxLength="customFieldLength"/>
<property :editable="false" :field="field" v-for="field in statFields" :key="field.name"/>
</div>
@@ -27,6 +27,7 @@
</template>
<script>
+ import {v4 as uuid} from 'uuid';
import Icon from '@vue/Components/Icon';
import {Password} from 'passwords-client/models';
import Property from '@vue/Components/Password/Property';
@@ -45,12 +46,11 @@
data() {
return {
- isEditMode : false,
- defaultFields : this.getDefaultFields(),
- customFields : this.getCustomFields(),
- updatedFields : {},
- errorQueue : [],
- customFieldLength: 8192
+ isEditMode : false,
+ defaultFields: this.getDefaultFields(),
+ customFields : this.getCustomFields(),
+ updatedValues: {},
+ errorQueue : []
};
},
@@ -66,14 +66,8 @@
}
return 'reqular';
},
- sharedIcon() {
- if(this.password.getProperty('shared') === true) {
- return 'users';
- }
- return 'user-shield';
- },
- showNewCustomField() {
- return this.allowNewCustomField();
+ customFieldLength() {
+ return 8192 - JSON.stringify(this.getValidatedCustomFields()).length;
},
canEdit() {
return !this.isEditMode && this.password.isEditable();
@@ -110,6 +104,33 @@
}
return fields;
},
+ getCustomFields() {
+ let editFields = [];
+
+ for(let field of this.password.getCustomFields()) {
+ editFields.push(
+ {
+ id : uuid(),
+ label: field.label,
+ value: field.value,
+ type : field.type
+ }
+ );
+ }
+
+ if(editFields.length < 20) {
+ editFields.push(
+ {
+ id : uuid(),
+ label: '',
+ value: '',
+ type : 'text'
+ }
+ );
+ }
+
+ return editFields;
+ },
getFieldObject(property, type, editable, required, allowCopy, maxLength) {
return {
name : property,
@@ -121,33 +142,6 @@
maxLength
};
},
- getCustomFields() {
- let result = this.password.getProperty('customFields');
- result.push(this.getNewCustomField());
- this.customFieldLength = 8192 - JSON.stringify(result).length;
- return result;
- },
- getNewCustomField() {
- return (
- {
- label: '',
- value: '',
- type : 'text'
- }
- );
- },
- allowNewCustomField() {
- if(this.customFields === undefined
- || this.customFields.length >= 20) {
- return false;
- }
- if(this.updatedFields !== undefined
- && this.updatedFields.customFields !== undefined
- && this.updatedFields.customFields.length >= 20) {
- return false;
- }
- return true;
- },
async updateFavorite() {
let data = {
id : this.password.getId(),
@@ -169,10 +163,14 @@
this.isEditMode = !this.isEditMode;
},
async save() {
- if(Object.keys(this.updatedFields).length !== 0) {
- this.removeEmptyCustomFields();
- this.updatedFields.id = this.password.getId();
- let response = await MessageService.send({type: 'password.update', payload: {data: this.updatedFields}});
+ let customFields = this.getValidatedCustomFields();
+ if(JSON.stringify(customFields) !== JSON.stringify(this.password.getCustomFields())) {
+ this.updatedValues.customFields = customFields;
+ }
+
+ if(Object.keys(this.updatedValues).length !== 0) {
+ this.updatedValues.id = this.password.getId();
+ let response = await MessageService.send({type: 'password.update', payload: {data: this.updatedValues}});
if(response.getPayload().success) {
ToastService.success('ToastPasswordUpdated').catch(ErrorManager.catch);
this.password.setProperties(response.getPayload().data);
@@ -180,36 +178,32 @@
ToastService.error(response.getPayload().message).catch(ErrorManager.catch);
}
- this.updatedFields = {};
+ this.updatedValues = {};
}
},
updateField(field, value) {
- this.updatedFields[field] = value;
+ this.updatedValues[field] = value;
},
- updateCustomField() {
- this.updatedFields.customFields = this.customFields;
- this.customFieldLength = 8192 - JSON.stringify(this.customFields).length;
- if(!this.allowNewCustomField()) return;
- let emptyFieldAvailable = false;
- this.updatedFields.customFields.forEach((e) => {
- if(e.label === '' && e.value === '' && e.type !== 'data' && e.type !== 'file') {
- emptyFieldAvailable = true;
- }
- });
- if(!emptyFieldAvailable) {
- this.customFields.push(this.getNewCustomField());
+ getValidatedCustomFields() {
+ let json = [];
+
+ for(let field of this.customFields) {
+ if(field.label === '' || field.value === '' || ['text', 'secret', 'email', 'url', ' file', 'data'].indexOf(field.type) === -1) continue;
+
+ json.push(
+ {
+ label: field.label,
+ type : field.type,
+ value: field.value
+ }
+ );
}
- },
- removeEmptyCustomFields() {
- if(this.updatedFields.customFields === undefined) return;
- this.updatedFields.customFields.forEach((e) => {
- if((e.label === '' && e.value === '' && e.type !== 'data' && e.type !== 'file')
- || e.label === 'ext:field/' && e.type === 'data') {
-
- let i = this.updatedFields.customFields.indexOf(e);
- this.updatedFields.customFields.splice(i, 1);
- }
- });
+
+ if(json.length > 20) {
+ json = json.slice(0, 20);
+ }
+
+ return json;
},
handleValidationError(field, error) {
if(this.errorQueue.indexOf(field) !== -1) {
@@ -221,6 +215,28 @@
this.errorQueue.push(field);
}
}
+ },
+ handleFieldUpdate(field) {
+ let hasEmpty = false;
+ for(let customField of this.customFields) {
+ if(customField.id === field.id) {
+ customField.type = field.type;
+ customField.label = field.label;
+ customField.value = field.value;
+ }
+
+ if(customField.label === '' || customField.value === '') hasEmpty = true;
+ }
+
+ if(hasEmpty) return;
+ this.customFields.push(
+ {
+ id : uuid(),
+ label: '',
+ value: '',
+ type : 'text'
+ }
+ );
}
}
};