committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
97 changed files with 7563 additions and 513 deletions
-
20.github/ISSUE_TEMPLATE/feature_request.md
-
33BACKERS.md
-
8README.md
-
4ajax/bandwidth/get_bandwidth.php
-
9ajax/bandwidth/get_bandwidth_hourly.php
-
2ajax/networking/get_netcfg.php
-
9ajax/networking/get_wgcfg.php
-
22ajax/networking/get_wgkey.php
-
93ajax/networking/save_net_dev_config.php
-
1ajax/networking/wifi_stations.php
-
26ajax/openvpn/activate_ovpncfg.php
-
13ajax/openvpn/del_ovpncfg.php
-
8app/css/hackernews.css
-
28app/img/wg-qr-code.php
-
8app/img/wifi-qr-code.php
-
131app/js/custom.js
-
2app/lib/system.php
-
505app/lib/uploader.php
-
2config/090_raspap.conf
-
4config/client_config/70-mobile-data-sticks.rules
-
3config/client_config/80-raspap-net-devices.rules
-
505config/client_config/huawei_hilink_api.sh
-
109config/client_config/info_huawei.sh
-
95config/client_config/info_huawei_hilink.sh
-
52config/client_config/info_huawei_modem.sh
-
13config/client_config/interfaces
-
1691config/client_config/mcc-mnc-table.csv
-
58config/client_config/onoff_huawei_hilink.sh
-
21config/client_config/ppp0_route.sh
-
21config/client_config/ppp0_setpin.sh
-
51config/client_config/raspap_helpers.sh
-
13config/client_config/start_huawei_hilink@.service
-
16config/client_config/start_ppp0_device.service
-
21config/client_config/wvdial.conf
-
64config/client_udev_prototypes.json
-
5config/config.php
-
19config/defaults.json
-
205config/iptables_rules.json
-
BINdist/raspap/css/fonts/RaspAP.eot
-
12dist/raspap/css/fonts/RaspAP.svg
-
BINdist/raspap/css/fonts/RaspAP.ttf
-
BINdist/raspap/css/fonts/RaspAP.woff
-
54dist/raspap/css/style.css
-
4includes/adblock.php
-
8includes/configure_client.php
-
8includes/defaults.php
-
2includes/dhcp.php
-
368includes/firewall.php
-
151includes/functions.php
-
307includes/get_clients.php
-
34includes/hostapd.php
-
20includes/internetRoute.php
-
117includes/openvpn.php
-
1includes/system.php
-
6includes/themes.php
-
30includes/wifi_functions.php
-
310includes/wireguard.php
-
30index.php
-
44installers/common.sh
-
2installers/configauth.sh
-
40installers/install_feature_clients.sh
-
20installers/install_feature_firewall.sh
-
2installers/openvpnlog.sh
-
27installers/raspap.sudoers
-
2installers/uninstall.sh
-
29installers/update_firewall.sh
-
BINlocale/da_DK/LC_MESSAGES/messages.mo
-
69locale/da_DK/LC_MESSAGES/messages.po
-
BINlocale/en_US/LC_MESSAGES/messages.mo
-
78locale/en_US/LC_MESSAGES/messages.po
-
BINlocale/es_MX/LC_MESSAGES/messages.mo
-
116locale/es_MX/LC_MESSAGES/messages.po
-
BINlocale/ja_JP/LC_MESSAGES/messages.mo
-
119locale/ja_JP/LC_MESSAGES/messages.po
-
BINlocale/ko_KR/LC_MESSAGES/messages.mo
-
124locale/ko_KR/LC_MESSAGES/messages.po
-
BINlocale/ro_RO/LC_MESSAGES/messages.mo
-
1206locale/ro_RO/LC_MESSAGES/messages.po
-
BINlocale/ru_RU/LC_MESSAGES/messages.mo
-
68locale/ru_RU/LC_MESSAGES/messages.po
-
4templates/dhcp/logging.php
-
105templates/dhcp/static_leases.php
-
110templates/firewall.php
-
13templates/hostapd/advanced.php
-
124templates/openvpn.php
-
35templates/openvpn/configs.php
-
70templates/openvpn/general.php
-
16templates/openvpn/logging.php
-
2templates/themes.php
-
0templates/torproxy.php
-
108templates/wg/general.php
-
19templates/wg/logging.php
-
82templates/wg/peers.php
-
5templates/wifi_stations.php
-
7templates/wifi_stations/network.php
-
53templates/wireguard.php
-
25yarn.lock
@ -0,0 +1,20 @@ |
|||
--- |
|||
name: Feature request |
|||
about: Suggest an idea for this project |
|||
title: '' |
|||
labels: '' |
|||
assignees: '' |
|||
|
|||
--- |
|||
|
|||
**Is your feature request related to a problem? Please describe.** |
|||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] |
|||
|
|||
**Describe the solution you'd like** |
|||
A clear and concise description of what you want to happen. |
|||
|
|||
**Describe alternatives you've considered** |
|||
A clear and concise description of any alternative solutions or features you've considered. |
|||
|
|||
**Additional context** |
|||
Add any other context or screenshots about the feature request here. |
@ -0,0 +1,9 @@ |
|||
<?php |
|||
|
|||
require '../../includes/csrf.php'; |
|||
require_once '../../includes/config.php'; |
|||
|
|||
// fetch wg client.conf
|
|||
exec('sudo cat '. RASPI_WIREGUARD_PATH.'client.conf', $return); |
|||
echo implode(PHP_EOL,$return); |
|||
|
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
require '../../includes/csrf.php'; |
|||
require_once '../../includes/config.php'; |
|||
|
|||
$entity = $_POST['entity']; |
|||
|
|||
if (isset($entity)) { |
|||
|
|||
// generate public/private key pairs for entity
|
|||
$pubkey = RASPI_WIREGUARD_PATH.$entity.'-public.key'; |
|||
$privkey = RASPI_WIREGUARD_PATH.$entity.'-private.key'; |
|||
$pubkey_tmp = '/tmp/'.$entity.'-public.key'; |
|||
$privkey_tmp = '/tmp/'.$entity.'-private.key'; |
|||
|
|||
exec("sudo wg genkey | tee $privkey_tmp | wg pubkey > $pubkey_tmp", $return); |
|||
$wgdata['pubkey'] = str_replace("\n",'',file_get_contents($pubkey_tmp)); |
|||
exec("sudo mv $privkey_tmp $privkey", $return); |
|||
exec("sudo mv $pubkey_tmp $pubkey", $return); |
|||
|
|||
echo json_encode($wgdata); |
|||
} |
@ -0,0 +1,93 @@ |
|||
<?php |
|||
/* |
|||
Save settings of network devices (type, name, PW, APN ...) |
|||
|
|||
Called by js saveNetDeviceSettings (App/js/custom.js) |
|||
*/ |
|||
|
|||
|
|||
require '../../includes/csrf.php'; |
|||
|
|||
require_once '../../includes/config.php'; |
|||
require_once '../../includes/functions.php'; |
|||
|
|||
if (isset($_POST['interface'])) { |
|||
$int = $_POST['interface']; |
|||
$cfg = []; |
|||
$file = $RASPI_MOBILEDATA_CONFIG; |
|||
$cfgfile="/etc/wvdial.conf"; |
|||
if ( $int == "mobiledata") { |
|||
$cfg['pin'] = $_POST["pin-mobile"]; |
|||
$cfg['apn'] = $_POST["apn-mobile"]; |
|||
$cfg['apn_user'] = $_POST["apn-user-mobile"]; |
|||
$cfg['apn_pw'] = $_POST["apn-pw-mobile"]; |
|||
$cfg['router_user'] = $cfg['apn_user'] ; |
|||
$cfg['router_pw'] = $cfg['apn_pw'] ; |
|||
if (file_exists($cfgfile)) { |
|||
if($cfg["pin"] !== "") exec('sudo /bin/sed -i "s/CPIN=\".*\"/CPIN=\"'.$cfg["pin"].'\"/gi" '.$cfgfile); |
|||
if($cfg["apn"] !== "") exec('sudo /bin/sed -i "s/\"IP\"\,\".*\"/\"IP\"\,\"'.$cfg["apn"].'\"/gi" '.$cfgfile); |
|||
if($cfg["apn_user"] !== "") exec('sudo /bin/sed -i "s/^username = .*$/Username = '.$cfg["apn_user"].'/gi" '.$cfgfile); |
|||
if($cfg["apn_pw"] !== "") exec('sudo /bin/sed -i "s/^password = .*$/Password = '.$cfg["apn_pw"].'/gi" '.$cfgfile); |
|||
} |
|||
if (write_php_ini($cfg, RASPI_MOBILEDATA_CONFIG)) { |
|||
$jsonData = ['return'=>0,'output'=>['Successfully saved mobile data settings']]; |
|||
} else { |
|||
$jsonData = ['return'=>1,'output'=>['Error saving mobile data settings']]; |
|||
} |
|||
} else if ( preg_match("/netdevices/",$int)) { |
|||
if(!isset($_POST['opts']) ) { |
|||
$jsonData = ['return'=>0,'output'=>['No valid data to add/delete udev rule ']]; |
|||
echo json_encode($jsonData); |
|||
return; |
|||
} else { |
|||
$opts=explode(" ",$_POST['opts'] ); |
|||
$dev=$opts[0]; |
|||
$vid=$_POST["int-vid-".$dev]; |
|||
$pid=$_POST["int-pid-".$dev]; |
|||
$mac=$_POST["int-mac-".$dev]; |
|||
$name=trim($_POST["int-name-".$dev]); |
|||
// limit device name to letters and numbers. Total length max 20
|
|||
$name=preg_replace("/[^a-z0-9]/", "", strtolower($name)); |
|||
$name=substr($name, 0, min(strlen($name),20)); |
|||
$type=$_POST["int-type-".$dev]; |
|||
$newtype=$_POST["int-new-type-".$dev]; |
|||
$udevfile=$_SESSION["udevrules"]["udev_rules_file"]; // default file /etc/udev/rules.d/80-net-devices.rules";
|
|||
|
|||
// find the rule prototype and prefix
|
|||
$rule = ""; |
|||
foreach($_SESSION["udevrules"]["network_devices"] as $devt) { |
|||
if($devt["type"]==$newtype) { |
|||
$rulenew = $devt["udev_rule"]; |
|||
$prefix = $devt["name_prefix"]; |
|||
} |
|||
} |
|||
|
|||
// check for an existing rule and delete lines with same MAC or same VID/PID
|
|||
if (!empty($vid) && !empty($pid)) { |
|||
$rule = '^.*ATTRS{idVendor}==\"' . $vid . '\".*ATTRS{idProduct}==\"' . $pid . '\".*$'; |
|||
exec('sudo sed -i "/'.$rule.'/Id" '.$udevfile); // clear all entries with this VID/PID
|
|||
$rule = '^.*ATTRS{idProduct}==\"' . $pid . '\".*ATTRS{idVendor}==\"' . $vid . '\".*$'; |
|||
exec('sudo sed -i "/'.$rule.'/Id" '.$udevfile); // clear all entries with this VID/PID
|
|||
} |
|||
if (!empty($mac)) { |
|||
exec('sudo sed -i "/^.*'.$mac.'.*$/d" '.$udevfile); // clear all entries with same MAC
|
|||
} |
|||
// create new entry
|
|||
if ( ($type != $newtype) || !empty($name) ) { // new device type or new name
|
|||
if (empty($name)) $name = $prefix."%n"; |
|||
if (!empty($mac)) $rule = preg_replace("/\\\$MAC\\\$/i", $mac, $rulenew); |
|||
if (!empty($vid)) $rule = preg_replace("/\\\$IDVENDOR\\\$/i", $vid, $rule); |
|||
if (!empty($pid)) $rule = preg_replace("/\\\$IDPRODUCT\\\$/i", $pid, $rule); |
|||
if (!empty($name)) $rule = preg_replace("/\\\$DEVNAME\\\$/i",$name,$rule); |
|||
if (!empty($rule)) exec('echo \''.$rule.'\' | sudo /usr/bin/tee -a '.$udevfile); |
|||
} |
|||
$jsonData = ['return'=>0,'output'=>['Settings changed for device '.$dev. '<br>Changes will only be in effect after reconnecting the device' ] ]; |
|||
} |
|||
} else { |
|||
$jsonData = ['return'=>1,'output'=>['Unknown network configuration']]; |
|||
} |
|||
} else { |
|||
$jsonData = ['return'=>2,'output'=>'Unable to detect interface']; |
|||
} |
|||
|
|||
echo json_encode($jsonData); |
@ -0,0 +1,26 @@ |
|||
<?php |
|||
|
|||
require_once '../../includes/config.php'; |
|||
require_once '../../includes/functions.php'; |
|||
|
|||
if (isset($_POST['cfg_id'])) { |
|||
$ovpncfg_id = $_POST['cfg_id']; |
|||
$ovpncfg_client = RASPI_OPENVPN_CLIENT_PATH.$ovpncfg_id.'_client.conf'; |
|||
$ovpncfg_login = RASPI_OPENVPN_CLIENT_PATH.$ovpncfg_id.'_login.conf'; |
|||
|
|||
// remove existing client config +login and symbolically link the selected one
|
|||
system("sudo rm ".RASPI_OPENVPN_CLIENT_CONFIG, $return); |
|||
system("sudo ln -s $ovpncfg_client ".RASPI_OPENVPN_CLIENT_CONFIG, $return); |
|||
system("sudo rm ".RASPI_OPENVPN_CLIENT_LOGIN, $return); |
|||
system("sudo ln -s $ovpncfg_login ".RASPI_OPENVPN_CLIENT_LOGIN, $return); |
|||
|
|||
// restart service
|
|||
exec("sudo /bin/systemctl stop openvpn-client@client", $return); |
|||
sleep(1); |
|||
exec("sudo /bin/systemctl enable openvpn-client@client", $return); |
|||
sleep(1); |
|||
exec("sudo /bin/systemctl start openvpn-client@client", $return); |
|||
|
|||
echo json_encode($return); |
|||
} |
|||
|
@ -0,0 +1,13 @@ |
|||
<?php |
|||
|
|||
require_once '../../includes/config.php'; |
|||
require_once '../../includes/functions.php'; |
|||
|
|||
if (isset($_POST['cfg_id'])) { |
|||
$ovpncfg_id = $_POST['cfg_id']; |
|||
$ovpncfg_files = pathinfo(RASPI_OPENVPN_CLIENT_LOGIN, PATHINFO_DIRNAME).'/'.$ovpncfg_id.'_*.conf'; |
|||
exec("sudo rm $ovpncfg_files", $return); |
|||
$jsonData = ['return'=>$return]; |
|||
echo json_encode($jsonData); |
|||
} |
|||
|
@ -0,0 +1,28 @@ |
|||
<?php |
|||
|
|||
require_once '../../includes/config.php'; |
|||
require_once '../../includes/defaults.php'; |
|||
require_once '../../includes/functions.php'; |
|||
|
|||
// prevent direct file access
|
|||
if (!isset($_SERVER['HTTP_REFERER'])) { |
|||
header('HTTP/1.0 403 Forbidden'); |
|||
exit; |
|||
} |
|||
|
|||
exec("sudo cat " .RASPI_WIREGUARD_PATH.'client.conf', $return); |
|||
$peer_conf = implode(PHP_EOL,$return); |
|||
$peer_conf.= PHP_EOL; |
|||
$command = "qrencode -t svg -m 0 -o - " . mb_escapeshellarg($peer_conf); |
|||
$svg = shell_exec($command); |
|||
$etag = hash('sha256', $peer_conf); |
|||
$content_length = strlen($svg); |
|||
$last_modified = date("Y-m-d H:i:s"); |
|||
|
|||
header("Content-Type: image/svg+xml"); |
|||
header("Content-Length: $content_length"); |
|||
header("Last-Modified: $last_modified"); |
|||
header("ETag: \"$etag\"");
|
|||
header("X-QR-Code-Content: $peer_conf"); |
|||
echo shell_exec($command); |
|||
|
@ -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); |
|||
} |
|||
} |
|||
|
@ -1,4 +1,4 @@ |
|||
# RaspAP default config |
|||
log-facility=/tmp/dnsmasq.log |
|||
log-facility=/var/log/dnsmasq.log |
|||
conf-dir=/etc/dnsmasq.d |
|||
|
@ -0,0 +1,4 @@ |
|||
# mobile data modem - ttyUSB0 device appears |
|||
SUBSYSTEM=="tty", KERNEL=="ttyUSB0", TAG+="systemd", ENV{SYSTEMD_WANTS}="start start_ppp0_device.service" |
|||
|
|||
|
@ -0,0 +1,3 @@ |
|||
SUBSYSTEM=="net", ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="14db", NAME="hilink%n", TAG+="systemd", ENV{SYSTEMD_WANTS}="start start_huawei_hilink@hilink%n.service" |
|||
|
|||
|
@ -0,0 +1,505 @@ |
|||
#!/bin/bash |
|||
# |
|||
# Huawei Hilink API |
|||
# ================= |
|||
# - communication with Hilink devices via HTTP |
|||
# - send a standard http request with a xml formatted string to the device (default IP 192.169.8.1) |
|||
# - Howto: |
|||
# o "source" this script in your own script from the command line |
|||
# o if hilink_host ip/name differs, set "hilink_host=192.168.178.1" before calling any function |
|||
# o if the device is locked by a password, set hilink_user="admin"; hilink_password"1234secret" |
|||
# _login is called automatically |
|||
# only password type 4 is supported |
|||
# o if the SIM is requiring a PIN, set "hilink_pin=1234" |
|||
# o connect device to network: _switchMobileData ON ( or 1 ) |
|||
# o disconnect device: _switchMobileData OFF ( or 0 ) |
|||
# o get informations about the device: _getDeviceInformation and _getStatus and _getNetProvider |
|||
# all functions return XML formatted data in $response. |
|||
# o _getAllInformations: returns all available informations as key/value pairs (outputs text) |
|||
# o Check if device is connected: "if _isConnected; then .... fi" |
|||
# o $response can be parsed by calling _valueFromResponse |
|||
# e.g "_valueFromResponse msisdn" to get the phone number after a call to _getDeviceInformation |
|||
# |
|||
# |
|||
# Usage of functions |
|||
# - call the function with parameters (if required) |
|||
# - return code: 0 - success; 1 - failed |
|||
# - $status: status information (OK, ERROR) |
|||
# - $response: xml response to be parsed for the required information |
|||
# |
|||
# |
|||
# required software: curl, base64, sha256sum, sed |
|||
# |
|||
# ToDo: improve error handling |
|||
# |
|||
# zbchristian 2021 |
|||
# |
|||
|
|||
# Initialization procedure |
|||
# ======================== |
|||
# |
|||
# hilink_host=192.168.8.1 # ip address of device |
|||
# hilink_user="admin" # user name if locked (default admin) |
|||
# hilink_password="1234Secret" # password if locked |
|||
# hilink_pin="1234" # PIN of SIM |
|||
# _initHilinkAPI # initialize the API |
|||
# |
|||
# Termination |
|||
# =========== |
|||
# cleanup the API before quitting the shell |
|||
# _closeHilinkAPI (optional: add parameter "save" to save the session/token data for subsequent calls. Valid for a few minutes.) |
|||
# |
|||
# BE AWARE, THAT THE API USES SOME GLOBAL VARIABLES : hilink_host, user, password, pin, response, status |
|||
# USE THESE ONLY TO COMMUNICATE WITH THE API. |
|||
# DO NOT USE THE VARIABLE PRE_FIX "hilink_" FOR YOUR OWN VARIABLES |
|||
# |
|||
|
|||
hilink_host_default="192.168.8.1" |
|||
hilink_save_file="/tmp/hilink_api_saved.dat" |
|||
hilink_save_age=60 |
|||
hilink_header_file="/tmp/hilink_login_hdr.txt" |
|||
|
|||
# initialize |
|||
function _initHilinkAPI() { |
|||
local age |
|||
if [ -z "$hilink_host" ]; then hilink_host=$hilink_host_default; fi |
|||
if ! _hostReachable; then return 1; fi |
|||
if [ -f $hilink_save_file ]; then # found file with saved data |
|||
_getSavedData |
|||
age=$(( $(date +%s) - $(stat $hilink_save_file -c %Y) )) |
|||
if [[ $age -gt $hilink_save_age ]]; then |
|||
rm -f $hilink_save_file |
|||
_logout |
|||
_sessToken |
|||
fi |
|||
fi |
|||
if [ -z "$hilink_sessID" ] || [ -z "$hilink_token" ]; then _sessToken; fi |
|||
_login |
|||
return $? |
|||
} |
|||
|
|||
function _getSavedData() { |
|||
local dat |
|||
if [ -f $hilink_save_file ]; then # restore saved session data |
|||
dat=$(cat $hilink_save_file) |
|||
hilink_sessID=$(echo "$dat" | sed -nr 's/sessionid: ([a-z0-9]*)/\1/ip') |
|||
hilink_token=$(echo "$dat" | sed -nr 's/token: ([a-z0-9]*)/\1/ip') |
|||
hilink_tokenlist=( $(echo "$dat" | sed -nr 's/tokenlist: ([a-z0-9 ]*)/\1/ip') ) |
|||
fi |
|||
} |
|||
|
|||
# Cleanup |
|||
# parameter: "save" - will store sessionid and tokens in file |
|||
function _closeHilinkAPI() { |
|||
local opt |
|||
if [ -z "$hilink_host" ]; then hilink_host=$hilink_host_default; fi |
|||
if ! _hostReachable; then return 1; fi |
|||
rm -f $hilink_save_file |
|||
[ ! -z "$1" ] && opt="${1,,}" |
|||
if [ ! -z "$opt" ] && [ "$opt" = "save" ]; then |
|||
echo "sessionid: $hilink_sessID" > $hilink_save_file |
|||
echo "token: $hilink_token" >> $hilink_save_file |
|||
echo "tokenlist: ${hilink_tokenlist[@]}" >> $hilink_save_file |
|||
fi |
|||
_logout |
|||
hilink_tokenlist="" |
|||
hilink_sessID="" |
|||
hilink_token="" |
|||
return 0 |
|||
} |
|||
|
|||
# get status (connection status, DNS, ) |
|||
# parameter: none |
|||
function _getStatus() { |
|||
if _login; then |
|||
if _sendRequest "api/monitoring/status"; then |
|||
if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi |
|||
fi |
|||
return $? |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
function _isConnected() { |
|||
local conn |
|||
conn=$(_getStatus "connectionstatus") |
|||
status="NO" |
|||
if [ ! -z "$conn" ] && [ $conn -eq 901 ]; then |
|||
status="YES" |
|||
return 0 |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# get device information (device name, imei, imsi, msisdn-phone number, MAC, WAN IP ...) |
|||
# parameter: name of parameter to return |
|||
function _getDeviceInformation() { |
|||
if _login; then |
|||
if _sendRequest "api/device/information"; then |
|||
if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi |
|||
fi |
|||
return $? |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# get net provider information |
|||
# parameter: name of parameter to return |
|||
function _getNetProvider() { |
|||
if _login; then |
|||
if _sendRequest "api/net/current-plmn"; then |
|||
if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi |
|||
fi |
|||
return $? |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# get signal level |
|||
# parameter: name of parameter to return |
|||
function _getSignal() { |
|||
if _login; then |
|||
if _sendRequest "api/device/signal"; then |
|||
if [ ! -z "$1" ]; then _valueFromResponse "$1"; fi |
|||
fi |
|||
return $? |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
function _getAllInformations() { |
|||
if _getDeviceInformation; then _keyValuePairs; fi |
|||
if _getSignal; then _keyValuePairs; fi |
|||
if _getNetProvider; then _keyValuePairs; fi |
|||
} |
|||
|
|||
# get status of mobile data connection |
|||
# parameter: none |
|||
function _getMobileDataStatus() { |
|||
if _login; then |
|||
if _sendRequest "api/dialup/mobile-dataswitch"; then |
|||
status=$(_valueFromResponse "dataswitch") |
|||
if [ $? -eq 0 ] && [ ! -z "$status" ]; then echo "$status"; fi |
|||
fi |
|||
return $? |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
|
|||
# PIN of SIM can be passed either as $hilink_pin, or as parameter |
|||
# parameter: PIN number of SIM card |
|||
function _enableSIM() { |
|||
#SimState: |
|||
#255 - no SIM, |
|||
#256 - error CPIN, |
|||
#257 - ready, |
|||
#258 - PIN disabled, |
|||
#259 - check PIN, |
|||
#260 - PIN required, |
|||
#261 - PUK required |
|||
local simstate |
|||
if [ ! -z "$1" ]; then hilink_pin="$1"; fi |
|||
if ! _login; then return 1; fi |
|||
if _sendRequest "api/pin/status"; then |
|||
simstate=$(echo $response | sed -rn 's/.*<simstate>([0-9]*)<\/simstate>.*/\1/pi') |
|||
if [[ $simstate -eq 257 ]]; then status="SIM ready"; return 0; fi |
|||
if [[ $simstate -eq 260 ]]; then |
|||
status="PIN required" |
|||
if [ ! -z "$hilink_pin" ]; then _setPIN "$hilink_pin"; fi |
|||
return $? |
|||
fi |
|||
if [[ $simstate -eq 255 ]]; then status="NO SIM"; return 1; fi |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# obtain session and verification token - stored in vars $hilink_sessID and $token |
|||
# parameter: none |
|||
function _sessToken() { |
|||
hilink_tokenlist="" |
|||
hilink_token="" |
|||
hilink_sessID="" |
|||
response=$(curl -s http://$hilink_host/api/webserver/SesTokInfo -m 5 2> /dev/null) |
|||
if [ -z "$response" ]; then echo "No access to device at $hilink_host"; return 1; fi |
|||
status=$(echo "$response" | sed -nr 's/.*<code>([0-9]*)<\/code>.*/\1/ip') |
|||
if [ -z "$status" ]; then |
|||
hilink_token=$(echo $response | sed -r 's/.*<TokInfo>(.*)<\/TokInfo>.*/\1/') |
|||
hilink_sessID=$(echo $response | sed -r 's/.*<SesInfo>(.*)<\/SesInfo>.*/\1/') |
|||
if [ ! -z "$hilink_sessID" ] && [ ! -z "$hilink_token" ]; then |
|||
hilink_sessID="SessionID=$hilink_sessID" |
|||
return 0 |
|||
fi |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# unlock device (if locked) with user name and password |
|||
# requires stored hilink_user="admin"; hilink_password"1234secret";hilink_host=$hilink_host_default |
|||
# parameter: none |
|||
function _login() { |
|||
local ret encpw pwtype pwtype3 hashedpw pwtype4 |
|||
if _loginState; then return 0; fi # login not required, or already done |
|||
_sessToken |
|||
# get password type |
|||
if ! _sendRequest "api/user/state-login"; then return 1; fi |
|||
pwtype=$(echo "$response" | sed -rn 's/.*<password_type>([0-9])<\/password_type>.*/\1/pi') |
|||
if [ -z "$pwtype" ];then pwtype=4; fi # fallback is type 4 |
|||
ret=1 |
|||
if [[ ! -z "$hilink_user" ]] && [[ ! -z "$hilink_password" ]]; then |
|||
# password encoding |
|||
# type 3 : base64(pw) encoded |
|||
# type 4 : base64(sha256sum(user + base64(sha256sum(pw)) + token)) |
|||
pwtype3=$(echo -n "$hilink_password" | base64 --wrap=0) |
|||
hashedpw=$(echo -n "$hilink_password" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) |
|||
hashedpw=$(echo -n "$hashedpw" | base64 --wrap=0) |
|||
pwtype4=$(echo -n "$hilink_user$hashedpw$hilink_token" | sha256sum -b | sed -nr 's/^([0-9a-z]*).*$/\1/ip' ) |
|||
encpw=$(echo -n "$pwtype4" | base64 --wrap=0) |
|||
if [ $pwtype -ne 4 ]; then encpw=$pwtype3; fi |
|||
hilink_xmldata="<?xml version='1.0' encoding='UTF-8'?><request><Username>$hilink_user</Username><Password>$encpw</Password><password_type>$pwtype</password_type></request>" |
|||
hilink_xtraopts="--dump-header $hilink_header_file" |
|||
rm -f $hilink_header_file |
|||
_sendRequest "api/user/login" |
|||
if [ ! -z "$status" ] && [ "$status" = "OK" ]; then |
|||
# store the list of 30 tokens. Each token is valid for a single request |
|||
hilink_tokenlist=( $(cat $hilink_header_file | sed -rn 's/^__RequestVerificationToken:\s*([0-9a-z#]*).*$/\1/pi' | sed 's/#/ /g') ) |
|||
_getToken |
|||
hilink_sessID=$(cat $hilink_header_file | grep -ioP 'SessionID=([a-z0-9]*)') |
|||
if [ ! -z "$hilink_sessID" ] && [ ! -z "$hilink_token" ]; then ret=0; fi |
|||
fi |
|||
rm -f $hilink_header_file |
|||
fi |
|||
return $ret |
|||
} |
|||
|
|||
# logout of hilink device |
|||
# parameter: none |
|||
function _logout() { |
|||
if _loginState; then |
|||
hilink_xmldata="<?xml version: '1.0' encoding='UTF-8'?><request><Logout>1</Logout></request>" |
|||
if _sendRequest "api/user/logout"; then |
|||
hilink_tokenlist="" |
|||
hilink_sessID="" |
|||
hilink_token="" |
|||
hilink_login_enabled="" |
|||
fi |
|||
return $? |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# parameter: none |
|||
function _loginState() { |
|||
local state |
|||
status="OK" |
|||
if [ -z "$hilink_login_enabled" ]; then _checkLoginEnabled; fi |
|||
if [ $hilink_login_enabled -eq 1 ]; then return 0; fi # login is disabled |
|||
_sendRequest "api/user/state-login" |
|||
state=`echo "$response" | sed -rn 's/.*<state>(.*)<\/state>.*/\1/pi'` |
|||
if [ ! -z "$state" ] && [ $state -eq 0 ]; then # already logged in |
|||
return 0 |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
function _checkLoginEnabled() { |
|||
local state |
|||
if _sendRequest "api/user/hilink_login"; then |
|||
hilink_login_enabled=0 |
|||
state=$(echo $response | sed -rn 's/.*<hilink_login>(.*)<\/hilink_login>.*/\1/pi') |
|||
if [ ! -z "$state" ] && [ $state -eq 0 ]; then # no login enabled |
|||
hilink_login_enabled=1 |
|||
fi |
|||
else |
|||
hilink_login_enabled="" |
|||
fi |
|||
} |
|||
|
|||
# switch mobile data on/off 1/0 |
|||
# if SIM is locked, $hilink_pin has to be set |
|||
# parameter: state - ON/OFF or 1/0 |
|||
function _switchMobileData() { |
|||
local mode |
|||
if [ -z "$1" ]; then return 1; fi |
|||
_login |
|||
mode="${1,,}" |
|||
[ "$mode" = "on" ] && mode=1 |
|||
[ "$mode" = "off" ] && mode=0 |
|||
if [[ $mode -ge 0 ]]; then |
|||
if _enableSIM "$hilink_pin"; then |
|||
hilink_xmldata="<?xml version: '1.0' encoding='UTF-8'?><request><dataswitch>$mode</dataswitch></request>" |
|||
_sendRequest "api/dialup/mobile-dataswitch" |
|||
return $? |
|||
fi |
|||
fi |
|||
return 1 |
|||
} |
|||
|
|||
# parameter: PIN of SIM card |
|||
function _setPIN() { |
|||
local pin |
|||
if [ -z "$1" ]; then return 1; fi |
|||
pin="$1" |
|||
hilink_xmldata="<?xml version: '1.0' encoding='UTF-8'?><request><OperateType>0</OperateType><CurrentPin>$pin</CurrentPin><NewPin></NewPin><PukCode></PukCode></request>" |
|||
_sendRequest "api/pin/operate" |
|||
return $? |
|||
} |
|||
|
|||
# Send request to host at http://$hilink_host/$apiurl |
|||
# data in $hilink_xmldata and options in $hilink_xtraopts |
|||
# parameter: apiurl (e.g. "api/user/login") |
|||
function _sendRequest() { |
|||
local ret apiurl |
|||
status="ERROR" |
|||
if [ -z "$1" ]; then return 1; fi |
|||
apiurl="$1" |
|||
ret=1 |
|||
if [ -z "$hilink_sessID" ] || [ -z "$hilink_token" ]; then _sessToken; fi |
|||
if [ -z "$hilink_xmldata" ];then |
|||
response=$(curl -s http://$hilink_host/$apiurl -m 10 \ |
|||
-H "Cookie: $hilink_sessID") |
|||
else |
|||
response=$(curl -s -X POST http://$hilink_host/$apiurl -m 10 \ |
|||
-H "Content-Type: text/xml" \ |
|||
-H "Cookie: $hilink_sessID" \ |
|||
-H "__RequestVerificationToken: $hilink_token" \ |
|||
-d "$hilink_xmldata" $hilink_xtraopts 2> /dev/null) |
|||
_getToken |
|||
fi |
|||
if [ ! -z "$response" ];then |
|||
response=$(echo $response | tr -d '\012\015') # delete newline chars |
|||
status=$(echo "$response" | sed -nr 's/.*<code>([0-9]*)<\/code>.*/\1/ip') # check for error code |
|||
if [ -z "$status" ]; then |
|||
status="OK" |
|||
response=$(echo "$response" | sed -nr 's/.*<response>(.*)<\/response>.*/\1/ip') |
|||
[ -z "$response" ] && response="none" |
|||
ret=0 |
|||
else |
|||
status="ERROR $status" |
|||
fi |
|||
else |
|||
status="ERROR" |
|||
fi |
|||
if [[ "$status" =~ ERROR ]]; then _handleError; fi |
|||
hilink_xtraopts="" |
|||
hilink_xmldata="" |
|||
return $ret |
|||
} |
|||
|
|||
# handle the list of tokens available after login |
|||
# parameter: none |
|||
function _getToken() { |
|||
if [ ! -z "$hilink_tokenlist" ] && [ ${#hilink_tokenlist[@]} -gt 0 ]; then |
|||
hilink_token |