Sync: warn CachyOS/UFW/firewalld users to open the sync ports with copyable commands; ask before sharing newly created SSH keys, passwords and VPN configurations
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -267,6 +267,7 @@ handle('sync:pair', (id) => sync.pair(id));
|
||||
handle('sync:unpair', (id) => sync.unpair(id));
|
||||
handle('sync:now', () => sync.syncAll());
|
||||
handle('sync:share', (sel) => sync.setShare(sel));
|
||||
handle('sync:shareItem', (c, id, yes) => sync.shareItem(c, id, yes));
|
||||
handle('sync:probe', (address) => sync.probe(address));
|
||||
|
||||
// ---------- VPN ----------
|
||||
|
||||
+31
-2
@@ -14,6 +14,21 @@ const net = require('net');
|
||||
const os = require('os');
|
||||
const crypto = require('crypto');
|
||||
const i18n = require('../i18n');
|
||||
const fs = require('fs');
|
||||
const { execFileSync } = require('child_process');
|
||||
|
||||
// Lokale Firewall erkennen, die Broadcasts/eingehende Verbindungen blockieren könnte (Linux).
|
||||
// Ob die Ports bereits freigegeben sind, lässt sich ohne root nicht prüfen (UFW-Regeln sind nur für root lesbar).
|
||||
function localFirewall() {
|
||||
if (process.platform !== 'linux') return null;
|
||||
const read = (f) => { try { return fs.readFileSync(f, 'utf8'); } catch { return ''; } };
|
||||
const active = (unit) => { try { return execFileSync('systemctl', ['is-active', unit], { timeout: 3000 }).toString().trim() === 'active'; } catch { return false; } };
|
||||
const os = (read('/etc/os-release').match(/^ID=(.*)$/m) || [])[1]?.replace(/"/g, '') || '';
|
||||
const ufw = /^ENABLED=yes/m.test(read('/etc/ufw/ufw.conf')) || active('ufw');
|
||||
const firewalld = active('firewalld');
|
||||
if (!ufw && !firewalld && os !== 'cachyos') return null;
|
||||
return { os, ufw, firewalld };
|
||||
}
|
||||
|
||||
const UDP_PORT = 47811;
|
||||
const TCP_PORT = 47812;
|
||||
@@ -170,6 +185,7 @@ class SyncService {
|
||||
this.running = false;
|
||||
this.lastError = '';
|
||||
this.syncing = new Set();
|
||||
this.firewall = localFirewall();
|
||||
}
|
||||
|
||||
get cfg() {
|
||||
@@ -271,7 +287,7 @@ class SyncService {
|
||||
enabled: c.enabled, running: this.running, deviceId: c.deviceId, deviceName: c.deviceName, pairable: this.pairable, port: this.port,
|
||||
peers: c.peers.map((p) => ({ id: p.id, name: p.name, lastSync: p.lastSync || 0, online: this.seen.has(p.id), address: p.address, error: p.error || '' })),
|
||||
nearby: [...this.seen.values()].filter((p) => !c.peers.some((x) => x.id === p.id)).map(({ id, name, address, pairable }) => ({ id, name, address, pairable })),
|
||||
share: c.share, asked: !!c.asked, sealed: !!this.store.sealed,
|
||||
share: c.share, asked: !!c.asked, sealed: !!this.store.sealed, firewall: this.firewall,
|
||||
};
|
||||
}
|
||||
emitState() { this.emit('sync:state', this.status()); }
|
||||
@@ -452,12 +468,25 @@ class SyncService {
|
||||
setShare(share) {
|
||||
const clean = (a) => (Array.isArray(a) ? a.filter((x) => typeof x === 'string') : []);
|
||||
const c = this.cfg;
|
||||
c.share = { keys: clean(share?.keys), hosts: clean(share?.hosts), vpns: clean(share?.vpns) };
|
||||
c.share = { keys: clean(share?.keys), hosts: clean(share?.hosts), vpns: clean(share?.vpns), declined: { keys: [], hosts: [], vpns: [] } };
|
||||
c.asked = true;
|
||||
this.store.save();
|
||||
return this.status();
|
||||
}
|
||||
|
||||
// Einzelnes neues Geheimnis teilen oder ablehnen (Ablehnung wird gemerkt, damit nicht erneut gefragt wird)
|
||||
shareItem(c, id, yes) {
|
||||
if (!SECRETS[c] || typeof id !== 'string') throw new Error('Invalid');
|
||||
const sh = this.cfg.share;
|
||||
sh.declined ||= { keys: [], hosts: [], vpns: [] };
|
||||
sh[c] = (sh[c] || []).filter((x) => x !== id);
|
||||
sh.declined[c] = (sh.declined[c] || []).filter((x) => x !== id);
|
||||
(yes ? sh[c] : sh.declined[c]).push(id);
|
||||
this.store.save();
|
||||
if (yes) this.schedule(500);
|
||||
return this.status();
|
||||
}
|
||||
|
||||
// Gerät per IP hinzufügen (wenn Broadcasts im Netz blockiert sind)
|
||||
async probe(address, port = TCP_PORT) {
|
||||
if (!/^[\w.:-]+$/.test(address)) throw new Error('Invalid address');
|
||||
|
||||
Reference in New Issue
Block a user