return Promise.resolve().then(() => { const text = kdbxweb.ByteUtils.bytesToString(data); const id = 'plugin-css-' + name; this.createElementInHead('style', id, 'text/css', text); if (theme) { const locKey = this.getThemeLocaleKey(theme.name); SettingsManager.allThemes[theme.name] = locKey; BaseLocale[locKey] = theme.title; for (const styleSheet of document.styleSheets) { if (styleSheet.ownerNode.id === id) { this.processThemeStyleSheet(styleSheet, theme); break; } } } this.logger.debug('Plugin style installed'); });
return Promise.resolve().then(() => { const aesCbc = kdbxweb.CryptoEngine.createAesCbc(); const key = '6b2796fa863a6552986c428528d053b76de7ba8e12f8c0e74edb5ed44da3f601'; const data = 'e567554429098a38d5f819115edffd39'; const iv = '4db46dff4add42cb813b98de98e627c4'; const exp = '46ab4c37d9ec594e5742971f76f7c1620bc29f2e0736b27832d6bcc5c1c39dc1'; return aesCbc.importKey(kdbxweb.ByteUtils.hexToBytes(key)).then(() => { return aesCbc.encrypt(kdbxweb.ByteUtils.hexToBytes(data), kdbxweb.ByteUtils.hexToBytes(iv)).then(res => { if (kdbxweb.ByteUtils.bytesToHex(res) !== exp) { throw 'AES is not working properly'; } if (kdbxweb.CryptoEngine.random(1).length !== 1) { throw 'Random is not working'; } }); }).catch(e => { throw 'WebCrypto is not supported: ' + e; }); });
get: function() { var pseudoValue = this.pseudoValue, salt = this.salt, len = pseudoValue.length, byteLength = 0, valueBytes = new Uint8Array(len * 4), saltBytes = kdbxweb.Random.getBytes(len * 4), ch, bytes; for (var i = 0; i < len; i++) { ch = String.fromCharCode(pseudoValue.charCodeAt(i) ^ salt[i]); bytes = kdbxweb.ByteUtils.stringToBytes(ch); for (var j = 0; j < bytes.length; j++) { valueBytes[byteLength] = bytes[j] ^ saltBytes[byteLength]; byteLength++; } } return new kdbxweb.ProtectedValue(valueBytes.buffer.slice(0, byteLength), saltBytes.buffer.slice(0, byteLength)); }
readKdfParams: function() { const kdfParameters = this.db.header.kdfParameters; if (!kdfParameters) { return undefined; } let uuid = kdfParameters.get('$UUID'); if (!uuid) { return undefined; } uuid = kdbxweb.ByteUtils.bytesToBase64(uuid); if (uuid !== kdbxweb.Consts.KdfId.Argon2) { return undefined; } return { parallelism: kdfParameters.get('P').valueOf(), iterations: kdfParameters.get('I').valueOf(), memory: kdfParameters.get('M').valueOf() }; },
kdbxweb.Kdbx.load(fileData, credentials, (function(db, err) { if (err) { if (err.code === kdbxweb.Consts.ErrorCodes.InvalidKey && password && !password.byteLength) { logger.info('Error opening file with empty password, try to open with null password'); return this.open(null, fileData, keyFileData, callback); } logger.error('Error opening file', err.code, err.message, err); callback(err); } else { this.db = db; this.readModel(); this.setOpenFile({ passwordLength: password ? password.textLength : 0 }); if (keyFileData) { kdbxweb.ByteUtils.zeroBuffer(keyFileData); } logger.info('Opened file ' + this.get('name') + ': ' + logger.ts(ts) + ', ' + db.header.keyEncryptionRounds + ' rounds, ' + Math.round(fileData.byteLength / 1024) + ' kB'); callback(); } }).bind(this));
xhr.addEventListener('load', () => { const data = xhr.response; const gallery = JSON.parse(data); const dataToVerify = data.replace(gallery.signature, ''); SignatureVerifier.verify( kdbxweb.ByteUtils.stringToBytes(dataToVerify), gallery.signature ).then(isValid => { if (!isValid) { this.logger.error('JSON signature invalid'); this.galleryLoadError = true; resolve(); return; } this.logger.debug(`Loaded ${gallery.plugins.length} plugins`, this.logger.ts(ts)); resolve(gallery); }).catch(e => { this.logger.error('Error verifying plugins signature', e); resolve(); }); });
return Promise.resolve().then(() => { let text = kdbxweb.ByteUtils.bytesToString(data); this.module = {exports: {}}; const id = 'plugin-' + Date.now().toString() + Math.random().toString(); global[id] = { require: PluginApi.require, module: this.module }; text = `(function(require, module){${text}})(window["${id}"].require,window["${id}"].module);`; const ts = this.logger.ts(); this.createElementInHead('script', 'plugin-js-' + name, 'text/javascript', text); return new Promise((resolve, reject) => { setTimeout(() => { delete global[id]; if (this.module.exports.uninstall) { this.logger.debug('Plugin script installed', this.logger.ts(ts)); this.loadPluginSettings(); resolve(); } else { reject('Plugin script installation failed'); } }, 0); }); });
addCustomIcon: function(iconData) { const uuid = kdbxweb.KdbxUuid.random(); this.db.meta.customIcons[uuid] = kdbxweb.ByteUtils.arrayToBuffer(kdbxweb.ByteUtils.base64ToBytes(iconData)); return uuid.toString(); },
getKeyFileHash: function() { const hash = this.db.credentials.keyFileHash; return hash ? kdbxweb.ByteUtils.bytesToBase64(hash.getBinary()) : null; },