UNPKG

insomnia-plugin-keepass

Version:

This is a plugin for [insomnia](https://insomnia.rest) which provides access to Keepass and KeepassXC for fetching credentials.

255 lines (237 loc) 9.36 kB
const {createHash} = require('crypto'), Utils = require('./src/Utils'), _C = {...Utils.constants}, isMacOS = process.platform === 'darwin', isWindows = process.platform === 'win32'; isLinux = process.platform.toLowerCase().startsWith('linux'); function buildDisplayText(which, field, url, filter, filter_key, filter_value) { let text = `${_C.KEEPASS_MAP[which]} - ${_C.FIELD_MAP[field]} of Entry url: ${url}` if (filter === 'true') { text = text.concat( ` (filter: '${filter_key}' value: '${filter_value}')`) } return text } module.exports.templateTags = [{ _error: false, _message: null, _actionHandler: null, name: 'keepass', displayName: 'Fetch from Keepass', description: 'Retrieve value from Keepass / KeepassXC', liveDisplayName: args => buildDisplayText(args[0].value, args[4].value, args[3].value, args[5].value, args[6].value, args[7].value), args: [ { type: 'enum', displayName: `${_C.KEEPASS_MAP[_C.KEEPASS]} / ${_C.KEEPASS_MAP[_C.KEEPASSXC]}`, options: [ { displayName: _C.KEEPASS_MAP[_C.KEEPASS], value: _C.KEEPASS, description: 'Requires KeepassHttp plugin' }, { displayName: _C.KEEPASS_MAP[_C.KEEPASSXC], value: _C.KEEPASSXC } ] }, { type: 'string', displayName: 'KeepassHttp URL', help: `Leave empty for default value of ${_C.DEFAULT_KEEPASSHTTP_URL}`, placeholder: _C.DEFAULT_KEEPASSHTTP_URL, hide: args => args[0].value !== _C.KEEPASS }, { type: 'file', displayName: 'Path to KeepassXC application', defaultValue: isMacOS ? '/Applications/' : isLinux ? _C.LINUX_PROXY : '', itemTypes: ['file'], extensions: [].concat(isMacOS ? ['*.app'] : []).concat(isWindows ? ['*.exe'] : []), help: () => { if (isMacOS) { return `Leave empty for default value of ${_C.DEFAULT_KEEPASSXC_MACOS}` } else if (isLinux) { return `Leave empty for default value of ${_C.LINUX_PROXY}` } return 'Full path to keepassxc-proxy executable' }, hide: args => args[0].value !== _C.KEEPASSXC }, { type: 'string', displayName: 'Search URL', help: args => `URL to search ${_C.KEEPASS_MAP[args[0].value]} database for credentials`, validate: value => { if (!value) { return 'Required'; } else if (value.startsWith('_.')) { return ''; } try { new URL(value); return ''; } catch (err) { return 'Invalid URL'; } } }, { type: 'enum', displayName: 'Select entry field', defaultValue: _C.FIELD_PASSWORD, options: [ { displayName: 'Username', value: _C.FIELD_USERNAME }, { displayName: 'Password', value: _C.FIELD_PASSWORD }, { displayName: 'Entry Name', value: _C.FIELD_ENTRY_NAME }, { displayName: 'Group', value: _C.FIELD_GROUP } ] }, { type: 'boolean', displayName: 'Filter entries by field?', defaultValue: false, hide: args => args[0].value !== _C.KEEPASSXC }, { type: 'enum', displayName: 'Filter Field', defaultValue: _C.FIELD_USERNAME, options: [ { displayName: 'Username', value: _C.FIELD_USERNAME }, { displayName: 'Entry Name', value: _C.FIELD_ENTRY_NAME }, { displayName: 'Group', value: _C.FIELD_GROUP }, { displayName: 'Additional Attribute', description: 'Name format: "KPH: \\<VALUE\\>"', value: _C.FIELD_ADDITIONAL_ATTRIBUTE } ], hide: args => args[0].value !== _C.KEEPASSXC || args[5].value === false }, { type: 'string', displayName: 'Field value', hide: args => args[0].value !== _C.KEEPASSXC || args[5].value === false } ], actions: [ { name: ' Create Database link', icon: 'fa fa-link', run: Utils.actionHandler(this, async function ({store}, which, host, file) { if (await Utils.associationExists(store)) { this._error = true; return 'Database link already established, you need to unlink first.'; } try { const keepass = await Utils.createKeepassInstance({which, host, file}), association = await keepass.associate(); await Utils.storeAssociation(store, association); return 'Database link succesfully established.'; } catch (err) { this._error = true; return 'Database link could not be established'; } }) }, { name: ' Unlink Database', icon: 'fa fa-unlink', run: Utils.actionHandler(this, async function ({store}) { if (await Utils.associationExists(store)) { await Utils.removeAssociation(store); return 'Unlink database successful.'; } this._error = true; return 'No database link established yet.' }) } ], async run(context, which, host, file, url, field, filter, filter_key, filter_value) { const {store, renderPurpose} = context; host = which === _C.KEEPASS ? host || Utils.defaultHost : undefined; file = which === _C.KEEPASSXC ? ((isMacOS || isLinux) ? file || Utils.defaultFile : file) : undefined; await Utils.handleActionHandler(this, {context, which, host, file, url, field}); if (Utils.isValidUrl(url) === false) { throw new Error('Search URL must be a valid URL.'); } if (renderPurpose === 'send') { const keepass = await Utils.createKeepassInstance({store, which, host, file}); await keepass.testAssociate(); entries = await keepass.getCredentials(url, filter, filter_key, filter_value); if (entries.length) { return entries.pop()[field] || ''; } throw new Error(`No entry found in database for search url ${url}`); } const refreshButton = Utils.getRefreshLivePreviewButton(), onRefresh = () => Utils.clearCache(store); if (refreshButton) { refreshButton.removeEventListener('click', onRefresh); refreshButton.addEventListener('click', onRefresh); } const hash = createHash('MD5').update(JSON.stringify({ which, host, file, url, field, filter, filter_key, filter_value })).digest('hex'); let cachedResult = await store.getItem(hash); if (cachedResult === null) { if (await Utils.associationExists(store) === false) { throw new Error('No Database link established. You need to create a database link first.'); } else { const keepass = await Utils.createKeepassInstance({store, which, host, file}); if (await keepass.testAssociate() === false) { throw new Error( 'Database link is invalid. Please try re-establishing a link.'); } entries = await keepass.getCredentials(url, filter, filter_key, filter_value); cachedResult = entries.length.toString(); await store.setItem(hash, cachedResult); } } if (~~cachedResult > 0) { return buildDisplayText(which, field, url, filter, filter_key, filter_value); } throw new Error(`No entry found in database for search url ${url}`); } }];