127 lines
3.1 KiB
TypeScript
127 lines
3.1 KiB
TypeScript
import * as plugins from './smartvpn.plugins.js';
|
|
import type { TVpnPlatform, IVpnServiceUnit } from './smartvpn.interfaces.js';
|
|
|
|
/**
|
|
* Install the smartvpn daemon as a system service.
|
|
*/
|
|
export class VpnInstaller {
|
|
/**
|
|
* Detect the current platform.
|
|
*/
|
|
public static detectPlatform(): TVpnPlatform {
|
|
switch (process.platform) {
|
|
case 'linux':
|
|
return 'linux';
|
|
case 'darwin':
|
|
return 'macos';
|
|
case 'win32':
|
|
return 'windows';
|
|
default:
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate a systemd unit file for Linux.
|
|
*/
|
|
public static generateSystemdUnit(options: {
|
|
binaryPath: string;
|
|
socketPath: string;
|
|
mode: 'client' | 'server';
|
|
configPath?: string;
|
|
description?: string;
|
|
}): IVpnServiceUnit {
|
|
const desc = options.description || `SmartVPN ${options.mode} daemon`;
|
|
const content = `[Unit]
|
|
Description=${desc}
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=${options.binaryPath} --management-socket ${options.socketPath} --mode ${options.mode}
|
|
Restart=always
|
|
RestartSec=5
|
|
LimitNOFILE=65535
|
|
|
|
# Security hardening
|
|
NoNewPrivileges=no
|
|
ProtectSystem=strict
|
|
ProtectHome=yes
|
|
ReadWritePaths=/var/run /dev/net/tun
|
|
PrivateTmp=yes
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
`;
|
|
|
|
return {
|
|
platform: 'linux',
|
|
content,
|
|
installPath: `/etc/systemd/system/smartvpn-${options.mode}.service`,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate a launchd plist for macOS.
|
|
*/
|
|
public static generateLaunchdPlist(options: {
|
|
binaryPath: string;
|
|
socketPath: string;
|
|
mode: 'client' | 'server';
|
|
description?: string;
|
|
}): IVpnServiceUnit {
|
|
const label = `rocks.push.smartvpn.${options.mode}`;
|
|
const content = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>Label</key>
|
|
<string>${label}</string>
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
<string>${options.binaryPath}</string>
|
|
<string>--management-socket</string>
|
|
<string>${options.socketPath}</string>
|
|
<string>--mode</string>
|
|
<string>${options.mode}</string>
|
|
</array>
|
|
<key>RunAtLoad</key>
|
|
<true/>
|
|
<key>KeepAlive</key>
|
|
<true/>
|
|
<key>StandardErrorPath</key>
|
|
<string>/var/log/smartvpn-${options.mode}.err.log</string>
|
|
<key>StandardOutPath</key>
|
|
<string>/var/log/smartvpn-${options.mode}.out.log</string>
|
|
</dict>
|
|
</plist>
|
|
`;
|
|
|
|
return {
|
|
platform: 'macos',
|
|
content,
|
|
installPath: `/Library/LaunchDaemons/${label}.plist`,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate the appropriate service unit for the current platform.
|
|
*/
|
|
public static generateServiceUnit(options: {
|
|
binaryPath: string;
|
|
socketPath: string;
|
|
mode: 'client' | 'server';
|
|
}): IVpnServiceUnit {
|
|
const platform = VpnInstaller.detectPlatform();
|
|
switch (platform) {
|
|
case 'linux':
|
|
return VpnInstaller.generateSystemdUnit(options);
|
|
case 'macos':
|
|
return VpnInstaller.generateLaunchdPlist(options);
|
|
default:
|
|
throw new Error(`VpnInstaller: unsupported platform: ${platform}`);
|
|
}
|
|
}
|
|
}
|