This commit is contained in:
antelle 2021-01-01 23:54:00 +01:00
parent 7b8ef9f428
commit 0edac3d127
No known key found for this signature in database
GPG Key ID: 63C9777AAB7C563C
1 changed files with 67 additions and 52 deletions

View File

@ -36,13 +36,13 @@ function run() {
let uninstalled; let uninstalled;
let server; let server;
uninstall = function() { uninstall = function () {
uninstalled = true; uninstalled = true;
removeEventListeners(); removeEventListeners();
stopServer(); stopServer();
}; };
restart = function() { restart = function () {
stopServer(); stopServer();
startServer(); startServer();
}; };
@ -66,8 +66,12 @@ function run() {
server = http.createServer((req, res) => { server = http.createServer((req, res) => {
const origin = req.headers.origin; const origin = req.headers.origin;
const referer = req.headers.referrer || req.headers.referer; const referer = req.headers.referrer || req.headers.referer;
if (req.method !== 'POST' || referer || origin && if (
!origin.startsWith('chrome-extension://') && !origin.startsWith('safari-extension://') req.method !== 'POST' ||
referer ||
(origin &&
!origin.startsWith('chrome-extension://') &&
!origin.startsWith('safari-extension://'))
) { ) {
if (DebugMode) { if (DebugMode) {
logger.debug('Request dropped', req.method, req.url, req.headers); logger.debug('Request dropped', req.method, req.url, req.headers);
@ -78,22 +82,20 @@ function run() {
} }
if (req.method === 'POST') { if (req.method === 'POST') {
const body = []; const body = [];
req.on('data', data => body.push(data)); req.on('data', (data) => body.push(data));
req.on('end', () => { req.on('end', () => {
const postData = Buffer.concat(body).toString(); const postData = Buffer.concat(body).toString();
if (DebugMode) { if (DebugMode) {
logger.debug('< ' + postData); logger.debug('< ' + postData);
} }
new RequestContext(postData) new RequestContext(postData).handle().then((response) => {
.handle() if (DebugMode) {
.then(response => { logger.debug('> ' + response);
if (DebugMode) { }
logger.debug('> ' + response); res.statusCode = 200;
} res.setHeader('Content-Type', 'application/json');
res.statusCode = 200; res.end(response);
res.setHeader('Content-Type', 'application/json'); });
res.end(response);
});
}); });
} }
}); });
@ -106,7 +108,7 @@ function run() {
} }
logger.debug(`Server running at http://${hostname}:${port}/`); logger.debug(`Server running at http://${hostname}:${port}/`);
}); });
server.on('connection', conn => { server.on('connection', (conn) => {
const key = conn.remoteAddress + ':' + conn.remotePort; const key = conn.remoteAddress + ':' + conn.remotePort;
server.conn[key] = conn; server.conn[key] = conn;
conn.on('close', () => { conn.on('close', () => {
@ -136,7 +138,7 @@ function run() {
} }
function readAllKeys() { function readAllKeys() {
AppModel.instance.files.forEach(file => readKeys(file)); AppModel.instance.files.forEach((file) => readKeys(file));
} }
function readKeys(file) { function readKeys(file) {
@ -162,7 +164,7 @@ function run() {
} }
function writeAddedKeysToAllFiles() { function writeAddedKeysToAllFiles() {
AppModel.instance.files.forEach(file => { AppModel.instance.files.forEach((file) => {
writeAddedKeys(file); writeAddedKeys(file);
}); });
} }
@ -207,7 +209,7 @@ function run() {
this.req = JSON.parse(this.postData); this.req = JSON.parse(this.postData);
const response = this.execute() || this.resp; const response = this.execute() || this.resp;
if (response instanceof Promise) { if (response instanceof Promise) {
result = response.catch(e => { result = response.catch((e) => {
return this.makeError(e); return this.makeError(e);
}); });
} else { } else {
@ -216,7 +218,7 @@ function run() {
} catch (e) { } catch (e) {
result = Promise.resolve(this.makeError(e)); result = Promise.resolve(this.makeError(e));
} }
return result.then(res => JSON.stringify(res)); return result.then((res) => JSON.stringify(res));
} }
execute() { execute() {
@ -228,9 +230,9 @@ function run() {
case 'get-logins': case 'get-logins':
return this.getLogins({}); return this.getLogins({});
case 'get-logins-count': case 'get-logins-count':
return this.getLogins({onlyCount: true}); return this.getLogins({ onlyCount: true });
case 'get-all-logins': case 'get-all-logins':
return this.getLogins({all: true}); return this.getLogins({ all: true });
case 'set-login': case 'set-login':
return this.setLogin(); return this.setLogin();
case 'generate-password': case 'generate-password':
@ -241,7 +243,7 @@ function run() {
} }
makeError(e, skipLog) { makeError(e, skipLog) {
const requestType = this.req && this.req.RequestType || ''; const requestType = (this.req && this.req.RequestType) || '';
if (!skipLog) { if (!skipLog) {
logger.error('handleRequest error', requestType, e); logger.error('handleRequest error', requestType, e);
} }
@ -284,7 +286,9 @@ function run() {
} else { } else {
data = Buffer.from(value, 'utf8'); data = Buffer.from(value, 'utf8');
} }
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]).toString('base64'); const encrypted = Buffer.concat([cipher.update(data), cipher.final()]).toString(
'base64'
);
data.fill(0); data.fill(0);
return encrypted; return encrypted;
} }
@ -324,7 +328,10 @@ function run() {
const key = Buffer.from(keys[this.req.Id], 'base64'); const key = Buffer.from(keys[this.req.Id], 'base64');
const nonce = crypto.randomBytes(16); const nonce = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, nonce); const cipher = crypto.createCipheriv('aes-256-cbc', key, nonce);
const encrypted = Buffer.concat([cipher.update(nonce.toString('base64'), 'utf8'), cipher.final()]).toString('base64'); const encrypted = Buffer.concat([
cipher.update(nonce.toString('base64'), 'utf8'),
cipher.final()
]).toString('base64');
resp.Id = this.req.Id; resp.Id = this.req.Id;
resp.Nonce = nonce.toString('base64'); resp.Nonce = nonce.toString('base64');
resp.Verifier = encrypted; resp.Verifier = encrypted;
@ -357,7 +364,8 @@ function run() {
Alerts.yesno({ Alerts.yesno({
icon: 'plug', icon: 'plug',
header: 'External Connection', 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.', 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: () => { success: () => {
resolve(); resolve();
}, },
@ -387,7 +395,7 @@ function run() {
} }
const url = this.req.Url ? this.decrypt(this.req.Url) : ''; const url = this.req.Url ? this.decrypt(this.req.Url) : '';
this.createResponse(); this.createResponse();
const filter = new AutoTypeFilter({url}, AppModel.instance); const filter = new AutoTypeFilter({ url }, AppModel.instance);
if (config.all) { if (config.all) {
filter.ignoreWindowInfo = true; filter.ignoreWindowInfo = true;
} }
@ -395,7 +403,7 @@ function run() {
this.resp.Count = entries.length; this.resp.Count = entries.length;
logger.info(`getLogins(${url}): ${this.resp.Count}`); logger.info(`getLogins(${url}): ${this.resp.Count}`);
if (!config.onlyCount) { if (!config.onlyCount) {
this.resp.Entries = entries.map(entry => { this.resp.Entries = entries.map((entry) => {
let customFields = null; let customFields = null;
for (const field of Object.keys(entry.fields)) { for (const field of Object.keys(entry.fields)) {
if (!customFields) { if (!customFields) {
@ -428,7 +436,7 @@ function run() {
if (uuid) { if (uuid) {
let result = 'not found'; let result = 'not found';
AppModel.instance.files.forEach(file => { AppModel.instance.files.forEach((file) => {
const entry = file.getEntry(file.subId(uuid)); const entry = file.getEntry(file.subId(uuid));
if (entry) { if (entry) {
if (entry.user !== login) { if (entry.user !== login) {
@ -444,8 +452,8 @@ function run() {
} else { } else {
logger.info(`setLogin(${url}, ${login}, ${password.length}): inserted`); logger.info(`setLogin(${url}, ${login}, ${password.length}): inserted`);
let group, file; let group, file;
AppModel.instance.files.forEach(f => { AppModel.instance.files.forEach((f) => {
f.forEachGroup(g => { f.forEachGroup((g) => {
if (g.title === CreatePasswordsGroupTitle) { if (g.title === CreatePasswordsGroupTitle) {
group = g; group = g;
file = f; file = f;
@ -458,8 +466,10 @@ function run() {
group.setName(CreatePasswordsGroupTitle); group.setName(CreatePasswordsGroupTitle);
} }
const entry = EntryModel.newEntry(group, file); const entry = EntryModel.newEntry(group, file);
const domain = url.match(/^(?:\w+:\/\/)?(?:(?:www|wwws|secure)\.)?([^\/]+)\/?(?:.*)/); const domain = url.match(
const title = domain && domain[1] || 'Saved Password'; /^(?:\w+:\/\/)?(?:(?:www|wwws|secure)\.)?([^\/]+)\/?(?:.*)/
);
const title = (domain && domain[1]) || 'Saved Password';
entry.setField('Title', title); entry.setField('Title', title);
entry.setField('URL', url); entry.setField('URL', url);
entry.setField('UserName', login); entry.setField('UserName', login);
@ -473,33 +483,38 @@ function run() {
generatePassword() { generatePassword() {
this.verifyRequest(); this.verifyRequest();
this.createResponse(); this.createResponse();
const preset = GeneratorPresets.all.filter(p => p.default)[0] || GeneratorPresets.defaultPreset; const preset =
GeneratorPresets.all.filter((p) => p.default)[0] || GeneratorPresets.defaultPreset;
const password = PasswordGenerator.generate(preset); const password = PasswordGenerator.generate(preset);
const bits = Buffer.from(password, 'utf8').byteLength * 8; const bits = Buffer.from(password, 'utf8').byteLength * 8;
this.resp.Count = 1; this.resp.Count = 1;
this.resp.Entries = [{ this.resp.Entries = [
Login: this.encrypt(bits.toString()), {
Name: '', Login: this.encrypt(bits.toString()),
Password: this.encrypt(password), Name: '',
StringFields: null, Password: this.encrypt(password),
Uuid: '' StringFields: null,
}]; Uuid: ''
}
];
} }
} }
} }
module.exports.getSettings = function() { module.exports.getSettings = function () {
return [{ return [
name: 'ServerPort', {
label: 'Port to listen to (do not change this setting without a special need to do so)', name: 'ServerPort',
type: 'text', label: 'Port to listen to (do not change this setting without a special need to do so)',
maxlength: 5, type: 'text',
placeholder: '19455', maxlength: 5,
value: '19455' placeholder: '19455',
}]; value: '19455'
}
];
}; };
module.exports.setSettings = function(changes) { module.exports.setSettings = function (changes) {
if (changes.ServerPort) { if (changes.ServerPort) {
const port = +changes.ServerPort; const port = +changes.ServerPort;
if (port > 1024 && port < 65535) { if (port > 1024 && port < 65535) {
@ -511,7 +526,7 @@ module.exports.setSettings = function(changes) {
} }
}; };
module.exports.uninstall = function() { module.exports.uninstall = function () {
if (uninstall) { if (uninstall) {
uninstall(); uninstall();
} else { } else {