diff --git a/docs/plugins/haveibeenpwned/index.html b/docs/plugins/haveibeenpwned/index.html index 3f75e6c..65d55c1 100644 --- a/docs/plugins/haveibeenpwned/index.html +++ b/docs/plugins/haveibeenpwned/index.html @@ -14,7 +14,11 @@

KeeWeb Plugin: HaveIBeenPwned

https://plugins.keeweb.info/plugins/haveibeenpwned -

This plugin checks the HaveIBeenPwned site each time you enter either a user name or a password to look if they have been pawned in a breach. The password is safely checked (not sent over the network).

+

This plugin checks the HaveIBeenPwned site each time you enter a password to look if it has been pawned in a breach.
+Note: Passwords is safely checked (only a hash is sent over the network).

+

Since the V3 version of the HaveIBeenPwned API (mid 2019), checking user names is not free anymore +(3.5$/month, see API V3 Key)...
+So user name checking has been disabled in the latest version of this plugin.

Freely inspired from the equivalent keepass plugin

diff --git a/docs/plugins/haveibeenpwned/manifest.json b/docs/plugins/haveibeenpwned/manifest.json index 18a06bc..2b6696d 100644 --- a/docs/plugins/haveibeenpwned/manifest.json +++ b/docs/plugins/haveibeenpwned/manifest.json @@ -1,5 +1,5 @@ { - "version": "0.1.0", + "version": "0.1.7", "manifestVersion": "0.1.0", "name": "haveibeenpwned", "description": "Check HaveIBeenPwned password database", @@ -9,10 +9,10 @@ "url": "https://github.com/leolivier" }, "resources": { - "js": "J4heWnJtiOqcd4MUZ9skJztilT4tyT9EhGmuE+NkjDNXZFFKEnOEiIUboFV8LeXEAQZk+jHLY8s1Xxxt9v1tNq8RqeYrzNl+Cjuj4jZSaMDheDJsnp1AFkbZAEteR3UGk54uVjdwEPhCJm5qjCEi7IfIO8eTEl8HbjIkBAX91D3gh1e8+EM2v7XQ9wj/q5HbKQFNQSYMB4VO752ZdcZtLu52xJU29EjOkHZBkbo7zPMZtqGwqEvaa8E6DOnpnYruzh/XSMimbbG5aN66JjPEPTNkjWjJGD8XsCzyDJee3doLroK1C7sanM46KnKszVAAZ2zJU5dpV99ojDTykHCK0w==", - "css": "FOHXfuz24aCv4zj2TnMUbZDGjJHRMaXwVQUlLNPL2GJku+W/FsAqrcdtZeWNmFW07J/jVFZd3sQA9uSJYn8BWdxGxlabT+nKWDdkjVjPed5wghvRZRkzwkI4oR6SCaaTM5uUtS/7QkKiHaLdo9AwS0A7fuuQ0icxENxkDa/E8Evf4EwAbGtFgAAAwP5yZtyIK+nwjvsOfYut01m1uiq461whTiTGPAqSCd5pMqFv7JhJAlrRqYAtgQUL64K/MrCjHbOsl4sYYwITFb/w3rPhzgCkE6rTFWo6WOwpsIAbVJq5qhPgsXTQq1zZSNVLO7Q3n2j4t4jcmpDzlL1+OenEgg==" + "js": "CR/pcbMGlka6OI5sVMV50m+GFuJOT3I4Geuf7wWvjVHGeIqf2ffegVlMJ9/nkLv+d9RmLfQaHCDN1IUfAqrdo/MxRGZVBvIwOUBe/U/Fzw3u11C/qCfvF526CNS5Lj9xW3ZLMCHvgbSpNigVl3HIYJ3wW8Zz+2dLKQPaotrdW5ILKES7sLOO2sgIQy7adF3CJNelezgzLQEGO7IBv1IyM/qnQYhK9mHvYHCGJyIE/sjUe8KbOODnkMCmOfP6A2TYZWlyKR0ATQE+frgIK/Ur/M+4ntafkralCyhfBUHpe+5REeZI5buaklCx6nF6QUs/U41cCP178HM69sItDrjWnQ==", + "css": "em80YYK5vogs+ctoz9AtDdvsQfc8mstefQ5Nhu/cxpmg4/I12u95rEcQdAvQ36iA+Q3QqtnbSfKZt4zLexJWvWsPX9+nPJdLPfkTm0xKtjvl8gwGuUJfCkinV661RRsmS9n5Cs3scjeiZrnt501JPZ9+kU7OGVCl8cNb+5DNms1EVoWieeyJo2saODN4LGEA242t9Ol6y4bnDZmzDiB+TvIhNt4joncRaAf45zfzda9+XZK4S8ZrjHO9sJXXaR5WKVB15zckyGKziSpZBJqzqMONEQqJVqmuefzkcif+vGMmhnWenaGZuxybxwkWY3Cq0I30VtxvUXNLB3XR1h/s2Q==" }, "url": "https://plugins.keeweb.info/plugins/haveibeenpwned", - "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp9Cay/z7whBsHcf9klDjlA4qylWT7a/igTJ2nvUq2XuQrx98PTOexzzzg5oflk8nPEaMIsaFIf90V/rvQjJ1z9DR4zuQKDb4/GZVzxoylECAwNk80LvSPc1G0+6mwXIFp48wc6Advd4iYQCMkzWDCJXEm/1E+q85ty+H6EaLleKcJI0vlW96bbA9vFCmOsM5PYZfoGnVFRBLVthyUcGneilMvsxu5J7DKggQKPs04/WQZ5oHbUG83mxkxTdYDC3glpvV4BiaAD6z+2usO+fA97bXb+rY3O2iHJgWsa7jH0ybO0Nif6txE4d2+LJOLmfoImv7kdyu/eN3A78KejCOhwIDAQAB", + "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmycO5RAzrGrdP1pFZd3YCqS9MwTJxoL4PxO+um6NS4Af3XviV0VFr/OBL19PBq8c8EBbIYRrh202PbO7/DzRDUegUPONvD3sw15887prtclf7mX8urF3aOy9iEVe0tn2+HqEjDEPf4uuR6UD2HRUECFgc5veQ/JzXenBYKWj+q5axSFnaonRHv5qDK0+9Ja2bNgaNqfJC+h0jkajA8N4i/EPhQdvYHgUn+k0rCxKSwKaR1Tad+ixuyR8eG7Nv6t7fEbOmUOvr6G+bWcW/GmhoGA0pgYY1WfjDSPZMsMXNEXt+XLKziPz6Q5x4iX4XIHjIDbQQVnDZWvFCiWmW04S4QIDAQAB", "license": "MIT" -} +} \ No newline at end of file diff --git a/docs/plugins/haveibeenpwned/plugin.css b/docs/plugins/haveibeenpwned/plugin.css index 33f8cf3..2d49c90 100644 --- a/docs/plugins/haveibeenpwned/plugin.css +++ b/docs/plugins/haveibeenpwned/plugin.css @@ -4,7 +4,7 @@ text-align: center; background-color: var(--text-color); background-size:cover; - position: relative;; + position: relative; width:1.5em; height:1.5em; animation: hibp-spin 1s linear 0s infinite; diff --git a/docs/plugins/haveibeenpwned/plugin.js b/docs/plugins/haveibeenpwned/plugin.js index 091a0bf..a6c6745 100644 --- a/docs/plugins/haveibeenpwned/plugin.js +++ b/docs/plugins/haveibeenpwned/plugin.js @@ -4,15 +4,15 @@ * @license MIT */ -const Logger = require('util/logger'); +const Logger = require('util/logger').Logger; // change log level here. const LogLevel = Logger.Level.Info; -const DetailsView = require('views/details/details-view'); -const InputFx = require('util/input-fx'); +const DetailsView = require('views/details/details-view').DetailsView; +const InputFx = require('util/ui/input-fx').InputFx; const Kdbxweb = require('kdbxweb'); -const _ = require('_'); -const Tip = require('util/tip'); +const utilFn = require('util/fn'); +const Tip = require('util/ui/tip').Tip; const detailsViewFieldChanged = DetailsView.prototype.fieldChanged; let _seen = []; @@ -26,6 +26,7 @@ class HIBPUtils { this.logger = new Logger('HaveIBeenPwned'); this.logger.setLevel(LogLevel); }; + replacer(key, value) { if (value != null && typeof value === 'object') { if (_seen.indexOf(value) >= 0) { @@ -35,11 +36,13 @@ class HIBPUtils { } return value; }; + stringify(obj) { const ret = JSON.stringify(obj, this.replacer); _seen = []; return ret; }; + xhrcall (config) { const xhr = new XMLHttpRequest(); if (config.responseType) { @@ -64,12 +67,13 @@ class HIBPUtils { }); xhr.open(config.method || 'GET', config.url); if (config.headers) { - config.headers.forEach((value, key) => { - xhr.setRequestHeader(key, value); - }); + for (var key in config.headers) { + xhr.setRequestHeader(key, config.headers[key]); + }; }; xhr.send(config.data); }; + hex (buffer) { const hexCodes = []; const view = new DataView(buffer); @@ -86,6 +90,7 @@ class HIBPUtils { // Join all the hex strings into one return hexCodes.join(''); }; + digest(algo, str) { const buffer = Kdbxweb.ByteUtils.stringToBytes(str); const subtle = window.crypto.subtle || window.crypto.webkitSubtle; @@ -94,12 +99,15 @@ class HIBPUtils { return _self.hex(hash); }); }; + sha1(str) { return this.digest('SHA-1', str); }; + sha256(str) { return this.digest('SHA-256', str); }; + alert (el, msg) { // Alerts.info({ body: msg, title: 'HaveIBeenPwned' }); el.focus(); @@ -108,6 +116,7 @@ class HIBPUtils { Tip.createTip(el, { title: msg, placement: 'bottom' }); InputFx.shake(el); }; + passed(el, msg) { hibp.logger.info(msg); el.removeClass('input--error'); @@ -126,14 +135,14 @@ DetailsView.prototype.checkNamePwned = function (name) { url: url, method: 'GET', responseType: 'json', - headers: undefined, + headers: { "Access-Control-Allow-Origin" : '*'}, //, "Access-Control-Allow-Methods" : 'GET,OPTIONS', "Access-Control-Allow-Headers" : 'Content-Type'}, data: null, statuses: [200, 404], success: (data, xhr) => { if (data && data.length > 0) { hibp.logger.debug('found breaches ' + JSON.stringify(data)); let breaches = ''; - data.forEach(breach => { breaches += '
  • ' + _.escape(breach.Name) + '
  • \n'; }); + data.forEach(breach => { breaches += '
  • ' + utilFn.escape(breach.Name) + '
  • \n'; }); hibp.alert(this.userEditView.$el, `WARNING! This account has been pawned in the following breaches
    \n\n

    Please check on https://haveibeenpwned.com\n`); } else { hibp.passed(this.userEditView.$el, 'check pwned user name passed...'); @@ -149,7 +158,7 @@ DetailsView.prototype.checkPwdPwned = function (passwordHash) { url: `https://api.pwnedpasswords.com/range/${prefix}`, method: 'GET', responseType: 'text', - headers: undefined, + headers: {'Access-Control-Allow-Origin': '*'}, data: null, statuses: [200, 404], success: data => { @@ -159,7 +168,7 @@ DetailsView.prototype.checkPwdPwned = function (passwordHash) { const h = line.split(':'); const suffix = h[0]; if (prefix + suffix === passwordHash) { - const nb = _.escape(h[1]); + const nb = utilFn.escape(h[1]); hibp.alert(this.passEditView.$el, `WARNING: This password is referenced as pawned ${nb} times on https://haveibeenpwned.com!\n`); } }); @@ -195,21 +204,22 @@ module.exports.getSettings = function () { label: 'Check passwords against HaveIBeenPwned list', type: 'checkbox', value: hibp.checkPwnedPwd - }, { - name: 'checkPwnedName', - label: 'Check user ids against HaveIBeenPwned list', - type: 'checkbox', - value: hibp.checkPwnedName +// disabled since API V3 of HaveIbeenPwned is not free anymore for checking accounts +// }, { +// name: 'checkPwnedName', +// label: 'Check user ids against HaveIBeenPwned list', +// type: 'checkbox', +// value: hibp.checkPwnedName }, { name: 'blockPwnedPwd', label: 'Block pwned passwords if they are in HaveIBeenPwned list', type: 'checkbox', value: hibp.blockPwnedPwd - }, { - name: 'blockPwnedName', - label: 'Block pwned names if they are in HaveIBeenPwned list', - type: 'checkbox', - value: hibp.blockPwnedName +// }, { +// name: 'blockPwnedName', +// label: 'Block pwned names if they are in HaveIBeenPwned list', +// type: 'checkbox', +// value: hibp.blockPwnedName }]; }; @@ -218,6 +228,9 @@ module.exports.setSettings = function (changes) { const ccfield = field.substr(0, 1).toLowerCase() + field.substring(1); hibp[ccfield] = changes[field]; } +// disabled since API V3 of HaveIbeenPwned is not free anymore for checking accounts + hibp.checkPwnedName = false; + hibp.blockPwnedName = false }; module.exports.uninstall = function () {