better cache management

This commit is contained in:
leolivier 2018-04-07 16:57:30 +02:00
parent f0f828af96
commit 4497d4d1ea
2 changed files with 133 additions and 108 deletions

View File

@ -9,7 +9,7 @@
"url": "https://github.com/leolivier"
},
"resources": {
"js": "h3UBDSmKHUhkUr68XqTlr5MrtmlYEfBUTRzBqn26hSQnLLDhBTgYQ+yvN24kVH4E4Xa49+olnzfWMPKUx4aSZbIcMGqXTj2UBSit6JvW25udbhf3DKhrJ+g5h0drh/GSuBMWzID5HSDvF72f0na+VXFjy/n+Y4UPPAIh9tFOhG0rw9j+NicR6lM4azKcnD1I8+rz9AjPqbWGgWZ3AwqRNmSO8RIxw3yO9g7lNxd3Jipf6lylFgGNBvZ9vrGenke5cnELQKHZqlwHg2xhtZuWDr5GOsgIf4gNF1hqDASvP88mf9nZHgizs96m6+6968ezIXf1HBtihXLEnHen8rXOow==",
"js": "Rr1O/FVRUbRVj/eQb1lbXfWDdoHi7eszvvgOuYqe4pvJxH8+j6vFreyqV6P7sBKgYLB9Cq38x/x1S5m+Du8QEabxuxDPuurw5FeQqRhEANOJuhR/Z5IgSvuUlsA2e79IuJJGAIEFLXqwrYVl1NDpOduS5RPWgv2UQ39q7w6wvr2W2emW5FAHi3DUYrbOGBm/iQmZweqePft8yZhHy5AoCgwq9MS1eKXRrVBtfkEVWLklfKQvl5eL0ErfNc8ZpcdaOqbAl5cOZiyohflxDasWCTHtI8Vxqb1EmlrUVErdiwHdLXx39SeY+dO8LurHHJH9Bqgcnd8oxPHtYtnv/EZdQg==",
"css": "hL9Bv6NIxyP1vsHPZftppZSoM2zvP+H8ZxaEP4NwFZPoWlWZvn6l7f/x8FJly7mv7mFqpygMP4qZguPk9ZAcE5C5wj6mI9RloUg3f+500rN1mEVTpd+wH7AxR0eh/tjrYK0oq9BKpM099NknZ/t0J+aWODlk7HHbo9R2HUuvG2cpY2R137z0vkI8NPl2KQWi5vwIzKa+/EUwVIxoRApg603XzUgK8FFvAcrCsNdrXjoKEuQpZfEz8XBMjp62SuKS8KxdtyyJdsGbNrPkR8gc52ZBY0yFPC+FrSVhl6sxvu6UAMXW5xVtN5pE2Pn7+jnaVnaCafPYeqpDk5brf8G3JA=="
},
"url": "https://plugins.keeweb.info/plugins/haveibeenpwned",

View File

