mirror of
https://github.com/hak5/nano-tetra-modules.git
synced 2025-10-29 16:58:09 +00:00
Add OpenVPNConnect Module (#11)
This commit is contained in:
parent
abe6d3060c
commit
194526857f
214
OpenVPNConnect/api/module.php
Normal file
214
OpenVPNConnect/api/module.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
// Define the pineapple namespace
|
||||
namespace pineapple;
|
||||
|
||||
// Upload Directory where we store vpn_configs
|
||||
define('__UPLOAD__', "/root/vpn_config/");
|
||||
|
||||
/* Main module class for OpenVPNConnect */
|
||||
class OpenVPNConnect extends Module{
|
||||
|
||||
// Set up our routes for our angular functions to call
|
||||
public function route(){
|
||||
|
||||
switch ($this->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]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
222
OpenVPNConnect/js/module.js
Normal file
222
OpenVPNConnect/js/module.js
Normal file
@ -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.
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}]);
|
||||
151
OpenVPNConnect/module.html
Normal file
151
OpenVPNConnect/module.html
Normal file
@ -0,0 +1,151 @@
|
||||
<div class="col-md-12" ng-controller="openVPNConnectController">
|
||||
<div class="panel-group">
|
||||
<div class="col-md-12">
|
||||
<!-- OpenVPN Connect Title Panel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-header text-muted text-center">
|
||||
<h3>OpenVPN Connect
|
||||
</h5>
|
||||
</div>
|
||||
<div id="main-panel" class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<!-- Dependency Installer UI -->
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label text-center">Dependencies:</label>
|
||||
<button type="button" style="width: 90px;" class="btn btn-{{installLabel}} btn-xs" ng-click="handleDependencies()">{{installLabelText}}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label text-center">Setup Status</label>
|
||||
<p>
|
||||
<input class="form-control" ng-model="workspace.setupcontent" placeholder="" readonly></input>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenVPN Cert Selector -->
|
||||
<div class="panel-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<p>
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#ovpn_upload_view">Upload Cert</button>
|
||||
</p>
|
||||
<p>
|
||||
<div>
|
||||
<label class="control-label">
|
||||
<a href="javascript:;" data-toggle="collapse" data-parent="#accordion" data-target="#collapseCertList">
|
||||
<button type="button" class="btn btn-default" ng-click="refreshCertList()">
|
||||
Select Cert +
|
||||
</button>
|
||||
</a>
|
||||
</label>
|
||||
<div id="collapseCertList" class="panel-collapse collapse">
|
||||
<div class="panel panel-default">
|
||||
<div>
|
||||
<ul class="list-group text-center" ng-repeat="cert in workspace.availablecerts">
|
||||
<li class="list-group-item">
|
||||
<button type="button" class="btn btn-default" ng-click="setConfig(cert)">{{cert}}</button>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<!-- OpenVPN Connect Option Form -->
|
||||
<label class="control-label text-center">VPN Config Name:</label>
|
||||
<a href="javascript:;" ng-click="workspace.config = ''">Clear</a>
|
||||
<p>
|
||||
<input class="form-control" ng-model="workspace.config" placeholder="Enter input"></input>
|
||||
</p>
|
||||
<label class="control-label text-center">VPN Config Password (Optional):</label>
|
||||
<a href="javascript:;" ng-click="workspace.pass = ''">Clear</a>
|
||||
<p>
|
||||
<input class="form-control" type="password" ng-model="workspace.pass" placeholder="Enter input"></input>
|
||||
</p>
|
||||
<label class="control-label text-center">OpenVPN Flags (Optional):</label>
|
||||
<a href="javascript:;" ng-click="workspace.flags = ''">Clear</a>
|
||||
<p>
|
||||
<input class="form-control" ng-model="workspace.flags" placeholder="Enter input"></input>
|
||||
</p>
|
||||
<label class="control-label text-center">Share Connection With Clients:</label>
|
||||
<input type="checkbox" ng-model="workspace.sharedconnection">
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn text-center">
|
||||
<button class="btn btn-default" type="button" ng-click="startVPN()">Start VPN</button>
|
||||
<button class="btn btn-default" type="button" ng-click="stopVPN()">Stop VPN</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- OpenVPN Status Section -->
|
||||
<div class="panel-body">
|
||||
<div class="form-group">
|
||||
<label class="control-label text-center">OpenVPN Status</label>
|
||||
<p>
|
||||
<textarea class="form-control" rows="1" ng-model="workspace.outputcontent" placeholder="" readonly></textarea>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- OpenVPN Cert Upload Modal -->
|
||||
<div id="ovpn_upload_view" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<div class="btn btn-primary">
|
||||
<label for="selectedFiles" style="cursor: pointer">Add files</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>File</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="file in selectedFiles">
|
||||
<td>{{ file.name }}</td>
|
||||
<td>
|
||||
<button class="btn btn-danger" ng-click="removeSelectedFile(file);">Remove
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="text-align:center">
|
||||
<input type="file" accept=".ovpn" id="selectedFiles" onchange="angular.element(this).scope().setSelectedFiles()" style="visibility: hidden;" multiple>
|
||||
<img ng-show="uploading" ng-hide="!uploading">
|
||||
<button class="btn" ng-show="!uploading" ng-hide="uploading" ng-disabled="selectedFiles.length == 0" ng-click="uploadFile();">Upload</button>
|
||||
<div class="alert alert-{{workspace.uploadstatus}}">{{workspace.uploadstatusLabel}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Change Log Pannel -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-header text-muted text-center">
|
||||
<h5>
|
||||
<a href="javascript:;" data-toggle="collapse" data-parent="#accordion" data-target="#collapseChangelog">Change Log</a>
|
||||
</h5>
|
||||
</div>
|
||||
<div id="collapseChangelog" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
<ul>
|
||||
<li>
|
||||
<b>1.0</b>
|
||||
</li>
|
||||
<ul>
|
||||
<li class="text-muted">Initial Pineapple Nano Release</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
10
OpenVPNConnect/module.info
Normal file
10
OpenVPNConnect/module.info
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"author": "3ndG4me",
|
||||
"description": "OpenVPN Connection Utility",
|
||||
"devices": [
|
||||
"nano",
|
||||
"tetra"
|
||||
],
|
||||
"title": "OpenVPNConnect",
|
||||
"version": "1.0"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user