From 8ae0fce366f287a33a6b18bf8e747ff08c121843 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 3 Jul 2021 23:01:35 +0100 Subject: [PATCH 01/18] Initial commit --- app/lib/uploader.php | 503 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 503 insertions(+) create mode 100644 app/lib/uploader.php diff --git a/app/lib/uploader.php b/app/lib/uploader.php new file mode 100644 index 00000000..e8a31b8e --- /dev/null +++ b/app/lib/uploader.php @@ -0,0 +1,503 @@ + + * @author Aivis Silins + * @link https://github.com/aivis/PHP-file-upload-class + * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE + */ + +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); + } +} + From b7a9c6254edfe88d23f2ebc07f2ae843d582a7b8 Mon Sep 17 00:00:00 2001 From: billz Date: Sat, 3 Jul 2021 23:03:14 +0100 Subject: [PATCH 02/18] Refactor w/ file upload class --- includes/openvpn.php | 78 ++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/includes/openvpn.php b/includes/openvpn.php index 67084df4..6243b603 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(); @@ -87,6 +88,18 @@ function DisplayOpenVPNConfig() ); } +/* 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.'); + } + } +} + /** * Validates uploaded .ovpn file, adds auth-user-pass and * stores auth credentials in login.conf. Copies files from @@ -100,8 +113,10 @@ function DisplayOpenVPNConfig() */ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) { - $tmp_ovpnclient = '/tmp/ovpnclient.ovpn'; - $tmp_authdata = '/tmp/authdata'; + define('KB', 1024); + $tmp_destdir = '/tmp/'; + $tmp_ovpnclient = $tmp_destdir .'ovpn/ovpnclient.ovpn'; + $tmp_authdata = $tmp_destdir .'ovpn/authdata'; $auth_flag = 0; try { @@ -110,61 +125,24 @@ 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 = 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]); } + echo '
' . var_export($results, true) . '
'; + #die(); // 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; file_put_contents($tmp_authdata, $auth); chmod($tmp_authdata, 0644); From 8409c3e7d89a0d68bd2646cb03eb268504923ada Mon Sep 17 00:00:00 2001 From: billz Date: Sun, 4 Jul 2021 10:46:00 +0100 Subject: [PATCH 03/18] Update sudoers ovpn actions --- installers/raspap.sudoers | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index 260a45fc..2892c227 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 From 699f9ff3970666ef297471f7161269b234ca4223 Mon Sep 17 00:00:00 2001 From: billz Date: Sun, 4 Jul 2021 10:47:45 +0100 Subject: [PATCH 04/18] Bugfix + remove debug output --- includes/openvpn.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/includes/openvpn.php b/includes/openvpn.php index 6243b603..7d4b2858 100755 --- a/includes/openvpn.php +++ b/includes/openvpn.php @@ -88,18 +88,6 @@ function DisplayOpenVPNConfig() ); } -/* 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.'); - } - } -} - /** * Validates uploaded .ovpn file, adds auth-user-pass and * stores auth credentials in login.conf. Copies files from @@ -115,8 +103,6 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) { define('KB', 1024); $tmp_destdir = '/tmp/'; - $tmp_ovpnclient = $tmp_destdir .'ovpn/ovpnclient.ovpn'; - $tmp_authdata = $tmp_destdir .'ovpn/authdata'; $auth_flag = 0; try { @@ -137,17 +123,16 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) if (!empty($results['errors'])) { throw new RuntimeException($results['errors'][0]); } - echo '
' . var_export($results, true) . '
'; - #die(); // Good file upload, update auth credentials if present if (!empty($authUser) && !empty($authPassword)) { $auth_flag = 1; + $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) { @@ -161,9 +146,11 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) $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'; + $tmp_ovpn = $results['full_path']; chmod($tmp_ovpnclient, 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 ln -s $client_ovpn ".RASPI_OPENVPN_CLIENT_CONFIG, $return); @@ -179,3 +166,16 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) return $status; } } + +/* 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.'); + } + } +} + From 87352b8b42d88123d430e1fdd2d68fd128afba9f Mon Sep 17 00:00:00 2001 From: billz Date: Sun, 4 Jul 2021 11:15:50 +0100 Subject: [PATCH 05/18] Update w/ namespace, fix configauth for client.conf --- includes/openvpn.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/openvpn.php b/includes/openvpn.php index 7d4b2858..598f0b03 100755 --- a/includes/openvpn.php +++ b/includes/openvpn.php @@ -111,7 +111,7 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) throw new RuntimeException('Invalid parameters'); } - $upload = Upload::factory('ovpn',$tmp_destdir); + $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); @@ -128,7 +128,7 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) if (!empty($authUser) && !empty($authPassword)) { $auth_flag = 1; $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); chmod($tmp_authdata, 0644); $client_auth = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_login.conf'; @@ -141,15 +141,15 @@ 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'; - $tmp_ovpn = $results['full_path']; - chmod($tmp_ovpnclient, 0644); + 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); From 8cd2c59ca12a1d4845ed40871813eb27cf535be1 Mon Sep 17 00:00:00 2001 From: billz Date: Sun, 4 Jul 2021 11:16:21 +0100 Subject: [PATCH 06/18] Update w/ namespace --- app/lib/uploader.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/lib/uploader.php b/app/lib/uploader.php index e8a31b8e..6e19d9e8 100644 --- a/app/lib/uploader.php +++ b/app/lib/uploader.php @@ -12,6 +12,8 @@ * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE */ +namespace RaspAP\Uploader; + class Upload { @@ -130,7 +132,7 @@ class Upload throw new Exception('Upload: Unable to create destination. '.$this->root . $this->destination); } //create finfo object - $this->finfo = new finfo(); + $this->finfo = new \finfo(); } /** From de586e00249701fdd20f8d3d5f72b127271cc001 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 6 Jul 2021 22:18:43 +0100 Subject: [PATCH 07/18] Work in progress: WG server config panels --- app/js/custom.js | 11 ++++- templates/wg/general.php | 102 +++++++++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 37 deletions(-) diff --git a/app/js/custom.js b/app/js/custom.js index 4ba0436b..ff0b303f 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,16 @@ $('#ovpn-userpw,#ovpn-certs').on('click', function (e) { } }); +$('#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/templates/wg/general.php b/templates/wg/general.php index 06d09811..86eefe75 100644 --- a/templates/wg/general.php +++ b/templates/wg/general.php @@ -9,47 +9,77 @@

