mirror of
https://github.com/kopia/kopia.git
synced 2026-01-26 15:28:06 -05:00
* cli: added --tls-print-server-cert flag This prints complete server certificate that is base64 and PEM-encoded. It is needed for Electron to securely connect to the server outside of the browser, since there's no way to trust certificate by fingerprint. * server: added repo/exists API * server: added ClientOptions to create and connect API * server: exposed current-user API * server: API to change description of a repository * htmlui: refactored connect/create flow This cleaned up the code a lot and made UX more obvious. * kopia-ui: simplified repository management UX Removed repository configuration window which was confusing due to the notion of 'server'. Now KopiaUI will automatically launch 'kopia server --ui' for each config found in the kopia config directory and shut it down every time repository is disconnected. See https://youtu.be/P4Ll_LR4UVM for a quick demo. Fixes #583
156 lines
3.7 KiB
JavaScript
156 lines
3.7 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const Electron = require('electron');
|
|
const log = require("electron-log");
|
|
|
|
let configs = {};
|
|
const configFileSuffix = ".config";
|
|
|
|
let configDir = "";
|
|
let isPortable = false;
|
|
let firstRun = false;
|
|
|
|
// returns the list of directories to be checked for portable configurations
|
|
function portableConfigDirs() {
|
|
let result = [];
|
|
|
|
if (process.env.KOPIA_UI_PORTABLE_CONFIG_DIR) {
|
|
result.push(process.env.KOPIA_UI_PORTABLE_CONFIG_DIR);
|
|
}
|
|
|
|
if (process.platform == "darwin") {
|
|
// on Mac support 'repositories' directory next to the KopiaUI.app
|
|
result.push(path.join(path.dirname(Electron.app.getPath("exe")), "..", "..", "..", "repositories"));
|
|
} else {
|
|
// on other platforms support 'repositories' directory next to directory
|
|
// containing executable or 'repositories' subdirectory.
|
|
result.push(path.join(path.dirname(Electron.app.getPath("exe")), "repositories"));
|
|
result.push(path.join(path.dirname(Electron.app.getPath("exe")), "..", "repositories"));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function globalConfigDir() {
|
|
if (!configDir) {
|
|
// try portable config dirs in order.
|
|
portableConfigDirs().forEach(d => {
|
|
if (configDir) {
|
|
return;
|
|
}
|
|
|
|
d = path.normalize(d)
|
|
|
|
if (!fs.existsSync(d)) {
|
|
return;
|
|
}
|
|
|
|
configDir = d;
|
|
isPortable = true;
|
|
});
|
|
|
|
// still not set, fall back to per-user config dir.
|
|
// we use the same directory that is used by Kopia CLI.
|
|
if (!configDir) {
|
|
configDir = path.join(Electron.app.getPath("appData"), "kopia");
|
|
}
|
|
}
|
|
|
|
return configDir;
|
|
}
|
|
|
|
function allConfigs() {
|
|
let result = [];
|
|
|
|
for (let k in configs) {
|
|
result.push(k);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function addNewConfig() {
|
|
let id;
|
|
|
|
if (!configs) {
|
|
// first repository is always named "repository" to match Kopia CLI.
|
|
id = "repository";
|
|
} else {
|
|
id = "repository-" + new Date().valueOf();
|
|
}
|
|
|
|
configs[id] = true;
|
|
return id;
|
|
}
|
|
|
|
Electron.ipcMain.on('config-list-fetch', (event, arg) => {
|
|
emitConfigListUpdated();
|
|
});
|
|
|
|
function emitConfigListUpdated() {
|
|
Electron.ipcMain.emit('config-list-updated-event', allConfigs());
|
|
};
|
|
|
|
function deleteConfigIfDisconnected(repoID) {
|
|
if (repoID === "repository") {
|
|
// never delete default repository config
|
|
return false;
|
|
}
|
|
|
|
if (!fs.existsSync(path.join(globalConfigDir(), repoID + configFileSuffix))) {
|
|
delete (configs[repoID]);
|
|
emitConfigListUpdated();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
module.exports = {
|
|
loadConfigs() {
|
|
fs.mkdirSync(globalConfigDir(), { recursive: true, mode: 0700 });
|
|
let entries = fs.readdirSync(globalConfigDir());
|
|
|
|
let count = 0;
|
|
entries.filter(e => path.extname(e) == configFileSuffix).forEach(v => {
|
|
const repoID = v.replace(configFileSuffix, "");
|
|
configs[repoID] = true;
|
|
count++;
|
|
});
|
|
|
|
if (!configs["repository"]) {
|
|
configs["repository"] = true;
|
|
firstRun = true;
|
|
}
|
|
},
|
|
|
|
isPortableConfig() {
|
|
globalConfigDir();
|
|
return isPortable;
|
|
},
|
|
|
|
isFirstRun() {
|
|
return firstRun;
|
|
},
|
|
|
|
configDir() {
|
|
return globalConfigDir();
|
|
},
|
|
|
|
deleteConfigIfDisconnected,
|
|
|
|
addNewConfig,
|
|
|
|
allConfigs,
|
|
|
|
configForRepo(repoID) {
|
|
let c = configs[repoID];
|
|
if (c) {
|
|
return c;
|
|
}
|
|
|
|
configs[repoID] = true;
|
|
emitConfigListUpdated();
|
|
return c;
|
|
}
|
|
} |