From 018aaa3fb76ff2a0e52a173fbca5c55f157210e4 Mon Sep 17 00:00:00 2001 From: charleswrayjr Date: Tue, 9 Sep 2025 08:40:44 -0500 Subject: [PATCH] Adding available clients to VPN. --- app.js | 2 ++ src/controllers/vpn.controller.js | 58 +++++++++++++++++++++++++++++++ src/routes/vpn.routes.js | 3 ++ 3 files changed, 63 insertions(+) diff --git a/app.js b/app.js index 2e0e761..2a6dca8 100755 --- a/app.js +++ b/app.js @@ -12,6 +12,7 @@ const runOnce = require ( './src/middleware/custom-startup' ); const Routes = require( './src/routes' ); const phsdb = require( './src/phsdb' ); const fs = require('fs'); +const path = require('path'); const Docker = require('dockerode'); const docker = new Docker({ socketPath: '/var/run/docker.sock' }); const sshConfig = { @@ -36,6 +37,7 @@ global.fs = fs; global.sshConfig = sshConfig; global.docker = docker; global.createError = createError; +global.path = path; // noinspection JSCheckFunctionSignatures app.use( bodyParser.json( { diff --git a/src/controllers/vpn.controller.js b/src/controllers/vpn.controller.js index 95c5073..a4d755a 100644 --- a/src/controllers/vpn.controller.js +++ b/src/controllers/vpn.controller.js @@ -143,6 +143,64 @@ module.exports = { next( error ); } ).connect( sshConfig ); }, + getAvailableClients: async ( req, res, next ) => { + const conn = new Client(); + conn.on( 'ready', () => { + const commands = [ + `ls /etc/openvpn/ccd 2>/dev/null || true`, + `ls /etc/openvpn/easy-rsa/pki/issued/*.crt 2>/dev/null || true`, + ]; + conn.exec( commands.join( ' && ' ), ( err, stream ) => { + if (err) { + conn.end(); + const error = new createError( 500, `SSH command failed` ); + next( error ); + } + let output = ''; + stream.on('data', (data) => (output += data)); + stream.stderr.on('data', (data) => (output += data)); + stream.on('close', async (code) => { + conn.end(); + if (code !== 0) { + return next(new createError(500, `Command failed: ${output}`)); + } + const clients = []; + const ccdFiles = output.split('\n').filter(line => line.endsWith('.ccd')); + const crtFiles = output.split('\n').filter(line => line.endsWith('.crt')); + + // Process .ccd files for static IPs + for (const ccdFile of ccdFiles) { + const clientName = path.basename( ccdFile, '.ccd' ); + try { + const ccdContent = fs.readFileSync( ccdFile, 'utf8' ); + const staticIpMatch = ccdContent.match( /ifconfig-push (\S+)/ ); + clients.push( { + clientName, + staticIp:staticIpMatch ? staticIpMatch[1] : null, + hasCertificate:crtFiles.some( crt => crt.includes( `${ clientName }.crt` ) ), + } ); + } catch (error) { + logger.warn( `Failed to read ${ ccdFile }: ${ error.message }` ); + } + }// Add clients with certificates but no .ccd + for (const crtFile of crtFiles) { + const clientName = path.basename( crtFile, '.crt' ); + if (!clients.some( client => client.clientName === clientName )) { + clients.push( { + clientName, + staticIp:null, + hasCertificate:true, + } ); + } + } + res.json( { clients } ); + }); + } ); + } ).on( 'error', ( err ) => { + const error = new createError( 500, `SSH connection failed: ${ err.message }` ); + next( error ); + } ).connect( sshConfig ) + }, getClients:async ( req, res, next ) => { const conn = new Client(); conn.on( 'ready', () => { diff --git a/src/routes/vpn.routes.js b/src/routes/vpn.routes.js index 4626e15..f4bf5db 100644 --- a/src/routes/vpn.routes.js +++ b/src/routes/vpn.routes.js @@ -4,8 +4,11 @@ const { validateAuth } = require( '../middleware/routeHelpers' ); const vpnController = require( '../controllers/vpn.controller' ); module.exports = ( passport ) => { + router.post( '/create-client', vpnController.createClient ); router.put( '/revoke-client/', vpnController.revokeClient ); router.get( '/clients', vpnController.getClients ); + router.get( '/available-clients', vpnController.getAvailableClients ); + return router; }; \ No newline at end of file -- 2.43.0