fix(vpn-manager): persist WireGuard private keys for valid client exports and QR codes
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '11.20.0',
|
||||
version: '11.20.1',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ interface IPersistedClient {
|
||||
assignedIp?: string;
|
||||
noisePublicKey: string;
|
||||
wgPublicKey: string;
|
||||
/** WireGuard private key — stored so exports and QR codes produce valid configs */
|
||||
wgPrivateKey?: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
expiresAt?: string;
|
||||
@@ -188,7 +190,7 @@ export class VpnManager {
|
||||
description: opts.description,
|
||||
});
|
||||
|
||||
// Persist client entry (without private keys)
|
||||
// Persist client entry (including WG private key for export/QR)
|
||||
const persisted: IPersistedClient = {
|
||||
clientId: bundle.entry.clientId,
|
||||
enabled: bundle.entry.enabled ?? true,
|
||||
@@ -197,6 +199,7 @@ export class VpnManager {
|
||||
assignedIp: bundle.entry.assignedIp,
|
||||
noisePublicKey: bundle.entry.publicKey,
|
||||
wgPublicKey: bundle.entry.wgPublicKey || '',
|
||||
wgPrivateKey: bundle.secrets?.wgPrivateKey,
|
||||
createdAt: Date.now(),
|
||||
updatedAt: Date.now(),
|
||||
expiresAt: bundle.entry.expiresAt,
|
||||
@@ -265,11 +268,12 @@ export class VpnManager {
|
||||
if (!this.vpnServer) throw new Error('VPN server not running');
|
||||
const bundle = await this.vpnServer.rotateClientKey(clientId);
|
||||
|
||||
// Update persisted entry with new public keys
|
||||
// Update persisted entry with new keys (including private key for export/QR)
|
||||
const client = this.clients.get(clientId);
|
||||
if (client) {
|
||||
client.noisePublicKey = bundle.entry.publicKey;
|
||||
client.wgPublicKey = bundle.entry.wgPublicKey || '';
|
||||
client.wgPrivateKey = bundle.secrets?.wgPrivateKey;
|
||||
client.updatedAt = Date.now();
|
||||
await this.persistClient(client);
|
||||
}
|
||||
@@ -278,11 +282,24 @@ export class VpnManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a client config (without secrets).
|
||||
* Export a client config. Injects the stored WG private key for complete configs.
|
||||
*/
|
||||
public async exportClientConfig(clientId: string, format: 'smartvpn' | 'wireguard'): Promise<string> {
|
||||
if (!this.vpnServer) throw new Error('VPN server not running');
|
||||
return this.vpnServer.exportClientConfig(clientId, format);
|
||||
let config = await this.vpnServer.exportClientConfig(clientId, format);
|
||||
|
||||
// Inject stored WG private key so exports produce valid, scannable configs
|
||||
if (format === 'wireguard') {
|
||||
const persisted = this.clients.get(clientId);
|
||||
if (persisted?.wgPrivateKey) {
|
||||
config = config.replace(
|
||||
'[Interface]\n',
|
||||
`[Interface]\nPrivateKey = ${persisted.wgPrivateKey}\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// ── Tag-based access control ───────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user