diff options
author | flo-mic <florianmichel@hotmail.de> | 2021-02-22 15:31:54 +0300 |
---|---|---|
committer | flo-mic <florianmichel@hotmail.de> | 2021-02-22 15:31:54 +0300 |
commit | c64354217c7422ac2a91175170d1234f9009e540 (patch) | |
tree | f287c1a8c86e3454f79dca1a03e7a4139153ec5b /src | |
parent | 8bb7fbf679af7a68b4b738633deed27117cb1bf3 (diff) |
introduce clear passwords from clipboard feature
Diffstat (limited to 'src')
-rw-r--r-- | src/js/Controller/Setting/Get.js | 4 | ||||
-rw-r--r-- | src/js/Controller/Setting/Reset.js | 4 | ||||
-rw-r--r-- | src/js/Controller/Setting/Set.js | 15 | ||||
-rw-r--r-- | src/js/Manager/ClipboardManager.js | 90 | ||||
-rw-r--r-- | src/js/Manager/ControllerManager.js | 7 | ||||
-rw-r--r-- | src/js/Settings/MasterSettingsProvider.js | 12 | ||||
-rw-r--r-- | src/platform/chrome/manifest.json | 2 | ||||
-rw-r--r-- | src/platform/fenix/manifest.json | 1 | ||||
-rw-r--r-- | src/platform/firefox/manifest.json | 1 | ||||
-rw-r--r-- | src/platform/generic/_locales/de/messages.json | 22 | ||||
-rw-r--r-- | src/platform/generic/_locales/en/messages.json | 22 | ||||
-rw-r--r-- | src/vue/Components/List/Item/Password.vue | 8 | ||||
-rw-r--r-- | src/vue/Components/Options/Settings.vue | 39 | ||||
-rw-r--r-- | src/vue/Components/Tools/Generate.vue | 2 |
14 files changed, 218 insertions, 11 deletions
diff --git a/src/js/Controller/Setting/Get.js b/src/js/Controller/Setting/Get.js index 9d9cc63..18d996e 100644 --- a/src/js/Controller/Setting/Get.js +++ b/src/js/Controller/Setting/Get.js @@ -20,7 +20,9 @@ export default class Get extends AbstractController { 'server.default', 'theme.current', 'theme.custom', - 'debug.localisation.enabled' + 'debug.localisation.enabled', + 'clipboard.clear.delay', + 'clipboard.clear.passwords' ]; } diff --git a/src/js/Controller/Setting/Reset.js b/src/js/Controller/Setting/Reset.js index bd64e4e..059c350 100644 --- a/src/js/Controller/Setting/Reset.js +++ b/src/js/Controller/Setting/Reset.js @@ -17,7 +17,9 @@ export default class Reset extends AbstractController { 'server.default', 'theme.current', 'theme.custom', - 'debug.localisation.enabled' + 'debug.localisation.enabled', + 'clipboard.clear.passwords', + 'clipboard.clear.delay' ]; } diff --git a/src/js/Controller/Setting/Set.js b/src/js/Controller/Setting/Set.js index 6e211c8..f4cfa80 100644 --- a/src/js/Controller/Setting/Set.js +++ b/src/js/Controller/Setting/Set.js @@ -16,7 +16,8 @@ export default class Set extends AbstractController { 'popup.related.search', 'notification.password.new', 'notification.password.update', - 'debug.localisation.enabled' + 'debug.localisation.enabled', + 'clipboard.clear.passwords' ]; } @@ -36,6 +37,8 @@ export default class Set extends AbstractController { await this._setDefaultServer(value); } else if(setting === 'theme.current') { await this._setCurrentTheme(value); + } else if(setting === 'clipboard.clear.delay') { + await this._setClipboardClearDelay(Number(value)); } else if(this._booleanSettings.indexOf(setting) !== -1) { await this._setBoolean(setting, value); } else { @@ -91,4 +94,14 @@ export default class Set extends AbstractController { async _setBoolean(setting, value) { await SettingsService.set(setting, value === true); } + + /** + * + * @param {Number} value + * @return {Promise<void>} + * @private + */ + async _setClipboardClearDelay(value) { + await SettingsService.set('clipboard.clear.delay', value); + } }
\ No newline at end of file diff --git a/src/js/Manager/ClipboardManager.js b/src/js/Manager/ClipboardManager.js new file mode 100644 index 0000000..4608502 --- /dev/null +++ b/src/js/Manager/ClipboardManager.js @@ -0,0 +1,90 @@ +import ErrorManager from '@js/Manager/ErrorManager'; +import SettingsService from '@js/Services/SettingsService'; + +class ClipboardManager { + + /** + * + * @return {String} + */ + async readText() { + try { + var element = this._CreateDOMElement(); + await document.execCommand('paste'); + var result = element.value + this._RemoveDOMElement(element); + return result; + } catch (e) { + ErrorManager.logError(e, "ClipboardManager.readText()"); + } + } + + /** + * + * @param {String} type + * @param {String} value + */ + write(type, value) { + if(type === "password") { + this.writePassword(value); + } + else { + this.writeText(value); + } + } + + /** + * + * @param {String} value + * @param {String} type + */ + writeText(value) { + try { + var element = this._CreateDOMElement(value); + document.execCommand('copy', false, element.value); + this._RemoveDOMElement(element); + } catch (e) { + ErrorManager.logError(e); + } + } + + /** + * + * @param {String} value + */ + async writePassword(value) { + var self = this; + this.writeText(value); + if(await SettingsService.getValue('clipboard.clear.passwords') == true) { + setTimeout(async function() { + if(await self.readText() === value) { + self.writeText(" "); + } + }, Number(await SettingsService.getValue('clipboard.clear.delay')) * 1000) + } + } + + /** + * + * @param {String} type + */ + _CreateDOMElement(value = "", type = "text") { + var element = document.createElement("INPUT"); + element.setAttribute("type", type); + element.setAttribute("value", value); + document.body.appendChild(element); + element.select(); + return element; + } + + /** + * + * @param {String} type + */ + _RemoveDOMElement(element) { + element.blur(); + document.body.removeChild(element); + } +} + +export default new ClipboardManager();
\ No newline at end of file diff --git a/src/js/Manager/ControllerManager.js b/src/js/Manager/ControllerManager.js index 3d68736..61e683a 100644 --- a/src/js/Manager/ControllerManager.js +++ b/src/js/Manager/ControllerManager.js @@ -298,6 +298,13 @@ class ControllerManager { await this._executeController(module, message, reply); } ); + MessageService.listen( + 'clipboard.write', + async (message, reply) => { + let module = await import(/* webpackChunkName: "WriteClipboard" */ '@js/Controller/Clipboard/WriteClipboard'); + await this._executeController(module, message, reply); + } + ); } /** diff --git a/src/js/Settings/MasterSettingsProvider.js b/src/js/Settings/MasterSettingsProvider.js index bd68303..aae8b5b 100644 --- a/src/js/Settings/MasterSettingsProvider.js +++ b/src/js/Settings/MasterSettingsProvider.js @@ -76,6 +76,14 @@ class MasterSettingsProvider { ], 'debug.localisation.enabled' : [ 'local.localisation.enabled' + ], + 'clipboard.clear.passwords' : [ + 'sync.clipboard.clear.passwords', + 'local.clipboard.clear.passwords', + ], + 'clipboard.clear.delay' : [ + 'sync.clipboard.clear.delay', + 'local.clipboard.clear.delay', ] }; this._defaults = { @@ -91,7 +99,9 @@ class MasterSettingsProvider { 'password.folder.private' : null, 'notification.password.new' : true, 'notification.password.update': true, - 'debug.localisation.enabled' : true + 'debug.localisation.enabled' : true, + 'clipboard.clear.passwords' : true, + 'clipboard.clear.delay' : 60 }; } diff --git a/src/platform/chrome/manifest.json b/src/platform/chrome/manifest.json index 0614e48..ca24106 100644 --- a/src/platform/chrome/manifest.json +++ b/src/platform/chrome/manifest.json @@ -49,6 +49,8 @@ "*://*/*", "tabs", "storage", + "clipboardRead", + "clipboardWrite", "contextMenus", "notifications", "webRequest", diff --git a/src/platform/fenix/manifest.json b/src/platform/fenix/manifest.json index 9539414..b2c91c9 100644 --- a/src/platform/fenix/manifest.json +++ b/src/platform/fenix/manifest.json @@ -79,6 +79,7 @@ "tabs", "storage", "notifications", + "clipboardRead", "clipboardWrite", "webRequest", "webRequestBlocking" diff --git a/src/platform/firefox/manifest.json b/src/platform/firefox/manifest.json index b3a9ac9..764b82d 100644 --- a/src/platform/firefox/manifest.json +++ b/src/platform/firefox/manifest.json @@ -87,6 +87,7 @@ "menus", "storage", "notifications", + "clipboardRead", "clipboardWrite", "webRequest", "webRequestBlocking" diff --git a/src/platform/generic/_locales/de/messages.json b/src/platform/generic/_locales/de/messages.json index e2e5d18..32497d7 100644 --- a/src/platform/generic/_locales/de/messages.json +++ b/src/platform/generic/_locales/de/messages.json @@ -103,6 +103,28 @@ "message" : "Antwortet auf HTTP Basic Authentication Anfragen mit dem ersten Eintrag der vorgeschlagenen Zugangsdaten. Dadurch können Zugangsdaten ungewollt an nicht vertrauenswürdige Server übermittelt werden.", "description": "Help text in the extension settings for the setting to automatically respond with the first recommended credential to any http authentication auth request" }, + "SettingsClearClipboardPasswords" : { + "message" : "Kopierte Passwörter automatisch aus der Zwischenablage löschen", + "description": "Label of the setting in the extension settings to automatically clear passwords from clipboard after a certain time." + }, + "HelpClearClipboardPasswords" : { + "message" : "Die Zwischenablage kann nur geleert werden, wenn noch mindestens ein Browserfenster offen ist.", + "description": "Help text in the extension settings for the setting to automatically clean passwords from clipboard after a certain time." + }, + "SettingsClearClipboardDelay" : { + "message" : "Zwischenablage nach Ablauf folgender Zeit leeren (Sekunden)", + "description": "Label of the setting in the extension settings to define the time when the clipboard content will be removed." + }, + "SettingsClipboardClearDelayOptions" : { + "message" : "$ROW$", + "description" : "Time in seconds until clipboard will get empty.", + "placeholders": { + "row": { + "content": "$1", + "example": "One of 15, 30, 45, 60, 90" + } + } + }, "NotificationSettings" : { "message" : "Benachrichtigungen", "description": "Headline above the notification section in the other settings tab in the extension settings" diff --git a/src/platform/generic/_locales/en/messages.json b/src/platform/generic/_locales/en/messages.json index e3d3d45..c759827 100644 --- a/src/platform/generic/_locales/en/messages.json +++ b/src/platform/generic/_locales/en/messages.json @@ -103,6 +103,28 @@ "message" : "Automatically respond to http basic authentication requests with the first suggested credential. Be aware that this may expose credentials to untrustworthy servers.", "description": "Help text in the extension settings for the setting to automatically respond with the first recommended credential to any http basic authentication request" }, + "SettingsClearClipboardPasswords" : { + "message" : "Automatically empty clipboard after a certain time", + "description": "Label of the setting in the extension settings to automatically clear passwords from clipboard after a certain time." + }, + "HelpClearClipboardPasswords" : { + "message" : "This feature will not clear the clipboard if you close all browser windows before the timeout is reached!", + "description": "Help text in the extension settings for the setting to automatically clean passwords from clipboard after a certain time." + }, + "SettingsClearClipboardDelay" : { + "message" : "Empty clipboard after the defined time (seconds)", + "description": "Label of the setting in the extension settings to define the time when the clipboard content will be removed." + }, + "SettingsClipboardClearDelayOptions" : { + "message" : "$ROW$", + "description" : "Time in seconds until clipboard will get empty.", + "placeholders": { + "row": { + "content": "$1", + "example": "One of 15, 30, 45, 60, 90" + } + } + }, "NotificationSettings" : { "message" : "Notifications", "description": "Headline above the notification section in the other settings tab in the extension settings" diff --git a/src/vue/Components/List/Item/Password.vue b/src/vue/Components/List/Item/Password.vue index 28d59ea..7e99be1 100644 --- a/src/vue/Components/List/Item/Password.vue +++ b/src/vue/Components/List/Item/Password.vue @@ -5,8 +5,8 @@ {{ password.getLabel() }} </div> <div class="options"> - <icon icon="user" hover-icon="clipboard" @click="copy('username')" draggable="true" @dragstart="drag($event, 'username')"/> - <icon icon="key" font="solid" hover-icon="clipboard" hover-font="regular" @click="copy('password')" draggable="true" @dragstart="drag($event, 'password')"/> + <icon icon="user" hover-icon="clipboard" @click="copy('username', 'text')" draggable="true" @dragstart="drag($event, 'username')"/> + <icon icon="key" font="solid" hover-icon="clipboard" hover-font="regular" @click="copy('password', 'password')" draggable="true" @dragstart="drag($event, 'password')"/> </div> <icon :class="securityClass" icon="shield-alt" font="solid"/> </li> @@ -92,9 +92,9 @@ ErrorManager.logError(e); } }, - copy(property) { + copy(property, type) { let data = this.password.getProperty(property); - navigator.clipboard.writeText(data); + MessageService.send({type: 'clipboard.write', payload: {type: type, value: data}}).catch(ErrorManager.catch); let label = property.capitalize(); if(['password', 'username', 'url'].indexOf(property) === -1) { diff --git a/src/vue/Components/Options/Settings.vue b/src/vue/Components/Options/Settings.vue index f6824a5..22bd788 100644 --- a/src/vue/Components/Options/Settings.vue +++ b/src/vue/Components/Options/Settings.vue @@ -23,6 +23,15 @@ <translate tag="label" for="paste-basic-auth" say="SettingsPasteBasicAuth"/> <help-text type="warning" text="HelpPasteBasicAuth"/> </div> + <div class="setting"> + <slider-field id="clipboard-clear-passwords" v-model="clearClipboard"/> + <translate tag="label" for="clipboard-clear-passwords" say="SettingsClearClipboardPasswords"/> + <help-text type="warning" text="HelpClearClipboardPasswords"/> + </div> + <div class="setting"> + <translate tag="label" for="clipboard-clear-delay" say="SettingsClearClipboardDelay"/> + <select-field id="clipboard-clear-delay" :options="clearClipboardDelayOptions" v-model="clearClipboardDelay"/> + </div> <translate tag="h3" say="NotificationSettings"/> <div class="setting"> @@ -48,10 +57,11 @@ import SettingsService from '@js/Services/SettingsService'; import ToastService from '@js/Services/ToastService'; import SliderField from "@vue/Components/Form/SliderField"; + import SelectField from "@vue/Components/Form/SelectField"; import HelpText from "@vue/Components/Options/Setting/HelpText"; export default { - components: {HelpText, SliderField, Translate}, + components: {HelpText, SliderField, SelectField, Translate}, data() { return { autoclose : false, @@ -61,7 +71,9 @@ compromised : false, notifyPwNew : false, relatedSearch : false, - notifyPwUpdate: false + notifyPwUpdate: false, + clearClipboard: true, + clearClipboardDelay: 60 }; }, @@ -69,6 +81,17 @@ this.loadData(); }, + computed: { + clearClipboardDelayOptions() { + var i = 1; + var result = []; + for(let i of [15, 30, 45, 60, 90]) { + result.push({id: i, label: ['SettingsClipboardClearDelayOptions', i]}); + } + return result; + } + }, + methods: { loadData() { this.getSetting('paste.popup.close', 'autoclose'); @@ -79,6 +102,8 @@ this.getSetting('popup.related.search', 'relatedSearch'); this.getSetting('notification.password.new', 'notifyPwNew'); this.getSetting('notification.password.update', 'notifyPwUpdate'); + this.getSetting('clipboard.clear.passwords', 'clearClipboard'); + this.getSetting('clipboard.clear.delay', 'clearClipboardDelay'); }, async getSetting(name, variable) { try { @@ -124,6 +149,16 @@ this.setSetting('paste.basic-auth', value); } }, + clearClipboard(value, oldValue) { + if(oldValue !== null && value !== oldValue) { + this.setSetting('clipboard.clear.passwords', value); + } + }, + clearClipboardDelay(value, oldValue) { + if(oldValue !== null && value !== oldValue) { + this.setSetting('clipboard.clear.delay', value); + } + }, relatedSearch(value, oldValue) { if(oldValue !== null && value !== oldValue) { this.setSetting('popup.related.search', value); diff --git a/src/vue/Components/Tools/Generate.vue b/src/vue/Components/Tools/Generate.vue index ba1c55a..61e6aef 100644 --- a/src/vue/Components/Tools/Generate.vue +++ b/src/vue/Components/Tools/Generate.vue @@ -101,7 +101,7 @@ copy() { let data = this.password, label = LocalisationService.translate('PropertyPassword'); - navigator.clipboard.writeText(data); + MessageService.send({type: 'clipboard.write', payload: {type: 'password', value: data}}).catch(ErrorManager.catch); ToastService .success(['PasswordPropertyCopied', label]) |