@ -49,7 +49,8 @@ class HIBPUtils {
this.checkPwnedPwd = HIBPCheckLevel.Alert;
this.checkPwnedName = HIBPCheckLevel.Alert;
this.checkPwnedList = false;
this.pwnedListChecked = false;
this._pwnedNamesListChecked = {};
this._pwnedPwdsListChecked = {};
this.logger = new Logger('HaveIBeenPwned');
this.logger.setLevel(LogLevel);
};
@ -150,54 +151,72 @@ class HIBPUtils {
}
checkNamePwned (name) {
hibp.logger.info('check hibp name ' + name);
name = encodeURIComponent(name);
const url = `https://haveibeenpwned.com/api/v2/breachedaccount/${name}?truncateResponse=true`;
// hibp.logger.debug('url ' + url);
return hibp._xhrpromise({
url: url,
method: 'GET',
responseType: 'json',
headers: null,
data: null,
statuses: [200, 404]
}).then(data => {
if (data && data.length > 0) {
hibp.logger.debug('found breaches ' + JSON.stringify(data));
let breaches = '';
data.forEach(breach => { breaches += '<li>' + _.escape(breach.Name) + '</li>\n'; });
return breaches;
} else return null;
});
if (hibp._pwnedNamesListChecked[name]) {
return Promise.resolve(hibp._pwnedNamesListChecked[name] !== '' ? hibp._pwnedNamesListChecked[name] : null);
} else {
name = encodeURIComponent(name);
const url = `https://haveibeenpwned.com/api/v2/breachedaccount/${name}?truncateResponse=true`;
// hibp.logger.debug('url ' + url);
return hibp._xhrpromise({
url: url,
method: 'GET',
responseType: 'json',
headers: null,
data: null,
statuses: [200, 404]
}).then(data => {
if (data && data.length > 0) {
hibp.logger.debug('found breaches ' + JSON.stringify(data));
let breaches = '';
data.forEach(breach => { breaches += '<li>' + _.escape(breach.Name) + '</li>\n'; });
hibp._pwnedNamesListChecked[name] = breaches || '';
if (breaches) hibp.logger.debug(`name ${name} pwned in ${breaches}`);
return breaches;
} else {
hibp._pwnedNamesListChecked[name] = '';
return null;
}
});
}
};
checkPwdPwned (passwordHash) {
passwordHash = passwordHash.toUpperCase();
hibp.logger.info('check hibp pwd (hash) ' + passwordHash);
const prefix = passwordHash.substring(0, 5);
return hibp._xhrpromise({
url: `https://api.pwnedpasswords.com/range/${prefix}`,
method: 'GET',
responseType: 'text',
headers: null,
data: null,
statuses: [200, 404]
}).then(data => {
let nb = null;
if (data) {
// hibp.logger.debug('found breaches ' + JSON.stringify(data));
data.split('\r\n').some(line => {
const h = line.split(':');
const suffix = h[0];
if (prefix + suffix === passwordHash) {
nb = _.escape(h[1]);
// hibp.logger.debug('matching breach ' + suffix);
return true;
}
});
}
hibp.logger.debug('pawned:' + nb);
return nb;
});
if (hibp._pwnedPwdsListChecked[passwordHash]) {
return (hibp._pwnedPwdsListChecked[passwordHash] !== ''
? hibp._pwnedPwdsListChecked[passwordHash] : null);
} else {
return hibp._xhrpromise({
url: `https://api.pwnedpasswords.com/range/${prefix}`,
method: 'GET',
responseType: 'text',
headers: null,
data: null,
statuses: [200, 404]
}).then(data => {
let nb = null;
if (data) {
// hibp.logger.debug('found breaches ' + JSON.stringify(data));
data.split('\r\n').some(line => {
const h = line.split(':');
const suffix = h[0];
if (prefix + suffix === passwordHash) {
nb = _.escape(h[1]);
// hibp.logger.debug('matching breach ' + suffix);
return true;
}
});
}
hibp._pwnedPwdsListChecked[passwordHash] = nb || '';
if (nb) hibp.logger.debug(`password ${passwordHash} pawned ${nb} times`);
return nb;
});
}
};
elligiblePwd(pwd) {
return (pwd && pwd.replace(/\s/, '') !== '' && !pwd.startsWith('{REF:'));
}
showItem(model) {
if (model) {
hibp.logger.debug('show entry ' + model.title +
@ -217,7 +236,7 @@ DetailsView.prototype.fieldChanged = function (e) {
let pwd = e.val.getText();
if (typeof pwd !== 'string') pwd = pwd.getText();
hibp.logger.debug('pwd:>>>' + pwd + '<<< obj=' + hibp.stringify(pwd));
if (pwd && pwd.replace(/\s/, '') !== '' && !pwd.startsWith('{REF:')) {
if (hibp.elligiblePwd(pwd)) {
hibp.sha1(pwd)
.then(hibp.checkPwdPwned)
.then(npwned => { // pawned
@ -301,82 +320,59 @@ DetailsView.prototype.fieldChanged = function (e) {
DetailsView.prototype.addFieldViews = function () {
detailsViewAddFieldViews.apply(this, arguments);
let pwd = this.model.password;
if (typeof pwd !== 'string') pwd = pwd.getText();
const pwd = this.model.password ? this.model.password.getText() : null;
// hibp.logger.debug('addfv pwd:>>>' + pwd + '<<<');
if (hibp.checkPwnedPwd !== HIBPCheckLevel.None && pwd && pwd.replace(/\s/, '') !== '' && !pwd.startsWith('{REF:')) {
if (hibp.checkPwnedList) {
if (this.model.pwdPwned) {
const warning = HIBPLocale.hibpPwdWarning.replace('{}', this.model.pwdPwned);
hibp.alert(this.passEditView.$el, warning);
} else { // not pawned
hibp.passed(this.passEditView.$el, 'check pwned password passed...');
}
} else {
hibp.sha1(pwd)
.then(hibp.checkPwdPwned)
.then(npwned => {
this.model.pwdPwned = npwned;
if (npwned) { // pawned
const warning = HIBPLocale.hibpPwdWarning.replace('{}', npwned);
hibp.alert(this.passEditView.$el, warning);
} else { // not pawned
hibp.passed(this.passEditView.$el, 'check pwned password passed...');
}
}).catch(error => {
hibp.logger.info('check pwned pwd error: ' + error);
});
}
if (hibp.checkPwnedPwd !== HIBPCheckLevel.None && hibp.elligiblePwd(pwd)) {
hibp.sha1(pwd)
.then(hibp.checkPwdPwned)
.then(npwned => {
this.model.pwdPwned = npwned;
if (npwned) { // pawned
const warning = HIBPLocale.hibpPwdWarning.replace('{}', npwned);
hibp.alert(this.passEditView.$el, warning);
} else { // not pawned
hibp.passed(this.passEditView.$el, 'check pwned password passed...');
}
}).catch(error => {
hibp.logger.info('check pwned pwd error: ' + error);
});
}
let name = this.userEditView.value;
// hibp.logger.debug('addfv name:>>>' + name + '<<<');
if (name && name.replace(/\s/, '') !== '' && hibp.checkPwnedName !== HIBPCheckLevel.None) {
if (hibp.checkPwnedList) {
if (this.model.namePwned) {
name = _.escape(name); // breaches already escaped
const warning = HIBPLocale.hibpNameWarning.replace('{name}', name).replace('{breaches}', this.model.namePwned);
hibp.alert(this.userEditView.$el, warning);
} else { // not pawned
hibp.passed(this.userEditView.$el, 'check pwned user name passed...');
}
} else {
hibp.checkNamePwned(name)
.then(breaches => {
this.model.namePwned = breaches;
if (breaches) { // pawned
name = _.escape(name); // breaches already escaped
const warning = HIBPLocale.hibpNameWarning.replace('{name}', name).replace('{breaches}', breaches);
hibp.alert(this.userEditView.$el, warning);
} else { // not pawned
hibp.passed(this.userEditView.$el, 'check pwned user name passed...');
}
}).catch(error => {
hibp.logger.info('check pwned name error: ' + hibp.stringify(error));
});
}
hibp.checkNamePwned(name)
.then(breaches => {
this.model.namePwned = breaches;
if (breaches) { // pawned
name = _.escape(name); // breaches already escaped
const warning = HIBPLocale.hibpNameWarning.replace('{name}', name).replace('{breaches}', breaches);
hibp.alert(this.userEditView.$el, warning);
} else { // not pawned
hibp.passed(this.userEditView.$el, 'check pwned user name passed...');
}
}).catch(error => {
hibp.logger.info('check pwned name error: ' + hibp.stringify(error));
});
}
};
ListView.prototype.render = function () {
listViewRender.apply(this, arguments);
if (hibp.checkPwnedList && this.items && this.items.length) {
hibp.logger.debug('rendering list in hibp');
// this.items.forEach(hibp.showItem);
this.items.filter(item => item.namePwned || item.pwdPwned).forEach(item => {
hibp.logger.debug('list pwned ' + item.title);
const itemEl = document.getElementById(item.id);
if (itemEl) { itemEl.classList.add('hibp-pwned'); }
});
}
hibp.logger.debug('rendering list in hibp');
// this.items.forEach(hibp.showItem);
this.items.filter(item => item.namePwned || item.pwdPwned).forEach(item => {
hibp.logger.debug('list pwned ' + item.title);
const itemEl = document.getElementById(item.id);
if (itemEl) { itemEl.classList.add('hibp-pwned'); }
});
};
AppModel.prototype.getEntriesByFilter = function (filter) {
const entries = appModelGetEntriesByFilter.apply(this, arguments);
const names = [];
const pwds = [];
hibp.logger.debug('entries already checked=' + this.pwnedListChecked);
if (hibp.checkPwnedList && !hibp.pwnedListChecked && entries && entries.length) {
hibp.pwnedListChecked = true;
/* const names = {};
const pwds = {};
if (hibp.checkPwnedList && entries && entries.length) {
hibp.logger.debug('getEntriesByFilter');
entries.forEach(item => {
hibp.logger.debug('getEntriesByFilter: item = ' + item.title);
@ -388,7 +384,7 @@ AppModel.prototype.getEntriesByFilter = function (filter) {
}
let pwd = item.password;
if (pwd) {
hibp.logger.debug(`getEntriesByFilter: pwd=${pwd}`);
// hibp.logger.debug(`getEntriesByFilter: pwd=${pwd}`);
pwd = pwd.getText();
if (pwds[pwd]) pwds[pwd].push(item);
else pwds[pwd] = [item];
@ -418,6 +414,35 @@ AppModel.prototype.getEntriesByFilter = function (filter) {
});
}, 20);
}
*/
if (hibp.checkPwnedList && entries && entries.length) {
// asynchronously look for pawned names and pwds
setTimeout(() => {
entries.forEach(item => {
hibp.logger.debug('getEntriesByFilter: check item ' + item.title);
hibp.checkNamePwned(item.user)
.then(breaches => {
const itemPwned = item.namePwned;
item.namePwned = breaches;
if (!breaches !== !itemPwned) { // XOR
this.refresh();
}
});
const pwd = item.password ? item.password.getText() : null;
if (hibp.elligiblePwd(pwd)) {
hibp.sha1(pwd)
.then(hibp.checkPwdPwned)
.then(nb => {
const itemPwned = item.pwdPwned;
item.pwdPwned = nb;
if (!nb !== !itemPwned) { // XOR
this.refresh();
}
});
}
});
}, 20);
}
return entries;
};