UNPKG

node-vpn-manager

Version:

Controls a instance of OpenVpn Client through the manager interface

238 lines (214 loc) 6.33 kB
import Daemon from 'node-vpn-daemon' import * as Telnet from 'telnet-client' import { EventEmitter } from 'events' import * as util from 'util' //import * as _ from 'lodash' const waitMS = util.promisify(setTimeout) class Manager { private sudoPasswd: string private ovpnFile: string private username: string private password: string private Daemon: Daemon private pid: number private state private telnet: any private openVpnEmitter: any private onStateChange: any private onError: any private stateInterval: any private showLog: boolean /** * @constructs Manager * @param sudoPasswd sudo password to run the openvpn command as * @param ovpnFile string with absolute or relative path to the .ovpn file * @param username vpn server authentication username * @param password vpn server authentication password * @param onStateChange */ constructor({ sudoPasswd, ovpnFile = 'test.ovpn', username = 'test', password = 'test', onStateChange = undefined, showLog = false }: { sudoPasswd: string ovpnFile?: string username?: string password?: string status?: string onStateChange?: any showLog?: boolean }) { this.sudoPasswd = sudoPasswd this.showLog = showLog this.ovpnFile = ovpnFile this.username = username this.password = password this.Daemon = undefined this.onStateChange = onStateChange this.telnet = new Telnet() this.openVpnEmitter = new EventEmitter() this.pid = undefined this.stateInterval = 0 } public init = async () => { this.destroyListeners() this.telnet = new Telnet() this.openVpnEmitter = new EventEmitter() this.Daemon = new Daemon({ ovpnFile: this.ovpnFile, sudoPasswd: this.sudoPasswd }) if (await this.Daemon.isRunning()) { await this.Daemon.kill() } return await this.Daemon.start() } public getState = () => { console.log(this.stateInterval) return this.state } private changeState = async (newState: string) => { this.state = newState this.openVpnEmitter.emit('state-change') } private establishManagerConnection = async (params?: { host: string port: number shellPrompt: string timeout: number }) => { this.telnet.connect({ host: '127.0.0.1', port: 1337, shellPrompt: '', timeout: 5000, ...params }) } public clientPid = () => { return this.pid } private managerConnectionReady = async () => { this.streamLog() await this.execute('pid') await this.execute('bytecount 1') await this.execute('log on all') await this.execute('state on') await this.execute('hold release') await this.execute(util.format('username "Auth" "%s"', this.username)) await this.execute(util.format('password "Auth" "%s"', this.password)) } private setState = (state: string) => { if (this.state !== state) { this.changeState(state) } console.log(state) } private destroyListeners = async () => { this.telnet && this.telnet.removeAllListeners && this.telnet.removeAllListeners() this.telnet && this.telnet.hasOwnProperty('end') && this.telnet.end() this.telnet && this.telnet.hasOwnProperty('destroy') && this.telnet.destroy() this.telnet = false this.openVpnEmitter = false } public connect = async () => { this.setListeners() await this.establishManagerConnection() } public disconnect = async () => { await this.execute('signal SIGTERM') await waitMS(1500) } public changeIp = async () => { await this.execute('client-kill ' + this.pid) await waitMS(1500) await this.execute(util.format('username "Auth" "%s"', this.username)) await this.execute(util.format('password "Auth" "%s"', this.password)) } public changeServer = async ( ovpnFile: string, credentials?: { username: string; password: string } ) => { await this.disconnect() if (credentials) { this.username = credentials.username this.password = credentials.password } if (ovpnFile) { this.ovpnFile = ovpnFile } await this.init() await this.connect() } public kill = async () => { await this.execute('signal SIGTERM') } private execute = cmd => { return new Promise((resolve, reject) => { setTimeout(() => { if (this.telnet) { this.telnet.exec(cmd, resolve) } else { reject('no telnet instance') } }, 1000) }) } private setListeners = () => { this.telnet.on('end', () => { this.openVpnEmitter.emit('end') }) this.telnet.on('close', () => { this.openVpnEmitter.emit('close') }) this.telnet.on('error', error => { this.openVpnEmitter.emit('error', error) }) this.telnet.on('ready', this.managerConnectionReady) if (this.onStateChange) { this.openVpnEmitter.on('state-change', () => { this.onStateChange(this.state) }) } if (this.onError) { this.openVpnEmitter.on('error', this.onError) } this.openVpnEmitter.on('pid-set', () => { console.log('pid-set: ' + this.pid) }) } private streamLog = () => { this.telnet.shell().then(stream => { stream.on('data', (data: string) => { const log = data.toString() log.split('\n').forEach((line: string) => { // show log if (this.showLog) { console.log(line) } // get connected client pid if (line.indexOf('pid=') !== -1) { this.pid = parseInt(log.split('pid=')[1].trim()) this.openVpnEmitter.emit('pid-set') } // check if is state log line if (line.indexOf('>STATE:') !== -1) { const state = line .split('>STATE:')[1] .replace('\n', '') .trim() .split(',') //console.log(state) this.setState(state[1]) } }) }) }) } } export default Manager