+ +
++ +
+From 194526857f3795f3f11ffd18bf40cd906f4b2afc Mon Sep 17 00:00:00 2001 From: Casey Erdmann <14339392+3ndG4me@users.noreply.github.com> Date: Tue, 6 Mar 2018 01:10:38 -0500 Subject: [PATCH] Add OpenVPNConnect Module (#11) --- OpenVPNConnect/api/module.php | 214 ++++++++++++++++++++++++++++++++ OpenVPNConnect/js/module.js | 222 ++++++++++++++++++++++++++++++++++ OpenVPNConnect/module.html | 151 +++++++++++++++++++++++ OpenVPNConnect/module.info | 10 ++ 4 files changed, 597 insertions(+) create mode 100644 OpenVPNConnect/api/module.php create mode 100644 OpenVPNConnect/js/module.js create mode 100644 OpenVPNConnect/module.html create mode 100644 OpenVPNConnect/module.info diff --git a/OpenVPNConnect/api/module.php b/OpenVPNConnect/api/module.php new file mode 100644 index 0000000..804a9f9 --- /dev/null +++ b/OpenVPNConnect/api/module.php @@ -0,0 +1,214 @@ +request->action) { + + case 'startVPN': + $this->startVPN(); + break; + case 'stopVPN': + $this->stopVPN(); + break; + case 'initializeModule': + $this->initializeModule(); + break; + case 'handleDependencies': + $this->handleDependencies(); + break; + case 'checkDependencies': + $this->checkDependencies(); + break; + case 'uploadFile': + $this->uploadFile(); + } + } + + + // Checks the dependencies using the pineapple API functions + private function checkDependencies(){ + + if($this->checkDependency('openvpn')){ + $installLabel = 'success'; + $installLabelText = 'Installed'; + }else{ + $installLabel = 'danger'; + $installLabelText = 'Not Installed'; + } + + $this->response = array("success" => true, + "label" => $installLabel, + "text" => $installLabelText); + + } + + // Initializes the module by checking for/creating the required vpn_config directory in /root + private function initializeModule(){ + + $result = exec('cd /root && ls | grep vpn_config'); + + if($result == 'vpn_config'){ + $result = "VPN Connect is ready!"; + }else{ + $this->execBackground('cd /root && mkdir vpn_config'); + + $result = exec('cd /root && ls | grep vpn_config'); + + if($result == 'vpn_config'){ + $result = "VPN Connect is ready!"; + }else{ + $result = "VPN Connect setup failed :("; + } + } + + + //Get Available Certs + + $certs = preg_grep('/^([^.])/', scandir("/root/vpn_config/")); + $cert_arr = array(); + foreach ($certs as $cert){ + array_push($cert_arr, (object)array('name' => $cert)); + } + + $this->response = array("success" => true, + "content" => $result, + "certs" => $cert_arr); + + } + + // Handles dependency installation and removal + private function handleDependencies(){ + + + if($this->checkDependency('openvpn')){ + exec('opkg remove openvpn-openssl'); + $messsage = "Dependencies should now be removed! Note: the vpn_config directory is NOT removed in this process. Please wait for the page to refresh..."; + }else{ + $this->installDependency('openvpn-openssl'); + $messsage = "Depedencies should now be installed! Please wait for the page to refresh..."; + } + + $this->response = array("success" => true, + "content" => $messsage); + } + + // Builds the openvpn command string and calls it to star the VPN + private function startVPN(){ + + $inputData = $this->request->data; + + $open_vpn_cmd = "openvpn --config "; + + if($inputData[0] != ''){ + $config_name = $inputData[0]; + $open_vpn_cmd .= "/root/vpn_config/" . $config_name . " "; + }else{ + $this->response = array("success" => false, + "content" => "Please specify a VPN config name.."); + return; + } + + if($inputData[1] != ''){ + + //Create password file for openvpn command to read in + $config_pass = $inputData[1]; + $pass_file = fopen("/tmp/vpn_pass.txt", "w"); + fwrite($pass_file, $config_pass); + fclose($pass_file); + $open_vpn_cmd .= "--auth-nocache --askpass /tmp/vpn_pass.txt "; + } + + if($inputData[2] != ''){ + $openvpn_flags = $inputData[2]; + $open_vpn_cmd .= $openvpn_flags; + } + + + if($inputData[3] == true){ + //Share VPN With Clients Connecting + $this->execBackground("iptables -t nat -A POSTROUTING -s 172.16.42.0/24 -o tun0 -j MASQUERADE"); + $this->execBackground("iptables -A FORWARD -s 172.16.42.0/24 -o tun0 -j ACCEPT"); + $this->execBackground("iptables -A FORWARD -d 172.16.42.0/24 -m state --state ESTABLISHED,RELATED -i tun0 -j ACCEPT"); + } + + $result = $this->execBackground($open_vpn_cmd); + + $this->response = array("success" => true, + "content" => "VPN Running... "); + } + + + // Calls pkill to kill the OpenVPN process and stop the VPN + private function stopVPN(){ + + //Remove password file that could have been created, don't want any creds lying around ;) + unlink("/tmp/vpn_pass.txt"); + + exec("pkill openvpn"); + + $this->response = array("success" => true, + "content" => "VPN Stopped..."); + } + + // Uploads the .ovnp recieved from the service + private function uploadFile(){ + + $inputData = $this->request->file; + + $fileName = $inputData[0]; + + $file = base64_decode($inputData[1]); + + $response = []; + + $name = $fileName; + $type = pathinfo($fileName, PATHINFO_EXTENSION); + + // Do not accept any file other than .ovpn + if ($type != "ovpn") { + $this->response = array("success" => false); + return; + } + + // Ensure the upload directory exists + if (!file_exists(__UPLOAD__)) { + if (!mkdir(__UPLOAD__, 0755, true)) { + $response[$name] = "Failed. Unable to upload because vpn_certs directory does not exist/could not be created!"; + $this->response = array("success" => false); + return; + } + } + + $uploadPath = __UPLOAD__ . $name; + $res = file_put_contents( $uploadPath, $file ); + + if ($res) { + $response[$name] = true; + } else { + $response[$name] = false; + } + + + $this->response = array("success" => $response[$name]); + + } + + + +} + + + + + + diff --git a/OpenVPNConnect/js/module.js b/OpenVPNConnect/js/module.js new file mode 100644 index 0000000..f337edf --- /dev/null +++ b/OpenVPNConnect/js/module.js @@ -0,0 +1,222 @@ +/* Main AngularJS openVPNConnectController */ +registerController('openVPNConnectController', ['$api', '$scope', '$timeout', '$window', '$http', function($api, $scope, $timeout, $window, $http) { + + + // Workspace Variables. Each value is populated by the form or displays to the form. + $scope.workspace = {config: "", + pass: "", + flags: "", + sharedconnection: false, + setupcontent: "", + outputcontent: "", + availablecerts: [], + uploadstatusLabel: "", + uploadstatus: ""}; + + /* Other variables used to display content or assist the dependency installation and file upload + functions + */ + $scope.content = ""; + $scope.installLabel = "default"; + $scope.installLabelText = "Checking..." + $scope.selectedFiles = []; + $scope.uploading = false; + + // Call a function to install/uninstall dependencies for the module + $scope.handleDependencies = function(){ + + $scope.workspace.setupcontent = "Handling dependencies please wait..."; + + $api.request({ + module: 'OpenVPNConnect', + action: 'handleDependencies', + }, function(response) { + if (response.success === true) { + + $scope.workspace.setupcontent = response.content; + + checkDependencies(); + + $timeout(function() {$window.location.reload();}, 5000); + } + //console.log(response) //Log the response to the console, this is useful for debugging. + }); + + } + + /* Checks the current status of the dependencies for the module and displays + it via the dependency install/uninstall button to the user. + This is checked each time the app is loaded or when the user + installs/uninstalls dependencies manually + */ + var checkDependencies = function(){ + $api.request({ + module: 'OpenVPNConnect', + action: 'checkDependencies', + }, function(response) { + if (response.success === true) { + $scope.installLabel = response.label; + $scope.installLabelText = response.text; + } + //console.log(response) //Log the response to the console, this is useful for debugging. + }); + } + + // Call the checkDependencies function on page load + checkDependencies(); + + /* Initializes module by creating necessary folder structures and scanning for uploaded certs + this function is called each time the app is loaded to make sure the module is set up correctly + */ + var initializeModule = function(){ + $api.request({ + module: 'OpenVPNConnect', + action: 'initializeModule', + }, function(response) { + if (response.success === true) { + $scope.workspace.setupcontent = response.content; + + for(var i = 0; i <= response.certs.length - 1; i++){ + $scope.workspace.availablecerts.push(response.certs[i].name); + } + } + //console.log(response) //Log the response to the console, this is useful for debugging. + }); + } + + // Call the initializeModule function on page load + initializeModule(); + + /* Just calls the initializeModule function to refresh the cert list when the + user clicks the drop down menu button + */ + $scope.refreshCertList = function(){ + $scope.workspace.availablecerts = []; + initializeModule(); + } + + // Sets the current config to use for the VPN connection + $scope.setConfig = function(cert){ + $scope.workspace.config = cert; + } + + + /* Calls the startVPN function, passes all the form params to the API to run the OpenVPN command + Users can pass a config, an option password, and optional command line flags to run with the + openvpn command line utility. Also the shared connection open lets the user share the + VPN connection with its clients + */ + $scope.startVPN = function() { + $api.request({ + module: 'OpenVPNConnect', + action: 'startVPN', + data: [$scope.workspace.config, + $scope.workspace.pass, + $scope.workspace.flags, + $scope.workspace.sharedconnection] + }, function(response) { + if (response.success === true) { + $scope.workspace.outputcontent = response.content; + } + //console.log(response) //Log the response to the console, this is useful for debugging. + }); + } + + // This function calls the API to kill the openvpn process and stop the VPN + $scope.stopVPN = function() { + $api.request({ + module: 'OpenVPNConnect', + action: 'stopVPN' + }, function(response) { + if (response.success === true) { + $scope.workspace.outputcontent = response.content; + } + //console.log(response) //Log the response to the console, this is useful for debugging. + }); + } + + //File Upload Code, the first two functions prep the files for upload in the modal + + $scope.setSelectedFiles = function(){ + files = document.getElementById("selectedFiles").files; + for (var x = 0; x < files.length; x++) { + $scope.selectedFiles.push(files[x]); + } + }; + + $scope.removeSelectedFile = function(file){ + var x = $scope.selectedFiles.length; + while (x--) { + if ($scope.selectedFiles[x] === file) { + $scope.selectedFiles.splice(x,1); + } + } + }; + + /* File upload function. Instaitates a FileReader object the makes a promise call to + doUpload once the async reader call is complete on each iteration + */ + $scope.uploadFile = function(){ + + $scope.uploading = true; + + + for (x = 0; x < $scope.selectedFiles.length; x++) { + + var fileReader = new FileReader(); + + var fileName = $scope.selectedFiles[x].name; + + var filesToUpload = $scope.selectedFiles.length; + + readFile($scope.selectedFiles[x], fileName, filesToUpload); + + } + }; + + + // Read file function to handle a Promise for multiple file uploads using FilerReader + function readFile(file, file_name, files_to_upload){ + return new Promise((resolve, reject) => { + var fr = new FileReader(); + fr.onload = () => { + final_file = fr.result.split(',')[1] + resolve(doUpload(file_name, final_file, files_to_upload - 1)); + }; + fr.readAsDataURL(file); + }); + } + + + /* Actually performs the upload request to the API. Passes the file name and a base64 encoded + file to be uploaded by the service + */ + var doUpload = function(file_name, file, files_to_upload){ + + $api.request({ + module: 'OpenVPNConnect', + action: 'uploadFile', + file: [file_name, + file + ] + }, function(response) { + + if(response.success){ + $scope.workspace.uploadstatusLabel = "Upload Success!"; + $scope.workspace.uploadstatus = "success"; + }else{ + $scope.workspace.uploadstatusLabel = "One or more files failed to upload!"; + $scope.workspace.uploadstatus = "danger"; + } + + if(files_to_upload === 0){ + $scope.selectedFiles = []; + $scope.uploading = false; + } + + //console.log(response) //Log the response to the console, this is useful for debugging. + }); + + }; + +}]); \ No newline at end of file diff --git a/OpenVPNConnect/module.html b/OpenVPNConnect/module.html new file mode 100644 index 0000000..4a07d8c --- /dev/null +++ b/OpenVPNConnect/module.html @@ -0,0 +1,151 @@ +
+ +
++ +
+