diff options
author | Marius David Wieschollek <passwords.public@mdns.eu> | 2021-01-17 17:59:15 +0300 |
---|---|---|
committer | Marius David Wieschollek <passwords.public@mdns.eu> | 2021-01-17 17:59:15 +0300 |
commit | bba69b688e7519c3f6580c67ad00015d7fefa8a1 (patch) | |
tree | 6e6465e2ad5bf2cea2f5538fad1bc437d2fd165b /src/js | |
parent | 60c01cc5aed8112ae5d4e1203b36d08f21c9a857 (diff) |
Add local statistics to improve password recommendations
Signed-off-by: Marius David Wieschollek <passwords.public@mdns.eu>
Diffstat (limited to 'src/js')
-rw-r--r-- | src/js/App/Background.js | 2 | ||||
-rw-r--r-- | src/js/Controller/Password/Fill.js | 4 | ||||
-rw-r--r-- | src/js/Manager/RecommendationManager.js | 1 | ||||
-rw-r--r-- | src/js/Search/Indexer/PasswordIndexer.js | 10 | ||||
-rw-r--r-- | src/js/Search/Query/Field/AbstractField.js | 2 | ||||
-rw-r--r-- | src/js/Search/Query/Sort/AbstractSort.js | 2 | ||||
-rw-r--r-- | src/js/Services/PasswordStatisticsService.js | 120 |
7 files changed, 138 insertions, 3 deletions
diff --git a/src/js/App/Background.js b/src/js/App/Background.js index cea5277..a4e71d7 100644 --- a/src/js/App/Background.js +++ b/src/js/App/Background.js @@ -18,6 +18,7 @@ import ThemeRepository from '@js/Repositories/ThemeRepository'; import SettingsService from '@js/Services/SettingsService'; import MasterSettingsProvider from '@js/Settings/MasterSettingsProvider'; import LocalisationService from "@js/Services/LocalisationService"; +import PasswordStatisticsService from "@js/Services/PasswordStatisticsService"; import PassLinkManager from "@js/Manager/PassLinkManager"; class Background { @@ -41,6 +42,7 @@ class Background { BadgeManager.init(); ContextMenuManager.init(); MiningManager.init(); + await PasswordStatisticsService.init(); await ServerManager.init(); await LocalisationService.init(); } catch(e) { diff --git a/src/js/Controller/Password/Fill.js b/src/js/Controller/Password/Fill.js index fcc8aa1..13fc853 100644 --- a/src/js/Controller/Password/Fill.js +++ b/src/js/Controller/Password/Fill.js @@ -4,7 +4,7 @@ import AbstractController from '@js/Controller/AbstractController'; import TabManager from '@js/Manager/TabManager'; import SettingsService from '@js/Services/SettingsService'; import ErrorManager from '@js/Manager/ErrorManager'; -import ToastService from "@js/Services/ToastService"; +import PasswordStatisticsService from "@js/Services/PasswordStatisticsService"; import Message from "@js/Models/Message/Message"; export default class Fill extends AbstractController { @@ -24,6 +24,8 @@ export default class Fill extends AbstractController { TabManager.set('autofill.ids', ids); } + PasswordStatisticsService.registerUse(password.getId()).catch(ErrorManager.catchEvt) + try { let response = await MessageService.send( { diff --git a/src/js/Manager/RecommendationManager.js b/src/js/Manager/RecommendationManager.js index c64b600..02fef78 100644 --- a/src/js/Manager/RecommendationManager.js +++ b/src/js/Manager/RecommendationManager.js @@ -78,6 +78,7 @@ class RecommendationManager { .score(0.3) .limit(8) .sortBy('favorite') + .sortBy('uses') .sortBy('shared') .sortBy('score') .sortBy('label'); diff --git a/src/js/Search/Indexer/PasswordIndexer.js b/src/js/Search/Indexer/PasswordIndexer.js index 57a1bba..cce45e3 100644 --- a/src/js/Search/Indexer/PasswordIndexer.js +++ b/src/js/Search/Indexer/PasswordIndexer.js @@ -1,5 +1,7 @@ import Url from 'url-parse'; import AbstractIndexer from '@js/Search/Indexer/AbstractIndexer'; +import PasswordStatisticsService from "@js/Services/PasswordStatisticsService"; +import ErrorManager from "@js/Manager/ErrorManager"; export default class PasswordIndexer extends AbstractIndexer { @@ -28,6 +30,7 @@ export default class PasswordIndexer extends AbstractIndexer { id : password.getId(), type : 'password', hidden : password.isHidden(), + uses : 0, text : [], tag : [], folder : [], @@ -38,6 +41,13 @@ export default class PasswordIndexer extends AbstractIndexer { fields : {} }; + PasswordStatisticsService + .getUses(index.id) + .then((uses) => { + index.uses = uses; + }) + .catch(ErrorManager.catchEvt) + this._indexServer(password, index); this._indexTextFields(password, index); this._indexFields(password, index); diff --git a/src/js/Search/Query/Field/AbstractField.js b/src/js/Search/Query/Field/AbstractField.js index 539f7fb..4efef4e 100644 --- a/src/js/Search/Query/Field/AbstractField.js +++ b/src/js/Search/Query/Field/AbstractField.js @@ -43,7 +43,7 @@ export default class AbstractField { */ _getFieldValues(item) { if(item.hasOwnProperty(this._name)) { - if(this._name === 'id' || this._name === 'type') { + if(this._name === 'id' || this._name === 'type' || this._name === 'hidden' || this._name === 'uses') { return [item[this._name]]; } diff --git a/src/js/Search/Query/Sort/AbstractSort.js b/src/js/Search/Query/Sort/AbstractSort.js index 10e97fb..c906ec1 100644 --- a/src/js/Search/Query/Sort/AbstractSort.js +++ b/src/js/Search/Query/Sort/AbstractSort.js @@ -41,7 +41,7 @@ export default class AbstractSort { _getFieldValue(item) { let values = []; if(item.hasOwnProperty(this._field)) { - if(this._field === 'id' || this._field === 'type' || this._field === 'score') { + if(this._field === 'id' || this._field === 'type' || this._field === 'score' || this._field === 'hidden' || this._field === 'uses') { return item[this._field]; } diff --git a/src/js/Services/PasswordStatisticsService.js b/src/js/Services/PasswordStatisticsService.js new file mode 100644 index 0000000..6437f2a --- /dev/null +++ b/src/js/Services/PasswordStatisticsService.js @@ -0,0 +1,120 @@ +import ErrorManager from "@js/Manager/ErrorManager"; + +export default new class PasswordStatisticsService { + + constructor() { + this._db = null; + } + + /** + * @public + * @return {Promise<void>} + */ + async init() { + if(!window.indexedDB) return; + + return new Promise((resolve, reject) => { + let request = window.indexedDB.open('pwd_stats', 1); + + request.onerror = (event) => { + // @TODO use custom error here + ErrorManager.logError(new Error('Could not open database'), {event}); + resolve(); + }; + + request.onupgradeneeded = (event) => { + let db = event.target.result; + db.createObjectStore('uses', {keyPath: 'id'}); + }; + + request.onsuccess = (event) => { + this._db = event.target.result; + resolve(); + }; + }); + } + + /** + * @public + * @param {String} id + * @return {Promise<void>} + */ + async registerUse(id) { + if(this._db === null) return; + let hits = 0; + if(await this._entryExists(id)) { + hits = await this._readEntry(id); + } + + hits++; + + await this._writeEntry(id, hits); + } + + /** + * @public + * @param {String} id + * @return {Promise<Number>} + */ + async getUses(id) { + if(this._db === null) return 0; + + if(await this._entryExists(id)) { + return await this._readEntry(id); + } + + return 0; + } + + /** + * @param {String} id + * @return {Promise<Boolean>} + * @private + */ + async _entryExists(id) { + return new Promise((resolve, reject) => { + let transaction = this._db.transaction(['uses'], 'readonly'), + count = transaction.objectStore('uses').count(IDBKeyRange.only(id)); + + count.onsuccess = (e) => { + resolve(e.target.result !== 0); + }; + + count.onerror = reject; + }); + } + + /** + * @param {String} id + * @return {Promise<Number>} + * @private + */ + async _readEntry(id) { + return new Promise((resolve, reject) => { + let transaction = this._db.transaction(['uses'], 'readonly'), + read = transaction.objectStore('uses').get(id); + + read.onsuccess = (e) => { + resolve(e.target.result.value); + }; + + read.onerror = reject; + }); + } + + /** + * @param {String} id + * @param {Number} value + * @return {Promise<void>} + * @private + */ + async _writeEntry(id, value) { + return new Promise((resolve, reject) => { + let transaction = this._db.transaction(['uses'], 'readwrite'), + write = transaction.objectStore('uses').put({id, value}); + + write.onsuccess = resolve; + write.onerror = reject; + }); + } +};
\ No newline at end of file |