diff --git a/app/css/hackernews.css b/app/css/hackernews.css index 1dbb2e97..f2c68cbf 100644 --- a/app/css/hackernews.css +++ b/app/css/hackernews.css @@ -75,6 +75,9 @@ h5.card-title { font-family: Verdana, Geneva, sans-serif; } +.sidebar-light hr.sidebar-divider { + padding-top: 0.5rem; +} ul.nav-tabs, .nav-tabs .nav-link { background-color: #f6f6ef; @@ -154,6 +157,7 @@ ul.nav-tabs, .nav-tabs .nav-link { .info-item-xs { font-size: 0.7rem; margin-left: 0.3rem; + line-height: 1.5em; } .info-item-wifi { @@ -190,6 +194,10 @@ ul.nav-tabs, .nav-tabs .nav-link { } } +.fas.fa-circle { + font-size: 0.5rem; +} + .logoutput { width:100%; height:300px; diff --git a/config/config.php b/config/config.php index 2c476b57..0aeddbdb 100755 --- a/config/config.php +++ b/config/config.php @@ -21,6 +21,7 @@ define('RASPI_WPA_CTRL_INTERFACE', '/var/run/wpa_supplicant'); define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf'); define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf'); define('RASPI_OPENVPN_SERVER_CONFIG', '/etc/openvpn/server/server.conf'); +define('RASPI_WIREGUARD_CONFIG', '/etc/wireguard/wg0.conf'); define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc'); define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf'); define('RASPI_ACCESS_CHECK_IP', '1.1.1.1'); @@ -37,6 +38,7 @@ define('RASPI_NETWORK_ENABLED', true); define('RASPI_DHCP_ENABLED', true); define('RASPI_ADBLOCK_ENABLED', false); define('RASPI_OPENVPN_ENABLED', false); +define('RASPI_WIREGUARD_ENABLED', false); define('RASPI_TORPROXY_ENABLED', false); define('RASPI_CONFAUTH_ENABLED', true); define('RASPI_CHANGETHEME_ENABLED', true); diff --git a/dist/raspap/css/fonts/RaspAP.eot b/dist/raspap/css/fonts/RaspAP.eot new file mode 100755 index 00000000..d77690f6 Binary files /dev/null and b/dist/raspap/css/fonts/RaspAP.eot differ diff --git a/dist/raspap/css/fonts/RaspAP.svg b/dist/raspap/css/fonts/RaspAP.svg new file mode 100755 index 00000000..27920e40 --- /dev/null +++ b/dist/raspap/css/fonts/RaspAP.svg @@ -0,0 +1,12 @@ + + + +Generated by IcoMoon + + + + + + + + \ No newline at end of file diff --git a/dist/raspap/css/fonts/RaspAP.ttf b/dist/raspap/css/fonts/RaspAP.ttf new file mode 100755 index 00000000..11221442 Binary files /dev/null and b/dist/raspap/css/fonts/RaspAP.ttf differ diff --git a/dist/raspap/css/fonts/RaspAP.woff b/dist/raspap/css/fonts/RaspAP.woff new file mode 100755 index 00000000..875f0253 Binary files /dev/null and b/dist/raspap/css/fonts/RaspAP.woff differ diff --git a/dist/raspap/css/style.css b/dist/raspap/css/style.css new file mode 100644 index 00000000..45305ca1 --- /dev/null +++ b/dist/raspap/css/style.css @@ -0,0 +1,54 @@ + /*! + * RaspAP-Brands Brand Icons - https://raspap.com + * License - https://github.com/billz/RaspAP-Brands-webgui/blob/master/LICENSE + */ +@font-face { + font-family: 'RaspAP'; + src: url('fonts/RaspAP.eot?e76qs3'); + src: url('fonts/RaspAP.eot?e76qs3#iefix') format('embedded-opentype'), + url('fonts/RaspAP.ttf?e76qs3') format('truetype'), + url('fonts/RaspAP.woff?e76qs3') format('woff'), + url('fonts/RaspAP.svg?e76qs3#RaspAP') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +[class^="ra-"], [class*=" ra-"] { + /* use !important to prevent issues with browser extensions that change ..webfonts */ + font-family: 'RaspAP' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.ra-wireguard:before { + font-size: 1.2rem; + content: "\e900"; + color: #d1d3e2; + vertical-align: middle; +} + +.card-header .ra-wireguard:before { + color: #fff; +} + +.sidebar .nav-item.active .nav-link +span.ra-wireguard:before { + color: #6e707e; +} + +.ra-raspap:before { + font-size: 4.35rem; + content: "\e901"; + color: #d8224c; + margin-left: 0.1em; +} + diff --git a/includes/defaults.php b/includes/defaults.php index 93aa2df3..17a4af39 100755 --- a/includes/defaults.php +++ b/includes/defaults.php @@ -26,6 +26,7 @@ $defaults = [ 'RASPI_OPENVPN_CLIENT_CONFIG' => '/etc/openvpn/client/client.conf', 'RASPI_OPENVPN_CLIENT_LOGIN' => '/etc/openvpn/client/login.conf', 'RASPI_OPENVPN_SERVER_CONFIG' => '/etc/openvpn/server/server.conf', + 'RASPI_WIREGUARD_CONFIG' => '/etc/wireguard/wg0.conf', 'RASPI_TORPROXY_CONFIG' => '/etc/tor/torrc', 'RASPI_LIGHTTPD_CONFIG' => '/etc/lighttpd/lighttpd.conf', 'RASPI_ACCESS_CHECK_IP' => '1.1.1.1', @@ -42,6 +43,7 @@ $defaults = [ 'RASPI_DHCP_ENABLED' => true, 'RASPI_ADBLOCK_ENABLED' => false, 'RASPI_OPENVPN_ENABLED' => false, + 'RASPI_WIREGUARD_ENABLED' => false, 'RASPI_TORPROXY_ENABLED' => false, 'RASPI_CONFAUTH_ENABLED' => true, 'RASPI_CHANGETHEME_ENABLED' => true, diff --git a/includes/functions.php b/includes/functions.php index 1ca27d7d..183f1552 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -715,6 +715,33 @@ function getBridgedState() return $arrHostapdConf['BridgedEnable']; } +/** + * Validates the format of a CIDR notation string + * + * @param string $cidr + * @return bool + */ +function validateCidr($cidr) +{ + $parts = explode('/', $cidr); + if(count($parts) != 2) { + return false; + } + $ip = $parts[0]; + $netmask = intval($parts[1]); + + if($netmask < 0) { + return false; + } + if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + return $netmask <= 32; + } + if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + return $netmask <= 128; + } + return false; +} + // Validates a host or FQDN function validate_host($host) { return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host); diff --git a/includes/wireguard.php b/includes/wireguard.php new file mode 100644 index 00000000..84956b89 --- /dev/null +++ b/includes/wireguard.php @@ -0,0 +1,136 @@ + 5 || !is_numeric($_POST['wg_port'])) { + $status->addMessage('Invalid value for port number', 'danger'); + $good_input = false; + } + } + if (isset($_POST['wg_ipaddress'])) { + if (!validateCidr($_POST['wg_ipaddress'])) { + $status->addMessage('Invalid value for IP address', 'danger'); + $good_input = false; + } + } + if (isset($_POST['wg_endpoint']) && strlen(trim($_POST['wg_endpoint']) >0 )) { + if (!validateCidr($_POST['wg_endpoint'])) { + $status->addMessage('Invalid value for endpoint address', 'danger'); + $good_input = false; + } + } + if (isset($_POST['wg_allowedips'])) { + if (!validateCidr($_POST['wg_allowedips'])) { + $status->addMessage('Invalid value for allowed IPs', 'danger'); + $good_input = false; + } + } + if (isset($_POST['wg_pkeepalive']) && strlen(trim($_POST['wg_pkeepalive']) >0 )) { + if (strlen($_POST['wg_pkeepalive']) > 4 || !is_numeric($_POST['wg_pkeepalive'])) { + $status->addMessage('Invalid value for persistent keepalive', 'danger'); + $good_input = false; + } + } + // Save settings + if ($good_input) { + $config[] = '[Interface]'; + $config[] = 'Address = '.$_POST['wg_ipaddress']; + $config[] = 'ListenPort = '.$_POST['wg_port']; + $config[] = ''; + $config[] = 'PrivateKey = '.$_POST['wg_privkey']; + $config[] = 'PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE'; + $config[] = 'PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE'; + $config[] = ''; + $config[] = '[Peer]'; + $config[] = 'PublicKey = '.$_POST['wg_pubkey']; + if ($_POST['wg_endpoint'] !== '') { + $config[] = 'Endpoint = '.trim($_POST['wg_endpoint']); + } + $config[] = 'AllowedIPs = '.$_POST['wg_allowedips']; + if ($_POST['wg_pkeepalive'] !== '') { + $config[] = 'PersistentKeepalive = '.trim($_POST['wg_pkeepalive']); + } + $config[] = ''; + $config = join(PHP_EOL, $config); + + file_put_contents("/tmp/wgdata", $config); + system('sudo cp /tmp/wgdata '.RASPI_WIREGUARD_CONFIG, $return); + + // handle log option + if ($_POST['wg_log'] == "1") { + exec("sudo /bin/systemctl status wg-quick@wg0 | sudo tee /tmp/wireguard.log > /dev/null"); + } + foreach ($return as $line) { + $status->addMessage($line, 'info'); + } + if ($return == 0) { + $status->addMessage('Wireguard configuration updated successfully', 'success'); + } else { + $status->addMessage('Wireguard configuration failed to be updated.', 'danger'); + } + } + + } elseif (isset($_POST['startwg'])) { + $status->addMessage('Attempting to start WireGuard', 'info'); + exec('sudo /usr/bin/wg-quick up wg0', $return); + foreach ($return as $line) { + $status->addMessage($line, 'info'); + } + } elseif (isset($_POST['stopwg'])) { + $status->addMessage('Attempting to stop WireGuard', 'info'); + exec('sudo /usr/bin/wg-quick down wg0', $return); + foreach ($return as $line) { + $status->addMessage($line, 'info'); + } + } + } + + // fetch wg config + exec('sudo cat '. RASPI_WIREGUARD_CONFIG, $return); + $conf = ParseConfig($return); + $wg_port = $conf['ListenPort']; + $wg_ipaddress = $conf['Address']; + $wg_pubkey = $conf['PublicKey']; + $wg_privkey = $conf['PrivateKey']; + $wg_endpoint = $conf['Endpoint']; + $wg_allowedips = $conf['AllowedIPs']; + $wg_pkeepalive = $conf['PersistentKeepalive']; + + // fetch service status + exec('pidof wg-crypt-wg0 | wc -l', $wgstatus); + $serviceStatus = $wgstatus[0] == 0 ? "down" : "up"; + $wg_state = ($wgstatus[0] > 0); + + echo renderTemplate( + "wireguard", compact( + "status", + "wg_state", + "serviceStatus", + "wg_log", + "endpoint_enable", + "peer_id", + "wg_port", + "wg_ipaddress", + "wg_pubkey", + "wg_privkey", + "wg_endpoint", + "wg_allowedips", + "wg_pkeepalive" + ) + ); +} + diff --git a/index.php b/index.php index 026fde00..8f03521f 100755 --- a/index.php +++ b/index.php @@ -45,6 +45,7 @@ require_once 'includes/themes.php'; require_once 'includes/data_usage.php'; require_once 'includes/about.php'; require_once 'includes/openvpn.php'; +require_once 'includes/wireguard.php'; require_once 'includes/torproxy.php'; $config = getConfig(); @@ -82,6 +83,9 @@ $bridgedEnabled = getBridgedState(); + + + @@ -161,6 +165,11 @@ $bridgedEnabled = getBridgedState(); + + + @@ -259,6 +268,9 @@ $bridgedEnabled = getBridgedState(); case "/openvpn_conf": DisplayOpenVPNConfig(); break; + case "/wg_conf": + DisplayWireGuardConfig(); + break; case "/torproxy_conf": DisplayTorProxyConfig(); break; diff --git a/installers/common.sh b/installers/common.sh index fc7fea58..403187b5 100755 --- a/installers/common.sh +++ b/installers/common.sh @@ -297,6 +297,47 @@ function _prompt_install_openvpn() { fi } +# Prompt to install WireGuard +function _prompt_install_wireguard() { + _install_log "Configure WireGuard support" + echo -n "Install WireGuard and enable VPN tunnel configuration? [Y/n]: " + if [ "$assume_yes" == 0 ]; then + read answer < /dev/tty + if [ "$answer" != "${answer#[Nn]}" ]; then + echo -e + else + _install_wireguard + fi + elif [ "$wg_option" == 1 ]; then + _install_wireguard + else + echo "(Skipped)" + fi +} + +# Install Wireguard from the Debian unstable distro +function _install_wireguard() { + _install_log "Configure WireGuard support" + if [ "$OS" == "Raspbian" ]; then + echo "Installing raspberrypi-kernel-headers" + sudo apt-get install $apt_option raspberrypi-kernel-headers || _install_status 1 "Unable to install raspberrypi-kernel-headers" + fi + echo "Installing WireGuard from Debian unstable distro" + echo "Adding Debian distro" + echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee --append /etc/apt/sources.list.d/unstable.list || _install_status 1 "Unable to append to sources.list" + sudo apt-get install dirmngr || _install_status 1 "Unable to install dirmngr" + echo "Adding Debian distro keys" + sudo wget -q -O - https://ftp-master.debian.org/keys/archive-key-$(lsb_release -sr).asc | sudo apt-key add - || _install_status 1 "Unable to add keys" + printf 'Package: *\nPin: release a=unstable\nPin-Priority: 150\n' | sudo tee --append /etc/apt/preferences.d/limit-unstable || _install_status 1 "Unable to append to preferences.d" + echo "Installing WireGuard" + sudo apt-get update && sudo apt-get install $apt_option wireguard || _install_status 1 "Unable to install wireguard" + echo "Enabling wg-quick@wg0" + sudo systemctl enable wg-quick@wg0 || _install_status 1 "Failed to enable wg-quick service" + echo "Enabling WireGuard management option" + sudo sed -i "s/\('RASPI_WIREGUARD_ENABLED', \)false/\1true/g" "$webroot_dir/includes/config.php" || _install_status 1 "Unable to modify config.php" + _install_status 0 +} + # Install openvpn and enable client configuration option function _install_openvpn() { _install_log "Installing OpenVPN and enabling client configuration" diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index 49d4032b..19b9a7a8 100644 --- a/installers/raspap.sudoers +++ b/installers/raspap.sudoers @@ -39,7 +39,15 @@ www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/configauth.sh www-data ALL=(ALL) NOPASSWD:/etc/raspap/openvpn/openvpnlog.sh www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/hostapd.log www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/dnsmasq.log +www-data ALL=(ALL) NOPASSWD:/bin/chmod o+r /tmp/wireguard.log www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dnsmasqdata /etc/dnsmasq.d/090_adblock.conf 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/wg0.conf www-data ALL=(ALL) NOPASSWD:/etc/raspap/adblock/update_blocklist.sh +www-data ALL=(ALL) NOPASSWD:/usr/bin/tee /tmp/wireguard.log +www-data ALL=(ALL) NOPASSWD:/bin/systemctl status wg-quick@wg0 +www-data ALL=(ALL) NOPASSWD:/usr/bin/wg-quick up wg0 +www-data ALL=(ALL) NOPASSWD:/usr/bin/wg-quick down wg0 +www-data ALL=(ALL) NOPASSWD:/usr/bin/wg +www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wireguard/wg0.conf diff --git a/templates/wg/general.php b/templates/wg/general.php new file mode 100644 index 00000000..aa1de796 --- /dev/null +++ b/templates/wg/general.php @@ -0,0 +1,47 @@ + +
+
+
+

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

+ +

+
+
+
+ + +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+
+ +
+
+
+ diff --git a/templates/wg/logging.php b/templates/wg/logging.php new file mode 100644 index 00000000..c9cb4185 --- /dev/null +++ b/templates/wg/logging.php @@ -0,0 +1,19 @@ + +
+
+
+

+
+ aria-describedby="wg_log"> + +
+

+ '.htmlspecialchars($log, ENT_QUOTES).''; + ?> +
+
+
+ diff --git a/templates/wg/peers.php b/templates/wg/peers.php new file mode 100644 index 00000000..16337a08 --- /dev/null +++ b/templates/wg/peers.php @@ -0,0 +1,54 @@ + +
+ +
+
+

+
+ + +
+ aria-describedby="endpoint-description"> + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+ + +
+
+
+ + +
+
+
+ diff --git a/templates/wireguard.php b/templates/wireguard.php new file mode 100644 index 00000000..3ead09c7 --- /dev/null +++ b/templates/wireguard.php @@ -0,0 +1,53 @@ + + + "> + + "> + + "> + + + + +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ showMessages(); ?> +
+ + + + + +
+ + + +
+ + +
+
+ +
+
+
+