diff --git a/app/js/custom.js b/app/js/custom.js
index 4ba0436b..dc886d07 100644
--- a/app/js/custom.js
+++ b/app/js/custom.js
@@ -307,7 +307,6 @@ $('#ovpn-confirm-activate').on('shown.bs.modal', function (e) {
});
$('#ovpn-userpw,#ovpn-certs').on('click', function (e) {
-// e.stopPropagation();
if (this.id == 'ovpn-userpw') {
$('#PanelCerts').hide();
$('#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
$(".custom-file-input").on("change", function() {
var fileName = $(this).val().split("\\").pop();
diff --git a/app/lib/uploader.php b/app/lib/uploader.php
new file mode 100644
index 00000000..6e19d9e8
--- /dev/null
+++ b/app/lib/uploader.php
@@ -0,0 +1,505 @@
+
+ * @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);
+ }
+}
+
diff --git a/includes/functions.php b/includes/functions.php
index 93c609a3..8ccd2430 100755
--- a/includes/functions.php
+++ b/includes/functions.php
@@ -721,13 +721,15 @@ function validateCidr($cidr)
}
// 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);
}
// Gets night mode toggle value
// @return boolean
-function getNightmode(){
+function getNightmode()
+{
if ($_COOKIE['theme'] == 'lightsout.css') {
return true;
} else {
@@ -736,7 +738,8 @@ function getNightmode(){
}
// search array for matching string and return only first matching group
-function preg_only_match($pat,$haystack) {
+function preg_only_match($pat,$haystack)
+{
$match = "";
if(!empty($haystack) && !empty($pat)) {
if(!is_array($haystack)) $haystack = array($haystack);
@@ -754,10 +757,34 @@ function qr_encode($str)
return preg_replace('/(?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];
+}
+
diff --git a/includes/openvpn.php b/includes/openvpn.php
index 67084df4..a89c3e18 100755
--- a/includes/openvpn.php
+++ b/includes/openvpn.php
@@ -3,6 +3,7 @@
require_once 'includes/status_messages.php';
require_once 'includes/config.php';
require_once 'includes/wifi_functions.php';
+require_once 'app/lib/uploader.php';
getWifiInterface();
@@ -41,11 +42,9 @@ function DisplayOpenVPNConfig()
}
exec('pidof openvpn | wc -l', $openvpnstatus);
- exec('wget https://ipinfo.io/ip -qO -', $return);
-
$serviceStatus = $openvpnstatus[0] == 0 ? "down" : "up";
$auth = file(RASPI_OPENVPN_CLIENT_LOGIN, FILE_IGNORE_NEW_LINES);
- $public_ip = $return[0];
+ $public_ip = get_public_ip();
// parse client auth credentials
if (!empty($auth)) {
@@ -100,8 +99,8 @@ function DisplayOpenVPNConfig()
*/
function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
{
- $tmp_ovpnclient = '/tmp/ovpnclient.ovpn';
- $tmp_authdata = '/tmp/authdata';
+ define('KB', 1024);
+ $tmp_destdir = '/tmp/';
$auth_flag = 0;
try {
@@ -110,66 +109,28 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
throw new RuntimeException('Invalid parameters');
}
- // Parse returned errors
- switch ($file['error']) {
- case UPLOAD_ERR_OK:
- break;
- 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');
- }
+ $upload = \RaspAP\Uploader\Upload::factory('ovpn',$tmp_destdir);
+ $upload->set_max_file_size(64*KB);
+ $upload->set_allowed_mime_types(array('ovpn' => 'text/plain'));
+ $upload->file($file);
- // Validate extension
- $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
- if ($ext != 'ovpn') {
- throw new RuntimeException('Invalid file extension');
- }
+ $validation = new validation;
+ $upload->callbacks($validation, array('check_name_length'));
+ $results = $upload->upload();
- // Validate MIME type
- $finfo = new finfo(FILEINFO_MIME_TYPE);
- 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');
+ if (!empty($results['errors'])) {
+ throw new RuntimeException($results['errors'][0]);
}
// Good file upload, update auth credentials if present
if (!empty($authUser) && !empty($authPassword)) {
$auth_flag = 1;
- // Move tmp authdata to /etc/openvpn/login.conf
- $auth.= $authUser .PHP_EOL . $authPassword .PHP_EOL;
+ $tmp_authdata = $tmp_destdir .'ovpn/authdata';
+ $auth = $authUser .PHP_EOL . $authPassword .PHP_EOL;
file_put_contents($tmp_authdata, $auth);
chmod($tmp_authdata, 0644);
$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 ln -s $client_auth ".RASPI_OPENVPN_CLIENT_LOGIN, $return);
if ($return !=0) {
@@ -178,14 +139,16 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
}
// 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) {
$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';
- chmod($tmp_ovpnclient, 0644);
- system("sudo cp $tmp_ovpnclient $client_ovpn", $return);
+ chmod($tmp_ovpn, 0644);
+ system("sudo mv $tmp_ovpn $client_ovpn", $return);
system("sudo rm ".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;
}
}
+
diff --git a/includes/wireguard.php b/includes/wireguard.php
index c7f56cdd..cb66341b 100644
--- a/includes/wireguard.php
+++ b/includes/wireguard.php
@@ -10,8 +10,13 @@ function DisplayWireGuardConfig()
{
$status = new StatusMessages();
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);
+ } elseif (isset($_POST['savewgsettings']) && $optConf == 'upload' && is_uploaded_file($_FILES["wgFile"]["tmp_name"])) {
+ SaveWireGuardUpload($status, $_FILES['wgFile'], $optRules);
} elseif (isset($_POST['startwg'])) {
$status->addMessage('Attempting to start WireGuard', 'info');
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);
$conf = ParseConfig($return);
$wg_srvpubkey = exec('sudo cat '. RASPI_WIREGUARD_PATH .'wg-server-public.key', $return);
@@ -39,7 +44,7 @@ function DisplayWireGuardConfig()
$wg_senabled = true;
}
- // todo: iterate multiple peer configs
+ // fetch client config
exec('sudo cat '. RASPI_WIREGUARD_PATH.'client.conf', $preturn);
$conf = ParseConfig($preturn);
$wg_pipaddress = ($conf['Address'] == '') ? getDefaultNetValue('wireguard','peer','Address') : $conf['Address'];
@@ -55,12 +60,15 @@ function DisplayWireGuardConfig()
exec('pidof wg-crypt-wg0 | wc -l', $wgstatus);
$serviceStatus = $wgstatus[0] == 0 ? "down" : "up";
$wg_state = ($wgstatus[0] > 0);
+ $public_ip = get_public_ip();
echo renderTemplate(
"wireguard", compact(
"status",
"wg_state",
"serviceStatus",
+ "public_ip",
+ "optRules",
"wg_log",
"peer_id",
"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
*
diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers
index 2621d4e2..7ce40f28 100644
--- a/installers/raspap.sudoers
+++ b/installers/raspap.sudoers
@@ -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 stop 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/cp /tmp/authdata /etc/openvpn/client/*.conf
+www-data ALL=(ALL) NOPASSWD:/bin/mv /tmp/ovpn/* /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/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/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/* /etc/wireguard/*.conf
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/local/sbin/onoff_huawei_hilink.sh *
diff --git a/locale/en_US/LC_MESSAGES/messages.mo b/locale/en_US/LC_MESSAGES/messages.mo
index f51f7c62..b1d57510 100644
Binary files a/locale/en_US/LC_MESSAGES/messages.mo and b/locale/en_US/LC_MESSAGES/messages.mo differ
diff --git a/locale/en_US/LC_MESSAGES/messages.po b/locale/en_US/LC_MESSAGES/messages.po
index b1defed5..c1b9ff47 100644
--- a/locale/en_US/LC_MESSAGES/messages.po
+++ b/locale/en_US/LC_MESSAGES/messages.po
@@ -1026,14 +1026,44 @@ msgstr "Invalid custom host found on line "
msgid "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 .conf
file on this device."
+msgstr "This option uploads and installs an existing WireGuard .conf
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 iptables Postup
and PostDown
rules for the configured AP interface (%s)."
+msgstr "This option adds iptables Postup
and PostDown
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"
msgstr "Enable server"
-msgid "Enable this option to encrypt traffic by creating a tunnel between RaspAP and configured peers."
-msgstr "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 secure network traffic by creating an encrypted tunnel between RaspAP and configured peers."
-msgid "This option adds wg0.conf
to the WireGuard configuration."
-msgstr "This option adds wg0.conf
to the WireGuard configuration."
+msgid "This setting generates a new WireGuard .conf
file on this device."
+msgstr "This setting generates a new WireGuard .conf
file on this device."
msgid "Local public key"
msgstr "Local public key"
diff --git a/templates/wg/general.php b/templates/wg/general.php
index 06d09811..15d2f9e3 100644
--- a/templates/wg/general.php
+++ b/templates/wg/general.php
@@ -3,53 +3,106 @@
- - wg0.conf to the WireGuard configuration.") ?> -
-+ .conf file on this device.") ?> +
+
+ iptables Postup
and PostDown
rules for the configured AP interface (%s)."), $_SESSION['ap_interface']) ?>
+
+ + + .conf file on this device.") ?> + +
+