initial
This commit is contained in:
126
ts/smartvpn.classes.vpninstaller.ts
Normal file
126
ts/smartvpn.classes.vpninstaller.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user