- - wg0.conf to the WireGuard configuration.") ?> +

+
+
+ + +
+
+ + +
-
-
- -
-
- -
- - +
+
+
+
+
+

+ wg0.conf WireGuard configuration on this device.") ?> +

+
+
+ +
+ +
+ + +
+
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+ +
+
+
+

+ .conf file to this device.") ?> +

-
-
- -
-
- - -
-
- -
-
- - -
-
- -
-
- - -
-
- +
+
+
+
+ + +
+
+
+
+
+
- + From 84d5584150b556abbe03dbab57624da0b0562525 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 6 Jul 2021 23:10:10 +0100 Subject: [PATCH 08/18] Move file upload validation class to functions --- includes/functions.php | 25 +++++++++++++++++++++---- includes/openvpn.php | 12 ------------ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/includes/functions.php b/includes/functions.php index 93c609a3..b30ff825 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,24 @@ function qr_encode($str) return preg_replace('/(?file['filename']) > 255) { + $object->set_error('File name is too long.'); + } + } +} + diff --git a/includes/openvpn.php b/includes/openvpn.php index 598f0b03..eae9c42d 100755 --- a/includes/openvpn.php +++ b/includes/openvpn.php @@ -167,15 +167,3 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword) } } -/* 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.'); - } - } -} - From 1adaca1ea1cba242efa60cdd8963554339477650 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 6 Jul 2021 23:11:16 +0100 Subject: [PATCH 09/18] Set file upload as default wg config method --- app/js/custom.js | 4 ++++ templates/wg/general.php | 51 ++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/app/js/custom.js b/app/js/custom.js index ff0b303f..dc886d07 100644 --- a/app/js/custom.js +++ b/app/js/custom.js @@ -316,6 +316,10 @@ $('#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(); diff --git a/templates/wg/general.php b/templates/wg/general.php index 86eefe75..34147aef 100644 --- a/templates/wg/general.php +++ b/templates/wg/general.php @@ -9,21 +9,40 @@

- +

- - + +
- - + +
+ +
+
+
+

+ .conf file to this device.") ?> +

+
+
+
+
+
+ + +
+
+
+
+
@@ -46,12 +65,10 @@
-
-
@@ -59,27 +76,9 @@
-
-
-
-

- .conf file to this device.") ?> -

-
-
-
-
-
- - -
-
-
-
- + - From 8c3531e6d2bc24136c26e7f7336a35508854c793 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 6 Jul 2021 23:13:32 +0100 Subject: [PATCH 10/18] Work in progress: SaveWireGuardUpload() --- includes/wireguard.php | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/includes/wireguard.php b/includes/wireguard.php index c7f56cdd..0ce23353 100644 --- a/includes/wireguard.php +++ b/includes/wireguard.php @@ -12,6 +12,8 @@ function DisplayWireGuardConfig() if (!RASPI_MONITOR_ENABLED) { if (isset($_POST['savewgsettings'])) { SaveWireGuardConfig($status); + } elseif (is_uploaded_file( $_FILES["wgFile"]["tmp_name"])) { + SaveWireGuardUpload($status, $_FILES['wgFile']); } elseif (isset($_POST['startwg'])) { $status->addMessage('Attempting to start WireGuard', 'info'); exec('sudo /bin/systemctl start wg-quick@wg0', $return); @@ -79,6 +81,59 @@ function DisplayWireGuardConfig() ); } +/** + * Validates uploaded .conf file, adds iptables post-up and + * post-down rules. + * + * @param object $status + * @param object $file + * @return object $status + */ +function SaveWireGuardUpload($status, $file) +{ + 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]); + } + + // Good file upload, do any post-processing + + // Set iptables rules + + // Move uploaded .conf from /tmp to destination + + + 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 * From c3b45a7915ab7db3643c166397e26fc496eb665b Mon Sep 17 00:00:00 2001 From: billz Date: Wed, 7 Jul 2021 08:12:30 +0100 Subject: [PATCH 11/18] Update labels, add iptables rules toggle --- templates/wg/general.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/templates/wg/general.php b/templates/wg/general.php index 34147aef..63cd9bf5 100644 --- a/templates/wg/general.php +++ b/templates/wg/general.php @@ -15,7 +15,7 @@
- +
@@ -29,10 +29,23 @@

