From aa7fee653adb8e2c0aa15ff52a6283c87081ad4f Mon Sep 17 00:00:00 2001 From: antelle Date: Sat, 8 May 2021 22:38:53 +0200 Subject: [PATCH] deleted KeeWebHttp --- docs/plugins.json | 27 +- docs/plugins/keewebhttp/index.html | 24 -- docs/plugins/keewebhttp/manifest.json | 19 - docs/plugins/keewebhttp/plugin.js | 544 -------------------------- 4 files changed, 2 insertions(+), 612 deletions(-) delete mode 100644 docs/plugins/keewebhttp/index.html delete mode 100644 docs/plugins/keewebhttp/manifest.json delete mode 100644 docs/plugins/keewebhttp/plugin.js diff --git a/docs/plugins.json b/docs/plugins.json index 74ccf23..1fffeac 100644 --- a/docs/plugins.json +++ b/docs/plugins.json @@ -1,6 +1,6 @@ { - "date": "2021-05-08T08:54:44.596Z", - "signature": "KS+Q2i/t1bSEviqNVO0e8Xp3+NQl12O6b5hBAeFWM3OEJjieH4OIf/WT644YAeJmIyDTpMGXcAQcrUdmpTNPMpuy1y4aFc8vfyAzehVmComAzxUuNmv/XsZ83jZJJ3F9WYag49SzsOPhg4mrfqCWaE1cGRomCv9kQPzThmuFAAFwkeqWF/8mGL96cyz+ZABv2tmQFUu6h1nTP4fYPxVZC+ZXKa6O5mRWvv7AWH6xdlLSejD5i7xaLlVJdYbTs7LHmHOay14+8V0yiAkg7HKSyJBMgpaUKJujevahpjVHB84YaBAp9cR2PjtVefimfSk6KkX2obWudbPU2TIcxeKFbQ==", + "date": "2021-05-08T20:38:37.719Z", + "signature": "Nisjd1Y//AdjogoVI1D6PKJ+VZsz6s5Mk5JB8Om+Lu9eK2TKDmfLK0XWmEjDQKxnV5ZkSdxcPkOluUnzkuAlS7MDZfWo/CEDvdoUpsOUHZW69Dj/L5TYON+xuhLlop0+t6Me7UaOAcljfZyWL+Uq0CSxkfwQiCK25Ekp0SNg/nL9Q+3965rviBtBw43TIHeWI/bxO5HaZHdLRuNQ2YugwslI/LUUHxcdrKoSABi0M/BIVSzNP/eV1Io+77e5oVsyUmzbEwuEsDdL1bmAQZaJMjdQqIEyVWavz1TAQD7XT3/F4A28D0is1g0Sapdobxy7h2tCXab6V1NtwG27zEAVvA==", "plugins": [ { "url": "https://plugins.keeweb.info/translations/zh-CN", @@ -340,29 +340,6 @@ "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRq2k3TTx0ewTe6wDr6QVeB5diwiIWzsJD+ApfZu1KNPedcAgslAfjpNsYF1if6cYsPMJH70xJ2np6RQBl1VPdwShOuxkD7m0BD5Hw/Aar8Hdp5cvAdOOMdBO+0DbGeUMy+z66s+oUCJmqVp19T6PkkxbhN08rgtT7v+aFvrbqbO/vlsskbJpH2K2io+e1XmRGPnSr9q4KSqfGbTfe5gLwDIOFd66Z4mb5Utb5wWpsy6Gjh06Yf257AccGD3A1bkTNOyeeX0tqciYBePWMk0icP/aZ6hnErfhnUKf3tOgPLppSHiGcaSKekhChZ2xLUs3U64JwrXSmwHj+TzdO3S0QIDAQAB" } }, - { - "url": "https://plugins.keeweb.info/plugins/keewebhttp", - "official": true, - "manifest": { - "version": "1.0.2", - "manifestVersion": "0.1.0", - "versionMin": "1.11.0", - "name": "keewebhttp", - "description": "KeeWebHttp allows to use browser extensions with KeeWeb", - "author": { - "name": "KeeWeb", - "email": "antelle.net@gmail.com", - "url": "https://keeweb.info" - }, - "license": "MIT", - "url": "https://plugins.keeweb.info/plugins/keewebhttp", - "resources": { - "js": "LlPkehKQKbE9xZHoatfNHSx4TA4nZlzuu1ul1YVSJXW9FOmpY7FTVlU50Kl1sXBDwNNnj4sRmBpZ/SZbo7ALOx258iFZVUy+c2O2CSsQnxTmHBH0zoG3Pdse+ByxMszj/guH2Xeiq6q9wtjJszP3RwBNcxOxirjd3FFzNA4jS877Llu29MaadApOBZr+MCgHTzuFoNNU5DYnT5qCbxnW9U9FisiT5JIFsGagy+rEg1MMPtUnVdjFp27Fn8TtrrJr+BsVrQS+FjzV5EGHLqC+piBz5ljysl1yJDU3oFBytADDZjXQAgIjk/OvQDOIJ9/peOIm4NY43f6m8qYg9zVFqg==" - }, - "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRq2k3TTx0ewTe6wDr6QVeB5diwiIWzsJD+ApfZu1KNPedcAgslAfjpNsYF1if6cYsPMJH70xJ2np6RQBl1VPdwShOuxkD7m0BD5Hw/Aar8Hdp5cvAdOOMdBO+0DbGeUMy+z66s+oUCJmqVp19T6PkkxbhN08rgtT7v+aFvrbqbO/vlsskbJpH2K2io+e1XmRGPnSr9q4KSqfGbTfe5gLwDIOFd66Z4mb5Utb5wWpsy6Gjh06Yf257AccGD3A1bkTNOyeeX0tqciYBePWMk0icP/aZ6hnErfhnUKf3tOgPLppSHiGcaSKekhChZ2xLUs3U64JwrXSmwHj+TzdO3S0QIDAQAB", - "desktop": true - } - }, { "url": "https://plugins.keeweb.info/plugins/theme-darker", "official": true, diff --git a/docs/plugins/keewebhttp/index.html b/docs/plugins/keewebhttp/index.html deleted file mode 100644 index d21c62e..0000000 --- a/docs/plugins/keewebhttp/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - KeeWeb Plugin: KeeWebHttp - - - - -

KeeWeb Plugin: KeeWebHttp

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

This plugin enables integrations with browser extensions, like - chromeIPass - or - PassIFox. -

-

It's the same as KeePassHttp, but for KeeWeb.

- - diff --git a/docs/plugins/keewebhttp/manifest.json b/docs/plugins/keewebhttp/manifest.json deleted file mode 100644 index f786dae..0000000 --- a/docs/plugins/keewebhttp/manifest.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "1.0.2", - "manifestVersion": "0.1.0", - "versionMin": "1.11.0", - "name": "keewebhttp", - "description": "KeeWebHttp allows to use browser extensions with KeeWeb", - "author": { - "name": "KeeWeb", - "email": "antelle.net@gmail.com", - "url": "https://keeweb.info" - }, - "license": "MIT", - "url": "https://plugins.keeweb.info/plugins/keewebhttp", - "resources": { - "js": "LlPkehKQKbE9xZHoatfNHSx4TA4nZlzuu1ul1YVSJXW9FOmpY7FTVlU50Kl1sXBDwNNnj4sRmBpZ/SZbo7ALOx258iFZVUy+c2O2CSsQnxTmHBH0zoG3Pdse+ByxMszj/guH2Xeiq6q9wtjJszP3RwBNcxOxirjd3FFzNA4jS877Llu29MaadApOBZr+MCgHTzuFoNNU5DYnT5qCbxnW9U9FisiT5JIFsGagy+rEg1MMPtUnVdjFp27Fn8TtrrJr+BsVrQS+FjzV5EGHLqC+piBz5ljysl1yJDU3oFBytADDZjXQAgIjk/OvQDOIJ9/peOIm4NY43f6m8qYg9zVFqg==" - }, - "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRq2k3TTx0ewTe6wDr6QVeB5diwiIWzsJD+ApfZu1KNPedcAgslAfjpNsYF1if6cYsPMJH70xJ2np6RQBl1VPdwShOuxkD7m0BD5Hw/Aar8Hdp5cvAdOOMdBO+0DbGeUMy+z66s+oUCJmqVp19T6PkkxbhN08rgtT7v+aFvrbqbO/vlsskbJpH2K2io+e1XmRGPnSr9q4KSqfGbTfe5gLwDIOFd66Z4mb5Utb5wWpsy6Gjh06Yf257AccGD3A1bkTNOyeeX0tqciYBePWMk0icP/aZ6hnErfhnUKf3tOgPLppSHiGcaSKekhChZ2xLUs3U64JwrXSmwHj+TzdO3S0QIDAQAB", - "desktop": true -} \ No newline at end of file diff --git a/docs/plugins/keewebhttp/plugin.js b/docs/plugins/keewebhttp/plugin.js deleted file mode 100644 index ac2bcf6..0000000 --- a/docs/plugins/keewebhttp/plugin.js +++ /dev/null @@ -1,544 +0,0 @@ -let uninstall; -let restart; -let serverPort = 19455; -const timeout = setTimeout(run, 500); - -function run() { - const nodeRequire = window.require; - - const http = nodeRequire('http'); - const crypto = nodeRequire('crypto'); - const electron = nodeRequire('electron'); - - const kdbxweb = require('kdbxweb'); - const Events = require('framework/events').Events; - const AppModel = require('models/app-model').AppModel; - const EntryModel = require('models/entry-model').EntryModel; - const GroupModel = require('models/group-model').GroupModel; - const AutoTypeFilter = require('auto-type/auto-type-filter').AutoTypeFilter; - const Logger = require('util/logger').Logger; - const Alerts = require('comp/ui/alerts').Alerts; - const PasswordGenerator = require('util/generators/password-generator').PasswordGenerator; - const GeneratorPresets = require('comp/app/generator-presets').GeneratorPresets; - - const Version = '1.8.4.2'; - const DebugMode = localStorage.keewebhttpDebug; - const FileReadTimeout = 500; - const EntryTitle = 'KeePassHttp Settings'; - const EntryFieldPrefix = 'AES Key: '; - const EntryUuid = 'NGl6QIpbQcCfNol9Yj7LMQ=='; - const CreatePasswordsGroupTitle = 'KeePassHttp Passwords'; - - const keys = {}; - const addedKeys = {}; - const logger = new Logger('keewebhttp'); - - let uninstalled; - let server; - - uninstall = function () { - uninstalled = true; - removeEventListeners(); - stopServer(); - }; - - restart = function () { - stopServer(); - startServer(); - }; - - addEventListeners(); - startServer(); - readAllKeys(); - - function addEventListeners() { - AppModel.instance.files.on('add', fileOpened); - } - - function removeEventListeners() { - AppModel.instance.files.off('add', fileOpened); - } - - function startServer() { - if (uninstalled) { - return; - } - server = http.createServer((req, res) => { - const origin = req.headers.origin; - const userAgent = req.headers['user-agent'] || ''; - const referer = req.headers.referrer || req.headers.referer; - let originIsValid; - if (origin) { - if ( - origin.startsWith('chrome-extension://') || - origin.startsWith('safari-extension://') || - // Firefox sends 'null' here, see https://github.com/keeweb/keeweb-plugins/pull/26 - (userAgent.includes('Firefox') && origin === 'null') - ) { - originIsValid = true; - } - } else { - originIsValid = true; - } - const isAllowed = req.method === 'POST' && !referer && originIsValid; - if (!isAllowed) { - if (DebugMode) { - logger.debug('Request dropped', req.method, req.url, req.headers); - } - req.client.destroy(); - res.end(); - return; - } - if (req.method === 'POST') { - const body = []; - req.on('data', (data) => body.push(data)); - req.on('end', () => { - const postData = Buffer.concat(body).toString(); - if (DebugMode) { - logger.debug('< ' + postData); - } - new RequestContext(postData).handle().then((response) => { - if (DebugMode) { - logger.debug('> ' + response); - } - res.statusCode = 200; - res.setHeader('Content-Type', 'application/json'); - res.end(response); - }); - }); - } - }); - const port = serverPort; - const hostname = '127.0.0.1'; - server.listen(port, hostname, () => { - if (uninstalled) { - server.close(); - return; - } - logger.debug(`Server running at http://${hostname}:${port}/`); - }); - server.on('connection', (conn) => { - const key = conn.remoteAddress + ':' + conn.remotePort; - server.conn[key] = conn; - conn.on('close', () => { - if (server) { - delete server.conn[key]; - } - }); - }); - server.conn = {}; - } - - function stopServer() { - if (server) { - server.close(); - for (const key of Object.keys(server.conn)) { - server.conn[key].destroy(); - } - server = null; - } - } - - function fileOpened(file) { - setTimeout(() => { - readKeys(file); - writeAddedKeys(file); - }, FileReadTimeout); - } - - function readAllKeys() { - AppModel.instance.files.forEach((file) => readKeys(file)); - } - - function readKeys(file) { - if (uninstalled) { - return; - } - const entry = getSettingsEntry(file); - if (!entry) { - return; - } - for (const field of Object.keys(entry.fields)) { - if (field.startsWith(EntryFieldPrefix)) { - const key = field.replace(EntryFieldPrefix, ''); - let value = entry.fields[field]; - if (value && value.isProtected) { - value = value.getText(); - } - if (key && value && !keys[key]) { - keys[key] = value; - } - } - } - } - - function writeAddedKeysToAllFiles() { - AppModel.instance.files.forEach((file) => { - writeAddedKeys(file); - }); - } - - function writeAddedKeys(file) { - if (uninstalled || !Object.keys(addedKeys).length) { - return; - } - let settingsEntry = getSettingsEntry(file); - if (!settingsEntry) { - settingsEntry = EntryModel.newEntry(file.groups[0], file); - settingsEntry.entry.uuid = new kdbxweb.KdbxUuid(EntryUuid); - settingsEntry.setField('Title', EntryTitle); - } - for (const key of Object.keys(addedKeys)) { - const keyFieldName = EntryFieldPrefix + key; - const value = addedKeys[key]; - let oldValue = settingsEntry.fields[keyFieldName]; - if (oldValue && oldValue.isProtected) { - oldValue = oldValue.getText(); - } - if (oldValue !== value) { - settingsEntry.setField(keyFieldName, kdbxweb.ProtectedValue.fromString(value)); - } - } - file.reload(); - Events.emit('refresh'); - } - - function getSettingsEntry(file) { - return file.getEntry(file.subId(EntryUuid)); - } - - class RequestContext { - constructor(postData) { - this.postData = postData; - } - - handle() { - let result; - try { - this.req = JSON.parse(this.postData); - const response = this.execute() || this.resp; - if (response instanceof Promise) { - result = response.catch((e) => { - return this.makeError(e); - }); - } else { - result = Promise.resolve(response); - } - } catch (e) { - result = Promise.resolve(this.makeError(e)); - } - return result.then((res) => JSON.stringify(res)); - } - - execute() { - switch (this.req.RequestType) { - case 'test-associate': - return this.testAssociate(); - case 'associate': - return this.associate(); - case 'get-logins': - return this.getLogins({}); - case 'get-logins-count': - return this.getLogins({ onlyCount: true }); - case 'get-all-logins': - return this.getLogins({ all: true }); - case 'set-login': - return this.setLogin(); - case 'generate-password': - return this.generatePassword(); - default: - throw 'Not implemented'; - } - } - - makeError(e, skipLog) { - const requestType = (this.req && this.req.RequestType) || ''; - if (!skipLog) { - logger.error('handleRequest error', requestType, e); - } - return { - Error: e ? e.toString() : '', - Success: false, - RequestType: requestType, - Version: Version - }; - } - - decrypt(value) { - if (!this.aesKey) { - throw 'No key'; - } - if (!this.req.Nonce) { - throw 'No nonce'; - } - const key = Buffer.from(this.aesKey, 'base64'); - const nonce = Buffer.from(this.req.Nonce, 'base64'); - const decipher = crypto.createDecipheriv('aes-256-cbc', key, nonce); - return Buffer.concat([decipher.update(value, 'base64'), decipher.final()]).toString(); - } - - encrypt(value) { - if (!this.aesKey) { - throw 'No aes key'; - } - if (!this.resp || !this.resp.Nonce) { - throw 'No nonce'; - } - const key = Buffer.from(this.aesKey, 'base64'); - const nonce = Buffer.from(this.resp.Nonce, 'base64'); - const cipher = crypto.createCipheriv('aes-256-cbc', key, nonce); - let data; - if (value.isProtected) { - const binaryData = value.getBinary(); - data = Buffer.from(binaryData); - binaryData.fill(0); - } else { - data = Buffer.from(value, 'utf8'); - } - const encrypted = Buffer.concat([cipher.update(data), cipher.final()]).toString( - 'base64' - ); - data.fill(0); - return encrypted; - } - - getKeyById() { - return keys[this.req.Id]; - } - - saveKeyWithId() { - keys[this.req.Id] = this.req.Key; - addedKeys[this.req.Id] = this.req.Key; - writeAddedKeysToAllFiles(); - } - - verifyRequest() { - if (!this.req.Verifier) { - throw 'No verifier'; - } - if (!this.aesKey) { - this.aesKey = this.getKeyById(); - } - const decrypted = this.decrypt(this.req.Verifier); - if (decrypted !== this.req.Nonce) { - throw 'Bad signature'; - } - } - - createResponse() { - const resp = { - Success: true, - Nonce: '', - Verifier: '', - Version: Version, - RequestType: this.req.RequestType - }; - if (this.req.Id && keys[this.req.Id]) { - const key = Buffer.from(keys[this.req.Id], 'base64'); - const nonce = crypto.randomBytes(16); - const cipher = crypto.createCipheriv('aes-256-cbc', key, nonce); - const encrypted = Buffer.concat([ - cipher.update(nonce.toString('base64'), 'utf8'), - cipher.final() - ]).toString('base64'); - resp.Id = this.req.Id; - resp.Nonce = nonce.toString('base64'); - resp.Verifier = encrypted; - } - this.resp = resp; - } - - testAssociate() { - if (!this.req.Id) { - return this.makeError('', true); - } - if (!this.getKeyById(this.req.Id)) { - return this.makeError('Unknown Id', true); - } - this.verifyRequest(); - this.createResponse(); - } - - associate() { - if (this.req.Id) { - throw 'Id not expected'; - } - if (!this.req.Key) { - throw 'No request key'; - } - this.aesKey = this.req.Key; - this.verifyRequest(); - electron.remote.app.getMainWindow().focus(); - return new Promise((resolve, reject) => { - Alerts.yesno({ - icon: 'plug', - header: 'External Connection', - body: - 'Some app is trying to manage passwords in KeeWeb. If you are setting up your plugin, please allow the connection. Otherwise, click No.', - success: () => { - resolve(); - }, - cancel: () => { - reject('Rejected by user'); - } - }); - }).then(() => { - this.req.Id = 'KeeWeb ' + new Date().toISOString(); - logger.info(`associate: ${this.req.Id}`); - this.saveKeyWithId(); - this.createResponse(); - return this.resp; - }); - } - - getLogins(config) { - this.verifyRequest(); - if (!this.req.Url && !config.all) { - throw 'No url'; - } - if (!AppModel.instance.files.hasOpenFiles()) { - if (this.req.TriggerUnlock === true || this.req.TriggerUnlock === 'true') { - electron.remote.app.getMainWindow().focus(); - } - return this.makeError('Locked', true); - } - const url = this.req.Url ? this.decrypt(this.req.Url) : ''; - this.createResponse(); - const filter = new AutoTypeFilter({ url }, AppModel.instance); - if (config.all) { - filter.ignoreWindowInfo = true; - } - const entries = filter.getEntries(); - this.resp.Count = entries.length; - logger.info(`getLogins(${url}): ${this.resp.Count}`); - if (!config.onlyCount) { - this.resp.Entries = entries.map((entry) => { - let customFields = null; - for (const field of Object.keys(entry.fields)) { - if (!customFields) { - customFields = []; - } - const fieldKey = this.encrypt(field); - const fieldValue = this.encrypt(entry.fields[field]); - customFields.push({ Key: fieldKey, Value: fieldValue }); - } - return { - Login: entry.user ? this.encrypt(entry.user) : '', - Name: entry.title ? this.encrypt(entry.title) : '', - Password: entry.password ? this.encrypt(entry.password) : '', - StringFields: customFields, - Uuid: this.encrypt(entry.entry.uuid.id) - }; - }); - } - } - - setLogin() { - this.verifyRequest(); - if (!this.req.Url || !this.req.Login || !this.req.Password) { - throw 'Invalid request'; - } - const uuid = this.req.Uuid ? this.decrypt(this.req.Uuid) : null; - const url = this.decrypt(this.req.Url); - const login = this.decrypt(this.req.Login); - const password = this.decrypt(this.req.Password); - - if (uuid) { - let result = 'not found'; - AppModel.instance.files.forEach((file) => { - const entry = file.getEntry(file.subId(uuid)); - if (entry) { - if (entry.user !== login) { - entry.setField('UserName', login); - } - if (!entry.password.equals(password)) { - entry.setField('Password', kdbxweb.ProtectedValue.fromString(password)); - } - } - result = 'updated'; - }); - logger.info(`setLogin(${url}, ${login}, ${password.length}): ${result}`); - } else { - logger.info(`setLogin(${url}, ${login}, ${password.length}): inserted`); - let group, file; - AppModel.instance.files.forEach((f) => { - f.forEachGroup((g) => { - if (g.title === CreatePasswordsGroupTitle) { - group = g; - file = f; - } - }); - }); - if (!group) { - file = AppModel.instance.files[0]; - group = GroupModel.newGroup(file.groups[0], file); - group.setName(CreatePasswordsGroupTitle); - } - const entry = EntryModel.newEntry(group, file); - const domain = url.match( - /^(?:\w+:\/\/)?(?:(?:www|wwws|secure)\.)?([^\/]+)\/?(?:.*)/ - ); - const title = (domain && domain[1]) || 'Saved Password'; - entry.setField('Title', title); - entry.setField('URL', url); - entry.setField('UserName', login); - entry.setField('Password', kdbxweb.ProtectedValue.fromString(password)); - } - Events.emit('refresh'); - - this.createResponse(); - } - - generatePassword() { - this.verifyRequest(); - this.createResponse(); - const preset = - GeneratorPresets.all.filter((p) => p.default)[0] || GeneratorPresets.defaultPreset; - const password = PasswordGenerator.generate(preset); - const bits = Buffer.from(password, 'utf8').byteLength * 8; - this.resp.Count = 1; - this.resp.Entries = [ - { - Login: this.encrypt(bits.toString()), - Name: '', - Password: this.encrypt(password), - StringFields: null, - Uuid: '' - } - ]; - } - } -} - -module.exports.getSettings = function () { - return [ - { - name: 'ServerPort', - label: 'Port to listen to (do not change this setting without a special need to do so)', - type: 'text', - maxlength: 5, - placeholder: '19455', - value: '19455' - } - ]; -}; - -module.exports.setSettings = function (changes) { - if (changes.ServerPort) { - const port = +changes.ServerPort; - if (port > 1024 && port < 65535) { - serverPort = port; - if (restart) { - restart(); - } - } - } -}; - -module.exports.uninstall = function () { - if (uninstall) { - uninstall(); - } else { - clearTimeout(timeout); - } -};