VPN: WireGuard-/OpenVPN-Konfigurationen verwalten, Hosts zuordnen, automatischer Aufbau vor dem Verbinden (Linux: NetworkManager, Windows: WireGuard-Dienst/OpenVPN GUI)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+35
-6
@@ -11,6 +11,7 @@ const { Updater } = require('./updater');
|
||||
const { createEmbed, embedSupported } = require('./rdp-embed');
|
||||
const i18n = require('../i18n');
|
||||
const fido = require('./fido');
|
||||
const { VpnManager } = require('./vpn');
|
||||
const applyLanguage = () => i18n.setLanguage(store.get().settings.language, app.getLocale());
|
||||
|
||||
let win;
|
||||
@@ -59,6 +60,7 @@ function askSecret(sessionId, req) {
|
||||
|
||||
const ssh = new SshManager(store, confirmHostKey, askSecret);
|
||||
const updater = new Updater(store, send);
|
||||
const vpn = new VpnManager(store, app.getPath('userData'));
|
||||
|
||||
function createWindow() {
|
||||
win = new BrowserWindow({
|
||||
@@ -176,8 +178,26 @@ handle('lock:removeFido', (id) => {
|
||||
|
||||
// ---------- Vault ----------
|
||||
handle('vault:get', () => ({ ...store.get(), encrypted: store.encrypted, platform: process.platform }));
|
||||
handle('vault:upsert', (col, item) => store.upsert(col, item));
|
||||
handle('vault:remove', (col, id) => store.remove(col, id));
|
||||
handle('vault:upsert', async (col, item) => {
|
||||
// Geänderte VPN-Konfiguration: alte Systemverbindung entfernen, beim nächsten Verbinden neu importieren
|
||||
if (col === 'vpns' && item.id) {
|
||||
const old = store.get().vpns.find((v) => v.id === item.id);
|
||||
if (old && ['type', 'config', 'username', 'password'].some((k) => (old[k] || '') !== (item[k] || ''))) await vpn.forget(old);
|
||||
}
|
||||
return store.upsert(col, item);
|
||||
});
|
||||
handle('vault:remove', async (col, id) => {
|
||||
if (col === 'vpns') {
|
||||
await vpn.forget(store.get().vpns.find((v) => v.id === id));
|
||||
store.get().hosts.forEach((h) => { if (h.vpnId === id) h.vpnId = null; });
|
||||
}
|
||||
return store.remove(col, id);
|
||||
});
|
||||
|
||||
// ---------- VPN ----------
|
||||
handle('vpn:status', () => vpn.status());
|
||||
handle('vpn:up', (id) => vpn.up(id));
|
||||
handle('vpn:down', (id) => vpn.down(id));
|
||||
handle('vault:settings', (s) => {
|
||||
store.setSettings(s);
|
||||
if ('language' in s) applyLanguage();
|
||||
@@ -274,6 +294,8 @@ function hostWithOverrides(hostOrId) {
|
||||
handle('ssh:open', async (sessionId, hostRef, size) => {
|
||||
const host = hostWithOverrides(hostRef);
|
||||
if (host.id) store.addHistory({ hostId: host.id, at: Date.now() });
|
||||
const onEvent = (type, payload) => send('ssh:event', sessionId, type, payload);
|
||||
if (await vpn.ensureForHost(host, (m) => onEvent('status', m))) send('vpn:changed');
|
||||
await ssh.openShell(sessionId, host, size, (type, payload) => send('ssh:event', sessionId, type, payload));
|
||||
return true;
|
||||
});
|
||||
@@ -286,7 +308,11 @@ ipcMain.on('secret:reply', (_e, reqId, value) => {
|
||||
});
|
||||
|
||||
// ---------- SFTP ----------
|
||||
handle('sftp:open', (sessionId, hostRef) => ssh.openSftp(sessionId, hostWithOverrides(hostRef)));
|
||||
handle('sftp:open', async (sessionId, hostRef) => {
|
||||
const host = hostWithOverrides(hostRef);
|
||||
if (await vpn.ensureForHost(host)) send('vpn:changed');
|
||||
return ssh.openSftp(sessionId, host);
|
||||
});
|
||||
handle('sftp:list', (id, dir) => ssh.sftpList(id, dir));
|
||||
handle('sftp:op', (id, op, a, b) => ssh.sftpOp(id, op, a, b));
|
||||
handle('sftp:transfer', async (id, dir, localPath, remotePath, transferId) => {
|
||||
@@ -320,9 +346,10 @@ handle('local:op', (op, a, b) => {
|
||||
});
|
||||
|
||||
// ---------- Port-Forwarding ----------
|
||||
handle('fw:start', (id) => {
|
||||
handle('fw:start', async (id) => {
|
||||
const fw = store.get().forwards.find((f) => f.id === id);
|
||||
if (!fw) throw new Error(i18n.t('Rule not found'));
|
||||
if (await vpn.ensureForHost(store.resolveHost(fw.hostId))) send('vpn:changed');
|
||||
return ssh.startForward(fw, (ev) => send('fw:event', id, ev));
|
||||
});
|
||||
handle('fw:stop', (id) => ssh.stopForward(id));
|
||||
@@ -330,8 +357,9 @@ handle('fw:active', () => ssh.activeForwards());
|
||||
|
||||
// ---------- RDP ----------
|
||||
handle('rdp:detect', () => rdp.detect(store.get().settings));
|
||||
handle('rdp:launch', (hostId) => {
|
||||
handle('rdp:launch', async (hostId) => {
|
||||
const host = hostWithOverrides(hostId);
|
||||
if (await vpn.ensureForHost(host)) send('vpn:changed');
|
||||
if (host.id) store.addHistory({ hostId: host.id, at: Date.now() });
|
||||
const r = rdp.launch(host, store.get().settings);
|
||||
if (r.process) {
|
||||
@@ -351,6 +379,7 @@ handle('rdp:embedSupported', () => {
|
||||
handle('rdp:open', async (id, hostRef, bounds) => {
|
||||
const host = hostWithOverrides(hostRef);
|
||||
if (host.id) store.addHistory({ hostId: host.id, at: Date.now() });
|
||||
if (await vpn.ensureForHost(host)) send('vpn:changed');
|
||||
const emb = createEmbed(win.getNativeWindowHandle());
|
||||
const sess = { emb, cancelled: false };
|
||||
rdpSessions.set(id, sess);
|
||||
@@ -453,7 +482,7 @@ function scheduleUpdateCheck() {
|
||||
updateScheduled = true;
|
||||
setTimeout(() => updater.check().then((r) => { if (r.available) send('update:available', r); }).catch(() => {}), 6000);
|
||||
}
|
||||
app.on('window-all-closed', () => { ssh.closeAll(); app.quit(); });
|
||||
app.on('window-all-closed', async () => { ssh.closeAll(); await vpn.downOnQuit(); app.quit(); });
|
||||
|
||||
// Smoke-Test: MRTERM_SMOKE=<pfad.png> startet, loggt Renderer-Meldungen, speichert einen Screenshot und beendet.
|
||||
if (process.env.MRTERM_SMOKE) {
|
||||
|
||||
Reference in New Issue
Block a user