- .conf file to this device.") ?> + .conf file on this device.") ?>

+ +
+
+ + /> + + "> +

+ iptables Postup and PostDown rules for the configured AP interface (%s)."), $_SESSION['ap_interface']) ?> +

+
+
+
@@ -40,6 +53,8 @@
+
+
From d7baf5492f32b91b7af8e52079f4714d4b6feffa Mon Sep 17 00:00:00 2001 From: billz Date: Wed, 7 Jul 2021 22:58:50 +0100 Subject: [PATCH 12/18] Set toggle state from template var --- templates/wg/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/wg/general.php b/templates/wg/general.php index 63cd9bf5..00d840ac 100644 --- a/templates/wg/general.php +++ b/templates/wg/general.php @@ -36,7 +36,7 @@
- + /> "> From fbe1348e15f7f3f8c3cb771e3303eb9d55a6aec9 Mon Sep 17 00:00:00 2001 From: billz Date: Wed, 7 Jul 2021 22:59:51 +0100 Subject: [PATCH 13/18] Added sudoers mv /tmp/wg/* --- installers/raspap.sudoers | 1 + 1 file changed, 1 insertion(+) diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index 2892c227..1d51eb49 100644 --- a/installers/raspap.sudoers +++ b/installers/raspap.sudoers @@ -48,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 * From 225bff59b60d9c70a00010b9b16e8162f9545af2 Mon Sep 17 00:00:00 2001 From: billz Date: Wed, 7 Jul 2021 23:01:47 +0100 Subject: [PATCH 14/18] Upload wg config, set postup/down rules, move to destination --- includes/wireguard.php | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/includes/wireguard.php b/includes/wireguard.php index 0ce23353..af81a618 100644 --- a/includes/wireguard.php +++ b/includes/wireguard.php @@ -10,10 +10,11 @@ function DisplayWireGuardConfig() { $status = new StatusMessages(); if (!RASPI_MONITOR_ENABLED) { - if (isset($_POST['savewgsettings'])) { + $optRules = $_POST['wgRules']; + if (isset($_POST['savewgsettings']) && !is_uploaded_file($_FILES["wgFile"]["tmp_name"])) { SaveWireGuardConfig($status); - } elseif (is_uploaded_file( $_FILES["wgFile"]["tmp_name"])) { - SaveWireGuardUpload($status, $_FILES['wgFile']); + } elseif (isset($_POST['savewgsettings']) && 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); @@ -63,6 +64,7 @@ function DisplayWireGuardConfig() "status", "wg_state", "serviceStatus", + "optRules", "wg_log", "peer_id", "wg_srvpubkey", @@ -87,9 +89,10 @@ function DisplayWireGuardConfig() * * @param object $status * @param object $file + * @param boolean $optRules * @return object $status */ -function SaveWireGuardUpload($status, $file) +function SaveWireGuardUpload($status, $file, $optRules) { define('KB', 1024); $tmp_destdir = '/tmp/'; @@ -114,12 +117,23 @@ function SaveWireGuardUpload($status, $file) throw new RuntimeException($results['errors'][0]); } - // Good file upload, do any post-processing + // 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 uploaded .conf from /tmp to destination - + // Move uploaded file from to destination + system("sudo mv $tmp_wgconfig ". RASPI_WIREGUARD_CONFIG, $return); if ($return ==0) { $status->addMessage('WireGuard configuration uploaded successfully', 'info'); From 84fcedc203fdf7face427a751820ad204344ba1a Mon Sep 17 00:00:00 2001 From: billz Date: Wed, 7 Jul 2021 23:24:49 +0100 Subject: [PATCH 15/18] Added get_public_ip() --- includes/functions.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/includes/functions.php b/includes/functions.php index b30ff825..8ccd2430 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -778,3 +778,13 @@ class validation } } +/* 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]; +} + From 8374d032b392ba37ec5fa5f07007f25d7c39f137 Mon Sep 17 00:00:00 2001 From: billz Date: Wed, 7 Jul 2021 23:25:23 +0100 Subject: [PATCH 16/18] Update w/ common public_ip function --- includes/openvpn.php | 4 +--- includes/wireguard.php | 4 +++- templates/wg/general.php | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/includes/openvpn.php b/includes/openvpn.php index eae9c42d..a89c3e18 100755 --- a/includes/openvpn.php +++ b/includes/openvpn.php @@ -42,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)) { diff --git a/includes/wireguard.php b/includes/wireguard.php index af81a618..162e3eef 100644 --- a/includes/wireguard.php +++ b/includes/wireguard.php @@ -58,12 +58,14 @@ 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", @@ -132,7 +134,7 @@ function SaveWireGuardUpload($status, $file, $optRules) file_put_contents($tmp_wgconfig, $tmp_contents); } - // Move uploaded file from to destination + // Move processed file from tmp to destination system("sudo mv $tmp_wgconfig ". RASPI_WIREGUARD_CONFIG, $return); if ($return ==0) { diff --git a/templates/wg/general.php b/templates/wg/general.php index 00d840ac..c9b63071 100644 --- a/templates/wg/general.php +++ b/templates/wg/general.php @@ -3,6 +3,12 @@

