Merge pull request #45 from RaspAP/feature/wg-extended

Extend WG functionality
This commit is contained in:
Bill Zimmerman 2021-07-13 14:03:35 +02:00 committed by GitHub
commit 78c4dff40b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 779 additions and 114 deletions

View file

@ -307,7 +307,6 @@ $('#ovpn-confirm-activate').on('shown.bs.modal', function (e) {
}); });
$('#ovpn-userpw,#ovpn-certs').on('click', function (e) { $('#ovpn-userpw,#ovpn-certs').on('click', function (e) {
// e.stopPropagation();
if (this.id == 'ovpn-userpw') { if (this.id == 'ovpn-userpw') {
$('#PanelCerts').hide(); $('#PanelCerts').hide();
$('#PanelUserPW').show(); $('#PanelUserPW').show();
@ -317,6 +316,20 @@ $('#ovpn-userpw,#ovpn-certs').on('click', function (e) {
} }
}); });
$(document).ready(function(){
$("#PanelManual").hide();
});
$('#wg-upload,#wg-manual').on('click', function (e) {
if (this.id == 'wg-upload') {
$('#PanelManual').hide();
$('#PanelUpload').show();
} else if (this.id == 'wg-manual') {
$('#PanelUpload').hide();
$('#PanelManual').show();
}
});
// Add the following code if you want the name of the file appear on select // Add the following code if you want the name of the file appear on select
$(".custom-file-input").on("change", function() { $(".custom-file-input").on("change", function() {
var fileName = $(this).val().split("\\").pop(); var fileName = $(this).val().split("\\").pop();

505
app/lib/uploader.php Normal file
View file

@ -0,0 +1,505 @@
<?php
/**
* Simple PHP upload class
*
* Adapted from aivis/PHP-file-upload-class
*
* @description File upload class for RaspAP
* @author Bill Zimmerman <billzimmerman@gmail.com>
* @author Aivis Silins
* @link https://github.com/aivis/PHP-file-upload-class
* @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE
*/
namespace RaspAP\Uploader;
class Upload
{
/**
* Default directory persmissions (destination)
*/
protected $default_permissions = 0750;
/**
* File post array
*
* @var array
*/
protected $file_post = array();
/**
* Destination directory
*
* @var string
*/
protected $destination;
/**
* Fileinfo
*
* @var object
*/
protected $finfo;
/**
* Data about file
*
* @var array
*/
public $file = array();
/**
* Max. file size
*
* @var int
*/
protected $max_file_size;
/**
* Allowed mime types
*
* @var array
*/
protected $mimes = array();
/**
* Temp path
*
* @var string
*/
protected $tmp_name;
/**
* Validation errors
*
* @var array
*/
protected $validation_errors = array();
/**
* Filename (new)
*
* @var string
*/
protected $filename;
/**
* Internal callbacks (filesize check, mime, etc)
*
* @var array
*/
private $callbacks = array();
/**
* Root dir
*
* @var string
*/
protected $root;
/**
* Return upload object
*
* $destination = 'path/to/file/destination/';
*
* @param string $destination
* @param string $root
* @return Upload
*/
public static function factory($destination, $root = false)
{
return new Upload($destination, $root);
}
/**
* Define root constant and set & create destination path
*
* @param string $destination
* @param string $root
*/
public function __construct($destination, $root = false)
{
if ($root) {
$this->root = $root;
} else {
$this->root = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR;
}
// set & create destination path
if (!$this->set_destination($destination)) {
throw new Exception('Upload: Unable to create destination. '.$this->root . $this->destination);
}
//create finfo object
$this->finfo = new \finfo();
}
/**
* Set target filename
*
* @param string $filename
*/
public function set_filename($filename)
{
$this->filename = $filename;
}
/**
* Check & Save file
*
* Return data about current upload
*
* @return array
*/
public function upload($filename = false)
{
if($filename ) {
$this->set_filename($filename);
}
$this->set_filename($filename);
if ($this->check()) {
$this->save();
}
// return state data
return $this->get_state();
}
/**
* Save file on server
* Return state data
*
* @return array
*/
public function save()
{
$this->save_file();
return $this->get_state();
}
/**
* Validate file (execute callbacks)
* Returns TRUE if validation successful
*
* @return bool
*/
public function check()
{
//execute callbacks (check filesize, mime, also external callbacks
$this->validate();
//add error messages
$this->file['errors'] = $this->get_errors();
//change file validation status
$this->file['status'] = empty($this->validation_errors);
return $this->file['status'];
}
/**
* Get current state data
*
* @return array
*/
public function get_state()
{
return $this->file;
}
/**
* Save file on server
*/
protected function save_file()
{
//create & set new filename
if(empty($this->filename)) {
$this->create_new_filename();
}
//set filename
$this->file['filename'] = $this->filename;
//set full path
$this->file['full_path'] = $this->root . $this->destination . $this->filename;
$this->file['path'] = $this->destination . $this->filename;
$status = move_uploaded_file($this->tmp_name, $this->file['full_path']);
//checks whether upload successful
if (!$status) {
throw new Exception('Upload: Failed to upload file.');
}
//done
$this->file['status'] = true;
}
/**
* Set data about file
*/
protected function set_file_data()
{
$file_size = $this->get_file_size();
$this->file = array(
'status' => false,
'destination' => $this->destination,
'size_in_bytes' => $file_size,
'size_in_mb' => $this->bytes_to_mb($file_size),
'mime' => $this->get_file_mime(),
'filename' => $this->file_post['name'],
'tmp_name' => $this->file_post['tmp_name'],
'post_data' => $this->file_post,
);
}
/**
* Set validation error
*
* @param string $message
*/
public function set_error($message)
{
$this->validation_errors[] = $message;
}
/**
* Return validation errors
*
* @return array
*/
public function get_errors()
{
return $this->validation_errors;
}
/**
* Set external callback methods
*
* @param object $instance_of_callback_object
* @param array $callback_methods
*/
public function callbacks($instance_of_callback_object, $callback_methods)
{
if (empty($instance_of_callback_object)) {
throw new Exception('Upload: $instance_of_callback_object cannot be empty.');
}
if (!is_array($callback_methods)) {
throw new Exception('Upload: $callback_methods data type need to be array.');
}
$this->external_callback_object = $instance_of_callback_object;
$this->external_callback_methods = $callback_methods;
}
/**
* Execute callbacks
*/
protected function validate()
{
//get curent errors
$errors = $this->get_errors();
if (empty($errors)) {
//set data about current file
$this->set_file_data();
//execute internal callbacks
$this->execute_callbacks($this->callbacks, $this);
//execute external callbacks
$this->execute_callbacks($this->external_callback_methods, $this->external_callback_object);
}
}
/**
* Execute callbacks
*/
protected function execute_callbacks($callbacks, $object)
{
foreach($callbacks as $method) {
$object->$method($this);
}
}
/**
* File mime type validation callback
*
* @param object $object
*/
protected function check_mime_type($object)
{
if (!empty($object->mimes)) {
if (!in_array($object->file['mime'], $object->mimes)) {
$object->set_error('Mime type not allowed.');
}
}
}
/**
* Set allowed mime types
*
* @param array $mimes
*/
public function set_allowed_mime_types($mimes)
{
$this->mimes = $mimes;
//if mime types is set -> set callback
$this->callbacks[] = 'check_mime_type';
}
/**
* File size validation callback
*
* @param object $object
*/
protected function check_file_size($object)
{
if (!empty($object->max_file_size)) {
$file_size_in_mb = $this->bytes_to_mb($object->file['size_in_bytes']);
if ($object->max_file_size <= $file_size_in_mb) {
$object->set_error('File exceeds maximum allowed size.');
}
}
}
/**
* Set max file size
*
* @param int $size
*/
public function set_max_file_size($size)
{
$this->max_file_size = $size;
//if max file size is set -> set callback
$this->callbacks[] = 'check_file_size';
}
/**
* Set File array to object
*
* @param array $file
*/
public function file($file)
{
$this->set_file_array($file);
}
/**
* Set file array
*
* @param array $file
*/
protected function set_file_array($file)
{
//checks whether file array is valid
if (!$this->check_file_array($file)) {
//file not selected or some bigger problems (broken files array)
$this->set_error('Please select file.');
}
//set file data
$this->file_post = $file;
//set tmp path
$this->tmp_name = $file['tmp_name'];
}
/**
* Checks whether Files post array is valid
*
* @return bool
*/
protected function check_file_array($file)
{
return isset($file['error'])
&& !empty($file['name'])
&& !empty($file['type'])
&& !empty($file['tmp_name'])
&& !empty($file['size']);
}
/**
* Get file mime type
*
* @return string
*/
protected function get_file_mime()
{
return $this->finfo->file($this->tmp_name, FILEINFO_MIME_TYPE);
}
/**
* Get file size
*
* @return int
*/
protected function get_file_size()
{
return filesize($this->tmp_name);
}
/**
* Set destination path (return TRUE on success)
*
* @param string $destination
* @return bool
*/
protected function set_destination($destination)
{
$this->destination = $destination . DIRECTORY_SEPARATOR;
return $this->destination_exist() ? true : $this->create_destination();
}
/**
* Checks whether destination folder exists
*
* @return bool
*/
protected function destination_exist()
{
return is_writable($this->root . $this->destination);
}
/**
* Create path to destination
*
* @param string $dir
* @return bool
*/
protected function create_destination()
{
return mkdir($this->root . $this->destination, $this->default_permissions, true);
}
/**
* Set unique filename
*
* @return string
*/
protected function create_new_filename()
{
$filename = sha1(mt_rand(1, 9999) . $this->destination . uniqid()) . time();
$this->set_filename($filename);
}
/**
* Convert bytes to MB
*
* @param int $bytes
* @return int
*/
protected function bytes_to_mb($bytes)
{
return round(($bytes / 1048576), 2);
}
}

View file

@ -721,13 +721,15 @@ function validateCidr($cidr)
} }
// Validates a host or FQDN // Validates a host or FQDN
function validate_host($host) { function validate_host($host)
{
return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host); return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host);
} }
// Gets night mode toggle value // Gets night mode toggle value
// @return boolean // @return boolean
function getNightmode(){ function getNightmode()
{
if ($_COOKIE['theme'] == 'lightsout.css') { if ($_COOKIE['theme'] == 'lightsout.css') {
return true; return true;
} else { } else {
@ -736,7 +738,8 @@ function getNightmode(){
} }
// search array for matching string and return only first matching group // search array for matching string and return only first matching group
function preg_only_match($pat,$haystack) { function preg_only_match($pat,$haystack)
{
$match = ""; $match = "";
if(!empty($haystack) && !empty($pat)) { if(!empty($haystack) && !empty($pat)) {
if(!is_array($haystack)) $haystack = array($haystack); if(!is_array($haystack)) $haystack = array($haystack);
@ -754,10 +757,34 @@ function qr_encode($str)
return preg_replace('/(?<!\\\)([\":;,])/', '\\\\\1', $str); return preg_replace('/(?<!\\\)([\":;,])/', '\\\\\1', $str);
} }
function evalHexSequence($string) { function evalHexSequence($string)
{
$evaluator = function ($input) { $evaluator = function ($input) {
return hex2bin($input[1]); return hex2bin($input[1]);
}; };
return preg_replace_callback('/\\\x(..)/', $evaluator, $string); return preg_replace_callback('/\\\x(..)/', $evaluator, $string);
} }
/* File upload callback object
*
*/
class validation
{
public function check_name_length($object)
{
if (strlen($object->file['filename']) > 255) {
$object->set_error('File name is too long.');
}
}
}
/* Resolves public IP address
*
* @return string $public_ip
*/
function get_public_ip()
{
exec('wget https://ipinfo.io/ip -qO -', $public_ip);
return $public_ip[0];
}

View file

@ -3,6 +3,7 @@
require_once 'includes/status_messages.php'; require_once 'includes/status_messages.php';
require_once 'includes/config.php'; require_once 'includes/config.php';
require_once 'includes/wifi_functions.php'; require_once 'includes/wifi_functions.php';
require_once 'app/lib/uploader.php';
getWifiInterface(); getWifiInterface();
@ -41,11 +42,9 @@ function DisplayOpenVPNConfig()
} }
exec('pidof openvpn | wc -l', $openvpnstatus); exec('pidof openvpn | wc -l', $openvpnstatus);
exec('wget https://ipinfo.io/ip -qO -', $return);
$serviceStatus = $openvpnstatus[0] == 0 ? "down" : "up"; $serviceStatus = $openvpnstatus[0] == 0 ? "down" : "up";
$auth = file(RASPI_OPENVPN_CLIENT_LOGIN, FILE_IGNORE_NEW_LINES); $auth = file(RASPI_OPENVPN_CLIENT_LOGIN, FILE_IGNORE_NEW_LINES);
$public_ip = $return[0]; $public_ip = get_public_ip();
// parse client auth credentials // parse client auth credentials
if (!empty($auth)) { if (!empty($auth)) {
@ -100,8 +99,8 @@ function DisplayOpenVPNConfig()
*/ */
function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
{ {
$tmp_ovpnclient = '/tmp/ovpnclient.ovpn'; define('KB', 1024);
$tmp_authdata = '/tmp/authdata'; $tmp_destdir = '/tmp/';
$auth_flag = 0; $auth_flag = 0;
try { try {
@ -110,66 +109,28 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
throw new RuntimeException('Invalid parameters'); throw new RuntimeException('Invalid parameters');
} }
// Parse returned errors $upload = \RaspAP\Uploader\Upload::factory('ovpn',$tmp_destdir);
switch ($file['error']) { $upload->set_max_file_size(64*KB);
case UPLOAD_ERR_OK: $upload->set_allowed_mime_types(array('ovpn' => 'text/plain'));
break; $upload->file($file);
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException('OpenVPN configuration file not sent');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException('Exceeded filesize limit');
default:
throw new RuntimeException('Unknown errors');
}
// Validate extension $validation = new validation;
$ext = pathinfo($file['name'], PATHINFO_EXTENSION); $upload->callbacks($validation, array('check_name_length'));
if ($ext != 'ovpn') { $results = $upload->upload();
throw new RuntimeException('Invalid file extension');
}
// Validate MIME type if (!empty($results['errors'])) {
$finfo = new finfo(FILEINFO_MIME_TYPE); throw new RuntimeException($results['errors'][0]);
if (false === $ext = array_search(
$finfo->file($file['tmp_name']),
array(
'ovpn' => 'text/plain'
),
true
)
) {
throw new RuntimeException('Invalid file format');
}
// Validate filesize
define('KB', 1024);
if ($file['size'] > 64*KB) {
throw new RuntimeException('File size limit exceeded');
}
// Use safe filename, save to /tmp
if (!move_uploaded_file(
$file['tmp_name'],
sprintf(
'/tmp/%s.%s',
'ovpnclient',
$ext
)
)
) {
throw new RuntimeException('Unable to move uploaded file');
} }
// Good file upload, update auth credentials if present // Good file upload, update auth credentials if present
if (!empty($authUser) && !empty($authPassword)) { if (!empty($authUser) && !empty($authPassword)) {
$auth_flag = 1; $auth_flag = 1;
// Move tmp authdata to /etc/openvpn/login.conf $tmp_authdata = $tmp_destdir .'ovpn/authdata';
$auth.= $authUser .PHP_EOL . $authPassword .PHP_EOL; $auth = $authUser .PHP_EOL . $authPassword .PHP_EOL;
file_put_contents($tmp_authdata, $auth); file_put_contents($tmp_authdata, $auth);
chmod($tmp_authdata, 0644); chmod($tmp_authdata, 0644);
$client_auth = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_login.conf'; $client_auth = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_login.conf';
system("sudo cp $tmp_authdata $client_auth", $return); system("sudo mv $tmp_authdata $client_auth", $return);
system("sudo rm ".RASPI_OPENVPN_CLIENT_LOGIN, $return); system("sudo rm ".RASPI_OPENVPN_CLIENT_LOGIN, $return);
system("sudo ln -s $client_auth ".RASPI_OPENVPN_CLIENT_LOGIN, $return); system("sudo ln -s $client_auth ".RASPI_OPENVPN_CLIENT_LOGIN, $return);
if ($return !=0) { if ($return !=0) {
@ -178,14 +139,16 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
} }
// Set iptables rules and, optionally, auth-user-pass // Set iptables rules and, optionally, auth-user-pass
exec("sudo /etc/raspap/openvpn/configauth.sh $tmp_ovpnclient $auth_flag " .$_SESSION['ap_interface'], $return); $tmp_ovpn = $results['full_path'];
exec("sudo /etc/raspap/openvpn/configauth.sh $tmp_ovpn $auth_flag " .$_SESSION['ap_interface'], $return);
foreach ($return as $line) { foreach ($return as $line) {
$status->addMessage($line, 'info'); $status->addMessage($line, 'info');
} }
// Move uploaded ovpn config from /tmp and create symlink
$client_ovpn = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_client.conf'; $client_ovpn = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_client.conf';
chmod($tmp_ovpnclient, 0644); chmod($tmp_ovpn, 0644);
system("sudo cp $tmp_ovpnclient $client_ovpn", $return); system("sudo mv $tmp_ovpn $client_ovpn", $return);
system("sudo rm ".RASPI_OPENVPN_CLIENT_CONFIG, $return); system("sudo rm ".RASPI_OPENVPN_CLIENT_CONFIG, $return);
system("sudo ln -s $client_ovpn ".RASPI_OPENVPN_CLIENT_CONFIG, $return); system("sudo ln -s $client_ovpn ".RASPI_OPENVPN_CLIENT_CONFIG, $return);
@ -201,3 +164,4 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
return $status; return $status;
} }
} }

View file

@ -10,8 +10,13 @@ function DisplayWireGuardConfig()
{ {
$status = new StatusMessages(); $status = new StatusMessages();
if (!RASPI_MONITOR_ENABLED) { if (!RASPI_MONITOR_ENABLED) {
if (isset($_POST['savewgsettings'])) { $optRules = $_POST['wgRules'];
$optConf = $_POST['wgCnfOpt'];
$optSrvEnable = $_POST['wgSrvEnable'];
if (isset($_POST['savewgsettings']) && $optConf == 'manual' && $optSrvEnable == 1 ) {
SaveWireGuardConfig($status); SaveWireGuardConfig($status);
} elseif (isset($_POST['savewgsettings']) && $optConf == 'upload' && is_uploaded_file($_FILES["wgFile"]["tmp_name"])) {
SaveWireGuardUpload($status, $_FILES['wgFile'], $optRules);
} elseif (isset($_POST['startwg'])) { } elseif (isset($_POST['startwg'])) {
$status->addMessage('Attempting to start WireGuard', 'info'); $status->addMessage('Attempting to start WireGuard', 'info');
exec('sudo /bin/systemctl start wg-quick@wg0', $return); exec('sudo /bin/systemctl start wg-quick@wg0', $return);
@ -27,7 +32,7 @@ function DisplayWireGuardConfig()
} }
} }
// fetch wg config // fetch server config
exec('sudo cat '. RASPI_WIREGUARD_CONFIG, $return); exec('sudo cat '. RASPI_WIREGUARD_CONFIG, $return);
$conf = ParseConfig($return); $conf = ParseConfig($return);
$wg_srvpubkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-server-public.key', $return); $wg_srvpubkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-server-public.key', $return);
@ -39,7 +44,7 @@ function DisplayWireGuardConfig()
$wg_senabled = true; $wg_senabled = true;
} }
// todo: iterate multiple peer configs // fetch client config
exec('sudo cat '. RASPI_WIREGUARD_PATH.'client.conf', $preturn); exec('sudo cat '. RASPI_WIREGUARD_PATH.'client.conf', $preturn);
$conf = ParseConfig($preturn); $conf = ParseConfig($preturn);
$wg_pipaddress = ($conf['Address'] == '') ? getDefaultNetValue('wireguard','peer','Address') : $conf['Address']; $wg_pipaddress = ($conf['Address'] == '') ? getDefaultNetValue('wireguard','peer','Address') : $conf['Address'];
@ -55,12 +60,15 @@ function DisplayWireGuardConfig()
exec('pidof wg-crypt-wg0 | wc -l', $wgstatus); exec('pidof wg-crypt-wg0 | wc -l', $wgstatus);
$serviceStatus = $wgstatus[0] == 0 ? "down" : "up"; $serviceStatus = $wgstatus[0] == 0 ? "down" : "up";
$wg_state = ($wgstatus[0] > 0); $wg_state = ($wgstatus[0] > 0);
$public_ip = get_public_ip();
echo renderTemplate( echo renderTemplate(
"wireguard", compact( "wireguard", compact(
"status", "status",
"wg_state", "wg_state",
"serviceStatus", "serviceStatus",
"public_ip",
"optRules",
"wg_log", "wg_log",
"peer_id", "peer_id",
"wg_srvpubkey", "wg_srvpubkey",
@ -79,6 +87,71 @@ function DisplayWireGuardConfig()
); );
} }
/**
* Validates uploaded .conf file, adds iptables post-up and
* post-down rules.
*
* @param object $status
* @param object $file
* @param boolean $optRules
* @return object $status
*/
function SaveWireGuardUpload($status, $file, $optRules)
{
define('KB', 1024);
$tmp_destdir = '/tmp/';
$auth_flag = 0;
try {
// If undefined or multiple files, treat as invalid
if (!isset($file['error']) || is_array($file['error'])) {
throw new RuntimeException('Invalid parameters');
}
$upload = \RaspAP\Uploader\Upload::factory('wg',$tmp_destdir);
$upload->set_max_file_size(64*KB);
$upload->set_allowed_mime_types(array('text/plain'));
$upload->file($file);
$validation = new validation;
$upload->callbacks($validation, array('check_name_length'));
$results = $upload->upload();
if (!empty($results['errors'])) {
throw new RuntimeException($results['errors'][0]);
}
// Valid upload, get file contents
$tmp_wgconfig = $results['full_path'];
$tmp_contents = file_get_contents($tmp_wgconfig);
// Set iptables rules
if (isset($optRules) && !preg_match('/PostUp|PostDown/m',$tmp_contents)) {
$rules[] = 'PostUp = '.getDefaultNetValue('wireguard','server','PostUp');
$rules[] = 'PostDown = '.getDefaultNetValue('wireguard','server','PostDown');
$rules[] = '';
$rules = join(PHP_EOL, $rules);
$rules = preg_replace('/wlan0/m', $_SESSION['ap_interface'], $rules);
$tmp_contents = preg_replace('/^\s*$/ms', $rules, $tmp_contents, 1);
file_put_contents($tmp_wgconfig, $tmp_contents);
}
// Move processed file from tmp to destination
system("sudo mv $tmp_wgconfig ". RASPI_WIREGUARD_CONFIG, $return);
if ($return ==0) {
$status->addMessage('WireGuard configuration uploaded successfully', 'info');
} else {
$status->addMessage('Unable to save WireGuard configuration', 'danger');
}
return $status;
} catch (RuntimeException $e) {
$status->addMessage($e->getMessage(), 'danger');
return $status;
}
}
/** /**
* Validate user input, save wireguard configuration * Validate user input, save wireguard configuration
* *

View file

@ -20,8 +20,7 @@ www-data ALL=(ALL) NOPASSWD:/bin/systemctl start openvpn-client@client
www-data ALL=(ALL) NOPASSWD:/bin/systemctl enable openvpn-client@client www-data ALL=(ALL) NOPASSWD:/bin/systemctl enable openvpn-client@client
www-data ALL=(ALL) NOPASSWD:/bin/systemctl stop openvpn-client@client www-data ALL=(ALL) NOPASSWD:/bin/systemctl stop openvpn-client@client
www-data ALL=(ALL) NOPASSWD:/bin/systemctl disable openvpn-client@client www-data ALL=(ALL) NOPASSWD:/bin/systemctl disable openvpn-client@client
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/ovpnclient.ovpn /etc/openvpn/client/*.conf www-data ALL=(ALL) NOPASSWD:/bin/mv /tmp/ovpn/* /etc/openvpn/client/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/authdata /etc/openvpn/client/*.conf
www-data ALL=(ALL) NOPASSWD:/usr/bin/ln -s /etc/openvpn/client/*.conf /etc/openvpn/client/*.conf www-data ALL=(ALL) NOPASSWD:/usr/bin/ln -s /etc/openvpn/client/*.conf /etc/openvpn/client/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/openvpn/client/*.conf www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/openvpn/client/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_*.conf www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_*.conf
@ -49,6 +48,7 @@ www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_adblock.
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasq_custom /etc/raspap/adblock/custom.txt www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasq_custom /etc/raspap/adblock/custom.txt
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wgdata /etc/wireguard/*.conf www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wgdata /etc/wireguard/*.conf
www-data ALL=(ALL) NOPASSWD:/bin/mv /tmp/wg-*.key /etc/wireguard/wg-*.key www-data ALL=(ALL) NOPASSWD:/bin/mv /tmp/wg-*.key /etc/wireguard/wg-*.key
www-data ALL=(ALL) NOPASSWD:/bin/mv /tmp/wg/* /etc/wireguard/*.conf
www-data ALL=(ALL) NOPASSWD:/etc/raspap/adblock/update_blocklist.sh www-data ALL=(ALL) NOPASSWD:/etc/raspap/adblock/update_blocklist.sh
www-data ALL=(ALL) NOPASSWD:/usr/bin/socat - /dev/ttyUSB[0-9] www-data ALL=(ALL) NOPASSWD:/usr/bin/socat - /dev/ttyUSB[0-9]
www-data ALL=(ALL) NOPASSWD:/usr/local/sbin/onoff_huawei_hilink.sh * www-data ALL=(ALL) NOPASSWD:/usr/local/sbin/onoff_huawei_hilink.sh *

Binary file not shown.

View file

@ -1026,14 +1026,44 @@ msgstr "Invalid custom host found on line "
msgid "Tunnel settings" msgid "Tunnel settings"
msgstr "Tunnel settings" msgstr "Tunnel settings"
msgid "Configuration Method"
msgstr "Configuration Method"
msgid "Upload file"
msgstr "Upload file"
msgid "Create manually"
msgstr "Create manually"
msgid "Upload a WireGuard config"
msgstr "Upload a WireGuard config"
msgid "This option uploads and installs an existing WireGuard <code>.conf</code> file on this device."
msgstr "This option uploads and installs an existing WireGuard <code>.conf</code> file on this device."
msgid "Apply iptables rules for AP interface"
msgstr "Apply iptables rules for AP interface"
msgid "Recommended if you wish to forward network traffic from the wg0 interface to clients connected on the AP interface."
msgstr "Recommended if you wish to forward network traffic from the wg0 interface to clients connected on the AP interface."
msgid "This option adds <strong>iptables</strong> <code>Postup</code> and <code>PostDown</code> rules for the configured AP interface (%s)."
msgstr "This option adds <strong>iptables</strong> <code>Postup</code> and <code>PostDown</code> rules for the configured AP interface (%s)."
msgid "Select WireGuard configuration file (.conf)"
msgstr "Select WireGuard configuration file (.conf)"
msgid "Create a local WireGuard config"
msgstr "Create a local WireGuard config"
msgid "Enable server" msgid "Enable server"
msgstr "Enable server" msgstr "Enable server"
msgid "Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers." msgid "Enable this option to secure network traffic by creating an encrypted tunnel between RaspAP and configured peers."
msgstr "Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers." msgstr "Enable this option to secure network traffic by creating an encrypted tunnel between RaspAP and configured peers."
msgid "This option adds <code>wg0.conf</code> to the WireGuard configuration." msgid "This setting generates a new WireGuard <code>.conf</code> file on this device."
msgstr "This option adds <code>wg0.conf</code> to the WireGuard configuration." msgstr "This setting generates a new WireGuard <code>.conf</code> file on this device."
msgid "Local public key" msgid "Local public key"
msgstr "Local public key" msgstr "Local public key"

View file

@ -3,21 +3,77 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h4 class="mt-3"><?php echo _("Tunnel settings"); ?></h4> <h4 class="mt-3"><?php echo _("Tunnel settings"); ?></h4>
<div class="col-lg-12 mt-2">
<div class="row mt-3 mb-2">
<div class="info-item col-xs-3"><?php echo _("IPv4 Address"); ?></div>
<div class="info-value col-xs-3"><?php echo htmlspecialchars($public_ip, ENT_QUOTES); ?><a class="text-gray-500" href="https://ipapi.co/<?php echo($public_ip); ?>" target="_blank" rel="noopener noreferrer"><i class="fas fa-external-link-alt ml-2"></i></a></div>
</div>
</div>
<h5><?php echo _("Configuration Method"); ?></h5>
<div class="col-sm-12 mt-2 mb-2 form-check">
<input class="form-check-input" id="wg-upload" name="wgCnfOpt" value="upload" data-toggle="" data-parent="#serversettings" data-target="#wgUpload" type="radio" checked>
<label class="form-check-label"><?php echo _("Upload file"); ?></label>
</div>
<div class="col-sm-12 mt-2 mb-2 form-check">
<input class="form-check-input" id="wg-manual" name="wgCnfOpt" value="manual" data-toggle="" data-parent="#serversettings" data-target="#wgManual" type="radio">
<label class="form-check-label"><?php echo _("Create manually"); ?></label>
</div>
<div class="col-sm-12 ml-2">
<div class="panel-group" id="serversettings">
<div class="panel panel-default panel-collapse" id="PanelUpload">
<div class="panel-heading">
<h5 class="panel-title"><?php echo _("Upload a WireGuard config"); ?></h5>
<p id="wg-description">
<small><?php echo _("This option uploads and installs an existing WireGuard <code>.conf</code> file on this device.") ?></small>
</p>
</div>
<div class="panel-body">
<div class="form-group col-sm-12">
<div class="custom-control custom-switch">
<?php $checked = $optRules == 1 ? 'checked="checked"' : '' ?>
<input class="custom-control-input" id="chxwgrules" name="wgRules" type="checkbox" value="1" <?php echo $checked ?> />
<label class="custom-control-label" for="chxwgrules"><?php echo _("Apply iptables rules for AP interface"); ?></label>
<i class="fas fa-question-circle text-muted" data-toggle="tooltip" data-placement="auto" title="<?php echo _("Recommended if you wish to forward network traffic from the wg0 interface to clients connected on the AP interface."); ?>"></i>
<p id="wg-description">
<small><?php printf(_("This option adds <strong>iptables</strong> <code>Postup</code> and <code>PostDown</code> rules for the configured AP interface (%s)."), $_SESSION['ap_interface']) ?></small>
</p>
</div>
</div>
<div class="form-group">
<h5 class="panel-title"><?php echo _("Configuration File"); ?></h4>
<div class="custom-file">
<input type="file" class="custom-file-input" name="wgFile" id="wgFile">
<label class="custom-file-label" for="wgFile"><?php echo _("Select WireGuard configuration file (.conf)"); ?></label>
</div>
</div>
<div class="row mb-2"></div>
</div><!-- /.panel-body -->
</div><!-- /.panel -->
<div class="panel panel-default panel-collapse" id="PanelManual">
<div class="panel-heading">
<h5 class="panel-title"><?php echo _("Create a local WireGuard config"); ?></h5>
<div class="input-group"> <div class="input-group">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input class="custom-control-input" id="server_enabled" type="checkbox" name="wg_senabled" value="1" <?php echo $wg_senabled ? ' checked="checked"' : "" ?> aria-describedby="server-description"> <input class="custom-control-input" id="server_enabled" type="checkbox" name="wgSrvEnable" value="1" <?php echo $wg_senabled ? ' checked="checked"' : "" ?> aria-describedby="server-description">
<label class="custom-control-label" for="server_enabled"><?php echo _("Enable server") ?></label> <label class="custom-control-label" for="server_enabled"><?php echo _("Enable server") ?></label>
</div> </div>
<p id="wg-description"> <p id="wg-description">
<small><?php echo _("Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers.") ?></small> <small>
<small><?php echo _("This option adds <code>wg0.conf</code> to the WireGuard configuration.") ?></small> <?php echo _("Enable this option to secure network traffic by creating an encrypted tunnel between RaspAP and configured peers.") ?>
<?php echo _("This setting generates a new WireGuard <code>.conf</code> file on this device.") ?>
</small>
</p> </p>
</div> </div>
<div class="row">
<div class="col-xs-3 col-sm-6">
<label for="code"><?php echo _("Local public key"); ?></label>
</div> </div>
<div class="panel-body">
<label for="code"><?php echo _("Local public key"); ?></label>
<div class="input-group col-md-12 mb-3"> <div class="input-group col-md-12 mb-3">
<input type="text" class="form-control" name="wg-server" id="wg-srvpubkey" value="<?php echo htmlspecialchars($wg_srvpubkey, ENT_QUOTES); ?>" /> <input type="text" class="form-control" name="wg-server" id="wg-srvpubkey" value="<?php echo htmlspecialchars($wg_srvpubkey, ENT_QUOTES); ?>" />
<div class="input-group-append"> <div class="input-group-append">
@ -27,29 +83,26 @@
</div> </div>
</div> </div>
<div class="row">
<div class="form-group col-xs-3 col-sm-3"> <div class="form-group col-xs-3 col-sm-3">
<label for="code"><?php echo _("Local Port"); ?></label> <label for="code"><?php echo _("Local Port"); ?></label>
<input type="text" class="form-control" name="wg_srvport" value="<?php echo htmlspecialchars($wg_srvport, ENT_QUOTES); ?>" /> <input type="text" class="form-control" name="wg_srvport" value="<?php echo htmlspecialchars($wg_srvport, ENT_QUOTES); ?>" />
</div> </div>
</div>
<div class="row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="code"><?php echo _("IP Address"); ?></label> <label for="code"><?php echo _("IP Address"); ?></label>
<input type="text" class="form-control" name="wg_srvipaddress" value="<?php echo htmlspecialchars($wg_srvipaddress, ENT_QUOTES); ?>" /> <input type="text" class="form-control" name="wg_srvipaddress" value="<?php echo htmlspecialchars($wg_srvipaddress, ENT_QUOTES); ?>" />
</div> </div>
</div>
<div class="row">
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label for="code"><?php echo _("DNS"); ?></label> <label for="code"><?php echo _("DNS"); ?></label>
<input type="text" class="form-control" name="wg_srvdns" value="<?php echo htmlspecialchars($wg_srvdns, ENT_QUOTES); ?>" /> <input type="text" class="form-control" name="wg_srvdns" value="<?php echo htmlspecialchars($wg_srvdns, ENT_QUOTES); ?>" />
</div> </div>
</div> <div class="row mb-3"></div>
</div> </div><!-- /.panel-body -->
</div><!-- /.panel -->
</div><!-- /.panel-group -->
</div><!-- /.col -->
</div><!-- /.row --> </div><!-- /.row -->
</div><!-- /.tab-pane | settings tab --> </div><!-- /.tab-pane | settings tab -->