mirror of
https://github.com/kopia/kopia.git
synced 2026-10-26 16:18:53 -04:00
kopia-ui: UI/API server security (TLS & base auth)
This automatically launches Kopia CLI with new flags: `--tls-generate-cert` which generates in-memory TLS certs for the server and prints its fingerprint to stderr. `--random-password` which sets up random base auth password KopiaUI will then listen to the stderr messages and parse the cert fingerprint and password and automatically provide them in the browser it opens to show the UI. This ensures that any local process (or script in a browser, etc.) other than KopiaUI itself won't have access to the server API nor UI because they won't know the ephemeral random password and won't be able to intercept it due to TLS protection.
This commit is contained in:
1 parent
0a42ceab27
commit
758dbccd01
2 files changed
+76
-3
No files matched your search
+28
-2
@@ -5,7 +5,7 @@ const config = require('electron-json-config');
|
||||
|
||||
const { resourcesPath, selectByOS } = require('./utils');
|
||||
const { toggleLaunchAtStartup, willLaunchAtStartup, refreshWillLaunchAtStartup } = require('./auto-launch');
|
||||
const { stopServer, actuateServer } = require('./server');
|
||||
const { stopServer, actuateServer, getServerAddress, getServerCertSHA256, getServerPassword } = require('./server');
|
||||
|
||||
|
||||
ipcMain.on('fetch-config', (event, arg) => {
|
||||
@@ -62,7 +62,7 @@ function showMainWindow() {
|
||||
autoHideMenuBar: true,
|
||||
})
|
||||
|
||||
mainWindow.loadURL('http://localhost:51515/?ts=' + new Date().valueOf());
|
||||
mainWindow.loadURL(getServerAddress() + '/?ts=' + new Date().valueOf());
|
||||
|
||||
mainWindow.on('closed', function () {
|
||||
// forget the reference.
|
||||
@@ -86,6 +86,32 @@ app.on('will-quit', function () {
|
||||
stopServer();
|
||||
});
|
||||
|
||||
app.on('login', (event, webContents, request, authInfo, callback) => {
|
||||
// intercept password prompts and automatically enter password that the server has printed for us.
|
||||
const p = getServerPassword();
|
||||
if (p) {
|
||||
event.preventDefault();
|
||||
console.log('automatically logging in...');
|
||||
callback('kopia', p);
|
||||
}
|
||||
});
|
||||
|
||||
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
|
||||
// intercept certificate errors and automatically trust the certificate the server has printed for us.
|
||||
const expected = 'sha256/' + Buffer.from(getServerCertSHA256(), 'hex').toString('base64');
|
||||
if (certificate.fingerprint === expected) {
|
||||
console.log('accepting server certificate.');
|
||||
|
||||
// On certificate error we disable default behaviour (stop loading the page)
|
||||
// and we then say "it is all fine - true" to the callback
|
||||
event.preventDefault();
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('certificate error:', certificate.fingerprint, expected);
|
||||
});
|
||||
|
||||
// Ignore
|
||||
app.on('window-all-closed', function () {})
|
||||
|
||||
|
||||
+48
-1
@@ -6,6 +6,37 @@ const { defaultServerBinary } = require('./utils');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
let serverProcess = null;
|
||||
let serverCertSHA256 = "";
|
||||
let serverPassword = "";
|
||||
let serverAddress = "";
|
||||
|
||||
function detectServerParam(data) {
|
||||
let lines = (data + '').split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const p = lines[i].indexOf(": ");
|
||||
if (p < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
const key = lines[i].substring(0, p);
|
||||
const value = lines[i].substring(p + 2);
|
||||
switch (key) {
|
||||
case "SERVER PASSWORD":
|
||||
serverPassword = value;
|
||||
break;
|
||||
|
||||
case "SERVER CERT SHA256":
|
||||
serverCertSHA256 = value;
|
||||
break;
|
||||
|
||||
case "SERVER ADDRESS":
|
||||
serverAddress = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
appendToLog(data);
|
||||
}
|
||||
|
||||
function startServer() {
|
||||
let kopiaPath = config.get('kopiaPath');
|
||||
@@ -22,12 +53,16 @@ function startServer() {
|
||||
|
||||
args.push('server', '--ui');
|
||||
|
||||
args.push('--random-password')
|
||||
args.push('--tls-generate-cert')
|
||||
// args.push('--auto-shutdown=600s')
|
||||
|
||||
console.log(`spawning ${kopiaPath} ${args.join(' ')}`);
|
||||
serverProcess = spawn(kopiaPath, args);
|
||||
ipcMain.emit('server-status-updated');
|
||||
|
||||
serverProcess.stdout.on('data', appendToLog);
|
||||
serverProcess.stderr.on('data', appendToLog);
|
||||
serverProcess.stderr.on('data', detectServerParam);
|
||||
|
||||
serverProcess.on('close', (code, signal) => {
|
||||
appendToLog(`child process exited with code ${code} and signal ${signal}`);
|
||||
@@ -81,5 +116,17 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
getServerAddress() {
|
||||
return serverAddress;
|
||||
},
|
||||
|
||||
getServerCertSHA256() {
|
||||
return serverCertSHA256;
|
||||
},
|
||||
|
||||
getServerPassword() {
|
||||
return serverPassword;
|
||||
},
|
||||
|
||||
stopServer: stopServer,
|
||||
}
|
||||
Reference in new issue
Block a user