+
+
+
+
+
+
aria-describedby="server-description"> From 2ccce60189494c081095f17599db0a493703b80e Mon Sep 17 00:00:00 2001 From: billz Date: Thu, 8 Jul 2021 11:22:17 +0100 Subject: [PATCH 17/18] Simplify template, update save actions --- includes/wireguard.php | 12 +++++++----- templates/wg/general.php | 31 +++++++++++++++++-------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/includes/wireguard.php b/includes/wireguard.php index 162e3eef..cb66341b 100644 --- a/includes/wireguard.php +++ b/includes/wireguard.php @@ -10,10 +10,12 @@ function DisplayWireGuardConfig() { $status = new StatusMessages(); if (!RASPI_MONITOR_ENABLED) { - $optRules = $_POST['wgRules']; - if (isset($_POST['savewgsettings']) && !is_uploaded_file($_FILES["wgFile"]["tmp_name"])) { + $optRules = $_POST['wgRules']; + $optConf = $_POST['wgCnfOpt']; + $optSrvEnable = $_POST['wgSrvEnable']; + if (isset($_POST['savewgsettings']) && $optConf == 'manual' && $optSrvEnable == 1 ) { SaveWireGuardConfig($status); - } elseif (isset($_POST['savewgsettings']) && is_uploaded_file($_FILES["wgFile"]["tmp_name"])) { + } 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'); @@ -30,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); @@ -42,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']; diff --git a/templates/wg/general.php b/templates/wg/general.php index c9b63071..15d2f9e3 100644 --- a/templates/wg/general.php +++ b/templates/wg/general.php @@ -9,22 +9,13 @@
-
-
- aria-describedby="server-description"> - -
-

- -

-
- +
- +
@@ -67,10 +58,20 @@
-

- wg0.conf WireGuard configuration on this device.") ?> -

+
+
+ aria-describedby="server-description"> + +
+

+ + + .conf file on this device.") ?> + +

+
+
@@ -94,6 +95,8 @@
+
+
From ab3e147bbfe709538ed8ea466dafcf269bd6f3c2 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 13 Jul 2021 12:51:09 +0100 Subject: [PATCH 18/18] Update wg messages for en_US locale --- locale/en_US/LC_MESSAGES/messages.mo | Bin 26387 -> 28313 bytes locale/en_US/LC_MESSAGES/messages.po | 38 ++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/locale/en_US/LC_MESSAGES/messages.mo b/locale/en_US/LC_MESSAGES/messages.mo index f51f7c62d77de2fcf26b546fbdae30f2fa79006b..b1d575103df844f9061bbe9f73cf985b650b4813 100644 GIT binary patch literal 28313 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 delta 7766 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 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"