256 lines
8.7 KiB
TypeScript
256 lines
8.7 KiB
TypeScript
import * as plugins from '../../plugins.js';
|
|
import type { OpsServer } from '../classes.opsserver.js';
|
|
import * as interfaces from '../../../ts_interfaces/index.js';
|
|
|
|
export class VpnHandler {
|
|
constructor(private opsServerRef: OpsServer) {
|
|
this.registerHandlers();
|
|
}
|
|
|
|
private registerHandlers(): void {
|
|
const viewRouter = this.opsServerRef.viewRouter;
|
|
const adminRouter = this.opsServerRef.adminRouter;
|
|
|
|
// ---- Read endpoints (viewRouter — valid identity required via middleware) ----
|
|
|
|
// Get all registered VPN clients
|
|
viewRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnClients>(
|
|
'getVpnClients',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { clients: [] };
|
|
}
|
|
const clients = manager.listClients().map((c) => ({
|
|
clientId: c.clientId,
|
|
enabled: c.enabled,
|
|
serverDefinedClientTags: c.serverDefinedClientTags,
|
|
description: c.description,
|
|
assignedIp: c.assignedIp,
|
|
createdAt: c.createdAt,
|
|
updatedAt: c.updatedAt,
|
|
expiresAt: c.expiresAt,
|
|
}));
|
|
return { clients };
|
|
},
|
|
),
|
|
);
|
|
|
|
// Get VPN server status
|
|
viewRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnStatus>(
|
|
'getVpnStatus',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
const vpnConfig = this.opsServerRef.dcRouterRef.options.vpnConfig;
|
|
if (!manager) {
|
|
return {
|
|
status: {
|
|
running: false,
|
|
subnet: vpnConfig?.subnet || '10.8.0.0/24',
|
|
wgListenPort: vpnConfig?.wgListenPort ?? 51820,
|
|
serverPublicKeys: null,
|
|
registeredClients: 0,
|
|
connectedClients: 0,
|
|
},
|
|
};
|
|
}
|
|
|
|
const connected = await manager.getConnectedClients();
|
|
return {
|
|
status: {
|
|
running: manager.running,
|
|
subnet: manager.getSubnet(),
|
|
wgListenPort: vpnConfig?.wgListenPort ?? 51820,
|
|
serverPublicKeys: manager.getServerPublicKeys(),
|
|
registeredClients: manager.listClients().length,
|
|
connectedClients: connected.length,
|
|
},
|
|
};
|
|
},
|
|
),
|
|
);
|
|
|
|
// ---- Write endpoints (adminRouter — admin identity required via middleware) ----
|
|
|
|
// Create a new VPN client
|
|
adminRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_CreateVpnClient>(
|
|
'createVpnClient',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
const bundle = await manager.createClient({
|
|
clientId: dataArg.clientId,
|
|
serverDefinedClientTags: dataArg.serverDefinedClientTags,
|
|
description: dataArg.description,
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
client: {
|
|
clientId: bundle.entry.clientId,
|
|
enabled: bundle.entry.enabled ?? true,
|
|
serverDefinedClientTags: bundle.entry.serverDefinedClientTags,
|
|
description: bundle.entry.description,
|
|
assignedIp: bundle.entry.assignedIp,
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
expiresAt: bundle.entry.expiresAt,
|
|
},
|
|
wireguardConfig: bundle.wireguardConfig,
|
|
};
|
|
} 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>(
|
|
'deleteVpnClient',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
await manager.removeClient(dataArg.clientId);
|
|
return { success: true };
|
|
} catch (err: unknown) {
|
|
return { success: false, message: (err as Error).message };
|
|
}
|
|
},
|
|
),
|
|
);
|
|
|
|
// Enable a VPN client
|
|
adminRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_EnableVpnClient>(
|
|
'enableVpnClient',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
await manager.enableClient(dataArg.clientId);
|
|
return { success: true };
|
|
} catch (err: unknown) {
|
|
return { success: false, message: (err as Error).message };
|
|
}
|
|
},
|
|
),
|
|
);
|
|
|
|
// Disable a VPN client
|
|
adminRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_DisableVpnClient>(
|
|
'disableVpnClient',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
await manager.disableClient(dataArg.clientId);
|
|
return { success: true };
|
|
} catch (err: unknown) {
|
|
return { success: false, message: (err as Error).message };
|
|
}
|
|
},
|
|
),
|
|
);
|
|
|
|
// Rotate a VPN client's keys
|
|
adminRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RotateVpnClientKey>(
|
|
'rotateVpnClientKey',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
const bundle = await manager.rotateClientKey(dataArg.clientId);
|
|
return {
|
|
success: true,
|
|
wireguardConfig: bundle.wireguardConfig,
|
|
};
|
|
} catch (err: unknown) {
|
|
return { success: false, message: (err as Error).message };
|
|
}
|
|
},
|
|
),
|
|
);
|
|
|
|
// Export a VPN client config
|
|
adminRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ExportVpnClientConfig>(
|
|
'exportVpnClientConfig',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
const config = await manager.exportClientConfig(dataArg.clientId, dataArg.format);
|
|
return { success: true, config };
|
|
} catch (err: unknown) {
|
|
return { success: false, message: (err as Error).message };
|
|
}
|
|
},
|
|
),
|
|
);
|
|
|
|
// Get telemetry for a specific VPN client
|
|
viewRouter.addTypedHandler(
|
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_GetVpnClientTelemetry>(
|
|
'getVpnClientTelemetry',
|
|
async (dataArg, toolsArg) => {
|
|
const manager = this.opsServerRef.dcRouterRef.vpnManager;
|
|
if (!manager) {
|
|
return { success: false, message: 'VPN not configured' };
|
|
}
|
|
|
|
try {
|
|
const telemetry = await manager.getClientTelemetry(dataArg.clientId);
|
|
if (!telemetry) {
|
|
return { success: false, message: 'Client not found or not connected' };
|
|
}
|
|
return {
|
|
success: true,
|
|
telemetry: {
|
|
clientId: telemetry.clientId,
|
|
assignedIp: telemetry.assignedIp,
|
|
bytesSent: telemetry.bytesSent,
|
|
bytesReceived: telemetry.bytesReceived,
|
|
packetsDropped: telemetry.packetsDropped,
|
|
bytesDropped: telemetry.bytesDropped,
|
|
lastKeepaliveAt: telemetry.lastKeepaliveAt,
|
|
keepalivesReceived: telemetry.keepalivesReceived,
|
|
rateLimitBytesPerSec: telemetry.rateLimitBytesPerSec,
|
|
burstBytes: telemetry.burstBytes,
|
|
},
|
|
};
|
|
} catch (err: unknown) {
|
|
return { success: false, message: (err as Error).message };
|
|
}
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|