termify-agent 1.0.33 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +13 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +236 -0
- package/dist/agent.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +184 -15
- package/dist/index.js.map +1 -1
- package/dist/network/backends/windows-wireguard-backend.d.ts +29 -0
- package/dist/network/backends/windows-wireguard-backend.d.ts.map +1 -0
- package/dist/network/backends/windows-wireguard-backend.js +190 -0
- package/dist/network/backends/windows-wireguard-backend.js.map +1 -0
- package/dist/network/key-rotation.d.ts +55 -0
- package/dist/network/key-rotation.d.ts.map +1 -0
- package/dist/network/key-rotation.js +105 -0
- package/dist/network/key-rotation.js.map +1 -0
- package/dist/network/nat-traversal.d.ts +27 -0
- package/dist/network/nat-traversal.d.ts.map +1 -0
- package/dist/network/nat-traversal.js +76 -0
- package/dist/network/nat-traversal.js.map +1 -0
- package/dist/network/uapi-client.d.ts +50 -0
- package/dist/network/uapi-client.d.ts.map +1 -0
- package/dist/network/uapi-client.js +260 -0
- package/dist/network/uapi-client.js.map +1 -0
- package/dist/network/wireguard-backend.d.ts +60 -0
- package/dist/network/wireguard-backend.d.ts.map +1 -0
- package/dist/network/wireguard-backend.js +9 -0
- package/dist/network/wireguard-backend.js.map +1 -0
- package/dist/network/wireguard-installer.d.ts +24 -0
- package/dist/network/wireguard-installer.d.ts.map +1 -0
- package/dist/network/wireguard-installer.js +362 -0
- package/dist/network/wireguard-installer.js.map +1 -0
- package/dist/network/wireguard-manager.d.ts +92 -0
- package/dist/network/wireguard-manager.d.ts.map +1 -0
- package/dist/network/wireguard-manager.js +575 -0
- package/dist/network/wireguard-manager.js.map +1 -0
- package/dist/network/wireguard-state-store.d.ts +55 -0
- package/dist/network/wireguard-state-store.d.ts.map +1 -0
- package/dist/network/wireguard-state-store.js +196 -0
- package/dist/network/wireguard-state-store.js.map +1 -0
- package/dist/ssh-manager.d.ts +5 -0
- package/dist/ssh-manager.d.ts.map +1 -1
- package/dist/ssh-manager.js +104 -0
- package/dist/ssh-manager.js.map +1 -1
- package/dist/tunnel-manager.d.ts +65 -0
- package/dist/tunnel-manager.d.ts.map +1 -0
- package/dist/tunnel-manager.js +267 -0
- package/dist/tunnel-manager.js.map +1 -0
- package/dist/ws-client.d.ts +145 -0
- package/dist/ws-client.d.ts.map +1 -1
- package/dist/ws-client.js +136 -1
- package/dist/ws-client.js.map +1 -1
- package/package.json +1 -1
- package/scripts/postinstall.js +100 -35
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level WireGuard orchestrator for the Termify agent.
|
|
3
|
+
*
|
|
4
|
+
* Combines:
|
|
5
|
+
* - wireguard-installer (detection / auto-install)
|
|
6
|
+
* - wireguard-state-store (persistent keypair)
|
|
7
|
+
* - WireGuardBackend (platform-specific interface management)
|
|
8
|
+
*
|
|
9
|
+
* Emits events:
|
|
10
|
+
* - 'ready' after interface is up
|
|
11
|
+
* - 'peer:added' { peer }
|
|
12
|
+
* - 'peer:removed' { publicKey }
|
|
13
|
+
* - 'health' WgHealthSnapshot
|
|
14
|
+
* - 'error' Error
|
|
15
|
+
* - 'shutdown' when torn down
|
|
16
|
+
*/
|
|
17
|
+
import { EventEmitter } from 'node:events';
|
|
18
|
+
import { execFile as execFileCb, spawn } from 'node:child_process';
|
|
19
|
+
import { promisify } from 'node:util';
|
|
20
|
+
import { platform as osPlatform, homedir } from 'node:os';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { logger } from '../utils/logger.js';
|
|
23
|
+
import { detectWireGuard, installWireGuard, } from './wireguard-installer.js';
|
|
24
|
+
import { WireGuardStateStore } from './wireguard-state-store.js';
|
|
25
|
+
import { WindowsWireGuardBackend } from './backends/windows-wireguard-backend.js';
|
|
26
|
+
import { uapiSetInterface, uapiAddPeer, uapiRemovePeer, uapiUpdatePeerEndpoint, uapiGetStatus, } from './uapi-client.js';
|
|
27
|
+
const execFile = promisify(execFileCb);
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Linux / macOS backend implementation
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
/**
|
|
32
|
+
* Concrete WireGuardBackend for Linux (kernel module) and macOS (wireguard-go).
|
|
33
|
+
*
|
|
34
|
+
* Supports two modes:
|
|
35
|
+
* - CLI mode: uses `wg` CLI tool (for Linux kernel module)
|
|
36
|
+
* - UAPI mode: talks directly to wireguard-go socket (no `wg` CLI needed)
|
|
37
|
+
*
|
|
38
|
+
* All commands use `execFile` with array args to avoid shell injection.
|
|
39
|
+
* Private keys are referenced by file path only - never passed as args.
|
|
40
|
+
*/
|
|
41
|
+
class UnixWireGuardBackend {
|
|
42
|
+
plat;
|
|
43
|
+
/** When true, use UAPI socket instead of `wg` CLI for configuration */
|
|
44
|
+
useUapi = false;
|
|
45
|
+
constructor() {
|
|
46
|
+
this.plat = osPlatform();
|
|
47
|
+
}
|
|
48
|
+
/** Enable UAPI mode (used when backend is wireguard-go) */
|
|
49
|
+
setUapiMode(enabled) {
|
|
50
|
+
this.useUapi = enabled;
|
|
51
|
+
if (enabled) {
|
|
52
|
+
logger.info('[WG Backend] UAPI mode enabled (no wg CLI needed)');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async isAvailable() {
|
|
56
|
+
const result = await detectWireGuard();
|
|
57
|
+
return {
|
|
58
|
+
available: result.available,
|
|
59
|
+
reason: result.available ? undefined : result.availability,
|
|
60
|
+
version: result.version,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async ensureInterface(config) {
|
|
64
|
+
const { interfaceName, virtualIp, listenPort, privateKeyPath, privateKeyBase64 } = config;
|
|
65
|
+
if (this.plat === 'darwin') {
|
|
66
|
+
await this.ensureInterfaceDarwin(interfaceName, virtualIp, listenPort, privateKeyPath, privateKeyBase64);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
await this.ensureInterfaceLinux(interfaceName, virtualIp, listenPort, privateKeyPath, privateKeyBase64);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// -- Linux ---------------------------------------------------------------
|
|
73
|
+
async ensureInterfaceLinux(iface, virtualIp, listenPort, privateKeyPath, privateKeyBase64) {
|
|
74
|
+
// Create interface if it doesn't exist
|
|
75
|
+
if (!(await this.interfaceExists(iface))) {
|
|
76
|
+
logger.debug('[WG Backend] Creating interface ' + iface);
|
|
77
|
+
await execFile('ip', ['link', 'add', 'dev', iface, 'type', 'wireguard']);
|
|
78
|
+
}
|
|
79
|
+
// Assign address (flush first to be idempotent)
|
|
80
|
+
const cidr = virtualIp.includes('/') ? virtualIp : virtualIp + '/32';
|
|
81
|
+
try {
|
|
82
|
+
await execFile('ip', ['addr', 'flush', 'dev', iface]);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// May fail if interface just created with no addresses
|
|
86
|
+
}
|
|
87
|
+
await execFile('ip', ['addr', 'add', cidr, 'dev', iface]);
|
|
88
|
+
// Configure WireGuard
|
|
89
|
+
if (this.useUapi && privateKeyBase64) {
|
|
90
|
+
await uapiSetInterface(iface, privateKeyBase64, listenPort);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
await execFile('wg', [
|
|
94
|
+
'set', iface,
|
|
95
|
+
'private-key', privateKeyPath,
|
|
96
|
+
'listen-port', String(listenPort),
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
// Bring interface up
|
|
100
|
+
await execFile('ip', ['link', 'set', iface, 'up']);
|
|
101
|
+
logger.info('[WG Backend] Interface ' + iface + ' up with ' + cidr);
|
|
102
|
+
}
|
|
103
|
+
// -- macOS ---------------------------------------------------------------
|
|
104
|
+
async ensureInterfaceDarwin(iface, virtualIp, listenPort, privateKeyPath, privateKeyBase64) {
|
|
105
|
+
// On macOS, wireguard-go creates a utun device.
|
|
106
|
+
// We start wireguard-go if the interface doesn't exist yet.
|
|
107
|
+
if (!(await this.interfaceExists(iface))) {
|
|
108
|
+
logger.debug('[WG Backend] Starting wireguard-go for ' + iface);
|
|
109
|
+
await this.startWireGuardGo(iface);
|
|
110
|
+
await this.waitForInterface(iface, 5_000);
|
|
111
|
+
}
|
|
112
|
+
// Configure WireGuard via UAPI (preferred) or CLI
|
|
113
|
+
if (this.useUapi && privateKeyBase64) {
|
|
114
|
+
await uapiSetInterface(iface, privateKeyBase64, listenPort);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
await execFile('wg', [
|
|
118
|
+
'set', iface,
|
|
119
|
+
'private-key', privateKeyPath,
|
|
120
|
+
'listen-port', String(listenPort),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
// Assign IP address
|
|
124
|
+
const ip = virtualIp.replace(/\/\d+$/, ''); // strip CIDR if present
|
|
125
|
+
await execFile('ifconfig', [iface, 'inet', ip, ip, 'up']);
|
|
126
|
+
// Add route so traffic to the VPN subnet goes through our interface
|
|
127
|
+
try {
|
|
128
|
+
await execFile('route', ['add', '-net', ip + '/32', '-interface', iface]);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Route may already exist
|
|
132
|
+
}
|
|
133
|
+
logger.info('[WG Backend] Interface ' + iface + ' up with ' + ip + ' (macOS)');
|
|
134
|
+
}
|
|
135
|
+
async startWireGuardGo(iface) {
|
|
136
|
+
// Search for bundled wireguard-go first, then fall back to PATH
|
|
137
|
+
const bundledPath = join(homedir(), '.termify', 'wireguard-go');
|
|
138
|
+
let binaryPath = 'wireguard-go';
|
|
139
|
+
try {
|
|
140
|
+
const { access, constants } = await import('node:fs/promises');
|
|
141
|
+
await access(bundledPath, constants.X_OK);
|
|
142
|
+
binaryPath = bundledPath;
|
|
143
|
+
logger.debug('[WG Backend] Using bundled wireguard-go: ' + bundledPath);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
logger.debug('[WG Backend] Using system wireguard-go from PATH');
|
|
147
|
+
}
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
const proc = spawn(binaryPath, [iface], {
|
|
150
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
151
|
+
detached: true,
|
|
152
|
+
});
|
|
153
|
+
let stderr = '';
|
|
154
|
+
proc.stderr.on('data', (data) => {
|
|
155
|
+
stderr += data.toString();
|
|
156
|
+
});
|
|
157
|
+
// wireguard-go exits immediately after creating the interface
|
|
158
|
+
proc.on('close', (code) => {
|
|
159
|
+
if (code !== 0 && code !== null) {
|
|
160
|
+
reject(new Error('wireguard-go failed (code=' + code + '): ' + stderr.trim()));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
resolve();
|
|
164
|
+
});
|
|
165
|
+
proc.on('error', (err) => {
|
|
166
|
+
reject(err);
|
|
167
|
+
});
|
|
168
|
+
proc.unref();
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// -- Shared ops ----------------------------------------------------------
|
|
172
|
+
async setPeers(interfaceName, peers) {
|
|
173
|
+
// Get existing peers and remove them first
|
|
174
|
+
const health = await this.getHealth(interfaceName);
|
|
175
|
+
for (const existing of health.peers) {
|
|
176
|
+
await this.removePeer(interfaceName, existing.publicKey);
|
|
177
|
+
}
|
|
178
|
+
// Add new peers
|
|
179
|
+
for (const peer of peers) {
|
|
180
|
+
await this.addPeer(interfaceName, peer);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async addPeer(interfaceName, peer) {
|
|
184
|
+
if (this.useUapi) {
|
|
185
|
+
await uapiAddPeer(interfaceName, peer.publicKey, peer.allowedIps, peer.persistentKeepalive, peer.endpoint);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const args = [
|
|
189
|
+
'set', interfaceName,
|
|
190
|
+
'peer', peer.publicKey,
|
|
191
|
+
'allowed-ips', peer.allowedIps,
|
|
192
|
+
'persistent-keepalive', String(peer.persistentKeepalive),
|
|
193
|
+
];
|
|
194
|
+
if (peer.endpoint) {
|
|
195
|
+
args.push('endpoint', peer.endpoint);
|
|
196
|
+
}
|
|
197
|
+
await execFile('wg', args);
|
|
198
|
+
logger.debug('[WG Backend] Added peer ' + peer.publicKey.slice(0, 8) + '...');
|
|
199
|
+
}
|
|
200
|
+
async removePeer(interfaceName, publicKey) {
|
|
201
|
+
if (this.useUapi) {
|
|
202
|
+
await uapiRemovePeer(interfaceName, publicKey);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
await execFile('wg', ['set', interfaceName, 'peer', publicKey, 'remove']);
|
|
206
|
+
logger.debug('[WG Backend] Removed peer ' + publicKey.slice(0, 8) + '...');
|
|
207
|
+
}
|
|
208
|
+
async updatePeerEndpoint(interfaceName, publicKey, endpoint) {
|
|
209
|
+
if (this.useUapi) {
|
|
210
|
+
await uapiUpdatePeerEndpoint(interfaceName, publicKey, endpoint);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
await execFile('wg', ['set', interfaceName, 'peer', publicKey, 'endpoint', endpoint]);
|
|
214
|
+
logger.debug('[WG Backend] Updated endpoint for peer ' + publicKey.slice(0, 8) + '...');
|
|
215
|
+
}
|
|
216
|
+
async getHealth(interfaceName) {
|
|
217
|
+
if (this.useUapi) {
|
|
218
|
+
try {
|
|
219
|
+
return await uapiGetStatus(interfaceName);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return { interfaceUp: false, publicKey: '', listenPort: 0, peers: [] };
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// `wg show <iface> dump` outputs tab-separated values:
|
|
226
|
+
// Line 1: private-key public-key listen-port fwmark
|
|
227
|
+
// Line 2+: public-key preshared-key endpoint allowed-ips latest-handshake transfer-rx transfer-tx persistent-keepalive
|
|
228
|
+
let stdout;
|
|
229
|
+
try {
|
|
230
|
+
const result = await execFile('wg', ['show', interfaceName, 'dump']);
|
|
231
|
+
stdout = result.stdout;
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return {
|
|
235
|
+
interfaceUp: false,
|
|
236
|
+
publicKey: '',
|
|
237
|
+
listenPort: 0,
|
|
238
|
+
peers: [],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
const lines = stdout.trim().split('\n');
|
|
242
|
+
if (lines.length === 0) {
|
|
243
|
+
return { interfaceUp: false, publicKey: '', listenPort: 0, peers: [] };
|
|
244
|
+
}
|
|
245
|
+
// Parse interface line
|
|
246
|
+
const ifaceParts = lines[0].split('\t');
|
|
247
|
+
const publicKey = ifaceParts[1] ?? '';
|
|
248
|
+
const listenPort = parseInt(ifaceParts[2] ?? '0', 10);
|
|
249
|
+
// Parse peer lines
|
|
250
|
+
const peers = [];
|
|
251
|
+
for (let i = 1; i < lines.length; i++) {
|
|
252
|
+
const parts = lines[i].split('\t');
|
|
253
|
+
if (parts.length < 7)
|
|
254
|
+
continue;
|
|
255
|
+
const handshakeEpoch = parseInt(parts[4] ?? '0', 10);
|
|
256
|
+
peers.push({
|
|
257
|
+
publicKey: parts[0],
|
|
258
|
+
endpoint: parts[2] === '(none)' ? undefined : parts[2],
|
|
259
|
+
allowedIps: parts[3],
|
|
260
|
+
latestHandshake: handshakeEpoch > 0 ? new Date(handshakeEpoch * 1000) : undefined,
|
|
261
|
+
transferRx: parseInt(parts[5] ?? '0', 10),
|
|
262
|
+
transferTx: parseInt(parts[6] ?? '0', 10),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
interfaceUp: true,
|
|
267
|
+
publicKey,
|
|
268
|
+
listenPort,
|
|
269
|
+
peers,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
async teardown(interfaceName) {
|
|
273
|
+
if (this.plat === 'darwin') {
|
|
274
|
+
// On macOS, deleting the utun socket file kills wireguard-go
|
|
275
|
+
try {
|
|
276
|
+
const { unlink } = await import('node:fs/promises');
|
|
277
|
+
await unlink('/var/run/wireguard/' + interfaceName + '.sock');
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Socket may not exist
|
|
281
|
+
}
|
|
282
|
+
// Also try ifconfig down
|
|
283
|
+
try {
|
|
284
|
+
await execFile('ifconfig', [interfaceName, 'down']);
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// Interface may already be gone
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
// Linux: ip link delete
|
|
292
|
+
try {
|
|
293
|
+
await execFile('ip', ['link', 'delete', 'dev', interfaceName]);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// Interface may not exist
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
logger.info('[WG Backend] Interface ' + interfaceName + ' torn down');
|
|
300
|
+
}
|
|
301
|
+
// -- Utility -------------------------------------------------------------
|
|
302
|
+
async interfaceExists(iface) {
|
|
303
|
+
if (this.plat === 'darwin') {
|
|
304
|
+
try {
|
|
305
|
+
await execFile('ifconfig', [iface]);
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
try {
|
|
314
|
+
await execFile('ip', ['link', 'show', iface]);
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async waitForInterface(iface, timeoutMs) {
|
|
323
|
+
const start = Date.now();
|
|
324
|
+
while (Date.now() - start < timeoutMs) {
|
|
325
|
+
if (await this.interfaceExists(iface))
|
|
326
|
+
return;
|
|
327
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
328
|
+
}
|
|
329
|
+
throw new Error('Timeout waiting for interface ' + iface);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
// WireGuardManager - high-level orchestrator
|
|
334
|
+
// ---------------------------------------------------------------------------
|
|
335
|
+
export class WireGuardManager extends EventEmitter {
|
|
336
|
+
backend = null;
|
|
337
|
+
stateStore;
|
|
338
|
+
identity = null;
|
|
339
|
+
installResult = null;
|
|
340
|
+
interfaceName = null;
|
|
341
|
+
connectedPeers = 0;
|
|
342
|
+
constructor(configDir) {
|
|
343
|
+
super();
|
|
344
|
+
this.stateStore = new WireGuardStateStore(configDir);
|
|
345
|
+
}
|
|
346
|
+
// -----------------------------------------------------------------------
|
|
347
|
+
// Public API
|
|
348
|
+
// -----------------------------------------------------------------------
|
|
349
|
+
/**
|
|
350
|
+
* Detect and optionally install WireGuard.
|
|
351
|
+
* Does NOT throw on failure - returns the detection result.
|
|
352
|
+
*/
|
|
353
|
+
async ensureInstalled() {
|
|
354
|
+
try {
|
|
355
|
+
let result = await detectWireGuard();
|
|
356
|
+
if (!result.available && result.availability === 'missing_binary') {
|
|
357
|
+
logger.info('[WG Manager] WireGuard not found, attempting install...');
|
|
358
|
+
result = await installWireGuard();
|
|
359
|
+
}
|
|
360
|
+
this.installResult = result;
|
|
361
|
+
if (result.available) {
|
|
362
|
+
if (osPlatform() === 'win32') {
|
|
363
|
+
this.backend = new WindowsWireGuardBackend();
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
const unixBackend = new UnixWireGuardBackend();
|
|
367
|
+
// Enable UAPI mode when using wireguard-go (eliminates `wg` CLI dependency)
|
|
368
|
+
if (result.backend === 'wireguard-go') {
|
|
369
|
+
unixBackend.setUapiMode(true);
|
|
370
|
+
}
|
|
371
|
+
this.backend = unixBackend;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return result;
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
378
|
+
logger.error('[WG Manager] Failed to detect/install WireGuard: ' + message);
|
|
379
|
+
this.emit('error', err);
|
|
380
|
+
this.installResult = {
|
|
381
|
+
available: false,
|
|
382
|
+
availability: 'missing_binary',
|
|
383
|
+
backend: 'none',
|
|
384
|
+
};
|
|
385
|
+
return this.installResult;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Set up the WireGuard interface with the agent's virtual IP.
|
|
390
|
+
*/
|
|
391
|
+
async ensureInterface(virtualIp) {
|
|
392
|
+
if (!this.backend) {
|
|
393
|
+
throw new Error('WireGuard backend not initialized. Call ensureInstalled() first.');
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
// Load or generate identity
|
|
397
|
+
this.identity = await this.stateStore.ensureIdentity();
|
|
398
|
+
this.interfaceName = this.identity.interfaceName;
|
|
399
|
+
const config = {
|
|
400
|
+
interfaceName: this.identity.interfaceName,
|
|
401
|
+
virtualIp,
|
|
402
|
+
listenPort: this.identity.listenPort,
|
|
403
|
+
privateKeyPath: this.stateStore.getPrivateKeyPath(),
|
|
404
|
+
privateKeyBase64: this.identity.privateKey,
|
|
405
|
+
};
|
|
406
|
+
await this.backend.ensureInterface(config);
|
|
407
|
+
this.emit('ready');
|
|
408
|
+
logger.info('[WG Manager] Interface ready: ' + this.identity.interfaceName);
|
|
409
|
+
}
|
|
410
|
+
catch (err) {
|
|
411
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
412
|
+
logger.error('[WG Manager] Failed to set up interface: ' + message);
|
|
413
|
+
this.emit('error', err);
|
|
414
|
+
throw err;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Replace all peers (called when server sends full peer list).
|
|
419
|
+
*/
|
|
420
|
+
async setPeers(peers) {
|
|
421
|
+
if (!this.backend || !this.interfaceName) {
|
|
422
|
+
throw new Error('WireGuard interface not initialized.');
|
|
423
|
+
}
|
|
424
|
+
await this.backend.setPeers(this.interfaceName, peers);
|
|
425
|
+
this.connectedPeers = peers.length;
|
|
426
|
+
logger.info('[WG Manager] Set ' + peers.length + ' peers');
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Add a single peer.
|
|
430
|
+
*/
|
|
431
|
+
async addPeer(peer) {
|
|
432
|
+
if (!this.backend || !this.interfaceName) {
|
|
433
|
+
throw new Error('WireGuard interface not initialized.');
|
|
434
|
+
}
|
|
435
|
+
await this.backend.addPeer(this.interfaceName, peer);
|
|
436
|
+
this.connectedPeers++;
|
|
437
|
+
this.emit('peer:added', peer);
|
|
438
|
+
logger.info('[WG Manager] Added peer ' + peer.agentId);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Remove a peer by public key.
|
|
442
|
+
*/
|
|
443
|
+
async removePeer(publicKey) {
|
|
444
|
+
if (!this.backend || !this.interfaceName) {
|
|
445
|
+
throw new Error('WireGuard interface not initialized.');
|
|
446
|
+
}
|
|
447
|
+
await this.backend.removePeer(this.interfaceName, publicKey);
|
|
448
|
+
this.connectedPeers = Math.max(0, this.connectedPeers - 1);
|
|
449
|
+
this.emit('peer:removed', { publicKey });
|
|
450
|
+
logger.info('[WG Manager] Removed peer ' + publicKey.slice(0, 8) + '...');
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Update the endpoint of an existing peer (for NAT traversal hot-update).
|
|
454
|
+
*/
|
|
455
|
+
async updatePeerEndpoint(publicKey, endpoint) {
|
|
456
|
+
if (!this.backend || !this.interfaceName) {
|
|
457
|
+
throw new Error('WireGuard interface not initialized.');
|
|
458
|
+
}
|
|
459
|
+
await this.backend.updatePeerEndpoint(this.interfaceName, publicKey, endpoint);
|
|
460
|
+
logger.info('[WG Manager] Updated endpoint for peer ' + publicKey.slice(0, 8) + '...');
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Rotate the WireGuard keypair. Generates a new key, updates the interface.
|
|
464
|
+
* Returns the new public key.
|
|
465
|
+
*/
|
|
466
|
+
async rotateKey() {
|
|
467
|
+
if (!this.backend || !this.interfaceName) {
|
|
468
|
+
throw new Error('WireGuard interface not initialized.');
|
|
469
|
+
}
|
|
470
|
+
// Rotate keys in the state store
|
|
471
|
+
const newIdentity = await this.stateStore.rotateKeys();
|
|
472
|
+
this.identity = newIdentity;
|
|
473
|
+
// Update the interface with the new private key
|
|
474
|
+
if (this.installResult?.backend === 'wireguard-go') {
|
|
475
|
+
// UAPI mode: pass private key directly to wireguard-go socket
|
|
476
|
+
await uapiSetInterface(this.interfaceName, newIdentity.privateKey, newIdentity.listenPort);
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
// CLI mode: reference private key file
|
|
480
|
+
await execFile('wg', [
|
|
481
|
+
'set', this.interfaceName,
|
|
482
|
+
'private-key', this.stateStore.getPrivateKeyPath(),
|
|
483
|
+
]);
|
|
484
|
+
}
|
|
485
|
+
logger.info('[WG Manager] Key rotated, new pubkey: ' + newIdentity.publicKey.slice(0, 8) + '...');
|
|
486
|
+
return { publicKey: newIdentity.publicKey };
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Update a peer's public key (for key rotation).
|
|
490
|
+
* Removes the old peer and adds with new key, preserving other settings.
|
|
491
|
+
*/
|
|
492
|
+
async updatePeerKey(oldPublicKey, newPublicKey, allowedIps, endpoint) {
|
|
493
|
+
if (!this.backend || !this.interfaceName) {
|
|
494
|
+
throw new Error('WireGuard interface not initialized.');
|
|
495
|
+
}
|
|
496
|
+
// Remove old peer
|
|
497
|
+
await this.backend.removePeer(this.interfaceName, oldPublicKey);
|
|
498
|
+
// Add with new key
|
|
499
|
+
await this.backend.addPeer(this.interfaceName, {
|
|
500
|
+
agentId: '', // not needed for the wg command
|
|
501
|
+
publicKey: newPublicKey,
|
|
502
|
+
allowedIps,
|
|
503
|
+
endpoint,
|
|
504
|
+
persistentKeepalive: 25,
|
|
505
|
+
});
|
|
506
|
+
logger.info('[WG Manager] Updated peer key: ' + oldPublicKey.slice(0, 8) + '... -> ' + newPublicKey.slice(0, 8) + '...');
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Get current manager status for reporting to the server.
|
|
510
|
+
*/
|
|
511
|
+
getStatus() {
|
|
512
|
+
return {
|
|
513
|
+
available: this.installResult?.available ?? false,
|
|
514
|
+
availability: this.installResult?.availability ?? 'missing_binary',
|
|
515
|
+
backend: this.installResult?.backend ?? 'none',
|
|
516
|
+
version: this.installResult?.version,
|
|
517
|
+
interfaceName: this.interfaceName ?? undefined,
|
|
518
|
+
publicKey: this.identity?.publicKey,
|
|
519
|
+
listenPort: this.identity?.listenPort,
|
|
520
|
+
connectedPeers: this.connectedPeers,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Get health snapshot from the running interface.
|
|
525
|
+
*/
|
|
526
|
+
async getHealth() {
|
|
527
|
+
if (!this.backend || !this.interfaceName) {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
try {
|
|
531
|
+
const health = await this.backend.getHealth(this.interfaceName);
|
|
532
|
+
this.emit('health', health);
|
|
533
|
+
return health;
|
|
534
|
+
}
|
|
535
|
+
catch (err) {
|
|
536
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
537
|
+
logger.error('[WG Manager] Health check failed: ' + message);
|
|
538
|
+
return null;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Check if a specific peer has had a recent handshake (within 3 minutes).
|
|
543
|
+
*/
|
|
544
|
+
async isPeerHealthy(publicKey) {
|
|
545
|
+
const health = await this.getHealth();
|
|
546
|
+
if (!health)
|
|
547
|
+
return false;
|
|
548
|
+
const peer = health.peers.find((p) => p.publicKey === publicKey);
|
|
549
|
+
if (!peer || !peer.latestHandshake)
|
|
550
|
+
return false;
|
|
551
|
+
const threeMinutesAgo = Date.now() - 3 * 60 * 1000;
|
|
552
|
+
return peer.latestHandshake.getTime() > threeMinutesAgo;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Tear down the interface and clean up.
|
|
556
|
+
*/
|
|
557
|
+
async shutdown() {
|
|
558
|
+
if (this.backend && this.interfaceName) {
|
|
559
|
+
try {
|
|
560
|
+
await this.backend.teardown(this.interfaceName);
|
|
561
|
+
logger.info('[WG Manager] Shutdown complete');
|
|
562
|
+
}
|
|
563
|
+
catch (err) {
|
|
564
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
565
|
+
logger.error('[WG Manager] Shutdown error: ' + message);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
this.backend = null;
|
|
569
|
+
this.identity = null;
|
|
570
|
+
this.interfaceName = null;
|
|
571
|
+
this.connectedPeers = 0;
|
|
572
|
+
this.emit('shutdown');
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
//# sourceMappingURL=wireguard-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireguard-manager.js","sourceRoot":"","sources":["../../src/network/wireguard-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent WireGuard identity store.
|
|
3
|
+
*
|
|
4
|
+
* Keeps the agent's WG keypair, interface name, and listen port in
|
|
5
|
+
* ~/.termify/wireguard.json so the identity survives restarts.
|
|
6
|
+
*
|
|
7
|
+
* Private key material is NEVER logged. Both the JSON state file and
|
|
8
|
+
* the standalone private key file are created with 0600 permissions.
|
|
9
|
+
*/
|
|
10
|
+
export interface WgIdentity {
|
|
11
|
+
privateKey: string;
|
|
12
|
+
publicKey: string;
|
|
13
|
+
interfaceName: string;
|
|
14
|
+
listenPort: number;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
keyVersion: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generate a WireGuard-compatible X25519 keypair using Node.js built-in crypto.
|
|
20
|
+
* Returns base64-encoded 32-byte keys, identical format to `wg genkey`/`wg pubkey`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateWgKeypair(): {
|
|
23
|
+
privateKey: string;
|
|
24
|
+
publicKey: string;
|
|
25
|
+
};
|
|
26
|
+
export declare class WireGuardStateStore {
|
|
27
|
+
private configDir;
|
|
28
|
+
constructor(configDir?: string);
|
|
29
|
+
/**
|
|
30
|
+
* Load existing identity or generate a new keypair and persist it.
|
|
31
|
+
*/
|
|
32
|
+
ensureIdentity(): Promise<WgIdentity>;
|
|
33
|
+
/**
|
|
34
|
+
* Read the persisted identity, or null if none exists.
|
|
35
|
+
*/
|
|
36
|
+
getIdentity(): Promise<WgIdentity | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Persist the identity to disk with restrictive permissions.
|
|
39
|
+
*/
|
|
40
|
+
saveIdentity(identity: WgIdentity): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Returns the path to the standalone private key file expected by `wg set`.
|
|
43
|
+
*/
|
|
44
|
+
getPrivateKeyPath(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Generate a new keypair, replacing the existing one.
|
|
47
|
+
* Preserves interfaceName and listenPort, increments keyVersion.
|
|
48
|
+
* Returns the new identity.
|
|
49
|
+
*/
|
|
50
|
+
rotateKeys(): Promise<WgIdentity>;
|
|
51
|
+
private ensureConfigDir;
|
|
52
|
+
private writePrivateKeyFile;
|
|
53
|
+
private generateIdentity;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=wireguard-state-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wireguard-state-store.d.ts","sourceRoot":"","sources":["../../src/network/wireguard-state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqBH,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAeD;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAY7E;AAMD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,CAAC,EAAE,MAAM;IAkB9B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;IAgB3C;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAiB/C;;OAEG;IACG,YAAY,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBvD;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC;YAiCzB,eAAe;YAYf,mBAAmB;YAenB,gBAAgB;CAY/B"}
|