feat(vpn): add VPN client editing and connected client visibility in ops server

This commit is contained in:
2026-03-31 09:53:37 +00:00
parent cfb727b86d
commit 11ca64a1cd
14 changed files with 447 additions and 30 deletions

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@serve.zone/dcrouter',
version: '11.21.5',
version: '11.22.0',
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
}

View File

@@ -72,6 +72,31 @@ export class VpnHandler {
),
);
// Get currently connected VPN clients
viewRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnConnectedClients>(
'getVpnConnectedClients',
async (dataArg, toolsArg) => {
const manager = this.opsServerRef.dcRouterRef.vpnManager;
if (!manager) {
return { connectedClients: [] };
}
const connected = await manager.getConnectedClients();
return {
connectedClients: connected.map((c) => ({
clientId: c.registeredClientId || c.clientId,
assignedIp: c.assignedIp,
connectedSince: c.connectedSince,
bytesSent: c.bytesSent,
bytesReceived: c.bytesReceived,
transport: c.transportType,
})),
};
},
),
);
// ---- Write endpoints (adminRouter — admin identity required via middleware) ----
// Create a new VPN client
@@ -112,6 +137,29 @@ export class VpnHandler {
),
);
// Update a VPN client's metadata
adminRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_UpdateVpnClient>(
'updateVpnClient',
async (dataArg, toolsArg) => {
const manager = this.opsServerRef.dcRouterRef.vpnManager;
if (!manager) {
return { success: false, message: 'VPN not configured' };
}
try {
await manager.updateClient(dataArg.clientId, {
description: dataArg.description,
serverDefinedClientTags: dataArg.serverDefinedClientTags,
});
return { success: true };
} catch (err: unknown) {
return { success: false, message: (err as Error).message };
}
},
),
);
// Delete a VPN client
adminRouter.addTypedHandler(
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DeleteVpnClient>(

View File

@@ -275,6 +275,22 @@ export class VpnManager {
this.config.onClientChanged?.();
}
/**
* Update a client's metadata (description, tags) without rotating keys.
*/
public async updateClient(clientId: string, update: {
description?: string;
serverDefinedClientTags?: string[];
}): Promise<void> {
const client = this.clients.get(clientId);
if (!client) throw new Error(`Client not found: ${clientId}`);
if (update.description !== undefined) client.description = update.description;
if (update.serverDefinedClientTags !== undefined) client.serverDefinedClientTags = update.serverDefinedClientTags;
client.updatedAt = Date.now();
await this.persistClient(client);
this.config.onClientChanged?.();
}
/**
* Rotate a client's keys. Returns the new config bundle.
*/