mirror of
https://github.com/billz/raspap-webgui.git
synced 2023-10-10 13:37:24 +02:00
Compare commits
No commits in common. "master" and "2.5.2" have entirely different histories.
5
.github/FUNDING.yml
vendored
5
.github/FUNDING.yml
vendored
@ -1,2 +1,3 @@
|
|||||||
github: RaspAP
|
github: billz
|
||||||
|
open_collective: raspap
|
||||||
|
custom: ["https://paypal.me/billzgithub"]
|
||||||
|
70
.github/ISSUE_TEMPLATE/bug_report.md
vendored
70
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -7,53 +7,39 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- These comments will NOT appear in your issue, so it's OK to ignore them -->
|
**Before submitting an issue**
|
||||||
<!--
|
Please read this first https://github.com/billz/raspap-webgui/wiki/Reporting-issues
|
||||||
Thanks for reporting a bug for RaspAP.
|
|
||||||
|
|
||||||
Important: If you are NOT using a clean installation of a compatible OS, start with a fresh SD card, install RaspAP and replicate your bug BEFORE reporting an issue.
|
* [x] This is a bug report
|
||||||
|
* [ ] I searched existing issues before opening this one
|
||||||
|
* [ ] I checked the FAQ before creating this issue
|
||||||
|
* [ ] I have read and understand the issue reporting guidelines
|
||||||
|
|
||||||
All submitters MUST read the issue policy and reporting guidelines:
|
**Describe the bug**
|
||||||
https://docs.raspap.com/issues/
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
Refer to the frequently asked questions (FAQ) and official documentation:
|
**Your environment**
|
||||||
https://docs.raspap.com/faq/
|
* Raspberry Pi hardware (examples: Pi 3 Model B+, Pi Zero W)
|
||||||
|
* Raspbian version (examples: Buster Lite, Buster Desktop)
|
||||||
|
* Followed the project prerequisites? (Y/N)
|
||||||
|
* Checked the project FAQ? (Y/N)
|
||||||
|
* RaspAP Quick Install or Manual setup?
|
||||||
|
* Using default configuration? (Y/N)
|
||||||
|
* Simultaneous AP and managed mode? (Y/N)
|
||||||
|
* Onboard wireless chipset or external adapter?
|
||||||
|
* Other software or services running with RaspAP?
|
||||||
|
|
||||||
Do you have a question or want to suggest a new feature? Start a Discussion here:
|
**Steps to reproduce**
|
||||||
https://github.com/RaspAP/raspap-webgui/discussions
|
Tell us how to reproduce this issue. Provide as much detailed information as possible.
|
||||||
|
|
||||||
Be sure there are no issues similar to yours that are already open. You can check this by searching the issues in this repository. If there is a duplicate issue, please close this one and add a comment to the existing issue instead.
|
**Expected behavior**
|
||||||
-->
|
A clear and concise description of what you expected to happen.
|
||||||
<!-- Provide a general summary of the issue in the Title above -->
|
|
||||||
|
|
||||||
## Checklist
|
**Actual behavior**
|
||||||
<!-- IMPORTANT! Fill in the boxes that apply by marking them like so: [x] -->
|
Tell us what you observed instead.
|
||||||
- [ ] This is a bug report
|
|
||||||
- [ ] I observed this bug on a clean install of the OS
|
|
||||||
- [ ] I have followed the project prerequisites
|
|
||||||
- [ ] I have searched this repository for existing issues
|
|
||||||
- [ ] I checked the FAQ and official documentation before creating this issue
|
|
||||||
- [ ] I have read and understand the issue reporting guidelines
|
|
||||||
|
|
||||||
## Bug description
|
**Screenshots**
|
||||||
<!-- Provide a detailed description of the issue -->
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
## Your environment
|
**Additional context**
|
||||||
1. Operating System: **ENTER HERE** <!-- RPi OS 32-bit Lite, Armbian, Debian, etc. -->
|
Add any other context about the problem here.
|
||||||
2. Hardware and version: <!-- RPi Zero/3B+/4, OrangePi 3, etc. -->
|
|
||||||
3. RaspAP version: <!-- reported by the Quick Installer or About page -->
|
|
||||||
4. Clean install of a compatible operating system? <!-- Yes/No -->
|
|
||||||
5. RaspAP Quick Install or Manual setup? <!-- Quick Install/Manual -->
|
|
||||||
6. Using default configuration? <!-- Yes/No -->
|
|
||||||
7. Simultaneous AP and managed mode? <!-- Yes/No -->
|
|
||||||
8. Onboard wireless chipset or external adapter? <!-- Onboard/External -->
|
|
||||||
9. Other software or services running with RaspAP?
|
|
||||||
|
|
||||||
## Steps to reproduce
|
|
||||||
<!-- Tell us how to reproduce this issue. Provide as much detailed information as possible -->
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
<!-- If applicable, add screenshots to help explain your problem -->
|
|
||||||
|
|
||||||
## Additional context
|
|
||||||
<!-- Add any other context about the problem here -->
|
|
||||||
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest an idea for this project
|
|
||||||
title: ''
|
|
||||||
labels: ''
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Is your feature request related to a problem?
|
|
||||||
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.
|
|
67
.github/workflows/codeql-analysis.yml
vendored
67
.github/workflows/codeql-analysis.yml
vendored
@ -1,67 +0,0 @@
|
|||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ master ]
|
|
||||||
pull_request:
|
|
||||||
# The branches below must be a subset of the branches above
|
|
||||||
branches: [ master ]
|
|
||||||
schedule:
|
|
||||||
- cron: '17 9 * * 1'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'javascript', 'python' ]
|
|
||||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
|
||||||
# Learn more:
|
|
||||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v1
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
- name: Autobuild
|
|
||||||
uses: github/codeql-action/autobuild@v1
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 https://git.io/JvXDl
|
|
||||||
|
|
||||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
||||||
# and modify them (or add more) to build your code if your project
|
|
||||||
# uses a compiled language
|
|
||||||
|
|
||||||
#- run: |
|
|
||||||
# make bootstrap
|
|
||||||
# make release
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v1
|
|
16
.github/workflows/main.yml
vendored
16
.github/workflows/main.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened, edited]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
auto_close_issues:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
- name: Automatically close issues that don't follow the issue template
|
|
||||||
uses: lucasbento/auto-close-issues@v1.0.2
|
|
||||||
with:
|
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
issue-close-message: "@${issue.user.login}: hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template.\nPlease review this project's issue policy https://docs.raspap.com/issues" # optional property
|
|
||||||
closed-issues-label: "invalid" # optional property
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,4 +4,3 @@ yarn-error.log
|
|||||||
*.swp
|
*.swp
|
||||||
includes/config.php
|
includes/config.php
|
||||||
rootCA.pem
|
rootCA.pem
|
||||||
vendor
|
|
||||||
|
69
BACKERS.md
69
BACKERS.md
@ -1,52 +1,35 @@
|
|||||||
<img width="465" alt="Insiders logo" src="https://user-images.githubusercontent.com/229399/115766971-e19e1900-a3a8-11eb-8c6f-379deb4313d2.png">
|
## Sponors
|
||||||
|
|
||||||
Development of RaspAP is made possible thanks to a sponsorware release model. This means that new features are first exclusively released to sponsors as part of **Insiders**. Read on to learn how sponsorship works, and how easy it is to get access to Insiders.
|
Development of RaspAP is made possible thanks to our awesome sponsors. If you use RaspAP in a commerical application, consider sponsoring the project at a commerical tier. There are several benefits for sponsors at this level. Find out more about [becoming a sponsor](https://github.com/sponsors/billz).
|
||||||
|
|
||||||
## How sponsorship works
|
#### 💖 Benefactors
|
||||||
New features first land in **Insiders**, which means that *sponsors will have access to them immediately*. Every feature is tied to a funding goal in monthly subscriptions. When a funding goal is hit, the features that are tied to it are merged back into the [public RaspAP repository](https://github.com/RaspAP/raspap-webgui) and released for general availability. Bugfixes and minor enhancements are always released simultaneously in both editions.
|
|
||||||
|
|
||||||
Don't want to sponsor? No problem, RaspAP already has tons of features available, so chances are that most of your requirements are already satisfied. See the list of **exclusive features** to learn which features are currently only available to sponsors.
|
#### 🏆 Gilded supporters
|
||||||
|
|
||||||
## How to become a sponsor
|
#### 🤖 Robot fuelers
|
||||||
You can become a sponsor using your individual or organization's GitHub account. Just pick any tier from $10/month and complete the checkout. Then, after a few hours, you will be added as a team member to the super-secret private GitHub repository containing the Insiders edition, which has all exclusive features. In addition, you get access to Insiders-only team discussions and content.
|
|
||||||
|
|
||||||
**Important**: If you're sponsoring [RaspAP](https://github.com/RaspAP/sponsors) through a GitHub organization, please send a short email to [sponsors@raspap.com](mailto:sponsors@raspap.com) with the name of your organization and the account that should be added as a collaborator.
|
#### ☕️ Coffee supporters
|
||||||
|
|
||||||
## Exclusive features
|
## Donors
|
||||||
The following features are currently available exclusively to sponsors. A tangible side benefit of sponsorship is that Insiders are able to help steer future development of RaspAP. This is done through Insiders' access to discussions, feature requests, issues and pull requests in the private GitHub repository.
|
|
||||||
|
|
||||||
✅ [Network device management](https://docs.raspap.com/net-devices/)
|
Recurring and one-time donors are vital to the continued development of this project. Join these awesome donors by pledging via [OpenCollective](https://opencollective.com/raspap) or [PayPal](https://paypal.me/billzgithub).
|
||||||
✅ [Firewall settings](https://docs.raspap.com/firewall/)
|
|
||||||
✅ [WPA3-Personal AP security](https://docs.raspap.com/ap-basics/#wpa3-personal)
|
|
||||||
✅ [802.11w Protected Management Frames](https://docs.raspap.com/ap-basics/#80211w)
|
|
||||||
✅ [Printable Wi-Fi signs](https://docs.raspap.com/ap-basics/#printable-signs)
|
|
||||||
✅ [Drag & drop dashboard widgets](https://docs.raspap.com/ap-basics/#drag-drop-widgets)
|
|
||||||
✅ [MAC address cloning](https://docs.raspap.com/net-devices/#changing-the-mac-address)
|
|
||||||
✅ [Network diagnostics](https://docs.raspap.com/net-devices/#diagnostics)
|
|
||||||
✅ [WireGuard VPN kill switch](https://docs.raspap.com/wireguard/#kill-switch)
|
|
||||||
✅ [Dynamic DNS](https://docs.raspap.com/dynamicdns/)
|
|
||||||
✅ [Multiple WireGuard configs](https://docs.raspap.com/wireguard/#multiple-configs)
|
|
||||||
|
|
||||||
Look for the list above to grow as we add more exclusive features. Be sure to visit this page from time to time to learn about what's new, check the [Insiders docs page](https://docs.raspap.com/insiders/) and follow [@RaspAP on Twitter](https://twitter.com/rasp_ap) to stay updated.
|
## OpenCollective
|
||||||
|
Navisense GmbH - $500
|
||||||
|
Wechaty - $20
|
||||||
|
Pheppy - $10
|
||||||
|
Mark H - $10
|
||||||
|
Phil K - $10
|
||||||
|
T.Paul L - $5
|
||||||
|
Wouter D - $20
|
||||||
|
Andy N - $20
|
||||||
|
Paul B - $20
|
||||||
|
|
||||||
## Funding targets
|
## PayPal
|
||||||
Below is a list of funding targets. When a funding target is reached, the features that are tied to it are merged back into RaspAP and released to the public for general availability.
|
Ray E - "This project is awesome and just works; saved me and my client tons of work. Thank you!" - $20
|
||||||
|
Erin C - "Just got Raspap up and running, looks very cool, thanks!" -$20 CAD
|
||||||
### $1000
|
Ralf J - "Thanks for RaspAP including OpenVPN. It was a big help for me." -€15
|
||||||
The second **Insiders Edition** includes the features listed above.
|
Felipe C - "Thanks for the good work on RaspAP!" -$6
|
||||||
|
Webagentur S - "Like what you and RaspAP are doing." -€20
|
||||||
### $500
|
Matthew B - "Great project, easy to set up." -£15
|
||||||
The [first Insiders Edition goal](https://docs.raspap.com/insiders/#500-1st-insiders-edition) was reached in December 2021. Thank you sponsors!
|
Mikko M - "Thanks for the great RaspAP." -€10
|
||||||
|
|
||||||
## Quarterly giving
|
|
||||||
Beginning in 2022, each quarter 15% of all proceeds from Insiders will be donated directly to the [Raspberry Pi Foundation](https://www.raspberrypi.org/). The Raspberry Pi Foundation is a UK-based charity that works to put the power of computing and digital making into the hands of people all over the world.
|
|
||||||
|
|
||||||
[![Get involved with the Raspberry Pi Foundation](https://img.youtube.com/vi/dEzg92g1LHw/0.jpg)](https://www.youtube.com/watch?v=dEzg92g1LHw)
|
|
||||||
|
|
||||||
When you become an Insider, not only do you support development of RaspAP but you also help inspire young people by harnessing the power of computing to solve problems and express themselves creatively.
|
|
||||||
|
|
||||||
## Frequently asked questions
|
|
||||||
We've covered all you need to know [here](https://docs.raspap.com/insiders/#frequently-asked-questions).
|
|
||||||
|
|
||||||
### Terms
|
|
||||||
See our [official project documentation](https://docs.raspap.com/insiders/#terms).
|
|
||||||
|
@ -9,5 +9,4 @@
|
|||||||
This project follows the [PSR-2](http://www.php-fig.org/psr/psr-2/) coding style guidelines. There are many ways to check your code for PSR-2. An excellent tool is [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). The command line tool phpcs can be run against any single file. [Phing](https://www.phing.info/), a PHP build tool, integrates nicely with `phpcs` to automate PSR-2 checks across all source files in a project.
|
This project follows the [PSR-2](http://www.php-fig.org/psr/psr-2/) coding style guidelines. There are many ways to check your code for PSR-2. An excellent tool is [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). The command line tool phpcs can be run against any single file. [Phing](https://www.phing.info/), a PHP build tool, integrates nicely with `phpcs` to automate PSR-2 checks across all source files in a project.
|
||||||
|
|
||||||
### Development process
|
### Development process
|
||||||
Development processes used by contributors to the project are described [on this page](https://docs.raspap.com/developers/). It does not endorse one over the other; rather it is meant to share two different approaches.
|
Development processes used by contributors to the project are described [on this page](https://github.com/billz/raspap-webgui/wiki/Development-process). It does not endorse one over the other; rather it is meant to share two different approaches.
|
||||||
|
|
||||||
|
145
README.md
145
README.md
@ -1,13 +1,13 @@
|
|||||||
![](https://i.imgur.com/xeKD93p.png)
|
![](https://i.imgur.com/xeKD93p.png)
|
||||||
[![Release 2.9.6](https://img.shields.io/badge/release-v2.9.6-green)](https://github.com/raspap/raspap-webgui/releases) [![Awesome](https://awesome.re/badge.svg)](https://github.com/thibmaek/awesome-raspberry-pi) [![Join Insiders](https://img.shields.io/static/v1?label=Join%20Insiders&message=%E2%9D%A4&logo=GitHub&color=ff69b4)](https://github.com/sponsors/RaspAP) [![Build Status](https://app.travis-ci.com/RaspAP/raspap-webgui.svg?branch=master)](https://app.travis-ci.com/RaspAP/raspap-webgui) [![Crowdin](https://badges.crowdin.net/raspap/localized.svg)](https://crowdin.com/project/raspap) [![Twitter URL](https://img.shields.io/twitter/url?label=%40RaspAP&logoColor=%23d8224c&url=https%3A%2F%2Ftwitter.com%2Frasp_ap)](https://twitter.com/rasp_ap) [![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/RaspAP?style=social)](https://www.reddit.com/r/RaspAP/) [![Join the chat at https://app.gitter.im/#/room/#RaspAP:gitter.im](https://img.shields.io/badge/chat-on%20gitter-brightgreen)](https://app.gitter.im/#/room/#RaspAP:gitter.im)
|
[![Release 2.5.2](https://img.shields.io/badge/Release-2.5.2-green.svg)](https://github.com/billz/raspap-webgui/releases) [![Awesome](https://awesome.re/badge.svg)](https://github.com/thibmaek/awesome-raspberry-pi) [![Financial Contributors on Open Collective](https://opencollective.com/raspap/all/badge.svg?label=financial+contributors)](https://opencollective.com/raspap) ![https://travis-ci.com/billz/raspap-webgui/](https://img.shields.io/travis/com/billz/raspap-webgui/master) [![Crowdin](https://badges.crowdin.net/raspap/localized.svg)](https://crowdin.com/project/raspap) [![Twitter URL](https://img.shields.io/twitter/url?label=%40RaspAP&logoColor=%23d8224c&url=https%3A%2F%2Ftwitter.com%2Frasp_ap)](https://twitter.com/rasp_ap) [![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/RaspAP?style=social)](https://www.reddit.com/r/RaspAP/)
|
||||||
|
|
||||||
RaspAP is feature-rich wireless router software that _just works_ on many popular [Debian-based devices](#supported-operating-systems), including the Raspberry Pi. Our popular [Quick installer](#quick-installer) creates a known-good default configuration for all current Raspberry Pis with onboard wireless. A fully responsive, mobile-ready interface gives you control over the relevant services and networking options. Advanced DHCP settings, WireGuard and OpenVPN support, [SSL certificates](https://docs.raspap.com/ssl-quick/), security audits, [captive portal integration](https://docs.raspap.com/captive/), themes and [multilingual options](https://docs.raspap.com/translations/) are included.
|
RaspAP lets you quickly get a WiFi access point up and running to share the connectivity of many popular [Debian-based devices](#supported-operating-systems), including the Raspberry Pi. Our popular [Quick installer](#quick-installer) creates a known-good default configuration that "just works" on all current Raspberry Pis with onboard wireless. A responsive interface gives you control over the relevant services and networking options. Advanced DHCP settings, OpenVPN client support, SSL, security audits, themes and multilingual options are included.
|
||||||
|
|
||||||
RaspAP has been featured on sites such as [Instructables](http://www.instructables.com/id/Raspberry-Pi-As-Completely-Wireless-Router/), [Adafruit](https://blog.adafruit.com/2016/06/24/raspap-wifi-configuration-portal-piday-raspberrypi-raspberry_pi/), [Raspberry Pi Weekly](https://www.raspberrypi.org/weekly/commander/) and [Awesome Raspberry Pi](https://project-awesome.org/thibmaek/awesome-raspberry-pi) and implemented in countless projects.
|
RaspAP has been featured on sites such as [Instructables](http://www.instructables.com/id/Raspberry-Pi-As-Completely-Wireless-Router/), [Adafruit](https://blog.adafruit.com/2016/06/24/raspap-wifi-configuration-portal-piday-raspberrypi-raspberry_pi/), [Raspberry Pi Weekly](https://www.raspberrypi.org/weekly/commander/) and [Awesome Raspberry Pi](https://project-awesome.org/thibmaek/awesome-raspberry-pi) and implemented in countless projects.
|
||||||
|
|
||||||
We hope you enjoy using RaspAP as much as we do creating it. Tell us how you use this with [your own projects](https://github.com/raspap/raspap-awesome).
|
We hope you enjoy using RaspAP as much as we do creating it. Tell us how you use this with [your own projects](https://github.com/billz/raspap-awesome).
|
||||||
|
|
||||||
![](https://i.imgur.com/uhBFoOB.png)
|
![](https://i.imgur.com/ikWvsMG.gif)
|
||||||
![](https://i.imgur.com/EiIpdOS.gif)
|
![](https://i.imgur.com/EiIpdOS.gif)
|
||||||
![](https://i.imgur.com/eCjUS1H.gif)
|
![](https://i.imgur.com/eCjUS1H.gif)
|
||||||
![](https://i.imgur.com/5FT2BcS.gif)
|
![](https://i.imgur.com/5FT2BcS.gif)
|
||||||
@ -16,33 +16,32 @@ We hope you enjoy using RaspAP as much as we do creating it. Tell us how you use
|
|||||||
|
|
||||||
- [Prerequisites](#prerequisites)
|
- [Prerequisites](#prerequisites)
|
||||||
- [Quick installer](#quick-installer)
|
- [Quick installer](#quick-installer)
|
||||||
- [Join Insiders](#join-insiders)
|
|
||||||
- [WireGuard support](#wireguard-support)
|
|
||||||
- [OpenVPN support](#openvpn-support)
|
|
||||||
- [Ad Blocking](#ad-blocking)
|
- [Ad Blocking](#ad-blocking)
|
||||||
- [Bridged AP](#bridged-ap)
|
- [Bridged AP](#bridged-ap)
|
||||||
- [Simultaneous AP and Wifi client](#simultaneous-ap-and-wifi-client)
|
- [Simultaneous AP and Wifi client](#simultaneous-ap-and-wifi-client)
|
||||||
|
- [Support us](#support-us)
|
||||||
- [Manual installation](#manual-installation)
|
- [Manual installation](#manual-installation)
|
||||||
- [802.11ac 5GHz support](#80211ac-5ghz-support)
|
- [802.11ac 5GHz support](#80211ac-5ghz-support)
|
||||||
- [Supported operating systems](#supported-operating-systems)
|
- [Supported operating systems](#supported-operating-systems)
|
||||||
- [Multilingual support](#multilingual-support)
|
- [Multilingual support](#multilingual-support)
|
||||||
- [HTTPS support](#https-support)
|
- [HTTPS support](#https-support)
|
||||||
|
- [OpenVPN support](#openvpn-support)
|
||||||
- [How to contribute](#how-to-contribute)
|
- [How to contribute](#how-to-contribute)
|
||||||
- [Reporting issues](#reporting-issues)
|
- [Reporting issues](#reporting-issues)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
Start with a clean install of the [latest release of Raspberry Pi OS Lite](https://www.raspberrypi.com/software/operating-systems/). Both the 32- and 64-bit Lite versions are supported. The Raspberry Pi OS desktop distro is [unsupported](https://docs.raspap.com/faq/#distros).
|
Start with a clean install of the [latest release of Raspberry Pi OS (32-bit) Lite](https://www.raspberrypi.org/downloads/raspbian/). The Raspberry Pi OS desktop and 64-bit beta distros are unsupported.
|
||||||
|
|
||||||
1. Update Raspbian, including the kernel and firmware, followed by a reboot:
|
1. Update Raspbian, including the kernel and firmware, followed by a reboot:
|
||||||
```
|
```
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get full-upgrade
|
sudo apt-get dist-upgrade
|
||||||
sudo reboot
|
sudo reboot
|
||||||
```
|
```
|
||||||
2. Set the "WLAN country" option in `raspi-config`'s **Localisation Options**: `sudo raspi-config`
|
2. Set the WiFi country in raspi-config's **Localisation Options**: `sudo raspi-config`
|
||||||
|
|
||||||
3. If you have a device without an onboard wireless chipset, the [**Edimax Wireless 802.11b/g/n nano USB adapter**](https://www.edimax.com/edimax/merchandise/merchandise_detail/data/edimax/global/wireless_adapters_n150/ew-7811un) is an excellent option – it's small, cheap and has good driver support.
|
3. If you have a device without an onboard WiFi chipset, the [**Edimax Wireless 802.11b/g/n nano USB adapter**](https://www.edimax.com/edimax/merchandise/merchandise_detail/data/edimax/global/wireless_adapters_n150/ew-7811un) is an excellent option – it's small, cheap and has good driver support.
|
||||||
|
|
||||||
With the prerequisites done, you can proceed with either the Quick installer or Manual installation steps below.
|
With the prerequisites done, you can proceed with either the Quick installer or Manual installation steps below.
|
||||||
|
|
||||||
@ -51,81 +50,59 @@ Install RaspAP from your device's shell prompt:
|
|||||||
```sh
|
```sh
|
||||||
curl -sL https://install.raspap.com | bash
|
curl -sL https://install.raspap.com | bash
|
||||||
```
|
```
|
||||||
The [installer](https://docs.raspap.com/quick/) will complete the steps in the manual installation (below) for you.
|
The [installer](https://github.com/billz/raspap-webgui/wiki/Quick-Installer-usage) will complete the steps in the manual installation (below) for you.
|
||||||
|
|
||||||
After the reboot at the end of the installation the wireless network will be
|
After the reboot at the end of the installation the wireless network will be
|
||||||
configured as an access point as follows:
|
configured as an access point as follows:
|
||||||
* IP address: 10.3.141.1
|
* IP address: 10.3.141.1
|
||||||
* Username: admin
|
* Username: admin
|
||||||
* Password: secret
|
* Password: secret
|
||||||
* DHCP range: 10.3.141.50 — 10.3.141.254
|
* DHCP range: 10.3.141.50 to 10.3.141.255
|
||||||
* SSID: `raspi-webgui`
|
* SSID: `raspi-webgui`
|
||||||
* Password: ChangeMe
|
* Password: ChangeMe
|
||||||
|
|
||||||
**Note:** As the name suggests, the Quick Installer is a great way to quickly setup a new AP. However, it does not automagically detect the unique configuration of your system. Best results are obtained by connecting to ethernet (`eth0`) or as a WiFi client, also known as managed mode, with `wlan0`. For the latter, refer to [this FAQ](https://docs.raspap.com/faq/#headless). Special instructions for the Pi Zero W are [available here](https://docs.raspap.com/ap-sta/).
|
**Note:** As the name suggests, the Quick Installer is a great way to quickly setup a new AP. However, it does not automagically detect the unique configuration of your system. Best results are obtained by connecting to ethernet (`eth0`) or as a WiFi client, also known as managed mode, with `wlan0`. For the latter, refer to [this FAQ](https://github.com/billz/raspap-webgui/wiki/FAQs#how-do-i-prepare-the-sd-card-to-connect-to-wifi-in-headless-mode). Special instructions for the Pi Zero W are [available here](https://github.com/billz/raspap-webgui/wiki/RPi-Zero-W-AP-STA-mode).
|
||||||
|
|
||||||
Please [read this](https://docs.raspap.com/issues/) before reporting an issue.
|
|
||||||
|
|
||||||
## Join Insiders
|
|
||||||
[![](https://i.imgur.com/eml7k0b.png)](https://github.com/sponsors/RaspAP/)
|
|
||||||
|
|
||||||
RaspAP is free software, but powered by _your_ support. If you find RaspAP useful for your personal or commercial projects, [become an Insider](https://github.com/sponsors/RaspAP/) and get early access to [exclusive features](https://docs.raspap.com/insiders/#exclusive-features) in the [Insiders Edition](https://docs.raspap.com/insiders/).
|
|
||||||
|
|
||||||
A tangible side benefit of sponsorship is that **Insiders** are able to help _steer future development of RaspAP_. This is done through Insiders' team access to discussions, feature requests, issues and more in the private GitHub repository.
|
|
||||||
|
|
||||||
## WireGuard support
|
|
||||||
|
|
||||||
![](https://i.imgur.com/5YDv37e.png)
|
|
||||||
|
|
||||||
WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be considerably more performant than OpenVPN, and is generally regarded as the most secure, easiest to use, and simplest VPN solution for modern Linux distributions.
|
|
||||||
|
|
||||||
WireGuard may be optionally installed by the [Quick Installer](https://docs.raspap.com/quick/). Once this is done, you can manage local (server) settings, create a peer configuration and control the `wg-quick` service with RaspAP.
|
|
||||||
|
|
||||||
Details are [provided here](https://docs.raspap.com/wireguard/).
|
|
||||||
|
|
||||||
## OpenVPN support
|
|
||||||
|
|
||||||
![](https://i.imgur.com/ta7tCon.png)
|
|
||||||
|
|
||||||
OpenVPN may be optionally installed by the Quick Installer. Once this is done, you can [manage client configurations](https://docs.raspap.com/openvpn/) and the `openvpn-client` service with RaspAP.
|
|
||||||
|
|
||||||
To configure an OpenVPN client, upload a valid .ovpn file and, optionally, specify your login credentials. RaspAP will store your client configuration and add firewall rules to forward traffic from OpenVPN's `tun0` interface to your configured wireless interface.
|
|
||||||
|
|
||||||
See our [OpenVPN documentation](https://docs.raspap.com/openvpn/) for more information.
|
|
||||||
|
|
||||||
|
Please [read this](https://github.com/billz/raspap-webgui/wiki/Reporting-issues) before reporting an issue.
|
||||||
|
|
||||||
## Ad Blocking
|
## Ad Blocking
|
||||||
This feature uses DNS blacklisting to block requests for ads, trackers and other undesirable hosts. To enable ad blocking, simply respond to the prompt during the installation. As a beta release, we encourage testing and feedback from users of RaspAP.
|
This feature uses DNS blacklisting to block requests for ads, trackers and other undesirable hosts. To enable ad blocking, simply respond to the prompt during the installation. As a beta release, we encourage testing and feedback from users of RaspAP.
|
||||||
|
|
||||||
Details are [provided here](https://docs.raspap.com/adblock/).
|
Details are [provided here](https://github.com/billz/raspap-webgui/wiki/Ad-blocking).
|
||||||
|
|
||||||
## Bridged AP
|
## Bridged AP
|
||||||
By default RaspAP configures a routed AP for your clients to connect to. A bridged AP configuration is also possible. Slide the **Bridged AP mode** toggle under the **Advanced** tab of **Configure hotspot**, then save and restart the hotspot.
|
By default RaspAP configures a routed AP for your clients to connect to. A bridged AP configuration is also possible. Slide the **Bridged AP mode** toggle under the **Advanced** tab of **Configure hotspot**, then save and restart the hotspot.
|
||||||
|
|
||||||
|
![](https://i.imgur.com/J5VKSay.png)
|
||||||
|
|
||||||
**Note:** In bridged mode, all routing capabilities are handled by your upstream router. Because your router assigns IP addresses to your device's hotspot and its clients, you might not be able to reach the RaspAP web interface from the default `10.3.141.1` address. Instead use your RPi's hostname followed by `.local` to access the RaspAP web interface. With Raspbian default settings, this should look like `raspberrypi.local`. Alternate methods are [discussed here](https://www.raspberrypi.org/documentation/remote-access/ip-address.md).
|
**Note:** In bridged mode, all routing capabilities are handled by your upstream router. Because your router assigns IP addresses to your device's hotspot and its clients, you might not be able to reach the RaspAP web interface from the default `10.3.141.1` address. Instead use your RPi's hostname followed by `.local` to access the RaspAP web interface. With Raspbian default settings, this should look like `raspberrypi.local`. Alternate methods are [discussed here](https://www.raspberrypi.org/documentation/remote-access/ip-address.md).
|
||||||
|
|
||||||
More information on Bridged AP mode is provided [in our documentation](https://docs.raspap.com/bridged/).
|
More information on Bridged AP mode is provided [on our wiki](https://github.com/billz/raspap-webgui/wiki/Bridged-AP-mode).
|
||||||
|
|
||||||
## Simultaneous AP and Wifi client
|
## Simultaneous AP and Wifi client
|
||||||
RaspAP lets you create an AP with a Wifi client configuration, often called [AP-STA mode](https://docs.raspap.com/ap-sta/). With your system configured in managed mode, enable the AP from the **Advanced** tab of **Configure hotspot** by sliding the **Wifi client AP mode** toggle. Save settings and start the hotspot. The managed mode AP is functional without restart.
|
RaspAP lets you create an AP with a Wifi client configuration, often called [AP-STA mode](https://github.com/billz/raspap-webgui/wiki/RPi-Zero-W-AP-STA-mode). With your system configured in managed mode, enable the AP from the **Advanced** tab of **Configure hotspot** by sliding the **Wifi client AP mode** toggle. Save settings and start the hotspot. The managed mode AP is functional without restart.
|
||||||
|
|
||||||
**Note:** This option is disabled until you configure your system as a wireless client. For a device operating in [managed mode](https://docs.raspap.com/faq/#headless) without an `eth0` connection, this configuration must be enabled [_before_ a reboot](https://docs.raspap.com/ap-sta/).
|
**Note:** This option is disabled until you configure your system as a wireless client. For a device operating in [managed mode](https://github.com/billz/raspap-webgui/wiki/FAQs#how-do-i-prepare-the-sd-card-to-connect-to-wifi-in-headless-mode) without an `eth0` connection, this configuration must be enabled [_before_ a reboot](https://github.com/billz/raspap-webgui/wiki/RPi-Zero-W-AP-STA-mode).
|
||||||
|
|
||||||
|
## Support us
|
||||||
|
RaspAP is free software, but powered by your support. If you find RaspAP useful for your personal or commercial projects, please [become a GitHub sponsor](https://github.com/sponsors/billz), join the project on [Open Collective](https://opencollective.com/raspap) or make a one-time donation with [PayPal](https://www.paypal.com/paypalme2/billzgithub). Any of these options makes a big difference!
|
||||||
|
|
||||||
|
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg?style=for-the-badge&logo=paypal&link=https://www.paypal.com/paypalme2/billzgithub)](https://www.paypal.com/paypalme2/billzgithub)
|
||||||
|
|
||||||
## Manual installation
|
## Manual installation
|
||||||
Detailed manual setup instructions are provided [on our documentation site](https://docs.raspap.com/manual/).
|
Detailed manual setup instructions are provided [on our wiki](https://github.com/billz/raspap-webgui/wiki/Manual-installation).
|
||||||
|
|
||||||
## 802.11ac 5GHz support
|
## 802.11ac 5GHz support
|
||||||
RaspAP provides an 802.11ac wireless mode option for supported hardware (currently the RPi 3B+/4 and compatible Orange Pi models) and wireless regulatory domains. See [this FAQ](https://docs.raspap.com/faq/#80211ac) for more information.
|
RaspAP provides an 802.11ac wireless mode option for supported hardware (currently the RPi 3B+/4 and compatible Orange Pi models) and wireless regulatory domains. See [this FAQ](https://github.com/billz/raspap-webgui/wiki/FAQs#80211ac) for more information.
|
||||||
|
|
||||||
## Supported operating systems
|
## Supported operating systems
|
||||||
RaspAP was originally made for Raspbian, but now also installs on the following Debian-based distros.
|
RaspAP was originally made for Raspbian, but now also installs on the following Debian-based distros.
|
||||||
|
|
||||||
| Distribution | Release | Architecture | Support |
|
| Distribution | Release | Architecture | Support |
|
||||||
|---|:---:|:---:|:---:|
|
|---|:---:|:---:|:---:|
|
||||||
| Raspberry Pi OS | (32-bit) Lite Bullseye | ARM | Official |
|
| Raspberry Pi OS | (32-bit) Lite Buster | ARM | Official |
|
||||||
| Raspberry Pi OS | (64-bit) Lite Bullseye | ARM | Official |
|
| Armbian | Buster | [ARM](https://docs.armbian.com/#supported-chips) | Official |
|
||||||
| Armbian | Bullseye | [ARM](https://docs.armbian.com/#supported-socs) | Official |
|
| Debian | Buster | ARM / x86_64 | Beta |
|
||||||
| Debian | Bullseye | ARM / x86_64 | Beta |
|
|
||||||
| Ubuntu | 18.04 LTS / 19.10 | ARM / x86_64 | Beta |
|
| Ubuntu | 18.04 LTS / 19.10 | ARM / x86_64 | Beta |
|
||||||
|
|
||||||
![](https://i.imgur.com/luiyYNw.png)
|
![](https://i.imgur.com/luiyYNw.png)
|
||||||
@ -133,12 +110,35 @@ RaspAP was originally made for Raspbian, but now also installs on the following
|
|||||||
We find Armbian particularly well-suited for this project. Please note that "supported" is not a guarantee. If you are able to improve support for your preferred distro, we encourage you to [actively contribute](#how-to-contribute) to the project.
|
We find Armbian particularly well-suited for this project. Please note that "supported" is not a guarantee. If you are able to improve support for your preferred distro, we encourage you to [actively contribute](#how-to-contribute) to the project.
|
||||||
|
|
||||||
## Multilingual support
|
## Multilingual support
|
||||||
RaspAP uses [GNU Gettext](https://www.gnu.org/software/gettext/) to manage multilingual messages. In order to use RaspAP with one of our supported translations, you must configure a corresponding language package on your RPi. To list languages currently installed on your system, use `locale -a` at the shell prompt. To generate new locales, run `sudo dpkg-reconfigure locales` and select any other desired locales. Details are provided on our [documentation site](https://docs.raspap.com/translations/).
|
RaspAP uses [GNU Gettext](https://www.gnu.org/software/gettext/) to manage multilingual messages. In order to use RaspAP with one of our supported translations, you must configure a corresponding language package on your RPi. To list languages currently installed on your system, use `locale -a` at the shell prompt. To generate new locales, run `sudo dpkg-reconfigure locales` and select any other desired locales. Details are provided on our [wiki](https://github.com/billz/raspap-webgui/wiki/Translations#raspap-in-your-language).
|
||||||
|
|
||||||
See this list of [supported languages](https://docs.raspap.com/translations/#supported-languages) that are actively maintained by volunteer translators. If your language is not supported, why not [contribute a translation](https://docs.raspap.com/translations/#contributing-to-a-translation)? Contributors will receive credit as the original translators.
|
The following translations are currently maintained by the project:
|
||||||
|
|
||||||
|
- Čeština
|
||||||
|
- 正體中文 (Chinese traditional)
|
||||||
|
- 简体中文 (Chinese Simplified)
|
||||||
|
- Dansk
|
||||||
|
- Deutsch
|
||||||
|
- Español
|
||||||
|
- Finnish
|
||||||
|
- Français
|
||||||
|
- Ελληνικά (Greek)
|
||||||
|
- Indonesian
|
||||||
|
- Italiano
|
||||||
|
- 日本語 (Japanese)
|
||||||
|
- 한국어 (Korean)
|
||||||
|
- Nederlands
|
||||||
|
- Polskie
|
||||||
|
- Português
|
||||||
|
- Русский
|
||||||
|
- Svenska
|
||||||
|
- Türkçe
|
||||||
|
- Tiếng Việt (Vietnamese)
|
||||||
|
|
||||||
|
If your language is not in the list above, why not [contribute a translation](https://github.com/billz/raspap-webgui/wiki/Translations#contributing-a-translation)? Contributors will receive credit as the original translators.
|
||||||
|
|
||||||
## HTTPS support
|
## HTTPS support
|
||||||
The Quick Installer may be used to [generate SSL certificates](https://docs.raspap.com/ssl-quick/) with `mkcert`. The installer automates the manual steps [described here](https://docs.raspap.com/ssl-manual/), including configuring lighttpd with SSL support.
|
The Quick Installer may be used to [generate SSL certificates](https://github.com/billz/raspap-webgui/wiki/SSL-certificates-(Quick-Installer)) with `mkcert`. The installer automates the manual steps [described in the wiki](https://github.com/billz/raspap-webgui/wiki/SSL-(Manual-steps)), including configuring lighttpd with SSL support.
|
||||||
|
|
||||||
Simply append the `-c` or `--cert` option to the Quick Installer, like so:
|
Simply append the `-c` or `--cert` option to the Quick Installer, like so:
|
||||||
|
|
||||||
@ -148,7 +148,14 @@ curl -sL https://install.raspap.com | bash -s -- --cert
|
|||||||
|
|
||||||
**Note**: this only installs mkcert and generates an SSL certificate with the input you provide. It does *not* (re)install RaspAP.
|
**Note**: this only installs mkcert and generates an SSL certificate with the input you provide. It does *not* (re)install RaspAP.
|
||||||
|
|
||||||
More information on SSL certificates and HTTPS support is available [in our documentation](https://docs.raspap.com/ssl-quick/).
|
More information on SSL certificates and HTTPS support is available [on our wiki](https://github.com/billz/raspap-webgui/wiki/SSL-certificates-(Quick-Installer)).
|
||||||
|
|
||||||
|
## OpenVPN support
|
||||||
|
OpenVPN may be optionally installed by the Quick Installer. Once this is done, you can manage client configuration and the `openvpn-client` service with RaspAP.
|
||||||
|
|
||||||
|
To configure an OpenVPN client, upload a valid .ovpn file and, optionally, specify your login credentials. RaspAP will store your client configuration and add firewall rules to forward traffic from OpenVPN's `tun0` interface to your configured wireless interface.
|
||||||
|
|
||||||
|
**Note**: this feature is currently in beta. Please [read this](https://github.com/billz/raspap-webgui/wiki/FAQs#-openvpn-fails-to-start-andor-i-have-no-internet-help) before reporting an issue.
|
||||||
|
|
||||||
## How to contribute
|
## How to contribute
|
||||||
1. Fork the project in your account and create a new branch: `your-great-feature`.
|
1. Fork the project in your account and create a new branch: `your-great-feature`.
|
||||||
@ -159,19 +166,35 @@ More information on SSL certificates and HTTPS support is available [in our docu
|
|||||||
Find out more about our [coding style guidelines and recommended tools](CONTRIBUTING.md).
|
Find out more about our [coding style guidelines and recommended tools](CONTRIBUTING.md).
|
||||||
|
|
||||||
## Reporting issues
|
## Reporting issues
|
||||||
Please [read this](https://docs.raspap.com/issues/) before reporting a bug.
|
Please [read this](https://github.com/billz/raspap-webgui/wiki/Reporting-issues) before reporting a bug.
|
||||||
|
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
### Code Contributors
|
### Code Contributors
|
||||||
This project exists thanks to all the awesome people who [contribute](CONTRIBUTING.md) their time and expertise.
|
This project exists thanks to all the awesome people who [contribute](CONTRIBUTING.md) their time and expertise.
|
||||||
|
|
||||||
<a href="https://github.com/raspap/raspap-webgui/graphs/contributors"><img src="https://opencollective.com/raspap/contributors.svg?width=890&button=false" /></a>
|
<a href="https://github.com/billz/raspap-webgui/graphs/contributors"><img src="https://opencollective.com/raspap/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
### Financial Contributors
|
### Financial Contributors
|
||||||
Development of RaspAP is made possible thanks to a sponsorware release model. This means that new features are first exclusively released to sponsors as part of [**Insiders**](https://github.com/sponsors/RaspAP).
|
Become a [financial contributor](https://opencollective.com/raspap/contribute) and help us sustain our community.
|
||||||
|
|
||||||
Learn more about [how sponsorship works](https://docs.raspap.com/insiders/#how-sponsorship-works), and how easy it is to get access to Insiders.
|
#### Individuals
|
||||||
|
<a href="https://opencollective.com/raspap"><img src="https://opencollective.com/raspap/individuals.svg?width=890"></a>
|
||||||
|
|
||||||
|
#### Organizations
|
||||||
|
|
||||||
|
[Support this project](https://opencollective.com/raspap/contribute) with your organization. Your logo will show up here with a link to your website.
|
||||||
|
|
||||||
|
<a href="https://opencollective.com/raspap/organization/0/website"><img src="https://opencollective.com/raspap/organization/0/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/1/website"><img src="https://opencollective.com/raspap/organization/1/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/2/website"><img src="https://opencollective.com/raspap/organization/2/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/3/website"><img src="https://opencollective.com/raspap/organization/3/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/4/website"><img src="https://opencollective.com/raspap/organization/4/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/5/website"><img src="https://opencollective.com/raspap/organization/5/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/6/website"><img src="https://opencollective.com/raspap/organization/6/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/7/website"><img src="https://opencollective.com/raspap/organization/7/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/8/website"><img src="https://opencollective.com/raspap/organization/8/avatar.svg"></a>
|
||||||
|
<a href="https://opencollective.com/raspap/organization/9/website"><img src="https://opencollective.com/raspap/organization/9/avatar.svg"></a>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
See the [LICENSE](./LICENSE) file.
|
See the [LICENSE](./LICENSE) file.
|
||||||
|
27
SECURITY.md
27
SECURITY.md
@ -1,27 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
The RaspAP team and community take all security vulnerabilities seriously. This document outlines security procedures and general policies for the RaspAP open source projects as found on https://github.com/RaspAP/.
|
|
||||||
If you believe you have found a security vulnerability in any RaspAP-owned repository, please report it to us as described below.
|
|
||||||
|
|
||||||
## Reporting a vulnerability in RaspAP
|
|
||||||
|
|
||||||
Thank you for improving the security of our open source software.
|
|
||||||
We appreciate your efforts and responsible disclosure, and will make every effort to acknowledge your contributions.
|
|
||||||
|
|
||||||
Please report (suspected) security vulnerabilities to [security@raspap.com](mailto:security@raspap.com). The requested information listed below will help us better understand the nature and scope of the possible issue:
|
|
||||||
|
|
||||||
1. Type of issue (eg. shell exploit, cross-site scripting, etc.)
|
|
||||||
2. Full paths of source file(s) related to the manifestation of the issue
|
|
||||||
3. The location of the affected source code (tag/branch/commit or direct URL)
|
|
||||||
4. Any special configuration required to reproduce the issue
|
|
||||||
5. Step-by-step instructions to reproduce the issue
|
|
||||||
6. Proof-of-concept or exploit code (if possible)
|
|
||||||
7. Impact of the issue, including how an attacker might exploit the issue
|
|
||||||
|
|
||||||
This information will help us triage your report more quickly.
|
|
||||||
|
|
||||||
You will receive a response from us within 48 hours. Developers may ask for additional information or clarity on your report.
|
|
||||||
If the issue is confirmed, we will release a patch as soon as possible depending on complexity, but historically within a few days.
|
|
||||||
|
|
||||||
## Third-party modules
|
|
||||||
Report security vulnerabilities in third-party modules to the person or team maintaining the module.
|
|
@ -4,50 +4,21 @@ require '../../includes/csrf.php';
|
|||||||
require_once '../../includes/config.php';
|
require_once '../../includes/config.php';
|
||||||
|
|
||||||
if (isset($_POST['blocklist_id'])) {
|
if (isset($_POST['blocklist_id'])) {
|
||||||
$blocklist_id = escapeshellcmd($_POST['blocklist_id']);
|
$blocklist_id = $_POST['blocklist_id'];
|
||||||
|
$notracking_url = "https://raw.githubusercontent.com/notracking/hosts-blocklists/master/";
|
||||||
|
|
||||||
switch ($blocklist_id) {
|
switch ($blocklist_id) {
|
||||||
case "StevenBlack/hosts \(default\)":
|
case "notracking-hostnames":
|
||||||
$list_url = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts";
|
$file = "hostnames.txt";
|
||||||
$dest_file = "hostnames.txt";
|
break;
|
||||||
break;
|
case "notracking-domains":
|
||||||
case "badmojr/1Hosts \(Mini\)":
|
$file = "domains.txt";
|
||||||
$list_url = "https://badmojr.github.io/1Hosts/mini/hosts.txt";
|
break;
|
||||||
$dest_file = "hostnames.txt";
|
|
||||||
break;
|
|
||||||
case "badmojr/1Hosts \(Lite\)":
|
|
||||||
$list_url = "https://badmojr.github.io/1Hosts/Lite/hosts.txt";
|
|
||||||
$dest_file = "hostnames.txt";
|
|
||||||
break;
|
|
||||||
case "badmojr/1Hosts \(Pro\)":
|
|
||||||
$list_url = "https://badmojr.github.io/1Hosts/Pro/hosts.txt";
|
|
||||||
$dest_file = "hostnames.txt";
|
|
||||||
break;
|
|
||||||
case "badmojr/1Hosts \(Xtra\)":
|
|
||||||
$list_url = "https://badmojr.github.io/1Hosts/Xtra/hosts.txt";
|
|
||||||
$dest_file = "hostnames.txt";
|
|
||||||
break;
|
|
||||||
case "oisd/big \(default\)":
|
|
||||||
$list_url = "https://big.oisd.nl/dnsmasq";
|
|
||||||
$dest_file = "domains.txt";
|
|
||||||
break;
|
|
||||||
case "oisd/small":
|
|
||||||
$list_url = "https://small.oisd.nl/dnsmasq";
|
|
||||||
$dest_file = "domains.txt";
|
|
||||||
break;
|
|
||||||
case "oisd/nsfw":
|
|
||||||
$list_url = "https://nsfw.oisd.nl/dnsmasq";
|
|
||||||
$dest_file = "domains.txt";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
$blocklist = $list_url . $dest_file;
|
$blocklist = $notracking_url . $file;
|
||||||
$dest = substr($dest_file, 0, strrpos($dest_file, "."));
|
|
||||||
|
|
||||||
exec("sudo /etc/raspap/adblock/update_blocklist.sh $list_url $dest_file " .RASPI_ADBLOCK_LISTPATH, $return);
|
exec("sudo /etc/raspap/adblock/update_blocklist.sh $blocklist $file " .RASPI_ADBLOCK_LISTPATH, $return);
|
||||||
$jsonData = ['return'=>$return,'list'=>$dest];
|
$jsonData = ['return'=>$return];
|
||||||
echo json_encode($jsonData);
|
|
||||||
} else {
|
|
||||||
$jsonData = ['return'=>2,'output'=>['Error getting data']];
|
|
||||||
echo json_encode($jsonData);
|
echo json_encode($jsonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
require '../../includes/csrf.php';
|
require '../../includes/csrf.php';
|
||||||
|
|
||||||
require_once '../../includes/config.php';
|
require_once '../../includes/config.php';
|
||||||
|
require_once RASPI_CONFIG.'/raspap.php';
|
||||||
|
|
||||||
|
header('X-Frame-Options: DENY');
|
||||||
|
header("Content-Security-Policy: default-src 'none'; connect-src 'self'");
|
||||||
|
require_once '../../includes/authenticate.php';
|
||||||
|
|
||||||
|
|
||||||
$interface = filter_input(INPUT_GET, 'inet', FILTER_SANITIZE_SPECIAL_CHARS);
|
$interface = filter_input(INPUT_GET, 'inet', FILTER_SANITIZE_SPECIAL_CHARS);
|
||||||
if (empty($interface)) {
|
if (empty($interface)) {
|
||||||
@ -36,14 +42,13 @@ $jsonobj = json_decode($jsonstdoutvnstat[0], true);
|
|||||||
$timeunits = filter_input(INPUT_GET, 'tu');
|
$timeunits = filter_input(INPUT_GET, 'tu');
|
||||||
if ($timeunits === 'm') {
|
if ($timeunits === 'm') {
|
||||||
// months
|
// months
|
||||||
$jsonData = $jsonobj['interfaces'][0]['traffic']['month'];
|
$jsonData = $jsonobj['interfaces'][0]['traffic']['months'];
|
||||||
} else {
|
} else {
|
||||||
// default: days
|
// default: days
|
||||||
$jsonData = $jsonobj['interfaces'][0]['traffic']['day'];
|
$jsonData = $jsonobj['interfaces'][0]['traffic']['days'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$datasizeunits = filter_input(INPUT_GET, 'dsu');
|
$datasizeunits = filter_input(INPUT_GET, 'dsu');
|
||||||
$dsu_factor = $datasizeunits == "mb" ? 1024 * 1024 : 1024;
|
|
||||||
header('X-Content-Type-Options: nosniff');
|
header('X-Content-Type-Options: nosniff');
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo '[ ';
|
echo '[ ';
|
||||||
@ -68,8 +73,13 @@ for ($i = count($jsonData) - 1; $i >= 0; --$i) {
|
|||||||
echo ',';
|
echo ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
$datasend = round($jsonData[$i]['tx'] / $dsu_factor, 0);
|
if ($datasizeunits == 'mb') {
|
||||||
$datareceived = round($jsonData[$i]['rx'] / $dsu_factor, 0);
|
$datasend = round($jsonData[$i]['tx'] / 1024, 0);
|
||||||
|
$datareceived = round($jsonData[$i]['rx'] / 1024, 0);
|
||||||
|
} else {
|
||||||
|
$datasend = $jsonData[$i]['rx'];
|
||||||
|
$datareceived = $jsonData[$i]['rx'];
|
||||||
|
}
|
||||||
|
|
||||||
if ($timeunits === 'm') {
|
if ($timeunits === 'm') {
|
||||||
echo '{ "date": "' , $dt->format('Y-m') , '", "rx": "' , $datareceived ,
|
echo '{ "date": "' , $dt->format('Y-m') , '", "rx": "' , $datareceived ,
|
||||||
|
@ -34,19 +34,19 @@ if (filter_input(INPUT_GET, 'tu') == 'h') {
|
|||||||
23 => array('date' => '23:00', 'rx' => 0, 'tx' => 0)
|
23 => array('date' => '23:00', 'rx' => 0, 'tx' => 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exec(sprintf('vnstat -i %s --json h', escapeshellarg($interface)), $jsonstdoutvnstat, $exitcodedaily);
|
exec(sprintf('vnstat -i %s --json h', escapeshellarg($interface)), $jsonstdoutvnstat, $exitcodedaily);
|
||||||
if ($exitcodedaily !== 0) {
|
if ($exitcodedaily !== 0) {
|
||||||
exit('vnstat error');
|
exit('vnstat error');
|
||||||
}
|
}
|
||||||
|
|
||||||
$datasizeunits = filter_input(INPUT_GET, 'dsu');
|
|
||||||
$dsu_factor = $datasizeunits == "mb" ? 1024 * 1024 : 1024;
|
|
||||||
|
|
||||||
$jsonobj = json_decode($jsonstdoutvnstat[0], true)['interfaces'][0];
|
$jsonobj = json_decode($jsonstdoutvnstat[0], true)['interfaces'][0];
|
||||||
$jsonData = $jsonobj['traffic']['hour'];
|
$jsonData = $jsonobj['traffic']['hours'];
|
||||||
for ($i = count($jsonData) - 1; $i >= 0 && $i >= count($jsonData)-25; --$i) {
|
for ($i = count($jsonData) - 1; $i >= 0; --$i) {
|
||||||
$data_template[$jsonData[$i]['time']['hour']]['rx'] = round($jsonData[$i]['rx'] / $dsu_factor, 0);
|
$data_template[$jsonData[$i]['id']]['rx'] = round($jsonData[$i]['rx'] / 1024, 0);
|
||||||
$data_template[$jsonData[$i]['time']['hour']]['tx'] = round($jsonData[$i]['tx'] / $dsu_factor, 0);
|
$data_template[$jsonData[$i]['id']]['tx'] = round($jsonData[$i]['tx'] / 1024, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = array();
|
$data = array();
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
require_once '../../includes/functions.php';
|
|
||||||
|
|
||||||
if (isset($_POST['logfile'])) {
|
|
||||||
$logfile = escapeshellcmd($_POST['logfile']);
|
|
||||||
|
|
||||||
// truncate requested log file
|
|
||||||
exec("sudo truncate -s 0 $logfile", $return);
|
|
||||||
echo json_encode($return);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
require_once '../../includes/session.php';
|
|
||||||
require_once '../../includes/functions.php';
|
|
||||||
|
|
||||||
if (isset($_POST['csrf_token'])) {
|
|
||||||
if (csrfValidateRequest() && !CSRFValidate()) {
|
|
||||||
handleInvalidCSRFToken();
|
|
||||||
}
|
|
||||||
$return = 0;
|
|
||||||
$path = "../../config";
|
|
||||||
$configs = array(
|
|
||||||
array("src" => $path .'/hostapd.conf', "tmp" => "/tmp/hostapddata", "dest" => RASPI_HOSTAPD_CONFIG),
|
|
||||||
array("src" => $path .'/dhcpcd.conf', "tmp" => "/tmp/dhcpddata", "dest" => RASPI_DHCPCD_CONFIG),
|
|
||||||
array("src" => $path .'/090_wlan0.conf', "tmp" => "/tmp/dnsmasqdata", "dest" => RASPI_DNSMASQ_PREFIX.'wlan0.conf'),
|
|
||||||
array("src" => $path .'/090_raspap.conf', "tmp" => "/tmp/dnsmasqdata", "dest" => RASPI_DNSMASQ_PREFIX.'raspap.conf'),
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ($configs as $config) {
|
|
||||||
try {
|
|
||||||
$tmp = file_get_contents($config["src"]);
|
|
||||||
file_put_contents($config["tmp"], $tmp);
|
|
||||||
system("sudo cp ".$config["tmp"]. " ".$config["dest"]);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$return = $e->getCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$jsonData = ['return'=>$return];
|
|
||||||
echo json_encode($jsonData);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
handleInvalidCSRFToken();
|
|
||||||
}
|
|
||||||
|
|
48
ajax/networking/gen_int_config.php
Normal file
48
ajax/networking/gen_int_config.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require '../../includes/csrf.php';
|
||||||
|
|
||||||
|
require_once '../../includes/config.php';
|
||||||
|
require_once '../../includes/functions.php';
|
||||||
|
|
||||||
|
if (isset($_POST['generate'])) {
|
||||||
|
$cnfNetworking = array_diff(scandir(RASPI_CONFIG_NETWORKING, 1), array('..','.','dhcpcd.conf','defaults'));
|
||||||
|
$cnfNetworking = array_combine($cnfNetworking, $cnfNetworking);
|
||||||
|
$strConfFile = file_get_contents(RASPI_CONFIG_NETWORKING.'/defaults')."\n";
|
||||||
|
foreach ($cnfNetworking as $index => $file) {
|
||||||
|
if ($index != "defaults") {
|
||||||
|
$cnfFile = parse_ini_file(RASPI_CONFIG_NETWORKING.'/'.$file, false, INI_SCANNER_RAW);
|
||||||
|
if ($cnfFile['static'] === 'true') {
|
||||||
|
$strConfFile .= "#Static IP configured for ".$cnfFile['interface']."\n";
|
||||||
|
$strConfFile .= "interface ".$cnfFile['interface']."\n";
|
||||||
|
if (isset($cnfFile['metric'])) {
|
||||||
|
$strConfFile .= "metric ".$cnfFile['metric']."\n";
|
||||||
|
}
|
||||||
|
$strConfFile .= "static ip_address=".$cnfFile['ip_address']."\n";
|
||||||
|
$strConfFile .= "static routers=".$cnfFile['routers']."\n";
|
||||||
|
$strConfFile .= "static domain_name_servers=".$cnfFile['domain_name_server']."\n\n";
|
||||||
|
} elseif ($cnfFile['static'] === 'false' && $cnfFile['failover'] === 'true') {
|
||||||
|
$strConfFile .= "#Failover static IP configured for ".$cnfFile['interface']."\n";
|
||||||
|
$strConfFile .= "profile static_".$cnfFile['interface']."\n";
|
||||||
|
$strConfFile .= "static ip_address=".$cnfFile['ip_address']."\n";
|
||||||
|
$strConfFile .= "static routers=".$cnfFile['routers']."\n";
|
||||||
|
$strConfFile .= "static domain_name_servers=".$cnfFile['domain_name_server']."\n\n";
|
||||||
|
$strConfFile .= "interface ".$cnfFile['interface']."\n";
|
||||||
|
if (isset($cnfFile['metric'])) {
|
||||||
|
$strConfFile .= "metric ".$cnfFile['metric']."\n";
|
||||||
|
}
|
||||||
|
$strConfFile .= "fallback static_".$cnfFile['interface']."\n\n";
|
||||||
|
} else {
|
||||||
|
$strConfFile .= "#DHCP configured for ".pathinfo($file, PATHINFO_FILENAME)."\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_put_contents(RASPI_CONFIG_NETWORKING.'/dhcpcd.conf', $strConfFile)) {
|
||||||
|
exec('sudo /bin/cp '.RASPI_CONFIG_NETWORKING.'/dhcpcd.conf '.RASPI_DHCPCD_CONFIG);
|
||||||
|
$output = ['return'=>0,'output'=>'Settings successfully applied'];
|
||||||
|
} else {
|
||||||
|
$output = ['return'=>2,'output'=>'Unable to write to apply settings'];
|
||||||
|
}
|
||||||
|
echo json_encode($output);
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
require_once '../../includes/locale.php';
|
|
||||||
|
|
||||||
if (isset($_POST['interface'])) {
|
|
||||||
|
|
||||||
define( 'NL80211_BAND_24GHZ', 0x1 );
|
|
||||||
define( 'NL80211_BAND_5GHZ', 0x2 );
|
|
||||||
$iface = escapeshellcmd($_POST['interface']);
|
|
||||||
$flags = 0;
|
|
||||||
|
|
||||||
// get physical device for selected interface
|
|
||||||
exec("iw dev | awk '/$iface/ {print line}{line = $0}'", $return);
|
|
||||||
$phy = $return[0];
|
|
||||||
|
|
||||||
// get frequencies supported by device
|
|
||||||
exec('iw '.$phy.' info | sed -rn "s/^.*\*\s([0-9]{4})\sMHz.*/\1/p"', $frequencies);
|
|
||||||
|
|
||||||
if (count(preg_grep('/^24[0-9]{2}/i', $frequencies)) >0) {
|
|
||||||
$flags += NL80211_BAND_24GHZ;
|
|
||||||
}
|
|
||||||
if (count(preg_grep('/^5[0-9]{3}/i', $frequencies)) >0) {
|
|
||||||
$flags += NL80211_BAND_5GHZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($flags) {
|
|
||||||
case NL80211_BAND_24GHZ:
|
|
||||||
$msg = sprintf(_("The selected interface (%s) has support for the 2.4 GHz wireless band only."), $iface);
|
|
||||||
break;
|
|
||||||
case NL80211_BAND_5GHZ:
|
|
||||||
$msg = sprintf(_("The selected interface (%s) has support for the 5 GHz wireless band only."), $iface);
|
|
||||||
break;
|
|
||||||
case NL80211_BAND_24GHZ | NL80211_BAND_5GHZ:
|
|
||||||
$msg = sprintf(_("The selected interface (%s) has support for both the 2.4 and 5 GHz wireless bands."), $iface);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$msg = sprintf(_("The selected interface (%s) does not support wireless mode operation."), $iface);
|
|
||||||
}
|
|
||||||
echo json_encode($msg);
|
|
||||||
}
|
|
||||||
|
|
23
ajax/networking/get_int_config.php
Normal file
23
ajax/networking/get_int_config.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require '../../includes/csrf.php';
|
||||||
|
|
||||||
|
require_once '../../includes/config.php';
|
||||||
|
require_once '../../includes/functions.php';
|
||||||
|
|
||||||
|
|
||||||
|
if (isset($_POST['interface'])) {
|
||||||
|
$int = preg_replace('/[^a-z0-9]/', '', $_POST['interface']);
|
||||||
|
if (!file_exists(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini')) {
|
||||||
|
touch(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini');
|
||||||
|
}
|
||||||
|
|
||||||
|
$intConfig = parse_ini_file(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini', false, INI_SCANNER_RAW);
|
||||||
|
$jsonData = ['return'=>1,'output'=>['intConfig'=>$intConfig]];
|
||||||
|
echo json_encode($jsonData);
|
||||||
|
|
||||||
|
// Todo - get dhcp lease information from `dhcpcd -U eth0` ? maybe ?
|
||||||
|
} else {
|
||||||
|
$jsonData = ['return'=>2,'output'=>['Error getting data']];
|
||||||
|
echo json_encode($jsonData);
|
||||||
|
}
|
@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
|
|
||||||
$interface = $_GET['iface'];
|
|
||||||
|
|
||||||
if (isset($interface)) {
|
|
||||||
// fetch dnsmasq.conf settings for interface
|
|
||||||
exec('cat '. escapeshellarg(RASPI_DNSMASQ_PREFIX.$interface.'.conf'), $return);
|
|
||||||
$conf = ParseConfig($return);
|
|
||||||
|
|
||||||
$dhcpdata['DHCPEnabled'] = empty($conf) ? false : true;
|
|
||||||
$arrRange = explode(",", $conf['dhcp-range']);
|
|
||||||
$dhcpdata['RangeStart'] = $arrRange[0];
|
|
||||||
$dhcpdata['RangeEnd'] = $arrRange[1];
|
|
||||||
$dhcpdata['RangeMask'] = $arrRange[2];
|
|
||||||
$dhcpdata['leaseTime'] = $arrRange[3];
|
|
||||||
$dhcpHost = $conf["dhcp-host"];
|
|
||||||
$dhcpHost = empty($dhcpHost) ? [] : $dhcpHost;
|
|
||||||
$dhcpdata['dhcpHost'] = is_array($dhcpHost) ? $dhcpHost : [ $dhcpHost ];
|
|
||||||
$upstreamServers = is_array($conf['server']) ? $conf['server'] : [ $conf['server'] ];
|
|
||||||
$dhcpdata['upstreamServersEnabled'] = empty($conf['server']) ? false: true;
|
|
||||||
$dhcpdata['upstreamServers'] = array_filter($upstreamServers);
|
|
||||||
preg_match('/([0-9]*)([a-z])/i', $dhcpdata['leaseTime'], $arrRangeLeaseTime);
|
|
||||||
$dhcpdata['leaseTime'] = $arrRangeLeaseTime[1];
|
|
||||||
$dhcpdata['leaseTimeInterval'] = $arrRangeLeaseTime[2];
|
|
||||||
if (isset($conf['dhcp-option'])) {
|
|
||||||
$arrDns = explode(",", $conf['dhcp-option']);
|
|
||||||
if ($arrDns[0] == '6') {
|
|
||||||
if (count($arrDns) > 1) {
|
|
||||||
$dhcpdata['DNS1'] = $arrDns[1];
|
|
||||||
}
|
|
||||||
if (count($arrDns) > 2) {
|
|
||||||
$dhcpdata['DNS2'] = $arrDns[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch dhcpcd.conf settings for interface
|
|
||||||
$conf = file_get_contents(RASPI_DHCPCD_CONFIG);
|
|
||||||
preg_match('/^#\sRaspAP\s'.$interface.'\s.*?(?=\s*+$)/ms', $conf, $matched);
|
|
||||||
preg_match('/metric\s(\d*)/', $matched[0], $metric);
|
|
||||||
preg_match('/static\sip_address=(.*)/', $matched[0], $static_ip);
|
|
||||||
preg_match('/static\srouters=(.*)/', $matched[0], $static_routers);
|
|
||||||
preg_match('/static\sdomain_name_server=(.*)/', $matched[0], $static_dns);
|
|
||||||
preg_match('/fallback\sstatic_'.$interface.'/', $matched[0], $fallback);
|
|
||||||
preg_match('/(?:no)?gateway/', $matched[0], $gateway);
|
|
||||||
preg_match('/nohook\swpa_supplicant/', $matched[0], $nohook_wpa_supplicant);
|
|
||||||
$dhcpdata['Metric'] = $metric[1];
|
|
||||||
$dhcpdata['StaticIP'] = strpos($static_ip[1],'/') ? substr($static_ip[1], 0, strpos($static_ip[1],'/')) : $static_ip[1];
|
|
||||||
$dhcpdata['SubnetMask'] = cidr2mask($static_ip[1]);
|
|
||||||
$dhcpdata['StaticRouters'] = $static_routers[1];
|
|
||||||
$dhcpdata['StaticDNS'] = $static_dns[1];
|
|
||||||
$dhcpdata['FallbackEnabled'] = empty($fallback) ? false: true;
|
|
||||||
$dhcpdata['DefaultRoute'] = $gateway[0] == "gateway";
|
|
||||||
$dhcpdata['NoHookWPASupplicant'] = $nohook_wpa_supplicant[0] == "nohook wpa_supplicant";
|
|
||||||
|
|
||||||
echo json_encode($dhcpdata);
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
<?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);
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
|
|
||||||
$entity = escapeshellcmd($_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);
|
|
||||||
}
|
|
35
ajax/networking/save_int_config.php
Normal file
35
ajax/networking/save_int_config.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require '../../includes/csrf.php';
|
||||||
|
|
||||||
|
require_once '../../includes/config.php';
|
||||||
|
require_once '../../includes/functions.php';
|
||||||
|
|
||||||
|
if (isset($_POST['interface'])) {
|
||||||
|
$int = $_POST['interface'];
|
||||||
|
$cfg = [];
|
||||||
|
$file = $int.".ini";
|
||||||
|
$ip = $_POST[$int.'-ipaddress'];
|
||||||
|
$netmask = mask2cidr($_POST[$int.'-netmask']);
|
||||||
|
$dns1 = $_POST[$int.'-dnssvr'];
|
||||||
|
$dns2 = $_POST[$int.'-dnssvralt'];
|
||||||
|
|
||||||
|
|
||||||
|
$cfg['interface'] = $int;
|
||||||
|
$cfg['routers'] = $_POST[$int.'-gateway'];
|
||||||
|
$cfg['ip_address'] = $ip."/".$netmask;
|
||||||
|
$cfg['domain_name_server'] = $dns1." ".$dns2;
|
||||||
|
$cfg['static'] = $_POST[$int.'-static'];
|
||||||
|
$cfg['failover'] = $_POST[$int.'-failover'];
|
||||||
|
$cfg['metric'] = $_POST[$int.'-metric'];
|
||||||
|
|
||||||
|
if (write_php_ini($cfg, RASPI_CONFIG_NETWORKING.'/'.$file)) {
|
||||||
|
$jsonData = ['return'=>0,'output'=>['Successfully Updated Network Configuration']];
|
||||||
|
} else {
|
||||||
|
$jsonData = ['return'=>1,'output'=>['Error saving network configuration to file']];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$jsonData = ['return'=>2,'output'=>'Unable to detect interface'];
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($jsonData);
|
@ -1,93 +0,0 @@
|
|||||||
<?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);
|
|
@ -14,10 +14,5 @@ knownWifiStations($networks);
|
|||||||
nearbyWifiStations($networks, !isset($_REQUEST["refresh"]));
|
nearbyWifiStations($networks, !isset($_REQUEST["refresh"]));
|
||||||
connectedWifiStations($networks);
|
connectedWifiStations($networks);
|
||||||
sortNetworksByRSSI($networks);
|
sortNetworksByRSSI($networks);
|
||||||
foreach ($networks as $ssid => $network) $networks[$ssid]["ssidutf8"] = ssid2utf8( $ssid );
|
|
||||||
|
|
||||||
$connected = array_filter($networks, function($n) { return $n['connected']; } );
|
echo renderTemplate('wifi_stations', compact('networks'));
|
||||||
$known = array_filter($networks, function($n) { return !$n['connected'] && $n['configured']; } );
|
|
||||||
$nearby = array_filter($networks, function($n) { return !$n['configured']; } );
|
|
||||||
|
|
||||||
echo renderTemplate('wifi_stations', compact('networks', 'connected', 'known', 'nearby'), true);
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
require_once '../../includes/functions.php';
|
|
||||||
|
|
||||||
if (isset($_POST['cfg_id'])) {
|
|
||||||
$ovpncfg_id = escapeshellcmd($_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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
require_once '../../includes/config.php';
|
|
||||||
require_once '../../includes/functions.php';
|
|
||||||
|
|
||||||
if (isset($_POST['cfg_id'])) {
|
|
||||||
$ovpncfg_id = escapeshellcmd($_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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require '../../includes/csrf.php';
|
|
||||||
|
|
||||||
$action = escapeshellcmd($_POST['a']);
|
|
||||||
|
|
||||||
if (isset($action)) {
|
|
||||||
|
|
||||||
switch($action) {
|
|
||||||
case "reboot":
|
|
||||||
$response = shell_exec("sudo /sbin/reboot");
|
|
||||||
break;
|
|
||||||
case "shutdown":
|
|
||||||
$response = shell_exec("sudo /sbin/shutdown -h now");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$response = 'Unknown action: '.$action;
|
|
||||||
}
|
|
||||||
echo json_encode($response);
|
|
||||||
}
|
|
||||||
|
|
235
app/css/all.css
235
app/css/all.css
@ -1,235 +0,0 @@
|
|||||||
/*
|
|
||||||
Name: all.css
|
|
||||||
Author: @billz
|
|
||||||
Author URI: https://github.com/billz
|
|
||||||
Description: Classes shared by all themes
|
|
||||||
License: GNU General Public License v3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Small devices (portrait phones, up to 576px) */
|
|
||||||
@media (max-width: 576px) {
|
|
||||||
.container-fluid, .card-body, .col-md-6 { padding-left: 0.5rem; padding-right: 0.5rem; }
|
|
||||||
.card .card-header { padding: .75rem .5rem; font-size: 1.0rem; }
|
|
||||||
.row { margin-left: 0rem; margin-right: 0rem; }
|
|
||||||
.col-lg-12 { padding-right: 0.25rem; padding-left: 0.25rem; }
|
|
||||||
.form-group.col-md-6 { margin-left: -0.5rem; }
|
|
||||||
h4.mt-3 { margin-left: 0.5rem; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-brand-text {
|
|
||||||
text-transform: none;
|
|
||||||
color: #212529;
|
|
||||||
font-size: 2.0rem;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: Helvetica, Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h-underlined {
|
|
||||||
border-bottom: 1px solid #e3e6f0;
|
|
||||||
padding-bottom: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-logo {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-left: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-header {
|
|
||||||
font-size: 26pt;
|
|
||||||
margin: 20px 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item {
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 0.7em;
|
|
||||||
color: #858796;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-value {
|
|
||||||
font-size: 0.7rem;
|
|
||||||
margin-left: 0.7rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item-xs {
|
|
||||||
font-size: 0.7rem;
|
|
||||||
margin-left: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item-wifi {
|
|
||||||
width: 6rem;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.service-status {
|
|
||||||
border-width: 0;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.service-status-up {
|
|
||||||
color: #a1ec38 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.service-status-warn {
|
|
||||||
color: #f6f044 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.service-status-down {
|
|
||||||
color: #f80107 !important;
|
|
||||||
animation: flash 1s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes flash {
|
|
||||||
50% {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.logoutput {
|
|
||||||
width:100%;
|
|
||||||
height: 20rem;
|
|
||||||
border: 1px solid #d1d3e2;
|
|
||||||
border-radius: .35rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dhcp-static-leases {
|
|
||||||
margin-top: 1em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dhcp-static-lease-row {
|
|
||||||
margin-top: 0.5em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-spinner {
|
|
||||||
background: url("../../app/img/loading-spinner.gif") no-repeat scroll center center transparent;
|
|
||||||
min-height: 450px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 576px) {
|
|
||||||
.card-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: minmax(0, 1fr) 50%;
|
|
||||||
grid-gap: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-off.btn {
|
|
||||||
padding-left: 1.2rem;
|
|
||||||
font-size: 0.9rem!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-on.btn {
|
|
||||||
font-size: 0.9rem!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas#divDBChartBandwidthhourly {
|
|
||||||
height: 350px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-container {
|
|
||||||
height: 150px;
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dbChart {
|
|
||||||
display: flex;
|
|
||||||
height: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
margin-bottom: 0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-progress {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa-check {
|
|
||||||
color: #90ee90;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fa-times {
|
|
||||||
color: #ff4500;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-light.js-toggle-password {
|
|
||||||
border: 1px solid lightgrey;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon {
|
|
||||||
margin-top: 2px;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
.signal-icon .signal-bar {
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 1px;
|
|
||||||
opacity: 30%;
|
|
||||||
background: <?php echo $color; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon .signal-bar:nth-child(1) { height: 40%; }
|
|
||||||
.signal-icon .signal-bar:nth-child(2) { height: 70%; }
|
|
||||||
.signal-icon .signal-bar:nth-child(3) { height: 100%; }
|
|
||||||
|
|
||||||
.signal-icon.weak .signal-bar:nth-child(1),
|
|
||||||
.signal-icon.medium .signal-bar:nth-child(1),
|
|
||||||
.signal-icon.medium .signal-bar:nth-child(2),
|
|
||||||
.signal-icon.strong .signal-bar:nth-child(1),
|
|
||||||
.signal-icon.strong .signal-bar:nth-child(2),
|
|
||||||
.signal-icon.strong .signal-bar:nth-child(3)
|
|
||||||
{ opacity: 100%; }.signal-icon {
|
|
||||||
margin-top: 2px;
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
.signal-icon .signal-bar {
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 1px;
|
|
||||||
opacity: 30%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon .signal-bar:nth-child(1) { height: 40%; }
|
|
||||||
.signal-icon .signal-bar:nth-child(2) { height: 70%; }
|
|
||||||
.signal-icon .signal-bar:nth-child(3) { height: 100%; }
|
|
||||||
|
|
||||||
.signal-icon.weak .signal-bar:nth-child(1),
|
|
||||||
.signal-icon.medium .signal-bar:nth-child(1),
|
|
||||||
.signal-icon.medium .signal-bar:nth-child(2),
|
|
||||||
.signal-icon.strong .signal-bar:nth-child(1),
|
|
||||||
.signal-icon.strong .signal-bar:nth-child(2),
|
|
||||||
.signal-icon.strong .signal-bar:nth-child(3)
|
|
||||||
{ opacity: 100%; }
|
|
||||||
|
|
||||||
.gs-edit {
|
|
||||||
border: 1px dashed #ccc;
|
|
||||||
background-color: #f1faee;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
figcaption.figure-caption a {
|
|
||||||
color: #858796;
|
|
||||||
}
|
|
||||||
|
|
||||||
button > i.fas {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
}
|
|
||||||
|
|
@ -12,37 +12,59 @@ Description: Default theme for RaspAP
|
|||||||
License: GNU General Public License v3.0
|
License: GNU General Public License v3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import url('all.css');
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
color: #212529;
|
color: #212529;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
margin: 20px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-logo {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small devices (portrait phones, up to 576px) */
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.container-fluid, .card-body, .col-md-6 { padding-left: 0.5rem; padding-right: 0.5rem; }
|
||||||
|
.card .card-header { padding: .75rem .5rem; font-size: 1.0rem; }
|
||||||
|
.row { margin-left: 0rem; margin-right: 0rem; }
|
||||||
|
.col-lg-12 { padding-right: 0.25rem; padding-left: 0.25rem; }
|
||||||
|
.form-group.col-md-6 { margin-left: -0.5rem; }
|
||||||
|
.js-wifi-stations { margin-left: -0.5rem; margin-right: -0.5rem; }
|
||||||
|
h4.mt-3 { margin-left: 0.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
background-color: #f8f9fc;
|
background-color: #f8f9fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-brand-text {
|
||||||
|
text-transform: none;
|
||||||
|
color: #212529;
|
||||||
|
font-size: 2.0rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar .nav-item.active .nav-link {
|
.sidebar .nav-item.active .nav-link {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card .card-header, .modal-header {
|
.card .card-header {
|
||||||
border-color: <?php echo $color; ?>;
|
border-color: <?php echo $color; ?>;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: <?php echo $color; ?>;
|
background-color: <?php echo $color; ?>;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
color: <?php echo $color; ?>;
|
color: <?php echo $color; ?>;
|
||||||
border-color: <?php echo $color; ?>;
|
border-color: <?php echo $color; ?>;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-footer, .modal-footer {
|
.card-footer {
|
||||||
background-color: #f2f1f0;
|
background-color: #f2f1f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,12 +114,76 @@ i.fa.fa-bars:hover{
|
|||||||
color: #6e707e;
|
color: #6e707e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
width: 10rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item-xs {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
margin-left: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item-wifi {
|
||||||
|
width: 6rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status {
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-up {
|
||||||
|
color: #a1ec38;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-warn {
|
||||||
|
color: #f6f044;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-down {
|
||||||
|
color: #f80107;
|
||||||
|
animation: flash 1s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes flash {
|
||||||
|
50% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.logoutput {
|
||||||
|
width:100%;
|
||||||
|
height: 20rem;
|
||||||
|
border: 1px solid #d1d3e2;
|
||||||
|
border-radius: .35rem;
|
||||||
|
}
|
||||||
|
|
||||||
pre.unstyled {
|
pre.unstyled {
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dhcp-static-leases {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dhcp-static-lease-row {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
background: url("../../app/img/loading-spinner.gif") no-repeat scroll center center transparent;
|
||||||
|
min-height: 150px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-reload-wifi-stations {
|
||||||
|
min-width: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar.toggled .nav-item .nav-link span {
|
.sidebar.toggled .nav-item .nav-link span {
|
||||||
display: none;
|
display: none;
|
||||||
} .sidebar .nav-item .nav-link i,
|
} .sidebar .nav-item .nav-link i,
|
||||||
@ -109,7 +195,46 @@ pre.unstyled {
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signal-icon .signal-bar {
|
.toggle-off.btn {
|
||||||
background: <?php echo $color; ?>;
|
padding-left: 1.2rem;
|
||||||
|
font-size: 0.9rem!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-on.btn {
|
||||||
|
font-size: 0.9rem!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas#divDBChartBandwidthhourly {
|
||||||
|
height: 350px!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 150px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-updated {
|
||||||
|
opacity: 0;
|
||||||
|
color: #90ee90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-progress {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-check {
|
||||||
|
color: #90ee90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-times {
|
||||||
|
color: #ff4500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,9 @@ Description: A theme inspired by HackerNews for RaspAP
|
|||||||
License: GNU General Public License v3.0
|
License: GNU General Public License v3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import url('all.css');
|
|
||||||
|
|
||||||
html * {
|
html * {
|
||||||
font-family: Verdana, Geneva, sans-serif;
|
font-family: Verdana, Geneva, sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
color: #828282;
|
color: #828282;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,12 +34,12 @@ h5.card-title {
|
|||||||
color: #212529;
|
color: #212529;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card, .modal-dialog {
|
.card {
|
||||||
border-radius: 3px;
|
border-radius: 1px;
|
||||||
border-color: #ff6600;
|
border-color: #ff6600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card>.card-header, .modal-header {
|
.card>.card-header {
|
||||||
border-color: #ff6600;
|
border-color: #ff6600;
|
||||||
background-color: #ff6600;
|
background-color: #ff6600;
|
||||||
color: #000;
|
color: #000;
|
||||||
@ -54,23 +53,19 @@ h5.card-title {
|
|||||||
font-size: 1.0rem;
|
font-size: 1.0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header [class^="fa"], .modal-header [class^="fa"] {
|
.card-header [class^="fa"] {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1.0rem;
|
font-size: 1.0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.sidebar-brand-text {
|
||||||
color: #000;
|
text-transform: none;
|
||||||
font-size: 1.0rem;
|
color: #212529;
|
||||||
|
font-size: 2.0rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: Verdana, Geneva, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light hr.sidebar-divider {
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav-tabs, .nav-tabs .nav-link {
|
ul.nav-tabs, .nav-tabs .nav-link {
|
||||||
background-color: #f6f6ef;
|
background-color: #f6f6ef;
|
||||||
@ -79,19 +74,39 @@ ul.nav-tabs, .nav-tabs .nav-link {
|
|||||||
|
|
||||||
.sidebar .nav-item .nav-link {
|
.sidebar .nav-item .nav-link {
|
||||||
padding: 0.6rem;
|
padding: 0.6rem;
|
||||||
margin-left: 0.6rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-light .nav-item.active .nav-link {
|
.sidebar-light .nav-item.active .nav-link {
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
font-size: 26pt;
|
||||||
|
margin: 10px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-logo {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
#wrapper,#page-wrapper,
|
#wrapper,#page-wrapper,
|
||||||
#wrapper #content-wrapper,
|
#wrapper #content-wrapper,
|
||||||
.nav>li>a,.nav {
|
.nav>li>a,.nav {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Small devices (portrait phones, up to 576px) */
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.container-fluid, .card-body, .col-md-6 { padding-left: 0.5rem; padding-right: 0.5rem; }
|
||||||
|
.card .card-header { padding: .75rem .5rem; font-size: 1.0rem; }
|
||||||
|
.row { margin-left: 0rem; margin-right: 0rem; }
|
||||||
|
.col-lg-12 { padding-right: 0.25rem; padding-left: 0.25rem; }
|
||||||
|
.form-group.col-md-6 { margin-left: -0.5rem; }
|
||||||
|
.js-wifi-stations { margin-left: -0.5rem; margin-right: -0.5rem; }
|
||||||
|
h4.mt-3 { margin-left: 0.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
background-color: #f6f6ef;
|
background-color: #f6f6ef;
|
||||||
}
|
}
|
||||||
@ -122,8 +137,48 @@ ul.nav-tabs, .nav-tabs .nav-link {
|
|||||||
color: #eee;
|
color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fas.fa-circle {
|
.info-item {
|
||||||
|
width: 10rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item-xs {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
|
margin-left: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item-wifi {
|
||||||
|
width: 6rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logoutput {
|
||||||
|
width: 100%;
|
||||||
|
height: 20rem;
|
||||||
|
border: 1px solid #d1d3e2;
|
||||||
|
border-radius: .35rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status {
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-up {
|
||||||
|
color: #a1ec38!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-warn {
|
||||||
|
color: #f6f044!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-down {
|
||||||
|
color: #f80107!important;
|
||||||
|
animation: flash 1s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes flash {
|
||||||
|
50% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoutput {
|
.logoutput {
|
||||||
@ -137,6 +192,26 @@ pre.unstyled {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dhcp-static-leases {
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dhcp-static-lease-row {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
background: url("../../app/img/loading-spinner.gif") no-repeat scroll center center transparent;
|
||||||
|
min-height: 150px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-reload-wifi-stations {
|
||||||
|
min-width: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar.toggled .nav-item .nav-link {
|
.sidebar.toggled .nav-item .nav-link {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: .6rem 1rem;
|
padding: .6rem 1rem;
|
||||||
@ -154,7 +229,45 @@ pre.unstyled {
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.signal-icon .signal-bar {
|
.toggle-off.btn {
|
||||||
background: #ff6600;
|
padding-left: 0.9rem;
|
||||||
|
font-size: 0.9rem!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-on.btn {
|
||||||
|
font-size: 0.9rem!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas#divDBChartBandwidthhourly {
|
||||||
|
height: 350px!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 150px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-updated {
|
||||||
|
opacity: 0;
|
||||||
|
color: #1cc88a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-progress {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-check {
|
||||||
|
color: #90ee90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-times {
|
||||||
|
color: #ff4500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,9 @@ Description: A dark mode theme for RaspAP
|
|||||||
License: GNU General Public License v3.0
|
License: GNU General Public License v3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import url('all.css');
|
|
||||||
|
|
||||||
html * {
|
html * {
|
||||||
font-family: Helvetica,Arial,sans-serif;
|
font-family: Helvetica,Arial,sans-serif;
|
||||||
|
font-size: 1.0rem;
|
||||||
color: #afafaf;
|
color: #afafaf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,8 +25,14 @@ h5.card-title {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
|
padding: 0 20px;
|
||||||
border-left: .01rem solid #d2d2d2;
|
border-left: .01rem solid #d2d2d2;
|
||||||
border-bottom: .01rem solid #d2d2d2;
|
}
|
||||||
|
|
||||||
|
.navbar-logo {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
filter: brightness(70%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-light .nav-item.active .nav-link i {
|
.sidebar-light .nav-item.active .nav-link i {
|
||||||
@ -42,6 +47,17 @@ h5.card-title {
|
|||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Small devices (portait phones, up to 576px) */
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.container-fluid, .card-body, .col-md-6 { padding-left: 0.5rem; padding-right: 0.5rem; }
|
||||||
|
.card .card-header { padding: .75rem .5rem; font-size: 1.0rem; }
|
||||||
|
.row { margin-left: 0rem; margin-right: 0rem; }
|
||||||
|
.col-lg-12 { padding-right: 0.25rem; padding-left: 0.25rem; }
|
||||||
|
.form-group.col-md-6 { margin-left: -0.5rem; }
|
||||||
|
.js-wifi-stations { margin-left: -0.5rem; margin-right: -0.5rem; }
|
||||||
|
h4.mt-3 { margin-left: 0.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
}
|
}
|
||||||
@ -76,6 +92,7 @@ h5.card-title {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#content, .navbar, .sidebar, .footer, .sticky-footer {
|
#content, .navbar, .sidebar, .footer, .sticky-footer {
|
||||||
|
background-image: url('/app/img/bg.png');
|
||||||
background-attachment: scroll;
|
background-attachment: scroll;
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
background-size: auto;
|
background-size: auto;
|
||||||
@ -102,7 +119,7 @@ a:focus, a:hover {
|
|||||||
color: #d2d2d2;
|
color: #d2d2d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card>.card-header, .modal-content, .modal-header {
|
.card>.card-header {
|
||||||
border-color: #404040;
|
border-color: #404040;
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
color: #afafaf;
|
color: #afafaf;
|
||||||
@ -112,10 +129,6 @@ a:focus, a:hover {
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
background-color: #141414;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header .fa {
|
.card>.card-header .fa {
|
||||||
color: #202020;
|
color: #202020;
|
||||||
}
|
}
|
||||||
@ -139,8 +152,18 @@ hr {
|
|||||||
border-top: .01rem solid #d2d2d2;
|
border-top: .01rem solid #d2d2d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
font-size: 24pt;
|
||||||
|
margin: 10px 0 20px;
|
||||||
|
border-bottom: .01rem solid #d2d2d2;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-brand-text {
|
.sidebar-brand-text {
|
||||||
color: #2b8080 !important;
|
text-transform: none;
|
||||||
|
color: #ac1b3d;
|
||||||
|
font-size: 2.0rem;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ra-raspap:before {
|
.ra-raspap:before {
|
||||||
@ -174,15 +197,11 @@ hr {
|
|||||||
width: 6.5rem;
|
width: 6.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-footer, .modal-footer {
|
.card-footer {
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
border-top: 0px;
|
border-top: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-footer {
|
|
||||||
border-radius: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header::before, .navbar-default::before {
|
.card>.card-header::before, .navbar-default::before {
|
||||||
content: " ";
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
@ -222,6 +241,22 @@ hr {
|
|||||||
border-right: 1px solid #404040;
|
border-right: 1px solid #404040;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
width: 12rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item-xs {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item-wifi {
|
||||||
|
width: 6rem;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
.label-warning {
|
.label-warning {
|
||||||
background-color: #d2d2d2;
|
background-color: #d2d2d2;
|
||||||
}
|
}
|
||||||
@ -315,33 +350,46 @@ color: #d2d2d2 !important
|
|||||||
background-color: #d2d2d2;
|
background-color: #d2d2d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.figure-img {
|
|
||||||
filter: opacity(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-wireguard:before {
|
|
||||||
color: #404040 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-wireguard:hover:before {
|
|
||||||
color: #d1d3e2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item.active .nav-link span.ra-wireguard:before {
|
|
||||||
color: #d2d2d2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logoutput {
|
.logoutput {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
background-color: #202020;
|
background-color: #202020;
|
||||||
border-color: #404040;
|
border-color: #404040;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tspan, rect {
|
||||||
|
fill: #d2d2d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.text.service-status {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin-top: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-muted {
|
.text-muted {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fas.fa-circle {
|
.fas.fa-circle {
|
||||||
font-size: 0.7rem;
|
font-size: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-up {
|
||||||
|
color: #a1ec38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-warn {
|
||||||
|
color: #f6f044 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-status-down {
|
||||||
|
color: #f80107 !important;
|
||||||
|
animation: flash 1s linear infinite;
|
||||||
|
}
|
||||||
|
@keyframes flash {
|
||||||
|
50% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
@ -349,12 +397,60 @@ pre {
|
|||||||
border: #202020;
|
border: #202020;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn.btn-light.js-toggle-password {
|
.dhcp-static-leases {
|
||||||
border: 1px solid #343434;
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dhcp-static-lease-row {
|
||||||
.signal-icon .signal-bar {
|
margin-top: 0.5em;
|
||||||
background: #2b8080;
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-off.btn {
|
||||||
|
padding-left: 1.2rem;
|
||||||
|
font-size: 0.9rem!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-on.btn {
|
||||||
|
font-size: 0.9rem!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas#divDBChartBandwidthhourly {
|
||||||
|
height: 350px!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
height: 150px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.figure, .authors {
|
||||||
|
filter: brightness(70%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-updated {
|
||||||
|
opacity: 0;
|
||||||
|
color: #1cc88a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-progress {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-check {
|
||||||
|
color: #90ee90;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-times {
|
||||||
|
color: #ff4500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,627 +0,0 @@
|
|||||||
<?php header("Content-Type: text/css; charset=utf-8"); ?>
|
|
||||||
<?php
|
|
||||||
require_once '../../includes/functions.php';
|
|
||||||
$color = getColorOpt();
|
|
||||||
?>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Theme Name: Material Dark
|
|
||||||
Author: @marek-guran
|
|
||||||
Author URI: https://github.com/marek-guran
|
|
||||||
Description: Inspired by Google's Material You Design
|
|
||||||
License: GNU General Public License v3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
<?php
|
|
||||||
// Base color
|
|
||||||
$baseColor = $color;
|
|
||||||
|
|
||||||
// Function to darken a color by a percentage
|
|
||||||
function darkenColor($color, $percent)
|
|
||||||
{
|
|
||||||
$percent /= 100;
|
|
||||||
$r = hexdec(substr($color, 1, 2));
|
|
||||||
$g = hexdec(substr($color, 3, 2));
|
|
||||||
$b = hexdec(substr($color, 5, 2));
|
|
||||||
|
|
||||||
$r = round($r * (1 - $percent));
|
|
||||||
$g = round($g * (1 - $percent));
|
|
||||||
$b = round($b * (1 - $percent));
|
|
||||||
|
|
||||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to lighten a color by a percentage
|
|
||||||
function lightenColor($color, $percent)
|
|
||||||
{
|
|
||||||
$percent /= 100;
|
|
||||||
$r = hexdec(substr($color, 1, 2));
|
|
||||||
$g = hexdec(substr($color, 3, 2));
|
|
||||||
$b = hexdec(substr($color, 5, 2));
|
|
||||||
|
|
||||||
$r = round($r + (255 - $r) * $percent);
|
|
||||||
$g = round($g + (255 - $g) * $percent);
|
|
||||||
$b = round($b + (255 - $b) * $percent);
|
|
||||||
|
|
||||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
|
||||||
}
|
|
||||||
|
|
||||||
$textColor = lightenColor($baseColor, 95);
|
|
||||||
// Create other color variables
|
|
||||||
$cardsColor = darkenColor($baseColor, 60);
|
|
||||||
$secondaryColor = lightenColor($baseColor, 30);
|
|
||||||
$primaryColor = $baseColor;
|
|
||||||
$backgroundColor = darkenColor($baseColor, 90);
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
@import url('all.css');
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
html * {
|
|
||||||
font-family: Helvetica,Arial,sans-serif;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item.active .nav-link {
|
|
||||||
position: relative;
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
||||||
border-top-right-radius: 18px;
|
|
||||||
border-bottom-right-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 2rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5.card-title {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-header {
|
|
||||||
border-left: .01rem solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-bottom: .01rem solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light .nav-item.active .nav-link i {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item.active .nav-link {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item .nav-link span:hover {
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrapper #content-wrapper #content {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header .col i.fa-tachometer-alt,
|
|
||||||
.card-header .col i.fa-dot-circle,
|
|
||||||
.card-header .col i.fa-wifi,
|
|
||||||
.card-header .col i.fa-exchange-alt,
|
|
||||||
.card-header .col i.fa-hand-paper,
|
|
||||||
.card-header .col i.fa-network-wired,
|
|
||||||
.card-header .col i.fa-key,
|
|
||||||
.card-header .ra-wireguard,
|
|
||||||
.card-header .ra-wireguard:before,
|
|
||||||
.card-header .col i.fa-user-lock,
|
|
||||||
.card-header .col i.fa-chart-bar,
|
|
||||||
.card-header .col i.fa-cube,
|
|
||||||
.card-header .col i.fa-info-circle,
|
|
||||||
.card-header .col i.fa-globe,
|
|
||||||
.card-header .col i.fa-shield-alt {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.fa-bars {
|
|
||||||
color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs {
|
|
||||||
border-bottom: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
.nav-tabs .nav-link.active,
|
|
||||||
.nav-tabs .nav-link {
|
|
||||||
font-size: 1.0rem;
|
|
||||||
border-top-left-radius: 18px;
|
|
||||||
border-top-right-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs .nav-link:hover {
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-brand:hover {
|
|
||||||
color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-toggle {
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-toggle .icon-bar {
|
|
||||||
background-color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-toggle:focus,
|
|
||||||
.navbar-default .navbar-toggle:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content, .navbar, .sidebar, .footer, .sticky-footer {
|
|
||||||
background-attachment: scroll;
|
|
||||||
background-repeat: repeat;
|
|
||||||
background-size: auto;
|
|
||||||
background-position: 0 0;
|
|
||||||
background-origin: padding-box;
|
|
||||||
background-clip: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sticky-footer {
|
|
||||||
background-position: 30px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
background-position: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs .nav-link.active {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:focus, a:hover {
|
|
||||||
color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header, .modal-content, .modal-header {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
border-radius: 18px;
|
|
||||||
font-size: 1.0rem;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
border-bottom-left-radius: 0px!important;
|
|
||||||
border-bottom-right-radius: 0px!important;
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: -18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header .fa {
|
|
||||||
color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header [class^="fa"] {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
font-size: 1.0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card, .card-body {
|
|
||||||
border-color: transparent;
|
|
||||||
border-radius: 18px;
|
|
||||||
background-color: <?php echo $cardsColor; ?>;
|
|
||||||
box-shadow: 0px -5px 5px rgba(0, 0, 0, 0.1),
|
|
||||||
0px 4px 6px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body {
|
|
||||||
padding-top: 36px; /* 18px to move down + 18px space at the top */
|
|
||||||
padding-bottom: 36px; /* 18px space at the bottom */
|
|
||||||
}
|
|
||||||
|
|
||||||
.unstyled {
|
|
||||||
background-color: <?php echo $cardsColor; ?>;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border-top: .01rem solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-brand-text {
|
|
||||||
color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-raspap:before {
|
|
||||||
color: #ac1b3d !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light #sidebarToggle {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>; !important
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light #sidebarToggle::after {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light .nav-item .nav-link:hover i {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light #sidebarToggle:hover {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar.toggled .nav-item .nav-link span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar.toggled .nav-item .nav-link {
|
|
||||||
text-align: center;
|
|
||||||
padding: .6rem 1rem;
|
|
||||||
width: 6.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-footer, .modal-footer {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
border-top: 0px;
|
|
||||||
border-bottom-right-radius: 18px!important;
|
|
||||||
border-bottom-left-radius: 18px!important;
|
|
||||||
position: relative;
|
|
||||||
margin-top: -18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-footer {
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header::before, .navbar-default::before {
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 2;
|
|
||||||
background-size: 100% 2px, 3px 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light, .sticky-footer {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light .nav-item .nav-link i {
|
|
||||||
color: rgba(230, 230, 230, .3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item .nav-link {
|
|
||||||
padding: 0.6rem;
|
|
||||||
padding-left: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light hr.sidebar-divider {
|
|
||||||
border-top: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item .nav-link span {
|
|
||||||
font-size: 1.0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar .topbar-divider {
|
|
||||||
border-right: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-warning {
|
|
||||||
background-color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.label.label-warning {
|
|
||||||
color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table>tbody>tr>td,
|
|
||||||
.table>tbody>tr>th,
|
|
||||||
.table>tfoot>tr>td,
|
|
||||||
.table>tfoot>tr>th,
|
|
||||||
.table>thead>tr>td,
|
|
||||||
.table>thead>tr>th {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border-top: .01rem solid <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table{
|
|
||||||
border-radius: 18px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table>thead>tr>th {
|
|
||||||
vertical-align: bottom;
|
|
||||||
border-bottom: 0 solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="btn"], [class*="btn"]:focus, [class*="btn"]:disabled {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
border-radius: 18px;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="btn"]:hover {
|
|
||||||
border-radius: 18px;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="btn"]:hover .disabled {
|
|
||||||
background-color:red;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="alert"] {
|
|
||||||
border-radius: 18px;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: 1px solid #404040;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
font-size: 1.2em;
|
|
||||||
font-weight: 400;
|
|
||||||
text-shadow: none;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control,
|
|
||||||
.form-control:focus,
|
|
||||||
.custom-select {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:disabled,
|
|
||||||
.form-control[readonly] {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control::-webkit-input-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control:-moz-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control::-moz-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control:-ms-input-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control::-ms-input-placeholder { color: #d2d2d2; }
|
|
||||||
|
|
||||||
.form-control option {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"]{
|
|
||||||
color: <?php echo $textColor; ?>; !important
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#progressBar {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar.bg-success {
|
|
||||||
background-color: <?php echo $primaryColor; ?>!important;
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress .progress-bar {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar.progress-bar-info.progress-bar-striped.active {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.figure-img {
|
|
||||||
filter: opacity(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-wireguard:before {
|
|
||||||
color: #404040 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-wireguard:hover:before {
|
|
||||||
color: #d1d3e2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item.active .nav-link span.ra-wireguard:before {
|
|
||||||
color: #d2d2d2 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-control-input:checked ~ .custom-control-label::before {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-control-input:checked ~ .custom-control-label::before {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wg-keygen {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid yellow <?php echo $secondaryColor; ?>;
|
|
||||||
border-top-right-radius: 18px !important;
|
|
||||||
border-bottom-right-radius: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-secondary.js-add-dhcp-upstream-server {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-top-right-radius: 18px !important;
|
|
||||||
border-bottom-right-radius: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-success.js-add-dhcp-static-lease {
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-success.js-add-dhcp-static-lease:hover {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-muted {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fas.fa-circle {
|
|
||||||
font-size: 0.7rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-light.js-toggle-password {
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.service-status {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-success {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-success:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon .signal-bar {
|
|
||||||
background: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.figure-img {
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logoutput {
|
|
||||||
border-radius: 18px!important;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: 1px solid <?php echo $primaryColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
border-top-right-radius: 18px!important;
|
|
||||||
border-bottom-right-radius: 18px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon .signal-bar {
|
|
||||||
background: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-warning {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-warning:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-danger {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-danger:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group label.active {
|
|
||||||
background-color: <?php echo $primaryColor; ?>!important;
|
|
||||||
border-color:transparent!important;
|
|
||||||
color: <?php echo $textColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group {
|
|
||||||
background-color: <?php echo $cardsColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group:hover {
|
|
||||||
background-color: <?php echo $cardsColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-secondary#gen_wpa_passphrase {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-top-right-radius: 18px !important;
|
|
||||||
border-bottom-right-radius: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.scroll-to-top.rounded {
|
|
||||||
display: inline;
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-radius: 18px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.scroll-to-top.rounded i.fas.fa-angle-up {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-sm.btn-outline-secondary.rounded-right {
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item.col-xs-3 {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-muted {
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-stack-item-content {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 5px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
@ -1,633 +0,0 @@
|
|||||||
<?php header("Content-Type: text/css; charset=utf-8"); ?>
|
|
||||||
<?php
|
|
||||||
require_once '../../includes/functions.php';
|
|
||||||
$color = getColorOpt();
|
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Theme Name: Material Light
|
|
||||||
Author: @marek-guran
|
|
||||||
Author URI: https://github.com/marek-guran
|
|
||||||
Description: Inspired by Google's Material You Design
|
|
||||||
License: GNU General Public License v3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
<?php
|
|
||||||
// Base color
|
|
||||||
$baseColor = $color;
|
|
||||||
|
|
||||||
// Function to darken a color by a percentage
|
|
||||||
function darkenColor($color, $percent)
|
|
||||||
{
|
|
||||||
$percent /= 100;
|
|
||||||
$r = hexdec(substr($color, 1, 2));
|
|
||||||
$g = hexdec(substr($color, 3, 2));
|
|
||||||
$b = hexdec(substr($color, 5, 2));
|
|
||||||
|
|
||||||
$r = round($r * (1 - $percent));
|
|
||||||
$g = round($g * (1 - $percent));
|
|
||||||
$b = round($b * (1 - $percent));
|
|
||||||
|
|
||||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to lighten a color by a percentage
|
|
||||||
function lightenColor($color, $percent)
|
|
||||||
{
|
|
||||||
$percent /= 100;
|
|
||||||
$r = hexdec(substr($color, 1, 2));
|
|
||||||
$g = hexdec(substr($color, 3, 2));
|
|
||||||
$b = hexdec(substr($color, 5, 2));
|
|
||||||
|
|
||||||
$r = round($r + (255 - $r) * $percent);
|
|
||||||
$g = round($g + (255 - $g) * $percent);
|
|
||||||
$b = round($b + (255 - $b) * $percent);
|
|
||||||
|
|
||||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
|
||||||
}
|
|
||||||
|
|
||||||
$textColor = lightenColor($baseColor, 95);
|
|
||||||
// Create other color variables
|
|
||||||
$cardsColor = lightenColor($baseColor, 50);
|
|
||||||
$secondaryColor = lightenColor($baseColor, 30);
|
|
||||||
$primaryColor = $baseColor;
|
|
||||||
$backgroundColor = lightenColor($baseColor, 60);
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
@import url('all.css');
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
html * {
|
|
||||||
font-family: Helvetica,Arial,sans-serif;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-item.active .nav-link {
|
|
||||||
position: relative;
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
||||||
border-top-right-radius: 18px;
|
|
||||||
border-bottom-right-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 2rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5.card-title {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-header {
|
|
||||||
border-left: .01rem solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-bottom: .01rem solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light .nav-item.active .nav-link i {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item.active .nav-link {
|
|
||||||
font-weight: 400;
|
|
||||||
color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wrapper #content-wrapper #content {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header .col i.fa-tachometer-alt,
|
|
||||||
.card-header .col i.fa-dot-circle,
|
|
||||||
.card-header .col i.fa-wifi,
|
|
||||||
.card-header .col i.fa-exchange-alt,
|
|
||||||
.card-header .col i.fa-hand-paper,
|
|
||||||
.card-header .col i.fa-network-wired,
|
|
||||||
.card-header .col i.fa-key,
|
|
||||||
.card-header .ra-wireguard,
|
|
||||||
.card-header .ra-wireguard:before,
|
|
||||||
.card-header .col i.fa-user-lock,
|
|
||||||
.card-header .col i.fa-chart-bar,
|
|
||||||
.card-header .col i.fa-cube,
|
|
||||||
.card-header .col i.fa-info-circle,
|
|
||||||
.card-header .col i.fa-globe,
|
|
||||||
.card-header .col i.fa-shield-alt {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
i.fa-bars {
|
|
||||||
color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs {
|
|
||||||
border-bottom: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
.nav-tabs .nav-link.active,
|
|
||||||
.nav-tabs .nav-link {
|
|
||||||
font-size: 1.0rem;
|
|
||||||
border-top-left-radius: 18px;
|
|
||||||
border-top-right-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs .nav-link:hover {
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-brand:hover {
|
|
||||||
color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-toggle {
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-toggle .icon-bar {
|
|
||||||
background-color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-default .navbar-toggle:focus,
|
|
||||||
.navbar-default .navbar-toggle:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content, .navbar, .sidebar, .footer, .sticky-footer {
|
|
||||||
background-attachment: scroll;
|
|
||||||
background-repeat: repeat;
|
|
||||||
background-size: auto;
|
|
||||||
background-position: 0 0;
|
|
||||||
background-origin: padding-box;
|
|
||||||
background-clip: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sticky-footer {
|
|
||||||
background-position: 30px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
background-position: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-tabs .nav-link.active {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:focus, a:hover {
|
|
||||||
color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header, .modal-content, .modal-header {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
border-radius: 18px;
|
|
||||||
font-size: 1.0rem;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
border-bottom-left-radius: 0px!important;
|
|
||||||
border-bottom-right-radius: 0px!important;
|
|
||||||
position: relative;
|
|
||||||
margin-bottom: -18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header .fa {
|
|
||||||
color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header [class^="fa"] {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
font-size: 1.0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card, .card-body {
|
|
||||||
border-color: transparent;
|
|
||||||
border-radius: 18px;
|
|
||||||
background-color: <?php echo $cardsColor; ?>;
|
|
||||||
box-shadow: 0px -5px 5px rgba(0, 0, 0, 0.1),
|
|
||||||
0px 4px 6px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body {
|
|
||||||
padding-top: 36px; /* 18px to move down + 18px space at the top */
|
|
||||||
padding-bottom: 36px; /* 18px space at the bottom */
|
|
||||||
}
|
|
||||||
|
|
||||||
.unstyled {
|
|
||||||
background-color: <?php echo $cardsColor; ?>;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border-top: .01rem solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-brand-text {
|
|
||||||
color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-raspap:before {
|
|
||||||
color: #ac1b3d !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light #sidebarToggle {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>; !important
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light #sidebarToggle::after {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light .nav-item .nav-link:hover i {
|
|
||||||
color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light #sidebarToggle:hover {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar.toggled .nav-item .nav-link span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar.toggled .nav-item .nav-link {
|
|
||||||
text-align: center;
|
|
||||||
padding: .6rem 1rem;
|
|
||||||
width: 6.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-footer, .modal-footer {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
border-top: 0px;
|
|
||||||
border-bottom-right-radius: 18px!important;
|
|
||||||
border-bottom-left-radius: 18px!important;
|
|
||||||
position: relative;
|
|
||||||
margin-top: -18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-footer {
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card>.card-header::before, .navbar-default::before {
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 2;
|
|
||||||
background-size: 100% 2px, 3px 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light, .sticky-footer {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light .nav-item .nav-link i {
|
|
||||||
color: <?php echo $textColor; ?>;;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item .nav-link {
|
|
||||||
padding: 0.6rem;
|
|
||||||
padding-left: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-light hr.sidebar-divider {
|
|
||||||
border-top: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item .nav-link span {
|
|
||||||
font-size: 1.0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item .nav-link span:hover {
|
|
||||||
color: <?php echo $primaryColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar .topbar-divider {
|
|
||||||
border-right: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-warning {
|
|
||||||
background-color: #d2d2d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.label.label-warning {
|
|
||||||
color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table>tbody>tr>td,
|
|
||||||
.table>tbody>tr>th,
|
|
||||||
.table>tfoot>tr>td,
|
|
||||||
.table>tfoot>tr>th,
|
|
||||||
.table>thead>tr>td,
|
|
||||||
.table>thead>tr>th {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border-top: .01rem solid <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table{
|
|
||||||
border-radius: 18px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.table>thead>tr>th {
|
|
||||||
vertical-align: bottom;
|
|
||||||
border-bottom: 0 solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="btn"], [class*="btn"]:focus, [class*="btn"]:disabled {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
border-radius: 18px;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="btn"]:hover {
|
|
||||||
border-radius: 18px;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="btn"]:hover .disabled {
|
|
||||||
background-color:red;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="alert"] {
|
|
||||||
border-radius: 18px;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: 1px solid #404040;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close {
|
|
||||||
font-size: 1.2em;
|
|
||||||
font-weight: 400;
|
|
||||||
text-shadow: none;
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control,
|
|
||||||
.form-control:focus,
|
|
||||||
.custom-select {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:disabled,
|
|
||||||
.form-control[readonly] {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control::-webkit-input-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control:-moz-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control::-moz-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control:-ms-input-placeholder { color: #d2d2d2; }
|
|
||||||
.form-control::-ms-input-placeholder { color: #d2d2d2; }
|
|
||||||
|
|
||||||
.form-control option {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control::placeholder {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"]{
|
|
||||||
color: <?php echo $textColor; ?>; !important
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
color: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#progressBar {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar.bg-success {
|
|
||||||
background-color: <?php echo $primaryColor; ?>!important;
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress .progress-bar {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar.progress-bar-info.progress-bar-striped.active {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.figure-img {
|
|
||||||
filter: opacity(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-wireguard:before {
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ra-wireguard:hover:before {
|
|
||||||
color: <?php echo $primaryColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-item.active .nav-link span.ra-wireguard:before {
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-control-input:checked ~ .custom-control-label::before {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-control-input:checked ~ .custom-control-label::before {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wg-keygen {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid yellow <?php echo $secondaryColor; ?>;
|
|
||||||
border-top-right-radius: 18px !important;
|
|
||||||
border-bottom-right-radius: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-secondary.js-add-dhcp-upstream-server {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-top-right-radius: 18px !important;
|
|
||||||
border-bottom-right-radius: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-success.js-add-dhcp-static-lease {
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-success.js-add-dhcp-static-lease:hover {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-muted {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fas.fa-circle {
|
|
||||||
font-size: 0.7rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: <?php echo $backgroundColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-light.js-toggle-password {
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.service-status {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-success {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-success:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon .signal-bar {
|
|
||||||
background: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.figure-img {
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logoutput {
|
|
||||||
border-radius: 18px!important;
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;
|
|
||||||
border: 1px solid <?php echo $primaryColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
border-top-right-radius: 18px!important;
|
|
||||||
border-bottom-right-radius: 18px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signal-icon .signal-bar {
|
|
||||||
background: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-warning {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn.btn-warning:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-danger {
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn.btn-danger:hover {
|
|
||||||
background-color: <?php echo $backgroundColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group label.active {
|
|
||||||
background-color: <?php echo $primaryColor; ?>!important;
|
|
||||||
border-color:transparent!important;
|
|
||||||
color: <?php echo $textColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group {
|
|
||||||
background-color: <?php echo $cardsColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-group:hover {
|
|
||||||
background-color: <?php echo $cardsColor; ?>;!important
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-outline-secondary#gen_wpa_passphrase {
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
border-top-right-radius: 18px !important;
|
|
||||||
border-bottom-right-radius: 18px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.scroll-to-top.rounded {
|
|
||||||
display: inline;
|
|
||||||
background-color: <?php echo $secondaryColor; ?>;
|
|
||||||
border-radius: 18px!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.scroll-to-top.rounded i.fas.fa-angle-up {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.btn-sm.btn-outline-secondary.rounded-right {
|
|
||||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
|
||||||
background-color: <?php echo $primaryColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-item.col-xs-3 {
|
|
||||||
color: <?php echo $textColor; ?>;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-muted {
|
|
||||||
color: <?php echo $textColor; ?>!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-stack-item-content {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
padding: 5px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
@ -3,7 +3,7 @@
|
|||||||
"short_name": "RaspAP",
|
"short_name": "RaspAP",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/app/icons/android-chrome-192x192.png",
|
"src": "/dist/icons/android-chrome-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
}
|
}
|
||||||
|
BIN
app/img/180x150.png
Normal file
BIN
app/img/180x150.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
BIN
app/img/authors-8bit-200px.png
Normal file
BIN
app/img/authors-8bit-200px.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
app/img/bg.png
Normal file
BIN
app/img/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
@ -1,28 +0,0 @@
|
|||||||
<?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);
|
|
||||||
|
|
@ -10,6 +10,11 @@ if (!isset($_SERVER['HTTP_REFERER'])) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function qr_encode($str)
|
||||||
|
{
|
||||||
|
return preg_replace('/(?<!\\\)([\":;,])/', '\\\\\1', $str);
|
||||||
|
}
|
||||||
|
|
||||||
$hostapd = parse_ini_file(RASPI_HOSTAPD_CONFIG, false, INI_SCANNER_RAW);
|
$hostapd = parse_ini_file(RASPI_HOSTAPD_CONFIG, false, INI_SCANNER_RAW);
|
||||||
|
|
||||||
// assume wpa encryption and get the passphrase
|
// assume wpa encryption and get the passphrase
|
||||||
@ -36,7 +41,7 @@ $ssid = qr_encode($ssid);
|
|||||||
$password = qr_encode($password);
|
$password = qr_encode($password);
|
||||||
|
|
||||||
$data = "WIFI:S:$ssid;T:$type;P:$password;$hidden;";
|
$data = "WIFI:S:$ssid;T:$type;P:$password;$hidden;";
|
||||||
$command = "qrencode -t svg -m 1 -o - " . mb_escapeshellarg($data);
|
$command = "qrencode -t svg -m 0 -o - " . mb_escapeshellarg($data);
|
||||||
$svg = shell_exec($command);
|
$svg = shell_exec($command);
|
||||||
|
|
||||||
$config_mtime = filemtime(RASPI_HOSTAPD_CONFIG);
|
$config_mtime = filemtime(RASPI_HOSTAPD_CONFIG);
|
||||||
@ -47,8 +52,7 @@ $content_length = strlen($svg);
|
|||||||
header("Content-Type: image/svg+xml");
|
header("Content-Type: image/svg+xml");
|
||||||
header("Content-Length: $content_length");
|
header("Content-Length: $content_length");
|
||||||
header("Last-Modified: $last_modified");
|
header("Last-Modified: $last_modified");
|
||||||
header("Content-Disposition: attachment; filename=\"qr.svg\"");
|
|
||||||
header("ETag: \"$etag\"");
|
header("ETag: \"$etag\"");
|
||||||
header("X-QR-Code-Content: $data");
|
header("X-QR-Code-Content: $data");
|
||||||
echo $svg;
|
echo shell_exec($command);
|
||||||
|
|
||||||
|
414
app/js/custom.js
414
app/js/custom.js
@ -1,5 +1,6 @@
|
|||||||
function msgShow(retcode,msg) {
|
function msgShow(retcode,msg) {
|
||||||
if(retcode == 0) { var alertType = 'success';
|
if(retcode == 0) {
|
||||||
|
var alertType = 'success';
|
||||||
} else if(retcode == 2 || retcode == 1) {
|
} else if(retcode == 2 || retcode == 1) {
|
||||||
var alertType = 'danger';
|
var alertType = 'danger';
|
||||||
}
|
}
|
||||||
@ -18,9 +19,9 @@ function createNetmaskAddr(bitCount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadSummary(strInterface) {
|
function loadSummary(strInterface) {
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
$.post('ajax/networking/get_ip_summary.php',{interface:strInterface},function(data){
|
||||||
$.post('ajax/networking/get_ip_summary.php',{'interface': strInterface, 'csrf_token': csrfToken},function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
jsonData = JSON.parse(data);
|
||||||
|
console.log(jsonData);
|
||||||
if(jsonData['return'] == 0) {
|
if(jsonData['return'] == 0) {
|
||||||
$('#'+strInterface+'-summary').html(jsonData['output'].join('<br />'));
|
$('#'+strInterface+'-summary').html(jsonData['output'].join('<br />'));
|
||||||
} else if(jsonData['return'] == 2) {
|
} else if(jsonData['return'] == 2) {
|
||||||
@ -48,24 +49,89 @@ function setupTabs() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadCurrentSettings(strInterface) {
|
||||||
|
$.post('ajax/networking/get_int_config.php',{interface:strInterface},function(data){
|
||||||
|
jsonData = JSON.parse(data);
|
||||||
|
$.each(jsonData['output'],function(i,v) {
|
||||||
|
var int = v['interface'];
|
||||||
|
$.each(v,function(i2,v2) {
|
||||||
|
switch(i2) {
|
||||||
|
case "static":
|
||||||
|
if(v2 == 'true') {
|
||||||
|
$('#'+int+'-static').click();
|
||||||
|
$('#'+int+'-nofailover').click();
|
||||||
|
} else {
|
||||||
|
$('#'+int+'-dhcp').click();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "failover":
|
||||||
|
if(v2 === 'true') {
|
||||||
|
$('#'+int+'-failover').click();
|
||||||
|
} else {
|
||||||
|
$('#'+int+'-nofailover').click();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ip_address":
|
||||||
|
var arrIPNetmask = v2.split('/');
|
||||||
|
$('#'+int+'-ipaddress').val(arrIPNetmask[0]);
|
||||||
|
$('#'+int+'-netmask').val(createNetmaskAddr(arrIPNetmask[1]));
|
||||||
|
break;
|
||||||
|
case "routers":
|
||||||
|
$('#'+int+'-gateway').val(v2);
|
||||||
|
break;
|
||||||
|
case "domain_name_server":
|
||||||
|
svrsDNS = v2.split(" ");
|
||||||
|
$('#'+int+'-dnssvr').val(svrsDNS[0]);
|
||||||
|
$('#'+int+'-dnssvralt').val(svrsDNS[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveNetworkSettings(int) {
|
||||||
|
var frmInt = $('#frm-'+int).find(':input');
|
||||||
|
var arrFormData = {};
|
||||||
|
$.each(frmInt,function(i3,v3){
|
||||||
|
if($(v3).attr('type') == 'radio') {
|
||||||
|
arrFormData[$(v3).attr('id')] = $(v3).prop('checked');
|
||||||
|
} else {
|
||||||
|
arrFormData[$(v3).attr('id')] = $(v3).val();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
arrFormData['interface'] = int;
|
||||||
|
$.post('ajax/networking/save_int_config.php',arrFormData,function(data){
|
||||||
|
var jsonData = JSON.parse(data);
|
||||||
|
$('#msgNetworking').html(msgShow(jsonData['return'],jsonData['output']));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyNetworkSettings() {
|
||||||
|
var int = $(this).data('int');
|
||||||
|
arrFormData = {};
|
||||||
|
arrFormData['generate'] = '';
|
||||||
|
$.post('ajax/networking/gen_int_config.php',arrFormData,function(data){
|
||||||
|
var jsonData = JSON.parse(data);
|
||||||
|
$('#msgNetworking').html(msgShow(jsonData['return'],jsonData['output']));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$(document).on("click", ".js-add-dhcp-static-lease", function(e) {
|
$(document).on("click", ".js-add-dhcp-static-lease", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var container = $(".js-new-dhcp-static-lease");
|
var container = $(".js-new-dhcp-static-lease");
|
||||||
var mac = $("input[name=mac]", container).val().trim();
|
var mac = $("input[name=mac]", container).val().trim();
|
||||||
var ip = $("input[name=ip]", container).val().trim();
|
var ip = $("input[name=ip]", container).val().trim();
|
||||||
var comment = $("input[name=comment]", container).val().trim();
|
|
||||||
if (mac == "" || ip == "") {
|
if (mac == "" || ip == "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var row = $("#js-dhcp-static-lease-row").html()
|
var row = $("#js-dhcp-static-lease-row").html()
|
||||||
.replace("{{ mac }}", mac)
|
.replace("{{ mac }}", mac)
|
||||||
.replace("{{ ip }}", ip)
|
.replace("{{ ip }}", ip);
|
||||||
.replace("{{ comment }}", comment);
|
|
||||||
$(".js-dhcp-static-lease-container").append(row);
|
$(".js-dhcp-static-lease-container").append(row);
|
||||||
|
|
||||||
$("input[name=mac]", container).val("");
|
$("input[name=mac]", container).val("");
|
||||||
$("input[name=ip]", container).val("");
|
$("input[name=ip]", container).val("");
|
||||||
$("input[name=comment]", container).val("");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", ".js-remove-dhcp-static-lease", function(e) {
|
$(document).on("click", ".js-remove-dhcp-static-lease", function(e) {
|
||||||
@ -122,36 +188,6 @@ $(document).on("click", "#gen_wpa_passphrase", function(e) {
|
|||||||
$('#txtwpapassphrase').val(genPassword(63));
|
$('#txtwpapassphrase').val(genPassword(63));
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", "#js-clearhostapd-log", function(e) {
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
$.post('ajax/logging/clearlog.php?',{'logfile':'/tmp/hostapd.log', 'csrf_token': csrfToken},function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
$("#hostapd-log").val("");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on("click", "#js-cleardnsmasq-log", function(e) {
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
$.post('ajax/logging/clearlog.php?',{'logfile':'/var/log/dnsmasq.log', 'csrf_token': csrfToken},function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
$("#dnsmasq-log").val("");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on("click", "#js-clearopenvpn-log", function(e) {
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
$.post('ajax/logging/clearlog.php?',{'logfile':'/tmp/openvpn.log', 'csrf_token': csrfToken},function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
$("#openvpn-log").val("");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Enable Bootstrap tooltips
|
|
||||||
$(function () {
|
|
||||||
$('[data-toggle="tooltip"]').tooltip()
|
|
||||||
})
|
|
||||||
|
|
||||||
function genPassword(pwdLen) {
|
function genPassword(pwdLen) {
|
||||||
var pwdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
var pwdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
var rndPass = Array(pwdLen).fill(pwdChars).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
|
var rndPass = Array(pwdLen).fill(pwdChars).map(function(x) { return x[Math.floor(Math.random() * x.length)] }).join('');
|
||||||
@ -177,19 +213,15 @@ function setCSRFTokenHeader(event, xhr, settings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function contentLoaded() {
|
function contentLoaded() {
|
||||||
pageCurrent = window.location.href.split("/").pop();
|
pageCurrent = window.location.href.split("?")[1].split("=")[1];
|
||||||
|
pageCurrent = pageCurrent.replace("#","");
|
||||||
switch(pageCurrent) {
|
switch(pageCurrent) {
|
||||||
case "network_conf":
|
case "network_conf":
|
||||||
getAllInterfaces();
|
getAllInterfaces();
|
||||||
setupTabs();
|
setupTabs();
|
||||||
setupBtns();
|
setupBtns();
|
||||||
break;
|
|
||||||
case "hostapd_conf":
|
case "hostapd_conf":
|
||||||
loadChannel();
|
loadChannel();
|
||||||
setHardwareModeTooltip();
|
|
||||||
break;
|
|
||||||
case "dhcpd_conf":
|
|
||||||
loadInterfaceDHCPSelect();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,68 +236,9 @@ function loadWifiStations(refresh) {
|
|||||||
.load('ajax/networking/wifi_stations.php'+qs, complete);
|
.load('ajax/networking/wifi_stations.php'+qs, complete);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$(".js-reload-wifi-stations").on("click", loadWifiStations(true));
|
$(".js-reload-wifi-stations").on("click", loadWifiStations(true));
|
||||||
|
|
||||||
/*
|
|
||||||
Populates the DHCP server form fields
|
|
||||||
Option toggles are set dynamically depending on the loaded configuration
|
|
||||||
*/
|
|
||||||
function loadInterfaceDHCPSelect() {
|
|
||||||
var strInterface = $('#cbxdhcpiface').val();
|
|
||||||
$.get('ajax/networking/get_netcfg.php?iface='+strInterface,function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
$('#dhcp-iface')[0].checked = jsonData.DHCPEnabled;
|
|
||||||
$('#txtipaddress').val(jsonData.StaticIP);
|
|
||||||
$('#txtsubnetmask').val(jsonData.SubnetMask);
|
|
||||||
$('#txtgateway').val(jsonData.StaticRouters);
|
|
||||||
$('#chkfallback')[0].checked = jsonData.FallbackEnabled;
|
|
||||||
$('#default-route').prop('checked', jsonData.DefaultRoute);
|
|
||||||
if (strInterface.startsWith("wl")) {
|
|
||||||
$('#nohook-wpa-supplicant').parent().parent().parent().show()
|
|
||||||
$('#nohook-wpa-supplicant').prop('checked', jsonData.NoHookWPASupplicant);
|
|
||||||
} else {
|
|
||||||
$('#nohook-wpa-supplicant').parent().parent().parent().hide()
|
|
||||||
}
|
|
||||||
$('#txtrangestart').val(jsonData.RangeStart);
|
|
||||||
$('#txtrangeend').val(jsonData.RangeEnd);
|
|
||||||
$('#txtrangeleasetime').val(jsonData.leaseTime);
|
|
||||||
$('#txtdns1').val(jsonData.DNS1);
|
|
||||||
$('#txtdns2').val(jsonData.DNS2);
|
|
||||||
$('#cbxrangeleasetimeunits').val(jsonData.leaseTimeInterval);
|
|
||||||
$('#no-resolv')[0].checked = jsonData.upstreamServersEnabled;
|
|
||||||
$('#cbxdhcpupstreamserver').val(jsonData.upstreamServers[0]);
|
|
||||||
$('#txtmetric').val(jsonData.Metric);
|
|
||||||
|
|
||||||
if (jsonData.StaticIP !== null && jsonData.StaticIP !== '' && !jsonData.FallbackEnabled) {
|
|
||||||
$('#chkstatic').closest('.btn').button('toggle');
|
|
||||||
$('#chkstatic').closest('.btn').button('toggle').blur();
|
|
||||||
$('#chkstatic').blur();
|
|
||||||
$('#chkfallback').prop('disabled', true);
|
|
||||||
} else {
|
|
||||||
$('#chkdhcp').closest('.btn').button('toggle');
|
|
||||||
$('#chkdhcp').closest('.btn').button('toggle').blur();
|
|
||||||
$('#chkdhcp').blur();
|
|
||||||
$('#chkfallback').prop('disabled', false);
|
|
||||||
}
|
|
||||||
if (jsonData.FallbackEnabled || $('#chkdhcp').is(':checked')) {
|
|
||||||
$('#dhcp-iface').prop('disabled', true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setDHCPToggles(state) {
|
|
||||||
if ($('#chkfallback').is(':checked') && state) {
|
|
||||||
$('#chkfallback').prop('checked', state);
|
|
||||||
}
|
|
||||||
if ($('#dhcp-iface').is(':checked') && !state) {
|
|
||||||
$('#dhcp-iface').prop('checked', state);
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#chkfallback').prop('disabled', state);
|
|
||||||
$('#dhcp-iface').prop('disabled', !state);
|
|
||||||
//$('#dhcp-iface').prop('checked', state);
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadChannel() {
|
function loadChannel() {
|
||||||
$.get('ajax/networking/get_channel.php',function(data){
|
$.get('ajax/networking/get_channel.php',function(data){
|
||||||
jsonData = JSON.parse(data);
|
jsonData = JSON.parse(data);
|
||||||
@ -273,116 +246,6 @@ function loadChannel() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#hostapdModal').on('shown.bs.modal', function (e) {
|
|
||||||
var seconds = 9;
|
|
||||||
var countDown = setInterval(function(){
|
|
||||||
if(seconds <= 0){
|
|
||||||
clearInterval(countDown);
|
|
||||||
}
|
|
||||||
var pct = Math.floor(100-(seconds*100/9));
|
|
||||||
document.getElementsByClassName('progress-bar').item(0).setAttribute('style','width:'+Number(pct)+'%');
|
|
||||||
seconds --;
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#configureClientModal').on('shown.bs.modal', function (e) {
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#ovpn-confirm-delete').on('click', '.btn-delete', function (e) {
|
|
||||||
var cfg_id = $(this).data('recordId');
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
$.post('ajax/openvpn/del_ovpncfg.php',{'cfg_id':cfg_id, 'csrf_token': csrfToken},function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
$("#ovpn-confirm-delete").modal('hide');
|
|
||||||
var row = $(document.getElementById("openvpn-client-row-" + cfg_id));
|
|
||||||
row.fadeOut( "slow", function() {
|
|
||||||
row.remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#ovpn-confirm-delete').on('show.bs.modal', function (e) {
|
|
||||||
var data = $(e.relatedTarget).data();
|
|
||||||
$('.btn-delete', this).data('recordId', data.recordId);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#ovpn-confirm-activate').on('click', '.btn-activate', function (e) {
|
|
||||||
var cfg_id = $(this).data('record-id');
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
$.post('ajax/openvpn/activate_ovpncfg.php',{'cfg_id':cfg_id, 'csrf_token': csrfToken},function(data){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
$("#ovpn-confirm-activate").modal('hide');
|
|
||||||
setTimeout(function(){
|
|
||||||
window.location.reload();
|
|
||||||
},300);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#ovpn-confirm-activate').on('shown.bs.modal', function (e) {
|
|
||||||
var data = $(e.relatedTarget).data();
|
|
||||||
$('.btn-activate', this).data('recordId', data.recordId);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#ovpn-userpw,#ovpn-certs').on('click', function (e) {
|
|
||||||
if (this.id == 'ovpn-userpw') {
|
|
||||||
$('#PanelCerts').hide();
|
|
||||||
$('#PanelUserPW').show();
|
|
||||||
} else if (this.id == 'ovpn-certs') {
|
|
||||||
$('#PanelUserPW').hide();
|
|
||||||
$('#PanelCerts').show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#js-system-reset-confirm').on('click', function (e) {
|
|
||||||
var progressText = $('#js-system-reset-confirm').attr('data-message');
|
|
||||||
var successHtml = $('#system-reset-message').attr('data-message');
|
|
||||||
var closeHtml = $('#js-system-reset-cancel').attr('data-message');
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
var progressHtml = $('<div>').text(progressText).html() + '<i class="fas fa-cog fa-spin ml-2"></i>';
|
|
||||||
$('#system-reset-message').html(progressHtml);
|
|
||||||
$.post('ajax/networking/do_sys_reset.php?',{'csrf_token':csrfToken},function(data){
|
|
||||||
setTimeout(function(){
|
|
||||||
jsonData = JSON.parse(data);
|
|
||||||
if(jsonData['return'] == 0) {
|
|
||||||
$('#system-reset-message').text(successHtml);
|
|
||||||
} else {
|
|
||||||
$('#system-reset-message').text('Error occured: '+ jsonData['return']);
|
|
||||||
}
|
|
||||||
$("#js-system-reset-confirm").hide();
|
|
||||||
$("#js-system-reset-cancel").text(closeHtml);
|
|
||||||
},750);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#js-sys-reboot, #js-sys-shutdown').on('click', function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
var action = $(this).data('action');
|
|
||||||
$.post('ajax/system/sys_actions.php?',{'a': action, 'csrf_token': csrfToken},function(data){
|
|
||||||
var response = JSON.parse(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).ready(function(){
|
|
||||||
$("#PanelManual").hide();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#wg-upload,#wg-manual').on('click', function (e) {
|
|
||||||
if (this.id == 'wg-upload') {
|
|
||||||
$('#PanelManual').hide();
|
|
||||||
$('#PanelUpload').show();
|
|
||||||
} else if (this.id == 'wg-manual') {
|
|
||||||
$('#PanelUpload').hide();
|
|
||||||
$('#PanelManual').show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the following code if you want the name of the file appear on select
|
|
||||||
$(".custom-file-input").on("change", function() {
|
|
||||||
var fileName = $(this).val().split("\\").pop();
|
|
||||||
$(this).siblings(".custom-file-label").addClass("selected").html(fileName);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sets the wirelss channel select options based on hw_mode and country_code.
|
Sets the wirelss channel select options based on hw_mode and country_code.
|
||||||
|
|
||||||
@ -395,6 +258,7 @@ Source: https://en.wikipedia.org/wiki/List_of_WLAN_channels
|
|||||||
Additional: https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
|
Additional: https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
|
||||||
*/
|
*/
|
||||||
function loadChannelSelect(selected) {
|
function loadChannelSelect(selected) {
|
||||||
|
|
||||||
// Fetch wireless regulatory data
|
// Fetch wireless regulatory data
|
||||||
$.getJSON("config/wireless.json", function(json) {
|
$.getJSON("config/wireless.json", function(json) {
|
||||||
var hw_mode = $('#cbxhwmode').val();
|
var hw_mode = $('#cbxhwmode').val();
|
||||||
@ -409,9 +273,7 @@ function loadChannelSelect(selected) {
|
|||||||
var countries_5Ghz_max48ch = data["5Ghz_max48ch"].countries;
|
var countries_5Ghz_max48ch = data["5Ghz_max48ch"].countries;
|
||||||
|
|
||||||
// Map selected hw_mode and country to determine channel list
|
// Map selected hw_mode and country to determine channel list
|
||||||
if (hw_mode === 'a') {
|
if (($.inArray(country_code, countries_2_4Ghz_max11ch) !== -1) && (hw_mode !== 'ac') ) {
|
||||||
selectablechannels = data["5Ghz_max48ch"].channels;
|
|
||||||
} else if (($.inArray(country_code, countries_2_4Ghz_max11ch) !== -1) && (hw_mode !== 'ac') ) {
|
|
||||||
selectablechannels = data["2_4GHz_max11ch"].channels;
|
selectablechannels = data["2_4GHz_max11ch"].channels;
|
||||||
} else if (($.inArray(country_code, countries_2_4Ghz_max14ch) !== -1) && (hw_mode === 'b')) {
|
} else if (($.inArray(country_code, countries_2_4Ghz_max14ch) !== -1) && (hw_mode === 'b')) {
|
||||||
selectablechannels = data["2_4GHz_max14ch"].channels;
|
selectablechannels = data["2_4GHz_max14ch"].channels;
|
||||||
@ -429,39 +291,21 @@ function loadChannelSelect(selected) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets hardware mode tooltip text for selected interface.
|
|
||||||
*/
|
|
||||||
function setHardwareModeTooltip() {
|
|
||||||
var iface = $('#cbxinterface').val();
|
|
||||||
var hwmodeText = '';
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
// Explanatory text if 802.11ac is disabled
|
|
||||||
if ($('#cbxhwmode').find('option[value="ac"]').prop('disabled') == true ) {
|
|
||||||
var hwmodeText = $('#hwmode').attr('data-tooltip');
|
|
||||||
}
|
|
||||||
$.post('ajax/networking/get_frequencies.php?',{'interface': iface, 'csrf_token': csrfToken},function(data){
|
|
||||||
var responseText = JSON.parse(data);
|
|
||||||
$('#tiphwmode').attr('data-original-title', responseText + '\n' + hwmodeText );
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Updates the selected blocklist
|
/* Updates the selected blocklist
|
||||||
* Request is passed to an ajax handler to download the associated list.
|
* Request is passed to an ajax handler to download the associated list.
|
||||||
* Interface elements are updated to indicate current progress, status.
|
* Interface elements are updated to indicate current progress, status.
|
||||||
*/
|
*/
|
||||||
function updateBlocklist() {
|
function updateBlocklist() {
|
||||||
var opt = $('#cbxblocklist option:selected');
|
var blocklist_id = $('#cbxblocklist').val();
|
||||||
var blocklist_id = opt.val();
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
if (blocklist_id == '') { return; }
|
if (blocklist_id == '') { return; }
|
||||||
$('#cbxblocklist-status').find('i').removeClass('fas fa-check').addClass('fas fa-cog fa-spin');
|
$('#cbxblocklist-status').find('i').removeClass('fas fa-check').addClass('fas fa-cog fa-spin');
|
||||||
$('#cbxblocklist-status').removeClass('check-hidden').addClass('check-progress');
|
$('#cbxblocklist-status').removeClass('check-hidden').addClass('check-progress');
|
||||||
$.post('ajax/adblock/update_blocklist.php',{ 'blocklist_id':blocklist_id, 'csrf_token': csrfToken},function(data){
|
$.post('ajax/adblock/update_blocklist.php',{ 'blocklist_id':blocklist_id },function(data){
|
||||||
var jsonData = JSON.parse(data);
|
var jsonData = JSON.parse(data);
|
||||||
if (jsonData['return'] == '0') {
|
if (jsonData['return'] == '0') {
|
||||||
$('#cbxblocklist-status').find('i').removeClass('fas fa-cog fa-spin').addClass('fas fa-check');
|
$('#cbxblocklist-status').find('i').removeClass('fas fa-cog fa-spin').addClass('fas fa-check');
|
||||||
$('#cbxblocklist-status').removeClass('check-progress').addClass('check-updated').delay(500).animate({ opacity: 1 }, 700);
|
$('#cbxblocklist-status').removeClass('check-progress').addClass('check-updated').delay(500).animate({ opacity: 1 }, 700);
|
||||||
$('#blocklist-'+jsonData['list']).text("Just now");
|
$('#'+blocklist_id).text("Just now");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -469,78 +313,42 @@ function updateBlocklist() {
|
|||||||
function clearBlocklistStatus() {
|
function clearBlocklistStatus() {
|
||||||
$('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden');
|
$('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler for the wireguard generate key button
|
|
||||||
$('.wg-keygen').click(function(){
|
|
||||||
var entity_pub = $(this).parent('div').prev('input[type="text"]');
|
|
||||||
var entity_priv = $(this).parent('div').next('input[type="hidden"]');
|
|
||||||
var updated = entity_pub.attr('name')+"-pubkey-status";
|
|
||||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
|
||||||
$.post('ajax/networking/get_wgkey.php',{'entity':entity_pub.attr('name'), 'csrf_token': csrfToken},function(data){
|
|
||||||
var jsonData = JSON.parse(data);
|
|
||||||
entity_pub.val(jsonData.pubkey);
|
|
||||||
$('#' + updated).removeClass('check-hidden').addClass('check-updated').delay(500).animate({ opacity: 1 }, 700);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Handler for wireguard client.conf download
|
|
||||||
$('.wg-client-dl').click(function(){
|
|
||||||
var req = new XMLHttpRequest();
|
|
||||||
var url = 'ajax/networking/get_wgcfg.php';
|
|
||||||
req.open('get', url, true);
|
|
||||||
req.responseType = 'blob';
|
|
||||||
req.setRequestHeader('Content-type', 'text/plain; charset=UTF-8');
|
|
||||||
req.onreadystatechange = function (event) {
|
|
||||||
if(req.readyState == 4 && req.status == 200) {
|
|
||||||
var blob = req.response;
|
|
||||||
var link=document.createElement('a');
|
|
||||||
link.href=window.URL.createObjectURL(blob);
|
|
||||||
link.download = 'client.conf';
|
|
||||||
link.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req.send();
|
|
||||||
})
|
|
||||||
|
|
||||||
// Event listener for Bootstrap's form validation
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
// Fetch all the forms we want to apply custom Bootstrap validation styles to
|
|
||||||
var forms = document.getElementsByClassName('needs-validation');
|
|
||||||
// Loop over them and prevent submission
|
|
||||||
var validation = Array.prototype.filter.call(forms, function(form) {
|
|
||||||
form.addEventListener('submit', function(event) {
|
|
||||||
if (form.checkValidity() === false) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
form.classList.add('was-validated');
|
|
||||||
}, false);
|
|
||||||
});
|
|
||||||
}, false);
|
|
||||||
|
|
||||||
// Static Array method
|
// Static Array method
|
||||||
Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
|
Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
|
||||||
|
|
||||||
$(document).on("click", ".js-toggle-password", function(e) {
|
$(document).on("click", ".js-toggle-password", function(e) {
|
||||||
var button = $(e.target)
|
var button = $(e.target)
|
||||||
var field = $(button.data("target"));
|
var field = $(button.data("target"));
|
||||||
|
|
||||||
if (field.is(":input")) {
|
if (field.is(":input")) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!button.data("__toggle-with-initial")) {
|
if (!button.data("__toggle-with-initial")) {
|
||||||
$("i", this).removeClass("fas fa-eye").addClass(button.attr("data-toggle-with"));
|
button.data("__toggle-with-initial", button.text())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.attr("type") === "password") {
|
if (field.attr("type") === "password") {
|
||||||
|
button.text(button.data("toggle-with"));
|
||||||
field.attr("type", "text");
|
field.attr("type", "text");
|
||||||
} else {
|
} else {
|
||||||
$("i", this).removeClass("fas fa-eye-slash").addClass("fas fa-eye");
|
button.text(button.data("__toggle-with-initial"));
|
||||||
field.attr("type", "password");
|
field.attr("type", "password");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on("keyup", ".js-validate-psk", function(e) {
|
||||||
|
var field = $(e.target);
|
||||||
|
var colors = field.data("colors").split(",");
|
||||||
|
var target = $(field.data("target"));
|
||||||
|
if (field.val().length < 8 || field.val().length > 63) {
|
||||||
|
field.css("backgroundColor", colors[0]);
|
||||||
|
target.attr("disabled", true);
|
||||||
|
} else {
|
||||||
|
field.css("backgroundColor", colors[1]);
|
||||||
|
target.attr("disabled", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
$('#theme-select').change(function() {
|
$('#theme-select').change(function() {
|
||||||
var theme = themes[$( "#theme-select" ).val() ];
|
var theme = themes[$( "#theme-select" ).val() ];
|
||||||
@ -554,32 +362,6 @@ function set_theme(theme) {
|
|||||||
setCookie('theme',theme,90);
|
setCookie('theme',theme,90);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function() {
|
|
||||||
var currentTheme = getCookie('theme');
|
|
||||||
// Check if the current theme is a dark theme
|
|
||||||
var isDarkTheme = currentTheme === 'lightsout.css' || currentTheme === 'material-dark.php';
|
|
||||||
|
|
||||||
$('#night-mode').prop('checked', isDarkTheme);
|
|
||||||
$('#night-mode').change(function() {
|
|
||||||
var state = $(this).is(':checked');
|
|
||||||
var currentTheme = getCookie('theme');
|
|
||||||
|
|
||||||
if (state == true) {
|
|
||||||
if (currentTheme == 'custom.php') {
|
|
||||||
set_theme('lightsout.css');
|
|
||||||
} else if (currentTheme == 'material-light.php') {
|
|
||||||
set_theme('material-dark.php');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (currentTheme == 'lightsout.css') {
|
|
||||||
set_theme('custom.php');
|
|
||||||
} else if (currentTheme == 'material-dark.php') {
|
|
||||||
set_theme('material-light.php');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function setCookie(cname, cvalue, exdays) {
|
function setCookie(cname, cvalue, exdays) {
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
d.setTime(d.getTime() + (exdays*24*60*60*1000));
|
d.setTime(d.getTime() + (exdays*24*60*60*1000));
|
||||||
@ -598,8 +380,6 @@ var themes = {
|
|||||||
"default": "custom.php",
|
"default": "custom.php",
|
||||||
"hackernews" : "hackernews.css",
|
"hackernews" : "hackernews.css",
|
||||||
"lightsout" : "lightsout.css",
|
"lightsout" : "lightsout.css",
|
||||||
"material-light" : "material-light.php",
|
|
||||||
"material-dark" : "material-dark.php",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggles the sidebar navigation.
|
// Toggles the sidebar navigation.
|
||||||
|
@ -11,7 +11,7 @@ var hueb = new Huebee( elem, {
|
|||||||
// Set custom color if defined
|
// Set custom color if defined
|
||||||
var color = getCookie('color');
|
var color = getCookie('color');
|
||||||
if (color == null || color == '') {
|
if (color == null || color == '') {
|
||||||
color = '#2b8080';
|
color = '#d8224c';
|
||||||
}
|
}
|
||||||
hueb.setColor(color);
|
hueb.setColor(color);
|
||||||
|
|
||||||
|
@ -3,15 +3,13 @@
|
|||||||
// Support for dark theme
|
// Support for dark theme
|
||||||
theme = getCookie('theme');
|
theme = getCookie('theme');
|
||||||
if (theme == 'lightsout.css') {
|
if (theme == 'lightsout.css') {
|
||||||
|
var bgColor1 = '#141414';
|
||||||
|
var bgColor2 = '#141414';
|
||||||
var borderColor = 'rgba(37, 153, 63, 1)';
|
var borderColor = 'rgba(37, 153, 63, 1)';
|
||||||
var labelColor = 'rgba(37, 153, 63, 1)';
|
var labelColor = 'rgba(37, 153, 63, 1)';
|
||||||
} else if (theme == 'material-light.php') {
|
|
||||||
var borderColor = '#f2f2fb';
|
|
||||||
var labelColor = '#f2f2fb';
|
|
||||||
} else if (theme == 'material-dark.php') {
|
|
||||||
var borderColor = '#f2f2fb';
|
|
||||||
var labelColor = '#f2f2fb';
|
|
||||||
} else {
|
} else {
|
||||||
|
var bgColor1 = '#d4edda';
|
||||||
|
var bgColor2 = '#eaecf4';
|
||||||
var borderColor = 'rgba(147, 210, 162, 1)';
|
var borderColor = 'rgba(147, 210, 162, 1)';
|
||||||
var labelColor = 'rgba(130, 130, 130, 1)';
|
var labelColor = 'rgba(130, 130, 130, 1)';
|
||||||
}
|
}
|
||||||
@ -19,7 +17,7 @@ if (theme == 'lightsout.css') {
|
|||||||
let data1 = {
|
let data1 = {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: [linkQ, 100-linkQ],
|
data: [linkQ, 100-linkQ],
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: [bgColor1, bgColor2],
|
||||||
borderColor: borderColor,
|
borderColor: borderColor,
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
59
app/lib/system.php
Normal file
59
app/lib/system.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class System {
|
||||||
|
public function hostname() {
|
||||||
|
return shell_exec("hostname -f");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uptime() {
|
||||||
|
$uparray = explode(" ", exec("cat /proc/uptime"));
|
||||||
|
$seconds = round($uparray[0], 0);
|
||||||
|
$minutes = $seconds / 60;
|
||||||
|
$hours = $minutes / 60;
|
||||||
|
$days = floor($hours / 24);
|
||||||
|
$hours = floor($hours - ($days * 24));
|
||||||
|
$minutes = floor($minutes - ($days * 24 * 60) - ($hours * 60));
|
||||||
|
$uptime= '';
|
||||||
|
if ($days != 0) {
|
||||||
|
$uptime .= $days . ' day' . (($days > 1)? 's ':' ');
|
||||||
|
}
|
||||||
|
if ($hours != 0) {
|
||||||
|
$uptime .= $hours . ' hour' . (($hours > 1)? 's ':' ');
|
||||||
|
}
|
||||||
|
if ($minutes != 0) {
|
||||||
|
$uptime .= $minutes . ' minute' . (($minutes > 1)? 's ':' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uptime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function usedMemory() {
|
||||||
|
$used = shell_exec("free -m | awk '/Mem:/ { total=$2 ; used=$3 } END { print used/total*100}'");
|
||||||
|
return floor($used);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processorCount() {
|
||||||
|
$procs = shell_exec("nproc --all");
|
||||||
|
return intval($procs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadAvg1Min() {
|
||||||
|
$load = exec("awk '{print $1}' /proc/loadavg");
|
||||||
|
return floatval($load);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function systemLoadPercentage() {
|
||||||
|
return intval(($this->loadAvg1Min() * 100) / $this->processorCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function systemTemperature() {
|
||||||
|
$cpuTemp = file_get_contents("/sys/class/thermal/thermal_zone0/temp");
|
||||||
|
return number_format((float)$cpuTemp/1000, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hostapdStatus() {
|
||||||
|
exec('pidof hostapd | wc -l', $status);
|
||||||
|
return $status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "raspap/raspap-webgui",
|
"name": "billz/raspap-webgui",
|
||||||
"description": "Simple wireless AP setup and mangement for Debian-based devices",
|
"description": "Simple AP setup and wifi mangement for Debian-based devices",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"homepage": "https://raspap.com/",
|
"homepage": "https://raspap.com/",
|
||||||
"keywords": ["raspberrypi", "debian", "armbian", "wifi"],
|
"keywords": ["raspberrypi", "debian", "armbian", "wifi"],
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
# RaspAP default config
|
|
||||||
log-facility=/var/log/dnsmasq.log
|
|
||||||
conf-dir=/etc/dnsmasq.d
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
# RaspAP wlan0 configuration for wired (ethernet) AP mode
|
|
||||||
interface=wlan0
|
|
||||||
domain-needed
|
|
||||||
dhcp-range=10.3.141.50,10.3.141.254,255.255.255.0,12h
|
|
||||||
dhcp-option=6,9.9.9.9,1.1.1.1
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
server.modules += (
|
|
||||||
"mod_rewrite",
|
|
||||||
)
|
|
||||||
|
|
||||||
$HTTP["url"] =~ "^/REPLACE_ME/(?!(dist|app|ajax|config)).*" {
|
|
||||||
url.rewrite-once = ( "^/REPLACE_ME/(.*?)(\?.+)?$"=>"/REPLACE_ME/index.php/$1$2" )
|
|
||||||
server.error-handler-404 = "/REPLACE_ME/index.php"
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +1,6 @@
|
|||||||
{
|
{
|
||||||
"StevenBlack/hosts": [
|
"notracking/hosts-blocklist": [
|
||||||
"StevenBlack/hosts (default)"
|
"notracking-hostnames",
|
||||||
],
|
"notracking-domains"
|
||||||
"badmojr/hosts": [
|
]
|
||||||
"badmojr/1Hosts (Mini)",
|
|
||||||
"badmojr/1Hosts (Lite)",
|
|
||||||
"badmojr/1Hosts (Pro)",
|
|
||||||
"badmojr/1Hosts (Xtra)"
|
|
||||||
],
|
|
||||||
"OISD/domains": [
|
|
||||||
"oisd/big (default)",
|
|
||||||
"oisd/small",
|
|
||||||
"oisd/nsfw"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
# mobile data modem - ttyUSB0 device appears
|
|
||||||
SUBSYSTEM=="tty", KERNEL=="ttyUSB0", TAG+="systemd", ENV{SYSTEMD_WANTS}="start start_ppp0_device.service"
|
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
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"
|
|
||||||
|
|
||||||
|
|
@ -1,505 +0,0 @@
|
|||||||
#!/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=${hilink_tokenlist[0]} # get first token in list
|
|
||||||
hilink_tokenlist=("${hilink_tokenlist[@]:1}") # remove used token from list
|
|
||||||
if [ ${#hilink_tokenlist[@]} -eq 0 ]; then
|
|
||||||
_logout # use the last token to logout
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
_sessToken # old token has been used - need new session
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Analyse $status for error code
|
|
||||||
# return error text in $status
|
|
||||||
function _handleError() {
|
|
||||||
local ret txt
|
|
||||||
txt=$(_getErrorText)
|
|
||||||
if [ -z "$code" ]; then return 1; fi
|
|
||||||
ret=0
|
|
||||||
case "$code" in
|
|
||||||
101|108003|108007)
|
|
||||||
ret=1
|
|
||||||
status="$txt"
|
|
||||||
;;
|
|
||||||
108001|108002|108006)
|
|
||||||
ret=1
|
|
||||||
status="$txt"
|
|
||||||
;;
|
|
||||||
125001|125002|125003)
|
|
||||||
_sessToken
|
|
||||||
ret=0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
return "$ret"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare -A hilink_err_api
|
|
||||||
hilink_err_api[101]="Unable to get session ID/token"
|
|
||||||
hilink_err_api[108001]="Invalid username/password"
|
|
||||||
hilink_err_api[108002]=${hilink_err_api[108001]}
|
|
||||||
hilink_err_api[108006]=${hilink_err_api[108001]}
|
|
||||||
hilink_err_api[108003]="User already logged in - need to wait a bit"
|
|
||||||
hilink_err_api[108007]="Too many login attempts - need to wait a bit"
|
|
||||||
hilink_err_api[125001]="Invalid session/request token"
|
|
||||||
hilink_err_api[125002]=${hilink_err_api[125001]}
|
|
||||||
hilink_err_api[125003]=${hilink_err_api[125001]}
|
|
||||||
|
|
||||||
# check error and return error text
|
|
||||||
# status passsed in $status, or $1
|
|
||||||
function _getErrorText() {
|
|
||||||
local err code errortext
|
|
||||||
err="$status"
|
|
||||||
code="0"
|
|
||||||
if [ ! -z "$1" ]; then err="$1"; fi
|
|
||||||
if [ -z "$err" ]; then return 1; fi
|
|
||||||
errortext="$err"
|
|
||||||
if [[ "$err" =~ ERROR\ *([0-9]*) ]] && [ ! -z "${BASH_REMATCH[1]}" ]; then
|
|
||||||
code=${BASH_REMATCH[1]}
|
|
||||||
if [ ! -z "$code" ] && [ ! -z "${hilink_err_api[$code]}" ]; then
|
|
||||||
errortext="${hilink_err_api[$code]}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo $errortext
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
function _hostReachable() {
|
|
||||||
local avail
|
|
||||||
avail=$( timeout 0.5 ping -c 1 $hilink_host | sed -rn 's/.*time=.*/1/p' )
|
|
||||||
if [ -z "$avail" ]; then status="ERROR: Not reachable"; return 1; fi
|
|
||||||
status="OK"
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
# helper function to parse $response (xml format) for a value
|
|
||||||
# call another function first!
|
|
||||||
# parameter: tag-name
|
|
||||||
function _valueFromResponse() {
|
|
||||||
local par value
|
|
||||||
if [ -z "$response" ] || [ -z "$1" ]; then return 1; fi
|
|
||||||
par="$1"
|
|
||||||
value=$(echo $response | sed -rn 's/.*<'$par'>(.*)<\/'$par'>.*/\1/pi')
|
|
||||||
if [ -z "$value" ]; then return 1; fi
|
|
||||||
echo "$value"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# list all keys of the current xml response
|
|
||||||
function _keysFromResponse() {
|
|
||||||
if [ -z "$response" ]; then return 1; fi
|
|
||||||
echo $response | grep -oiP "(?<=<)[a-z_-]*(?=>)"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# return all key=value pairs of the current xml response
|
|
||||||
function _keyValuePairs() {
|
|
||||||
if [ -z "$response" ]; then return 1; fi
|
|
||||||
echo $response | sed -n 's/<\([^>]*\)>\(.*\)<\/\1>[^<]*/\1=\"\2\"\n/gpi'
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
hilink_token=""
|
|
||||||
hilink_tokenlist=""
|
|
||||||
hilink_sessID=""
|
|
||||||
hilink_xmldata=""
|
|
||||||
hilink_xtraopts=""
|
|
||||||
hilink_host=$hilink_host_default
|
|
||||||
hilink_user="admin"
|
|
||||||
hilink_password=""
|
|
||||||
hilink_pin=""
|
|
||||||
response=""
|
|
||||||
status=""
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# get info about device and signal of Huawei mobile USB devices
|
|
||||||
# parm:
|
|
||||||
# $1 : requested information (manufacturer, device, imei, imsi, telnumber, ipaddress, mode, signal, operator)
|
|
||||||
# $2 : (optional) type - hilink or modem (default: hilink)
|
|
||||||
# $3 : (optional) for hilink: ip address of the device (default: 192.168.8.1)
|
|
||||||
# for modem: tty interface for communication (default: /dev/ttypUSB2)
|
|
||||||
# $4 : more options can be added for Hilink devices ('-u user -P password -p pin'). These are passed to the corresponding script
|
|
||||||
#
|
|
||||||
# requires: bc
|
|
||||||
# calls the scripts info_huawei_hilink.sh and info_huawei_modem.sh (same path as this script)
|
|
||||||
#
|
|
||||||
# zbchristian 2020
|
|
||||||
#
|
|
||||||
path=$(dirname "$0")
|
|
||||||
opt="device"
|
|
||||||
if [ ! -z "$1" ]; then opt=${1,,}; fi
|
|
||||||
type="hilink"
|
|
||||||
if [ ! -z "$2" ]; then type=${2,,}; fi
|
|
||||||
|
|
||||||
parms=""
|
|
||||||
if [ "$type" = "hilink" ]; then
|
|
||||||
connect="-h 192.168.8.1"
|
|
||||||
if [ ! -z "$3" ]; then connect="-h $3"; fi
|
|
||||||
if [ ! -z "$4" ]; then parms="$4"; fi
|
|
||||||
script="$path/info_huawei_hilink.sh"
|
|
||||||
else
|
|
||||||
connect="/dev/ttyUSB2"
|
|
||||||
if [ ! -z "$3" ]; then connect=$3; fi
|
|
||||||
script="$path/info_huawei_modem.sh"
|
|
||||||
fi
|
|
||||||
res=$($script $opt $connect $parms)
|
|
||||||
|
|
||||||
# some results require special treatment
|
|
||||||
case $opt in
|
|
||||||
|
|
||||||
# manufacturer)
|
|
||||||
# if [ "$res" = "none" ]; then res="Huawei"; fi
|
|
||||||
# ;;
|
|
||||||
|
|
||||||
# device)
|
|
||||||
# if [ ! "$res" = "none" ]; then res="Huawei $res";
|
|
||||||
# else res="Huawei"; fi
|
|
||||||
# ;;
|
|
||||||
|
|
||||||
mode)
|
|
||||||
if [ ! "$res" = "none" ]; then
|
|
||||||
if [ "$type" = "hilink" ]; then
|
|
||||||
if [ "$res" = "LTE" ]; then res="4G"
|
|
||||||
elif [ "$res" = "WCDMA" ]; then res="3G";
|
|
||||||
else res="2G"; fi
|
|
||||||
else
|
|
||||||
if [ $res -eq 7 ]; then res="4G"
|
|
||||||
elif [ $res -lt 7 ] && [ $res -gt 2 ] ; then res="3G";
|
|
||||||
else res="2G"; fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
signal)
|
|
||||||
# return signal strength/quality in %
|
|
||||||
if [ "$type" = "hilink" ]; then
|
|
||||||
# signal request tries to get RSRQ value
|
|
||||||
# try to get RSRQ (4G), EC/IO (3G) or RSSI (2G) value
|
|
||||||
if [ "$res" = "none" ]; then res=$($script "ecio"); fi
|
|
||||||
if [ ! "$res" = "none" ]; then
|
|
||||||
# for rsrq and ecio assume: -3dB (100%) downto -20dB (0%)
|
|
||||||
qual=${res//dB/}
|
|
||||||
if [[ ! "$qual" =~ [-0-9\.]* ]]; then qual=-100; fi
|
|
||||||
qual=$(bc <<< "scale=0;res=$qual-0.5;res/1") # just round to next integer
|
|
||||||
if [ $qual -le -20 ]; then qual=0;
|
|
||||||
elif [ $qual -ge -3 ]; then qual=100;
|
|
||||||
else qual=$(bc <<< "scale=0;res=100.0/17.0*$qual+2000.0/17.0;res/1"); fi
|
|
||||||
else
|
|
||||||
# try rssi: >-70dBm (100%) downto -100dBm (0%)
|
|
||||||
res=$($script "rssi");
|
|
||||||
if [ ! "$res" = "none" ]; then
|
|
||||||
if [[ ! $res =~ [-0-9\.]* ]]; then res="-120 dBm"; fi
|
|
||||||
qual=${res//dBm/}
|
|
||||||
qual=$(bc <<< "scale=0;res=$qual+0.5;res/1") # just round to next integer
|
|
||||||
if [ $qual -le -110 ]; then qual=0;
|
|
||||||
elif [ $qual -ge -70 ]; then qual=100;
|
|
||||||
else qual=$(bc <<< "scale=0;res=2.5*$qual+275;res/1"); fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# modem returns RSSI as number 0-31 - 0 = -113dB (0%), 1 = -111dB, 31 = >=51dB (100%)
|
|
||||||
qual=$(bc <<< "scale=0;res=$res*3.5+0.5;res/1")
|
|
||||||
if [ $qual -gt 100 ]; then res=100; fi
|
|
||||||
fi
|
|
||||||
if [ ! "$res" = "none" ]; then res="$res (${qual}%)"; fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
operator)
|
|
||||||
# check if operator/network is just a 5 digit number -> extract network name from table
|
|
||||||
if [[ $res =~ ^[0-9]{5}$ ]]; then
|
|
||||||
mcc=${res:0:3}
|
|
||||||
mnc=${res:3:2}
|
|
||||||
op=$(cat $path/mcc-mnc-table.csv | sed -rn 's/^'$mcc'\,[0-9]*\,'$mnc'\,(.*\,){4}(.*)$/\2/p')
|
|
||||||
if [ ! -z "$op" ]; then res="$op ($res)"; fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo $res
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Information about HUAWEI hilink
|
|
||||||
# -------------------------------
|
|
||||||
# get info about the device and signal
|
|
||||||
# parameter: $1 - "connected", "device", "ipaddress", "mode", "signal" (see case statement below)
|
|
||||||
# -u,--user - username
|
|
||||||
# -P,--password - password
|
|
||||||
# -p,--pin - SIM pin
|
|
||||||
# -h,--host - host ip address for API calls (optional)
|
|
||||||
# returns the value of the parameter, or "none" if not found or empty
|
|
||||||
#
|
|
||||||
# All device informations are buffered for 5 secs to speed up subsequent calls
|
|
||||||
#
|
|
||||||
# zbchristian 2021
|
|
||||||
|
|
||||||
function _setAPIParams() {
|
|
||||||
if [ ! -z "$hostip" ]; then hilink_host="$hostip"; fi
|
|
||||||
if [ ! -z "$username" ]; then hilink_user="$username"; fi
|
|
||||||
if [ ! -z "$password" ]; then hilink_password="$password"; fi
|
|
||||||
if [ ! -z "$simpin" ]; then hilink_pin="$simpin"; fi
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "$1" ]; then echo "none"; exit; fi
|
|
||||||
property="${1,,}"
|
|
||||||
shift
|
|
||||||
hostip="192.168.8.1"
|
|
||||||
while [ -n "$1" ]; do
|
|
||||||
case "$1" in
|
|
||||||
-u|--user) username="$2"; shift ;;
|
|
||||||
-P|--password) password="$2"; shift ;;
|
|
||||||
-p|--pin) simpin="$2"; shift ;;
|
|
||||||
-h|--host) hostip="$2"; shift ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
status="no valid option given"
|
|
||||||
result="none"
|
|
||||||
hostip="192.168.8.1"
|
|
||||||
if [ "$opt" = "connected" ]; then
|
|
||||||
source /usr/local/sbin/huawei_hilink_api.sh
|
|
||||||
_setAPIParams
|
|
||||||
if ! _initHilinkAPI; then echo "none"; exit; fi
|
|
||||||
result=$(_getMobileDataStatus)
|
|
||||||
_closeHilinkAPI
|
|
||||||
else
|
|
||||||
info_file="/tmp/huawei_infos_${hostip}_$(id -u).dat"
|
|
||||||
if [ -f "$info_file" ]; then
|
|
||||||
age=$(( $(date +%s) - $(stat $info_file -c %Y) ))
|
|
||||||
if [[ $age -gt 10 ]]; then rm -f $info_file; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$info_file" ]; then
|
|
||||||
infos=$(cat $info_file)
|
|
||||||
else
|
|
||||||
source /usr/local/sbin/huawei_hilink_api.sh
|
|
||||||
_setAPIParams
|
|
||||||
if ! _initHilinkAPI; then echo "none"; exit; fi
|
|
||||||
infos=$(_getAllInformations)
|
|
||||||
_closeHilinkAPI
|
|
||||||
if [ ! -z "$infos" ]; then echo -n "$infos" > $info_file; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$property" in
|
|
||||||
device|devicename)
|
|
||||||
key="devicename"
|
|
||||||
;;
|
|
||||||
ipaddress|wanipaddress)
|
|
||||||
key="wanipaddress"
|
|
||||||
;;
|
|
||||||
mode)
|
|
||||||
key="workmode"
|
|
||||||
;;
|
|
||||||
telnumber)
|
|
||||||
key="msisdn"
|
|
||||||
;;
|
|
||||||
imei|imsi|rssi|rsrq|rsrp|sinr|ecio)
|
|
||||||
key="$property"
|
|
||||||
;;
|
|
||||||
signal)
|
|
||||||
key="rsrq"
|
|
||||||
;;
|
|
||||||
operator|fullname)
|
|
||||||
key="fullname"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
key="device"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
if [ -z "$key" ]; then result="none"; fi
|
|
||||||
result=$(echo "$infos" | sed -rn 's/'$key'=\"([^ \s]*)\"/\1/ip')
|
|
||||||
if [ -z "$result" ]; then result="none"; fi
|
|
||||||
fi
|
|
||||||
echo -n "$result"
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Information about HUAWEI modem - via AT commands
|
|
||||||
# ------------------------------------------------
|
|
||||||
# get info about the device and signal
|
|
||||||
# parameter: $1 - see opts list below
|
|
||||||
# $2 - tty device name for the communicaton (optional)
|
|
||||||
# returns the value of the parameter, or "none" if not found or empty
|
|
||||||
#
|
|
||||||
# requires: socat
|
|
||||||
#
|
|
||||||
# zbchristian 2020
|
|
||||||
|
|
||||||
opts=("manufacturer" "device" "imei" "imsi" "telnumber" "mode" "signal" "operator")
|
|
||||||
|
|
||||||
# at command to extract information
|
|
||||||
atcmds=("AT+CGMI" "AT+CGMM" "AT+CGSN" "AT+CIMI" "AT+CNUM" "AT+COPS?" "AT+CSQ" "AT+COPS?")
|
|
||||||
# regexp pattern to extract wanted information from result string
|
|
||||||
pats=( " " " " " " " " ".*\,\"([0-9\+]*)\".*" '.*\,([0-9])$' ".*: ([0-9]*).*" '.*\,\"([^ ]*)\".*$')
|
|
||||||
|
|
||||||
# tty device for communication - usually 3 tty devices are created and the 3rd ttyUSB2 is available, even, when the device is connected
|
|
||||||
dev="/dev/ttyUSB2"
|
|
||||||
|
|
||||||
atsilent="AT^CURC=0"
|
|
||||||
|
|
||||||
if [ ! -z $2 ]; then dev=$2; fi
|
|
||||||
|
|
||||||
idx=-1
|
|
||||||
opt=${opts[0]}
|
|
||||||
if [ ! -z $1 ]; then opt=$1; fi
|
|
||||||
|
|
||||||
for i in "${!opts[@]}"; do
|
|
||||||
if [[ ${opts[$i]} == $opt ]]; then idx=$i; fi
|
|
||||||
done
|
|
||||||
if [[ $idx == -1 ]];then echo "none"; exit; fi
|
|
||||||
|
|
||||||
atcmd=${atcmds[$idx]}
|
|
||||||
pat=${pats[$idx]}
|
|
||||||
|
|
||||||
|
|
||||||
result=`(echo $atsilent; echo $atcmd) | sudo /usr/bin/socat - $dev`
|
|
||||||
# escape the AT command to be used in the regexp
|
|
||||||
atesc=${atcmd//[\+]/\\+}
|
|
||||||
atesc=${atesc//[\?]/\\?}
|
|
||||||
result=`echo $result | sed -rn 's/.*'"$atesc"'\s([^ ]+|[^ ]+ [^ ]+)\sOK.*$/\1/pg'`
|
|
||||||
if [[ $pat != " " ]]; then
|
|
||||||
result=`echo $result | sed -rn 's/'"$pat"'/\1/pg'`
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$result" ]; then result="none"; fi
|
|
||||||
|
|
||||||
echo $result
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
# interfaces(5) file used by ifup(8) and ifdown(8)
|
|
||||||
|
|
||||||
# Please note that this file is written to be used with dhcpcd
|
|
||||||
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
|
|
||||||
|
|
||||||
# Include files from /etc/network/interfaces.d:
|
|
||||||
source-directory /etc/network/interfaces.d
|
|
||||||
|
|
||||||
auto ppp0
|
|
||||||
iface ppp0 inet wvdial
|
|
||||||
provider connect
|
|
||||||
pre-up /usr/local/sbin/ppp0_setpin.sh
|
|
||||||
up /usr/local/sbin/ppp0_route.sh
|
|
File diff suppressed because it is too large
Load Diff
@ -1,58 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# connect/disconnect Huawei mobile data stick in Hilink mode (e.g. E3372h)
|
|
||||||
# ========================================================================
|
|
||||||
#
|
|
||||||
# options: -u, --user - user name (default "admin")
|
|
||||||
# -P, --password - password
|
|
||||||
# -h, --host - host ip address (default 192.168.8.1)
|
|
||||||
# -d, --devname - device name (IP is extracted using default route)
|
|
||||||
# -p, --pin - PIN of SIM card
|
|
||||||
# -c, --connect - connect 0/1 to set datamode off/on
|
|
||||||
#
|
|
||||||
# required software: curl, base64, sha256sum
|
|
||||||
#
|
|
||||||
# zbchristian 2021
|
|
||||||
|
|
||||||
# include the hilink API (defaults: hilink_user=admin, hilink_host=192.168.8.1)
|
|
||||||
source /usr/local/sbin/huawei_hilink_api.sh
|
|
||||||
|
|
||||||
# include the raspap helper functions
|
|
||||||
source /usr/local/sbin/raspap_helpers.sh
|
|
||||||
|
|
||||||
datamode=""
|
|
||||||
devname=""
|
|
||||||
while [ -n "$1" ]; do
|
|
||||||
case "$1" in
|
|
||||||
-u|--user) hilink_user="$2"; shift ;;
|
|
||||||
-P|--password) hilink_password="$2"; shift ;;
|
|
||||||
-p|--pin) if [[ $2 =~ ^[0-9]{4,8} ]]; then hilink_pin="$2"; fi; shift ;;
|
|
||||||
-h|--host) hilink_host="$2"; shift ;;
|
|
||||||
-d|--devname) devname="$2"; shift ;;
|
|
||||||
-c|--connect) if [ "$2" = "1" ]; then datamode=1; else datamode=0; fi; shift ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -z "$devname" ]; then # get host IP for given device name
|
|
||||||
gw=$(ip route list | sed -rn "s/default via (([0-9]{1,3}\.){3}[0-9]{1,3}).*dev $devname.*/\1/p")
|
|
||||||
if [ -z "$gw" ]; then exit; fi # device name not found in routing list -> abort
|
|
||||||
hilink_host="$gw"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$hilink_password" ] || [ -z "$hilink_pin" ]; then
|
|
||||||
_getAuthRouter
|
|
||||||
if [ ! -z "$raspap_user" ]; then hilink_user="$raspap_user"; fi
|
|
||||||
if [ ! -z "$raspap_password" ]; then hilink_password="$raspap_password"; fi
|
|
||||||
if [ ! -z "$raspap_pin" ]; then hilink_pin="$raspap_pin"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Hilink: switch device at $hilink_host to mode $datamode" | systemd-cat
|
|
||||||
|
|
||||||
status="usage: -c 1/0 to disconnect/connect"
|
|
||||||
if [ -z "$datamode" ] || [ ! _initHilinkAPI ]; then echo "Hilink: failed - return status: $status"; exit; fi
|
|
||||||
|
|
||||||
if ! _switchMobileData "$datamode"; then echo -n "Hilink: could not switch the data mode on/off . Error: ";_getErrorText; fi
|
|
||||||
|
|
||||||
if ! _closeHilinkAPI; then echo -n "Hilink: failed - return status: $status . Error: ";_getErrorText; fi
|
|
||||||
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# get gateway and ip address of UTMS modem connected to ppp0
|
|
||||||
# add a default route
|
|
||||||
# called by /etc/network/interfaces.d/ppp0, when device is coming up
|
|
||||||
#
|
|
||||||
ppp0rt=""
|
|
||||||
let i=1
|
|
||||||
while [ -z "$ppp0rt" ] ; do
|
|
||||||
let i+=1
|
|
||||||
if [ $i -gt 20 ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
sleep 1
|
|
||||||
ppp0rt=`ip route list | grep -m 1 ppp0`
|
|
||||||
done
|
|
||||||
gate=`echo $ppp0rt | sed -rn 's/(([0-9]{1,3}\.){3}[0-9]{1,3}).*ppp0.*src (([0-9]{1,3}\.){3}[0-9]{1,3})/\1/p'`
|
|
||||||
src=`echo $ppp0rt | sed -rn 's/(([0-9]{1,3}\.){3}[0-9]{1,3}).*ppp0.*src (([0-9]{1,3}\.){3}[0-9]{1,3})/\3/p'`
|
|
||||||
|
|
||||||
ip route add default via $gate proto dhcp src $src metric 10
|
|
||||||
exit 0
|
|
@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# in case /dev/ttyUSB0 does not exist, wait for it at most 30 seconds
|
|
||||||
let i=1
|
|
||||||
while ! test -c /dev/ttyUSB0; do
|
|
||||||
let i+=1
|
|
||||||
if [ $i -gt 2 ]; then
|
|
||||||
logger -s -t setpin "/dev/ttyUSB0 does not exist"
|
|
||||||
exit 3
|
|
||||||
fi
|
|
||||||
logger -s -t setpin "waiting 3 seconds for /dev/ttyUSB0"
|
|
||||||
sleep 3
|
|
||||||
done
|
|
||||||
# check for pin and set it if necessary
|
|
||||||
wvdial pinstatus 2>&1 | grep -q '^+CPIN: READY'
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
logger -s -t setpin "SIM card is ready to use :-)"
|
|
||||||
else
|
|
||||||
logger -s -t setpin "setting PIN"
|
|
||||||
wvdial pin 2>/dev/null
|
|
||||||
fi
|
|
||||||
exit 0
|
|
@ -1,51 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Helper functions to extract informations from RaspAP config/settings
|
|
||||||
#
|
|
||||||
# zbchristian 2021
|
|
||||||
#
|
|
||||||
# get the values of a RaspAP config variable
|
|
||||||
# call: _getRaspapConfig RASPAP_MOBILEDATA_CONFIG
|
|
||||||
|
|
||||||
raspap_webroot="/var/www/html"
|
|
||||||
|
|
||||||
function _getWebRoot() {
|
|
||||||
local path
|
|
||||||
path=$(cat /etc/lighttpd/lighttpd.conf | sed -rn "s/server.document-root \s*= \"([^ \s]*)\"/\1/p")
|
|
||||||
if [ ! -z "$path" ]; then raspap_webroot="$path"; fi
|
|
||||||
if [ -z "$path" ]; then return 1; else return 0; fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# expand an RaspAP config variable utilizing PHP
|
|
||||||
function _getRaspapConfig() {
|
|
||||||
local conf var
|
|
||||||
raspap_config=""
|
|
||||||
var="$1"
|
|
||||||
if [ ! -z "$var" ]; then
|
|
||||||
if ! _getWebRoot; then return 1; fi
|
|
||||||
conf="$raspap_webroot/includes/config.php"
|
|
||||||
if [ -f "$conf" ]; then
|
|
||||||
conf=$(php -r 'include "'$conf'"; echo '$var';' 2> /dev/null)
|
|
||||||
if [ ! -z "$conf" ] && [ -d ${conf%/*} ]; then raspap_config="$conf"; fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if [ -z "$raspap_config" ]; then return 1; else return 0; fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Username and password for mobile data devices is stored in a file (RASPAP_MOBILEDATA_CONFIG)
|
|
||||||
function _getAuthRouter() {
|
|
||||||
local mfile mdata pin user pw
|
|
||||||
if ! _getRaspapConfig "RASPI_MOBILEDATA_CONFIG"; then return 1; fi
|
|
||||||
mfile="$raspap_config"
|
|
||||||
if [ -f $mfile ]; then
|
|
||||||
mdata=$(cat "$mfile")
|
|
||||||
pin=$(echo "$mdata" | sed -rn 's/pin = ([^ \s]*)/\1/ip')
|
|
||||||
if [ ! -z "$pin" ]; then raspap_pin="$pin"; fi
|
|
||||||
user=$(echo "$mdata" | sed -rn 's/router_user = ([^ \s]*)/\1/ip')
|
|
||||||
if [ ! -z "$user" ]; then raspap_user="$user"; fi
|
|
||||||
pw=$(echo "$mdata" | sed -rn 's/router_pw = ([^ \s]*)/\1/ip')
|
|
||||||
if [ ! -z "$pw" ]; then raspap_password="$pw"; fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Bring up HUAWEI mobile hilink device
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
RemainAfterExit=no
|
|
||||||
ExecStart=/bin/sleep 15
|
|
||||||
ExecStart=/usr/local/sbin/onoff_huawei_hilink.sh -c 1 -d %i
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
Alias=start_ltemodem.service
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Start ppp0 interface
|
|
||||||
BindsTo=dev-ttyUSB0.device
|
|
||||||
After=dev-ttyUSB0.device
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=forking
|
|
||||||
RemainAfterExit=yes
|
|
||||||
ExecStart=/sbin/ifup ppp0
|
|
||||||
ExecStop=/sbin/ifdown ppp0
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
Alias=startppp0.service
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
[Dialer Defaults]
|
|
||||||
Modem Type = Analog Modem
|
|
||||||
ISDN = 0
|
|
||||||
Baud = 9600
|
|
||||||
Modem = /dev/ttyUSB0
|
|
||||||
|
|
||||||
[Dialer pin]
|
|
||||||
Init1 = AT+CPIN="XXXX"
|
|
||||||
|
|
||||||
[Dialer connect]
|
|
||||||
Init1 = ATZ
|
|
||||||
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
|
|
||||||
Init3 = AT+CGDCONT=1,"IP","web.vodafone.de"
|
|
||||||
New PPPD = yes
|
|
||||||
Phone = *99#
|
|
||||||
Password = me
|
|
||||||
Username = vodafone
|
|
||||||
Stupid Mode = 1
|
|
||||||
|
|
||||||
[Dialer pinstatus]
|
|
||||||
Init1 = AT+CPIN?
|
|
@ -1,64 +0,0 @@
|
|||||||
{
|
|
||||||
"info": "UDEV rules for different client types. $...$ expressions will be replaces automatically ($MAC$, $IDVENDOR$, $IDPRODUCT$, $DEVNAME$)",
|
|
||||||
"udev_rules_file": "/etc/udev/rules.d/80-raspap-net-devices.rules",
|
|
||||||
"script_path": "/usr/local/sbin",
|
|
||||||
"network_devices": [
|
|
||||||
{
|
|
||||||
"type": "eth",
|
|
||||||
"type_info": "ethernet port",
|
|
||||||
"clientid": 0,
|
|
||||||
"comment": "standard ethernet port",
|
|
||||||
"name_prefix": "eth",
|
|
||||||
"udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", ATTR{address}==\"$MAC$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"eth\" "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "usb",
|
|
||||||
"type_info": "usb network interface",
|
|
||||||
"clientid": 1,
|
|
||||||
"comment": "network interface - e.g. USB tethering of an Android phone ",
|
|
||||||
"name_prefix": "usb",
|
|
||||||
"udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"$IDVENDOR$\", ATTRS{idProduct}==\"$IDPRODUCT$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"eth\" "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "wlan",
|
|
||||||
"type_info": "wireless adapter",
|
|
||||||
"clientid": 2,
|
|
||||||
"comment": "standard wireless interface",
|
|
||||||
"name_prefix": "wlan",
|
|
||||||
"udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", ATTR{address}==\"$MAC$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"wlan\" "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "ppp",
|
|
||||||
"type_info": "mobile data modem",
|
|
||||||
"clientid": 3,
|
|
||||||
"name_prefix": "ppp",
|
|
||||||
"comment": "recognized mobile data modems are automatically named as ppp0-9. Renaming is not possible. Dialin service relies on the name",
|
|
||||||
"udev_rule": "SUBSYSTEM==\"tty\", KERNEL==\"ttyUSB0\", TAG+=\"systemd\", ENV{SYSTEMD_WANTS}=\"start start_ppp0_device.service\" "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "hilink",
|
|
||||||
"type_info": "Huawei Hilink",
|
|
||||||
"clientid": 4,
|
|
||||||
"comment": "Huawei mobile data device in router mode. Control via HTTP. Device is connecting via service",
|
|
||||||
"name_prefix": "hilink",
|
|
||||||
"default_ip": "192.168.8.1",
|
|
||||||
"udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"$IDVENDOR$\", ATTRS{idProduct}==\"$IDPRODUCT$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"hilink\", TAG+=\"systemd\", ENV{SYSTEMD_WANTS}=\"start start_huawei_hilink@hilink%n.service\" "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "phone",
|
|
||||||
"type_info": "USB tethered phone",
|
|
||||||
"clientid": 5,
|
|
||||||
"comment": "ethernet access provided by tethering from phone via USB",
|
|
||||||
"name_prefix": "phone",
|
|
||||||
"udev_rule": "SUBSYSTEM==\"net\", ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"$IDVENDOR$\", ATTRS{idProduct}==\"$IDPRODUCT$\", NAME=\"$DEVNAME$\", ENV{raspapType}=\"phone\" "
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "tun",
|
|
||||||
"type_info": "tunnel device",
|
|
||||||
"clientid": -1,
|
|
||||||
"comment": "tunneling device used by OpenVPN",
|
|
||||||
"name_prefix": "tun"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -2,40 +2,34 @@
|
|||||||
|
|
||||||
define('RASPI_BRAND_TEXT', 'RaspAP');
|
define('RASPI_BRAND_TEXT', 'RaspAP');
|
||||||
define('RASPI_CONFIG', '/etc/raspap');
|
define('RASPI_CONFIG', '/etc/raspap');
|
||||||
define('RASPI_CONFIG_NETWORK', RASPI_CONFIG.'/networking/defaults.json');
|
define('RASPI_CONFIG_NETWORKING', RASPI_CONFIG.'/networking');
|
||||||
define('RASPI_ADMIN_DETAILS', RASPI_CONFIG.'/raspap.auth');
|
define('RASPI_ADMIN_DETAILS', RASPI_CONFIG.'/raspap.auth');
|
||||||
define('RASPI_WIFI_AP_INTERFACE', 'wlan0');
|
define('RASPI_WIFI_AP_INTERFACE', 'wlan0');
|
||||||
define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
|
define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
|
||||||
|
|
||||||
// Constants for configuration file paths.
|
// Constants for configuration file paths.
|
||||||
// These are typical for default RPi installs. Modify if needed.
|
// These are typical for default RPi installs. Modify if needed.
|
||||||
|
define('RASPI_DNSMASQ_CONFIG', '/etc/dnsmasq.d/090_raspap.conf');
|
||||||
define('RASPI_DNSMASQ_LEASES', '/var/lib/misc/dnsmasq.leases');
|
define('RASPI_DNSMASQ_LEASES', '/var/lib/misc/dnsmasq.leases');
|
||||||
define('RASPI_DNSMASQ_PREFIX', '/etc/dnsmasq.d/090_');
|
|
||||||
define('RASPI_ADBLOCK_LISTPATH', '/etc/raspap/adblock/');
|
define('RASPI_ADBLOCK_LISTPATH', '/etc/raspap/adblock/');
|
||||||
define('RASPI_ADBLOCK_CONFIG', RASPI_DNSMASQ_PREFIX.'adblock.conf');
|
define('RASPI_ADBLOCK_CONFIG', '/etc/dnsmasq.d/090_adblock.conf');
|
||||||
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
|
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
|
||||||
define('RASPI_DHCPCD_CONFIG', '/etc/dhcpcd.conf');
|
define('RASPI_DHCPCD_CONFIG', '/etc/dhcpcd.conf');
|
||||||
define('RASPI_DHCPCD_LOG', '/var/log/dnsmasq.log');
|
|
||||||
define('RASPI_WPA_SUPPLICANT_CONFIG', '/etc/wpa_supplicant/wpa_supplicant.conf');
|
define('RASPI_WPA_SUPPLICANT_CONFIG', '/etc/wpa_supplicant/wpa_supplicant.conf');
|
||||||
define('RASPI_HOSTAPD_CTRL_INTERFACE', '/var/run/hostapd');
|
define('RASPI_HOSTAPD_CTRL_INTERFACE', '/var/run/hostapd');
|
||||||
define('RASPI_WPA_CTRL_INTERFACE', '/var/run/wpa_supplicant');
|
define('RASPI_WPA_CTRL_INTERFACE', '/var/run/wpa_supplicant');
|
||||||
define('RASPI_OPENVPN_CLIENT_PATH', '/etc/openvpn/client/');
|
|
||||||
define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf');
|
define('RASPI_OPENVPN_CLIENT_CONFIG', '/etc/openvpn/client/client.conf');
|
||||||
define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf');
|
define('RASPI_OPENVPN_CLIENT_LOGIN', '/etc/openvpn/client/login.conf');
|
||||||
define('RASPI_WIREGUARD_PATH', '/etc/wireguard/');
|
define('RASPI_OPENVPN_SERVER_CONFIG', '/etc/openvpn/server/server.conf');
|
||||||
define('RASPI_WIREGUARD_CONFIG', RASPI_WIREGUARD_PATH.'wg0.conf');
|
|
||||||
define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc');
|
define('RASPI_TORPROXY_CONFIG', '/etc/tor/torrc');
|
||||||
define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
|
define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
|
||||||
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
|
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
|
||||||
define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one');
|
define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one');
|
||||||
|
|
||||||
// Constants for the 5GHz wireless regulatory domain.
|
// Constant for the 5GHz wireless regulatory domain
|
||||||
define('RASPI_5GHZ_ISO_ALPHA2', array('NL','US'));
|
define('RASPI_5GHZ_ISO_ALPHA2', array('NL','US'));
|
||||||
define('RASPI_5GHZ_MAX_CHANNEL', 165);
|
define('RASPI_5GHZ_MAX_CHANNEL', 165);
|
||||||
|
|
||||||
// Enable basic authentication for the web admin.
|
|
||||||
define('RASPI_AUTH_ENABLED', true);
|
|
||||||
|
|
||||||
// Optional services, set to true to enable.
|
// Optional services, set to true to enable.
|
||||||
define('RASPI_WIFICLIENT_ENABLED', true);
|
define('RASPI_WIFICLIENT_ENABLED', true);
|
||||||
define('RASPI_HOTSPOT_ENABLED', true);
|
define('RASPI_HOTSPOT_ENABLED', true);
|
||||||
@ -43,7 +37,6 @@ define('RASPI_NETWORK_ENABLED', true);
|
|||||||
define('RASPI_DHCP_ENABLED', true);
|
define('RASPI_DHCP_ENABLED', true);
|
||||||
define('RASPI_ADBLOCK_ENABLED', false);
|
define('RASPI_ADBLOCK_ENABLED', false);
|
||||||
define('RASPI_OPENVPN_ENABLED', false);
|
define('RASPI_OPENVPN_ENABLED', false);
|
||||||
define('RASPI_WIREGUARD_ENABLED', false);
|
|
||||||
define('RASPI_TORPROXY_ENABLED', false);
|
define('RASPI_TORPROXY_ENABLED', false);
|
||||||
define('RASPI_CONFAUTH_ENABLED', true);
|
define('RASPI_CONFAUTH_ENABLED', true);
|
||||||
define('RASPI_CHANGETHEME_ENABLED', true);
|
define('RASPI_CHANGETHEME_ENABLED', true);
|
||||||
|
12
config/default_hostapd
Normal file
12
config/default_hostapd
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Location of hostapd configuration file
|
||||||
|
DAEMON_CONF="/etc/hostapd/hostapd.conf"
|
||||||
|
|
||||||
|
# Additional daemon options to be appended to hostapd command:-
|
||||||
|
# -d show more debug messages (-dd for even more)
|
||||||
|
# -K include key data in debug messages
|
||||||
|
# -t include timestamps in some debug messages
|
||||||
|
#
|
||||||
|
# Note that -B (daemon mode) and -P (pidfile) options are automatically
|
||||||
|
# configured by the init.d script and must not be added to DAEMON_OPTS.
|
||||||
|
#
|
||||||
|
#DAEMON_OPTS=""
|
@ -1,57 +0,0 @@
|
|||||||
{
|
|
||||||
"dhcp": {
|
|
||||||
"wlan0": {
|
|
||||||
"static ip_address": [ "10.3.141.1/24" ],
|
|
||||||
"static routers": [ "10.3.141.1" ],
|
|
||||||
"static domain_name_server": [ "1.1.1.1 8.8.8.8" ],
|
|
||||||
"subnetmask": [ "255.255.255.0" ]
|
|
||||||
},
|
|
||||||
"uap0": {
|
|
||||||
"static ip_address": [ "192.168.50.1/24" ],
|
|
||||||
"static routers": [ "192.168.50.1" ],
|
|
||||||
"static domain_name_server": [ "1.1.1.1 8.8.8.8" ],
|
|
||||||
"subnetmask": [ "255.255.255.0" ]
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"# RaspAP default configuration": null,
|
|
||||||
"hostname": null,
|
|
||||||
"clientid": null,
|
|
||||||
"persistent": null,
|
|
||||||
"option rapid_commit": null,
|
|
||||||
"option domain_name_servers, domain_name, domain_search, host_name": null,
|
|
||||||
"option classless_static_routes": null,
|
|
||||||
"option ntp_servers": null,
|
|
||||||
"require dhcp_server_identifier": null,
|
|
||||||
"slaac private": null,
|
|
||||||
"nohook lookup-hostname": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dnsmasq": {
|
|
||||||
"wlan0": {
|
|
||||||
"dhcp-range": [ "10.3.141.50,10.3.141.254,255.255.255.0,12h" ]
|
|
||||||
},
|
|
||||||
"uap0": {
|
|
||||||
"dhcp-range": [ "192.168.50.50,192.168.50.150,12h" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"wireguard": {
|
|
||||||
"server": {
|
|
||||||
"Address": [ "10.8.2.1/24" ],
|
|
||||||
"ListenPort": [ "51820" ],
|
|
||||||
"DNS": [ "9.9.9.9" ],
|
|
||||||
"PostUp": [ "iptables -A FORWARD -i wlan0 -o wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE" ],
|
|
||||||
"PostDown": [ "iptables -D FORWARD -i wlan0 -o wg0 -j ACCEPT; iptables -D FORWARD -i wg0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE" ]
|
|
||||||
},
|
|
||||||
"peer": {
|
|
||||||
"Address": [ "10.8.1.2/24" ],
|
|
||||||
"Endpoint": [ "10.8.2.1:51820" ],
|
|
||||||
"ListenPort": [ "21841" ],
|
|
||||||
"AllowedIPs": ["10.8.2.0/24"],
|
|
||||||
"PersistentKeepalive": [ "15" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"txpower": {
|
|
||||||
"dbm": [ "auto", "30", "20", "17", "10", "6", "3", "1", "0" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
# RaspAP default configuration
|
# Defaults from Raspberry Pi configuration
|
||||||
hostname
|
hostname
|
||||||
clientid
|
clientid
|
||||||
persistent
|
persistent
|
||||||
@ -10,9 +10,18 @@ require dhcp_server_identifier
|
|||||||
slaac private
|
slaac private
|
||||||
nohook lookup-hostname
|
nohook lookup-hostname
|
||||||
|
|
||||||
|
#denyinterfaces eth0 wlan0 #BRIDGED
|
||||||
|
|
||||||
|
# RaspAP br0 configuration
|
||||||
|
interface br0
|
||||||
|
|
||||||
# RaspAP wlan0 configuration
|
# RaspAP wlan0 configuration
|
||||||
interface wlan0
|
interface wlan0
|
||||||
static ip_address=10.3.141.1/24
|
static ip_address=10.3.141.1/24
|
||||||
static routers=10.3.141.1
|
static routers=10.3.141.1
|
||||||
static domain_name_server=9.9.9.9 1.1.1.1
|
static domain_name_server=9.9.9.9 1.1.1.1
|
||||||
|
|
||||||
|
# RaspAP uap0 configuration
|
||||||
|
interface uap0
|
||||||
|
static ip_address=192.168.50.1/24
|
||||||
|
nohook wpa_supplicant
|
||||||
|
@ -22,8 +22,7 @@
|
|||||||
"208.67.222.222"
|
"208.67.222.222"
|
||||||
],
|
],
|
||||||
"Quad9": [
|
"Quad9": [
|
||||||
"9.9.9.9",
|
"9.9.9.9"
|
||||||
"149.112.112.112"
|
|
||||||
],
|
],
|
||||||
"Yandex.DNS": [
|
"Yandex.DNS": [
|
||||||
"77.88.8.2",
|
"77.88.8.2",
|
||||||
|
13
config/dnsmasq.conf
Normal file
13
config/dnsmasq.conf
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# RaspAP wlan0 configuration for wired (ethernet) AP mode
|
||||||
|
interface=wlan0
|
||||||
|
dhcp-range=10.3.141.50,10.3.141.255,255.255.255.0,12h
|
||||||
|
dhcp-option=6,1.1.1.1,8.8.8.8
|
||||||
|
|
||||||
|
# RaspAP uap0 configuration for wireless client AP mode
|
||||||
|
#interface=lo,uap0 # Use interfaces lo and uap0
|
||||||
|
#bind-interfaces # Bind to the interfaces
|
||||||
|
#server=8.8.8.8 # Forward DNS requests to Google DNS
|
||||||
|
#domain-needed # Don't forward short names
|
||||||
|
#bogus-priv # Never forward addresses in the non-routed address spaces
|
||||||
|
#dhcp-range=192.168.50.50,192.168.50.150,12h
|
||||||
|
|
@ -11,7 +11,7 @@ wpa_passphrase=ChangeMe
|
|||||||
interface=wlan0
|
interface=wlan0
|
||||||
wpa=2
|
wpa=2
|
||||||
wpa_pairwise=CCMP
|
wpa_pairwise=CCMP
|
||||||
country_code=GB
|
country_code=
|
||||||
## Rapberry Pi 3 specific to on board WLAN/WiFi
|
## Rapberry Pi 3 specific to on board WLAN/WiFi
|
||||||
#ieee80211n=1 # 802.11n support (Raspberry Pi 3)
|
#ieee80211n=1 # 802.11n support (Raspberry Pi 3)
|
||||||
#wmm_enabled=1 # QoS support (Raspberry Pi 3)
|
#wmm_enabled=1 # QoS support (Raspberry Pi 3)
|
||||||
@ -20,5 +20,5 @@ country_code=GB
|
|||||||
## RaspAP wireless client AP mode
|
## RaspAP wireless client AP mode
|
||||||
#interface=uap0
|
#interface=uap0
|
||||||
|
|
||||||
## RaspAP bridge AP mode, disabled by default
|
## RaspAP bridge AP mode (disabled by default)
|
||||||
#bridge=br0
|
#bridge=br0
|
||||||
|
@ -1,205 +0,0 @@
|
|||||||
{
|
|
||||||
"info": "IPTABLES rules. $...$ expressions will be replaces automatically ($INTERFACE$, $PORT$, $IPADDRESS$)",
|
|
||||||
"rules_v4_file": "/etc/iptables/rules.v4",
|
|
||||||
"rules_v6_file": "/etc/iptables/rules.v6",
|
|
||||||
"order": [ "pre_rules", "restriction_rules", "main_rules", "exception_rules" ],
|
|
||||||
"pre_rules": [
|
|
||||||
{
|
|
||||||
"name": "firewall policies",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "Policy rules (firewall)",
|
|
||||||
"rules": [
|
|
||||||
"-P INPUT DROP",
|
|
||||||
"-P FORWARD ACCEPT",
|
|
||||||
"-P OUTPUT ACCEPT",
|
|
||||||
"-t nat -P PREROUTING ACCEPT",
|
|
||||||
"-t nat -P POSTROUTING ACCEPT",
|
|
||||||
"-t nat -P INPUT ACCEPT",
|
|
||||||
"-t nat -P OUTPUT ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "policies",
|
|
||||||
"fw-state": false,
|
|
||||||
"comment": "Policy rules",
|
|
||||||
"rules": [
|
|
||||||
"-P INPUT ACCEPT",
|
|
||||||
"-P FORWARD ACCEPT",
|
|
||||||
"-P OUTPUT ACCEPT",
|
|
||||||
"-t nat -P PREROUTING ACCEPT",
|
|
||||||
"-t nat -P POSTROUTING ACCEPT",
|
|
||||||
"-t nat -P INPUT ACCEPT",
|
|
||||||
"-t nat -P OUTPUT ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "loopback",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "allow loopback device",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -i lo -j ACCEPT",
|
|
||||||
"-A OUTPUT -o lo -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ping",
|
|
||||||
"fw-state": true,
|
|
||||||
"ip-version": 4,
|
|
||||||
"comment": "allow ping request and echo",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p icmp --icmp-type 8/0 -j ACCEPT",
|
|
||||||
"-A INPUT -p icmp --icmp-type 0/0 -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ping IPv6",
|
|
||||||
"fw-state": true,
|
|
||||||
"ip-version": 6,
|
|
||||||
"comment": "allow ping request and echo for IPv6",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p icmpv6 --icmpv6-type echo-request -j ACCEPT",
|
|
||||||
"-A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ntp",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "allow ntp request via udp (tcp should work w/o rule)",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p udp --sport 123 -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dns",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "allow dns request via tcp and udp",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p udp -m multiport --sport 53,853 -j ACCEPT",
|
|
||||||
"-A INPUT -p tcp -m multiport --sport 53,853 -j ACCEPT"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"main_rules": [
|
|
||||||
{
|
|
||||||
"name": "accesspoint",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "Access point interface by default no restrictions",
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "ap-device", "type": "string", "replace": "$INTERFACE$" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -i $INTERFACE$ -j ACCEPT",
|
|
||||||
"-A OUTPUT -o $INTERFACE$ -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "NAT for access point",
|
|
||||||
"comment": "Masquerading needed for access point",
|
|
||||||
"rules": [
|
|
||||||
"-t nat -A POSTROUTING -j MASQUERADE"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "clients",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "Rules for client interfaces (includes tun device)",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "openvpn",
|
|
||||||
"comment": "Rules for tunnel device (tun)",
|
|
||||||
"ip-version": 4,
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "openvpn-enable", "type": "bool" },
|
|
||||||
{ "var": "openvpn-serverip", "type": "string", "replace": "$IPADDRESS$" },
|
|
||||||
{ "var": "ap-device", "type": "string", "replace": "$INTERFACE$" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p udp -s $IPADDRESS$ -j ACCEPT",
|
|
||||||
"-A FORWARD -i tun+ -o $INTERFACE$ -m state --state RELATED,ESTABLISHED -j ACCEPT",
|
|
||||||
"-A FORWARD -i $INTERFACE$ -o tun+ -j ACCEPT",
|
|
||||||
"-t nat -A POSTROUTING -o tun+ -j MASQUERADE"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "wireguard",
|
|
||||||
"comment": "Rules for wireguard device (wg)",
|
|
||||||
"ip-version": 4,
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "wireguard-enable", "type": "bool" },
|
|
||||||
{ "var": "wireguard-serverip", "type": "string", "replace": "$IPADDRESS$" },
|
|
||||||
{ "var": "client-device", "type": "string", "replace": "$INTERFACE$" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p udp -s $IPADDRESS$ -j ACCEPT",
|
|
||||||
"-A FORWARD -i wg+ -j ACCEPT",
|
|
||||||
"-t nat -A POSTROUTING -o $INTERFACE$ -j MASQUERADE"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"exception_rules": [
|
|
||||||
{
|
|
||||||
"name": "ssh",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "Allow ssh access to RaspAP on port 22",
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "ssh-enable", "type": "bool" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p tcp --dport 22 -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "http",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "Allow access to RaspAP GUI (https)",
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "http-enable", "type": "bool" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "interface",
|
|
||||||
"fw-state": true,
|
|
||||||
"comment": "Exclude interface from firewall",
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "excl-devices", "type": "list", "replace": "$INTERFACE$" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -i $INTERFACE$ -j ACCEPT",
|
|
||||||
"-A OUTPUT -o $INTERFACE$ -j ACCEPT"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ipaddress",
|
|
||||||
"fw-state": true,
|
|
||||||
"ip-version": 4,
|
|
||||||
"comment": "allow access from/to IP",
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "excluded-ips", "type": "list", "replace": "$IPADDRESS$" }
|
|
||||||
],
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -s $IPADDRESS$ -j ACCEPT",
|
|
||||||
"-A INPUT -d $IPADDRESS$ -j ACCEPT"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"restriction_rules": [
|
|
||||||
{
|
|
||||||
"name": "ipaddress",
|
|
||||||
"fw-state": true,
|
|
||||||
"ip-version": 4,
|
|
||||||
"dependson": [
|
|
||||||
{ "var": "restricted-ips", "type": "list", "replace": "$IPADDRESS$" }
|
|
||||||
],
|
|
||||||
"comment": "Block access from IP-address",
|
|
||||||
"rules": [
|
|
||||||
"-A INPUT -s $IPADDRESS$ -j DROP"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
network:
|
|
||||||
version: 2
|
|
||||||
renderer: networkd
|
|
||||||
ethernets:
|
|
||||||
eth0:
|
|
||||||
dhcp4: no
|
|
||||||
bridges:
|
|
||||||
br0:
|
|
||||||
dhcp4: yes
|
|
||||||
interfaces:
|
|
||||||
- eth0
|
|
BIN
dist/raspap/css/fonts/RaspAP.eot
vendored
BIN
dist/raspap/css/fonts/RaspAP.eot
vendored
Binary file not shown.
12
dist/raspap/css/fonts/RaspAP.svg
vendored
12
dist/raspap/css/fonts/RaspAP.svg
vendored
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<metadata>Generated by IcoMoon</metadata>
|
|
||||||
<defs>
|
|
||||||
<font id="RaspAP" horiz-adv-x="1024">
|
|
||||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
|
||||||
<missing-glyph horiz-adv-x="1024" />
|
|
||||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
|
||||||
<glyph unicode="" glyph-name="wireguard" d="M1023.147 463.147c0 0 23.595 496.853-522.453 496.853-482.859 0-497.963-476.587-497.963-476.587s-70.997-547.413 509.141-547.413c556.501 0 511.275 527.147 511.275 527.147zM347.947 636.757c102.4 62.72 233.344 24.363 282.368-69.888 9.301-17.877 10.496-45.355 4.608-64.128-20.352-64.683-68.309-100.949-134.187-116.395 19.413 16.64 34.859 35.499 39.808 61.525 1.195 5.504 1.88 11.827 1.88 18.31 0 20.027-6.533 38.528-17.584 53.488l0.174-0.246c-16.797 22.874-43.588 37.556-73.809 37.556-11.257 0-22.038-2.037-31.995-5.763l0.63 0.207c-40.533-15.36-62.72-52.395-58.752-97.877 3.712-42.24 35.797-69.632 95.787-80.043-8.96-4.736-15.872-8.235-22.613-11.989-27.988-15.524-51.374-35.995-69.74-60.451l-0.404-0.562c-6.101-8.192-10.24-8.875-19.541-3.2-120.619 73.771-128.384 258.859 3.371 339.456zM257.707 180.992c-19.413-4.949-38.187-12.203-57.984-18.688 9.685 65.365 86.229 125.568 150.997 118.699-18.043-24.598-29.583-54.982-31.551-87.945l-0.022-0.46c-21.504-3.968-41.813-6.613-61.44-11.605zM669.995 819.2c19.115-0.725 38.315-0.427 57.472-0.853 5.287-0.363 10.162-1.075 14.91-2.128l-0.659 0.123c-4.574-6.938-9.348-12.986-14.582-18.599l0.076 0.082c-6.827-6.4-14.549-12.629-24.448-2.944-2.347 2.347-7.979 1.792-12.075 1.877-19.072 0.213-38.144 0.853-57.173 0.128-17.856-0.589-34.82-2.396-51.386-5.353l2.149 0.318c-3.072-0.555-7.595-10.667-6.229-14.421 3.328-8.832 8.149-18.56 15.317-24.192 26.411-20.907 54.485-39.595 81.067-60.288 25.771-20.139 49.792-42.24 64.427-72.533 19.029-39.595 19.627-81.067 11.392-122.752-13.739-69.547-48.939-127.147-105.941-169.045-22.955-16.853-51.413-26.453-77.696-38.528-23.168-10.667-46.933-19.84-70.144-30.379-41.813-19.029-65.28-64.427-58.411-111.573 6.357-43.307 44.373-79.445 87.851-86.912 52.181-8.96 106.069 25.003 118.827 78.080 14.336 59.605-18.048 112.896-78.72 129.024l-10.923 2.816c16.213 7.253 30.208 12.416 43.179 19.541q33.835 18.645 66.475 39.467c6.4 4.096 9.856 4.096 15.36-0.597 41.685-36.096 66.56-80.981 73.557-135.979 11.52-91.093-31.573-174.763-112.896-217.643-125.781-66.347-279.765 9.173-307.541 148.651-23.808 119.467 60.501 227.84 162.005 248.747 43.648 9.003 83.541 27.179 114.56 60.8 20.053 21.675 29.739 40.277 33.067 48.683 5.86 14.568 9.259 31.458 9.259 49.142 0 0.094 0 0.187 0 0.281v-0.014c-0.72 15.473-4.371 29.921-10.408 43.044l0.296-0.719c-10.581 24.149-51.2 62.549-61.227 70.656l-95.573 74.837c-3.371 2.773-7.168 2.56-15.36 2.005-9.813-0.683-34.773-2.048-45.525 0.768 8.704 6.613 32.427 16.213 42.667 23.893-30.976 20.907-66.304 13.397-98.773 19.627 7.509 13.995 44.629 35.456 65.749 37.888-1.455 13.545-3.483 25.484-6.166 37.173l0.406-2.101c-1.28 4.736-6.571 9.387-11.221 12.075-11.179 6.571-23.083 11.989-35.968 18.517 10.935 7.156 24.244 11.558 38.555 11.945l0.101 0.002c1.66 0.068 3.608 0.107 5.566 0.107 11.77 0 23.21-1.408 34.163-4.064l-0.987 0.202c23.040-5.248 41.387-1.792 59.691 13.824-14.421 5.803-28.843 11.093-42.795 17.365-16.163 7.396-29.343 14.415-42.082 22.091l1.89-1.056c36.267-5.035 71.296-18.645 108.373-13.653l0.939 5.035-86.101 20.053c51.328 4.693 99.115 5.461 144.384-16.555 12.757-6.229 26.027-11.349 38.272-18.432 5.973-3.413 9.941-10.24 14.848-15.573 3.84-4.181 6.997-9.813 11.776-12.373 18.091-9.6 37.973-9.984 58.283-9.515l0.427 6.827c20.437-6.4 43.392-29.952 43.392-47.147-33.109 0-66.133 0.128-99.2-0.171-3.541 0-7.040-2.603-10.539-4.011 3.328-1.963 6.613-5.461 10.027-5.589zM627.328 868.139c-1.461-0.899-2.42-2.488-2.42-4.302 0-1.516 0.67-2.876 1.731-3.799l0.006-0.005c1.344-2.305 3.804-3.83 6.62-3.83 1.429 0 2.767 0.393 3.91 1.076l-0.035-0.019c3.2 1.621 6.315 3.328 10.155 5.333-3.072 2.645-5.547 4.864-8.107 6.955-4.523 3.712-8.235 1.365-11.861-1.408z" />
|
|
||||||
<glyph unicode="" glyph-name="raspap" horiz-adv-x="1031" d="M540.058 281.983c0-104.182-84.446-188.637-188.625-188.637-104.176 0-188.62 84.455-188.62 188.637 0 104.171 84.444 188.625 188.62 188.625 104.179 0 188.625-84.455 188.625-188.625zM351.437 550.062c-147.818 0-268.074-120.259-268.074-268.080 0-147.826 120.257-268.091 268.074-268.091s268.077 120.265 268.077 268.091c0 147.821-120.259 268.080-268.077 268.080zM351.437-58.985c-188 0-340.95 152.958-340.95 340.967 0 188.003 152.95 340.956 340.95 340.956 188.003 0 340.953-152.953 340.953-340.956 0-188.009-152.95-340.967-340.953-340.967zM404.82 698.222c185.52 0 339.484-137.497 365.479-315.929l79.208-5.253c-24.125 224.046-214.339 399.077-444.686 399.077-10.909 0-21.723-0.412-32.433-1.186l5.16-77.823c9.017 0.661 18.093 1.113 27.272 1.113zM404.989 874.303c285.73 0 520.41-222.659 539.731-503.584l78.375-5.205c-16.843 326.355-287.644 586.685-618.106 586.685-14.884 0-29.644-0.561-44.264-1.6l5.157-77.719c12.919 0.928 25.958 1.424 39.106 1.424z" />
|
|
||||||
</font></defs></svg>
|
|
Before Width: | Height: | Size: 5.0 KiB |
BIN
dist/raspap/css/fonts/RaspAP.ttf
vendored
BIN
dist/raspap/css/fonts/RaspAP.ttf
vendored
Binary file not shown.
BIN
dist/raspap/css/fonts/RaspAP.woff
vendored
BIN
dist/raspap/css/fonts/RaspAP.woff
vendored
Binary file not shown.
54
dist/raspap/css/style.css
vendored
54
dist/raspap/css/style.css
vendored
@ -1,54 +0,0 @@
|
|||||||
/*!
|
|
||||||
* 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: #2b8080;
|
|
||||||
margin-left: 0.1em;
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,7 @@ const pkg = require('./package.json');
|
|||||||
const banner = ['/*!\n',
|
const banner = ['/*!\n',
|
||||||
' * RaspAP - <%= pkg.title %> v<%= pkg.version %> (<%= pkg.homepage %>)\n',
|
' * RaspAP - <%= pkg.title %> v<%= pkg.version %> (<%= pkg.homepage %>)\n',
|
||||||
' * Copyright 2013-' + (new Date()).getFullYear(), ' <%= pkg.author %>\n',
|
' * Copyright 2013-' + (new Date()).getFullYear(), ' <%= pkg.author %>\n',
|
||||||
' * Licensed under <%= pkg.license %> (https://github.com/raspap/raspap-webgui/<%= pkg.name %>/blob/master/LICENSE)\n',
|
' * Licensed under <%= pkg.license %> (https://github.com/raspap-webgui/<%= pkg.name %>/blob/master/LICENSE)\n',
|
||||||
' */\n',
|
' */\n',
|
||||||
'\n'
|
'\n'
|
||||||
].join('');
|
].join('');
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once "app/lib/Parsedown.php";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays info about the RaspAP project
|
* Displays info about the RaspAP project
|
||||||
*/
|
*/
|
||||||
function DisplayAbout()
|
function DisplayAbout()
|
||||||
{
|
{
|
||||||
$Parsedown = new Parsedown();
|
echo renderTemplate("about");
|
||||||
$strContent = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/BACKERS.md');
|
|
||||||
$sponsorsHtml = $Parsedown->text($strContent);
|
|
||||||
|
|
||||||
echo renderTemplate("about", compact('sponsorsHtml'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'includes/status_messages.php';
|
||||||
require_once 'config.php';
|
require_once 'config.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,7 +9,7 @@ require_once 'config.php';
|
|||||||
*/
|
*/
|
||||||
function DisplayAdBlockConfig()
|
function DisplayAdBlockConfig()
|
||||||
{
|
{
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
$status = new StatusMessages();
|
||||||
$enabled = false;
|
$enabled = false;
|
||||||
$custom_enabled = false;
|
$custom_enabled = false;
|
||||||
|
|
||||||
@ -74,34 +75,13 @@ function DisplayAdBlockConfig()
|
|||||||
$dnsmasq_state = ($dnsmasq[0] > 0);
|
$dnsmasq_state = ($dnsmasq[0] > 0);
|
||||||
$serviceStatus = $dnsmasq_state && $enabled ? "up" : "down";
|
$serviceStatus = $dnsmasq_state && $enabled ? "up" : "down";
|
||||||
|
|
||||||
if (file_exists(RASPI_ADBLOCK_LISTPATH .'custom.txt')) {
|
|
||||||
$adblock_custom_content = file_get_contents(RASPI_ADBLOCK_LISTPATH .'custom.txt');
|
|
||||||
} else {
|
|
||||||
$adblock_custom_content = '';
|
|
||||||
}
|
|
||||||
$adblock_log = '';
|
|
||||||
exec('sudo chmod o+r '.RASPI_DHCPCD_LOG);
|
|
||||||
$handle = fopen(RASPI_DHCPCD_LOG, "r");
|
|
||||||
if ($handle) {
|
|
||||||
while (($line = fgets($handle)) !== false) {
|
|
||||||
if (preg_match('/(is 0.0.0.0)|(using only locally-known addresses)/', $line)) {
|
|
||||||
$adblock_log .= $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose($handle);
|
|
||||||
} else {
|
|
||||||
$adblock_log = "Unable to open log file";
|
|
||||||
}
|
|
||||||
|
|
||||||
echo renderTemplate(
|
echo renderTemplate(
|
||||||
"adblock", compact(
|
"adblock", compact(
|
||||||
"status",
|
"status",
|
||||||
"serviceStatus",
|
"serviceStatus",
|
||||||
"dnsmasq_state",
|
"dnsmasq_state",
|
||||||
"enabled",
|
"enabled",
|
||||||
"custom_enabled",
|
"custom_enabled"
|
||||||
"adblock_custom_content",
|
|
||||||
"adblock_log"
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
function DisplayAuthConfig($username)
|
require_once 'includes/status_messages.php';
|
||||||
{
|
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
|
||||||
$auth = new \RaspAP\Auth\HTTPAuth;
|
|
||||||
$config = $auth->getAuthConfig();
|
|
||||||
$password = $config['admin_pass'];
|
|
||||||
|
|
||||||
|
function DisplayAuthConfig($username, $password)
|
||||||
|
{
|
||||||
|
$status = new StatusMessages();
|
||||||
if (isset($_POST['UpdateAdminPassword'])) {
|
if (isset($_POST['UpdateAdminPassword'])) {
|
||||||
if (password_verify($_POST['oldpass'], $password)) {
|
if (password_verify($_POST['oldpass'], $password)) {
|
||||||
$new_username=trim($_POST['username']);
|
$new_username=trim($_POST['username']);
|
||||||
@ -35,10 +33,5 @@ function DisplayAuthConfig($username)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo renderTemplate(
|
echo renderTemplate("admin", compact("status", "username"));
|
||||||
"admin", compact(
|
|
||||||
"status",
|
|
||||||
"username"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
$user = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
$pass = $_SERVER['PHP_AUTH_PW'];
|
||||||
|
|
||||||
if (RASPI_AUTH_ENABLED) {
|
$validated = ($user == $config['admin_user']) && password_verify($pass, $config['admin_pass']);
|
||||||
$user = $_SERVER['PHP_AUTH_USER'] ?? '';
|
|
||||||
$pass = $_SERVER['PHP_AUTH_PW'] ?? '';
|
|
||||||
|
|
||||||
$auth = new \RaspAP\Auth\HTTPAuth;
|
if (!$validated) {
|
||||||
|
header('WWW-Authenticate: Basic realm="RaspAP"');
|
||||||
if (!$auth->isLogged()) {
|
if (function_exists('http_response_code')) {
|
||||||
if ($auth->login($user, $pass)) {
|
// http_response_code will respond with proper HTTP version back.
|
||||||
$config = $auth->getAuthConfig();
|
http_response_code(401);
|
||||||
} else {
|
} else {
|
||||||
$auth->authenticate();
|
header('HTTP/1.0 401 Unauthorized');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit('Not authorized'.PHP_EOL);
|
||||||
}
|
}
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* PSR-4 compliant class autoloader
|
|
||||||
*
|
|
||||||
* @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md
|
|
||||||
* @link https://www.php.net/manual/en/function.spl-autoload-register.php
|
|
||||||
* @param string $class fully-qualified class name
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
spl_autoload_register(function ($class) {
|
|
||||||
|
|
||||||
// project-specific namespace prefix
|
|
||||||
$prefix = '';
|
|
||||||
|
|
||||||
// base directory for the namespace prefix
|
|
||||||
$base_dir = 'src/';
|
|
||||||
|
|
||||||
// normalize the base directory with a trailing separator
|
|
||||||
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
|
|
||||||
|
|
||||||
// does the class use the namespace prefix?
|
|
||||||
$len = strlen($prefix);
|
|
||||||
if (strncmp($prefix, $class, $len) !== 0) {
|
|
||||||
// no, move to the next registered autoloader
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the relative class name
|
|
||||||
$relative_class = substr($class, $len);
|
|
||||||
|
|
||||||
// replace the namespace prefix with the base directory, replace namespace
|
|
||||||
// separators with directory separators in the relative class name, append
|
|
||||||
// with .php
|
|
||||||
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
|
|
||||||
|
|
||||||
// if the file exists, require it
|
|
||||||
if (file_exists($file)) {
|
|
||||||
require $file;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'includes/status_messages.php';
|
||||||
require_once 'includes/wifi_functions.php';
|
require_once 'includes/wifi_functions.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,7 +9,7 @@ require_once 'includes/wifi_functions.php';
|
|||||||
*/
|
*/
|
||||||
function DisplayWPAConfig()
|
function DisplayWPAConfig()
|
||||||
{
|
{
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
$status = new StatusMessages();
|
||||||
$networks = [];
|
$networks = [];
|
||||||
|
|
||||||
getWifiInterface();
|
getWifiInterface();
|
||||||
@ -16,15 +17,8 @@ function DisplayWPAConfig()
|
|||||||
|
|
||||||
if (isset($_POST['connect'])) {
|
if (isset($_POST['connect'])) {
|
||||||
$result = 0;
|
$result = 0;
|
||||||
$iface = escapeshellarg($_SESSION['wifi_client_interface']);
|
exec('sudo wpa_cli -i ' . $_SESSION['wifi_client_interface'] . ' select_network '.strval($_POST['connect']));
|
||||||
$netid = intval($_POST['connect']);
|
|
||||||
exec('sudo wpa_cli -i ' . $iface . ' select_network ' . $netid);
|
|
||||||
$status->addMessage('New network selected', 'success');
|
$status->addMessage('New network selected', 'success');
|
||||||
} elseif (isset($_POST['wpa_reinit'])) {
|
|
||||||
$status->addMessage('Reinitializing wpa_supplicant', 'info', false);
|
|
||||||
$force_remove = true;
|
|
||||||
$result = reinitializeWPA($force_remove);
|
|
||||||
$status->addMessage($result, 'info');
|
|
||||||
} elseif (isset($_POST['client_settings'])) {
|
} elseif (isset($_POST['client_settings'])) {
|
||||||
$tmp_networks = $networks;
|
$tmp_networks = $networks;
|
||||||
if ($wpa_file = fopen('/tmp/wifidata', 'w')) {
|
if ($wpa_file = fopen('/tmp/wifidata', 'w')) {
|
||||||
@ -62,7 +56,7 @@ function DisplayWPAConfig()
|
|||||||
if (strlen($network['passphrase']) >=8 && strlen($network['passphrase']) <= 63) {
|
if (strlen($network['passphrase']) >=8 && strlen($network['passphrase']) <= 63) {
|
||||||
unset($wpa_passphrase);
|
unset($wpa_passphrase);
|
||||||
unset($line);
|
unset($line);
|
||||||
exec('wpa_passphrase '. ssid2utf8( escapeshellarg($ssid) ) . ' ' . escapeshellarg($network['passphrase']), $wpa_passphrase);
|
exec('wpa_passphrase '.escapeshellarg($ssid). ' ' . escapeshellarg($network['passphrase']), $wpa_passphrase);
|
||||||
foreach ($wpa_passphrase as $line) {
|
foreach ($wpa_passphrase as $line) {
|
||||||
if (preg_match('/^\s*}\s*$/', $line)) {
|
if (preg_match('/^\s*}\s*$/', $line)) {
|
||||||
if (array_key_exists('priority', $network)) {
|
if (array_key_exists('priority', $network)) {
|
||||||
@ -70,22 +64,9 @@ function DisplayWPAConfig()
|
|||||||
}
|
}
|
||||||
fwrite($wpa_file, $line.PHP_EOL);
|
fwrite($wpa_file, $line.PHP_EOL);
|
||||||
} else {
|
} else {
|
||||||
if ( preg_match('/\\\\x[0-9A-Fa-f]{2}/',$ssid) && strpos($line, "ssid=\"") !== false ) {
|
fwrite($wpa_file, $line.PHP_EOL);
|
||||||
fwrite($wpa_file, "\tssid=P\"".$ssid."\"".PHP_EOL);
|
|
||||||
} else {
|
|
||||||
fwrite($wpa_file, $line.PHP_EOL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif (strlen($network['passphrase']) == 0 && strlen($network['passkey']) == 64) {
|
|
||||||
$line = "\tpsk=" . $network['passkey'];
|
|
||||||
fwrite($wpa_file, "network={".PHP_EOL);
|
|
||||||
fwrite($wpa_file, "\tssid=\"".$ssid."\"".PHP_EOL);
|
|
||||||
fwrite($wpa_file, $line.PHP_EOL);
|
|
||||||
if (array_key_exists('priority', $network)) {
|
|
||||||
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
|
|
||||||
}
|
|
||||||
fwrite($wpa_file, "}".PHP_EOL);
|
|
||||||
} else {
|
} else {
|
||||||
$status->addMessage('WPA passphrase must be between 8 and 63 characters', 'danger');
|
$status->addMessage('WPA passphrase must be between 8 and 63 characters', 'danger');
|
||||||
$ok = false;
|
$ok = false;
|
||||||
@ -112,13 +93,9 @@ function DisplayWPAConfig()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$clientInterface = $_SESSION['wifi_client_interface'];
|
nearbyWifiStations($networks);
|
||||||
|
connectedWifiStations($networks);
|
||||||
|
sortNetworksByRSSI($networks);
|
||||||
|
|
||||||
exec('ip a show '.$clientInterface, $stdoutIp);
|
echo renderTemplate("configure_client", compact("status"));
|
||||||
$stdoutIpAllLinesGlued = implode(" ", $stdoutIp);
|
|
||||||
$stdoutIpWRepeatedSpaces = preg_replace('/\s\s+/', ' ', $stdoutIpAllLinesGlued);
|
|
||||||
preg_match('/state (UP|DOWN)/i', $stdoutIpWRepeatedSpaces, $matchesState) || $matchesState[1] = 'unknown';
|
|
||||||
$ifaceStatus = strtolower($matchesState[1]) ? "up" : "down";
|
|
||||||
|
|
||||||
echo renderTemplate("configure_client", compact("status", "clientInterface", "ifaceStatus"));
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
require_once 'includes/config.php';
|
require_once 'includes/config.php';
|
||||||
require_once 'includes/wifi_functions.php';
|
require_once 'includes/wifi_functions.php';
|
||||||
require_once 'includes/functions.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show dashboard page.
|
* Show dashboard page.
|
||||||
@ -10,7 +9,7 @@ require_once 'includes/functions.php';
|
|||||||
function DisplayDashboard(&$extraFooterScripts)
|
function DisplayDashboard(&$extraFooterScripts)
|
||||||
{
|
{
|
||||||
getWifiInterface();
|
getWifiInterface();
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
$status = new StatusMessages();
|
||||||
// Need this check interface name for proper shell execution.
|
// Need this check interface name for proper shell execution.
|
||||||
if (!preg_match('/^([a-zA-Z0-9]+)$/', $_SESSION['wifi_client_interface'])) {
|
if (!preg_match('/^([a-zA-Z0-9]+)$/', $_SESSION['wifi_client_interface'])) {
|
||||||
$status->addMessage(_('Interface name invalid.'), 'danger');
|
$status->addMessage(_('Interface name invalid.'), 'danger');
|
||||||
@ -107,7 +106,8 @@ function DisplayDashboard(&$extraFooterScripts)
|
|||||||
$wlanHasLink = false;
|
$wlanHasLink = false;
|
||||||
$matchesSSID[1] = 'None';
|
$matchesSSID[1] = 'None';
|
||||||
}
|
}
|
||||||
$connectedSSID = str_replace('\x20', '', $matchesSSID[1]);
|
|
||||||
|
$connectedSSID = $matchesSSID[1];
|
||||||
|
|
||||||
preg_match('/freq: (\d+)/i', $stdoutIwWRepSpaces, $matchesFrequency) || $matchesFrequency[1] = '';
|
preg_match('/freq: (\d+)/i', $stdoutIwWRepSpaces, $matchesFrequency) || $matchesFrequency[1] = '';
|
||||||
$frequency = $matchesFrequency[1].' MHz';
|
$frequency = $matchesFrequency[1].' MHz';
|
||||||
@ -136,7 +136,7 @@ function DisplayDashboard(&$extraFooterScripts)
|
|||||||
if ($signalLevel >= 0) {
|
if ($signalLevel >= 0) {
|
||||||
$strLinkQuality = 100;
|
$strLinkQuality = 100;
|
||||||
} else {
|
} else {
|
||||||
$strLinkQuality = 100 + intval($signalLevel);
|
$strLinkQuality = 100 + $signalLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,30 +177,9 @@ function DisplayDashboard(&$extraFooterScripts)
|
|||||||
$status->addMessage(sprintf(_('Interface is %s.'), strtolower($interfaceState)), $classMsgDevicestatus);
|
$status->addMessage(sprintf(_('Interface is %s.'), strtolower($interfaceState)), $classMsgDevicestatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// brought in from template
|
|
||||||
$arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini');
|
|
||||||
$bridgedEnable = $arrHostapdConf['BridgedEnable'];
|
|
||||||
$clientInterface = $_SESSION['wifi_client_interface'];
|
|
||||||
$apInterface = $_SESSION['ap_interface'];
|
|
||||||
$MACPattern = '"([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}"';
|
|
||||||
|
|
||||||
if (getBridgedState()) {
|
|
||||||
$moreLink = "hostapd_conf";
|
|
||||||
exec('iw dev ' . $apInterface . ' station dump | grep -oE ' . $MACPattern, $clients);
|
|
||||||
} else {
|
|
||||||
$moreLink = "dhcpd_conf";
|
|
||||||
exec('cat ' . RASPI_DNSMASQ_LEASES . '| grep -E $(iw dev ' . $apInterface . ' station dump | grep -oE ' . $MACPattern . ' | paste -sd "|")', $clients);
|
|
||||||
}
|
|
||||||
$ifaceStatus = $wlan0up ? "up" : "down";
|
|
||||||
|
|
||||||
echo renderTemplate(
|
echo renderTemplate(
|
||||||
"dashboard", compact(
|
"dashboard", compact(
|
||||||
"clients",
|
|
||||||
"moreLink",
|
|
||||||
"apInterface",
|
|
||||||
"clientInterface",
|
|
||||||
"ifaceStatus",
|
|
||||||
"bridgedEnable",
|
|
||||||
"status",
|
"status",
|
||||||
"ipv4Addrs",
|
"ipv4Addrs",
|
||||||
"ipv4Netmasks",
|
"ipv4Netmasks",
|
||||||
@ -224,3 +203,33 @@ function DisplayDashboard(&$extraFooterScripts)
|
|||||||
$extraFooterScripts[] = array('src'=>'app/js/linkquality.js', 'defer'=>false);
|
$extraFooterScripts[] = array('src'=>'app/js/linkquality.js', 'defer'=>false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a human readable data size string from a number of bytes.
|
||||||
|
*
|
||||||
|
* @param long $numbytes The number of bytes.
|
||||||
|
* @param int $precision The number of numbers to round to after the dot/comma.
|
||||||
|
* @return string Data size in units: PB, TB, GB, MB or KB otherwise an empty string.
|
||||||
|
*/
|
||||||
|
function getHumanReadableDatasize($numbytes, $precision = 2)
|
||||||
|
{
|
||||||
|
$humanDatasize = '';
|
||||||
|
$kib = 1024;
|
||||||
|
$mib = $kib * 1024;
|
||||||
|
$gib = $mib * 1024;
|
||||||
|
$tib = $gib * 1024;
|
||||||
|
$pib = $tib * 1024;
|
||||||
|
if ($numbytes >= $pib) {
|
||||||
|
$humanDatasize = ' ('.round($numbytes / $pib, $precision).' PB)';
|
||||||
|
} elseif ($numbytes >= $tib) {
|
||||||
|
$humanDatasize = ' ('.round($numbytes / $tib, $precision).' TB)';
|
||||||
|
} elseif ($numbytes >= $gib) {
|
||||||
|
$humanDatasize = ' ('.round($numbytes / $gib, $precision).' GB)';
|
||||||
|
} elseif ($numbytes >= $mib) {
|
||||||
|
$humanDatasize = ' ('.round($numbytes / $mib, $precision).' MB)';
|
||||||
|
} elseif ($numbytes >= $kib) {
|
||||||
|
$humanDatasize = ' ('.round($numbytes / $kib, $precision).' KB)';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $humanDatasize;
|
||||||
|
}
|
||||||
|
@ -6,29 +6,26 @@ if (!defined('RASPI_CONFIG')) {
|
|||||||
|
|
||||||
$defaults = [
|
$defaults = [
|
||||||
'RASPI_BRAND_TEXT' => 'RaspAP',
|
'RASPI_BRAND_TEXT' => 'RaspAP',
|
||||||
'RASPI_VERSION' => '2.9.6',
|
'RASPI_VERSION' => '2.5.2',
|
||||||
'RASPI_CONFIG_NETWORK' => RASPI_CONFIG.'/networking/defaults.json',
|
'RASPI_CONFIG_NETWORKING' => RASPI_CONFIG.'/networking',
|
||||||
'RASPI_ADMIN_DETAILS' => RASPI_CONFIG.'/raspap.auth',
|
'RASPI_ADMIN_DETAILS' => RASPI_CONFIG.'/raspap.auth',
|
||||||
'RASPI_WIFI_AP_INTERFACE' => 'wlan0',
|
'RASPI_WIFI_AP_INTERFACE' => 'wlan0',
|
||||||
'RASPI_CACHE_PATH' => sys_get_temp_dir() . '/raspap',
|
'RASPI_CACHE_PATH' => sys_get_temp_dir() . '/raspap',
|
||||||
|
|
||||||
// Constants for configuration file paths.
|
// Constants for configuration file paths.
|
||||||
// These are typical for default RPi installs. Modify if needed.
|
// These are typical for default RPi installs. Modify if needed.
|
||||||
|
'RASPI_DNSMASQ_CONFIG' => '/etc/dnsmasq.d/090_raspap.conf',
|
||||||
'RASPI_DNSMASQ_LEASES' => '/var/lib/misc/dnsmasq.leases',
|
'RASPI_DNSMASQ_LEASES' => '/var/lib/misc/dnsmasq.leases',
|
||||||
'RASPI_DNSMASQ_PREFIX' => '/etc/dnsmasq.d/090_',
|
|
||||||
'RASPI_ADBLOCK_LISTPATH' => '/etc/raspap/adblock/',
|
'RASPI_ADBLOCK_LISTPATH' => '/etc/raspap/adblock/',
|
||||||
'RASPI_ADBLOCK_CONFIG' => RASPI_DNSMASQ_PREFIX.'adblock.conf',
|
'RASPI_ADBLOCK_CONFIG' => '/etc/dnsmasq.d/090_adblock.conf',
|
||||||
'RASPI_HOSTAPD_CONFIG' => '/etc/hostapd/hostapd.conf',
|
'RASPI_HOSTAPD_CONFIG' => '/etc/hostapd/hostapd.conf',
|
||||||
'RASPI_DHCPCD_CONFIG' => '/etc/dhcpcd.conf',
|
'RASPI_DHCPCD_CONFIG' => '/etc/dhcpcd.conf',
|
||||||
'RASPI_DHCPCD_LOG' => '/var/log/dnsmasq.log',
|
|
||||||
'RASPI_WPA_SUPPLICANT_CONFIG' => '/etc/wpa_supplicant/wpa_supplicant.conf',
|
'RASPI_WPA_SUPPLICANT_CONFIG' => '/etc/wpa_supplicant/wpa_supplicant.conf',
|
||||||
'RASPI_HOSTAPD_CTRL_INTERFACE' => '/var/run/hostapd',
|
'RASPI_HOSTAPD_CTRL_INTERFACE' => '/var/run/hostapd',
|
||||||
'RASPI_WPA_CTRL_INTERFACE' => '/var/run/wpa_supplicant',
|
'RASPI_WPA_CTRL_INTERFACE' => '/var/run/wpa_supplicant',
|
||||||
'RASPI_OPENVPN_CLIENT_PATH' => '/etc/openvpn/client/',
|
|
||||||
'RASPI_OPENVPN_CLIENT_CONFIG' => '/etc/openvpn/client/client.conf',
|
'RASPI_OPENVPN_CLIENT_CONFIG' => '/etc/openvpn/client/client.conf',
|
||||||
'RASPI_OPENVPN_CLIENT_LOGIN' => '/etc/openvpn/client/login.conf',
|
'RASPI_OPENVPN_CLIENT_LOGIN' => '/etc/openvpn/client/login.conf',
|
||||||
'RASPI_WIREGUARD_PATH' => '/etc/wireguard/',
|
'RASPI_OPENVPN_SERVER_CONFIG' => '/etc/openvpn/server/server.conf',
|
||||||
'RASPI_WIREGUARD_CONFIG' => RASPI_WIREGUARD_PATH.'wg0.conf',
|
|
||||||
'RASPI_TORPROXY_CONFIG' => '/etc/tor/torrc',
|
'RASPI_TORPROXY_CONFIG' => '/etc/tor/torrc',
|
||||||
'RASPI_LIGHTTPD_CONFIG' => '/etc/lighttpd/lighttpd.conf',
|
'RASPI_LIGHTTPD_CONFIG' => '/etc/lighttpd/lighttpd.conf',
|
||||||
'RASPI_ACCESS_CHECK_IP' => '1.1.1.1',
|
'RASPI_ACCESS_CHECK_IP' => '1.1.1.1',
|
||||||
@ -45,7 +42,6 @@ $defaults = [
|
|||||||
'RASPI_DHCP_ENABLED' => true,
|
'RASPI_DHCP_ENABLED' => true,
|
||||||
'RASPI_ADBLOCK_ENABLED' => false,
|
'RASPI_ADBLOCK_ENABLED' => false,
|
||||||
'RASPI_OPENVPN_ENABLED' => false,
|
'RASPI_OPENVPN_ENABLED' => false,
|
||||||
'RASPI_WIREGUARD_ENABLED' => false,
|
|
||||||
'RASPI_TORPROXY_ENABLED' => false,
|
'RASPI_TORPROXY_ENABLED' => false,
|
||||||
'RASPI_CONFAUTH_ENABLED' => true,
|
'RASPI_CONFAUTH_ENABLED' => true,
|
||||||
'RASPI_CHANGETHEME_ENABLED' => true,
|
'RASPI_CHANGETHEME_ENABLED' => true,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'includes/status_messages.php';
|
||||||
require_once 'config.php';
|
require_once 'config.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7,12 +8,94 @@ require_once 'config.php';
|
|||||||
*/
|
*/
|
||||||
function DisplayDHCPConfig()
|
function DisplayDHCPConfig()
|
||||||
{
|
{
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
|
||||||
|
$status = new StatusMessages();
|
||||||
if (!RASPI_MONITOR_ENABLED) {
|
if (!RASPI_MONITOR_ENABLED) {
|
||||||
if (isset($_POST['savedhcpdsettings'])) {
|
if (isset($_POST['savedhcpdsettings'])) {
|
||||||
saveDHCPConfig($status);
|
$errors = '';
|
||||||
|
define('IFNAMSIZ', 16);
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9]+$/', $_POST['interface'])
|
||||||
|
|| strlen($_POST['interface']) >= IFNAMSIZ
|
||||||
|
) {
|
||||||
|
$errors .= _('Invalid interface name.').'<br />'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $_POST['RangeStart'])
|
||||||
|
&& !empty($_POST['RangeStart'])
|
||||||
|
) { // allow ''/null ?
|
||||||
|
$errors .= _('Invalid DHCP range start.').'<br />'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $_POST['RangeEnd'])
|
||||||
|
&& !empty($_POST['RangeEnd'])
|
||||||
|
) { // allow ''/null ?
|
||||||
|
$errors .= _('Invalid DHCP range end.').'<br />'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctype_digit($_POST['RangeLeaseTime']) && $_POST['RangeLeaseTimeUnits'] !== 'infinite') {
|
||||||
|
$errors .= _('Invalid DHCP lease time, not a number.').'<br />'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array($_POST['RangeLeaseTimeUnits'], array('m', 'h', 'd', 'infinite'))) {
|
||||||
|
$errors .= _('Unknown DHCP lease time unit.').'<br />'.PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$return = 1;
|
||||||
|
if (empty($errors)) {
|
||||||
|
$config = 'interface='.$_POST['interface'].PHP_EOL.
|
||||||
|
'dhcp-range='.$_POST['RangeStart'].','.$_POST['RangeEnd'].
|
||||||
|
',255.255.255.0,';
|
||||||
|
if ($_POST['RangeLeaseTimeUnits'] !== 'infinite') {
|
||||||
|
$config .= $_POST['RangeLeaseTime'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$config .= $_POST['RangeLeaseTimeUnits'].PHP_EOL;
|
||||||
|
|
||||||
|
for ($i=0; $i < count($_POST["static_leases"]["mac"]); $i++) {
|
||||||
|
$mac = trim($_POST["static_leases"]["mac"][$i]);
|
||||||
|
$ip = trim($_POST["static_leases"]["ip"][$i]);
|
||||||
|
if ($mac != "" && $ip != "") {
|
||||||
|
$config .= "dhcp-host=$mac,$ip".PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_POST['no-resolv'] == "1") {
|
||||||
|
$config .= "no-resolv".PHP_EOL;
|
||||||
|
}
|
||||||
|
foreach ($_POST['server'] as $server) {
|
||||||
|
$config .= "server=$server".PHP_EOL;
|
||||||
|
}
|
||||||
|
if ($_POST['log-dhcp'] == "1") {
|
||||||
|
$config .= "log-dhcp".PHP_EOL;
|
||||||
|
}
|
||||||
|
if ($_POST['log-queries'] == "1") {
|
||||||
|
$config .= "log-queries".PHP_EOL;
|
||||||
|
}
|
||||||
|
if ($_POST['DNS1']) {
|
||||||
|
$config .= "dhcp-option=6," . $_POST['DNS1'];
|
||||||
|
if ($_POST['DNS2']) {
|
||||||
|
$config .= ','.$_POST['DNS2'];
|
||||||
|
}
|
||||||
|
$config .= PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
$config .= "log-facility=/tmp/dnsmasq.log".PHP_EOL;
|
||||||
|
$config .= "conf-dir=/etc/dnsmasq.d".PHP_EOL;
|
||||||
|
|
||||||
|
file_put_contents("/tmp/dnsmasqdata", $config);
|
||||||
|
system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_CONFIG, $return);
|
||||||
|
} else {
|
||||||
|
$status->addMessage($errors, 'danger');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($return == 0) {
|
||||||
|
$status->addMessage('Dnsmasq configuration updated successfully', 'success');
|
||||||
|
} else {
|
||||||
|
$status->addMessage('Dnsmasq configuration failed to be updated.', 'danger');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exec('pidof dnsmasq | wc -l', $dnsmasq);
|
exec('pidof dnsmasq | wc -l', $dnsmasq);
|
||||||
$dnsmasq_state = ($dnsmasq[0] > 0);
|
$dnsmasq_state = ($dnsmasq[0] > 0);
|
||||||
|
|
||||||
@ -43,15 +126,57 @@ function DisplayDHCPConfig()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getWifiInterface();
|
|
||||||
$ap_iface = $_SESSION['ap_interface'];
|
|
||||||
$serviceStatus = $dnsmasq_state ? "up" : "down";
|
$serviceStatus = $dnsmasq_state ? "up" : "down";
|
||||||
exec('cat '. RASPI_DNSMASQ_PREFIX.'raspap.conf', $return);
|
|
||||||
|
exec('cat '. RASPI_DNSMASQ_CONFIG, $return);
|
||||||
$conf = ParseConfig($return);
|
$conf = ParseConfig($return);
|
||||||
exec('cat '. RASPI_DNSMASQ_PREFIX.$ap_iface.'.conf', $return);
|
$arrRange = explode(",", $conf['dhcp-range']);
|
||||||
$conf = array_merge(ParseConfig($return));
|
$RangeStart = $arrRange[0];
|
||||||
$hosts = (array)$conf['dhcp-host'];
|
$RangeEnd = $arrRange[1];
|
||||||
$upstreamServers = (array)$conf['server'];
|
$RangeMask = $arrRange[2];
|
||||||
|
$leaseTime = $arrRange[3];
|
||||||
|
$dhcpHost = $conf["dhcp-host"];
|
||||||
|
$dhcpHost = empty($dhcpHost) ? [] : $dhcpHost;
|
||||||
|
$dhcpHost = is_array($dhcpHost) ? $dhcpHost : [ $dhcpHost ];
|
||||||
|
$upstreamServers = is_array($conf['server']) ? $conf['server'] : [ $conf['server'] ];
|
||||||
|
$upstreamServers = array_filter($upstreamServers);
|
||||||
|
|
||||||
|
$DNS1 = '';
|
||||||
|
$DNS2 = '';
|
||||||
|
if (isset($conf['dhcp-option'])) {
|
||||||
|
$arrDns = explode(",", $conf['dhcp-option']);
|
||||||
|
if ($arrDns[0] == '6') {
|
||||||
|
if (count($arrDns) > 1) {
|
||||||
|
$DNS1 = $arrDns[1];
|
||||||
|
}
|
||||||
|
if (count($arrDns) > 2) {
|
||||||
|
$DNS2 = $arrDns[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$hselected = '';
|
||||||
|
$mselected = '';
|
||||||
|
$dselected = '';
|
||||||
|
$infiniteselected = '';
|
||||||
|
preg_match('/([0-9]*)([a-z])/i', $leaseTime, $arrRangeLeaseTime);
|
||||||
|
if ($leaseTime === 'infinite') {
|
||||||
|
$infiniteselected = ' selected="selected"';
|
||||||
|
} else {
|
||||||
|
switch ($arrRangeLeaseTime[2]) {
|
||||||
|
case 'h':
|
||||||
|
$hselected = ' selected="selected"';
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
$mselected = ' selected="selected"';
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
$dselected = ' selected="selected"';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
|
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
|
||||||
exec('cat ' . RASPI_DNSMASQ_LEASES, $leases);
|
exec('cat ' . RASPI_DNSMASQ_LEASES, $leases);
|
||||||
|
|
||||||
@ -59,236 +184,21 @@ function DisplayDHCPConfig()
|
|||||||
"dhcp", compact(
|
"dhcp", compact(
|
||||||
"status",
|
"status",
|
||||||
"serviceStatus",
|
"serviceStatus",
|
||||||
"dnsmasq_state",
|
"RangeStart",
|
||||||
"ap_iface",
|
"RangeEnd",
|
||||||
"conf",
|
"DNS1",
|
||||||
"hosts",
|
"DNS2",
|
||||||
"upstreamServers",
|
"upstreamServers",
|
||||||
|
"arrRangeLeaseTime",
|
||||||
|
"mselected",
|
||||||
|
"hselected",
|
||||||
|
"dselected",
|
||||||
|
"infiniteselected",
|
||||||
|
"dnsmasq_state",
|
||||||
|
"conf",
|
||||||
|
"dhcpHost",
|
||||||
"interfaces",
|
"interfaces",
|
||||||
"leases"
|
"leases"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves a DHCP configuration
|
|
||||||
*
|
|
||||||
* @return object $status
|
|
||||||
*/
|
|
||||||
function saveDHCPConfig($status)
|
|
||||||
{
|
|
||||||
$iface = $_POST['interface'];
|
|
||||||
$return = 1;
|
|
||||||
|
|
||||||
// handle disable dhcp option
|
|
||||||
if (!isset($_POST['dhcp-iface']) && file_exists(RASPI_DNSMASQ_PREFIX.$iface.'.conf')) {
|
|
||||||
// remove dhcp + dnsmasq configs for selected interface
|
|
||||||
$return = removeDHCPConfig($iface,$status);
|
|
||||||
$return = removeDnsmasqConfig($iface,$status);
|
|
||||||
} else {
|
|
||||||
$errors = validateDHCPInput();
|
|
||||||
if (empty($errors)) {
|
|
||||||
$return = updateDHCPConfig($iface,$status);
|
|
||||||
} else {
|
|
||||||
$status->addMessage($errors, 'danger');
|
|
||||||
}
|
|
||||||
if ($return == 1) {
|
|
||||||
$status->addMessage('Dnsmasq configuration failed to be updated.', 'danger');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (($_POST['dhcp-iface'] == "1")) {
|
|
||||||
$return = updateDnsmasqConfig($iface,$status);
|
|
||||||
}
|
|
||||||
if ($return == 0) {
|
|
||||||
$status->addMessage('Dnsmasq configuration updated successfully.', 'success');
|
|
||||||
} else {
|
|
||||||
$status->addMessage('Dnsmasq configuration failed to be updated.', 'danger');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates DHCP user input from the $_POST object
|
|
||||||
*
|
|
||||||
* @return string $errors
|
|
||||||
*/
|
|
||||||
function validateDHCPInput()
|
|
||||||
{
|
|
||||||
define('IFNAMSIZ', 16);
|
|
||||||
$iface = $_POST['interface'];
|
|
||||||
if (!preg_match('/^[^\s\/\\0]+$/', $iface)
|
|
||||||
|| strlen($iface) >= IFNAMSIZ
|
|
||||||
) {
|
|
||||||
$errors .= _('Invalid interface name.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!filter_var($_POST['StaticIP'], FILTER_VALIDATE_IP) && !empty($_POST['StaticIP'])) {
|
|
||||||
$errors .= _('Invalid static IP address.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!filter_var($_POST['SubnetMask'], FILTER_VALIDATE_IP) && !empty($_POST['SubnetMask'])) {
|
|
||||||
$errors .= _('Invalid subnet mask.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!filter_var($_POST['DefaultGateway'], FILTER_VALIDATE_IP) && !empty($_POST['DefaultGateway'])) {
|
|
||||||
$errors .= _('Invalid default gateway.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (($_POST['dhcp-iface'] == "1")) {
|
|
||||||
if (!filter_var($_POST['RangeStart'], FILTER_VALIDATE_IP) && !empty($_POST['RangeStart'])) {
|
|
||||||
$errors .= _('Invalid DHCP range start.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!filter_var($_POST['RangeEnd'], FILTER_VALIDATE_IP) && !empty($_POST['RangeEnd'])) {
|
|
||||||
$errors .= _('Invalid DHCP range end.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!ctype_digit($_POST['RangeLeaseTime']) && $_POST['RangeLeaseTimeUnits'] !== 'i') {
|
|
||||||
$errors .= _('Invalid DHCP lease time, not a number.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if (!in_array($_POST['RangeLeaseTimeUnits'], array('m', 'h', 'd', 'i'))) {
|
|
||||||
$errors .= _('Unknown DHCP lease time unit.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if ($_POST['Metric'] !== '' && !ctype_digit($_POST['Metric'])) {
|
|
||||||
$errors .= _('Invalid metric value, not a number.').'<br />'.PHP_EOL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares to string IPs
|
|
||||||
*
|
|
||||||
* @param string $ip1
|
|
||||||
* @param string $ip2
|
|
||||||
* @return boolean $result
|
|
||||||
*/
|
|
||||||
function compareIPs($ip1, $ip2)
|
|
||||||
{
|
|
||||||
$ipu1 = sprintf('%u', ip2long($ip1["ip"])) + 0;
|
|
||||||
$ipu2 = sprintf('%u', ip2long($ip2["ip"])) + 0;
|
|
||||||
return $ipu1 > $ipu2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a dnsmasq configuration
|
|
||||||
*
|
|
||||||
* @param string $iface
|
|
||||||
* @param object $status
|
|
||||||
* @return boolean $result
|
|
||||||
*/
|
|
||||||
function updateDnsmasqConfig($iface,$status)
|
|
||||||
{
|
|
||||||
$config = '# RaspAP '.$iface.' configuration'.PHP_EOL;
|
|
||||||
$config .= 'interface='.$iface.PHP_EOL.'dhcp-range='.$_POST['RangeStart'].','.$_POST['RangeEnd'].','.$_POST['SubnetMask'].',';
|
|
||||||
if ($_POST['RangeLeaseTimeUnits'] !== 'i') {
|
|
||||||
$config .= $_POST['RangeLeaseTime'];
|
|
||||||
$config .= $_POST['RangeLeaseTimeUnits'].PHP_EOL;
|
|
||||||
} else {
|
|
||||||
$config .= 'infinite'.PHP_EOL;
|
|
||||||
}
|
|
||||||
// Static leases
|
|
||||||
$staticLeases = array();
|
|
||||||
if (isset($_POST["static_leases"]["mac"])) {
|
|
||||||
for ($i=0; $i < count($_POST["static_leases"]["mac"]); $i++) {
|
|
||||||
$mac = trim($_POST["static_leases"]["mac"][$i]);
|
|
||||||
$ip = trim($_POST["static_leases"]["ip"][$i]);
|
|
||||||
$comment = trim($_POST["static_leases"]["comment"][$i]);
|
|
||||||
if ($mac != "" && $ip != "") {
|
|
||||||
$staticLeases[] = array('mac' => $mac, 'ip' => $ip, 'comment' => $comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sort ascending by IPs
|
|
||||||
usort($staticLeases, "compareIPs");
|
|
||||||
// Update config
|
|
||||||
for ($i = 0; $i < count($staticLeases); $i++) {
|
|
||||||
$mac = $staticLeases[$i]['mac'];
|
|
||||||
$ip = $staticLeases[$i]['ip'];
|
|
||||||
$comment = $staticLeases[$i]['comment'];
|
|
||||||
$config .= "dhcp-host=$mac,$ip # $comment".PHP_EOL;
|
|
||||||
}
|
|
||||||
if ($_POST['no-resolv'] == "1") {
|
|
||||||
$config .= "no-resolv".PHP_EOL;
|
|
||||||
}
|
|
||||||
foreach ($_POST['server'] as $server) {
|
|
||||||
$config .= "server=$server".PHP_EOL;
|
|
||||||
}
|
|
||||||
if ($_POST['DNS1']) {
|
|
||||||
$config .= "dhcp-option=6," . $_POST['DNS1'];
|
|
||||||
if ($_POST['DNS2']) {
|
|
||||||
$config .= ','.$_POST['DNS2'];
|
|
||||||
}
|
|
||||||
$config .= PHP_EOL;
|
|
||||||
}
|
|
||||||
file_put_contents("/tmp/dnsmasqdata", $config);
|
|
||||||
$msg = file_exists(RASPI_DNSMASQ_PREFIX.$iface.'.conf') ? 'updated' : 'added';
|
|
||||||
system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_PREFIX.$iface.'.conf', $result);
|
|
||||||
if ($result == 0) {
|
|
||||||
$status->addMessage('Dnsmasq configuration for '.$iface.' '.$msg.'.', 'success');
|
|
||||||
}
|
|
||||||
|
|
||||||
// write default 090_raspap.conf
|
|
||||||
$config = '# RaspAP default config'.PHP_EOL;
|
|
||||||
$config .='log-facility='.RASPI_DHCPCD_LOG.PHP_EOL;
|
|
||||||
$config .='conf-dir=/etc/dnsmasq.d'.PHP_EOL;
|
|
||||||
// handle log option
|
|
||||||
if ($_POST['log-dhcp'] == "1") {
|
|
||||||
$config .= "log-dhcp".PHP_EOL;
|
|
||||||
}
|
|
||||||
if ($_POST['log-queries'] == "1") {
|
|
||||||
$config .= "log-queries".PHP_EOL;
|
|
||||||
}
|
|
||||||
$config .= PHP_EOL;
|
|
||||||
file_put_contents("/tmp/dnsmasqdata", $config);
|
|
||||||
system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_PREFIX.'raspap.conf', $result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a dhcp configuration
|
|
||||||
*
|
|
||||||
* @param string $iface
|
|
||||||
* @param object $status
|
|
||||||
* @return boolean $result
|
|
||||||
*/
|
|
||||||
function updateDHCPConfig($iface,$status)
|
|
||||||
{
|
|
||||||
$cfg[] = '# RaspAP '.$iface.' configuration';
|
|
||||||
$cfg[] = 'interface '.$iface;
|
|
||||||
if (isset($_POST['StaticIP']) && $_POST['StaticIP'] !== '') {
|
|
||||||
$mask = ($_POST['SubnetMask'] !== '' && $_POST['SubnetMask'] !== '0.0.0.0') ? '/'.mask2cidr($_POST['SubnetMask']) : null;
|
|
||||||
$cfg[] = 'static ip_address='.$_POST['StaticIP'].$mask;
|
|
||||||
}
|
|
||||||
if (isset($_POST['DefaultGateway']) && $_POST['DefaultGateway'] !== '') {
|
|
||||||
$cfg[] = 'static routers='.$_POST['DefaultGateway'];
|
|
||||||
}
|
|
||||||
if ($_POST['DNS1'] !== '' || $_POST['DNS2'] !== '') {
|
|
||||||
$cfg[] = 'static domain_name_server='.$_POST['DNS1'].' '.$_POST['DNS2'];
|
|
||||||
}
|
|
||||||
if ($_POST['Metric'] !== '') {
|
|
||||||
$cfg[] = 'metric '.$_POST['Metric'];
|
|
||||||
}
|
|
||||||
if ($_POST['Fallback'] == 1) {
|
|
||||||
$cfg[] = 'profile static_'.$iface;
|
|
||||||
$cfg[] = 'fallback static_'.$iface;
|
|
||||||
}
|
|
||||||
$cfg[] = $_POST['DefaultRoute'] == '1' ? 'gateway' : 'nogateway';
|
|
||||||
if (( substr($iface, 0, 2) === "wl") && $_POST['NoHookWPASupplicant'] == '1') {
|
|
||||||
$cfg[] = 'nohook wpa_supplicant';
|
|
||||||
}
|
|
||||||
$dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
|
|
||||||
if (!preg_match('/^interface\s'.$iface.'$/m', $dhcp_cfg)) {
|
|
||||||
$cfg[] = PHP_EOL;
|
|
||||||
$cfg = join(PHP_EOL, $cfg);
|
|
||||||
$dhcp_cfg .= $cfg;
|
|
||||||
$status->addMessage('DHCP configuration for '.$iface.' added.', 'success');
|
|
||||||
} else {
|
|
||||||
$cfg = join(PHP_EOL, $cfg);
|
|
||||||
$dhcp_cfg = preg_replace('/^#\sRaspAP\s'.$iface.'\s.*?(?=\s*^\s*$)/ms', $cfg, $dhcp_cfg, 1);
|
|
||||||
$status->addMessage('DHCP configuration for '.$iface.' updated.', 'success');
|
|
||||||
}
|
|
||||||
file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
|
|
||||||
system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,42 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/* Functions for Networking */
|
/* Functions for Networking */
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a human readable data size string from a number of bytes.
|
|
||||||
*
|
|
||||||
* @param long $numbytes The number of bytes.
|
|
||||||
* @param int $precision The number of numbers to round to after the dot/comma.
|
|
||||||
* @return string Data size in units: PB, TB, GB, MB or KB otherwise an empty string.
|
|
||||||
*/
|
|
||||||
function getHumanReadableDatasize($numbytes, $precision = 2)
|
|
||||||
{
|
|
||||||
$humanDatasize = '';
|
|
||||||
$kib = 1024;
|
|
||||||
$mib = $kib * 1024;
|
|
||||||
$gib = $mib * 1024;
|
|
||||||
$tib = $gib * 1024;
|
|
||||||
$pib = $tib * 1024;
|
|
||||||
if ($numbytes >= $pib) {
|
|
||||||
$humanDatasize = ' ('.round($numbytes / $pib, $precision).' PB)';
|
|
||||||
} elseif ($numbytes >= $tib) {
|
|
||||||
$humanDatasize = ' ('.round($numbytes / $tib, $precision).' TB)';
|
|
||||||
} elseif ($numbytes >= $gib) {
|
|
||||||
$humanDatasize = ' ('.round($numbytes / $gib, $precision).' GB)';
|
|
||||||
} elseif ($numbytes >= $mib) {
|
|
||||||
$humanDatasize = ' ('.round($numbytes / $mib, $precision).' MB)';
|
|
||||||
} elseif ($numbytes >= $kib) {
|
|
||||||
$humanDatasize = ' ('.round($numbytes / $kib, $precision).' KB)';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $humanDatasize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a netmask to CIDR notation string
|
|
||||||
*
|
|
||||||
* @param string $mask
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function mask2cidr($mask)
|
function mask2cidr($mask)
|
||||||
{
|
{
|
||||||
$long = ip2long($mask);
|
$long = ip2long($mask);
|
||||||
@ -44,140 +8,8 @@ function mask2cidr($mask)
|
|||||||
return 32-log(($long ^ $base)+1, 2);
|
return 32-log(($long ^ $base)+1, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a CIDR notation string to a netmask
|
|
||||||
*
|
|
||||||
* @param string $cidr
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function cidr2mask($cidr)
|
|
||||||
{
|
|
||||||
$ipParts = explode('/', $cidr);
|
|
||||||
$ip = $ipParts[0];
|
|
||||||
$prefixLength = $ipParts[1];
|
|
||||||
|
|
||||||
$ipLong = ip2long($ip);
|
|
||||||
$netmaskLong = bindec(str_pad(str_repeat('1', $prefixLength), 32, '0'));
|
|
||||||
$netmask = long2ip(intval($netmaskLong));
|
|
||||||
|
|
||||||
return $netmask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a dhcp configuration block for the specified interface
|
|
||||||
*
|
|
||||||
* @param string $iface
|
|
||||||
* @param object $status
|
|
||||||
* @return boolean $result
|
|
||||||
*/
|
|
||||||
function removeDHCPConfig($iface,$status)
|
|
||||||
{
|
|
||||||
$dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
|
|
||||||
$dhcp_cfg = preg_replace('/^#\sRaspAP\s'.$iface.'\s.*?(?=\s*^\s*$)([\s]+)/ms', '', $dhcp_cfg, 1);
|
|
||||||
file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
|
|
||||||
system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $result);
|
|
||||||
if ($result == 0) {
|
|
||||||
$status->addMessage('DHCP configuration for '.$iface.' removed.', 'success');
|
|
||||||
} else {
|
|
||||||
$status->addMessage('Failed to remove DHCP configuration for '.$iface.'.', 'danger');
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a dhcp configuration block for the specified interface
|
|
||||||
*
|
|
||||||
* @param string $dhcp_cfg
|
|
||||||
* @param string $iface
|
|
||||||
* @return string $dhcp_cfg
|
|
||||||
*/
|
|
||||||
function removeDHCPIface($dhcp_cfg,$iface)
|
|
||||||
{
|
|
||||||
$dhcp_cfg = preg_replace('/^#\sRaspAP\s'.$iface.'\s.*?(?=\s*^\s*$)([\s]+)/ms', '', $dhcp_cfg, 1);
|
|
||||||
return $dhcp_cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a dnsmasq configuration block for the specified interface
|
|
||||||
*
|
|
||||||
* @param string $iface
|
|
||||||
* @param object $status
|
|
||||||
* @return boolean $result
|
|
||||||
*/
|
|
||||||
function removeDnsmasqConfig($iface,$status)
|
|
||||||
{
|
|
||||||
system('sudo rm '.RASPI_DNSMASQ_PREFIX.$iface.'.conf', $result);
|
|
||||||
if ($result == 0) {
|
|
||||||
$status->addMessage('Dnsmasq configuration for '.$iface.' removed.', 'success');
|
|
||||||
} else {
|
|
||||||
$status->addMessage('Failed to remove dnsmasq configuration for '.$iface.'.', 'danger');
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scans dnsmasq configuration dir for the specified interface
|
|
||||||
* Non-matching configs are removed, optional adblock.conf is protected
|
|
||||||
*
|
|
||||||
* @param string $dir_conf
|
|
||||||
* @param string $interface
|
|
||||||
* @param object $status
|
|
||||||
*/
|
|
||||||
function scanConfigDir($dir_conf,$interface,$status)
|
|
||||||
{
|
|
||||||
$syscnf = preg_grep('~\.(conf)$~', scandir($dir_conf));
|
|
||||||
foreach ($syscnf as $cnf) {
|
|
||||||
if ($cnf !== '090_adblock.conf' && !preg_match('/.*_'.$interface.'.conf/', $cnf)) {
|
|
||||||
system('sudo rm /etc/dnsmasq.d/'.$cnf, $result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a default (fallback) value for the selected service, interface & setting
|
|
||||||
* from /etc/raspap/networking/defaults.json
|
|
||||||
*
|
|
||||||
* @param string $svc
|
|
||||||
* @param string $iface
|
|
||||||
* @return string $value
|
|
||||||
*/
|
|
||||||
function getDefaultNetValue($svc,$iface,$key)
|
|
||||||
{
|
|
||||||
$json = json_decode(file_get_contents(RASPI_CONFIG_NETWORK), true);
|
|
||||||
if ($json === null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return $json[$svc][$iface][$key][0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns default options for the specified service
|
|
||||||
*
|
|
||||||
* @param string $svc
|
|
||||||
* @param string $key
|
|
||||||
* @return object $json
|
|
||||||
*/
|
|
||||||
function getDefaultNetOpts($svc,$key)
|
|
||||||
{
|
|
||||||
$json = json_decode(file_get_contents(RASPI_CONFIG_NETWORK), true);
|
|
||||||
if ($json === null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return $json[$svc][$key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Functions to write ini files */
|
/* Functions to write ini files */
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a configuration to an .ini file
|
|
||||||
*
|
|
||||||
* @param array $array
|
|
||||||
* @param string $file
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
function write_php_ini($array, $file)
|
function write_php_ini($array, $file)
|
||||||
{
|
{
|
||||||
$res = array();
|
$res = array();
|
||||||
@ -198,13 +30,6 @@ function write_php_ini($array, $file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes to a file without conflicts
|
|
||||||
*
|
|
||||||
* @param string $fileName
|
|
||||||
* @param string $dataToSave
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
function safefilerewrite($fileName, $dataToSave)
|
function safefilerewrite($fileName, $dataToSave)
|
||||||
{
|
{
|
||||||
if ($fp = fopen($fileName, 'w')) {
|
if ($fp = fopen($fileName, 'w')) {
|
||||||
@ -229,62 +54,6 @@ function safefilerewrite($fileName, $dataToSave)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepends data to a file if not exists
|
|
||||||
*
|
|
||||||
* @param string $filename
|
|
||||||
* @param string $dataToSave
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
function file_prepend_data($filename, $dataToSave)
|
|
||||||
{
|
|
||||||
$context = stream_context_create();
|
|
||||||
$file = fopen($filename, 'r', 1, $context);
|
|
||||||
$file_data = readfile($file);
|
|
||||||
|
|
||||||
if (!preg_match('/^'.$dataToSave.'/', $file_data)) {
|
|
||||||
$tmp_file = tempnam(sys_get_temp_dir(), 'php_prepend_');
|
|
||||||
file_put_contents($tmp_file, $dataToSave);
|
|
||||||
file_put_contents($tmp_file, $file, FILE_APPEND);
|
|
||||||
fclose($file);
|
|
||||||
unlink($filename);
|
|
||||||
rename($tmp_file, $filename);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches a meta value from a file
|
|
||||||
*
|
|
||||||
* @param string $filename
|
|
||||||
* @param string $pattern
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function file_get_meta($filename, $pattern)
|
|
||||||
{
|
|
||||||
if(file_exists($filename)) {
|
|
||||||
$context = stream_context_create();
|
|
||||||
$file_data = file_get_contents($filename, false, $context);
|
|
||||||
preg_match('/^'.$pattern.'/', $file_data, $matched);
|
|
||||||
return $matched[1];
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback function for array_filter
|
|
||||||
*
|
|
||||||
* @param string $var
|
|
||||||
* @return filtered value
|
|
||||||
*/
|
|
||||||
function filter_comments($var)
|
|
||||||
{
|
|
||||||
return $var[0] != '#';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a CSRF token in the session
|
* Saves a CSRF token in the session
|
||||||
*/
|
*/
|
||||||
@ -318,23 +87,23 @@ function CSRFMetaTag()
|
|||||||
*/
|
*/
|
||||||
function CSRFValidate()
|
function CSRFValidate()
|
||||||
{
|
{
|
||||||
if(isset($_POST['csrf_token'])) {
|
$post_token = $_POST['csrf_token'];
|
||||||
$post_token = $_POST['csrf_token'];
|
$header_token = $_SERVER['HTTP_X_CSRF_TOKEN'];
|
||||||
$header_token = $_SERVER['HTTP_X_CSRF_TOKEN'];
|
|
||||||
|
|
||||||
if (empty($post_token) && empty($header_token)) {
|
if (empty($post_token) && empty($header_token)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$request_token = $post_token;
|
|
||||||
if (empty($post_token)) {
|
$request_token = $post_token;
|
||||||
$request_token = $header_token;
|
if (empty($post_token)) {
|
||||||
}
|
$request_token = $header_token;
|
||||||
if (hash_equals($_SESSION['csrf_token'], $request_token)) {
|
}
|
||||||
return true;
|
|
||||||
} else {
|
if (hash_equals($_SESSION['csrf_token'], $request_token)) {
|
||||||
error_log('CSRF violation');
|
return true;
|
||||||
return false;
|
} else {
|
||||||
}
|
error_log('CSRF violation');
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,9 +199,8 @@ function ParseConfig($arrConfig)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($line, "=") !== false) {
|
list($option, $value) = array_map("trim", explode("=", $line, 2));
|
||||||
list($option, $value) = array_map("trim", explode("=", $line, 2));
|
|
||||||
}
|
|
||||||
if (empty($config[$option])) {
|
if (empty($config[$option])) {
|
||||||
$config[$option] = $value ?: true;
|
$config[$option] = $value ?: true;
|
||||||
} else {
|
} else {
|
||||||
@ -445,19 +213,6 @@ function ParseConfig($arrConfig)
|
|||||||
return $config;
|
return $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches DHCP configuration for an interface, returned as JSON data
|
|
||||||
*
|
|
||||||
* @param string $interface
|
|
||||||
* @return json $jsonData
|
|
||||||
*/
|
|
||||||
function getNetConfig($interface)
|
|
||||||
{
|
|
||||||
$URI = $_SERVER['REQUEST_SCHEME'].'://' .'localhost'. dirname($_SERVER['SCRIPT_NAME']) .'/ajax/networking/get_netcfg.php?iface='.$interface;
|
|
||||||
$jsonData = file_get_contents($URI, true);
|
|
||||||
return $jsonData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param string $freq
|
* @param string $freq
|
||||||
@ -554,11 +309,9 @@ function readCache($key)
|
|||||||
|
|
||||||
function writeCache($key, $data)
|
function writeCache($key, $data)
|
||||||
{
|
{
|
||||||
if (!file_exists(RASPI_CACHE_PATH)) {
|
mkdir(RASPI_CACHE_PATH, 0777, true);
|
||||||
mkdir(RASPI_CACHE_PATH, 0777, true);
|
$cacheKey = expandCacheKey($key);
|
||||||
$cacheKey = expandCacheKey($key);
|
file_put_contents($cacheKey, $data);
|
||||||
file_put_contents($cacheKey, $data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteCache($key)
|
function deleteCache($key)
|
||||||
@ -586,10 +339,11 @@ function mb_escapeshellarg($arg)
|
|||||||
{
|
{
|
||||||
$isWindows = strtolower(substr(PHP_OS, 0, 3)) === 'win';
|
$isWindows = strtolower(substr(PHP_OS, 0, 3)) === 'win';
|
||||||
if ($isWindows) {
|
if ($isWindows) {
|
||||||
return '"' . str_replace(array('"', '%'), '', $arg) . '"';
|
$escaped_arg = str_replace(array('"', '%'), '', $arg);
|
||||||
} else {
|
} else {
|
||||||
return "'" . str_replace("'", "'\\''", $arg) . "'";
|
$escaped_arg = str_replace("'", "'\\''", $arg);
|
||||||
}
|
}
|
||||||
|
return "\"$escaped_arg\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
function dnsServers()
|
function dnsServers()
|
||||||
@ -664,18 +418,10 @@ function formatDateAgo($datetime, $full = false)
|
|||||||
return $string ? implode(', ', $string) . ' ago' : 'just now';
|
return $string ? implode(', ', $string) . ' ago' : 'just now';
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeApp()
|
|
||||||
{
|
|
||||||
$_SESSION["theme_url"] = getThemeOpt();
|
|
||||||
$_SESSION["toggleState"] = getSidebarState();
|
|
||||||
$_SESSION["bridgedEnabled"] = getBridgedState();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThemeOpt()
|
function getThemeOpt()
|
||||||
{
|
{
|
||||||
if (!isset($_COOKIE['theme'])) {
|
if (!isset($_COOKIE['theme'])) {
|
||||||
$theme = "custom.php";
|
$theme = "custom.php";
|
||||||
setcookie('theme', $theme);
|
|
||||||
} else {
|
} else {
|
||||||
$theme = $_COOKIE['theme'];
|
$theme = $_COOKIE['theme'];
|
||||||
}
|
}
|
||||||
@ -685,19 +431,16 @@ function getThemeOpt()
|
|||||||
function getColorOpt()
|
function getColorOpt()
|
||||||
{
|
{
|
||||||
if (!isset($_COOKIE['color'])) {
|
if (!isset($_COOKIE['color'])) {
|
||||||
$color = "#2b8080";
|
$color = "#d8224c";
|
||||||
} else {
|
} else {
|
||||||
$color = $_COOKIE['color'];
|
$color = $_COOKIE['color'];
|
||||||
setcookie('color', $color);
|
|
||||||
}
|
}
|
||||||
return $color;
|
return $color;
|
||||||
}
|
}
|
||||||
function getSidebarState()
|
function getSidebarState()
|
||||||
{
|
{
|
||||||
if(isset($_COOKIE['sidebarToggled'])) {
|
if ($_COOKIE['sidebarToggled'] == 'true' ) {
|
||||||
if ($_COOKIE['sidebarToggled'] == 'true' ) {
|
return"toggled";
|
||||||
return "toggled";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,125 +452,8 @@ function getBridgedState()
|
|||||||
return $arrHostapdConf['BridgedEnable'];
|
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
|
// Validates a host or FQDN
|
||||||
function validate_host($host)
|
function validate_host($host) {
|
||||||
{
|
|
||||||
return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host);
|
return preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $host);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets night mode toggle value
|
|
||||||
// @return boolean
|
|
||||||
function getNightmode()
|
|
||||||
{
|
|
||||||
if (isset($_COOKIE['theme']) && $_COOKIE['theme'] == 'lightsout.css') {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// search array for matching string and return only first matching group
|
|
||||||
function preg_only_match($pat,$haystack)
|
|
||||||
{
|
|
||||||
$match = "";
|
|
||||||
if(!empty($haystack) && !empty($pat)) {
|
|
||||||
if(!is_array($haystack)) $haystack = array($haystack);
|
|
||||||
$str = preg_grep($pat,$haystack);
|
|
||||||
if (!empty($str) && preg_match($pat,array_shift($str),$match) === 1 ) $match = $match[1];
|
|
||||||
}
|
|
||||||
return $match;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitizes a string for QR encoding
|
|
||||||
// @param string $str
|
|
||||||
// @return string
|
|
||||||
function qr_encode($str)
|
|
||||||
{
|
|
||||||
return preg_replace('/(?<!\\\)([\":;,])/', '\\\\\1', $str);
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalHexSequence($string)
|
|
||||||
{
|
|
||||||
$evaluator = function ($input) {
|
|
||||||
return hex2bin($input[1]);
|
|
||||||
};
|
|
||||||
return preg_replace_callback('/\\\x(..)/', $evaluator, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hexSequence2lower($string) {
|
|
||||||
return preg_replace_callback('/\\\\x([0-9A-F]{2})/', function($b){ return '\x'.strtolower($b[1]); }, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* File upload callback object
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class validation
|
|
||||||
{
|
|
||||||
public function check_name_length($object)
|
|
||||||
{
|
|
||||||
if (strlen($object->file['filename']) > 255) {
|
|
||||||
$object->set_error('File name is too long.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resolves public IP address
|
|
||||||
*
|
|
||||||
* @return string $public_ip
|
|
||||||
*/
|
|
||||||
function get_public_ip()
|
|
||||||
{
|
|
||||||
exec('wget --timeout=5 --tries=1 https://ipinfo.io/ip -qO -', $public_ip);
|
|
||||||
return $public_ip[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns a standardized tooltip
|
|
||||||
*
|
|
||||||
* @return string $tooltip
|
|
||||||
*/
|
|
||||||
function getTooltip($msg, $id, $visible = true, $data_html = false)
|
|
||||||
{
|
|
||||||
($visible) ? $opt1 = 'visible' : $opt1 = 'invisible';
|
|
||||||
($data_html) ? $opt2 = 'data-html="true"' : $opt2 = 'data-html="false"';
|
|
||||||
echo '<i class="fas fa-question-circle text-muted ' .$opt1.'" id="' .$id. '" data-toggle="tooltip" ' .$opt2. ' data-placement="auto" title="' . _($msg). '"></i>';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load non default JS/ECMAScript in footer
|
|
||||||
function loadFooterScripts($extraFooterScripts)
|
|
||||||
{
|
|
||||||
foreach ($extraFooterScripts as $script) {
|
|
||||||
echo '<script type="text/javascript" src="' , $script['src'] , '"';
|
|
||||||
if ($script['defer']) {
|
|
||||||
echo ' defer="defer"';
|
|
||||||
}
|
|
||||||
echo '></script>' , PHP_EOL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,307 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require_once 'includes/functions.php';
|
|
||||||
require_once 'includes/wifi_functions.php';
|
|
||||||
|
|
||||||
function getClients($simple=true)
|
|
||||||
{
|
|
||||||
exec('ifconfig -a | grep -oP "^(?!lo)(\w*)"', $rawdevs); // all devices except loopback
|
|
||||||
$path=RASPI_CLIENT_SCRIPT_PATH;
|
|
||||||
$cl=array();
|
|
||||||
if (!empty($rawdevs) && is_array($rawdevs)) {
|
|
||||||
$cl["clients"]=count($rawdevs);
|
|
||||||
// search for possibly not connected modem
|
|
||||||
exec("find /sys/bus/usb/devices/usb*/ -name dev ", $devtty); // search for ttyUSB
|
|
||||||
$devtty = preg_only_match("/(ttyUSB0)/", $devtty);
|
|
||||||
if (empty(preg_only_match("/(ppp)[0-9]/", $rawdevs))) {
|
|
||||||
if (!empty($devtty)) {
|
|
||||||
$rawdevs[]="ppp0";
|
|
||||||
exec("udevadm info --name='$devtty' 2> /dev/null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach ($rawdevs as $i => $dev) {
|
|
||||||
$cl["device"][$i]["name"]=$dev;
|
|
||||||
$nam = (preg_match("/^(\w+)[0-9]$/",$dev,$nam) === 1) ? $nam=$nam[1] : "";
|
|
||||||
$cl["device"][$i]["type"]=$ty=getClientType($dev);
|
|
||||||
unset($udevinfo);
|
|
||||||
exec("udevadm info /sys/class/net/$dev 2> /dev/null", $udevinfo);
|
|
||||||
if ($nam == "ppp" && isset($devtty)) {
|
|
||||||
exec("udevadm info --name='$devtty' 2> /dev/null", $udevinfo);
|
|
||||||
}
|
|
||||||
if (!empty($udevinfo) && is_array($udevinfo)) {
|
|
||||||
$model = preg_only_match("/ID_MODEL_ENC=(.*)$/", $udevinfo);
|
|
||||||
if (empty($model) || preg_match("/^[0-9a-f]{4}$/", $model) === 1) {
|
|
||||||
$model = preg_only_match("/ID_MODEL_FROM_DATABASE=(.*)$/", $udevinfo);
|
|
||||||
}
|
|
||||||
if (empty($model)) {
|
|
||||||
$model = preg_only_match("/ID_OUI_FROM_DATABASE=(.*)$/", $udevinfo);
|
|
||||||
}
|
|
||||||
$vendor = preg_only_match("/ID_VENDOR_ENC=(.*)$/", $udevinfo);
|
|
||||||
if (empty($vendor) || preg_match("/^[0-9a-f]{4}$/", $vendor) === 1) {
|
|
||||||
$vendor = preg_only_match("/ID_VENDOR_FROM_DATABASE=(.*)$/", $udevinfo);
|
|
||||||
}
|
|
||||||
$driver = preg_only_match("/ID_NET_DRIVER=(.*)$/", $udevinfo);
|
|
||||||
$vendorid = preg_only_match("/ID_VENDOR_ID=(.*)$/", $udevinfo);
|
|
||||||
$productid = preg_only_match("/ID_MODEL_ID=(.*)$/", $udevinfo);
|
|
||||||
}
|
|
||||||
$cl["device"][$i]["model"] = preg_replace("/\\\\x20/", " ", $model);
|
|
||||||
$cl["device"][$i]["vendor"] = preg_replace("/\\\\x20/", " ", $vendor);
|
|
||||||
$cl["device"][$i]["vid"] = $vendorid;
|
|
||||||
$cl["device"][$i]["pid"] = $productid;
|
|
||||||
unset($mac);
|
|
||||||
exec("cat /sys/class/net/$dev/address 2> /dev/null", $mac);
|
|
||||||
$cl["device"][$i]["mac"] = empty($mac) ? "":$mac[0];
|
|
||||||
unset($ip);
|
|
||||||
exec("ifconfig $dev 2> /dev/null", $ip);
|
|
||||||
$cl["device"][$i]["ipaddress"] = preg_only_match("/.*inet ([0-9\.]+) .*/", $ip);
|
|
||||||
|
|
||||||
switch($ty) {
|
|
||||||
case "eth":
|
|
||||||
unset($res);
|
|
||||||
exec("ip link show $dev 2> /dev/null | grep -oP ' UP '", $res);
|
|
||||||
if (empty($res) && empty($ipadd)) {
|
|
||||||
$cl["device"][$i]["connected"] = "n";
|
|
||||||
} else {
|
|
||||||
$cl["device"][$i]["connected"] = "y";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "wlan":
|
|
||||||
unset($retiw);
|
|
||||||
exec("iwconfig $dev 2> /dev/null | sed -rn 's/.*(mode:master).*/1/ip'", $retiw);
|
|
||||||
$cl["device"][$i]["isAP"] = !empty($retiw);
|
|
||||||
unset($retiw);
|
|
||||||
exec("iw dev $dev link 2> /dev/null", $retiw);
|
|
||||||
if (!$simple && !empty($ssid=preg_only_match("/.*SSID:\s*([^\"]*).*/", $retiw)) ) {
|
|
||||||
$cl["device"][$i]["connected"] = "y";
|
|
||||||
$cl["device"][$i]["ssid"] = $ssid;
|
|
||||||
$cl["device"][$i]["ssidutf8"] = ssid2utf8($ssid);
|
|
||||||
$cl["device"][$i]["ap-mac"] = preg_only_match("/^Connected to ([0-9a-f\:]*).*$/", $retiw);
|
|
||||||
$sig = preg_only_match("/.*signal: (.*)$/", $retiw);
|
|
||||||
$val = preg_only_match("/^([0-9\.-]*).*$/", $sig);
|
|
||||||
if (!is_numeric($val)) {
|
|
||||||
$val = -100;
|
|
||||||
}
|
|
||||||
if ($val >= -50 ) {
|
|
||||||
$qual=100;
|
|
||||||
} else if ($val < -100) {
|
|
||||||
$qual=0;
|
|
||||||
} else {
|
|
||||||
$qual=round($val*2+200);
|
|
||||||
}
|
|
||||||
$cl["device"][$i]["signal"] = "$sig (".$qual."%)";
|
|
||||||
$cl["device"][$i]["bitrate"] = preg_only_match("/.*bitrate: ([0-9\.]* \w*\/s).*$/", $retiw);
|
|
||||||
$cl["device"][$i]["freq"] = preg_only_match("/.*freq: (.*)$/", $retiw);
|
|
||||||
$cl["device"][$i]["ap-mac"] = preg_only_match("/^Connected to ([0-9a-f\:]*).*$/", $retiw);
|
|
||||||
} else {
|
|
||||||
$cl["device"][$i]["connected"] = "n";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ppp":
|
|
||||||
unset($res);
|
|
||||||
exec("ip link show $dev 2> /dev/null | grep -oP '( UP | UNKNOWN)'", $res);
|
|
||||||
if ($simple) {
|
|
||||||
if (empty($res)) {
|
|
||||||
$cl["device"][$i]["connected"] = "n";
|
|
||||||
$cl["device"][$i]["signal"] = "-100 dB (0%)";
|
|
||||||
} else {
|
|
||||||
$cl["device"][$i]["connected"] = "y";
|
|
||||||
$cl["device"][$i]["signal"] = "-0 dB (0%)";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (empty($res) && empty($ipadd)) {
|
|
||||||
$cl["device"][$i]["connected"] = "n";
|
|
||||||
} else {
|
|
||||||
$cl["device"][$i]["connected"] = "y";
|
|
||||||
}
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh mode modem", $res);
|
|
||||||
$cl["device"][$i]["mode"] = $res[0];
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh device modem", $res);
|
|
||||||
if ($res[0] != "none" ) {
|
|
||||||
$cl["device"][$i]["model"] = $res[0];
|
|
||||||
}
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh signal modem", $res);
|
|
||||||
$cl["device"][$i]["signal"] = $res[0];
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh operator modem", $res);
|
|
||||||
$cl["device"][$i]["operator"] = $res[0];
|
|
||||||
break;
|
|
||||||
case "hilink":
|
|
||||||
$pin=$user=$pw="";
|
|
||||||
getMobileLogin($pin,$pw,$user);
|
|
||||||
$opts=$pin.' '.$user.' '.$pw;
|
|
||||||
unset($res);
|
|
||||||
// exec("ip link show $dev 2> /dev/null | grep -oP ' UP '",$res);
|
|
||||||
exec("ifconfig -a | grep -i $dev -A 1 | grep -oP '(?<=inet )([0-9]{1,3}\.){3}'", $apiadd);
|
|
||||||
$apiadd = !empty($apiadd) ? $apiadd[0]."1" : "";
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh mode hilink $apiadd \"$opts\" ", $res);
|
|
||||||
$cl["device"][$i]["mode"] = $res[0];
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh device hilink $apiadd \"$opts\" ", $res);
|
|
||||||
if ($res[0] != "none" ) {
|
|
||||||
$cl["device"][$i]["model"] = $res[0];
|
|
||||||
}
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh signal hilink $apiadd \"$opts\" ", $res);
|
|
||||||
$cl["device"][$i]["signal"] = $res[0];
|
|
||||||
unset($ipadd);
|
|
||||||
exec("$path/info_huawei.sh ipaddress hilink $apiadd \"$opts\" ", $ipadd);
|
|
||||||
if (!empty($ipadd) && $ipadd[0] !== "none" ) {
|
|
||||||
$cl["device"][$i]["connected"] = "y";
|
|
||||||
$cl["device"][$i]["wan_ip"] = $ipadd[0];
|
|
||||||
} else {
|
|
||||||
$cl["device"][$i]["connected"] = "n";
|
|
||||||
$cl["device"][$i]["wan_ip"] = "-";
|
|
||||||
}
|
|
||||||
unset($res);
|
|
||||||
exec("$path/info_huawei.sh operator hilink $apiadd \"$opts\" ", $res);
|
|
||||||
$cl["device"][$i]["operator"] = $res[0];
|
|
||||||
break;
|
|
||||||
case "phone":
|
|
||||||
case "usb":
|
|
||||||
$cl["device"][$i]["connected"] = "y";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
if (!isset($cl["device"][$i]["signal"])) {
|
|
||||||
$cl["device"][$i]["signal"]= $cl["device"][$i]["connected"] == "n" ? "-100 dB (0%)": "0 dB (100%)";;
|
|
||||||
}
|
|
||||||
if (!isset($cl["device"][$i]["isAP"])) {
|
|
||||||
$cl["device"][$i]["isAP"]=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $cl;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClientType($dev) {
|
|
||||||
loadClientConfig();
|
|
||||||
// check if device type stored in DEVTYPE or raspapType (from UDEV rule) protperty of the device
|
|
||||||
exec("udevadm info /sys/class/net/$dev 2> /dev/null", $udevadm);
|
|
||||||
$type="none";
|
|
||||||
if (!empty($udevadm)) {
|
|
||||||
$type=preg_only_match("/raspapType=(\w*)/i",$udevadm);
|
|
||||||
if (empty($type)) {
|
|
||||||
$type=preg_only_match("/DEVTYPE=(\w*)/i",$udevadm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (empty($type) || $type == "none" || array_search($type, $_SESSION["net-device-name-prefix"]) === false) {
|
|
||||||
// no device type yet -> get device type from device name
|
|
||||||
if (preg_match("/^(\w+)[0-9]$/",$dev,$nam) === 1) $nam=$nam[1];
|
|
||||||
else $nam="none";
|
|
||||||
if (($n = array_search($nam, $_SESSION["net-device-name-prefix"])) === false) $n = count($_SESSION["net-device-types"])-1;
|
|
||||||
$type = $_SESSION["net-device-types"][$n];
|
|
||||||
}
|
|
||||||
return $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMobileLogin(&$pin,&$pw,&$user) {
|
|
||||||
if (file_exists(($f = RASPI_MOBILEDATA_CONFIG))) {
|
|
||||||
$dat = parse_ini_file($f);
|
|
||||||
$pin = (isset($dat["pin"]) && preg_match("/^[0-9]*$/", $dat["pin"])) ? "-p ".$dat["pin"] : "";
|
|
||||||
$user = (isset($dat["router_user"]) && !empty($dat["router_user"]) ) ? "-u ".$dat["router_user"] : "";
|
|
||||||
$pw = (isset($dat["router_pw"]) && !empty($dat["router_pw"]) ) ? "-P ".$dat["router_pw"] : "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadClientConfig()
|
|
||||||
{
|
|
||||||
// load network device config file for UDEV rules into $_SESSION
|
|
||||||
if (!isset($_SESSION["udevrules"])) {
|
|
||||||
$_SESSION["net-device-types"]=array();
|
|
||||||
$_SESSION["net-device-name-prefix"]=array();
|
|
||||||
try {
|
|
||||||
$udevrules = file_get_contents(RASPI_CLIENT_CONFIG_PATH);
|
|
||||||
$_SESSION["udevrules"] = json_decode($udevrules, true);
|
|
||||||
// get device types
|
|
||||||
foreach ($_SESSION["udevrules"]["network_devices"] as $dev) {
|
|
||||||
$_SESSION["net-device-name-prefix"][]=$dev["name_prefix"];
|
|
||||||
$_SESSION["net-device-types"][]=$dev["type"];
|
|
||||||
$_SESSION["net-device-types-info"][]=$dev["type_info"];
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$_SESSION["udevrules"]= null;
|
|
||||||
}
|
|
||||||
$_SESSION["net-device-types"][]="none";
|
|
||||||
$_SESSION["net-device-types-info"][]="unknown";
|
|
||||||
$_SESSION["net-device-name-prefix"][]="none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findCurrentClientIndex($clients)
|
|
||||||
{
|
|
||||||
$devid = -1;
|
|
||||||
if (!empty($clients)) {
|
|
||||||
$ncl=$clients["clients"];
|
|
||||||
if ($ncl > 0) {
|
|
||||||
$ty=-1;
|
|
||||||
foreach ($clients["device"] as $i => $dev) {
|
|
||||||
$id=array_search($dev["type"], $_SESSION["net-device-types"]);
|
|
||||||
if ($id >=0 && $_SESSION["udevrules"]["network_devices"][$id]["clientid"] > $ty && !$dev["isAP"]) {
|
|
||||||
$ty=$id;
|
|
||||||
$devid=$i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $devid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function waitClientConnected($dev, $timeout=10)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
exec('ifconfig -a | grep -i '.$dev.' -A 1 | grep -oP "(?<=inet )([0-9]{1,3}\.){3}[0-9]{1,3}"', $res);
|
|
||||||
$connected= !empty($res);
|
|
||||||
if (!$connected) {
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
} while (!$connected && --$timeout > 0);
|
|
||||||
return $connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setClientState($state)
|
|
||||||
{
|
|
||||||
$clients=getClients();
|
|
||||||
if (($idx = findCurrentClientIndex($clients)) >= 0) {
|
|
||||||
$dev = $clients["device"][$idx];
|
|
||||||
exec('ifconfig -a | grep -i '.$dev["name"].' -A 1 | grep -oP "(?<=inet )([0-9]{1,3}\.){3}[0-9]{1,3}"', $res);
|
|
||||||
if (!empty($res)) {
|
|
||||||
$connected=$res[0];
|
|
||||||
}
|
|
||||||
switch($dev["type"]) {
|
|
||||||
case "wlan":
|
|
||||||
if ($state =="up") {
|
|
||||||
exec('sudo ip link set '.$dev["name"].' up');
|
|
||||||
}
|
|
||||||
if (!empty($connected) && $state =="down") {
|
|
||||||
exec('sudo ip link set '.$dev["name"].' down');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "hilink":
|
|
||||||
preg_match("/^([0-9]{1,3}\.){3}/", $connected, $ipadd);
|
|
||||||
$ipadd = $ipadd[0].'1'; // ip address of the Hilink api
|
|
||||||
$mode = ($state == "up") ? 1 : 0;
|
|
||||||
$pin=$user=$pw="";
|
|
||||||
getMobileLogin($pin,$pw,$user);
|
|
||||||
exec('sudo '.RASPI_CLIENT_SCRIPT_PATH.'/onoff_huawei_hilink.sh -c '.$mode.' -h '.$ipadd.' '.$pin.' '.$user.' '.$pw);
|
|
||||||
break;
|
|
||||||
case "ppp":
|
|
||||||
if ($state == "up") {
|
|
||||||
exec('sudo ifup '.$dev["name"]);
|
|
||||||
}
|
|
||||||
if (!empty($connected) && $state == "down") {
|
|
||||||
exec('sudo ifdown '.$dev["name"]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ($state=="up") {
|
|
||||||
waitClientConnected($dev["name"], 15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +1,51 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'status_messages.php';
|
||||||
|
require_once 'app/lib/system.php';
|
||||||
require_once 'includes/wifi_functions.php';
|
require_once 'includes/wifi_functions.php';
|
||||||
require_once 'includes/config.php';
|
require_once 'includes/config.php';
|
||||||
|
|
||||||
getWifiInterface();
|
getWifiInterface();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize hostapd values, display interface
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function DisplayHostAPDConfig()
|
function DisplayHostAPDConfig()
|
||||||
{
|
{
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
$status = new StatusMessages();
|
||||||
$system = new \RaspAP\System\Sysinfo;
|
$system = new System();
|
||||||
$operatingSystem = $system->operatingSystem();
|
|
||||||
$arrConfig = array();
|
$arrConfig = array();
|
||||||
$arr80211Standard = [
|
$arr80211Standard = [
|
||||||
'a' => '802.11a - 5 GHz',
|
'a' => '802.11a - 5 GHz',
|
||||||
'b' => '802.11b - 2.4 GHz',
|
'b' => '802.11b - 2.4 GHz',
|
||||||
'g' => '802.11g - 2.4 GHz',
|
'g' => '802.11g - 2.4 GHz',
|
||||||
'n' => '802.11n - 2.4 GHz',
|
'n' => '802.11n - 2.4 GHz',
|
||||||
'ac' => '802.11ac - 5 GHz'
|
'ac' => '802.11.ac - 5 GHz'
|
||||||
];
|
];
|
||||||
$arrSecurity = array(1 => 'WPA', 2 => 'WPA2', 3 => 'WPA+WPA2', 'none' => _("None"));
|
$arrSecurity = array(1 => 'WPA', 2 => 'WPA2', 3 => 'WPA+WPA2', 'none' => _("None"));
|
||||||
$arrEncType = array('TKIP' => 'TKIP', 'CCMP' => 'CCMP', 'TKIP CCMP' => 'TKIP+CCMP');
|
$arrEncType = array('TKIP' => 'TKIP', 'CCMP' => 'CCMP', 'TKIP CCMP' => 'TKIP+CCMP');
|
||||||
$arrTxPower = getDefaultNetOpts('txpower','dbm');
|
|
||||||
$managedModeEnabled = false;
|
$managedModeEnabled = false;
|
||||||
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
|
exec("ip -o link show | awk -F': ' '{print $2}'", $interfaces);
|
||||||
sort($interfaces);
|
|
||||||
|
|
||||||
exec("iw reg get | awk '/country / { sub(/:/,\"\",$2); print $2 }'", $country_code);
|
exec("iw reg get | awk '/country / { sub(/:/,\"\",$2); print $2 }'", $country_code);
|
||||||
|
|
||||||
$cmd = "iw dev ".$_SESSION['ap_interface']." info | awk '$1==\"txpower\" {print $2}'";
|
|
||||||
exec($cmd, $txpower);
|
|
||||||
$txpower = intval($txpower[0]);
|
|
||||||
|
|
||||||
if (isset($_POST['interface'])) {
|
|
||||||
$interface = escapeshellarg($_POST['interface']);
|
|
||||||
}
|
|
||||||
if (!RASPI_MONITOR_ENABLED) {
|
if (!RASPI_MONITOR_ENABLED) {
|
||||||
if (isset($_POST['SaveHostAPDSettings'])) {
|
if (isset($_POST['SaveHostAPDSettings'])) {
|
||||||
SaveHostAPDConfig($arrSecurity, $arrEncType, $arr80211Standard, $interfaces, $status);
|
SaveHostAPDConfig($arrSecurity, $arrEncType, $arr80211Standard, $interfaces, $status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini');
|
|
||||||
|
$arrHostapdConf = parse_ini_file('/etc/raspap/hostapd.ini');
|
||||||
|
|
||||||
if (!RASPI_MONITOR_ENABLED) {
|
if (!RASPI_MONITOR_ENABLED) {
|
||||||
if (isset($_POST['StartHotspot']) || isset($_POST['RestartHotspot'])) {
|
if (isset($_POST['StartHotspot']) || isset($_POST['RestartHotspot'])) {
|
||||||
$status->addMessage('Attempting to start hotspot', 'info');
|
$status->addMessage('Attempting to start hotspot', 'info');
|
||||||
if ($arrHostapdConf['BridgedEnable'] == 1) {
|
if ($arrHostapdConf['BridgedEnable'] == 1) {
|
||||||
exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface br0 --seconds 3', $return);
|
exec('sudo /etc/raspap/hostapd/servicestart.sh --interface br0 --seconds 3', $return);
|
||||||
} elseif ($arrHostapdConf['WifiAPEnable'] == 1) {
|
} elseif ($arrHostapdConf['WifiAPEnable'] == 1) {
|
||||||
exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --interface uap0 --seconds 3', $return);
|
exec('sudo /etc/raspap/hostapd/servicestart.sh --interface uap0 --seconds 3', $return);
|
||||||
} else {
|
} else {
|
||||||
exec('sudo '.RASPI_CONFIG.'/hostapd/servicestart.sh --seconds 3', $return);
|
exec('sudo /etc/raspap/hostapd/servicestart.sh --seconds 3', $return);
|
||||||
}
|
}
|
||||||
foreach ($return as $line) {
|
foreach ($return as $line) {
|
||||||
$status->addMessage($line, 'info');
|
$status->addMessage($line, 'info');
|
||||||
@ -66,12 +58,11 @@ function DisplayHostAPDConfig()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exec('cat '. RASPI_HOSTAPD_CONFIG, $hostapdconfig);
|
exec('cat '. RASPI_HOSTAPD_CONFIG, $hostapdconfig);
|
||||||
if (isset($interface)) {
|
exec('iwgetid '. $_POST['interface']. ' -r', $wifiNetworkID);
|
||||||
exec('iwgetid '. $interface. ' -r', $wifiNetworkID);
|
if (!empty($wifiNetworkID[0])) {
|
||||||
if (!empty($wifiNetworkID[0])) {
|
$managedModeEnabled = true;
|
||||||
$managedModeEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$hostapdstatus = $system->hostapdStatus();
|
$hostapdstatus = $system->hostapdStatus();
|
||||||
$serviceStatus = $hostapdstatus[0] == 0 ? "down" : "up";
|
$serviceStatus = $hostapdstatus[0] == 0 ? "down" : "up";
|
||||||
@ -80,6 +71,7 @@ function DisplayHostAPDConfig()
|
|||||||
if (strlen($hostapdconfigline) === 0) {
|
if (strlen($hostapdconfigline) === 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($hostapdconfigline[0] != "#") {
|
if ($hostapdconfigline[0] != "#") {
|
||||||
$arrLine = explode("=", $hostapdconfigline);
|
$arrLine = explode("=", $hostapdconfigline);
|
||||||
$arrConfig[$arrLine[0]]=$arrLine[1];
|
$arrConfig[$arrLine[0]]=$arrLine[1];
|
||||||
@ -94,49 +86,9 @@ function DisplayHostAPDConfig()
|
|||||||
$arrConfig['disassoc_low_ack_bool'] = 1;
|
$arrConfig['disassoc_low_ack_bool'] = 1;
|
||||||
}
|
}
|
||||||
// assign country_code from iw reg if not set in config
|
// assign country_code from iw reg if not set in config
|
||||||
if (empty($arrConfig['country_code']) && isset($country_code[0])) {
|
if (!isset($arrConfig['country_code']) && isset($country_code[0])) {
|
||||||
$arrConfig['country_code'] = $country_code[0];
|
$arrConfig['country_code'] = $country_code[0];
|
||||||
}
|
}
|
||||||
// set txpower with iw if value is non-default ('auto')
|
|
||||||
if (isset($_POST['txpower'])) {
|
|
||||||
if ($_POST['txpower'] != 'auto') {
|
|
||||||
$txpower = intval($_POST['txpower']);
|
|
||||||
$sdBm = $txpower * 100;
|
|
||||||
exec('sudo /sbin/iw dev '.$interface.' set txpower fixed '.$sdBm, $return);
|
|
||||||
$status->addMessage('Setting transmit power to '.$_POST['txpower'].' dBm.', 'success');
|
|
||||||
$txpower = $_POST['txpower'];
|
|
||||||
} elseif ($_POST['txpower'] == 'auto') {
|
|
||||||
exec('sudo /sbin/iw dev '.$interface.' set txpower auto', $return);
|
|
||||||
$status->addMessage('Setting transmit power to '.$_POST['txpower'].'.', 'success');
|
|
||||||
$txpower = $_POST['txpower'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$countries_5Ghz_max48ch = RASPI_5GHZ_ISO_ALPHA2;
|
|
||||||
$selectedHwMode = $arrConfig['hw_mode'];
|
|
||||||
if (isset($arrConfig['ieee80211n'])) {
|
|
||||||
if (strval($arrConfig['ieee80211n']) === '1') {
|
|
||||||
$selectedHwMode = 'n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($arrConfig['ieee80211ac'])) {
|
|
||||||
if (strval($arrConfig['ieee80211ac']) === '1') {
|
|
||||||
$selectedHwMode = 'ac';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isset($arrConfig['ieee80211w'])) {
|
|
||||||
if (strval($arrConfig['ieee80211w']) === '2') {
|
|
||||||
$selectedHwMode = 'w';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!in_array($arrConfig['country_code'], $countries_5Ghz_max48ch)) {
|
|
||||||
$hwModeDisabled = 'ac';
|
|
||||||
if ($selectedHwMode === $hwModeDisabled) {
|
|
||||||
unset($selectedHwMode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$hwModeDisabled = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo renderTemplate(
|
echo renderTemplate(
|
||||||
"hostapd", compact(
|
"hostapd", compact(
|
||||||
@ -150,38 +102,20 @@ function DisplayHostAPDConfig()
|
|||||||
"selectedHwMode",
|
"selectedHwMode",
|
||||||
"arrSecurity",
|
"arrSecurity",
|
||||||
"arrEncType",
|
"arrEncType",
|
||||||
"arrTxPower",
|
"arrHostapdConf"
|
||||||
"txpower",
|
|
||||||
"arrHostapdConf",
|
|
||||||
"operatingSystem",
|
|
||||||
"selectedHwMode",
|
|
||||||
"hwModeDisabled"
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate user input, save configs for hostapd, dnsmasq & dhcp
|
|
||||||
*
|
|
||||||
* @param array $wpa_array
|
|
||||||
* @param array $enc_types
|
|
||||||
* @param array $modes
|
|
||||||
* @param string $interface
|
|
||||||
* @param object $status
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
||||||
{
|
{
|
||||||
// It should not be possible to send bad data for these fields.
|
// It should not be possible to send bad data for these fields so clearly
|
||||||
// If wpa fields are absent, return false and log securely.
|
// someone is up to something if they fail. Fail silently.
|
||||||
if (!(array_key_exists($_POST['wpa'], $wpa_array)
|
if (!(array_key_exists($_POST['wpa'], $wpa_array)
|
||||||
&& array_key_exists($_POST['wpa_pairwise'], $enc_types)
|
&& array_key_exists($_POST['wpa_pairwise'], $enc_types)
|
||||||
&& array_key_exists($_POST['hw_mode'], $modes))
|
&& array_key_exists($_POST['hw_mode'], $modes))
|
||||||
) {
|
) {
|
||||||
$err = "Attempting to set hostapd config with wpa='".escapeshellarg($_POST['wpa']);
|
error_log("Attempting to set hostapd config with wpa='".$_POST['wpa']."', wpa_pairwise='".$_POST['wpa_pairwise']."' and hw_mode='".$_POST['hw_mode']."'"); // FIXME: log injection
|
||||||
$err .= "', wpa_pairwise='".$escapeshellarg(_POST['wpa_pairwise']);
|
|
||||||
$err .= "and hw_mode='".$escapeshellarg(_POST['hw_mode'])."'";
|
|
||||||
error_log($err);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Validate input
|
// Validate input
|
||||||
@ -191,11 +125,11 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
$status->addMessage('Attempting to set channel to invalid number.', 'danger');
|
$status->addMessage('Attempting to set channel to invalid number.', 'danger');
|
||||||
$good_input = false;
|
$good_input = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intval($_POST['channel']) < 1 || intval($_POST['channel']) > RASPI_5GHZ_MAX_CHANNEL) {
|
if (intval($_POST['channel']) < 1 || intval($_POST['channel']) > RASPI_5GHZ_MAX_CHANNEL) {
|
||||||
$status->addMessage('Attempting to set channel outside of permitted range', 'danger');
|
$status->addMessage('Attempting to set channel outside of permitted range', 'danger');
|
||||||
$good_input = false;
|
$good_input = false;
|
||||||
}
|
}
|
||||||
$arrHostapdConf = parse_ini_file('/etc/raspap/hostapd.ini');
|
|
||||||
|
|
||||||
// Check for Bridged AP mode checkbox
|
// Check for Bridged AP mode checkbox
|
||||||
$bridgedEnable = 0;
|
$bridgedEnable = 0;
|
||||||
@ -208,6 +142,7 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
$bridgedEnable = 1;
|
$bridgedEnable = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for WiFi client AP mode checkbox
|
// Check for WiFi client AP mode checkbox
|
||||||
$wifiAPEnable = 0;
|
$wifiAPEnable = 0;
|
||||||
if ($bridgedEnable == 0) { // enable client mode actions when not bridged
|
if ($bridgedEnable == 0) { // enable client mode actions when not bridged
|
||||||
@ -221,6 +156,7 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for Logfile output checkbox
|
// Check for Logfile output checkbox
|
||||||
$logEnable = 0;
|
$logEnable = 0;
|
||||||
if ($arrHostapdConf['LogEnable'] == 0) {
|
if ($arrHostapdConf['LogEnable'] == 0) {
|
||||||
@ -238,44 +174,30 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
exec('sudo '.RASPI_CONFIG.'/hostapd/disablelog.sh');
|
exec('sudo '.RASPI_CONFIG.'/hostapd/disablelog.sh');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// set AP interface default, override for ap-sta & bridged options
|
|
||||||
$ap_iface = $_POST['interface']; // the hostap AP interface
|
|
||||||
$cli_iface = $_POST['interface']; // the wifi client interface
|
|
||||||
$session_iface = $_POST['interface']; // the interface that the UI needs to monitor for data usage etc.
|
|
||||||
if ($wifiAPEnable) { // for AP-STA we monitor the uap0 interface, which is always the ap interface.
|
|
||||||
$ap_iface = 'uap0';
|
|
||||||
$session_iface = 'uap0';
|
|
||||||
}
|
|
||||||
if ($bridgedEnable) { // for bridged mode we monitor the bridge, but keep the selected interface as AP.
|
|
||||||
$session_iface = 'br0';
|
|
||||||
$cli_iface = 'br0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// persist user options to /etc/raspap
|
|
||||||
$cfg = [];
|
$cfg = [];
|
||||||
$cfg['WifiInterface'] = $ap_iface;
|
$cfg['WifiInterface'] = $_POST['interface'];
|
||||||
$cfg['LogEnable'] = $logEnable;
|
$cfg['LogEnable'] = $logEnable;
|
||||||
// Save previous Client mode status when Bridged
|
// Save previous Client mode status when Bridged
|
||||||
$cfg['WifiAPEnable'] = ($bridgedEnable == 1 ? $arrHostapdConf['WifiAPEnable'] : $wifiAPEnable);
|
$cfg['WifiAPEnable'] = ($bridgedEnable == 1 ?
|
||||||
|
$arrHostapdConf['WifiAPEnable'] : $wifiAPEnable);
|
||||||
$cfg['BridgedEnable'] = $bridgedEnable;
|
$cfg['BridgedEnable'] = $bridgedEnable;
|
||||||
$cfg['WifiManaged'] = $cli_iface;
|
$cfg['WifiManaged'] = $_POST['interface'];
|
||||||
write_php_ini($cfg, RASPI_CONFIG.'/hostapd.ini');
|
write_php_ini($cfg, RASPI_CONFIG.'/hostapd.ini');
|
||||||
$_SESSION['ap_interface'] = $session_iface;
|
$_SESSION['ap_interface'] = $_POST['interface'];
|
||||||
|
|
||||||
// Verify input
|
// Verify input
|
||||||
if (empty($_POST['ssid']) || strlen($_POST['ssid']) > 32) {
|
if (empty($_POST['ssid']) || strlen($_POST['ssid']) > 32) {
|
||||||
|
// Not sure of all the restrictions of SSID
|
||||||
$status->addMessage('SSID must be between 1 and 32 characters', 'danger');
|
$status->addMessage('SSID must be between 1 and 32 characters', 'danger');
|
||||||
$good_input = false;
|
$good_input = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
# NB: A pass-phrase is a sequence of between 8 and 63 ASCII-encoded characters (IEEE Std. 802.11i-2004)
|
if ($_POST['wpa'] !== 'none'
|
||||||
# Each character in the pass-phrase must have an encoding in the range of 32 to 126 (decimal). (IEEE Std. 802.11i-2004, Annex H.4.1)
|
&& (strlen($_POST['wpa_passphrase']) < 8 || strlen($_POST['wpa_passphrase']) > 63)
|
||||||
if ($_POST['wpa'] !== 'none' && (strlen($_POST['wpa_passphrase']) < 8 || strlen($_POST['wpa_passphrase']) > 63)) {
|
) {
|
||||||
$status->addMessage('WPA passphrase must be between 8 and 63 characters', 'danger');
|
$status->addMessage('WPA passphrase must be between 8 and 63 characters', 'danger');
|
||||||
$good_input = false;
|
$good_input = false;
|
||||||
} elseif (!ctype_print($_POST['wpa_passphrase'])) {
|
|
||||||
$status->addMessage('WPA passphrase must be comprised of printable ASCII characters', 'danger');
|
|
||||||
$good_input = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_POST['hiddenSSID'])) {
|
if (isset($_POST['hiddenSSID'])) {
|
||||||
@ -293,6 +215,8 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! in_array($_POST['interface'], $interfaces)) {
|
if (! in_array($_POST['interface'], $interfaces)) {
|
||||||
|
// The user is probably up to something here but it may also be a
|
||||||
|
// genuine error.
|
||||||
$status->addMessage('Unknown interface '.htmlspecialchars($_POST['interface'], ENT_QUOTES), 'danger');
|
$status->addMessage('Unknown interface '.htmlspecialchars($_POST['interface'], ENT_QUOTES), 'danger');
|
||||||
$good_input = false;
|
$good_input = false;
|
||||||
}
|
}
|
||||||
@ -314,94 +238,153 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
$_POST['max_num_sta'] = $_POST['max_num_sta'] < 1 ? null : $_POST['max_num_sta'];
|
$_POST['max_num_sta'] = $_POST['max_num_sta'] < 1 ? null : $_POST['max_num_sta'];
|
||||||
|
|
||||||
if ($good_input) {
|
if ($good_input) {
|
||||||
$return = updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable);
|
// Fixed values
|
||||||
|
$country_code = $_POST['country_code'];
|
||||||
// Fetch dhcp-range, lease time from system config
|
$config = 'driver=nl80211'.PHP_EOL;
|
||||||
$syscfg = parse_ini_file(RASPI_DNSMASQ_PREFIX.$ap_iface.'.conf', false, INI_SCANNER_RAW);
|
$config.= 'ctrl_interface='.RASPI_HOSTAPD_CTRL_INTERFACE.PHP_EOL;
|
||||||
|
$config.= 'ctrl_interface_group=0'.PHP_EOL;
|
||||||
|
$config.= 'auth_algs=1'.PHP_EOL;
|
||||||
|
$config.= 'wpa_key_mgmt=WPA-PSK'.PHP_EOL;
|
||||||
|
if (isset($_POST['beaconintervalEnable'])) {
|
||||||
|
$config.= 'beacon_int='.$_POST['beacon_interval'].PHP_EOL;
|
||||||
|
}
|
||||||
|
if (isset($_POST['disassoc_low_ackEnable'])) {
|
||||||
|
$config.= 'disassoc_low_ack=0'.PHP_EOL;
|
||||||
|
}
|
||||||
|
$config.= 'ssid='.$_POST['ssid'].PHP_EOL;
|
||||||
|
$config.= 'channel='.$_POST['channel'].PHP_EOL;
|
||||||
|
if ($_POST['hw_mode'] === 'n') {
|
||||||
|
$config.= 'hw_mode=g'.PHP_EOL;
|
||||||
|
$config.= 'ieee80211n=1'.PHP_EOL;
|
||||||
|
// Enable basic Quality of service
|
||||||
|
$config.= 'wmm_enabled=1'.PHP_EOL;
|
||||||
|
} elseif ($_POST['hw_mode'] === 'ac') {
|
||||||
|
$config.= 'hw_mode=a'.PHP_EOL.PHP_EOL;
|
||||||
|
$config.= '# N'.PHP_EOL;
|
||||||
|
$config.= 'ieee80211n=1'.PHP_EOL;
|
||||||
|
$config.= 'require_ht=1'.PHP_EOL;
|
||||||
|
$config.= 'ht_capab=[MAX-AMSDU-3839][HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40]'.PHP_EOL.PHP_EOL;
|
||||||
|
$config.= '# AC'.PHP_EOL;
|
||||||
|
$config.= 'ieee80211ac=1'.PHP_EOL;
|
||||||
|
$config.= 'require_vht=1'.PHP_EOL;
|
||||||
|
$config.= 'ieee80211d=0'.PHP_EOL;
|
||||||
|
$config.= 'ieee80211h=0'.PHP_EOL;
|
||||||
|
$config.= 'vht_capab=[MAX-AMSDU-3839][SHORT-GI-80]'.PHP_EOL;
|
||||||
|
$config.= 'vht_oper_chwidth=1'.PHP_EOL;
|
||||||
|
$config.= 'vht_oper_centr_freq_seg0_idx=42'.PHP_EOL.PHP_EOL;
|
||||||
|
} elseif ($_POST['hw_mode'] === 'w') {
|
||||||
|
$config.= 'ieee80211w=2'.PHP_EOL;
|
||||||
|
$config.= 'wpa_key_mgmt=WPA-EAP-SHA256'.PHP_EOL;
|
||||||
|
} else {
|
||||||
|
$config.= 'hw_mode='.$_POST['hw_mode'].PHP_EOL;
|
||||||
|
$config.= 'ieee80211n=0'.PHP_EOL;
|
||||||
|
}
|
||||||
|
if ($_POST['wpa'] !== 'none') {
|
||||||
|
$config.= 'wpa_passphrase='.$_POST['wpa_passphrase'].PHP_EOL;
|
||||||
|
}
|
||||||
if ($wifiAPEnable == 1) {
|
if ($wifiAPEnable == 1) {
|
||||||
// Enable uap0 configuration for ap-sta mode
|
$config.= 'interface=uap0'.PHP_EOL;
|
||||||
// Set dhcp-range from system config, fallback to default if undefined
|
} elseif ($bridgedEnable == 1) {
|
||||||
$dhcp_range = ($syscfg['dhcp-range'] == '') ? getDefaultNetValue('dnsmasq','uap0','dhcp-range') : $syscfg['dhcp-range'];
|
$config.='interface='.$_POST['interface'].PHP_EOL;
|
||||||
$config = [ '# RaspAP uap0 configuration' ];
|
$config.= 'bridge=br0'.PHP_EOL;
|
||||||
$config[] = 'interface=lo,uap0 # Enable uap0 interface for wireless client AP mode';
|
} else {
|
||||||
$config[] = 'bind-dynamic # Hybrid between --bind-interfaces and default';
|
$config.= 'interface='.$_POST['interface'].PHP_EOL;
|
||||||
$config[] = 'server=8.8.8.8 # Forward DNS requests to Google DNS';
|
}
|
||||||
$config[] = 'domain-needed # Don\'t forward short names';
|
$config.= 'wpa='.$_POST['wpa'].PHP_EOL;
|
||||||
$config[] = 'bogus-priv # Never forward addresses in the non-routed address spaces';
|
$config.= 'wpa_pairwise='.$_POST['wpa_pairwise'].PHP_EOL;
|
||||||
$config[] = 'dhcp-range='.$dhcp_range;
|
$config.= 'country_code='.$_POST['country_code'].PHP_EOL;
|
||||||
if (!empty($syscfg['dhcp-option'])) {
|
$config.= 'ignore_broadcast_ssid='.$ignore_broadcast_ssid.PHP_EOL;
|
||||||
$config[] = 'dhcp-option='.$syscfg['dhcp-option'];
|
if (isset($_POST['max_num_sta'])) {
|
||||||
}
|
$config.= 'max_num_sta='.$_POST['max_num_sta'].PHP_EOL;
|
||||||
$config[] = PHP_EOL;
|
|
||||||
scanConfigDir('/etc/dnsmasq.d/','uap0',$status);
|
|
||||||
$config = join(PHP_EOL, $config);
|
|
||||||
file_put_contents("/tmp/dnsmasqdata", $config);
|
|
||||||
system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_PREFIX.$ap_iface.'.conf', $return);
|
|
||||||
} elseif ($bridgedEnable !==1) {
|
|
||||||
$dhcp_range = ($syscfg['dhcp-range'] =='') ? getDefaultNetValue('dnsmasq','wlan0','dhcp-range') : $syscfg['dhcp-range'];
|
|
||||||
$config = [ '# RaspAP '.$_POST['interface'].' configuration' ];
|
|
||||||
$config[] = 'interface='.$_POST['interface'];
|
|
||||||
$config[] = 'domain-needed';
|
|
||||||
$config[] = 'dhcp-range='.$dhcp_range;
|
|
||||||
if (!empty($syscfg['dhcp-option'])) {
|
|
||||||
$config[] = 'dhcp-option='.$syscfg['dhcp-option'];
|
|
||||||
}
|
|
||||||
$config[] = PHP_EOL;
|
|
||||||
$config = join(PHP_EOL, $config);
|
|
||||||
file_put_contents("/tmp/dnsmasqdata", $config);
|
|
||||||
system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_PREFIX.$ap_iface.'.conf', $return);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set dhcp values from system config, fallback to default if undefined
|
file_put_contents("/tmp/hostapddata", $config);
|
||||||
$jsonData = json_decode(getNetConfig($ap_iface), true);
|
system("sudo cp /tmp/hostapddata " . RASPI_HOSTAPD_CONFIG, $return);
|
||||||
$ip_address = ($jsonData['StaticIP'] == '') ? getDefaultNetValue('dhcp',$ap_iface,'static ip_address') : $jsonData['StaticIP'];
|
|
||||||
$domain_name_server = ($jsonData['StaticDNS'] =='') ? getDefaultNetValue('dhcp','wlan0','static domain_name_server') : $jsonData['StaticDNS'];
|
// Fetch dhcp-range, lease time from system config
|
||||||
$routers = ($jsonData['StaticRouters'] == '') ? getDefaultNetValue('dhcp',$ap_iface,'static routers') : $jsonData['StaticRouters'];
|
$dhcpConfig = parse_ini_file(RASPI_DNSMASQ_CONFIG, false, INI_SCANNER_RAW);
|
||||||
$netmask = ($jsonData['SubnetMask'] == '' || $jsonData['SubnetMask'] == '0.0.0.0') ? getDefaultNetValue('dhcp',$ap_iface,'subnetmask') : $jsonData['SubnetMask'];
|
|
||||||
$ip_address.= (!preg_match('/.*\/\d+/', $ip_address)) ? '/'.mask2cidr($netmask) : null;
|
if ($wifiAPEnable == 1) {
|
||||||
|
// Enable uap0 configuration in dnsmasq for Wifi client AP mode
|
||||||
|
// Set dhcp-range from system config. If undefined, fallback to default
|
||||||
|
$dhcp_range = ($dhcpConfig['dhcp-range'] =='10.3.141.50,10.3.141.255,255.255.255.0,12h' ||
|
||||||
|
$dhcpConfig['dhcp-range'] =='') ? '192.168.50.50,192.168.50.150,12h' : $dhcpConfig['dhcp-range'];
|
||||||
|
$config = 'interface=lo,uap0 # Enable uap0 interface for wireless client AP mode'.PHP_EOL;
|
||||||
|
$config.= 'bind-dynamic # Hybrid between --bind-interfaces and default'.PHP_EOL;
|
||||||
|
$config.= 'server=8.8.8.8 # Forward DNS requests to Google DNS'.PHP_EOL;
|
||||||
|
$config.= 'domain-needed # Don\'t forward short names'.PHP_EOL;
|
||||||
|
$config.= 'bogus-priv # Never forward addresses in the non-routed address spaces'.PHP_EOL;
|
||||||
|
$config.= 'dhcp-range='.$dhcp_range.PHP_EOL;
|
||||||
|
if (!empty($dhcpConfig['dhcp-option'])) {
|
||||||
|
$config.= 'dhcp-option='.$dhcpConfig['dhcp-option'].PHP_EOL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Set dhcp-range from system config. If undefined, fallback to default
|
||||||
|
$dhcp_range = ($dhcpConfig['dhcp-range'] =='192.168.50.50,192.168.50.150,12h' ||
|
||||||
|
$dhcpConfig['dhcp-range'] =='') ? '10.3.141.50,10.3.141.255,255.255.255.0,12h' : $dhcpConfig['dhcp-range'];
|
||||||
|
$config = 'domain-needed'.PHP_EOL;
|
||||||
|
$config.= 'interface='.$_POST['interface'].PHP_EOL;
|
||||||
|
$config.= 'dhcp-range='.$dhcp_range.PHP_EOL;
|
||||||
|
if (!empty($dhcpConfig['dhcp-option'])) {
|
||||||
|
$config.= 'dhcp-option='.$dhcpConfig['dhcp-option'].PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_put_contents("/tmp/dnsmasqdata", $config);
|
||||||
|
system('sudo cp /tmp/dnsmasqdata '.RASPI_DNSMASQ_CONFIG, $return);
|
||||||
|
|
||||||
|
// Set dnsmasq values from ini, fallback to default if undefined
|
||||||
|
$intConfig = parse_ini_file(RASPI_CONFIG_NETWORKING.'/'.$_POST['interface'].'.ini', false, INI_SCANNER_RAW);
|
||||||
|
$domain_name_server = ($intConfig['domain_name_server'] =='') ? '1.1.1.1 8.8.8.8' : $intConfig['domain_name_server'];
|
||||||
|
$routers = ($intConfig['routers'] == '') ? '10.3.141.1' : $intConfig['routers'];
|
||||||
|
|
||||||
|
// write options to dhcpcd.conf
|
||||||
|
$config = [ '# RaspAP '.$_POST['interface'].' configuration' ];
|
||||||
|
$config[] = 'hostname';
|
||||||
|
$config[] = 'clientid';
|
||||||
|
$config[] = 'persistent';
|
||||||
|
$config[] = 'option rapid_commit';
|
||||||
|
$config[] = 'option domain_name_servers, domain_name, domain_search, host_name';
|
||||||
|
$config[] = 'option classless_static_routes';
|
||||||
|
$config[] = 'option ntp_servers';
|
||||||
|
$config[] = 'require dhcp_server_identifier';
|
||||||
|
$config[] = 'slaac private';
|
||||||
|
$config[] = 'nohook lookup-hostname';
|
||||||
|
|
||||||
if ($bridgedEnable == 1) {
|
if ($bridgedEnable == 1) {
|
||||||
$config = array_keys(getDefaultNetOpts('dhcp','options'));
|
|
||||||
$config[] = PHP_EOL.'# RaspAP br0 configuration';
|
|
||||||
$config[] = 'denyinterfaces eth0 wlan0';
|
$config[] = 'denyinterfaces eth0 wlan0';
|
||||||
$config[] = 'interface br0';
|
$config[] = 'interface br0';
|
||||||
$config[] = PHP_EOL;
|
|
||||||
} elseif ($wifiAPEnable == 1) {
|
} elseif ($wifiAPEnable == 1) {
|
||||||
$config = array_keys(getDefaultNetOpts('dhcp','options'));
|
// Enable uap0 configuration in dhcpcd for Wifi client AP mode
|
||||||
$config[] = PHP_EOL.'# RaspAP uap0 configuration';
|
$intConfig = parse_ini_file(RASPI_CONFIG_NETWORKING.'/uap0.ini', false, INI_SCANNER_RAW);
|
||||||
|
$ip_address = ($intConfig['ip_address'] == '') ? '192.168.50.1/24' : $intConfig['ip_address'];
|
||||||
$config[] = 'interface uap0';
|
$config[] = 'interface uap0';
|
||||||
$config[] = 'static ip_address='.$ip_address;
|
$config[] = 'static ip_address='.$ip_address;
|
||||||
$config[] = 'nohook wpa_supplicant';
|
$config[] = 'nohook wpa_supplicant';
|
||||||
$config[] = PHP_EOL;
|
|
||||||
} else {
|
} else {
|
||||||
|
// Default config
|
||||||
|
$ip_address = "10.3.141.1/24"; // fallback IP
|
||||||
|
// default IP of the AP xxx.xxx.xxx.1/24 of the selected dhcp range
|
||||||
$def_ip = array();
|
$def_ip = array();
|
||||||
$config = [ '# RaspAP '.$ap_iface.' configuration' ];
|
if (preg_match("/^([0-9]{1,3}\.){3}/",$dhcp_range,$def_ip) ) $ip_address = $def_ip[0]."1/24";
|
||||||
$config[] = 'interface '.$ap_iface;
|
// use static IP assigned to interface only, if consistent with the selected dhcp range
|
||||||
|
if (preg_match("/^([0-9]{1,3}\.){3}/",$intConfig['ip_address'],$int_ip) && $def_ip[0] === $int_ip[0]) $ip_address = $intConfig['ip_address'];
|
||||||
|
$config[] = 'interface '.$_POST['interface'];
|
||||||
$config[] = 'static ip_address='.$ip_address;
|
$config[] = 'static ip_address='.$ip_address;
|
||||||
$config[] = 'static routers='.$routers;
|
|
||||||
$config[] = 'static domain_name_server='.$domain_name_server;
|
$config[] = 'static domain_name_server='.$domain_name_server;
|
||||||
if (! is_null($jsonData['Metric'])) { $config[] = 'metric '.$jsonData['Metric']; }
|
|
||||||
}
|
|
||||||
$dhcp_cfg = file_get_contents(RASPI_DHCPCD_CONFIG);
|
|
||||||
if ($bridgedEnable == 1 || $wifiAPEnable == 1) {
|
|
||||||
$dhcp_cfg = join(PHP_EOL, $config);
|
|
||||||
$status->addMessage('DHCP configuration for '.$ap_iface.' enabled.', 'success');
|
|
||||||
} elseif (!preg_match('/^interface\s'.$ap_iface.'$/m', $dhcp_cfg)) {
|
|
||||||
$config[] = PHP_EOL;
|
$config[] = PHP_EOL;
|
||||||
$config= join(PHP_EOL, $config);
|
|
||||||
$dhcp_cfg = removeDHCPIface($dhcp_cfg,'br0');
|
// write the static IP back to the $_POST['interface'].ini file
|
||||||
$dhcp_cfg = removeDHCPIface($dhcp_cfg,'uap0');
|
$intConfig['interface'] = $_POST['interface'];
|
||||||
$dhcp_cfg .= $config;
|
$intConfig['ip_address'] = $ip_address;
|
||||||
$status->addMessage('DHCP configuration for '.$ap_iface.' added.', 'success');
|
$intConfig['domain_name_server'] = $domain_name_server;
|
||||||
} else {
|
$intConfig['routers'] = $routers;
|
||||||
$config = join(PHP_EOL, $config);
|
$intConfig['static'] = "true";
|
||||||
$dhcp_cfg = removeDHCPIface($dhcp_cfg,'br0');
|
$intConfig['failover'] = "false";
|
||||||
$dhcp_cfg = removeDHCPIface($dhcp_cfg,'uap0');
|
write_php_ini($intConfig, RASPI_CONFIG_NETWORKING.'/'.$_POST['interface'].".ini");
|
||||||
$dhcp_cfg = preg_replace('/^#\sRaspAP\s'.$ap_iface.'\s.*?(?=\s*^\s*$)/ms', $config, $dhcp_cfg, 1);
|
|
||||||
$status->addMessage('DHCP configuration for '.$ap_iface.' updated.', 'success');
|
|
||||||
}
|
}
|
||||||
file_put_contents("/tmp/dhcpddata", $dhcp_cfg);
|
|
||||||
|
$config = join(PHP_EOL, $config);
|
||||||
|
file_put_contents("/tmp/dhcpddata", $config);
|
||||||
system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $return);
|
system('sudo cp /tmp/dhcpddata '.RASPI_DHCPCD_CONFIG, $return);
|
||||||
|
|
||||||
if ($return == 0) {
|
if ($return == 0) {
|
||||||
@ -413,77 +396,6 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status)
|
|||||||
$status->addMessage('Unable to save wifi hotspot settings', 'danger');
|
$status->addMessage('Unable to save wifi hotspot settings', 'danger');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a hostapd configuration
|
|
||||||
*
|
|
||||||
* @return boolean $result
|
|
||||||
*/
|
|
||||||
function updateHostapdConfig($ignore_broadcast_ssid,$wifiAPEnable,$bridgedEnable)
|
|
||||||
{
|
|
||||||
// Fixed values
|
|
||||||
$country_code = $_POST['country_code'];
|
|
||||||
$config = 'driver=nl80211'.PHP_EOL;
|
|
||||||
$config.= 'ctrl_interface='.RASPI_HOSTAPD_CTRL_INTERFACE.PHP_EOL;
|
|
||||||
$config.= 'ctrl_interface_group=0'.PHP_EOL;
|
|
||||||
$config.= 'auth_algs=1'.PHP_EOL;
|
|
||||||
$config.= 'wpa_key_mgmt=WPA-PSK'.PHP_EOL;
|
|
||||||
if (isset($_POST['beaconintervalEnable'])) {
|
|
||||||
$config.= 'beacon_int='.$_POST['beacon_interval'].PHP_EOL;
|
|
||||||
}
|
|
||||||
if (isset($_POST['disassoc_low_ackEnable'])) {
|
|
||||||
$config.= 'disassoc_low_ack=0'.PHP_EOL;
|
|
||||||
}
|
|
||||||
$config.= 'ssid='.$_POST['ssid'].PHP_EOL;
|
|
||||||
$config.= 'channel='.$_POST['channel'].PHP_EOL;
|
|
||||||
if ($_POST['hw_mode'] === 'n') {
|
|
||||||
$config.= 'hw_mode=g'.PHP_EOL;
|
|
||||||
$config.= 'ieee80211n=1'.PHP_EOL;
|
|
||||||
// Enable basic Quality of service
|
|
||||||
$config.= 'wmm_enabled=1'.PHP_EOL;
|
|
||||||
} elseif ($_POST['hw_mode'] === 'ac') {
|
|
||||||
$config.= 'hw_mode=a'.PHP_EOL.PHP_EOL;
|
|
||||||
$config.= '# N'.PHP_EOL;
|
|
||||||
$config.= 'ieee80211n=1'.PHP_EOL;
|
|
||||||
$config.= 'require_ht=1'.PHP_EOL;
|
|
||||||
$config.= 'ht_capab=[MAX-AMSDU-3839][HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40]'.PHP_EOL.PHP_EOL;
|
|
||||||
$config.= '# AC'.PHP_EOL;
|
|
||||||
$config.= 'ieee80211ac=1'.PHP_EOL;
|
|
||||||
$config.= 'require_vht=1'.PHP_EOL;
|
|
||||||
$config.= 'ieee80211d=0'.PHP_EOL;
|
|
||||||
$config.= 'ieee80211h=0'.PHP_EOL;
|
|
||||||
$config.= 'vht_capab=[MAX-AMSDU-3839][SHORT-GI-80]'.PHP_EOL;
|
|
||||||
$config.= 'vht_oper_chwidth=1'.PHP_EOL;
|
|
||||||
$config.= 'vht_oper_centr_freq_seg0_idx=42'.PHP_EOL.PHP_EOL;
|
|
||||||
} elseif ($_POST['hw_mode'] === 'w') {
|
|
||||||
$config.= 'ieee80211w=2'.PHP_EOL;
|
|
||||||
$config.= 'wpa_key_mgmt=WPA-EAP-SHA256'.PHP_EOL;
|
|
||||||
} else {
|
|
||||||
$config.= 'hw_mode='.$_POST['hw_mode'].PHP_EOL;
|
|
||||||
$config.= 'ieee80211n=0'.PHP_EOL;
|
|
||||||
}
|
|
||||||
if ($_POST['wpa'] !== 'none') {
|
|
||||||
$config.= 'wpa_passphrase='.$_POST['wpa_passphrase'].PHP_EOL;
|
|
||||||
}
|
|
||||||
if ($wifiAPEnable == 1) {
|
|
||||||
$config.= 'interface=uap0'.PHP_EOL;
|
|
||||||
} elseif ($bridgedEnable == 1) {
|
|
||||||
$config.='interface='.$_POST['interface'].PHP_EOL;
|
|
||||||
$config.= 'bridge=br0'.PHP_EOL;
|
|
||||||
} else {
|
|
||||||
$config.= 'interface='.$_SESSION['ap_interface'].PHP_EOL;
|
|
||||||
}
|
|
||||||
$config.= 'wpa='.$_POST['wpa'].PHP_EOL;
|
|
||||||
$config.= 'wpa_pairwise='.$_POST['wpa_pairwise'].PHP_EOL;
|
|
||||||
$config.= 'country_code='.$_POST['country_code'].PHP_EOL;
|
|
||||||
$config.= 'ignore_broadcast_ssid='.$ignore_broadcast_ssid.PHP_EOL;
|
|
||||||
if (isset($_POST['max_num_sta'])) {
|
|
||||||
$config.= 'max_num_sta='.$_POST['max_num_sta'].PHP_EOL;
|
|
||||||
}
|
|
||||||
file_put_contents("/tmp/hostapddata", $config);
|
|
||||||
system("sudo cp /tmp/hostapddata " . RASPI_HOSTAPD_CONFIG, $result);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,68 +1,35 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
$rInfo=array();
|
||||||
* Fetches details of the kernel routing table
|
// get all default routes
|
||||||
*
|
exec('ip route list | sed -rn "s/default via (([0-9]{1,3}\.){3}[0-9]{1,3}).*dev (\w*).*src (([0-9]{1,3}\.){3}[0-9]{1,3}).*/\3 \4 \1/p"', $routes);
|
||||||
* @param boolean $checkAccesss Perform connectivity test
|
exec('ip route list | sed -rn "s/default dev (\w*) scope link/\1/p"',$devs);
|
||||||
* @return string
|
if(!empty($devs)) {
|
||||||
*/
|
foreach ($devs as $dev)
|
||||||
function getRouteInfo($checkAccess)
|
exec('ip route list | sed -rn "s/(([0-9]{1,3}\.){3}[0-9]{1,3}).*dev.*("'.$dev.'").*scope link src (([0-9]{1,3}\.){3}[0-9]{1,3}).*/\3 \4 \1/p"',$routes);
|
||||||
{
|
}
|
||||||
$rInfo = array();
|
if (!empty($routes) ) {
|
||||||
// get all default routes
|
foreach ($routes as $i => $route) {
|
||||||
exec('ip route list | sed -rn "s/default via (\b([0-9]{1,3}\.){3}[0-9]{1,3}).*dev (\w*)(.*((\b([0-9]{1,3}\.){3}[0-9]{1,3})))?/\3 \5 \1/p"', $routes);
|
$prop=explode(' ', $route);
|
||||||
$devpat = array("tun", "ppp"); // routing in case of VPN and PPP connection are different
|
$rInfo[$i]["interface"]=$prop[0];
|
||||||
foreach ($devpat as $pat) {
|
$rInfo[$i]["ip-address"]=$prop[1];
|
||||||
exec('ip route list | grep -oP "'.$pat.'[0-9]" | sort -u', $devs);
|
$rInfo[$i]["gateway"]=$prop[2];
|
||||||
}
|
// resolve the name of the gateway (if possible)
|
||||||
if (!empty($devs)) {
|
unset($host);
|
||||||
foreach ($devs as $dev) {
|
exec('host '.$prop[2].' | sed -rn "s/.*domain name pointer (.*)\./\1/p" | head -n 1', $host);
|
||||||
unset($gateway);
|
$rInfo[$i]["gw-name"] = empty($host) ? "*" : $host[0];
|
||||||
unset($ipadd);
|
if (isset($checkAccess) && $checkAccess) {
|
||||||
exec('ip route list | sed -rn "s/^.*via (([0-9]{1,3}\.){3}[0-9]{1,3}) dev "' . $dev . '".*$/\1/p" | head -n 1', $gateway);
|
// check internet connectivity w/ and w/o DNS resolution
|
||||||
if (empty($gateway)) {
|
unset($okip);
|
||||||
exec('ip route list | sed -rn "s/(([0-9]{1,3}\.){3}[0-9]{1,3}).*dev.*"' . $dev . '".*scope link src.*/\1/p"', $gateway);
|
exec('ping -W1 -c 1 -I '.$prop[0].' '.RASPI_ACCESS_CHECK_IP.' | sed -rn "s/.*icmp_seq=1.*time=.*/OK/p"',$okip);
|
||||||
}
|
$rInfo[$i]["access-ip"] = empty($okip) ? false : true;
|
||||||
exec('ifconfig -a | grep -i ' . $dev . ' -A 1 | grep -oP "(?<=inet )([0-9]{1,3}\.){3}[0-9]{1,3}"', $ipadd);
|
unset($okdns);
|
||||||
if (!empty($gateway) && !empty($ipadd)) {
|
exec('ping -W1 -c 1 -I '.$prop[0].' '.RASPI_ACCESS_CHECK_DNS.' | sed -rn "s/.*icmp_seq=1.*time=.*/OK/p"',$okdns);
|
||||||
$routes[]="$dev $ipadd[0] $gateway[0]";
|
$rInfo[$i]["access-dns"] = empty($okdns) ? false : true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!empty($routes)) {
|
} else {
|
||||||
foreach ($routes as $i => $route) {
|
$rInfo = array("error"=>"No route to the internet found");
|
||||||
$prop = explode(' ', $route);
|
|
||||||
$rInfo[$i]["interface"] = $prop[0];
|
|
||||||
$rInfo[$i]["ip-address"] = $prop[1];
|
|
||||||
$rInfo[$i]["gateway"] = $prop[2];
|
|
||||||
// resolve the name of the gateway (if possible)
|
|
||||||
unset($host);
|
|
||||||
exec('host ' . $prop[2] . ' | sed -rn "s/.*domain name pointer (.*)\./\1/p" | head -n 1', $host);
|
|
||||||
$rInfo[$i]["gw-name"] = empty($host) ? "*" : $host[0];
|
|
||||||
if (isset($checkAccess) && $checkAccess) {
|
|
||||||
// check internet connectivity w/ and w/o DNS resolution
|
|
||||||
unset($okip);
|
|
||||||
exec('ping -W1 -c 1 -I ' . $prop[0] . ' ' . RASPI_ACCESS_CHECK_IP . ' | sed -rn "s/.*icmp_seq=1.*time=.*/OK/p"', $okip);
|
|
||||||
$rInfo[$i]["access-ip"] = empty($okip) ? false : true;
|
|
||||||
unset($okdns);
|
|
||||||
exec('ping -W1 -c 1 -I ' . $prop[0] . ' ' . RASPI_ACCESS_CHECK_DNS . ' | sed -rn "s/.*icmp_seq=1.*time=.*/OK/p"', $okdns);
|
|
||||||
$rInfo[$i]["access-dns"] = empty($okdns) ? false : true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$rInfo = array("error" => "No route to the internet found");
|
|
||||||
}
|
|
||||||
return $rInfo;
|
|
||||||
}
|
}
|
||||||
|
$rInfo_json = json_encode($rInfo);
|
||||||
/*
|
?>
|
||||||
* Fetches raw output of ip route
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function getRouteInfoRaw()
|
|
||||||
{
|
|
||||||
exec('ip route list', $routes);
|
|
||||||
return $routes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -75,9 +75,6 @@ if (empty($_SESSION['locale']) && strlen($_SERVER['HTTP_ACCEPT_LANGUAGE']) >= 2)
|
|||||||
case "pl":
|
case "pl":
|
||||||
$locale = "pl_PL.UTF-8";
|
$locale = "pl_PL.UTF-8";
|
||||||
break;
|
break;
|
||||||
case "sk":
|
|
||||||
$locale = "sk_SK.UTF-8";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
$locale = "en_GB.UTF-8";
|
$locale = "en_GB.UTF-8";
|
||||||
break;
|
break;
|
||||||
@ -97,33 +94,3 @@ bindtextdomain(LOCALE_DOMAIN, LOCALE_ROOT);
|
|||||||
bind_textdomain_codeset(LOCALE_DOMAIN, 'UTF-8');
|
bind_textdomain_codeset(LOCALE_DOMAIN, 'UTF-8');
|
||||||
|
|
||||||
textdomain(LOCALE_DOMAIN);
|
textdomain(LOCALE_DOMAIN);
|
||||||
|
|
||||||
function getLocales()
|
|
||||||
{
|
|
||||||
$arrLocales = array(
|
|
||||||
'en_GB.UTF-8' => 'English',
|
|
||||||
'cs_CZ.UTF-8' => 'Čeština',
|
|
||||||
'zh_TW.UTF-8' => '正體中文 (Chinese traditional)',
|
|
||||||
'zh_CN.UTF-8' => '简体中文 (Chinese simplified)',
|
|
||||||
'da_DK.UTF-8' => 'Dansk',
|
|
||||||
'de_DE.UTF-8' => 'Deutsch',
|
|
||||||
'es_MX.UTF-8' => 'Español',
|
|
||||||
'fi_FI.UTF-8' => 'Finnish',
|
|
||||||
'fr_FR.UTF-8' => 'Français',
|
|
||||||
'el_GR.UTF-8' => 'Ελληνικά',
|
|
||||||
'id_ID.UTF-8' => 'Indonesian',
|
|
||||||
'it_IT.UTF-8' => 'Italiano',
|
|
||||||
'ja_JP.UTF-8' => '日本語 (Japanese)',
|
|
||||||
'ko_KR.UTF-8' => '한국어 (Korean)',
|
|
||||||
'nl_NL.UTF-8' => 'Nederlands',
|
|
||||||
'pl_PL.UTF-8' => 'Polskie',
|
|
||||||
'pt_BR.UTF-8' => 'Português',
|
|
||||||
'ru_RU.UTF-8' => 'Русский',
|
|
||||||
'ro_RO.UTF-8' => 'Română',
|
|
||||||
'sk_SK.UTF-8' => 'Slovenčina',
|
|
||||||
'sv_SE.UTF-8' => 'Svenska',
|
|
||||||
'tr_TR.UTF-8' => 'Türkçe',
|
|
||||||
'vi_VN.UTF-8' => 'Tiếng Việt (Vietnamese)'
|
|
||||||
);
|
|
||||||
return $arrLocales;
|
|
||||||
}
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
<nav class="navbar navbar-expand navbar-light topbar mb-1 static-top">
|
|
||||||
<!-- Sidebar Toggle (Topbar) -->
|
|
||||||
<button id="sidebarToggleTopbar" class="btn btn-link d-md-none rounded-circle mr-3">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</button>
|
|
||||||
<!-- Topbar Navbar -->
|
|
||||||
<p class="text-left brand-title mt-3 ml-2"></p>
|
|
||||||
<ul class="navbar-nav ml-auto">
|
|
||||||
<!-- Nav Item - Night mode -->
|
|
||||||
<div class="custom-control custom-switch mt-4">
|
|
||||||
<input type="checkbox" class="custom-control-input" id="night-mode" <?php echo getNightmode() ? 'checked' : null ; ?> >
|
|
||||||
<label class="custom-control-label" for="night-mode"><i class="far fa-moon mr-1 text-muted"></i></label>
|
|
||||||
</div>
|
|
||||||
<div class="topbar-divider d-none d-sm-block"></div>
|
|
||||||
<!-- Nav Item - User -->
|
|
||||||
<li class="nav-item dropdown no-arrow">
|
|
||||||
<a class="nav-link" href="auth_conf">
|
|
||||||
<span class="mr-2 d-none d-lg-inline small"><?php echo htmlspecialchars($_SESSION['user_id'], ENT_QUOTES); ?></span>
|
|
||||||
<i class="fas fa-user-circle fa-3x"></i>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once 'includes/internetRoute.php';
|
require_once 'includes/status_messages.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -8,19 +8,13 @@ require_once 'includes/internetRoute.php';
|
|||||||
*/
|
*/
|
||||||
function DisplayNetworkingConfig()
|
function DisplayNetworkingConfig()
|
||||||
{
|
{
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
|
||||||
|
$status = new StatusMessages();
|
||||||
|
|
||||||
exec("ls /sys/class/net | grep -v lo", $interfaces);
|
exec("ls /sys/class/net | grep -v lo", $interfaces);
|
||||||
$routeInfo = getRouteInfo(true);
|
|
||||||
$routeInfoRaw = getRouteInfoRaw();
|
|
||||||
$arrHostapdConf = parse_ini_file(RASPI_CONFIG.'/hostapd.ini');
|
|
||||||
$bridgedEnabled = $arrHostapdConf['BridgedEnable'];
|
|
||||||
|
|
||||||
echo renderTemplate("networking", compact(
|
foreach ($interfaces as $interface) {
|
||||||
"status",
|
exec("ip a show $interface", $$interface);
|
||||||
"interfaces",
|
}
|
||||||
"routeInfo",
|
echo renderTemplate("networking", compact("status", "interfaces"));
|
||||||
"routeInfoRaw",
|
|
||||||
"bridgedEnabled")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
require_once 'includes/status_messages.php';
|
||||||
require_once 'includes/config.php';
|
require_once 'includes/config.php';
|
||||||
require_once 'includes/wifi_functions.php';
|
require_once 'includes/wifi_functions.php';
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ getWifiInterface();
|
|||||||
*/
|
*/
|
||||||
function DisplayOpenVPNConfig()
|
function DisplayOpenVPNConfig()
|
||||||
{
|
{
|
||||||
$status = new \RaspAP\Messages\StatusMessage;
|
$status = new StatusMessages();
|
||||||
if (!RASPI_MONITOR_ENABLED) {
|
if (!RASPI_MONITOR_ENABLED) {
|
||||||
if (isset($_POST['SaveOpenVPNSettings'])) {
|
if (isset($_POST['SaveOpenVPNSettings'])) {
|
||||||
if (isset($_POST['authUser'])) {
|
if (isset($_POST['authUser'])) {
|
||||||
@ -19,9 +20,7 @@ function DisplayOpenVPNConfig()
|
|||||||
if (isset($_POST['authPassword'])) {
|
if (isset($_POST['authPassword'])) {
|
||||||
$authPassword = strip_tags(trim($_POST['authPassword']));
|
$authPassword = strip_tags(trim($_POST['authPassword']));
|
||||||
}
|
}
|
||||||
if (is_uploaded_file( $_FILES["customFile"]["tmp_name"])) {
|
$return = SaveOpenVPNConfig($status, $_FILES['customFile'], $authUser, $authPassword);
|
||||||
$return = SaveOpenVPNConfig($status, $_FILES['customFile'], $authUser, $authPassword);
|
|
||||||
}
|
|
||||||
} elseif (isset($_POST['StartOpenVPN'])) {
|
} elseif (isset($_POST['StartOpenVPN'])) {
|
||||||
$status->addMessage('Attempting to start OpenVPN', 'info');
|
$status->addMessage('Attempting to start OpenVPN', 'info');
|
||||||
exec('sudo /bin/systemctl start openvpn-client@client', $return);
|
exec('sudo /bin/systemctl start openvpn-client@client', $return);
|
||||||
@ -40,32 +39,16 @@ function DisplayOpenVPNConfig()
|
|||||||
}
|
}
|
||||||
|
|
||||||
exec('pidof openvpn | wc -l', $openvpnstatus);
|
exec('pidof openvpn | wc -l', $openvpnstatus);
|
||||||
|
exec('wget https://ipinfo.io/ip -qO -', $return);
|
||||||
|
|
||||||
$serviceStatus = $openvpnstatus[0] == 0 ? "down" : "up";
|
$serviceStatus = $openvpnstatus[0] == 0 ? "down" : "up";
|
||||||
$auth = file(RASPI_OPENVPN_CLIENT_LOGIN, FILE_IGNORE_NEW_LINES);
|
$auth = file(RASPI_OPENVPN_CLIENT_LOGIN, FILE_IGNORE_NEW_LINES);
|
||||||
$public_ip = get_public_ip();
|
$public_ip = $return[0];
|
||||||
|
|
||||||
// parse client auth credentials
|
// parse client auth credentials
|
||||||
if (!empty($auth)) {
|
if (!empty($auth)) {
|
||||||
$auth = array_filter($auth, 'filter_comments');
|
$authUser = $auth[0];
|
||||||
$authUser = current($auth);
|
$authPassword = $auth[1];
|
||||||
$authPassword = next($auth);
|
|
||||||
}
|
|
||||||
$clients = preg_grep('/_client.(conf)$/', scandir(pathinfo(RASPI_OPENVPN_CLIENT_CONFIG, PATHINFO_DIRNAME)));
|
|
||||||
exec("readlink ".RASPI_OPENVPN_CLIENT_CONFIG." | xargs basename", $ret);
|
|
||||||
$conf_default = empty($ret) ? "none" : $ret[0];
|
|
||||||
|
|
||||||
$logEnable = 0;
|
|
||||||
if (!empty($_POST) && !isset($_POST['log-openvpn'])) {
|
|
||||||
$logOutput = "";
|
|
||||||
$f = @fopen("/tmp/openvpn.log", "r+");
|
|
||||||
if ($f !== false) {
|
|
||||||
ftruncate($f, 0);
|
|
||||||
fclose($f);
|
|
||||||
}
|
|
||||||
} elseif (isset($_POST['log-openvpn']) || file_exists('/tmp/openvpn.log')) {
|
|
||||||
$logEnable = 1;
|
|
||||||
exec("sudo /etc/raspap/openvpn/openvpnlog.sh", $logOutput);
|
|
||||||
$logOutput = file_get_contents('/tmp/openvpn.log');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo renderTemplate(
|
echo renderTemplate(
|
||||||
@ -73,13 +56,9 @@ function DisplayOpenVPNConfig()
|
|||||||
"status",
|
"status",
|
||||||
"serviceStatus",
|
"serviceStatus",
|
||||||
"openvpnstatus",
|
"openvpnstatus",
|
||||||
"logEnable",
|
|
||||||
"logOutput",
|
|
||||||
"public_ip",
|
"public_ip",
|
||||||
"authUser",
|
"authUser",
|
||||||
"authPassword",
|
"authPassword"
|
||||||
"clients",
|
|
||||||
"conf_default"
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -97,8 +76,8 @@ function DisplayOpenVPNConfig()
|
|||||||
*/
|
*/
|
||||||
function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
|
function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
|
||||||
{
|
{
|
||||||
define('KB', 1024);
|
$tmp_ovpnclient = '/tmp/ovpnclient.ovpn';
|
||||||
$tmp_destdir = '/tmp/';
|
$tmp_authdata = '/tmp/authdata';
|
||||||
$auth_flag = 0;
|
$auth_flag = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -107,49 +86,76 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
|
|||||||
throw new RuntimeException('Invalid parameters');
|
throw new RuntimeException('Invalid parameters');
|
||||||
}
|
}
|
||||||
|
|
||||||
$upload = \RaspAP\Uploader\FileUpload::factory('ovpn',$tmp_destdir);
|
// Parse returned errors
|
||||||
$upload->set_max_file_size(64*KB);
|
switch ($file['error']) {
|
||||||
$upload->set_allowed_mime_types(array('ovpn' => 'text/plain'));
|
case UPLOAD_ERR_OK:
|
||||||
$upload->file($file);
|
break;
|
||||||
|
case UPLOAD_ERR_NO_FILE:
|
||||||
$validation = new validation;
|
throw new RuntimeException('OpenVPN configuration file not sent');
|
||||||
$upload->callbacks($validation, array('check_name_length'));
|
case UPLOAD_ERR_INI_SIZE:
|
||||||
$results = $upload->upload();
|
case UPLOAD_ERR_FORM_SIZE:
|
||||||
|
throw new RuntimeException('Exceeded filesize limit');
|
||||||
if (!empty($results['errors'])) {
|
default:
|
||||||
throw new RuntimeException($results['errors'][0]);
|
throw new RuntimeException('Unknown errors');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate extension
|
||||||
|
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
|
||||||
|
if ($ext != 'ovpn') {
|
||||||
|
throw new RuntimeException('Invalid file extension');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
}
|
||||||
// Good file upload, update auth credentials if present
|
// Good file upload, update auth credentials if present
|
||||||
if (!empty($authUser) && !empty($authPassword)) {
|
if (!empty($authUser) && !empty($authPassword)) {
|
||||||
$auth_flag = 1;
|
$auth_flag = 1;
|
||||||
$tmp_authdata = $tmp_destdir .'ovpn/authdata';
|
// Move tmp authdata to /etc/openvpn/login.conf
|
||||||
$auth = $authUser .PHP_EOL . $authPassword .PHP_EOL;
|
$auth = $authUser .PHP_EOL . $authPassword .PHP_EOL;
|
||||||
file_put_contents($tmp_authdata, $auth);
|
file_put_contents($tmp_authdata, $auth);
|
||||||
chmod($tmp_authdata, 0644);
|
system("sudo cp $tmp_authdata " . RASPI_OPENVPN_CLIENT_LOGIN, $return);
|
||||||
$client_auth = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_login.conf';
|
|
||||||
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) {
|
if ($return !=0) {
|
||||||
$status->addMessage('Unable to save client auth credentials', 'danger');
|
$status->addMessage('Unable to save client auth credentials', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set iptables rules and, optionally, auth-user-pass
|
// Set iptables rules and, optionally, auth-user-pass
|
||||||
$tmp_ovpn = $results['full_path'];
|
exec("sudo /etc/raspap/openvpn/configauth.sh $tmp_ovpnclient $auth_flag " .$_SESSION['ap_interface'], $return);
|
||||||
exec("sudo /etc/raspap/openvpn/configauth.sh $tmp_ovpn $auth_flag " .$_SESSION['ap_interface'], $return);
|
|
||||||
foreach ($return as $line) {
|
foreach ($return as $line) {
|
||||||
$status->addMessage($line, 'info');
|
$status->addMessage($line, 'info');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move uploaded ovpn config from /tmp and create symlink
|
// Copy tmp client config to /etc/openvpn/client
|
||||||
$client_ovpn = RASPI_OPENVPN_CLIENT_PATH.pathinfo($file['name'], PATHINFO_FILENAME).'_client.conf';
|
system("sudo cp $tmp_ovpnclient " . RASPI_OPENVPN_CLIENT_CONFIG, $return);
|
||||||
chmod($tmp_ovpn, 0644);
|
|
||||||
system("sudo mv $tmp_ovpn $client_ovpn", $return);
|
|
||||||
system("sudo rm ".RASPI_OPENVPN_CLIENT_CONFIG, $return);
|
|
||||||
system("sudo ln -s $client_ovpn ".RASPI_OPENVPN_CLIENT_CONFIG, $return);
|
|
||||||
|
|
||||||
if ($return ==0) {
|
if ($return ==0) {
|
||||||
$status->addMessage('OpenVPN client.conf uploaded successfully', 'info');
|
$status->addMessage('OpenVPN client.conf uploaded successfully', 'info');
|
||||||
} else {
|
} else {
|
||||||
@ -162,4 +168,3 @@ function SaveOpenVPNConfig($status, $file, $authUser, $authPassword)
|
|||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
$extraFooterScripts = array();
|
|
||||||
$page = $_SERVER['PATH_INFO'];
|
|
||||||
// handle page actions
|
|
||||||
switch ($page) {
|
|
||||||
case "/wlan0_info":
|
|
||||||
DisplayDashboard($extraFooterScripts);
|
|
||||||
break;
|
|
||||||
case "/dhcpd_conf":
|
|
||||||
DisplayDHCPConfig();
|
|
||||||
break;
|
|
||||||
case "/wpa_conf":
|
|
||||||
DisplayWPAConfig();
|
|
||||||
break;
|
|
||||||
case "/network_conf":
|
|
||||||
DisplayNetworkingConfig();
|
|
||||||
break;
|
|
||||||
case "/hostapd_conf":
|
|
||||||
DisplayHostAPDConfig();
|
|
||||||
break;
|
|
||||||
case "/adblock_conf":
|
|
||||||
DisplayAdBlockConfig();
|
|
||||||
break;
|
|
||||||
case "/openvpn_conf":
|
|
||||||
DisplayOpenVPNConfig();
|
|
||||||
break;
|
|
||||||
case "/wg_conf":
|
|
||||||
DisplayWireGuardConfig();
|
|
||||||
break;
|
|
||||||
case "/torproxy_conf":
|
|
||||||
DisplayTorProxyConfig();
|
|
||||||
break;
|
|
||||||
case "/auth_conf":
|
|
||||||
DisplayAuthConfig($_SESSION['user_id']);
|
|
||||||
break;
|
|
||||||
case "/save_hostapd_conf":
|
|
||||||
SaveTORAndVPNConfig();
|
|
||||||
break;
|
|
||||||
case "/data_use":
|
|
||||||
DisplayDataUsage($extraFooterScripts);
|
|
||||||
break;
|
|
||||||
case "/system_info":
|
|
||||||
DisplaySystem($extraFooterScripts);
|
|
||||||
break;
|
|
||||||
case "/about":
|
|
||||||
DisplayAbout();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DisplayDashboard($extraFooterScripts);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user