Compare commits

..

673 commits

Author SHA1 Message Date
billz
c3175459ab Update release version 2025-04-17 05:44:30 -07:00
Bill Zimmerman
3bf682d752
Merge pull request #1811 from RaspAP/feat/csrf-tokenizer
Feature: CSRF tokenizer class
2025-04-17 14:32:58 +02:00
Bill Zimmerman
9e0801aa0c
Merge pull request #1825 from RaspAP/fix/custom-blocklists
Fix: Check for presence of custom blocklist
2025-04-17 10:07:12 +02:00
billz
a21b0a8f99 Check for presence of custom blocklist in RASPI_ADBLOCK_LISTPATH 2025-04-16 23:33:13 -07:00
billz
5f1b16bc74 Remove instantiation of $token 2025-03-26 11:19:00 -07:00
billz
deba5e1e74 When session token expires, redirect instead of returning a 500 error 2025-03-26 09:51:39 -07:00
billz
0960e8bac9 Add CSRF protection include 2025-03-26 04:05:39 -07:00
billz
4a4506a913 Update with CSRF::hiddenField() 2025-03-26 04:03:37 -07:00
billz
bfab3d7441 Revise CSRFValidate() 2025-03-26 04:02:48 -07:00
billz
47d7c121de Generate new session id on logout() 2025-03-26 04:01:09 -07:00
billz
484b89718a Add validateRequest(), token check outside class 2025-03-26 04:00:34 -07:00
billz
d6c8ac32a7 Fix call to class method 2025-03-25 14:05:34 -07:00
billz
3d6b4e1f15 Simplify getVpnManaged check with ternary operator 2025-03-25 14:04:29 -07:00
billz
8d482845b0 Replace explicit token instantiation w/ includes/CSRF.php 2025-03-25 14:02:51 -07:00
billz
a1550d8049 Refactor templates to use CSRF facade 2025-03-25 14:00:24 -07:00
billz
5584e3b72c Initial commit 2025-03-25 13:58:52 -07:00
billz
b0ba029c66 Revert "Accept $token object, pass to renderTemplate()"
This reverts commit b3c6178274.
2025-03-25 13:23:58 -07:00
billz
48e492bf10 Ensure a CSRF token exists in session 2025-03-25 06:49:18 -07:00
billz
821ac9c1f8 Numerous fixes to class methods 2025-03-25 05:26:53 -07:00
billz
49cb3911b8 Fixup misnamed method getVpnManged -> getVpnManaged 2025-03-25 05:25:11 -07:00
billz
8ad582b3b2 Instantiate ExceptionHandler, CSRFTokenizer objects 2025-03-25 05:23:52 -07:00
billz
bbf1caf777 Update with $token->CSRFTokenFieldTag() 2025-03-25 05:23:06 -07:00
billz
b3c6178274 Accept $token object, pass to renderTemplate() 2025-03-25 05:22:29 -07:00
billz
a5907d8f7f Class loading handled by autoloader, objects instantiated by index.php 2025-03-25 05:21:35 -07:00
billz
8569c2b4d5 Remove CSRF related functions (made obsolete by Token class) 2025-03-25 05:17:58 -07:00
billz
2a70f6ee11 Replace csrf and explicit HTTPAuth includes with autoload.php 2025-03-25 05:15:34 -07:00
billz
c8b0408bd5 Refactor + fixup autoloader 2025-03-25 05:14:29 -07:00
Bill Zimmerman
125ae7a39a
Merge pull request #1810 from RaspAP/fix/php74-compatibility
Fix: php7.4 compatibility
2025-03-25 08:36:03 +01:00
billz
20fe5fc5a7 Fix: php7.4 compatibility 2025-03-24 23:58:30 -07:00
billz
168ed2448f Update release version 2025-03-24 01:51:08 -07:00
Bill Zimmerman
a2b8dfe551
Merge pull request #1806 from RaspAP/fix/fetch-update-response
Fix: Revise fetchUpdateResponse() and modal dialog
2025-03-24 09:45:33 +01:00
billz
4aee1e49d9 Revise fetchUpdateResponse() without endPolling flag 2025-03-24 01:37:16 -07:00
billz
16d92bb486 Set fa-check visible for updateStep1 2025-03-24 01:35:40 -07:00
billz
de376d04d1 Initial commit 2025-03-23 23:13:29 -07:00
Bill Zimmerman
d730c174d4
Update README.md 2025-03-24 06:29:58 +01:00
billz
c798f5fd69 Update BACKERS.md 2025-03-23 22:28:03 -07:00
Bill Zimmerman
3a73916206
Merge pull request #1805 from RaspAP/fix/connection-type
Update getConnectionType() regexes to match MAC-derived names
2025-03-24 06:24:33 +01:00
billz
f46be0139e Update getConnectionType() regexes to match MAC-derived names 2025-03-23 10:52:46 -07:00
Bill Zimmerman
a6295aef6e
Merge pull request #1799 from RaspAP/feat/dashboard-devices
Feature: Dashboard + System device illustrations
2025-03-23 17:51:20 +01:00
Bill Zimmerman
556c2be855
Merge pull request #1802 from RaspAP/fix/dhcp-settings-focus
Fix: Links to dhcp client-list tab
2025-03-23 17:51:05 +01:00
Bill Zimmerman
80e8178384
Update issue_form.yml 2025-03-23 17:13:44 +01:00
billz
b1c429f404 Fix: remove link to client-list tab 2025-03-23 08:45:21 -07:00
Bill Zimmerman
f0b992b9be
Merge pull request #1800 from RaspAP/fix/band-association
Fix: Update 802.11n band associations
2025-03-23 15:23:45 +01:00
billz
084b2e1268 Update 802.11n bands, resolves #1797 2025-03-23 07:22:15 -07:00
billz
0fd60e3730 Update device illustration w/ w/ $deviceImage 2025-03-23 07:18:55 -07:00
billz
cfc6644087 Merge branch 'master' into feat/dashboard-devices 2025-03-23 07:08:04 -07:00
Bill Zimmerman
2cd4abc3c2
Merge pull request #1798 from RaspAP/feat/tabbed-dashboard
Feature: Tabbed dashboard
2025-03-23 15:01:12 +01:00
Bill Zimmerman
8bd5b1b988
Merge pull request #1796 from RaspAP/feat/auth-enhancements
Feature: Auth enhancements
2025-03-23 15:00:57 +01:00
billz
2b8f7fd6d8 Initial commit 2025-03-23 02:18:50 -07:00
billz
b99addef4a Replace static device illustration w/ $deviceImage 2025-03-23 01:30:32 -07:00
billz
96ada80ce1 Update RPi models from latest revision codes 2025-03-23 01:28:51 -07:00
billz
5d33c79369 Return default if revision type not matched 2025-03-23 01:25:45 -07:00
billz
645ab89437 Update w/ getDeviceImage() 2025-03-23 01:22:54 -07:00
billz
62b342cdbb Set device image w/ getDeviceImage($revision) 2025-03-23 01:22:26 -07:00
billz
c235a4ff16 Create zero.php, move under /devices 2025-03-23 01:21:28 -07:00
billz
a24516a4d5 Tweak divDBChartBandwidthhourly 2025-03-23 00:33:27 -07:00
billz
483b1fc27d Split single template into tabs 2025-03-23 00:28:31 -07:00
billz
4d0de82986 Add &$extraFooterScripts to support data usage graph 2025-03-23 00:27:39 -07:00
billz
85663341eb Initial commit 2025-03-23 00:26:48 -07:00
billz
734043dee6 Define button object, add logout btn 2025-03-22 03:17:23 -07:00
billz
af2927f05b Update w/ qr code doc link 2025-03-22 03:16:53 -07:00
billz
3e54b1d7bb Remove authentication sidebar item (redundant) 2025-03-22 03:14:11 -07:00
billz
51a0ce220c Update w/ disableValidation() to support logout btn 2025-03-22 03:12:46 -07:00
billz
05e20e3bab Handle logout action 2025-03-22 03:12:09 -07:00
billz
03fc2c42ad Update w/ logout() method 2025-03-22 03:11:47 -07:00
billz
401172eb36 Initial commit 2025-03-22 03:11:03 -07:00
Bill Zimmerman
71f1132bc8
Update plugin_helper.sh 2025-03-20 18:50:02 +01:00
Bill Zimmerman
605486feda
Update w/ strict check on config destination path 2025-03-20 18:08:29 +01:00
Bill Zimmerman
23597e800d
Fix: Revert set permissions on $destination 2025-03-20 12:05:30 +01:00
Bill Zimmerman
3218d87b1b
Update dashboard screenshot 2025-03-20 11:13:32 +01:00
billz
0c58a6c92c Update release version 2025-03-20 03:11:31 -07:00
billz
afa3006de2 Minor: code cleanup 2025-03-20 02:54:30 -07:00
Bill Zimmerman
03b9bf9e7a
Merge pull request #1793 from RaspAP/maint/php-warnings
Resolves numerous PHP warnings
2025-03-20 10:35:58 +01:00
billz
028c0d3e06 Move template handling of wg_log to include/wireguard 2025-03-20 02:12:47 -07:00
billz
0005488884 Fix: Use null coalescing operator on $_POST object, fetch wg_log, set $peer_id 2025-03-20 02:12:00 -07:00
billz
f73f25708c Fix: Cleanup, resolve warnings in getWifiInterface() 2025-03-20 02:10:40 -07:00
billz
4e411aaa6b Fix: Use null coalescing operator on user_id 2025-03-20 02:09:39 -07:00
billz
6adeab7586 Fix: Evaluate HTTP_ACCEPT_LANGUAGE, check ['locale'] 2025-03-20 02:08:54 -07:00
billz
16f6b7f979 Fix numerous php warnings for undefined vars 2025-03-20 02:07:51 -07:00
billz
068f363f09 Remove obsolete toggleState functions, add file_exists() check 2025-03-20 02:06:11 -07:00
billz
d4554c6429 Update w/ getBridgedState() global function 2025-03-20 02:05:11 -07:00
billz
a3caa6485c Fix: Use null coalescing operator to prevent warnings 2025-03-20 02:04:40 -07:00
billz
795d55a2cd Fix: Sanitize $peer_conf before output to header 2025-03-20 02:04:00 -07:00
billz
c53c1a27a4 Fix: Specify global Exception class by adding backslash 2025-03-20 02:02:35 -07:00
Bill Zimmerman
903cc6bd8e
Merge pull request #1787 from RaspAP/maint/plugin-installer-keys
Updates PluginInstaller to handle signed third-party packages
2025-03-20 08:11:08 +01:00
Bill Zimmerman
13929acbd1
Merge pull request #1775 from RaspAP/fix/plugin-helper-config
Set permissions on parent directory when handling config files
2025-03-20 08:04:40 +01:00
Bill Zimmerman
f6da130fce
Merge pull request #1792 from RaspAP/fix/installer-submodules
Updates plugin submodules after cloning parent repo
2025-03-20 08:01:10 +01:00
billz
1fc793c3fd Exec git submodule update --remote plugins on $source_dir 2025-03-19 12:00:07 -07:00
Bill Zimmerman
4b6ac1a415
Merge pull request #1748 from RaspAP/feat/dashboard-redesign
Dashboard redesign
2025-03-19 17:02:48 +01:00
billz
304010db40 Update client lease ouput w/ human-readable timestamps 2025-03-18 12:28:06 -07:00
billz
66563c9d95 Update hrefs w/ tab param to load specific tabs on page load 2025-03-18 12:11:50 -07:00
billz
5eca4c045b Add event listener to activate tab on page load 2025-03-18 12:10:47 -07:00
billz
fd953e7a71 Remove obsolete svg file (replaced by device.php) 2025-03-18 08:56:32 -07:00
billz
52b20cb491 Revise getEthernetClients() w/ more robust method 2025-03-18 08:55:35 -07:00
billz
c987d2800d Fix php warning: define $firewallManaged 2025-03-18 08:54:47 -07:00
billz
6d6bacd6a1 Update en_US locale msgs + compile .mo 2025-03-18 04:12:34 -07:00
billz
f0a0c9228f Replace static labels w/ gettext() for locale support 2025-03-18 04:11:47 -07:00
billz
dfef9e5233 Define firewallManaged when Firewall plugin is installed 2025-03-18 03:23:25 -07:00
billz
ab77af9e5d Update firewallEnabled() config check 2025-03-18 03:22:03 -07:00
billz
5ce06c6214 Revise dashed svg stroke width, color 2025-03-18 03:20:46 -07:00
billz
d5cc80d1f2 Update en_US locale w/ new dashboard msgs + compile .mo 2025-03-18 02:15:09 -07:00
billz
e3f04192b8 Replace static labels w/ gettext() for locale support 2025-03-18 02:14:02 -07:00
billz
cfb8435373 Revise formatClientLabel() w/ ngettext 2025-03-18 02:13:14 -07:00
billz
615f2abed1 Minor: formatting 2025-03-18 01:45:56 -07:00
billz
ac926e84d7 Style tweak for fa-stack status-item 2025-03-18 01:45:38 -07:00
billz
8846b96905 Update function mappings for absolute paths 2025-03-18 01:45:10 -07:00
billz
677e99ffd9 Update w/ relevant href links, indicate active/inactive states 2025-03-18 00:57:04 -07:00
billz
a82b30179b Add device, clients active/inactive states 2025-03-18 00:55:56 -07:00
billz
ae4e9be739 Change default SSID to RaspAP (finally) 2025-03-18 00:53:59 -07:00
billz
7091a4016a Update media query to reflect markup changes, add .inactive 2025-03-18 00:53:29 -07:00
billz
24b292bf33 Replace static color values w/ --raspap-* vars 2025-03-17 11:42:20 -07:00
billz
c00f006cdd Migrate inline functions to class methods in RaspAP\UI 2025-03-17 11:41:22 -07:00
billz
ed47a41c9c Initial commit 2025-03-17 11:38:17 -07:00
billz
39cc92853a Set z-index for solid + dashed-lines 2025-03-17 10:32:32 -07:00
billz
34f7563bed Replace static placeholder with renderClientConnections 2025-03-17 10:25:04 -07:00
billz
964d7b38a8 Create getConnectionIcon(), renderClientConnections() 2025-03-17 10:24:32 -07:00
billz
17fbbca046 Create renderConnection(), update template 2025-03-17 07:33:37 -07:00
billz
64faf296a6 Apply dynamic theme color w/ rendered svg lines 2025-03-17 07:32:24 -07:00
billz
f1c404a443 Rename file to device.php 2025-03-17 07:09:10 -07:00
billz
5ed1312406 Revise getEthernetClients() w/ more robust method comparing arp + dhcp 2025-03-17 07:08:29 -07:00
billz
00c18451cc Replace static svg w/ device.php 2025-03-17 07:07:25 -07:00
billz
b737b5c748 Use dynamic theme color w/ device svg 2025-03-17 07:06:21 -07:00
billz
d852990314 Replace var raspap-brand-color w/ raspap-theme-color 2025-03-17 07:05:03 -07:00
billz
182073f41e Update placeholder values w/ template data + active route states 2025-03-17 06:04:02 -07:00
billz
64d3a11866 Create getConnectionType(), getWirelessClients() getEthernetClients() 2025-03-17 06:02:48 -07:00
billz
4865e85655 Various minor tweaks 2025-03-17 04:07:27 -07:00
billz
3d6095d652 Define buttons w/ ob_start(), network details block + wifi bands 2025-03-17 04:07:05 -07:00
billz
bd0e379d01 Create getActiveVpnInterface(), update revision strings 2025-03-17 04:05:23 -07:00
billz
93395a8aa5 Refactor DisplayDashboard() 2025-03-17 04:04:27 -07:00
billz
339437f47f Set hostapd_led to warn when status is down 2025-03-17 03:28:32 -07:00
billz
80db7edf18 Compatibility fix for php 7.4 2025-03-16 12:38:22 -07:00
Bill Zimmerman
41e86a9e51
Merge pull request #1789 from RaspAP/fix/installer-update
Fix for automated version update on About page
2025-03-16 14:01:59 +01:00
billz
ef04678947 Get installed plugins, add status checks for services 2025-03-16 03:33:10 -07:00
billz
1a964a283f Replace static hex values w/ css var, style tweaks 2025-03-16 03:30:26 -07:00
billz
6c47375d18 Create adBlockStatus() 2025-03-16 03:29:19 -07:00
billz
c2abce1e35 Add -p flag to mkdir in _create_plugin_scripts() 2025-03-16 01:11:21 -07:00
billz
b4b715f6e4 Add --check 0 option for update 2025-03-16 01:10:26 -07:00
billz
8a7c954d88 Cleanup interface statistics code (obsolete) 2025-03-16 01:04:48 -07:00
billz
639f7605d1 Template tweaks, update labels w/ gettext 2025-03-16 01:01:23 -07:00
billz
fbcf9809c5 Update hotspot icon > fa-bullseye 2025-03-15 16:00:27 -07:00
billz
2474765820 Add device illustration to system basic tab 2025-03-15 15:18:24 -07:00
Bill Zimmerman
ba4507bd22
Merge branch 'master' into feat/dashboard-redesign 2025-03-15 19:54:34 +01:00
billz
2610c44ac9 Adjust stroke-width, remove rect w/ fill for dark mode support 2025-03-15 11:34:49 -07:00
billz
f608282aa5 Define --raspap-text-light, replace hex colors w/ vars, tweaks 2025-03-15 11:33:03 -07:00
billz
781f376bea Standardize revision descriptions 2025-03-15 11:31:59 -07:00
Bill Zimmerman
6e1c3b95c2 Revise dashed .svg files 2025-03-15 17:44:31 +01:00
billz
0331eb7b25 Minor: suppress debug output from key install 2025-03-15 00:59:36 -07:00
billz
c3a210907a Throw exception for invalid key structure, update messages 2025-03-15 00:58:53 -07:00
billz
3e0f1f16c1 Revise installRepositoryKeys() w/ array of key data 2025-03-14 11:37:47 -07:00
billz
c2be25271b Update w/ signed packages from manifest 2025-03-14 11:36:17 -07:00
billz
bb131a7f53 Revise key handling with parameters for url, keyring, repo + list 2025-03-14 11:35:30 -07:00
billz
c753865305 Added handling for GPG keys to enable third-party apt repos 2025-03-14 03:36:43 -07:00
billz
0bac7deccc Define helperScriptPath, create installRepositoryKeys() 2025-03-14 03:35:32 -07:00
Bill Zimmerman
9ada9f9e68
Merge pull request #1777 from RaspAP/maint/php-warnings
Fix PHP warning in getProviderValue()
2025-03-08 10:09:35 +00:00
billz
02b9e20ce3 Use ?? to avoid undefined key warnings 2025-03-02 00:24:57 -08:00
billz
3c8cf996b5 Set permissions on parent directory 2025-03-02 00:10:43 -08:00
Bill Zimmerman
313e2eb06f
Update issue_form.yml 2025-03-01 08:18:54 +01:00
Bill Zimmerman
41fcbba5cc
Update README.md 2025-02-23 14:30:10 +01:00
Bill Zimmerman
ce9916a792
Update README.md 2025-02-23 14:21:58 +01:00
Bill Zimmerman
3f830458b1
Update issue_form.yml 2025-02-23 09:32:02 +01:00
billz
a8e24b7629 Update release version 2025-02-21 09:07:12 -08:00
billz
80f5cb5f46 Set plugins submodule to track master 2025-02-21 05:25:59 -08:00
billz
d45aa752c6 Set plugins submodule to track master 2025-02-21 05:16:45 -08:00
billz
2a1e39a880 Update release version 2025-02-21 05:03:10 -08:00
Bill Zimmerman
8f402ab303
Merge pull request #1763 from RaspAP/maint/plugin-installer
PluginInstaller improvements + fixes
2025-02-21 09:16:29 +01:00
Bill Zimmerman
644d2fe6cb
Update BACKERS.md 2025-02-21 08:02:56 +01:00
billz
b3fe781c19 Prepend this->rootPath if not absolute path 2025-02-19 06:03:07 -08:00
billz
69510a4e92 Set owner after copying dependencies 2025-02-19 06:00:32 -08:00
billz
163d727ee1 Fix: re-add copyPluginFiles() 2025-02-19 01:47:20 -08:00
billz
20fdd9024d Added safeOutputValue() 2025-02-19 01:25:07 -08:00
billz
23e0a6601a Fix: replace dirname var w/ destination param 2025-02-19 01:06:57 -08:00
billz
47d0305bec Revise installPlugin() to use plugins-available, fix copyJavaScriptFiles 2025-02-19 01:05:51 -08:00
billz
f28c5533bc Update pluginConfirm btn actions 2025-02-19 01:02:56 -08:00
billz
b89fe7c6b8 Set install_path, revise parameters used w/ installPlugin() 2025-02-19 01:02:04 -08:00
Bill Zimmerman
71ed223cf5
Merge pull request #1764 from juliovegap/master
Bug #1762
2025-02-19 08:47:52 +01:00
billz
335491124f Add install_path to ajax handler, various fixes + improvements 2025-02-18 09:00:49 -08:00
billz
e45c00b83c Create getRepository(), extend to installed & available plugins 2025-02-18 08:57:04 -08:00
billz
aa5fcef2d4 Add additional field to template, change source -> doc link 2025-02-18 08:55:52 -08:00
billz
01ddf6f4ea Update plugin details w/ javascript, default to none 2025-02-18 01:16:16 -08:00
juliovegap
bbac9a8802
Bug #1762
New versions of 'iw phy#0 info' provides frequencies output with decimals #1762. IW Parser patched to handle this new output format
2025-02-17 20:20:13 +01:00
billz
4374e78bbb Add JavaScript handling to installPlugin(), fix bug w/ manifest parsing 2025-02-17 02:35:42 -08:00
billz
6e0cf0b085 Update w/ javascript support 2025-02-17 02:34:20 -08:00
Bill Zimmerman
867a46bee9
Merge pull request #1757 from RaspAP/maint/version-motd
Fetch RaspAP version and set MOTD
2025-02-13 08:07:02 +01:00
Bill Zimmerman
4a89cb3b07
Update README.md 2025-02-13 07:59:38 +01:00
Bill Zimmerman
dc86f15b59
Update README.md 2025-02-12 23:45:26 +01:00
Bill Zimmerman
91c535ddbb
Update README.md 2025-02-12 23:41:33 +01:00
Bill Zimmerman
f576b02858
Update README.md 2025-02-12 23:20:49 +01:00
billz
eb27ba2c66 Fetch RaspAP version and set MOTD 2025-02-12 08:30:33 -08:00
billz
362a08c00f Update release version 2025-02-09 00:54:27 -08:00
Bill Zimmerman
43ae90bd34
Merge pull request #1754 from RaspAP/maint/release-naming
Update naming to reflect clarity in arch, OS + purpose
2025-02-09 09:51:25 +01:00
billz
c34cbeca8d Exec raspi-config noint do_wifi_country 2025-02-09 00:46:27 -08:00
billz
33f66fdae5 Update naming to reflect clarity in arch, OS + purpose 2025-02-08 10:52:26 -08:00
Bill Zimmerman
cc9720e8ef
Merge pull request #1752 from RaspAP/maint/installer-option
Adds -k --check option to install loader
2025-02-08 13:02:34 +01:00
Bill Zimmerman
74b1b10e31
Merge pull request #1753 from RaspAP/maint/release-check-flag
Specify --check 0 to skip connectivity check
2025-02-08 13:02:01 +01:00
billz
41ce72775e Set default repo at top of _main() 2025-02-08 01:41:43 -08:00
billz
9876ab1e3e Specify --check 0 to skip connectivity check 2025-02-08 01:22:52 -08:00
billz
bd0b226f61 Adds -k --check option to install loader 2025-02-08 01:18:47 -08:00
billz
3417115a84 Update release version 2025-02-08 00:11:43 -08:00
billz
7a880d563f Add _create_plugin_scripts to _update_raspap() 2025-02-07 23:48:30 -08:00
Bill Zimmerman
32e191e55d
Merge pull request #1717 from RaspAP/feat/plugin-manager
Plugin Manager UI
2025-02-08 08:31:07 +01:00
Bill Zimmerman
58501a74a7
Merge pull request #1750 from neo773/bs-redeisgn
feat: Dashboard redesign
2025-02-07 10:29:37 +01:00
neo773
80c1a04797
feat: dashboard redesign 2025-02-07 13:41:23 +05:30
billz
af3abe66f4 Initial commit 2025-02-06 02:44:37 -08:00
billz
8a8be213f7 Display plugins in monitor mode, suppress details dialog 2025-02-04 23:45:06 -08:00
billz
0efbe2b326 Define RASPI_PLUGINS_ENABLED, add condition to template 2025-02-04 23:44:04 -08:00
Bill Zimmerman
624e43f954
Merge pull request #1747 from rjdjohnston/fix/increase-curl-timeout
fix: Increase curl max-time to 15 seconds for connectivity check
2025-02-04 08:12:26 +01:00
RJ Johnston
55b6c81eca fix: Increase curl max-time to 15 seconds for connectivity check 2025-02-03 18:31:59 -05:00
Bill Zimmerman
aa49dcf32c
Merge pull request #1740 from RaspAP/feat/install-loader-check
Adds _check_internet() to install loader
2025-02-03 11:52:27 +01:00
Bill Zimmerman
10d5c4a8a6
Merge pull request #1745 from RaspAP/fix/armbian-dependencies
Install ARM 64- or 32-bit isoquery from Debian pkg (Armbian)
2025-02-03 11:51:15 +01:00
billz
2f205fe9e4 Install ARM 64- or-32 bit isoquery from Debian pkg (Armbian) 2025-02-03 01:33:32 -08:00
billz
6b7b8ef8d0 Refine API response condition 2025-02-03 00:20:03 -08:00
billz
a9804b2f9c Update _get_release() w/ API rate limit and undefined release var check 2025-02-02 03:08:35 -08:00
Bill Zimmerman
484d40f455
Update issue_form.yml 2025-02-01 19:31:47 +01:00
billz
18114df2bd Define component 2025-01-30 00:39:16 -08:00
billz
e61dac332c Add _check_internet() function. Resolves #1729 2025-01-30 00:08:59 -08:00
Bill Zimmerman
b9842b5462
Merge pull request #1739 from RaspAP/fix/debug-log
Fix quoting for dnsmasq_info()
2025-01-30 08:23:56 +01:00
billz
739057c7ac Fix quoting for dnsmasq_info(). Resolves #1738 2025-01-29 23:19:28 -08:00
Bill Zimmerman
d689024c1f
Merge pull request #1690 from Dhanus3133/ci/build-images
ci: build 32 bit and 64 bit images
2025-01-28 14:34:17 +01:00
Dhanus
c1975a78a1 chore: Use pi-gen fork 2025-01-28 15:29:42 +05:30
billz
5fbafeb455 Re-add plugins submodule 2025-01-27 04:49:31 -08:00
billz
7def2d6da1 Remove plugins/ to allow submodule usage 2025-01-27 04:43:01 -08:00
billz
538e37ceb7 Add --recurse-submodules to git clone operation 2025-01-27 04:29:07 -08:00
Bill Zimmerman
5d01fa59b1
Fix for DOM text reinterpreted as HTML
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-01-26 11:50:33 +01:00
billz
0b0f4bc06d Update plugin installed check 2025-01-26 02:45:47 -08:00
Bill Zimmerman
a619e7a25b
Merge branch 'master' into feat/plugin-manager 2025-01-26 10:33:49 +01:00
billz
a8bd85cc80 Create textarea.plugin-log class 2025-01-26 01:32:18 -08:00
billz
e423b7f4d3 Display diagnostic error message on plugin install fail 2025-01-26 01:31:40 -08:00
billz
47c509277c Add checks for empty vars, improve error propagation 2025-01-26 01:25:12 -08:00
billz
a6fdb63dd2 Catch HTTP 442 unprocessable content response 2025-01-26 01:23:42 -08:00
billz
75bb3e4a34 Resolve conflict: update .mo from master + ignore 2025-01-25 09:48:58 -08:00
billz
36c3e5036f Ignore compiled .mo files 2025-01-25 09:42:17 -08:00
billz
a9021c89f4 Refactor getUserPlugins(), define pluginsManifest 2025-01-25 02:49:48 -08:00
billz
77f183817a Replace try/catch callback w/ simplified JSON parsing 2025-01-25 02:48:52 -08:00
billz
97bc8174b4 Add include/session.php 2025-01-25 02:47:46 -08:00
billz
83ed9b5c19 Remove RASPI_PLUGINS_URL (obsolete) 2025-01-25 02:47:03 -08:00
billz
0871601b31 Initial commit 2025-01-25 02:46:34 -08:00
billz
eb25142e03 Update release version 2025-01-22 23:52:05 -08:00
billz
42b6c8fce3 Fix: correctly evaluate session status 2025-01-22 07:38:36 -08:00
Bill Zimmerman
7a9e5169f6
Merge pull request #1735 from RaspAP/feat/session-manager
Feature: Session manager & dedicated login
2025-01-22 15:11:30 +01:00
billz
2ca7448bd3 Define RASPI_BRAND_TITLE, replace static title 2025-01-22 00:46:00 -08:00
billz
cd3fde71e3 Revise login background gradient 2025-01-22 00:35:52 -08:00
billz
ec0dd304ee Add csrf token check, destroy session on timeout 2025-01-22 00:11:22 -08:00
billz
50ed5f9f4b Update en_US locale w/ new msgs, compile .mo 2025-01-21 05:36:13 -08:00
billz
259fac717f Update static label with RASPI_BRAND_TEXT 2025-01-21 05:35:34 -08:00
billz
0fd65fdbc2 Minor: mode change 2025-01-21 05:23:42 -08:00
billz
2b92d028f6 Minor: define status + redirectUrl vars 2025-01-21 05:23:19 -08:00
billz
9c4f8be363 Fix: include session 2025-01-21 05:22:22 -08:00
billz
21b9feb0ef Refactor auth method: http basic > user login 2025-01-21 05:14:18 -08:00
billz
bc7d4ef1c1 Include session in ajax handlers 2025-01-21 04:59:57 -08:00
billz
bc23dfc130 Remove timeout_duration from response 2025-01-21 04:55:56 -08:00
billz
9042ee8c01 Pass redirectUrl as action to login 2025-01-21 00:38:03 -08:00
billz
effcb5e48e Add global styles for login page 2025-01-21 00:35:27 -08:00
billz
111c9581a3 Resolve hash_equals() error w/ expired csrf_token, add login redirect 2025-01-21 00:33:24 -08:00
billz
6cb0be96b4 Set data-bs-backdrop + data-bs-keyboard attributes 2025-01-21 00:31:49 -08:00
billz
6dbdf89760 Add DisplayLogin() page handler 2025-01-21 00:30:40 -08:00
billz
792ce0c956 Include login.php, buffer page output 2025-01-21 00:29:59 -08:00
billz
3f883a70de Initial commit 2025-01-21 00:29:14 -08:00
billz
187041b030 Add checkSession(), showSessionExpiredModal() 2025-01-20 00:58:18 -08:00
billz
c51b520b8d Decouple session from csrf handler, set initial lastActivity 2025-01-20 00:55:21 -08:00
billz
866d8eb5b0 Update w/ sessionTimeoutModal, lastActivity 2025-01-20 00:53:26 -08:00
billz
3cf22a9cbb Define RASPI_SESSION_TIMEOUT 2025-01-20 00:52:28 -08:00
billz
6f1c34f28d Initial commit 2025-01-20 00:51:00 -08:00
Bill Zimmerman
41a138026b
Merge pull request #1733 from RaspAP/fix/dhcp-ignore
Set dhcp-ignore=tag:!known from option switch
2025-01-19 09:55:57 +01:00
billz
0c31b5ba71 Set dhcp-ignore=tag:!known from option switch 2025-01-19 00:23:06 -08:00
billz
2bab11b951 Update callbackTimeout interval, error msg 2025-01-19 00:18:56 -08:00
billz
b52bd84ea4 Add msgs to en_US locale + compile .mo 2025-01-05 02:15:16 -08:00
billz
ff7e674b2e Use callbackTimeout w/ getUserPlugins(), handle err if >2000ms 2025-01-05 02:14:16 -08:00
billz
3e91f50966 Create callbackTimeout() 2025-01-05 02:12:45 -08:00
billz
7dcc177424 Initial commit 2025-01-04 09:33:01 -08:00
Bill Zimmerman
94b502a336
Merge pull request #1724 from RaspAP/fix/adblock-update-ui
Revise bootstrap 5.3 adblock update btn
2025-01-03 00:49:38 -08:00
billz
bfd5859ce1 Revise bootstrap 5.3 adblock update btn 2025-01-03 00:38:45 -08:00
Bill Zimmerman
13cdfbd8cb
Merge pull request #1723 from RaspAP/fix/wg-endpoint-seg
Extends wg peer validation to dynamic addresses
2025-01-01 01:22:46 -08:00
billz
531970d9c6 Extend wg peer endpoint validation w/ subdomain + hostname 2025-01-01 00:41:56 -08:00
billz
5902a8d6a0 Update template + wg-keygen js handler 2025-01-01 00:37:25 -08:00
billz
9bb2075b77 Add strings to en_US locale, update template 2024-12-26 09:41:52 -08:00
billz
3c61954971 Minor: update label 2024-12-26 09:17:33 -08:00
billz
361a2f7531 Use text() instead of replaceWith() 2024-12-26 09:17:12 -08:00
billz
ad36695224 Set/read plugin-installed flag 2024-12-26 08:04:16 -08:00
billz
92ba7df9c6 Create plugin install event handler 2024-12-25 19:03:41 -08:00
billz
ae7b03857e Update install-plugin-progress modal btn 2024-12-25 19:00:41 -08:00
billz
2c0ace4500 Fix for getUserPlugins, add installed btn 2024-12-25 18:59:49 -08:00
billz
759e5dcf5d Add _create_plugin_scripts() 2024-12-25 18:57:59 -08:00
billz
bf0d9f88e2 Implement installPlugin() and related methods 2024-12-25 13:08:32 -08:00
billz
bf74ff7057 Update w/ config, plugin actions 2024-12-25 12:27:47 -08:00
billz
4328f54270 Add visudo -cf, plugin_helper to sudoers 2024-12-24 22:48:21 -08:00
billz
efd67fb698 Add plugin install progress modal 2024-12-24 22:46:17 -08:00
billz
44c99dacdf Initial commit 2024-12-24 22:45:18 -08:00
Bill Zimmerman
048d4ab3e6
Merge pull request #1720 from GuillaumeRossolini/patch-1
Update README.md
2024-12-23 14:53:46 -08:00
Guillaume Rossolini
801ca5a788
Update README.md
Replaced dead link for SSL certificates
2024-12-23 18:00:00 +01:00
billz
e5987a6b59 Update w/ link to plugin_uri 2024-12-22 09:27:40 -08:00
billz
2cb66660c5 Create modal install-user-plugin dialog, update template text 2024-12-21 22:42:34 -08:00
billz
c3968ba42e Encapsulate plugin related functions in PluginInstaller class 2024-12-21 22:40:55 -08:00
billz
edb86d7781 Populate #install-user-plugin modal dialog 2024-12-21 22:39:17 -08:00
billz
6785cc1104 Move getPluginManifest() to PluginInstaller class 2024-12-21 10:40:41 -08:00
billz
ee38614334 Initial commit 2024-12-21 10:39:46 -08:00
billz
9b087f88a7 Call PluginInstaller::getInstance(), set install option 2024-12-20 18:53:35 -08:00
billz
247b35b254 Initial commit 2024-12-20 18:52:09 -08:00
billz
89c4f16e45 Get plugin submodules, fetch manifest details + format output 2024-12-20 13:42:53 -08:00
billz
117370efcf Add plugins tab, render system/plugins template 2024-12-20 13:34:58 -08:00
billz
66e35c564c Initial commit 2024-12-20 13:34:05 -08:00
billz
36b0285158 Define RASPI_PLUGINS_URL 2024-12-20 13:33:46 -08:00
billz
07ec56227d Minor: mode change 2024-12-20 11:45:54 -08:00
billz
cf78f5dc94 Update release version 2024-12-17 17:16:22 -08:00
Bill Zimmerman
daa6bfd460
Merge pull request #1716 from RaspAP/fix/multiple-configs
Fix for updated bootstrap5.3 btn class
2024-12-17 16:56:17 -08:00
billz
6a85ac9b93 Fix for updated bootstrap5.3 btn class 2024-12-17 16:44:07 -08:00
billz
cc85c556a1 Update release version 2024-12-17 13:25:12 -08:00
Bill Zimmerman
80be4d34af
Merge pull request #1714 from RaspAP/fix/dhcp-roundup
Roundup of fixes for DHCP handling
2024-12-17 13:15:55 -08:00
billz
3898b82287 Fix remaining dhcp undefined array key warnings 2024-12-17 11:32:50 -08:00
billz
26c64d42e6 Fix php warnings w/ null coalescing operator for $_POST keys 2024-12-16 18:39:33 -08:00
billz
168dd18679 Fix template bug when upstream server is defined 2024-12-16 18:21:20 -08:00
billz
b7a6d334e3 Fix ParseConfig() handling of name-only options, thx @meandthemachine 2024-12-16 18:19:15 -08:00
billz
f811d21dc7 Resolve undefined array key php warnings 2024-12-16 17:56:41 -08:00
billz
26bd632bab Resolve php warnings w/ null coalescing operator 2024-12-16 17:54:17 -08:00
billz
5020e8b5a0 Resolve php warnings on undefined vars 2024-12-16 17:52:31 -08:00
Bill Zimmerman
b5179f3991
Merge pull request #1710 from RaspAP/maint/cidr-mask-notion
Add form-control support for CIDR masks
2024-12-11 20:47:55 +01:00
billz
86e8b208e0 Add form-control support for CIDR masks 2024-12-11 09:18:33 -08:00
Bill Zimmerman
a7ac30f548
Merge pull request #1707 from RaspAP/maint/attribution
Update w/ code attribution - thx @easylo
2024-12-07 08:33:53 +01:00
billz
7684a4932d Update w/ code attribution - thx @easylo 2024-12-06 01:22:28 -08:00
billz
4d1b746932 Update release version 2024-11-28 01:38:42 -08:00
Bill Zimmerman
dc922bab30
Merge pull request #1704 from RaspAP/feat/adguard-provider
Add VPN provider support for AdGuard
2024-11-28 10:28:04 +01:00
billz
66f5cd4183 Create stripAnsiSequence() 2024-11-27 23:19:41 -08:00
billz
50d0e0be82 Sanitize CLI output, fetch provider details after page functions 2024-11-27 00:41:24 -08:00
billz
83d9248249 Update Adguard regex + cmd_overrides 2024-11-27 00:36:32 -08:00
billz
72475b16ef Remove ANSI escape sequences w/ stripArtifacts() 2024-11-26 14:30:14 -08:00
billz
12b0d9f6c8 Append automatic yes answer to questions on connect 2024-11-26 01:43:46 -08:00
billz
68d47f9a41 Process Adguard cmd output 2024-11-26 01:23:20 -08:00
billz
4bba3384e4 Update w/ Adguard VPN 2024-11-26 01:22:42 -08:00
Bill Zimmerman
0e39896f3d
Merge pull request #1701 from RaspAP/fix/nogateway-default
Adds a nogateway option to wlan0 in default config
2024-11-19 10:06:34 +01:00
billz
90bac7f10f Add nogateway option to wlan0, resolves #1695 2024-11-17 01:02:14 -08:00
Bill Zimmerman
0e6f0f6df7
Merge pull request #1699 from RaspAP/maint/translations
Updates ko_KR locale 100% translated
2024-11-15 09:39:18 +01:00
billz
7037214f23 Update ko_KR locale 100% translated - thx @Dansunmi! 2024-11-14 02:30:52 -08:00
Bill Zimmerman
6294a620c0
Add custom plugin subsection 2024-11-14 08:57:51 +01:00
Bill Zimmerman
1ce4c207a6
Update supported distros 2024-11-14 08:45:28 +01:00
Bill Zimmerman
88806ec01a
Update BACKERS.md 2024-11-12 12:54:05 +01:00
billz
a4b26da5ec Update release version 2024-11-10 00:17:30 -08:00
Bill Zimmerman
b74db9464e
Merge pull request #1693 from RaspAP/feat/plugin-architecture
Plugin architecture to support user add-ons
2024-11-10 09:15:11 +01:00
billz
6fa4f3d5a6 Minor: code cleanup 2024-11-10 00:02:47 -08:00
billz
6e5ef8a866 Fixup callable conditions passed to addItem() 2024-11-08 04:10:55 -08:00
billz
4e71a6e753 Fix: evaluate pluginName in renderTemplate 2024-11-08 03:31:22 -08:00
billz
b33ac6ffa3 Revise handlePageAction for multiple plugin instances 2024-11-07 23:25:19 -08:00
billz
ce72d2a0ab Update interface with renderTemplate() method 2024-11-07 10:23:34 -08:00
billz
39a8a58f38 Fix handlePageAction for multiple plugin instances, move renderTemplate to plugins 2024-11-07 10:23:10 -08:00
billz
0bcc396b78 Minor: formatting 2024-11-07 01:19:08 -08:00
billz
04a6d007fd Consolidate handlePageAction in plugin class, remove functions.php from plugin 2024-11-07 00:44:06 -08:00
billz
7d4e6c1eaa Add plugins/ to .gitignore 2024-11-06 00:54:28 -08:00
billz
05126fbbf8 Fix system sidebar item page action 2024-11-05 18:34:31 -08:00
billz
3c59ce9d7e Remove includes/plugins (test) 2024-11-05 18:33:24 -08:00
billz
63924c26ac Revise handlePageAction() + getInstalledPlugins() 2024-11-05 18:27:24 -08:00
billz
3a19ed9c3d Check for plugin to handle request, fallback to core page actions 2024-11-05 18:24:41 -08:00
billz
3af68ca9a9 Create getClassName(), update renderTemplate() 2024-11-05 18:21:31 -08:00
billz
2ec0738455 Require plugins include 2024-11-05 09:14:58 -08:00
billz
316543cfa7 Removed (deprecated) 2024-11-05 09:14:24 -08:00
billz
6b3455345d Refactor to use PluginManager public methods 2024-11-05 09:13:37 -08:00
billz
8021099f49 Create renderStatus() 2024-11-05 09:12:42 -08:00
billz
262ff6a00e Initial commit 2024-11-05 09:12:19 -08:00
Bill Zimmerman
a86c637f04
Update README.md 2024-11-03 10:36:16 +01:00
Bill Zimmerman
4d208d0bf9
Update screenshots 2024-11-03 10:34:50 +01:00
billz
fbf3129ef4 Update release version 2024-11-03 01:08:04 -08:00
Bill Zimmerman
80d2e6b801
Merge pull request #1682 from RaspAP/maint/bootstrap5.3
Upgrade Bootstrap to v5.3.3
2024-11-03 10:05:32 +01:00
Dhanus
8ae468376f fix: enable all flags and install missing packages 2024-11-02 22:19:01 +05:30
Dhanus
90794c8828 fix: disable all options 2024-11-01 18:08:34 +05:30
Dhanus
28d1395bef chore: fail-fast false for 32 bit image build to finish 2024-11-01 12:17:55 +05:30
Dhanus
8048fcf5c4 chore: add apt-get update 2024-10-31 19:00:59 +05:30
Dhanus
710a8dab4e chore: add curl installation 2024-10-31 18:28:26 +05:30
Dhanus
274b42d225 chore: add custom stage 2024-10-31 18:20:25 +05:30
Dhanus
69d58f4713 chore: revert to previous commit due to extracted image size > 2GB
This reverts commit a1b0ade0a5.
2024-10-31 18:00:49 +05:30
Dhanus
d90ccf4277 fix: upload img instead of zip 2024-10-31 17:27:45 +05:30
Dhanus
a1b0ade0a5 chore: remove system update 2024-10-31 17:15:18 +05:30
Dhanus
f1a5b9163b fix: asset_name file type 2024-10-31 17:12:17 +05:30
Dhanus
cb4fc2ac54 ci: Add build for 32/64 bit images 2024-10-31 17:10:50 +05:30
billz
0a32215b39 Roundup template changes, update en_US locale + compile .mo 2024-10-31 00:19:53 -07:00
billz
f7e8f4d6eb Template tweaks 2024-10-30 10:26:59 -07:00
billz
40a526f217 Update release version 2024-10-29 09:54:24 -07:00
Bill Zimmerman
cf529fa0fb
Update BACKERS.md 2024-10-29 14:33:48 +01:00
Bill Zimmerman
54cf3132ad
Merge pull request #1686 from RaspAP/fix/check-tcp-bbr-available
Fix: Case insensitive modinfo return value check
2024-10-29 10:19:39 +01:00
billz
2f4680bc23 Update _check_tcp_bbr_available() case insensitive 2024-10-29 02:14:06 -07:00
billz
a12c3ce384 Style tweak 2024-10-29 02:11:49 -07:00
Bill Zimmerman
f1e093404c
Merge branch 'master' into maint/bootstrap5.3 2024-10-28 17:35:58 +01:00
Bill Zimmerman
9e52cda593
Merge pull request #1684 from RaspAP/fix/fallback-static-enabled
Add event listener to chkfallback, enable/disable static IP fields
2024-10-28 17:32:47 +01:00
billz
54a90353f8 Add event listener to chkfallback, enable/disable static IP fields 2024-10-28 00:28:59 -07:00
billz
13b894d411 Style tweaks + misc fixes 2024-10-27 00:05:45 -07:00
billz
95b44aed5e Apply common class styles to all.css, minor tweaks 2024-10-26 06:47:10 -07:00
billz
7e1fd32edc Define custom variables, set theme color + variants 2024-10-26 04:52:31 -07:00
billz
3004ce49cc Replace lightsout.php w/ dark.css, set data-bs-theme 2024-10-26 03:17:52 -07:00
billz
eb3873ac3f Initial commit 2024-10-26 03:16:30 -07:00
billz
23dbbd8ea8 Create setTheme() update night-mode switch + apply dark.css 2024-10-26 03:15:43 -07:00
billz
80fbb9aaed Update input-group fontawesome icons 2024-10-26 01:16:09 -07:00
billz
6c20740ffd Upgrade font-awesome to v6.6 2024-10-26 00:45:53 -07:00
billz
4876d3f04a Tweak system info-item layout 2024-10-25 02:45:53 -07:00
billz
61ca5d31be Update external link targets 2024-10-25 02:23:57 -07:00
billz
26d2f244f9 Template layout + compatibility tweaks 2024-10-25 02:19:17 -07:00
billz
b9c7108fd7 Replace inline styles w/ fontawesome 5 brand classes 2024-10-25 02:18:42 -07:00
billz
2d4960a3ab Update data-toggle with bsTarget 2024-10-25 02:17:43 -07:00
billz
80aca6a971 Global style tweaks 2024-10-25 01:19:44 -07:00
billz
bc1c7803e0 Revise/fixup tooltips 2024-10-25 01:19:19 -07:00
billz
6ee1b84489 Update hackernews theme 2024-10-25 01:03:09 -07:00
billz
ce46f87459 Remove material light/dark themes (deprecated) 2024-10-25 01:02:09 -07:00
billz
8087ae3ab1 Update deprecated input-group-append class 2024-10-25 01:00:58 -07:00
billz
c928629fc6 Revise layout of btn-group 2024-10-25 00:06:34 -07:00
billz
f9c91c2125 Process custom.js with bootstrap5-migration-tool 2024-10-25 00:05:29 -07:00
billz
c74c4deb63 Update alert classes 2024-10-25 00:03:31 -07:00
billz
6cd18ad571 Create footer.php 2024-10-25 00:02:38 -07:00
billz
9a1d362d30 Update chkstatic/chkdhcp radio btns classes 2024-10-24 23:13:14 -07:00
billz
87f95ab9f9 Apply theme color to form-check-input 2024-10-24 23:10:46 -07:00
billz
29ca176e49 Move nav elements to footer, style tweaks 2024-10-24 10:33:40 -07:00
billz
4e76445dab Apply text-secondary to logoutput 2024-10-24 10:30:53 -07:00
billz
063a2b1eaf Style tweaks 2024-10-24 06:49:23 -07:00
billz
ec11a527d7 Card border-radius fix for bg-dark 2024-10-24 06:06:04 -07:00
billz
177f42e12b Revise info-* column layout 2024-10-24 05:52:35 -07:00
billz
e00b2fcfde Update class name for selects 2024-10-24 02:20:34 -07:00
billz
7ddf16da6a Add .heart class + keyframes 2024-10-24 02:16:12 -07:00
billz
3dbc83e635 Update footer links 2024-10-24 02:15:09 -07:00
billz
4860b237a1 Update .sb-nav* .sb-sidenav* .sb-topnav* classes 2024-10-24 00:15:27 -07:00
billz
3f8dea4053 Updated for bootstrap 5.3.x 2024-10-24 00:13:44 -07:00
billz
363bcba144 Revise w/ updated sb-admin, bootstrap classes 2024-10-24 00:13:00 -07:00
billz
4f14502bac Upgrade bootstrap + sb-admin to latest release versions 2024-10-24 00:08:02 -07:00
billz
4799825738 Process templates w/ bootstrap-5-migrate-tool 2024-10-24 00:06:13 -07:00
Bill Zimmerman
bf22668284
Merge pull request #1680 from warpdesign/fix-passphrase-with-equal-character
Use sed instead of grep+cut to capture the passphrase
2024-10-22 18:49:49 +02:00
Nicolas Ramz
0bb8a5400e Use sed instead of grep+cut to capture the passphrase
Current method would crop any passphrase containing an '=' sign.

For eg. wpa_passwphrase=Foo=Bar would return 'Foo' instead of 'Foo=Bar'.
2024-10-22 17:27:31 +02:00
Bill Zimmerman
ba0bff9b9c
Merge pull request #1671 from RaspAP/fix/passphrase-htmlchars
Output passphrase w/ htmlspecialchars()
2024-10-06 11:45:17 +02:00
billz
5f8f91e7e4 Output passphrase w/ htmlspecialchars() 2024-10-06 02:33:51 -07:00
billz
246fd32058 Update release version 2024-09-27 01:10:32 -07:00
Bill Zimmerman
5fa8107fe7
Merge pull request #1667 from RaspAP/maint/translations
Update translations
2024-09-27 10:03:20 +02:00
Bill Zimmerman
20ce71070c
Merge pull request #1666 from RaspAP/feat/hostapd-userconf
Add support for custom hostapd.conf.users file
2024-09-27 10:02:35 +02:00
billz
7ad71a916d Update translations + compile .mo 2024-09-27 00:29:10 -07:00
billz
5b88728ec1 Create function parseUserHostapdCfg() 2024-09-26 04:17:34 -07:00
billz
677fe42d84 Add support for custom hostapd.conf.users file 2024-09-26 01:36:13 -07:00
Bill Zimmerman
56e5f6f778
Merge pull request #1662 from RaspAP/fix/escapeshell-ovpncfg
Apply escapeshellarg to OpenVPN auth + client configs
2024-09-20 09:11:23 +02:00
billz
74c7fb8c7a Apply escapeshellarg to OpenVPN auth + client configs 2024-09-20 09:06:43 +02:00
Bill Zimmerman
3889e2f04d
Merge pull request #1660 from RaspAP/fix/tcp-bbr-modprobe-intree
Revise tcp_bbr check method
2024-09-14 11:36:33 +02:00
billz
fa42e0c3f1 Revise tcp_bbr check method, resolves #1656 2024-09-14 11:17:43 +02:00
billz
57199def06 Update release version 2024-08-18 09:45:44 +02:00
Bill Zimmerman
85c38f2a9a
Merge pull request #1639 from RaspAP/feat/installer-tcp-bbr
Adds TCP BBR configuration option to installer
2024-08-18 08:42:32 +02:00
billz
8f033e5920 Add failure check to execute sysctl 2024-08-17 10:34:34 +02:00
billz
0e31670d25 Add TCP BBR configuration option to installer, addresses #1624 2024-08-17 10:26:28 +02:00
billz
d9f1a4dcfe Update release version 2024-08-11 09:39:10 +02:00
billz
9543587786 Improve OpenVPN logging, thx @frankozland 2024-08-11 09:38:57 +02:00
Bill Zimmerman
a5e2d832ef
Merge pull request #1635 from RaspAP/fix/nordvpn-cli
Update parsing of NordVPN countries, fixes #1634
2024-08-10 19:30:02 +02:00
billz
484820f324 Update parsing of NordVPN countries, fixes #1634 2024-08-10 19:25:54 +02:00
billz
90d63a679d Update release version 2024-08-03 08:22:21 +02:00
Bill Zimmerman
3a5766dcc0
Merge pull request #1630 from RaspAP/sec/restapi-svc
Security: set restapi.service file ownership
2024-08-03 08:16:15 +02:00
billz
4afd67f0b0 Add status message 2024-08-03 08:10:45 +02:00
billz
0f78411efe Set root owner on installers/restapi.service 2024-08-02 20:25:37 +02:00
Bill Zimmerman
98c2a7cb34
Merge pull request #1627 from daniel-rose/bugfix/handle-open-wifi-correctly
fix: handle open wifi in `setKnownStationsWPA` correctly
2024-08-02 19:05:06 +02:00
Daniel Rose
534b4df01a fix: handle open wifi in setKnownStationsWPA correctly
use `... key_mgmt NONE` instead of `... psk XXX`
2024-07-24 10:04:19 +02:00
billz
a0d8f22742 Update release version 2024-07-14 08:45:21 +02:00
Bill Zimmerman
ed008730e6
Merge pull request #1612 from RaspAP/fix/wg-status
Update method to determine wg-quick state
2024-07-07 20:31:16 +02:00
billz
828a463888 Update method to determine wg-quick state, resolves #1601 2024-07-07 20:13:06 +02:00
Bill Zimmerman
6541e9b2e1
Merge pull request #1586 from RaspAP/fix/wireguard-conf
Fix: correctly parse multiple wg DNS entries
2024-05-14 07:27:04 +02:00
billz
4175303cf8 Fix: correctly parse multiple wg DNS entries, resolves #1585 2024-05-14 07:21:55 +02:00
Bill Zimmerman
e386cc8dfe
Merge pull request #1583 from RaspAP/fix/armbian-dependencies
Add net-tools dependency to Armbian
2024-05-11 08:27:35 +02:00
billz
543a5e098a Add net-tools dependency to Armbian, resolves #290 2024-05-11 07:39:20 +02:00
Bill Zimmerman
884d4d95c5
Merge pull request #1576 from RaspAP/maint/debuglog
Adds output from rfkill to debug log
2024-05-03 09:44:36 +02:00
billz
e8a8ca6b65 Add _rfkill_info 2024-05-03 09:01:26 +02:00
Bill Zimmerman
f76cb71086
Update issue_form.yml 2024-05-03 08:58:31 +02:00
Bill Zimmerman
2d1d6fb566
Update issue_form.yml 2024-05-03 08:56:14 +02:00
billz
41bca8e581 Update release version 2024-04-01 17:15:31 +02:00
Bill Zimmerman
9fc38ffd0c
Merge pull request #1561 from RaspAP/fix/installer-options
Update install option vars, use indirect expansion
2024-04-01 17:07:04 +02:00
billz
87143e174a Update install option vars, use indirect expansion 2024-04-01 16:58:55 +02:00
billz
655b126a59 Update release version 2024-03-31 17:59:49 +02:00
billz
5930a123d2 Remove _check_incompatible_distro 2024-03-31 17:57:46 +02:00
billz
69387f196c Update release version 2024-03-28 12:08:53 +01:00
billz
5cbe66d99b Set RASPI_RESTAPI_ENABLED flag 2024-03-27 18:35:15 +01:00
Bill Zimmerman
48e7b7abb7
Merge pull request #1556 from RaspAP/maint/installer
Roll up install prompts with _prompt_install_features()
2024-03-26 18:25:48 +01:00
billz
5717d2f4a8 Update package check w/ dpkg-query 2024-03-25 19:47:19 +01:00
billz
fc77f79441 Add _check_incompatible_distro 2024-03-25 15:58:37 +01:00
billz
f4017ef29a Roll up install prompts with _prompt_install_features() 2024-03-24 16:31:21 +01:00
Bill Zimmerman
ee915f95a2
Merge pull request #1552 from nsdoukos/night-mode-fix
Fix night mode when changing theme
2024-03-22 07:52:39 +01:00
Nestoras Sdoukos
02ac421010 Fix night mode when changing theme
Signed-off-by: Nestoras Sdoukos <sdoukos@libre.space>
2024-03-21 22:31:37 +02:00
Bill Zimmerman
5b27f528c9
Update README.md 2024-03-17 20:12:42 +01:00
billz
d1fb8f69d6 Define RASPI_RESTAPI_ENABLED 2024-03-14 21:27:28 +01:00
billz
820621d301 Update release version 2024-03-13 08:38:14 +01:00
Bill Zimmerman
d0592b63de
Merge pull request #1548 from RaspAP/sec/authenticate-ajax
Add authentication to ajax pages, thx @lts-rad
2024-03-12 17:56:30 +01:00
billz
c98d2b0c15 Add authentication to ajax pages, thx @lts-rad 2024-03-11 18:52:34 +01:00
Bill Zimmerman
e92835f89d
Merge pull request #1545 from RaspAP/dependabot/pip/api/fastapi-0.109.1
Bump fastapi from 0.109.0 to 0.109.1 in /api
2024-03-09 15:24:18 +01:00
dependabot[bot]
603038efb1
Bump fastapi from 0.109.0 to 0.109.1 in /api
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.109.0 to 0.109.1.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.109.0...0.109.1)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-09 13:05:59 +00:00
Bill Zimmerman
2de012cc85
Merge pull request #1519 from NL-TCH/REST-API
RestAPI installer integrated
2024-03-09 14:05:30 +01:00
billz
d1be0caf54 Restart restapi.sevice on API key save 2024-03-09 12:23:20 +01:00
billz
8d6b8174d1 Bump position of sidebar item 2024-03-09 12:22:14 +01:00
billz
c408a6f5f8 Add message to en_US locale + compile 2024-03-09 12:21:31 +01:00
billz
220709b698 fix: mv api files /facepalm 2024-03-09 11:24:36 +01:00
billz
3262e3030f Update en_US locale + compile .mo 2024-03-09 09:25:34 +01:00
billz
f81c68de26 Add restAPI doc link when svc is active 2024-03-09 09:25:02 +01:00
billz
1e840abbaf Update installer switches 2024-03-09 09:17:05 +01:00
Bill Zimmerman
95f74c560e
Merge pull request #1542 from RaspAP/sec/providers
Sanitize country POST input
2024-03-08 21:20:08 +01:00
billz
d5009e0c1e Sanitize country POST input 2024-03-08 21:14:33 +01:00
billz
9c5c0cfb88 Remove /wireguard/{config} endpoint 2024-03-08 20:17:22 +01:00
billz
f61e1b5c1a Clean up serviceLog output 2024-03-08 20:14:08 +01:00
billz
19fe43466e Remove --reload from ExecStart 2024-03-08 20:13:20 +01:00
billz
49780d8ec9 Rename tag hostpost -> hotspot 2024-03-08 20:12:30 +01:00
billz
79d33db2bf Revert "Sanitize path to prevent directory traversal"
This reverts commit 2cdf6ef53e.
2024-03-08 11:27:44 +01:00
billz
2cdf6ef53e Sanitize path to prevent directory traversal 2024-03-08 11:15:31 +01:00
billz
ef7b67a445 Set serviceLog from systemctl status 2024-03-08 10:50:02 +01:00
billz
87216bdc02 Update sudoers .env permissions, systemd service user 2024-03-08 10:48:41 +01:00
billz
5d8fed824a Define RASPI_CONFIG_API, update class constructor, load + createEnv 2024-03-08 10:46:45 +01:00
billz
282b839f45 Add gen_apikey to template 2024-03-08 10:45:05 +01:00
billz
95ad90063b Validate client_config path expression 2024-03-08 09:08:53 +01:00
billz
b567f565d9 Disambiguate service name 2024-03-08 09:01:13 +01:00
billz
00f90f1f73 Sanitize user-provided inputs 2024-03-08 08:59:36 +01:00
billz
b80151be28 Fix SyntaxError: positional argument follows keyword 2024-03-07 18:54:15 +01:00
billz
75be1bf04e Add load_dotenv from dotenv 2024-03-07 18:53:17 +01:00
billz
2365c4e251 Add python-dotenv dependecy 2024-03-07 18:52:01 +01:00
billz
edc3a421ca Replace root user with %i, append --reload 2024-03-07 18:51:16 +01:00
billz
95acd497df Move /api dir to $raspap_dir 2024-03-07 18:50:39 +01:00
billz
5b7b968676 Fix: rename systemd service, set serviceStatus flag 2024-03-07 18:44:27 +01:00
billz
2b2cb8fa40 Update en_US locale messages + compile .mo 2024-02-28 19:50:20 +01:00
billz
0b9cbee210 Processed w/ phpcbf 2024-02-28 19:49:46 +01:00
billz
cfa916632b Replace external dependencies w/ native DotEnv class 2024-02-28 19:27:10 +01:00
billz
b835243e57 Add .env to gitignore 2024-02-28 19:24:49 +01:00
billz
5150224e66 Read RASPAP_API_KEY from Dotenv 2024-02-27 11:50:32 +01:00
billz
4bf514c992 Add required php-mbstring to _install_dependencies 2024-02-27 11:49:21 +01:00
billz
def8be88fb Update dependencies + cp vendor/*/src src/ 2024-02-27 11:48:37 +01:00
Bill Zimmerman
eabd356bcb
Merge pull request #1529 from RaspAP/dependabot/npm_and_yarn/es5-ext-0.10.63
Bump es5-ext from 0.10.51 to 0.10.63
2024-02-27 08:43:05 +01:00
dependabot[bot]
c8ed440c68
Bump es5-ext from 0.10.51 to 0.10.63
Bumps [es5-ext](https://github.com/medikoo/es5-ext) from 0.10.51 to 0.10.63.
- [Release notes](https://github.com/medikoo/es5-ext/releases)
- [Changelog](https://github.com/medikoo/es5-ext/blob/main/CHANGELOG.md)
- [Commits](https://github.com/medikoo/es5-ext/compare/v0.10.51...v0.10.63)

---
updated-dependencies:
- dependency-name: es5-ext
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-27 02:54:33 +00:00
Bill Zimmerman
a55b7d0605
Update BACKERS.md 2024-02-25 10:17:40 +01:00
billz
1e6b604e7f Update release version 2024-02-24 10:47:18 +01:00
Bill Zimmerman
e2530bbbbf
Merge pull request #1527 from RaspAP/fix/auth-user
Fix: Update user_id session var auth context
2024-02-24 10:42:26 +01:00
Bill Zimmerman
55508262de
Merge pull request #1528 from RaspAP/fix/hostapd-iface-check
Fix: Exec iwgetid with client iface session var
2024-02-24 10:41:50 +01:00
billz
cffcac0c52 Exec iwgetid w/ client iface session var 2024-02-24 10:35:35 +01:00
billz
ae44f5476d Update user_id session var auth context 2024-02-24 10:23:58 +01:00
billz
8ecd542eae Create api general + status tabs 2024-02-19 19:34:59 +01:00
billz
7dc2fd6538 Implement basic display/save settings 2024-02-19 19:33:59 +01:00
billz
9d7058527d Add start/stop restapi.service to sudoers 2024-02-19 18:57:02 +01:00
billz
2d41f74b6a Minor: fix caps in title 2024-02-19 18:31:48 +01:00
billz
4e258b3981 Add sidebar item, template stubs + page actions 2024-02-19 10:08:29 +01:00
billz
bf41d88340 Add constant to config.php + enable with installer 2024-02-19 09:12:33 +01:00
Bill Zimmerman
2e4d76a419
Merge pull request #1521 from RaspAP/fix/uninstaller
Install loader compatibility fix
2024-02-18 08:14:33 +01:00
TCH
1f1fa3711a no posts + everything behind auth 2024-02-17 19:45:39 +00:00
billz
35bb48d050 Install loader compatibility fix 2024-02-16 10:18:17 +01:00
Bill Zimmerman
c50d01d972
Bump Armbian release 2024-02-10 08:29:33 +01:00
Bill Zimmerman
4c6b01729e
Merge pull request #1518 from NL-TCH/patch-2
fix logging typo
2024-02-09 08:23:56 +01:00
NL-TCH
910616ef43 fix path error in servicefile 2024-02-09 02:17:15 +01:00
NL-TCH
aec0279135 change python -> python3 2024-02-09 01:57:59 +01:00
NL-TCH
8eae2d1606 check if python is present 2024-02-09 01:56:02 +01:00
NL-TCH
ccd0d62a5a why am i stupid? 2024-02-09 01:50:46 +01:00
NL-TCH
8c82c41330 parsing of restapi var to common 2024-02-09 00:50:10 +01:00
NL-TCH
08db1e5b66 bruh, i am stupid 2024-02-09 00:38:03 +01:00
NL-TCH
c43d2ea7ab fix installer 2024-02-09 00:08:46 +01:00
NL-TCH
8357fcb5e4 fix typo 2024-02-08 23:57:48 +01:00
NL-TCH
2ac9ba580f pip fix 2024-02-08 23:46:08 +01:00
NL-TCH
04a443a514 add --help option 2024-02-08 23:28:17 +01:00
NL-TCH
2ce8351b1a initial install test 2024-02-08 23:24:30 +01:00
TCH
3e4857dc67
fix logging typo
nothing major
2024-02-08 23:15:18 +01:00
Bill Zimmerman
ce63e48445
Merge pull request #1517 from RaspAP/maint/about-page
Update project links block
2024-02-08 12:35:15 +01:00
billz
631b6b36af Update project links block 2024-02-08 12:26:47 +01:00
Bill Zimmerman
67caedc992
Update CONTRIBUTING.md 2024-02-08 12:24:01 +01:00
Bill Zimmerman
becaa209f2
Update reddit bage 2024-02-08 11:51:31 +01:00
Bill Zimmerman
06a3b9386f
Update Discord badge 2024-02-08 11:41:24 +01:00
Bill Zimmerman
d296c67373
Update README.md 2024-02-08 11:18:39 +01:00
billz
20bc1830b4 Update release version 2024-02-08 10:26:43 +01:00
Bill Zimmerman
2f2330497d
Merge pull request #1516 from RaspAP/fix/auth-username
Fix get/set admin username
2024-02-08 09:53:52 +01:00
billz
cd7820ddd2 Fix get/set admin username 2024-02-08 09:41:42 +01:00
Bill Zimmerman
56b9ff5a3b
Update README.md 2024-02-08 09:03:26 +01:00
Bill Zimmerman
804034a871
Merge pull request #1515 from RaspAP/fix/parse-dhcp
Update parsing of dhcp-range
2024-02-08 08:46:11 +01:00
billz
3f11ac165b Update parsing of dhcp-range 2024-02-08 08:38:09 +01:00
Bill Zimmerman
0610848a25
Update features list 2024-02-03 16:47:53 +01:00
billz
a1b610b92d Update release version 2024-02-01 09:04:59 +00:00
Bill Zimmerman
4dd409211d
Merge pull request #1510 from RaspAP/feat/installer-update
Add --provider non-interactive option to installer
2024-02-01 10:01:24 +01:00
billz
38a84fc258 Add --provider non-interactive option to installer 2024-02-01 08:51:55 +00:00
Bill Zimmerman
ccbdf8dccf
Merge pull request #1509 from RaspAP/maint/os-detection
Parse /etc/os-release directly (compatibility)
2024-01-30 14:23:16 +01:00
billz
3ee4ea90f5 Parse /etc/os-release versus lsb_release (compatibility) 2024-01-30 12:54:32 +00:00
Bill Zimmerman
224f4ca784
Merge pull request #1508 from RaspAP/fix/dhcp-no-resolv
Fix uncaught TypeError: explode()
2024-01-30 12:27:24 +01:00
billz
54aca14d2c Fix uncaught TypeError: explode() 2024-01-30 11:00:49 +00:00
billz
e6d4f761bd Update release version 2024-01-25 07:26:31 +01:00
Bill Zimmerman
ef1dc5dae0
Update README.md 2024-01-18 21:08:20 +01:00
Bill Zimmerman
bdda08b53e
Merge pull request #1500 from RaspAP/fix/wpa-reinitialize
Update method used reinitialize wpa_supplicant
2024-01-17 11:25:37 +01:00
Bill Zimmerman
45159c7407
Merge pull request #1501 from NL-TCH/patch-1
add CM4 and Pi5 revision numbers
2024-01-17 09:51:36 +01:00
TCH
89187b7e44
fix missed comma 2024-01-16 23:45:57 +01:00
TCH
97adaf88bf
Update Sysinfo.php
source: https://github.com/raspberrypi/documentation/blob/develop/documentation/asciidoc/computers/raspberry-pi/revision-codes.adoc
2024-01-16 23:44:54 +01:00
billz
68a5085e87 Compile en_US .mo 2024-01-16 18:34:18 +01:00
billz
c304f10f81 Update en_US locale + standardize labels 2024-01-16 18:29:49 +01:00
billz
d56870e2db Update shell cmd used in reinitializeWPA 2024-01-16 18:29:16 +01:00
Bill Zimmerman
bb23dc79f6
Merge pull request #1497 from RaspAP/fix/static-leases
Validate static leases input
2024-01-13 16:40:37 +01:00
billz
e5c7ca4053 Add hexadecimal filter mask to MAC address input 2024-01-12 18:01:48 +00:00
billz
f778cd78a7 Added function validateDnsmasqInput() + update saveDHCPConfig 2024-01-12 12:21:56 +00:00
billz
effa38c0a0 Added function validateMac() 2024-01-12 12:21:00 +00:00
Bill Zimmerman
c594b8f4a9
Update README.md 2024-01-12 10:32:51 +01:00
billz
320379e449 Update release version 2023-12-31 08:20:04 +00:00
Bill Zimmerman
b2c78ff12c
Merge pull request #1491 from RaspAP/fix/sanitize-ajax
Security roundup
2023-12-31 09:10:59 +01:00
billz
ebfb1384a4 Remove file (deprecated) 2023-12-31 08:04:09 +00:00
billz
ca9c0471b6 Update handling of filePath argument 2023-12-31 08:03:19 +00:00
Bill Zimmerman
fd38a22c4f
Merge pull request #1486 from RaspAP/maint/exception-handler
Exception handler class
2023-12-27 20:58:59 +01:00
billz
e24b4cbdfa Update en_US locale + compile .mo 2023-12-27 17:21:36 +00:00
billz
ccbfa1a853 Replace literal with RASPI_ERROR_LOG 2023-12-27 16:48:29 +00:00
billz
939092d673 Style exception template 2023-12-27 16:47:39 +00:00
billz
ee29a4fa0a Define RASPI_ERROR_LOG 2023-12-27 16:46:30 +00:00
billz
405ae0bf17 Add constructor, setExceptionHandler, call HtmlErrorRenderer 2023-12-27 05:37:54 +00:00
billz
41bba09f42 Basic template implementation 2023-12-27 05:35:41 +00:00
billz
adf44d462b Move set_exception_handler to constructor 2023-12-27 05:35:03 +00:00
billz
36a6572971 Initial commit 2023-12-26 19:55:31 +00:00
billz
cb456246ca Add includes/exceptions.php + mode change 2023-12-22 23:18:13 +00:00
billz
e93b793686 Initial commit 2023-12-22 23:15:36 +00:00
Bill Zimmerman
27bc1d65af
Update CODE_OF_CONDUCT.md 2023-12-17 20:28:08 +01:00
Bill Zimmerman
627e99b0e9
Merge pull request #1478 from RaspAP/fix/installer-update
Add rsync dependency for Debian distros
2023-12-14 10:15:41 +01:00
billz
61ba236424 Set .service-status-warn amber color 2023-12-14 09:14:09 +00:00
billz
14f3a4dc09 Add rsync dependency for Debian distros 2023-12-12 17:18:25 +00:00
codesee-maps[bot]
581622ef0c
Install the CodeSee workflow. Learn more at https://docs.codesee.io 2023-12-12 08:08:46 +00:00
billz
3cb578ab30 Update release version 2023-12-05 17:17:38 +00:00
Bill Zimmerman
79dbb6d2ea
Merge pull request #1476 from RaspAP/fix/installer-update
Set rsync exclude parameter during update
2023-12-05 18:15:15 +01:00
billz
8d99be5092 Set rsync exclude parameter during update 2023-12-05 17:11:54 +00:00
Bill Zimmerman
f05cd43b5c
Merge pull request #1475 from RaspAP/maint/installer-pkgs
Install extra networking tools (insiders)
2023-12-05 09:46:13 +01:00
billz
eed05c7d6b Update release version 2023-12-05 07:29:11 +00:00
billz
243a5e49fa Install extra networking tools (insiders) 2023-12-04 16:15:32 +00:00
Bill Zimmerman
fc58d5037a
Merge pull request #1469 from RaspAP/fix/predictable-names
Fix: Support predictable interface names
2023-12-04 13:58:40 +01:00
billz
ce62edc698 Minor: code cleanup 2023-12-04 09:20:52 +00:00
billz
5ca9465e83 Update sudoers interface patterns 2023-12-04 09:00:02 +00:00
billz
9fe7bad7b1 Update reinitializeWPA method to use wpa_cli reconfigure 2023-12-04 08:13:13 +00:00
Bill Zimmerman
959f85e63d
Merge pull request #1466 from RaspAP/maint/wg-dependencies
Maintenance: Add dependency to wireguard install
2023-12-04 09:03:01 +01:00
Bill Zimmerman
692c7d1506
Merge pull request #1470 from RaspAP/maint/lightsout-tweaks
Maintenance: Apply consistent border-radius values to .btn + .card classes
2023-12-04 09:02:33 +01:00
Bill Zimmerman
7e39bc0d35
Merge pull request #1468 from RaspAP/fix/isoquery-opts
Fix: Version compatibility check for isoquery options
2023-12-04 08:59:21 +01:00
billz
0a547442a4 Minor: animation spin tweak 2023-12-03 07:23:27 +00:00
billz
e0751d6f90 Use getNetworkIdBySSID() to assign index values 2023-12-02 19:53:16 +00:00
billz
781a292b67 Replace loading-spinner.gif w/ fontawesome circle-notch icon 2023-12-02 18:15:03 +00:00
billz
69b629a59b Update woth setKnownStationsWPA($networks) 2023-12-02 17:32:39 +00:00
billz
e71042cb63 Create setKnownStationsWPA() 2023-12-02 17:32:15 +00:00
billz
1bf7a32bd5 Add wpa_cli list_networks 2023-12-02 17:28:15 +00:00
billz
c5ffab8332 Revise reinitializeWPA method 2023-12-02 14:32:13 +00:00
billz
79c61d383b Add wpa_cli cmds to set, enable + remove network 2023-12-02 14:31:52 +00:00
billz
b5d861a2b9 Add wpa_cli disconnect cmd 2023-12-02 14:16:15 +00:00
billz
84dc44d944 Add restricted wpa_cli commands to sudoers 2023-12-02 14:00:34 +00:00
billz
478c3fea5c Adjust .nav-link, .btn-light .h4 styles 2023-12-02 08:19:50 +00:00
billz
3717249f6a Apply consistent border-radius values to .btn + .card classes 2023-12-01 19:30:17 +00:00
billz
20589bacf3 Return wpa_cli failure in status message 2023-12-01 18:03:03 +00:00
billz
0cb3128158 Revised for predictable iface names 2023-12-01 18:02:01 +00:00
billz
89cb4621fa Version compatibility check for isoquery options 2023-12-01 14:18:38 +00:00
billz
93f6069dc3 Add resolvconf dependency to wg install for Debian 12/Ubuntu 22.04 2023-12-01 13:57:15 +00:00
Bill Zimmerman
ff7f1f01b4
Merge pull request #1467 from RaspAP/fix/theme-options
Feature / fix: Theme updates
2023-11-30 12:44:43 +01:00
Bill Zimmerman
194ca3a295
Merge branch 'master' into fix/theme-options 2023-11-29 17:28:37 +01:00
Bill Zimmerman
1a16f3c8a3
Merge pull request #1465 from RaspAP/feat/set-loglimit
Feature: Set diagnostic log size limit
2023-11-29 17:10:06 +01:00
billz
ba03688230 Apply @marek-guran's dynamic color to RaspAP dark theme 2023-11-29 09:20:27 +00:00
billz
cf63cfe63b Apply theme color to .sidebar-brand-text 2023-11-29 09:17:09 +00:00
billz
034a0b8f63 Generalize @marek-guran's lighten/darkenColor functions 2023-11-29 09:16:28 +00:00
billz
54ec50c27f Add resolvconf to wireguard install 2023-11-28 17:08:35 +00:00
billz
7818462f56 Update en_US locale + compile .mo 2023-11-28 11:07:25 +00:00
billz
74656c63ed Update templates w/ getLogLimited, add $logdata to payload 2023-11-28 10:05:06 +00:00
billz
05210e8967 Update en_US locale w/ new messages 2023-11-28 10:04:25 +00:00
billz
2a5241fb62 Add log size limit to Advanced tab, validate + set session var 2023-11-28 10:03:58 +00:00
billz
cf53c575ff Create getLogLimited() 2023-11-28 10:01:15 +00:00
billz
8cbfaed989 Define RASPI_LOG_SIZE_LIMIT, RASPI_HOSTAPD_LOG 2023-11-28 10:00:07 +00:00
Bill Zimmerman
7858bb5739
Update stale.yml 2023-11-27 08:41:37 +01:00
Bill Zimmerman
4705cc5ec1
Create stale.yml 2023-11-27 08:34:39 +01:00
Bill Zimmerman
21ee31b8ce
Delete .github/stale.yml 2023-11-27 08:34:01 +01:00
Bill Zimmerman
fd3034e976
Delete .github/workflows/main.yml 2023-11-27 08:26:23 +01:00
billz
f4b9eeb313 Update release version 2023-11-25 16:45:12 +00:00
Bill Zimmerman
0246761609
Update CODE_OF_CONDUCT.md 2023-11-25 13:40:00 +01:00
Bill Zimmerman
7ac8d8b9f3
Merge pull request #1462 from RaspAP/feat/check-update
Feature: Check for update
2023-11-25 13:18:19 +01:00
billz
61a1f063ea Update rsync exclusion path 2023-11-25 11:30:36 +00:00
billz
9a709b3ded Preserve /tmp/raspap_install.log literal 2023-11-25 09:54:28 +00:00
billz
2102fb9043 Remove temp $source_dir if exists, sudo rm raspap_install.log 2023-11-25 08:15:10 +00:00
billz
c0bf18bf50 Add RASPI_MONITOR_ENABLED to update check btn, require config.php 2023-11-24 22:53:06 +00:00
billz
484a1e8702 Cleanup template, fix timing of js execution 2023-11-24 18:10:16 +00:00
billz
d6a4d33758 Define RASPI_INSTALL_LOG 2023-11-24 18:07:47 +00:00
billz
aa3a88e9b1 Use existing raspbian.sh install loader for update 2023-11-24 07:49:52 +00:00
billz
99fd2f8ce7 Remove existing /tmp/raspap_install.log 2023-11-24 07:48:12 +00:00
billz
ffafcf2c83 Add successMsg, set btn state disabled until update complete 2023-11-23 11:43:38 +00:00
billz
ea5ee29d4a Set csrfToken for ajax post 2023-11-23 09:11:02 +00:00
billz
387d779bdf Update w/ ajax post sys_perform_update.php 2023-11-23 08:53:13 +00:00
billz
fec2c283c1 Update local installer pre-loader path 2023-11-23 08:45:40 +00:00
billz
1e4fe3b002 Remove setInterval(fetchUpdateResponse, 500) 2023-11-23 08:44:27 +00:00
billz
61c05d93d8 Revise en_US locale messages + compile .mo 2023-11-23 07:57:40 +00:00
billz
f6d7e9a2d1 Catch update complete + error states 2023-11-23 07:54:38 +00:00
billz
37dcaa41f1 Create performupdateModal w/ progress steps 2023-11-23 07:51:43 +00:00
billz
44c8b7c1ae Create fetchUpdateResponse(), update modals 2023-11-23 07:49:03 +00:00
billz
d14040d3a7 Initial commit 2023-11-23 07:44:46 +00:00
billz
e2111fdf1f Added /etc/raspap/system/app-update.sh to sudoers 2023-11-23 07:43:50 +00:00
billz
5fbcabd3c2 Initial commit 2023-11-23 07:43:33 +00:00
billz
90456e601e Replace mv source > dest with rsync, preserving sys_read_logfile.php 2023-11-22 19:00:32 +00:00
Bill Zimmerman
7b3662fb2b
Update stale.yml 2023-11-22 13:02:58 +01:00
billz
e55f4e2395 Update _download_latest_files, install app-update.sh 2023-11-21 20:14:19 +00:00
billz
61cf109f11 Compile en_US local .mo 2023-11-20 14:57:46 +00:00
billz
ba67d327af Revert change to RASPI_VERSION 2023-11-20 14:56:50 +00:00
billz
51e05dd270 Update en_US local messages 2023-11-20 14:48:59 +00:00
billz
ba45daad19 Patch applied + modified from RaspAP/raspap-insiders#242 2023-11-20 14:45:55 +00:00
1847 changed files with 57632 additions and 56657 deletions

View file

@ -34,13 +34,15 @@ body:
required: true
- label: I observed this bug on a clean install of a [supported OS](https://docs.raspap.com/#compatible-operating-systems).
required: true
- label: I have followed the [project prerequisites](https://docs.raspap.com/#quick-start).
- label: I have followed the [project prerequisites](https://docs.raspap.com/quick_start/#quick-install).
required: true
- label: I have searched this repository for existing issues.
required: true
- label: I checked the [FAQ](https://docs.raspap.com/faq/) and [official documentation](https://docs.raspap.com/).
required: true
- label: I have generated a [RaspAP debug log](https://docs.raspap.com/ap-basics/#debug-log) and performed a [self-diagnosis](https://docs.raspap.com/ap-basics/#diagnosing-problems).
- label: I am using an [external wireless adapter](https://docs.raspap.com/issues/#external-hardware).
required: false
- label: I have generated a [RaspAP debug log](https://docs.raspap.com/troubleshooting/#debug-log) and performed a [self-diagnosis](https://docs.raspap.com/troubleshooting/#diagnosing-problems).
required: true
- type: dropdown
@ -50,18 +52,19 @@ body:
options:
- Raspberry Pi OS (64-bit) Lite Bookworm
- Raspberry Pi OS (32-bit) Lite Bookworm
- Raspberry Pi OS (64-bit) Desktop Bookwom
- Raspberry Pi OS (64-bit) Lite Bullseye
- Raspberry Pi OS (32-bit) Lite Bullseye
- Armbian 23.05 (Suni)
- Debian Bookworm
- Ubuntu Server 23.04 (Lunar)
- Debian Bookworm
validations:
required: true
- type: dropdown
id: install
attributes:
label: Quick install or Manual setup?
label: Installation method
options:
- Pre-built image
- Quick install
- Manual setup
validations:
@ -87,6 +90,7 @@ body:
- Raspberry Pi 3 Model B
- Raspberry Pi Zero 2 W
- Raspberry Pi Zero W
- Raspberry Pi Compute Module
- Orange Pi family
- Other
validations:
@ -96,12 +100,8 @@ body:
attributes:
label: RaspAP version
options:
- 3.0 (Latest)
- 3.0-beta
- 2.9.9
- 2.9.8
- 2.9.7
- Other
- Latest
- Other (specify below)
validations:
required: true
- type: dropdown
@ -114,7 +114,6 @@ body:
- Not sure
validations:
required: true
- type: input
id: contact
attributes:

18
.github/stale.yml vendored
View file

@ -1,18 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- enhancement
- feature request
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View file

@ -0,0 +1,23 @@
# This workflow was added by CodeSee. Learn more at https://codesee.io/
# This is v2.0 of this workflow file
on:
push:
branches:
- master
pull_request_target:
types: [opened, synchronize, reopened]
name: CodeSee
permissions: read-all
jobs:
codesee:
runs-on: ubuntu-latest
continue-on-error: true
name: Analyze the repo with CodeSee
steps:
- uses: Codesee-io/codesee-action@v2
with:
codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
codesee-url: https://app.codesee.io

View file

@ -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

80
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,80 @@
name: Build and publish RaspAP images
permissions:
contents: write
on:
release:
types: [published]
jobs:
build-raspap-image:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- arch: "32-bit"
pi_gen_version: "master"
- arch: "64-bit"
pi_gen_version: "arm64"
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Add RaspAP Stage
run: |
mkdir -p stage-raspap/package-raspap &&
{
cat > stage-raspap/package-raspap/00-run-chroot.sh <<-EOF
#!/bin/bash
apt-get update -y && apt-get install -y curl dhcpcd5 iptables procps
curl -sL https://install.raspap.com | bash -s -- --yes --openvpn 1 --restapi 1 --adblock 1 --wireguard 1 --tcp-bbr 1 --check 0
# Set Wi-Fi country to prevent RF kill
raspi-config nonint do_wifi_country "US"
# Fetch RaspAP version and set MOTD
RASPAP_VERSION=\$(curl -sL https://install.raspap.com | bash -s -- --version)
echo "\$RASPAP_VERSION" | tee /etc/motd
EOF
} &&
chmod +x stage-raspap/package-raspap/00-run-chroot.sh &&
{
cat > stage-raspap/prerun.sh <<-EOF
#!/bin/bash -e
if [ ! -d "\${ROOTFS_DIR}" ]; then
copy_previous
fi
EOF
} &&
chmod +x stage-raspap/package-raspap/00-run-chroot.sh &&
{
cat > stage-raspap/prerun.sh <<-EOF
#!/bin/bash -e
if [ ! -d "\${ROOTFS_DIR}" ]; then
copy_previous
fi
EOF
} &&
chmod +x stage-raspap/prerun.sh
- name: Build RaspAP Image
id: build
uses: usimd/pi-gen-action@v1
with:
image-name: "raspap-bookworm-${{ matrix.arch == '32-bit' && 'armhf' || 'arm64' }}-lite-${{ github.event.inputs.tag || github.ref_name }}"
enable-ssh: 1
stage-list: stage0 stage1 stage2 ./stage-raspap
verbose-output: true
pi-gen-version: ${{ matrix.pi_gen_version }}
pi-gen-repository: RaspAP/pi-gen
- name: Upload Artifact
uses: svenstaro/upload-release-action@v2
with:
asset_name: "raspap-bookworm-${{ matrix.arch == '32-bit' && 'armhf' || 'arm64' }}-lite-${{ github.event.inputs.tag || github.ref_name }}.img.zip"
file: ${{ steps.build.outputs.image-path }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.event.inputs.tag || github.ref }}
overwrite: true

23
.github/workflows/stale.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v8.0.0
with:
days-before-issue-stale: 30
days-before-issue-close: 14
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
exempt-issue-labels: pinned, enhancement, feature request
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View file

@ -5,3 +5,5 @@ yarn-error.log
includes/config.php
rootCA.pem
vendor
.env
locale/**/*.mo

4
.gitmodules vendored Normal file
View file

@ -0,0 +1,4 @@
[submodule "plugins"]
path = plugins
url = https://github.com/RaspAP/plugins
branch = master

View file

@ -1,4 +1,4 @@
<img width="465" alt="Insiders logo" src="https://user-images.githubusercontent.com/229399/115766971-e19e1900-a3a8-11eb-8c6f-379deb4313d2.png">
<img width="465" alt="Insiders logo" src="https://i.imgur.com/62TMUy5.png">
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.
@ -15,18 +15,22 @@ You can become a sponsor using your individual or organization's GitHub account.
## Exclusive features
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/)
✅ [Firewall settings](https://docs.raspap.com/firewall/)
✅ [Network device management](https://docs.raspap.com/net-devices/)
✅ [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)
✅ [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)
✅ [Dynamic DNS support](https://docs.raspap.com/dynamicdns/)
✅ [Multiple WireGuard configs](https://docs.raspap.com/wireguard/#multiple-configs)
✅ [Wireless LAN routing](https://docs.raspap.com/wlanrouting/)
✅ [Custom user avatars](https://docs.raspap.com/authentication/#custom-user-avatars)
✅ [WiFi repeater mode](https://docs.raspap.com/ap-basics/#wifi-repeater-mode)
✅ [NTP Service](https://docs.raspap.com/ntp/)
✅ [Limited privilege user role](https://docs.raspap.com/authentication/#limited-privilege-user-role)
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.
## Funding targets

View file

@ -1,48 +1,44 @@
# Contributor Covenant Code of Conduct
# RaspAP Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone.
RaspAP is an open source community project devoted to building simple yet
powerful wireless router software for Debian-based devices. We as members, contributors,
and leaders pledge to make participation in our community an experience consisent with
the norms of civil behavior and respectful discourse.
We pledge to act and interact in ways that contribute to an open, welcoming,
inclusive, and healthy community.
To this end, we pledge to act and interact in ways that uphold the following standards.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Being excellent to one another
* Being respectful of differing opinions, viewpoints, and experiences
* Being excellent to one another (treat others as you wish to be treated)
* Giving and accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Being respectful of differing opinions and viewpoints
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
Examples of unacceptable behavior are provided below. Quotes in parantheses
are portions of actual comments or issues that have been posted to this project:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Unconstructive comments (this software "fails miserably")
* Complaining and/or emotional language ("I'm pulling my hair out!")
* Comments that are derogatory, trolling or are personal attacks ("what's wrong with you guys?")
* Public or private harassment of any kind
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
We have a zero tolerance policy for any and all of the above behavior.
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
We reserve the right to remove, edit, or reject comments, issues, commits,
discussions and other contributions that are not consistent with this Code of Conduct.
We may ban, temporarily or permanently, any contributor for violating this code, as appropriate.
## Scope
@ -52,52 +48,6 @@ Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],

View file

@ -15,7 +15,7 @@ This project follows the [PSR-2](http://www.php-fig.org/psr/psr-2/) coding style
RaspAP is made possible by a strong [community of developers](https://github.com/RaspAP/raspap-webgui/graphs/contributors). If you have any questions or would like to get involved in RaspAP, dive into any of these channels:
* [GitHub discussions](https://github.com/RaspAP/raspap-webgui/discussions)
* [Gitter chat](https://app.gitter.im/#/room/#RaspAP:gitter.im)
* [Discord chat](https://discord.gg/KVAsaAR)
* [Twitter](https://twitter.com/rasp_ap)
* [Reddit](https://www.reddit.com/r/RaspAP/)

101
README.md
View file

@ -1,61 +1,77 @@
![](https://i.imgur.com/xeKD93p.png)
[![Release 3.0.1](https://img.shields.io/badge/release-v3.0.1-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)
![RaspAP Custom OS images](https://github.com/user-attachments/assets/e871adf1-123c-450b-94eb-80a185c242cc)
[![Release 3.3.2](https://img.shields.io/badge/release-v3.3.2-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=Insiders&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) [![Reddit](https://img.shields.io/badge/%2Fr%2FRaspAP-e05d44?style=flat&logo=Reddit&logoColor=white&labelColor=e05d44&color=b14835)](https://reddit.com/r/RaspAP) [![Discord](https://img.shields.io/discord/642436993451819018?color=7289DA&label=Discord&logo=discord&style=flat)](https://discord.gg/KVAsaAR)
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 is feature-rich wireless router software that _just works_ on many popular [Debian-based devices](#supported-operating-systems), including the Raspberry Pi. Our [custom OS images](#pre-built-image), [Quick installer](#quick-installer) and [Docker container](#docker-support) create 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/), [ad blocking](#ad-blocking), security audits, [captive portal integration](https://docs.raspap.com/captive/), themes and [multilingual options](https://docs.raspap.com/translations/) 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 by [PC World](https://www.pcwelt.de/article/1789512/raspberry-pi-als-wlan-router.html), [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](https://github.com/RaspAP/raspap-awesome#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).
![](https://github.com/RaspAP/raspap-webgui/assets/229399/3df0d9c2-3c22-46f9-b5ac-8a5ea1626cb6)
![](https://github.com/RaspAP/raspap-webgui/assets/229399/e8a246d7-08ba-4a14-9df2-7743bfe1c7a2)
![](https://github.com/RaspAP/raspap-webgui/assets/229399/5f50d8db-265c-475b-ad53-af4491189e1a)
![](https://github.com/RaspAP/raspap-webgui/assets/229399/0035e542-5457-4576-aee4-6240764846f2)
![](https://github.com/RaspAP/raspap-webgui/assets/229399/8f99d89c-d996-460a-bf93-96f33a5eddb3)
![dashboard](https://github.com/user-attachments/assets/f7cf5c32-4d95-4ac8-8a30-6d892d7ac6ed)
<img width="32.5%" alt="Wifi Client" src="https://github.com/user-attachments/assets/95696ddc-da84-4339-97cc-f2a173054664">
<img width="32.5%" alt="Hotspot" src="https://github.com/user-attachments/assets/c1c4de15-3ff2-4d3c-a7af-339c24896749">
<img width="32.5%" alt="Adblock" src="https://github.com/user-attachments/assets/ab925687-8407-4bec-a952-9dc6a2675f49">
<img width="32.5%" alt="About" src="https://github.com/user-attachments/assets/ba62d8bb-34f0-44ee-9fe8-504763a03726">
<img width="32.5%" alt="Wireguard" src="https://github.com/user-attachments/assets/4ba16118-8671-4654-9a36-92ac7bc8507f">
<img width="32.5%" alt="System" src="https://github.com/user-attachments/assets/f54e04fc-dc2c-4a21-903b-23641795822b">
## Contents
- [Prerequisites](#prerequisites)
- [Quick installer](#quick-installer)
- [Quick start](#quick-start)
- [Join Insiders](#join-insiders)
- [WireGuard support](#wireguard-support)
- [OpenVPN support](#openvpn-support)
- [VPN Provider support](#vpn-provider-support)
- [Ad Blocking](#ad-blocking)
- [Bridged AP](#bridged-ap)
- [Simultaneous AP and Wifi client](#simultaneous-ap-and-wifi-client)
- [Manual installation](#manual-installation)
- [802.11ac 5GHz support](#80211ac-5ghz-support)
- [Supported operating systems](#supported-operating-systems)
- [Multilingual support](#multilingual-support)
- [HTTPS support](#https-support)
- [Docker support](#docker-support)
- [Custom user plugins](#custom-user-plugins)
- [Multilingual support](#multilingual-support)
- [How to contribute](#how-to-contribute)
- [Reporting issues](#reporting-issues)
- [License](#license)
## 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).
## Quick start
RaspAP gives you two different ways to get up and running quickly. The simplest and recommended approach is to use a custom Raspberry Pi OS image with RaspAP preinstalled. This option eliminates guesswork and gives you a base upon which to build. Alternatively, you may execute the Quick installer on an existing [compatible OS](https://docs.raspap.com/#compatible-operating-systems).
### Pre-built image
Custom Raspberry Pi OS Lite images with the latest RaspAP are available for [direct download](https://github.com/RaspAP/raspap-webgui/releases/latest). This includes both 32- and 64-bit builds for ARM architectures.
| Operating system | Debian version | Kernel version | RaspAP version | Size |
| ---------------------| ---------------|-----------------|----------------|-------|
| Raspberry Pi OS (64-bit) Lite | 12 (bookworm) | 6.6 | Latest | 777 MB|
| Raspberry Pi OS (32-bit) Lite | 12 (bookworm) | 6.6 | Latest | 805 MB|
These images are automatically generated with each release of RaspAP. You may choose between an `arm64` or `armhf` (32-bit) based build. Refer to [this resource](https://www.raspberrypi.com/software/operating-systems/) to ensure compatibility with your hardware.
After downloading your desired image from the [latest release page](https://github.com/RaspAP/raspap-webgui/releases/latest), use a utility such as the Raspberry Pi Imager or [balenaEtcher](https://www.balena.io/etcher) to flash the OS image onto a microSD card. Insert the card into your device and boot it up. The latest RaspAP release version with the most popular optional components will be active and ready for you to configure.
### Quick installer
Alternatively, start with a clean install of a [latest release of Raspberry Pi OS](https://www.raspberrypi.org/software/operating-systems/). Both the 32- and 64-bit release versions are supported, as well as the latest 64-bit Desktop distribution.
Update RPi OS to its latest version, 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 full-upgrade
sudo reboot
```
2. Set the "WLAN country" option in `raspi-config`'s **Localisation Options**: `sudo raspi-config`
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.
With the prerequisites done, you can proceed with either the Quick installer or Manual installation steps below.
## Quick installer
Install RaspAP from your device's shell prompt:
```sh
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.
After the reboot at the end of the installation the wireless network will be
configured as an access point as follows:
The Quick installer will respond to several [command line arguments](https://docs.raspap.com/quick/), or switches, to customize your installation in a variety of ways, or install one of RaspAP's optional helper tools.
### Initial settings
After completing either of these setup options, the wireless AP network will be configured as follows:
* IP address: 10.3.141.1
* Username: admin
* Password: secret
@ -63,7 +79,7 @@ configured as an access point as follows:
* SSID: `raspi-webgui`
* 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/).
It's _strongly recommended_ that your first post-install action is to change the default admin [authentication](https://docs.raspap.com/authentication/) settings. Thereafter, your AP's [basic settings](https://docs.raspap.com/ap-basics/) and many [advanced options](https://docs.raspap.com/ap-basics#advanced-options) are now ready to be modified by RaspAP.
Please [read this](https://docs.raspap.com/issues/) before reporting an issue.
@ -112,11 +128,6 @@ By default RaspAP configures a routed AP for your clients to connect to. A bridg
More information on Bridged AP mode is provided [in our documentation](https://docs.raspap.com/bridged/).
## 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.
**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/).
## Manual installation
Detailed manual setup instructions are provided [on our documentation site](https://docs.raspap.com/manual/).
@ -130,20 +141,15 @@ RaspAP was originally made for Raspbian, but now also installs on the following
|---|:---:|:---:|:---:|
| Raspberry Pi OS | (64-bit) Lite Bookworm | ARM | Official |
| Raspberry Pi OS | (32-bit) Lite Bookworm | ARM | Official |
| Raspberry Pi OS | (64-bit) Desktop Bookworm | ARM | Official |
| Raspberry Pi OS | (64-bit) Lite Bullseye | ARM | Official |
| Raspberry Pi OS | (32-bit) Lite Bullseye | ARM | Official |
| Armbian | 23.05 (Suni) | [ARM](https://docs.armbian.com/#supported-socs) | Official |
| Armbian | 23.11 (Jammy) | [ARM](https://docs.armbian.com/#supported-socs) | Beta |
| Debian | Bookworm | ARM / x86_64 | Beta |
| Ubuntu | Server 23.04 (Lunar) | ARM / x86_64 | Beta |
![](https://i.imgur.com/luiyYNw.png)
<img src="https://i.imgur.com/XiAJNKb.png" style="width:480px;" />
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
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/).
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.
You are also encouraged to use RaspAP's community-led [Docker container](#docker-support). 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.
## 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.
@ -158,6 +164,21 @@ curl -sL https://install.raspap.com | bash -s -- --cert
More information on SSL certificates and HTTPS support is available [in our documentation](https://docs.raspap.com/ssl/).
## Docker support
<img src="https://github.com/RaspAP/raspap-webgui/assets/229399/dc40dfc4-e9b8-405f-8ffb-6c5f88482b8e" width="450">
As an alternative to the [Quick installer](#quick-installer), RaspAP may be run in an isolated, portable [Docker container](https://docs.raspap.com/docker/).
See the [RaspAP-docker repo](https://github.com/RaspAP/raspap-docker/) for more information.
## Custom user plugins
RaspAP's integrated `PluginManager` provides a framework for developers to create custom plugins. To facilitate this, a `SamplePlugin` [repository](https://github.com/RaspAP/SamplePlugin) is available to get developers started on the right track. If you'd like to develop your own plugin for RaspAP, see the [documentation](https://docs.raspap.com/custom-plugins/) or get started right away by forking the [SamplePlugin](https://github.com/RaspAP/SamplePlugin).
## 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/).
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.
## How to contribute
1. Fork the project in your account and create a new branch: `your-great-feature`.
2. Open an issue in the repository describing the feature contribution you'd like to make.

View file

@ -1,7 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
if (isset($_POST['blocklist_id'])) {
$blocklist_id = escapeshellcmd($_POST['blocklist_id']);
@ -50,4 +52,3 @@ if (isset($_POST['blocklist_id'])) {
$jsonData = ['return'=>2,'output'=>['Error getting data']];
echo json_encode($jsonData);
}

View file

@ -1,8 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
$interface = filter_input(INPUT_GET, 'inet', FILTER_SANITIZE_SPECIAL_CHARS);
if (empty($interface)) {
@ -13,8 +14,7 @@ if (empty($interface)) {
} else {
exit('No network interfaces found.');
}
}
}
define('IFNAMSIZ', 16);
if (strlen($interface) > IFNAMSIZ) {
exit('Interface name too long.');
@ -72,14 +72,12 @@ for ($i = count($jsonData) - 1; $i >= 0; --$i) {
$datareceived = round($jsonData[$i]['rx'] / $dsu_factor, 0);
if ($timeunits === 'm') {
echo '{ "date": "' , $dt->format('Y-m') , '", "rx": "' , $datareceived ,
echo '{ "date": "' , $dt->format('Y-m') , '", "rx": "' , $datareceived ,
'", "tx": "' , $datasend , '" }';
} else {
echo '{ "date": "' , $dt->format('Y-m-d') , '", "rx": "' , $datareceived ,
echo '{ "date": "' , $dt->format('Y-m-d') , '", "rx": "' , $datareceived ,
'", "tx": "' , $datasend , '" }';
}
}
echo ' ]';

View file

@ -1,6 +1,9 @@
<?php
require '../../includes/csrf.php';
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
if (filter_input(INPUT_GET, 'tu') == 'h') {

View file

@ -1,13 +1,20 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/functions.php';
if (isset($_POST['logfile'])) {
$logfile = escapeshellcmd($_POST['logfile']);
$logfile = escapeshellarg($_POST['logfile']);
$valid = '/(\/var\/log|\/tmp)/';
// truncate requested log file
exec("sudo truncate -s 0 $logfile", $return);
if (preg_match($valid, $logfile)) {
// truncate requested log file
exec("sudo truncate -s 0 $logfile", $return);
} else {
$return = 1;
}
echo json_encode($return);
}

View file

@ -1,35 +1,29 @@
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/config.php';
require_once '../../includes/session.php';
require_once '../../includes/authenticate.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);
$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'),
);
} else {
handleInvalidCSRFToken();
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);

View file

@ -1,6 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
exec("ls /sys/class/net | grep -v lo", $interfaces);
echo json_encode($interfaces);

View file

@ -1,7 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
exec('cat '. RASPI_HOSTAPD_CONFIG, $hostapdconfig);
$arrConfig = array();
@ -15,3 +17,4 @@ foreach ($hostapdconfig as $hostapdconfigline) {
};
$channel = intval($arrConfig['channel']);
echo json_encode($channel);

View file

@ -1,7 +1,9 @@
<?php
require '../../includes/csrf.php';
require '../../src/RaspAP/Parsers/IwParser.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
if (isset($_POST['interface'])) {
@ -11,4 +13,3 @@ if (isset($_POST['interface'])) {
echo json_encode($supportedFrequencies);
}

View file

@ -1,8 +1,10 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/functions.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
if (isset($_POST['interface'])) {
$int = preg_replace('/[^a-z0-9]/', '', $_POST['interface']);

View file

@ -1,9 +1,12 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/functions.php';
$interface = $_GET['iface'];
$interface = $_POST['iface'];
if (isset($interface)) {
// fetch dnsmasq.conf settings for interface
@ -11,15 +14,19 @@ if (isset($interface)) {
$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"];
if (is_string($conf['dhcp-range'])) {
$arrRange = explode(",", $conf['dhcp-range']);
} else {
$arrRange = explode(",", $conf['dhcp-range'][0]);
}
$dhcpdata['RangeStart'] = $arrRange[0] ?? null;
$dhcpdata['RangeEnd'] = $arrRange[1] ?? null;
$dhcpdata['RangeMask'] = $arrRange[2] ?? null;
$dhcpdata['leaseTime'] = $arrRange[3] ?? null;
$dhcpHost = $conf["dhcp-host"] ?? null;
$dhcpHost = empty($dhcpHost) ? [] : $dhcpHost;
$dhcpdata['dhcpHost'] = is_array($dhcpHost) ? $dhcpHost : [ $dhcpHost ];
$upstreamServers = is_array($conf['server']) ? $conf['server'] : [ $conf['server'] ];
$upstreamServers = is_array($conf['server'] ?? null) ? $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);
@ -29,10 +36,10 @@ if (isset($interface)) {
$arrDns = explode(",", $conf['dhcp-option']);
if ($arrDns[0] == '6') {
if (count($arrDns) > 1) {
$dhcpdata['DNS1'] = $arrDns[1];
$dhcpdata['DNS1'] = $arrDns[1] ?? null;
}
if (count($arrDns) > 2) {
$dhcpdata['DNS2'] = $arrDns[2];
$dhcpdata['DNS2'] = $arrDns[2] ?? null;
}
}
}
@ -47,14 +54,15 @@ if (isset($interface)) {
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['Metric'] = $metric[1] ?? null;
$dhcpdata['StaticIP'] = isset($static_ip[1]) && strpos($static_ip[1], '/') !== false
? substr($static_ip[1], 0, strpos($static_ip[1], '/'))
: ($static_ip[1] ?? '');
$dhcpdata['SubnetMask'] = cidr2mask($static_ip[1] ?? '');
$dhcpdata['StaticRouters'] = $static_routers[1] ?? null;
$dhcpdata['StaticDNS'] = $static_dns[1] ?? null;
$dhcpdata['FallbackEnabled'] = empty($fallback) ? false: true;
$dhcpdata['DefaultRoute'] = $gateway[0] == "gateway";
$dhcpdata['NoHookWPASupplicant'] = $nohook_wpa_supplicant[0] == "nohook wpa_supplicant";
$dhcpdata['NoHookWPASupplicant'] = ($nohook_wpa_supplicant[0] ?? '') == "nohook wpa_supplicant";
echo json_encode($dhcpdata);
}

View file

@ -1,13 +1,20 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/locale.php';
if (isset($_POST['interface'])) {
define( 'NL80211_BAND_24GHZ', 0x1 );
define( 'NL80211_BAND_5GHZ', 0x2 );
if(!preg_match('/^[a-zA-Z0-9]+$/', $_POST['interface'])) {
exit('Invalid interface name.');
}
$iface = escapeshellcmd($_POST['interface']);
$flags = 0;
@ -17,7 +24,7 @@ if (isset($_POST['interface'])) {
// 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;
}
@ -40,4 +47,3 @@ if (isset($_POST['interface'])) {
}
echo json_encode($msg);
}

View file

@ -1,9 +1,10 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
// fetch wg client.conf
exec('sudo cat '. RASPI_WIREGUARD_PATH.'client.conf', $return);
echo implode(PHP_EOL,$return);

View file

@ -1,18 +1,20 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.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);

View file

@ -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 "/'.escapeshellarg($rule).'/Id" '.escapeshellarg($udevfile)); // clear all entries with this VID/PID
$rule = '^.*ATTRS{idProduct}==\"' . $pid . '\".*ATTRS{idVendor}==\"' . $vid . '\".*$';
exec('sudo sed -i "/'.escapeshellarg($rule).'/Id" '.escapeshellarg($udevfile)); // clear all entries with this VID/PID
}
if (!empty($mac)) {
exec('sudo sed -i "/^.*'.escapeshellarg($mac).'.*$/d" '.escapeshellarg($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);

View file

@ -1,7 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/defaults.php';
require_once '../../includes/functions.php';
require_once '../../includes/wifi_functions.php';
@ -14,7 +16,7 @@ knownWifiStations($networks);
nearbyWifiStations($networks, !isset($_REQUEST["refresh"]));
connectedWifiStations($networks);
sortNetworksByRSSI($networks);
foreach ($networks as $ssid => $network) $networks[$ssid]["ssidutf8"] = ssid2utf8( $ssid );
foreach ($networks as $ssid => $network) $networks[$ssid]["ssidutf8"] = ssid2utf8( $ssid );
$connected = array_filter($networks, function($n) { return $n['connected']; } );
$known = array_filter($networks, function($n) { return !$n['connected'] && $n['configured']; } );

View file

@ -1,7 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/functions.php';
if (isset($_POST['cfg_id'])) {
@ -24,4 +26,3 @@ if (isset($_POST['cfg_id'])) {
echo json_encode($return);
}

View file

@ -1,7 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/functions.php';
if (isset($_POST['cfg_id'])) {
@ -11,4 +13,3 @@ if (isset($_POST['cfg_id'])) {
$jsonData = ['return'=>$return];
echo json_encode($jsonData);
}

View file

@ -0,0 +1,26 @@
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
$pluginInstaller = \RaspAP\Plugins\PluginInstaller::getInstance();
$plugin_uri = $_POST['plugin_uri'] ?? null;
$plugin_version = $_POST['plugin_version'] ?? null;
$install_path = $_POST['install_path'] ?? null;
if (isset($plugin_uri, $plugin_version, $install_path)) {
try {
$return = $pluginInstaller->installPlugin($plugin_uri, $plugin_version, $install_path);
echo json_encode($return);
} catch (Exception $e) {
http_response_code(422); // unprocessable content
echo json_encode(['error' => $e->getMessage()]);
}
} else {
http_response_code(400); // Bad Request
echo json_encode(['error' => 'Plugin URI, version, and install path are required']);
exit;
}

View file

@ -0,0 +1,31 @@
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
$lastActivity = $_SESSION['lastActivity'] ?? time();
$sessionLifetime = time() - $lastActivity;
$status = $sessionLifetime >= RASPI_SESSION_TIMEOUT ? 'session_expired' : 'active';
if ($status === 'session_expired') {
session_unset(); // unset all session variables
session_destroy(); // destroy the session
}
// send response
header('Content-Type: application/json');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
header('Pragma: no-cache');
$response = [
'status' => $status,
'last_activity' => $lastActivity,
'session_lifetime' => $sessionLifetime
];
echo json_encode($response);
exit();

View file

@ -1,6 +1,9 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
$action = escapeshellcmd($_POST['a']);
@ -18,4 +21,3 @@ if (isset($action)) {
}
echo json_encode($response);
}

View file

@ -0,0 +1,22 @@
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
require_once '../../includes/defaults.php';
require_once '../../includes/functions.php';
$uri = RASPI_API_ENDPOINT;
preg_match('/(\d+(\.\d+)+)/', RASPI_VERSION, $matches);
$thisRelease = $matches[0];
$json = shell_exec("wget --timeout=5 --tries=1 $uri -qO -");
$data = json_decode($json, true);
$tagName = $data['tag_name'];
$updateAvailable = checkReleaseVersion($thisRelease, $tagName);
$response['tag'] = $tagName;
$response['update'] = $updateAvailable;
echo json_encode($response);

View file

@ -1,23 +1,18 @@
<?php
require '../../includes/csrf.php';
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
if (isset($_POST['csrf_token'])) {
if (csrfValidateRequest() && !CSRFValidate()) {
handleInvalidCSRFToken();
}
$root = getenv("DOCUMENT_ROOT");
exec('sudo '.RASPI_CONFIG.'/system/debuglog.sh -i '.$root, $return);
$root = getenv("DOCUMENT_ROOT");
exec('sudo '.RASPI_CONFIG.'/system/debuglog.sh -i '.$root, $return);
$logOutput = implode(PHP_EOL, $return);
$tempDir = sys_get_temp_dir();
$filePath = $tempDir . DIRECTORY_SEPARATOR . RASPI_DEBUG_LOG;
$handle = fopen($filePath, "w");
fwrite($handle, $logOutput);
fclose($handle);
echo json_encode($filePath);
} else {
handleInvalidCSRFToken();
}
$logOutput = implode(PHP_EOL, $return);
$tempDir = sys_get_temp_dir();
$filePath = $tempDir . DIRECTORY_SEPARATOR . RASPI_DEBUG_LOG;
$handle = fopen($filePath, "w");
fwrite($handle, $logOutput);
fclose($handle);
echo json_encode($filePath);

View file

@ -1,11 +1,14 @@
<?php
require '../../includes/csrf.php';
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
$filePath = $_GET['filePath'];
$tempDir = sys_get_temp_dir();
$filePath = $tempDir . DIRECTORY_SEPARATOR . RASPI_DEBUG_LOG;
if (isset($filePath) && strpos($filePath, RASPI_DEBUG_LOG) !== false) {
if (isset($filePath)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filePath));
header('Expires: 0');
@ -18,4 +21,3 @@ if (isset($filePath) && strpos($filePath, RASPI_DEBUG_LOG) !== false) {
header('Location: '.'/system_info');
exit();
}

View file

@ -0,0 +1,23 @@
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/CSRF.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
if (isset($_POST['csrf_token'])) {
if (csrfValidateRequest() && !CSRFValidate()) {
handleInvalidCSRFToken();
}
// set installer path + options
$path = getenv("DOCUMENT_ROOT");
$opts = " --update --yes --check 0 --path $path";
$installer = "sudo /etc/raspap/system/raspbian.sh";
$execUpdate = $installer.$opts;
$response = shell_exec($execUpdate);
echo json_encode($response);
} else {
handleInvalidCSRFToken();
}

View file

@ -0,0 +1,47 @@
<?php
require_once '../../includes/autoload.php';
require_once '../../includes/session.php';
require_once '../../includes/config.php';
require_once '../../includes/authenticate.php';
$logFile = '/tmp/raspap_install.log';
$searchStrings = [
'Configure update' => 1,
'Updating sources' => 2,
'Installing required packages' => 3,
'Cloning latest files' => 4,
'Installing application' => 5,
'Installation completed' => 6,
'error' => 7
];
usleep(500);
if (file_exists($logFile)) {
$handle = fopen($logFile, 'r');
if ($handle) {
while (($line = fgets($handle)) !== false) {
foreach ($searchStrings as $searchString => $value) {
if (strpos($line, $searchString) !== false) {
echo $value .PHP_EOL;
flush();
ob_flush();
if ($value === 6) {
fclose($handle);
exit();
} elseif ($value === 7) {
echo $line .PHP_EOL;
fclose($handle);
exit();
}
}
}
}
fclose($handle);
} else {
echo json_encode("Unable to open file: $logFile");
}
} else {
echo json_encode("File does not exist: $logFile");
}

24
api/auth.py Normal file
View file

@ -0,0 +1,24 @@
import os
from fastapi.security.api_key import APIKeyHeader
from fastapi import Security, HTTPException
from starlette.status import HTTP_403_FORBIDDEN
from dotenv import load_dotenv
load_dotenv()
apikey=os.getenv('RASPAP_API_KEY')
#if env not set, set the api key to "insecure"
if apikey == None:
apikey = "insecure"
print(apikey)
api_key_header = APIKeyHeader(name="access_token", auto_error=False)
async def get_api_key(api_key_header: str = Security(api_key_header)):
if api_key_header ==apikey:
return api_key_header
else:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="403: Unauthorized"
)

156
api/main.py Normal file
View file

@ -0,0 +1,156 @@
from fastapi import FastAPI, Depends
from fastapi.security.api_key import APIKey
import auth
import json
import modules.system as system
import modules.ap as ap
import modules.client as client
import modules.dns as dns
import modules.dhcp as dhcp
import modules.ddns as ddns
import modules.firewall as firewall
import modules.networking as networking
import modules.openvpn as openvpn
import modules.wireguard as wireguard
tags_metadata = [
]
app = FastAPI(
title="API for RaspAP",
openapi_tags=tags_metadata,
version="0.0.1",
license_info={
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html",
}
)
@app.get("/system", tags=["system"])
async def get_system(api_key: APIKey = Depends(auth.get_api_key)):
return{
'hostname': system.hostname(),
'uptime': system.uptime(),
'systime': system.systime(),
'usedMemory': system.usedMemory(),
'processorCount': system.processorCount(),
'LoadAvg1Min': system.LoadAvg1Min(),
'systemLoadPercentage': system.systemLoadPercentage(),
'systemTemperature': system.systemTemperature(),
'hostapdStatus': system.hostapdStatus(),
'operatingSystem': system.operatingSystem(),
'kernelVersion': system.kernelVersion(),
'rpiRevision': system.rpiRevision()
}
@app.get("/ap", tags=["accesspoint/hotspot"])
async def get_ap(api_key: APIKey = Depends(auth.get_api_key)):
return{
'driver': ap.driver(),
'ctrl_interface': ap.ctrl_interface(),
'ctrl_interface_group': ap.ctrl_interface_group(),
'auth_algs': ap.auth_algs(),
'wpa_key_mgmt': ap.wpa_key_mgmt(),
'beacon_int': ap.beacon_int(),
'ssid': ap.ssid(),
'channel': ap.channel(),
'hw_mode': ap.hw_mode(),
'ieee80211n': ap.ieee80211n(),
'wpa_passphrase': ap.wpa_passphrase(),
'interface': ap.interface(),
'wpa': ap.wpa(),
'wpa_pairwise': ap.wpa_pairwise(),
'country_code': ap.country_code(),
'ignore_broadcast_ssid': ap.ignore_broadcast_ssid()
}
@app.get("/clients/{wireless_interface}", tags=["Clients"])
async def get_clients(wireless_interface, api_key: APIKey = Depends(auth.get_api_key)):
return{
'active_clients_amount': client.get_active_clients_amount(wireless_interface),
'active_clients': json.loads(client.get_active_clients(wireless_interface))
}
@app.get("/dhcp", tags=["DHCP"])
async def get_dhcp(api_key: APIKey = Depends(auth.get_api_key)):
return{
'range_start': dhcp.range_start(),
'range_end': dhcp.range_end(),
'range_subnet_mask': dhcp.range_subnet_mask(),
'range_lease_time': dhcp.range_lease_time(),
'range_gateway': dhcp.range_gateway(),
'range_nameservers': dhcp.range_nameservers()
}
@app.get("/dns/domains", tags=["DNS"])
async def get_domains(api_key: APIKey = Depends(auth.get_api_key)):
return{
'domains': json.loads(dns.adblockdomains())
}
@app.get("/dns/hostnames", tags=["DNS"])
async def get_hostnames(api_key: APIKey = Depends(auth.get_api_key)):
return{
'hostnames': json.loads(dns.adblockhostnames())
}
@app.get("/dns/upstream", tags=["DNS"])
async def get_upstream(api_key: APIKey = Depends(auth.get_api_key)):
return{
'upstream_nameserver': dns.upstream_nameserver()
}
@app.get("/dns/logs", tags=["DNS"])
async def get_dnsmasq_logs(api_key: APIKey = Depends(auth.get_api_key)):
return(dns.dnsmasq_logs())
@app.get("/ddns", tags=["DDNS"])
async def get_ddns(api_key: APIKey = Depends(auth.get_api_key)):
return{
'use': ddns.use(),
'method': ddns.method(),
'protocol': ddns.protocol(),
'server': ddns.server(),
'login': ddns.login(),
'password': ddns.password(),
'domain': ddns.domain()
}
@app.get("/firewall", tags=["Firewall"])
async def get_firewall(api_key: APIKey = Depends(auth.get_api_key)):
return json.loads(firewall.firewall_rules())
@app.get("/networking", tags=["Networking"])
async def get_networking(api_key: APIKey = Depends(auth.get_api_key)):
return{
'interfaces': json.loads(networking.interfaces()),
'throughput': json.loads(networking.throughput())
}
@app.get("/openvpn", tags=["OpenVPN"])
async def get_openvpn(api_key: APIKey = Depends(auth.get_api_key)):
return{
'client_configs': openvpn.client_configs(),
'client_config_names': openvpn.client_config_names(),
'client_config_active': openvpn.client_config_active(),
'client_login_names': openvpn.client_login_names(),
'client_login_active': openvpn.client_login_active()
}
@app.get("/openvpn/{config}", tags=["OpenVPN"])
async def client_config_list(config, api_key: APIKey = Depends(auth.get_api_key)):
return{
'client_config': openvpn.client_config_list(config)
}
@app.get("/wireguard", tags=["WireGuard"])
async def get_wireguard(api_key: APIKey = Depends(auth.get_api_key)):
return{
'client_configs': wireguard.configs(),
'client_config_names': wireguard.client_config_names(),
'client_config_active': wireguard.client_config_active()
}

64
api/modules/ap.py Normal file
View file

@ -0,0 +1,64 @@
import subprocess
import json
def driver():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep driver= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def ctrl_interface():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ctrl_interface= | cut -d'=' -f2 | head -1", shell=True, capture_output=True, text=True).stdout.strip()
def ctrl_interface_group():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ctrl_interface_group= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def auth_algs():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep auth_algs= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def wpa_key_mgmt():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa_key_mgmt= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def beacon_int():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep beacon_int= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def ssid():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ssid= | cut -d'=' -f2 | head -1", shell=True, capture_output=True, text=True).stdout.strip()
def channel():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep channel= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def hw_mode():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep hw_mode= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def ieee80211n():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ieee80211n= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def wpa_passphrase():
return subprocess.run("sed -En 's/wpa_passphrase=(.*)/\1/p' /etc/hostapd/hostapd.conf", shell=True, capture_output=True, text=True).stdout.strip()
def interface():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep interface= | cut -d'=' -f2 | head -1", shell=True, capture_output=True, text=True).stdout.strip()
def wpa():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def wpa_pairwise():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep wpa_pairwise= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def country_code():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep country_code= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def ignore_broadcast_ssid():
return subprocess.run("cat /etc/hostapd/hostapd.conf | grep ignore_broadcast_ssid= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def logging():
log_output = subprocess.run(f"cat /tmp/hostapd.log", shell=True, capture_output=True, text=True).stdout.strip()
logs = {}
for line in log_output.split('\n'):
parts = line.split(': ')
if len(parts) >= 2:
interface, message = parts[0], parts[1]
if interface not in logs:
logs[interface] = []
logs[interface].append(message)
return json.dumps(logs, indent=2)

38
api/modules/client.py Normal file
View file

@ -0,0 +1,38 @@
import subprocess
import json
def get_active_clients_amount(interface):
arp_output = subprocess.run(['arp', '-i', interface], capture_output=True, text=True)
mac_addresses = arp_output.stdout.splitlines()
if mac_addresses:
grep_pattern = '|'.join(mac_addresses)
output = subprocess.run(['grep', '-iwE', grep_pattern, '/var/lib/misc/dnsmasq.leases'], capture_output=True, text=True)
return len(output.stdout.splitlines())
else:
return 0
def get_active_clients(interface):
arp_output = subprocess.run(['arp', '-i', interface], capture_output=True, text=True)
arp_mac_addresses = set(line.split()[2] for line in arp_output.stdout.splitlines()[1:])
dnsmasq_output = subprocess.run(['cat', '/var/lib/misc/dnsmasq.leases'], capture_output=True, text=True)
active_clients = []
for line in dnsmasq_output.stdout.splitlines():
fields = line.split()
mac_address = fields[1]
if mac_address in arp_mac_addresses:
client_data = {
"timestamp": int(fields[0]),
"mac_address": fields[1],
"ip_address": fields[2],
"hostname": fields[3],
"client_id": fields[4],
}
active_clients.append(client_data)
json_output = json.dumps(active_clients, indent=2)
return json_output

24
api/modules/ddns.py Normal file
View file

@ -0,0 +1,24 @@
import subprocess
def use():
return subprocess.run("cat /etc/ddclient.conf | grep use= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def method():
#get the contents of the line below "use="
return subprocess.run("awk '/^use=/ {getline; print}' /etc/ddclient.conf | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def protocol():
return subprocess.run("cat /etc/ddclient.conf | grep protocol= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def server():
return subprocess.run("cat /etc/ddclient.conf | grep server= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def login():
return subprocess.run("cat /etc/ddclient.conf | grep login= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def password():
return subprocess.run("cat /etc/ddclient.conf | grep password= | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def domain():
#get the contents of the line below "password="
return subprocess.run("awk '/^password=/ {getline; print}' /etc/ddclient.conf", shell=True, capture_output=True, text=True).stdout.strip()

30
api/modules/dhcp.py Normal file
View file

@ -0,0 +1,30 @@
import subprocess
import json
def range_start():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f1", shell=True, capture_output=True, text=True).stdout.strip()
def range_end():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def range_subnet_mask():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f3", shell=True, capture_output=True, text=True).stdout.strip()
def range_lease_time():
return subprocess.run("cat /etc/dnsmasq.d/090_wlan0.conf |grep dhcp-range= |cut -d'=' -f2| cut -d',' -f4", shell=True, capture_output=True, text=True).stdout.strip()
def range_gateway():
return subprocess.run("cat /etc/dhcpcd.conf | grep routers | cut -d'=' -f2", shell=True, capture_output=True, text=True).stdout.strip()
def range_nameservers():
output = subprocess.run("cat /etc/dhcpcd.conf", shell=True, capture_output=True, text=True).stdout.strip()
nameservers = []
lines = output.split('\n')
for line in lines:
if "static domain_name_server" in line:
servers = line.split('=')[1].strip().split()
nameservers.extend(servers)
return nameservers

38
api/modules/dns.py Normal file
View file

@ -0,0 +1,38 @@
import subprocess
import json
def adblockdomains():
output = subprocess.run("cat /etc/raspap/adblock/domains.txt", shell=True, capture_output=True, text=True).stdout.strip()
domains =output.split('\n')
domainlist=[]
for domain in domains:
if domain.startswith('#') or domain=="":
continue
domainlist.append(domain.split('=/')[1])
return domainlist
def adblockhostnames():
output = subprocess.run("cat /etc/raspap/adblock/hostnames.txt", shell=True, capture_output=True, text=True).stdout.strip()
hostnames = output.split('\n')
hostnamelist=[]
for hostname in hostnames:
if hostname.startswith('#') or hostname=="":
continue
hostnamelist.append(hostname.replace('0.0.0.0 ',''))
return hostnamelist
def upstream_nameserver():
return subprocess.run("awk '/nameserver/ {print $2}' /run/dnsmasq/resolv.conf", shell=True, capture_output=True, text=True).stdout.strip()
def dnsmasq_logs():
output = subprocess.run("cat /var/log/dnsmasq.log", shell=True, capture_output=True, text=True).stdout.strip()
log_entries = []
for line in output.split("\n"):
fields = line.split(" ")
log_dict = {
'timestamp': ' '.join(fields[:3]),
'process': fields[3][:-1], # Remove the trailing colon
'message': ' '.join(fields[4:]),
}
log_entries.append(log_dict)
return log_entries

4
api/modules/firewall.py Normal file
View file

@ -0,0 +1,4 @@
import subprocess
def firewall_rules():
return subprocess.run("cat /etc/raspap/networking/firewall/iptables_rules.json", shell=True, capture_output=True, text=True).stdout.strip()

68
api/modules/networking.py Normal file
View file

@ -0,0 +1,68 @@
import psutil
import json
def throughput():
interface_info = {}
# Get network interfaces
interfaces = psutil.net_if_stats()
for interface, stats in interfaces.items():
if interface.startswith("lo") or interface.startswith("docker"):
# Skip loopback and docker interface
continue
try:
# Get network traffic statistics
traffic_stats = psutil.net_io_counters(pernic=True)[interface]
rx_packets = traffic_stats[1]
rx_bytes = traffic_stats[0]
tx_packets = traffic_stats[3]
tx_bytes = traffic_stats[4]
interface_info[interface] = {
"RX_packets": rx_packets,
"RX_bytes": rx_bytes,
"TX_packets": tx_packets,
"TX_bytes": tx_bytes
}
except KeyError:
# Handle the case where network interface statistics are not available
pass
return json.dumps(interface_info, indent=2)
def interfaces():
interface_info = {}
# Get network interfaces
interfaces = psutil.net_if_addrs()
for interface, addrs in interfaces.items():
if interface.startswith("lo") or interface.startswith("docker"):
# Skip loopback and docker interface
continue
ip_address = None
netmask = None
mac_address = None
for addr in addrs:
if addr.family == 2: # AF_INET corresponds to the integer value 2
# IPv4 address
ip_address = addr.address
netmask = addr.netmask
# Get MAC address
for addr in psutil.net_if_addrs().get(interface, []):
if addr.family == psutil.AF_LINK:
mac_address = addr.address
interface_info[interface] = {
"IP_address": ip_address,
"Netmask": netmask,
"MAC_address": mac_address
}
return json.dumps(interface_info, indent=2)
#TODO: migrate to vnstat, to lose psutil dependency

41
api/modules/openvpn.py Normal file
View file

@ -0,0 +1,41 @@
import subprocess
def client_configs():
return subprocess.run("find /etc/openvpn/client/ -type f | wc -l", shell=True, capture_output=True, text=True).stdout.strip()
def client_config_names():
config_names_list = []
output = subprocess.run('''ls /etc/openvpn/client/ | grep -v "^client.conf$"''', shell=True, capture_output=True, text=True).stdout.strip()
lines = output.split("\n")
for client in lines:
if "_client" in client:
config_names_dict ={'config':client}
config_names_list.append(config_names_dict)
return config_names_list
def client_login_names():
config_names_list = []
output = subprocess.run('''ls /etc/openvpn/client/ | grep -v "^client.conf$"''', shell=True, capture_output=True, text=True).stdout.strip()
lines = output.split("\n")
for client in lines:
if "_login" in client:
config_names_dict ={'login':client}
config_names_list.append(config_names_dict)
return config_names_list
def client_config_active():
output = subprocess.run('''ls -al /etc/openvpn/client/ | grep "client.conf -"''', shell=True, capture_output=True, text=True).stdout.strip()
active_config = output.split("/etc/openvpn/client/")
return(active_config[1])
def client_login_active():
output = subprocess.run('''ls -al /etc/openvpn/client/ | grep "login.conf -"''', shell=True, capture_output=True, text=True).stdout.strip()
active_config = output.split("/etc/openvpn/client/")
return(active_config[1])
def client_config_list(client_config):
output = subprocess.run(["cat", f"/etc/openvpn/client/{client_config}"], capture_output=True, text=True).stdout.strip()
return output.split('\n')
#TODO: where is the logfile??
#TODO: is service connected?

86
api/modules/system.py Normal file
View file

@ -0,0 +1,86 @@
import subprocess
revisions = {
'0002': 'Model B Revision 1.0',
'0003': 'Model B Revision 1.0 + ECN0001',
'0004': 'Model B Revision 2.0 (256 MB)',
'0005': 'Model B Revision 2.0 (256 MB)',
'0006': 'Model B Revision 2.0 (256 MB)',
'0007': 'Model A',
'0008': 'Model A',
'0009': 'Model A',
'000d': 'Model B Revision 2.0 (512 MB)',
'000e': 'Model B Revision 2.0 (512 MB)',
'000f': 'Model B Revision 2.0 (512 MB)',
'0010': 'Model B+',
'0013': 'Model B+',
'0011': 'Compute Module',
'0012': 'Model A+',
'a01041': 'a01041',
'a21041': 'a21041',
'900092': 'PiZero 1.2',
'900093': 'PiZero 1.3',
'9000c1': 'PiZero W',
'a02082': 'Pi 3 Model B',
'a22082': 'Pi 3 Model B',
'a32082': 'Pi 3 Model B',
'a52082': 'Pi 3 Model B',
'a020d3': 'Pi 3 Model B+',
'a220a0': 'Compute Module 3',
'a020a0': 'Compute Module 3',
'a02100': 'Compute Module 3+',
'a03111': 'Model 4B Revision 1.1 (1 GB)',
'b03111': 'Model 4B Revision 1.1 (2 GB)',
'c03111': 'Model 4B Revision 1.1 (4 GB)',
'c03111': 'Model 4B Revision 1.1 (4 GB)',
'a03140': 'Compute Module 4 (1 GB)',
'b03140': 'Compute Module 4 (2 GB)',
'c03140': 'Compute Module 4 (4 GB)',
'd03140': 'Compute Module 4 (8 GB)',
'c04170': 'Pi 5 (4 GB)',
'd04170': 'Pi 5 (8 GB)'
}
def hostname():
return subprocess.run("hostname", shell=True, capture_output=True, text=True).stdout.strip()
def uptime():
return subprocess.run("uptime -p", shell=True, capture_output=True, text=True).stdout.strip()
def systime():
return subprocess.run("date", shell=True, capture_output=True, text=True).stdout.strip()
def usedMemory():
return round(float(subprocess.run("free -m | awk 'NR==2{total=$2 ; used=$3 } END { print used/total*100}'", shell=True, capture_output=True, text=True).stdout.strip()),2)
def processorCount():
return int(subprocess.run("nproc --all", shell=True, capture_output=True, text=True).stdout.strip())
def LoadAvg1Min():
return round(float(subprocess.run("awk '{print $1}' /proc/loadavg", shell=True, capture_output=True, text=True).stdout.strip()),2)
def systemLoadPercentage():
return round((float(LoadAvg1Min())*100)/float(processorCount()),2)
def systemTemperature():
try:
output = subprocess.run("cat /sys/class/thermal/thermal_zone0/temp", shell=True, capture_output=True, text=True).stdout.strip()
return round(float(output)/1000,2)
except ValueError:
return 0
def hostapdStatus():
return int(subprocess.run("pidof hostapd | wc -l", shell=True, capture_output=True, text=True).stdout.strip())
def operatingSystem():
return subprocess.run('''grep PRETTY_NAME /etc/os-release | cut -d= -f2- | sed 's/"//g' ''', shell=True, capture_output=True, text=True).stdout.strip()
def kernelVersion():
return subprocess.run("uname -r", shell=True, capture_output=True, text=True).stdout.strip()
def rpiRevision():
output = subprocess.run("grep Revision /proc/cpuinfo | awk '{print $3}'", shell=True, capture_output=True, text=True).stdout.strip()
try:
return revisions[output]
except KeyError:
return 'Unknown Device'

23
api/modules/wireguard.py Normal file
View file

@ -0,0 +1,23 @@
import subprocess
import re
def configs():
#ignore symlinks, because wg0.conf is in production the main config, but in insiders it is a symlink
return subprocess.run("find /etc/wireguard/ -type f | wc -l", shell=True, capture_output=True, text=True).stdout.strip()
def client_config_names():
config_names_list = []
output = subprocess.run('''ls /etc/wireguard/ | grep -v "^wg0.conf$"''', shell=True, capture_output=True, text=True).stdout.strip()
lines = output.split("\n")
for client in lines:
config_names_dict ={'config':client}
config_names_list.append(config_names_dict)
return config_names_list
def client_config_active():
output = subprocess.run('''ls -al /etc/wireguard/ | grep "wg0.conf -"''', shell=True, capture_output=True, text=True).stdout.strip()
active_config = output.split("/etc/wireguard/")
return(active_config[1])
#TODO: where is the logfile??
#TODO: is service connected?

5
api/requirements.txt Normal file
View file

@ -0,0 +1,5 @@
fastapi==0.109.1
uvicorn==0.25.0
psutil==5.9.8
python-dotenv==1.0.1

View file

@ -6,28 +6,42 @@ 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; }
:root {
--raspap-content-main: #495057;
--raspap-text-muted: #858796;
--raspap-text-light: #999999;
--raspap-brand-color: #2b8080;
--raspap-offwhite: #faf9f6;
}
.sidebar.toggled .nav-item .nav-link {
padding: 0.65rem 1rem;
a {
color: var(--raspap-brand-color);
text-decoration: none;
}
.sb-sidenav .sb-sidenav-menu .nav .nav-link {
padding-top: 0.6rem;
padding-bottom: 0.6rem;
}
.sb-sidenav-light .sb-sidenav-menu .nav-link, .card-title, h4 {
color: var(--raspap-content-main);
}
.sb-topnav.navbar-light #sidebarToggle {
color: var(--raspap-content-main);
}
.sidebar-brand-text {
text-transform: none;
color: #212529;
font-size: 2.0rem;
font-weight: 500;
font-family: Helvetica, Arial, sans-serif;
}
th {
color: var(--raspap-content-main) !important;
}
.h-underlined {
border-bottom: 1px solid #e3e6f0;
padding-bottom: 0.3rem;
@ -46,7 +60,7 @@ License: GNU General Public License v3.0
.info-item {
text-transform: uppercase;
font-size: 0.7em;
color: #858796;
color: var(--raspap-text-muted);
}
.info-value {
@ -78,7 +92,7 @@ License: GNU General Public License v3.0
}
.service-status-warn {
color: #f6f044 !important;
color: #ffbf00 !important;
}
.service-status-down {
@ -110,10 +124,31 @@ License: GNU General Public License v3.0
margin-bottom: 0.5em;
}
.loading-spinner {
background: url("../../app/img/loading-spinner.gif") no-repeat scroll center center transparent;
min-height: 450px;
#wifiClientContent #wpaConf {
min-height: calc(100vh / 3);
}
.loading-spinner::before {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: calc(100vh / 4);
display: flex;
justify-content: center;
align-items: center;
color: var(--raspap-text-muted);
content: "\f1ce"; /* Unicode for the circle-notch icon */
font-family: "Font Awesome 5 Free";
font-weight: 900; /* Adjust as needed */
font-size: 54px; /* Adjust icon size as needed */
animation: spin 1.2s linear infinite;
width: 100%;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@media (min-width: 576px) {
@ -134,12 +169,7 @@ License: GNU General Public License v3.0
}
canvas#divDBChartBandwidthhourly {
height: 350px!important;
}
.chart-container {
height: 150px;
width: 200px;
height: 509px!important;
}
.dbChart {
@ -156,7 +186,7 @@ canvas#divDBChartBandwidthhourly {
}
.check-progress {
color: #999;
color: var(--raspap-text-light);
}
.fa-check {
@ -184,7 +214,6 @@ button.btn.btn-light.js-toggle-password {
width: 4px;
border-radius: 1px;
opacity: 30%;
background: <?php echo $color; ?>;
}
.signal-icon .signal-bar:nth-child(1) { height: 40%; }
@ -231,7 +260,7 @@ button.btn.btn-light.js-toggle-password {
}
figcaption.figure-caption a {
color: #858796;
color: var(--raspap-text-muted);
}
button > i.fas {
@ -245,20 +274,390 @@ button > i.fas {
.was-validated .form-control:valid,
.was-validated .form-control:invalid {
background-position: center right calc(.375em + .4875rem);
background-position: center right calc(.375em + .4875rem);
}
.was-validated .form-control:invalid {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-control:valid {
background-size: calc(0.6em + 0.375rem) calc(0.6em + 0.375rem);
background-size: calc(0.6em + 0.375rem) calc(0.6em + 0.375rem);
}
.input-group>.input-group-append:not(:last-child)>.btn {
border-top-right-radius: 0.35rem;
border-bottom-right-radius: 0.35rem;
border-top-right-radius: 0.35rem;
border-bottom-right-radius: 0.35rem;
}
.nav-user {
position: relative;
bottom: 11px;
right: 3px;
}
.nav-item {
font-size: 0.85rem;
}
/* Font Awesome 5 brands */
.fa-reddit {
color: #ff4500;
}
.fa-twitter {
color: #55acee
}
.fa-discord {
color: #7289da
}
.fa-github {
color: #151b23
}
@keyframes heart {
0%, 40%, 80%, 100% {
transform: scale(1);
}
20%, 60% {
transform: scale(1.15);
}
}
.heart {
color: #e63946;
animation: heart 1000ms infinite;
}
#modal-admin-login .modal-content {
background: radial-gradient(circle at 120% -20%, #032626, #052c2c, #073232, #0a3838, #0d3f3f, #114545, #144c4c);
align-items: center;
}
#modal-admin-login .modal-body {
min-width: 330px;
}
.login-brand {
color: var(--raspap-theme-color);
filter: brightness(150%);
}
.admin-login {
color: var(--raspap-offwhite);
font-size: 1.2em
}
.btn-admin-login {
color: var(--raspap-offwhite);
background-color: var(--raspap-theme-color);
}
.btn-admin-login:hover {
color: var(--raspap-offwhite);
background-color: #236969;
}
.no-right-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.btn-passwd-append {
border: 1px solid #ced4da;
}
#passwd-toggle:active,
#passwd-toggle:hover,
#passwd-toggle:focus {
border: 1px solid #ced4da;
}
textarea.plugin-log {
width: 100%;
height: 150px;
resize: none;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
padding: 0.5rem;
background-color: #f8f9fa;
font-family: monospace;
font-size: 0.9rem;
}
.card-wrapper {
margin: 1rem;
}
.dashboard-container {
display: flex;
position: relative;
width: 100%;
min-height: 400px;
padding: 2rem;
}
.connections-left,
.connections-right {
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.connection-item {
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
z-index: 5;
color: var(--raspap-text-light);
}
.connection-right {
align-items: center;
margin-left: 10rem;
}
.connections-left i {
height: 40px;
display: flex;
align-items: center;
justify-content: left;
}
.connections-left i:first-child {
margin-top: 0;
}
.connections-left i:last-child {
margin-bottom: 0;
margin-left: 0.5rem;
}
.center-device {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
position: relative;
z-index: 1;
}
.center-device-top {
margin-bottom: 30px;
}
.client-group {
display: flex;
align-items: center;
flex-direction: row-reverse;
gap: 0.5rem;
}
.client-count {
text-align: right;
}
.clients-status {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
padding-right: 1rem;
}
.dashed-lines,
.solid-lines {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 1rem;
left: 112px;
}
.dashed-lines-right,
.solid-lines-right {
left: -80px;
}
.solid-lines, .solid-lines-right {
z-index: 3;
}
.dashed-lines, .dashed-lines-right {
z-index 0;
}
.device-status {
display: flex;
flex-wrap: wrap;
gap: 1rem;
justify-content: center;
margin: 0.8rem 0;
}
.wifi-bands {
display: flex;
gap: 0.5rem;
}
.band {
padding: 0.25rem 1rem;
border: 2px solid var(--raspap-text-light);
border-radius: 4px;
background: transparent;
font-weight: 600;
color: var(--raspap-text-light);
}
.band.active {
border-color: var(--raspap-theme-color);
color: var(--raspap-theme-color);
}
.device-label {
font-size: 1.3rem;
text-align: center;
color: var(--raspap-theme-color);
margin-top: 1rem;
}
.status-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.3rem;
color: var(--raspap-text-light);
}
.bottom {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.3rem;
width: 100%;
}
.status-item .fa-stack {
width: 1.5em!important;
}
.connection-item>i {
color: var(--raspap-text-light);
}
.connection-item .fa-stack {
min-width: 2.5em;
}
.connections-left>.connection-item>span {
color: var(--raspap-text-light);
margin-right: 0.5rem;
}
.inactive {
color: var(--raspap-text-light)!important;
}
a.inactive:hover,
a.inactive:focus {
color: var(--raspap-text-light) !important;
}
@media (max-width: 1200px) {
.connection-item a > span:not(.fa-stack) {
display: none!important;
}
}
@media (max-width: 991px) {
.connections-right,
.connections-left {
display: none!important;
}
.dashboard-container {
width: auto;
padding: 0;
}
.device-status {
gap: 0.5rem;
}
.clients-mobile {
display: flex!important;
flex-direction: row!important;
}
}
.connection-item.active > span {
color: var(--raspap-theme-color)!important;
}
.connection-item.active > i {
color: var(--raspap-theme-color)!important;
}
.status-item.active > span {
color: var(--raspap-theme-color)!important;
}
.status-item.active > i {
color: var(--raspap-theme-color)!important;
}
.clients-mobile {
display: none;
flex-direction: column;
gap: 1rem;
margin-top: 2rem;
}
.client-type {
position: relative;
display: inline-flex;
align-items: center;
gap: 1rem;
}
.client-type i {
font-size: 1.5rem;
color: var(--raspap-theme-color);
width: 45px;
height: 45px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid var(--raspap-theme-color);
}
.client-type i.badge-icon {
font-size: 0.7rem;
background: var(--raspap-theme-color);
color: var(--raspap-offwhite);
width: 20px;
height: 20px;
border: none;
}
.client-count {
position: absolute;
top: -5px;
right: -5px;
background: var(--raspap-theme-color);
color: var(--raspap-offwhite);
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.8rem;
}
.device-illustration {
min-width: 220px;
max-width: 250px;
}

View file

@ -3,7 +3,6 @@
require_once '../../includes/functions.php';
$color = getColorOpt();
?>
/*
Theme Name: RaspAP default
Author: @billz
@ -14,22 +13,60 @@ License: GNU General Public License v3.0
@import url('all.css');
:root {
--raspap-theme-color: <?php echo $color; ?>;
--raspap-theme-lighter: <?php echo lightenColor($color, 20); ?>;
--raspap-theme-darker: <?php echo darkenColor($color, 20); ?>;
}
body {
color: #212529;
background-color: #f8f9fc;
}
a {
color: var(--raspap-theme-color);
text-decoration: none;
}
a:focus, a:hover {
color: var(--raspap-theme-darker);
}
.sb-sidenav-light .sb-sidenav-menu .nav-link:hover {
color: var(--raspap-theme-color);
}
.sidebar-brand-text:focus,
.sidebar-brand-text:hover {
color: var(--raspap-theme-darker);
}
.form-check-input:checked {
background-color: var(--raspap-theme-color);
border-color: var(--raspap-theme-color);
}
.sidebar {
background-color: #f8f9fc;
}
.sb-nav-link-icon.active {
font-weight: 600;
}
.sidebar .nav-item.active .nav-link {
font-weight: 500;
}
.sidebar-brand-text {
color: var(--raspap-theme-color);
}
.card .card-header, .modal-header {
border-color: <?php echo $color; ?>;
border-color: var(--raspap-theme-color);
color: #fff;
background-color: <?php echo $color; ?>;
background-color: var(--raspap-theme-color);
}
.modal-header {
@ -37,25 +74,25 @@ body {
}
.btn-primary {
color: <?php echo $color; ?>;
border-color: <?php echo $color; ?>;
color: var(--raspap-theme-color);
border-color: var(--raspap-theme-color);
background-color: #fff;
}
.btn-primary:disabled {
color: <?php echo $color; ?> !important;
border-color: <?php echo $color; ?> !important;
color: var(--raspap-theme-color) !important;
border-color: var(--raspap-theme-color) !important;
background-color: #fff !important;
}
.card-body {
color: #495057;
}
.card-footer, .modal-footer {
background-color: #f2f1f0;
}
.nav-item {
font-size: 0.85rem;
}
.nav-tabs .nav-link.active,
.nav-tabs .nav-link {
font-size: 1.0rem;
@ -73,10 +110,6 @@ a.nav-link.active {
padding: 0.6rem 0.6rem 0.6rem 1.0rem;
}
.alert-success {
background-color: #d4edda;
}
.btn-primary {
background-color: #fff;
}
@ -86,8 +119,8 @@ a.nav-link.active {
}
.btn-primary:hover {
background-color: <?php echo $color; ?>;
border-color: <?php echo $color; ?>;
background-color: var(--raspap-theme-color);
border-color: var(--raspap-theme-color);
}
i.fa.fa-bars {
@ -116,6 +149,6 @@ pre.unstyled {
}
.signal-icon .signal-bar {
background: <?php echo $color; ?>;
background: var(--raspap-theme-color);
}

83
app/css/dark.css Normal file
View file

@ -0,0 +1,83 @@
/*
Theme Name: Lights Out
Author: @billz
Author URI: https://github.com/billz
Description: A Bootstrap dark mode theme for RaspAP
License: GNU General Public License v3.0
*/
@import url('custom.php');
html[data-bs-theme="dark"] {
background-color: var(--bs-dark);
color: var(--bs-light);
}
html[data-bs-theme="dark"] body,
html[data-bs-theme="dark"] footer,
html[data-bs-theme="dark"] .sb-sidenav,
html[data-bs-theme="dark"] .sb-topnav,
html[data-bs-theme="dark"] .card,
html[data-bs-theme="dark"] .card-footer {
background-color: var(--bs-dark);
}
html[data-bs-theme="dark"] .card-body,
html[data-bs-theme="dark"] .card-footer,
html[data-bs-theme="dark"] .info-item-xs,
html[data-bs-theme="dark"] .table>:not(caption)>*>* {
color: var(--bs-secondary);
}
html[data-bs-theme="dark"] .sb-topnav.navbar {
background-color: var(--bs-dark) !important;
color: var(--bs-light);
}
html[data-bs-theme="dark"] .sb-topnav.navbar,
html[data-bs-theme="dark"] .sb-topnav.navbar a {
color: var(--raspap-theme-color) !important;
}
html[data-bs-theme="dark"] .sb-topnav.navbar a:hover,
html[data-bs-theme="dark"] .sb-topnav.navbar a:focus {
color: var(--raspap-theme-darker) !important;
}
html[data-bs-theme="dark"] .sb-topnav.navbar {
--bs-navbar-bg: var(--bs-dark);
}
html[data-bs-theme="dark"] .sb-topnav.navbar.navbar-light {
color: var(--bs-light);
}
html[data-bs-theme="dark"] .card {
border-color: var(--bs-secondary);
color: var(--bs-light);
}
html[data-bs-theme="dark"] .card-footer {
border-color: var(--bs-secondary);
}
html[data-bs-theme="dark"] .nav-tabs {
--bs-nav-tabs-link-active-color: var(--bs-light);
--bs-nav-tabs-link-active-bg: var(--bs-dark);
--bs-nav-tabs-link-active-border-color: var(--bs-secondary) var(--bs-secondary) var(--bs-dark);
--bs-nav-tabs-border-color: var(--bs-secondary);
--bs-nav-tabs-link-hover-border-color: var(--bs-secondary);
}
html[data-bs-theme="dark"] .btn {
color: var(--bs-gray-800);
opacity: 75%;
}
html[data-bs-theme="dark"] select,
html[data-bs-theme="dark"] .form-control {
background-color: var(--bs-dark);
border-color: var(--bs-secondary);
color: var(--bs-light);
}

View file

@ -35,8 +35,12 @@ h5.card-title {
color: #212529;
}
.sb-sidenav-menu, footer {
background-color: var(--bs-body-bg);
}
.card, .modal-dialog {
border-radius: 3px;
border-radius: 5px;
border-color: #ff6600;
}
@ -75,8 +79,20 @@ h5.card-title {
ul.nav-tabs, .nav-tabs .nav-link {
background-color: #f6f6ef;
border-bottom: 1px solid #dddfeb;
color: #495057;
font-size: 1.0rem;
}
.form-switch .form-check-input:checked {
background-color: #ff6600;
border-color: #828282;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
.sidebar .nav-item .nav-link {
padding: 0.6rem;
margin-left: 0.6rem;
@ -86,16 +102,14 @@ ul.nav-tabs, .nav-tabs .nav-link {
font-weight: 300;
}
#wrapper,#page-wrapper,
#wrapper #content-wrapper,
.nav>li>a,.nav {
background-color: #fff;
}
.card-body {
background-color: #f6f6ef;
border-radius: 5px;
}
th {
color: #495057 !important;
}
.card-footer {
background-color: #eee;
}

View file

@ -1,360 +0,0 @@
/*
Theme Name: Lights Out
Author: @billz
Author URI: https://github.com/billz
Description: A dark mode theme for RaspAP
License: GNU General Public License v3.0
*/
@import url('all.css');
html * {
font-family: Helvetica,Arial,sans-serif;
color: #afafaf;
}
h2 {
font-size: 2rem !important;
}
h4 {
font-size: 1.3rem;
}
h5.card-title {
font-size: 1.2rem;
}
.page-header {
border-left: .01rem solid #d2d2d2;
border-bottom: .01rem solid #d2d2d2;
}
.sidebar-light .nav-item.active .nav-link i {
color: #d2d2d2;
}
.sidebar .nav-item.active .nav-link {
font-weight: 400;
}
#wrapper #content-wrapper #content {
background-color: #202020;
}
.topbar {
background-color: #202020;
}
.nav-tabs {
border-bottom: 1px solid #404040;
}
.nav-tabs .nav-link.active,
.nav-tabs .nav-link {
font-size: 1.0rem;
}
.nav-tabs .nav-link:hover {
border-color: transparent;
}
.navbar-default .navbar-brand:hover {
color: #d2d2d2;
}
.navbar-default .navbar-toggle {
border-color: #d2d2d2;
}
.navbar-default .navbar-toggle .icon-bar {
background-color: #d2d2d2;
}
.navbar-default .navbar-toggle:focus,
.navbar-default .navbar-toggle:hover {
background-color: #202020;
}
#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: #d2d2d2;
background-color: #141414;
border-color: #404040 #404040 #141414;
}
a:focus, a:hover {
color: #d2d2d2;
}
.card>.card-header, .modal-content, .modal-header {
border-color: #404040;
background-color: #202020;
color: #afafaf;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
font-size: 1.0rem;
font-weight: 400;
}
.modal-body {
background-color: #141414;
}
.card>.card-header .fa {
color: #202020;
}
.card-header [class^="fa"] {
color: #afafaf;
font-size: 1.0rem;
}
.col {
color: #afafaf;
}
.card, .card-body {
border-color: #343434;
border-radius: 3px;
background-color: #141414;
}
hr {
border-top: .01rem solid #d2d2d2;
}
.sidebar-brand-text {
color: #2b8080 !important;
}
.ra-raspap:before {
color: #ac1b3d !important;
}
.sidebar-light #sidebarToggle {
background-color: #202020;
border: 1px solid #afafaf !important
}
.sidebar-light #sidebarToggle::after {
color: #afafaf;
}
.sidebar-light .nav-item .nav-link:hover i {
color: #d2d2d2;
}
.sidebar-light #sidebarToggle:hover {
background-color: #202020;
}
.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: #202020;
border-top: 0px;
}
.modal-footer {
border-radius: 0.3rem;
}
.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: #202020;
}
.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 #404040;
padding-top: 0.5rem;
}
.sidebar .nav-item .nav-link span {
font-size: 1.0rem;
}
.topbar .topbar-divider {
border-right: 1px solid #404040;
}
.label-warning {
background-color: #d2d2d2;
}
span.label.label-warning {
color: #202020;
}
.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: #202020;
border-top: .01rem solid #202020;
}
.table>thead>tr>th {
vertical-align: bottom;
border-bottom: .01rem solid #d2d2d2;
}
[class*="btn"], [class*="btn"]:focus, [class*="btn"]:disabled {
background-color: #202020;
border-color: #404040;
border-radius: 3px;
color: #d2d2d2;
}
[class*="btn"]:hover {
border-radius: 3px;
color: #d2d2d2;
background-color: #202020;
border-color: #afafaf;
}
[class*="btn"]:hover .disabled {
background-color:red;
}
[class*="alert"] {
border-radius: .35rem;
color: #d2d2d2;
background-color: #202020;
border: 1px solid #404040;
}
.close {
font-size: 1.2em;
font-weight: 400;
text-shadow: none;
color: #d2d2d2;
}
.form-control,
.form-control:focus,
.custom-select {
color: #d2d2d2;
background-color: #202020;
border: 1px solid #404040;
border-radius: 3px;
}
.form-control:disabled,
.form-control[readonly] {
background-color: #202020;
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; }
input[type="text"]{
color: #d2d2d2 !important
}
.progress {
background-color: #202020;
border-radius: 0px;
}
.progress-bar {
color: #202020;
}
.progress-bar.progress-bar-info.progress-bar-striped.active {
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 {
background-color: #202020;
border-color: #404040;
}
.text-muted {
font-size: 0.8rem;
}
.fas.fa-circle {
font-size: 0.7rem;
}
pre {
background-color: #202020;
border: #202020;
}
button.btn.btn-light.js-toggle-password {
border: 1px solid #343434;
}
.signal-icon .signal-bar {
background: #2b8080;
}

View file

@ -1,644 +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; ?>;
min-height: 8rem;
}
.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; ?>;
}
.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;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1),
0px 4px 6px rgba(0, 0, 0, 0.1);
}
.modal-footer {
margin-top: 0px;
height: 3.5rem;
}
.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;
padding: 0.5rem;
}
.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;
}
.was-validated .form-control:valid,
.was-validated .form-control:invalid {
background-position: center right calc(.375em + .4875rem);
}
.was-validated .form-control:invalid {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-control:valid {
background-size: calc(0.6em + 0.375rem) calc(0.6em + 0.375rem);
}

View file

@ -1,650 +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; ?>;
min-height: 8rem;
}
.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; ?>;
}
.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;
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1),
0px 4px 6px rgba(0, 0, 0, 0.1);
}
.modal-footer {
margin-top: 0px;
height: 3.5rem;
}
.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;
padding: 0.5rem;
}
.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;
}
.was-validated .form-control:valid,
.was-validated .form-control:invalid {
background-position: center right calc(.375em + .4875rem);
}
.was-validated .form-control:invalid {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.was-validated .form-control:valid {
background-size: calc(0.6em + 0.375rem) calc(0.6em + 0.375rem);
}

54
app/img/dashed.svg Normal file
View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 227 596" style="enable-background:new 0 0 227 596;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#999999;stroke-width:3;}
.st1{fill:none;stroke:#999999;stroke-width:3;stroke-dasharray:6.0204,3.0102;}
.st2{fill:none;stroke:#999999;stroke-width:3;stroke-dasharray:5.7963,2.8981;}
</style>
<g id="dashed">
<g id="Line_1">
<g>
<line class="st0" x1="112.8" y1="0" x2="112.8" y2="3"/>
<line class="st1" x1="112.8" y1="6" x2="112.8" y2="591.5"/>
<line class="st0" x1="112.8" y1="593" x2="112.8" y2="596"/>
</g>
</g>
<g id="Line_2">
<g>
<line class="st0" x1="113.2" y1="0.8" x2="110.2" y2="0.8"/>
<line class="st2" x1="107.3" y1="0.8" x2="4.4" y2="0.8"/>
<line class="st0" x1="3" y1="0.8" x2="0" y2="0.8"/>
</g>
</g>
<g id="Line_3">
<g>
<line class="st0" x1="113.2" y1="198.9" x2="110.2" y2="198.9"/>
<line class="st2" x1="107.3" y1="198.9" x2="4.4" y2="198.9"/>
<line class="st0" x1="3" y1="198.9" x2="0" y2="198.9"/>
</g>
</g>
<g id="Line_4">
<g>
<line class="st0" x1="113.2" y1="397.1" x2="110.2" y2="397.1"/>
<line class="st2" x1="107.3" y1="397.1" x2="4.4" y2="397.1"/>
<line class="st0" x1="3" y1="397.1" x2="0" y2="397.1"/>
</g>
</g>
<g id="Line_5">
<g>
<line class="st0" x1="113.2" y1="595.2" x2="110.2" y2="595.2"/>
<line class="st2" x1="107.3" y1="595.2" x2="4.4" y2="595.2"/>
<line class="st0" x1="3" y1="595.2" x2="0" y2="595.2"/>
</g>
</g>
<g id="Line_6">
<g>
<line class="st0" x1="226.2" y1="297.8" x2="223.2" y2="297.8"/>
<line class="st2" x1="220.3" y1="297.8" x2="117.4" y2="297.8"/>
<line class="st0" x1="116" y1="297.8" x2="113" y2="297.8"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

1083
app/img/devices/compute.php Normal file

File diff suppressed because it is too large Load diff

4450
app/img/devices/default.php Normal file

File diff suppressed because it is too large Load diff

1561
app/img/devices/zero.php Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

0
app/img/raspAP-logo.php Normal file → Executable file
View file

40
app/img/right-dashed.svg Normal file
View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 314 594" style="enable-background:new 0 0 314 594;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#999999;stroke-width:3;}
.st1{fill:none;stroke:#999999;stroke-width:3;stroke-dasharray:6.04,3.02;}
.st2{fill:none;stroke:#999999;stroke-width:3;stroke-dasharray:5.7963,2.8981;}
</style>
<g id="dashed">
<g id="horizontal">
<g>
<line class="st0" x1="113.2" y1="144" x2="113.2" y2="147"/>
<line class="st1" x1="113.2" y1="150" x2="113.3" y2="447.5"/>
<line class="st0" x1="113.3" y1="449" x2="113.3" y2="452"/>
</g>
</g>
<g id="top">
<g>
<line class="st0" x1="114" y1="144.8" x2="117" y2="144.8"/>
<line class="st2" x1="119.9" y1="144.8" x2="222.8" y2="144.8"/>
<line class="st0" x1="224.2" y1="144.8" x2="227.2" y2="144.8"/>
</g>
</g>
<g id="out">
<g>
<line class="st0" x1="0" y1="297.8" x2="3" y2="297.8"/>
<line class="st2" x1="5.9" y1="297.8" x2="108.8" y2="297.8"/>
<line class="st0" x1="110.2" y1="297.8" x2="113.2" y2="297.8"/>
</g>
</g>
<g id="bottom">
<g>
<line class="st0" x1="113" y1="450.8" x2="116" y2="450.8"/>
<line class="st2" x1="118.9" y1="450.8" x2="221.8" y2="450.8"/>
<line class="st0" x1="223.2" y1="450.8" x2="226.2" y2="450.8"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

46
app/img/right-solid.php Normal file
View file

@ -0,0 +1,46 @@
<?php
header("Content-Type: image/svg+xml");
$showDevice1 = isset($_GET['device-1']);
$showOut = isset($_GET['out']);
$showDevice2 = isset($_GET['device-2']);
?>
<svg width="313" height="594" viewBox="0 0 313 594" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Frame 1">
<g id="right connection frame">
<g id="solid">
<?php if ($showDevice2): ?>
<line id="joint-device-2" y1="-0.75" x2="154" y2="-0.75"
transform="matrix(4.37114e-08 1 1 -4.37114e-08 114 297)"
stroke="#008281" stroke-width="4"/>
<?php endif; ?>
<?php if ($showDevice1): ?>
<line id="joint-device-1" style="display: inline;"
y1="-0.75" x2="154" y2="-0.75"
transform="matrix(4.37114e-08 1 1 -4.37114e-08 114 144)"
stroke="#008281" stroke-width="4"/>
<line id="device-1" style="display: inline;"
y1="-0.75" x2="113.231" y2="-0.75"
transform="matrix(1 8.74228e-08 8.74228e-08 -1 114 144)"
stroke="#008281" stroke-width="4"/>
<?php endif; ?>
<?php if ($showOut): ?>
<line id="out" style="display: inline;"
y1="-0.75" x2="113.231" y2="-0.75"
transform="matrix(1 8.74228e-08 8.74228e-08 -1 -0.000305176 297)"
stroke="#008281" stroke-width="4"/>
<?php endif; ?>
<?php if ($showDevice2): ?>
<line id="device-2" style="display: inline;"
y1="-0.75" x2="113.231" y2="-0.75"
transform="matrix(1 8.74228e-08 8.74228e-08 -1 113 450)"
stroke="#008281" stroke-width="4"/>
<?php endif; ?>
</g>
</g>
</g>
</svg>

65
app/img/solid.php Normal file
View file

@ -0,0 +1,65 @@
<?php
header("Content-Type: image/svg+xml");
require_once '../../includes/functions.php';
$color = getColorOpt();
$showJoint = isset($_GET['joint']);
$showDevice1 = isset($_GET['device-1']);
$showOut = isset($_GET['out']);
$showDevice2 = isset($_GET['device-2']);
$showDevice3 = isset($_GET['device-3']);
$showDevice4 = isset($_GET['device-4']);
?>
<svg xmlns="http://www.w3.org/2000/svg" width="227" height="596" viewBox="0 0 227 596" fill="none">
<?php
// Device positions array (y-coordinates)
$devicePositions = [
'device-1' => 0.75,
'out' => 297.75,
'device-2' => 198.75,
'device-3' => 397.058,
'device-4' => 595.211
];
// Calculate joint line segments
if ($showJoint) {
$activeDevices = array_filter([$showDevice1, $showDevice2, $showDevice3, $showDevice4]);
$activeYs = [];
foreach ($devicePositions as $device => $y) {
if (isset($_GET[$device])) {
$activeYs[] = $y;
}
}
// Add top/bottom if first/last device is connected
if ($showDevice1) array_unshift($activeYs, 0);
if ($showDevice4) $activeYs[] = 596;
// Draw segments between consecutive points
for ($i = 1; $i < count($activeYs); $i++) {
$y1 = $activeYs[$i-1];
$y2 = $activeYs[$i];
echo "<line x1='112.75' y1='$y1' x2='112.75' y2='$y2' stroke='$color' stroke-width='4'/>";
}
}
?>
<?php if ($showDevice1): ?>
<line x1="113.231" y1="0.75" x2="7.69496e-06" y2="0.75001" stroke="<?php echo $color; ?>" stroke-width="6" id="device-1"/>
<?php endif; ?>
<?php if ($showOut): ?>
<line x1="226.231" y1="297.75" x2="113" y2="297.75" stroke="<?php echo $color; ?>" stroke-width="4" id="out"/>
<?php endif; ?>
<?php if ($showDevice2): ?>
<line x1="113.231" y1="198.75" x2="7.69496e-06" y2="198.75" stroke="<?php echo $color; ?>" stroke-width="4" id="device-2"/>
<?php endif; ?>
<?php if ($showDevice3): ?>
<line x1="113.231" y1="397.058" x2="7.69496e-06" y2="397.058" stroke="<?php echo $color; ?>" stroke-width="4" id="device-3"/>
<?php endif; ?>
<?php if ($showDevice4): ?>
<line x1="113.231" y1="595.211" x2="7.69496e-06" y2="595.211" stroke="<?php echo $color; ?>" stroke-width="4" id="device-4"/>
<?php endif; ?>
</svg>

29
app/img/uri-qr-code.php Executable file
View file

@ -0,0 +1,29 @@
<?php
if (!isset($_GET['uri']) || !filter_var($_GET['uri'], FILTER_VALIDATE_URL)) {
header("HTTP/1.1 400 Bad Request");
exit("Invalid or missing URI parameter");
}
$uri = $_GET['uri'];
$command = "qrencode -t svg -m 0 -o - " . escapeshellarg($uri);
$svg = shell_exec($command);
if ($svg === null) {
error_log("QR generation failed for URI: $uri");
header("HTTP/1.1 500 Internal Server Error");
exit("Failed to generate QR code");
}
$etag = hash('sha256', $uri);
$content_length = strlen($svg);
$last_modified = gmdate("D, d M Y H:i:s") . " GMT";
header("Content-Type: image/svg+xml");
header("Content-Length: $content_length");
header("Last-Modified: $last_modified");
header("ETag: \"$etag\"");
header("X-QR-Code-Content: " . htmlspecialchars($uri, ENT_QUOTES, 'UTF-8'));
echo $svg;

3
app/img/wg-qr-code.php Normal file → Executable file
View file

@ -13,6 +13,7 @@ if (!isset($_SERVER['HTTP_REFERER'])) {
exec("sudo cat " .RASPI_WIREGUARD_PATH.'client.conf', $return);
$peer_conf = implode(PHP_EOL,$return);
$peer_conf.= PHP_EOL;
$peer_conf_sanitized = str_replace(["\r", "\n"], '', $peer_conf);
$command = "qrencode -t svg -m 0 -o - " . mb_escapeshellarg($peer_conf);
$svg = shell_exec($command);
$etag = hash('sha256', $peer_conf);
@ -23,6 +24,6 @@ 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");
header("X-QR-Code-Content: $peer_conf_sanitized");
echo shell_exec($command);

8
app/img/wifi-qr-code.php Normal file → Executable file
View file

@ -12,12 +12,12 @@ if (!isset($_SERVER['HTTP_REFERER'])) {
$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
$type = "WPA";
$password = isset($hostapd['wpa_psk']) ? $hostapd['wpa_psk'] : $hostapd['wpa_passphrase'];
// use wep if configured
$wep_default_key = intval($hostapd['wep_default_key']);
// use WEP if configured
$wep_default_key = intval($hostapd['wep_default_key'] ?? 0);
$wep_key = 'wep_key' . $wep_default_key;
if (array_key_exists($wep_key, $hostapd)) {
$type = "WEP";
@ -30,7 +30,7 @@ if (empty($password)) {
}
$ssid = $hostapd['ssid'];
$hidden = intval($hostapd['ignore_broadcast_ssid']) != 0 ? "H:true" : "";
$hidden = intval($hostapd['ignore_broadcast_ssid'] ?? 0) !== 0 ? "H:true" : "";
$ssid = qr_encode($ssid);
$password = qr_encode($password);

View file

@ -3,7 +3,7 @@ function msgShow(retcode,msg) {
} else if(retcode == 2 || retcode == 1) {
var alertType = 'danger';
}
var htmlMsg = '<div class="alert alert-'+alertType+' alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>'+msg+'</div>';
var htmlMsg = '<div class="alert alert-'+alertType+' alert-dismissible" role="alert"><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'+msg+'</div>';
return htmlMsg;
}
@ -24,7 +24,7 @@ function loadSummary(strInterface) {
if(jsonData['return'] == 0) {
$('#'+strInterface+'-summary').html(jsonData['output'].join('<br />'));
} else if(jsonData['return'] == 2) {
$('#'+strInterface+'-summary').append('<div class="alert alert-danger alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>'+jsonData['output'].join('<br />')+'</div>');
$('#'+strInterface+'-summary').append('<div class="alert alert-danger alert-dismissible" role="alert"><button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'+jsonData['output'].join('<br />')+'</div>');
}
});
}
@ -39,7 +39,7 @@ function getAllInterfaces() {
}
function setupTabs() {
$('a[data-toggle="tab"]').on('shown.bs.tab',function(e){
$('a[data-bs-toggle="tab"]').on('shown.bs.tab',function(e){
var target = $(e.target).attr('href');
if(!target.match('summary')) {
var int = target.replace("#","");
@ -122,6 +122,10 @@ $(document).on("click", "#gen_wpa_passphrase", function(e) {
$('#txtwpapassphrase').val(genPassword(63));
});
$(document).on("click", "#gen_apikey", function(e) {
$('#txtapikey').val(genPassword(32).toLowerCase());
});
$(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){
@ -149,7 +153,7 @@ $(document).on("click", "#js-clearopenvpn-log", function(e) {
// Enable Bootstrap tooltips
$(function () {
$('[data-toggle="tooltip"]').tooltip()
$('[data-bs-toggle="tooltip"]').tooltip()
})
function genPassword(pwdLen) {
@ -212,7 +216,8 @@ 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){
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/networking/get_netcfg.php', {'iface' : strInterface, 'csrf_token': csrfToken}, function(data){
jsonData = JSON.parse(data);
$('#dhcp-iface')[0].checked = jsonData.DHCPEnabled;
$('#txtipaddress').val(jsonData.StaticIP);
@ -237,16 +242,13 @@ function loadInterfaceDHCPSelect() {
$('#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();
$('#chkstatic').prop('checked', true).closest('.btn').addClass('active');
$('#chkdhcp').prop('checked', false).closest('.btn').removeClass('active');
$('#chkfallback').prop('disabled', true);
$('#dhcp-iface').removeAttr('disabled');
} else {
$('#chkdhcp').closest('.btn').button('toggle');
$('#chkdhcp').closest('.btn').button('toggle').blur();
$('#chkdhcp').blur();
$('#chkfallback').prop('disabled', false);
$('#chkdhcp').closest('.btn').addClass('active');
$('#chkdhcp').closest('.btn').button.blur();
}
if (jsonData.FallbackEnabled || $('#chkdhcp').is(':checked')) {
$('#dhcp-iface').prop('disabled', true);
@ -267,15 +269,109 @@ function setDHCPToggles(state) {
$('#dhcp-iface').prop('disabled', !state);
}
$('#chkfallback').change(function() {
if ($('#chkfallback').is(':checked')) {
setStaticFieldsEnabled();
} else {
setStaticFieldsDisabled();
}
});
$('#debugModal').on('shown.bs.modal', function (e) {
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_debug.php',{'csrf_token': csrfToken},function(data){
var filePath = JSON.parse(data);
window.location.replace('/ajax/system/sys_get_logfile.php?filePath='+filePath);
window.location.replace('/ajax/system/sys_get_logfile.php');
$('#debugModal').modal('hide');
});
});
$('#chkupdateModal').on('shown.bs.modal', function (e) {
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_chk_update.php',{'csrf_token': csrfToken},function(data){
var response = JSON.parse(data);
var tag = response.tag;
var update = response.update;
var msg;
var msgUpdate = $('#msgUpdate').data('message');
var msgLatest = $('#msgLatest').data('message');
var msgInstall = $('#msgInstall').data('message');
var msgDismiss = $('#js-check-dismiss').data('message');
var faCheck = '<i class="fas fa-check ms-2"></i><br />';
$("#updateSync").removeClass("fa-spin");
if (update === true) {
msg = msgUpdate +' '+tag;
$("#msg-check-update").html(msg);
$("#msg-check-update").append(faCheck);
$("#msg-check-update").append("<p>"+msgInstall+"</p>");
$("#js-sys-check-update").removeClass("collapse");
} else {
msg = msgLatest;
dismiss = $("#js-check-dismiss");
$("#msg-check-update").html(msg);
$("#msg-check-update").append(faCheck);
$("#js-sys-check-update").remove();
dismiss.text(msgDismiss);
dismiss.removeClass("btn-outline-secondary");
dismiss.addClass("btn-primary");
}
});
});
$('#performUpdate').on('submit', function(event) {
event.preventDefault();
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/system/sys_perform_update.php',{
'csrf_token': csrfToken
})
$('#chkupdateModal').modal('hide');
$('#performupdateModal').modal('show');
});
$('#performupdateModal').on('shown.bs.modal', function (e) {
fetchUpdateResponse();
});
function fetchUpdateResponse() {
const complete = 6;
const error = 7;
let phpFile = 'ajax/system/sys_read_logfile.php';
$.ajax({
url: phpFile,
type: 'GET',
success: function(response) {
for (let i = 1; i <= 6; i++) {
let divId = '#updateStep' + i;
if (response.includes(i.toString())) {
$(divId).removeClass('invisible');
}
}
// check if the update is complete or if there's an error
if (response.includes(complete)) {
var successMsg = $('#successMsg').data('message');
$('#updateMsg').after('<span class="small">' + successMsg + '</span>');
$('#updateMsg').addClass('fa-check');
$('#updateMsg').removeClass('invisible');
$('#updateStep6').removeClass('invisible');
$('#updateSync2').removeClass("fa-spin");
$('#updateOk').removeAttr('disabled');
} else if (response.includes(error)) {
var errorMsg = $('#errorMsg').data('message');
$('#updateMsg').after('<span class="small">' + errorMsg + '</span>');
$('#updateMsg').addClass('fa-times');
$('#updateMsg').removeClass('invisible');
$('#updateSync2').removeClass("fa-spin");
$('#updateOk').removeAttr('disabled');
} else {
setTimeout(fetchUpdateResponse, 500);
}
},
error: function(xhr, status, error) {
console.error("AJAX Error:", error);
}
});
}
$('#hostapdModal').on('shown.bs.modal', function (e) {
var seconds = 3;
var pct = 0;
@ -342,7 +438,7 @@ $('#js-system-reset-confirm').on('click', function (e) {
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>';
var progressHtml = $('<div>').text(progressText).html() + '<i class="fas fa-cog fa-spin ms-2"></i>';
$('#system-reset-message').html(progressHtml);
$.post('ajax/networking/do_sys_reset.php?',{'csrf_token':csrfToken},function(data){
setTimeout(function(){
@ -367,6 +463,139 @@ $('#js-sys-reboot, #js-sys-shutdown').on('click', function (e) {
});
});
$('#install-user-plugin').on('shown.bs.modal', function (e) {
var button = $(e.relatedTarget);
$(this).data('button', button);
var manifestData = button.data('plugin-manifest');
var installed = button.data('plugin-installed') || false;
var repoPublic = button.data('repo-public') || false;
var installPath = manifestData.install_path;
if (!installed && repoPublic && installPath === 'plugins-available') {
insidersHTML = 'Available with <i class="fas fa-heart heart me-1"></i><a href="https://docs.raspap.com/insiders" target="_blank" rel="noopener">Insiders</a>';
$('#plugin-additional').html(insidersHTML);
} else {
$('#plugin-additional').empty();
}
if (manifestData) {
$('#plugin-docs').html(manifestData.plugin_docs
? `<a href="${manifestData.plugin_docs}" target="_blank">${manifestData.plugin_docs}</a>`
: 'Unknown');
$('#plugin-icon').attr('class', `${manifestData.icon || 'fas fa-plug'} link-secondary h5 me-2`);
$('#plugin-name').text(manifestData.name || 'Unknown');
$('#plugin-version').text(manifestData.version || 'Unknown');
$('#plugin-description').text(manifestData.description || 'No description provided');
$('#plugin-author').html(manifestData.author
? manifestData.author + (manifestData.author_uri
? ` (<a href="${manifestData.author_uri}" target="_blank">profile</a>)` : '') : 'Unknown');
$('#plugin-license').text(manifestData.license || 'Unknown');
$('#plugin-locale').text(manifestData.default_locale || 'Unknown');
$('#plugin-configuration').html(formatProperty(manifestData.configuration || 'None'));
$('#plugin-packages').html(formatProperty(manifestData.keys || 'None'));
$('#plugin-dependencies').html(formatProperty(manifestData.dependencies || 'None'));
$('#plugin-javascript').html(formatProperty(manifestData.javascript || 'None'));
$('#plugin-sudoers').html(formatProperty(manifestData.sudoers || 'None'));
$('#plugin-user-name').html((manifestData.user_nonprivileged && manifestData.user_nonprivileged.name) || 'None');
}
if (installed) {
$('#js-install-plugin-confirm').html('OK');
} else if (!installed && repoPublic && installPath == 'plugins-available') {
$('#js-install-plugin-confirm').html('Get Insiders');
} else {
$('#js-install-plugin-confirm').html('Install now');
}
});
$('#js-install-plugin-confirm').on('click', function (e) {
var button = $('#install-user-plugin').data('button');
var manifestData = button.data('plugin-manifest');
var installPath = manifestData.install_path;
var pluginUri = manifestData.plugin_uri;
var pluginVersion = manifestData.version;
var pluginConfirm = $('#js-install-plugin-confirm').text();
var progressText = $('#js-install-plugin-confirm').attr('data-message');
var successHtml = $('#plugin-install-message').attr('data-message');
var successText = $('<div>').text(successHtml).text();
var csrfToken = $('meta[name=csrf_token]').attr('content');
if (pluginConfirm === 'Install now') {
$("#install-user-plugin").modal('hide');
$("#install-plugin-progress").modal('show');
$.post(
'ajax/plugins/do_plugin_install.php',
{
'plugin_uri': pluginUri,
'plugin_version': pluginVersion,
'install_path': installPath,
'csrf_token': csrfToken
},
function (data) {
setTimeout(function () {
response = JSON.parse(data);
if (response === true) {
$('#plugin-install-message').contents().first().text(successText);
$('#plugin-install-message')
.find('i')
.removeClass('fas fa-cog fa-spin link-secondary')
.addClass('fas fa-check');
$('#js-install-plugin-ok').removeAttr("disabled");
} else {
const errorMessage = jsonData.error || 'An unknown error occurred.';
var errorLog = '<textarea class="plugin-log text-secondary" readonly>' + errorMessage + '</textarea>';
$('#plugin-install-message')
.contents()
.first()
.replaceWith('An error occurred installing the plugin:');
$('#plugin-install-message').append(errorLog);
$('#plugin-install-message').find('i').removeClass('fas fa-cog fa-spin link-secondary');
$('#js-install-plugin-ok').removeAttr("disabled");
}
}, 200);
}
).fail(function (xhr) {
const jsonData = JSON.parse(xhr.responseText);
const errorMessage = jsonData.error || 'An unknown error occurred.';
$('#plugin-install-message')
.contents()
.first()
.replaceWith('An error occurred installing the plugin:');
var errorLog = '<textarea class="plugin-log text-secondary" readonly>' + errorMessage + '</textarea>';
$('#plugin-install-message').append(errorLog);
$('#plugin-install-message').find('i').removeClass('fas fa-cog fa-spin link-secondary');
$('#js-install-plugin-ok').removeAttr("disabled");
});
} else if (pluginConfirm === 'Get Insiders') {
window.open('https://docs.raspap.com/insiders/', '_blank');
return;
} else if (pluginConfirm === 'OK') {
$("#install-user-plugin").modal('hide');
}
});
$('#js-install-plugin-ok').on('click', function (e) {
$("#install-plugin-progress").modal('hide');
window.location.reload();
});
function formatProperty(prop) {
if (Array.isArray(prop)) {
if (typeof prop[0] === 'object') {
return prop.map(item => {
return Object.entries(item)
.map(([key, value]) => `${key}: ${value}`)
.join('<br/>');
}).join('<br/><br/>');
}
return prop.map(line => `${line}<br/>`).join('');
}
if (typeof prop === 'object') {
return Object.entries(prop)
.map(([key, value]) => `${key}: ${value}`)
.join('<br/>');
}
return prop || 'None';
}
$(document).ready(function(){
$("#PanelManual").hide();
$('.ip_address').mask('0ZZ.0ZZ.0ZZ.0ZZ', {
@ -377,6 +606,23 @@ $(document).ready(function(){
},
placeholder: "___.___.___.___"
});
$('.date').mask('FF:FF:FF:FF:FF:FF', {
translation: {
"F": {
pattern: /[0-9a-z]/, optional: true
}
},
placeholder: "__:__:__:__:__:__"
});
});
$(document).ready(function() {
$('.cidr').mask('099.099.099.099/099', {
translation: {
'0': { pattern: /[0-9]/ }
},
placeholder: "___.___.___.___/___"
});
});
$('#wg-upload,#wg-manual').on('click', function (e) {
@ -389,7 +635,6 @@ $('#wg-upload,#wg-manual').on('click', function (e) {
}
});
// 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);
@ -505,18 +750,18 @@ function clearBlocklistStatus() {
$('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden');
}
// Handler for the wireguard generate key button
// 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 parentGroup = $(this).closest('.input-group');
var entity_pub = parentGroup.find('input[type="text"]');
var updated = entity_pub.attr('name')+"-pubkey-status";
var csrfToken = $('meta[name=csrf_token]').attr('content');
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(){
@ -553,6 +798,44 @@ window.addEventListener('load', function() {
});
}, false);
let sessionCheckInterval = setInterval(checkSession, 5000);
function checkSession() {
// skip session check if on login page
if (window.location.pathname === '/login') {
return;
}
var csrfToken = $('meta[name=csrf_token]').attr('content');
$.post('ajax/session/do_check_session.php',{'csrf_token': csrfToken},function (data) {
if (data.status === 'session_expired') {
clearInterval(sessionCheckInterval);
showSessionExpiredModal();
}
}).fail(function (jqXHR, status, err) {
console.error("Error checking session status:", status, err);
});
}
function showSessionExpiredModal() {
$('#sessionTimeoutModal').modal('show');
}
$(document).on("click", "#js-session-expired-login", function(e) {
const loginModal = $('#modal-admin-login');
const redirectUrl = window.location.pathname;
window.location.href = `/login?action=${encodeURIComponent(redirectUrl)}`;
});
// show modal login on page load
$(document).ready(function () {
const params = new URLSearchParams(window.location.search);
const redirectUrl = $('#redirect-url').val() || params.get('action') || '/';
$('#modal-admin-login').modal('show');
$('#redirect-url').val(redirectUrl);
$('#username').focus();
$('#username').addClass("focusedInput");
});
// DHCP or Static IP option group
$('#chkstatic').on('change', function() {
if (this.checked) {
@ -628,20 +911,19 @@ function setDhcpFieldsDisabled() {
Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
$(document).on("click", ".js-toggle-password", function(e) {
var button = $(e.target)
var field = $(button.data("target"));
var button = $(e.currentTarget);
var field = $(button.data("bsTarget"));
if (field.is(":input")) {
e.preventDefault();
if (!button.data("__toggle-with-initial")) {
$("i", this).removeClass("fas fa-eye").addClass(button.attr("data-toggle-with"));
$("i", button).removeClass("fas fa-eye").addClass(button.attr("data-toggle-with"));
}
if (field.attr("type") === "password") {
field.attr("type", "text");
} else {
$("i", this).removeClass("fas fa-eye-slash").addClass("fas fa-eye");
$("i", button).removeClass("fas fa-eye-slash").addClass("fas fa-eye");
field.attr("type", "password");
}
}
@ -649,8 +931,18 @@ $(document).on("click", ".js-toggle-password", function(e) {
$(function() {
$('#theme-select').change(function() {
var theme = themes[$( "#theme-select" ).val() ];
set_theme(theme);
var theme = themes[$( "#theme-select" ).val() ];
var hasDarkTheme = theme === 'custom.php';
var nightModeChecked = $("#night-mode").prop("checked");
if (nightModeChecked && hasDarkTheme) {
if (theme === "custom.php") {
set_theme("dark.css");
}
} else {
set_theme(theme);
}
});
});
@ -663,7 +955,7 @@ function set_theme(theme) {
$(function() {
var currentTheme = getCookie('theme');
// Check if the current theme is a dark theme
var isDarkTheme = currentTheme === 'lightsout.css' || currentTheme === 'material-dark.php';
var isDarkTheme = currentTheme === 'dark.css';
$('#night-mode').prop('checked', isDarkTheme);
$('#night-mode').change(function() {
@ -672,15 +964,11 @@ $(function() {
if (state == true) {
if (currentTheme == 'custom.php') {
set_theme('lightsout.css');
} else if (currentTheme == 'material-light.php') {
set_theme('material-dark.php');
set_theme('dark.css');
}
} else {
if (currentTheme == 'lightsout.css') {
if (currentTheme == 'dark.css') {
set_theme('custom.php');
} else if (currentTheme == 'material-dark.php') {
set_theme('material-light.php');
}
}
});
@ -702,50 +990,49 @@ function getCookie(cname) {
// Define themes
var themes = {
"default": "custom.php",
"hackernews" : "hackernews.css",
"lightsout" : "lightsout.css",
"material-light" : "material-light.php",
"material-dark" : "material-dark.php",
"hackernews" : "hackernews.css"
}
// Toggles the sidebar navigation.
// Overrides the default SB Admin 2 behavior
$("#sidebarToggleTopbar").on('click', function(e) {
$("body").toggleClass("sidebar-toggled");
$(".sidebar").toggleClass("toggled d-none");
});
// Overrides SB Admin 2
$("#sidebarToggle, #sidebarToggleTop").on('click', function(e) {
var toggled = $(".sidebar").hasClass("toggled");
// Persist state in cookie
setCookie('sidebarToggled',toggled, 90);
});
$(function() {
if ($(window).width() < 768) {
$('.sidebar').addClass('toggled');
setCookie('sidebarToggled',false, 90);
}
});
$(window).on("load resize",function(e) {
if ($(window).width() > 768) {
$('.sidebar').removeClass('d-none d-md-block');
if (getCookie('sidebarToggled') == 'false') {
$('.sidebar').removeClass('toggled');
}
}
});
// Adds active class to current nav-item
$(window).bind("load", function() {
var url = window.location;
$('ul.navbar-nav a').filter(function() {
$('.sb-nav-link-icon a').filter(function() {
return this.href == url;
}).parent().addClass('active');
});
// Sets focus on a specified tab
document.addEventListener("DOMContentLoaded", function () {
const params = new URLSearchParams(window.location.search);
const targetTab = params.get("tab");
if (targetTab) {
let tabElement = document.querySelector(`[data-bs-toggle="tab"][href="#${targetTab}"]`);
if (tabElement) {
let tab = new bootstrap.Tab(tabElement);
tab.show();
}
}
});
function disableValidation(form) {
form.removeAttribute("novalidate");
form.classList.remove("needs-validation");
form.querySelectorAll("[required]").forEach(function (field) {
field.removeAttribute("required");
});
}
$(document).ready(function() {
const $htmlElement = $('html');
const $modeswitch = $('#night-mode');
$modeswitch.on('change', function() {
const isChecked = $(this).is(':checked');
const newTheme = isChecked ? 'dark' : 'light';
$htmlElement.attr('data-bs-theme', newTheme);
localStorage.setItem('bsTheme', newTheme);
});
});
$(document)
.ajaxSend(setCSRFTokenHeader)
.ready(contentLoaded)

View file

@ -13,12 +13,15 @@
}
],
"require": {
"php": "^7.0"
"php": "^8.2",
"phpoption/phpoption": "^1.9",
"ext-mbstring": "*"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2.0",
"phpcompatibility/php-compatibility": "^9.3.5",
"squizlabs/php_codesniffer": "^3.5.5"
"squizlabs/php_codesniffer": "^3.9.0",
"ext-simplexml": "*"
},
"scripts": {
"lint": "parallel-lint . --exclude vendor",

View file

@ -1,13 +1,18 @@
<?php
define('RASPI_BRAND_TEXT', 'RaspAP');
define('RASPI_BRAND_TITLE', RASPI_BRAND_TEXT.' Admin Panel');
define('RASPI_CONFIG', '/etc/raspap');
define('RASPI_CONFIG_NETWORK', RASPI_CONFIG.'/networking/defaults.json');
define('RASPI_CONFIG_PROVIDERS', 'config/vpn-providers.json');
define('RASPI_CONFIG_API', RASPI_CONFIG.'/api');
define('RASPI_ADMIN_DETAILS', RASPI_CONFIG.'/raspap.auth');
define('RASPI_WIFI_AP_INTERFACE', 'wlan0');
define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
define('RASPI_ERROR_LOG', sys_get_temp_dir() . '/raspap_error.log');
define('RASPI_DEBUG_LOG', 'raspap_debug.log');
define('RASPI_LOG_SIZE_LIMIT', 64);
define('RASPI_SESSION_TIMEOUT', 1440);
// Constants for configuration file paths.
// These are typical for default RPi installs. Modify if needed.
@ -18,6 +23,7 @@ define('RASPI_ADBLOCK_CONFIG', RASPI_DNSMASQ_PREFIX.'adblock.conf');
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
define('RASPI_DHCPCD_CONFIG', '/etc/dhcpcd.conf');
define('RASPI_DHCPCD_LOG', '/var/log/dnsmasq.log');
define('RASPI_HOSTAPD_LOG', '/tmp/hostapd.log');
define('RASPI_WPA_SUPPLICANT_CONFIG', '/etc/wpa_supplicant/wpa_supplicant.conf');
define('RASPI_HOSTAPD_CTRL_INTERFACE', '/var/run/hostapd');
define('RASPI_WPA_CTRL_INTERFACE', '/var/run/wpa_supplicant');
@ -31,6 +37,9 @@ define('RASPI_LIGHTTPD_CONFIG', '/etc/lighttpd/lighttpd.conf');
define('RASPI_ACCESS_CHECK_IP', '1.1.1.1');
define('RASPI_ACCESS_CHECK_DNS', 'one.one.one.one');
// Constant for the GitHub API latest release endpoint
define('RASPI_API_ENDPOINT', 'https://api.github.com/repos/RaspAP/raspap-webgui/releases/latest');
// Constant for the 5GHz wireless regulatory domain
define("RASPI_5GHZ_CHANNEL_MIN", 100);
define("RASPI_5GHZ_CHANNEL_MAX", 192);
@ -53,6 +62,8 @@ define('RASPI_CHANGETHEME_ENABLED', true);
define('RASPI_VNSTAT_ENABLED', true);
define('RASPI_SYSTEM_ENABLED', true);
define('RASPI_MONITOR_ENABLED', false);
define('RASPI_RESTAPI_ENABLED', false);
define('RASPI_PLUGINS_ENABLED', true);
// Locale settings
define('LOCALE_ROOT', 'locale');

View file

@ -15,4 +15,5 @@ interface wlan0
static ip_address=10.3.141.1/24
static routers=10.3.141.1
static domain_name_server=9.9.9.9 1.1.1.1
nogateway

View file

@ -4,7 +4,7 @@ ctrl_interface_group=0
beacon_int=100
auth_algs=1
wpa_key_mgmt=WPA-PSK
ssid=raspi-webgui
ssid=RaspAP
channel=1
hw_mode=g
wpa_passphrase=ChangeMe

View file

@ -50,6 +50,26 @@
"pattern": "(\\w+)\\s+",
"replace": "$1,$1\\n"
}
},
{
"id": 4,
"name": "AdGuard VPN",
"bin_path": "/usr/local/bin/adguardvpn-cli",
"install_page": "https://adguard-vpn.com/kb/adguard-vpn-for-linux/installation/",
"account_page": "https://my.adguard-vpn.com/en/account/product/vpn",
"cmd_overrides": {
"countries": "list-locations",
"connect": "connect -y -l",
"log": "status",
"account": "license",
"version": "--version"
},
"regex": {
"status": "\/vpn is disconnected\/",
"pattern": "/^([A-Z]{2})\\s+.*?\\s([A-Za-z]+(?:\\s[A-Za-z]+)?)\\s+\\d+$/m",
"replace": "$2",
"slice": 3
}
}
]
}

File diff suppressed because it is too large Load diff

1
dist/bootstrap/css/bootstrap.css.map vendored Normal file

File diff suppressed because one or more lines are too long

6
dist/bootstrap/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

7876
dist/font-awesome/css/all.css vendored Normal file

File diff suppressed because it is too large Load diff

9
dist/font-awesome/css/all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

1600
dist/font-awesome/css/brands.css vendored Normal file

File diff suppressed because it is too large Load diff

6
dist/font-awesome/css/brands.min.css vendored Normal file

File diff suppressed because one or more lines are too long

6215
dist/font-awesome/css/fontawesome.css vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

19
dist/font-awesome/css/regular.css vendored Normal file
View file

@ -0,0 +1,19 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
.far,
.fa-regular {
font-weight: 400; }

6
dist/font-awesome/css/regular.min.css vendored Normal file
View file

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}

19
dist/font-awesome/css/solid.css vendored Normal file
View file

@ -0,0 +1,19 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-style-family-classic: 'Font Awesome 6 Free';
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
@font-face {
font-family: 'Font Awesome 6 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
.fas,
.fa-solid {
font-weight: 900; }

6
dist/font-awesome/css/solid.min.css vendored Normal file
View file

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}

459
dist/font-awesome/css/svg-with-js.css vendored Normal file
View file

@ -0,0 +1,459 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
:root, :host {
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free';
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free';
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Pro';
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Pro';
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands';
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-regular: normal 400 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-light: normal 300 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-thin: normal 100 1em/1 'Font Awesome 6 Sharp';
--fa-font-sharp-duotone-solid: normal 900 1em/1 'Font Awesome 6 Sharp Duotone'; }
svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {
overflow: visible;
box-sizing: content-box; }
.svg-inline--fa {
display: var(--fa-display, inline-block);
height: 1em;
overflow: visible;
vertical-align: -.125em; }
.svg-inline--fa.fa-2xs {
vertical-align: 0.1em; }
.svg-inline--fa.fa-xs {
vertical-align: 0em; }
.svg-inline--fa.fa-sm {
vertical-align: -0.07143em; }
.svg-inline--fa.fa-lg {
vertical-align: -0.2em; }
.svg-inline--fa.fa-xl {
vertical-align: -0.25em; }
.svg-inline--fa.fa-2xl {
vertical-align: -0.3125em; }
.svg-inline--fa.fa-pull-left {
margin-right: var(--fa-pull-margin, 0.3em);
width: auto; }
.svg-inline--fa.fa-pull-right {
margin-left: var(--fa-pull-margin, 0.3em);
width: auto; }
.svg-inline--fa.fa-li {
width: var(--fa-li-width, 2em);
top: 0.25em; }
.svg-inline--fa.fa-fw {
width: var(--fa-fw-width, 1.25em); }
.fa-layers svg.svg-inline--fa {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0; }
.fa-layers-text, .fa-layers-counter {
display: inline-block;
position: absolute;
text-align: center; }
.fa-layers {
display: inline-block;
height: 1em;
position: relative;
text-align: center;
vertical-align: -.125em;
width: 1em; }
.fa-layers svg.svg-inline--fa {
transform-origin: center center; }
.fa-layers-text {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
transform-origin: center center; }
.fa-layers-counter {
background-color: var(--fa-counter-background-color, #ff253a);
border-radius: var(--fa-counter-border-radius, 1em);
box-sizing: border-box;
color: var(--fa-inverse, #fff);
line-height: var(--fa-counter-line-height, 1);
max-width: var(--fa-counter-max-width, 5em);
min-width: var(--fa-counter-min-width, 1.5em);
overflow: hidden;
padding: var(--fa-counter-padding, 0.25em 0.5em);
right: var(--fa-right, 0);
text-overflow: ellipsis;
top: var(--fa-top, 0);
transform: scale(var(--fa-counter-scale, 0.25));
transform-origin: top right; }
.fa-layers-bottom-right {
bottom: var(--fa-bottom, 0);
right: var(--fa-right, 0);
top: auto;
transform: scale(var(--fa-layers-scale, 0.25));
transform-origin: bottom right; }
.fa-layers-bottom-left {
bottom: var(--fa-bottom, 0);
left: var(--fa-left, 0);
right: auto;
top: auto;
transform: scale(var(--fa-layers-scale, 0.25));
transform-origin: bottom left; }
.fa-layers-top-right {
top: var(--fa-top, 0);
right: var(--fa-right, 0);
transform: scale(var(--fa-layers-scale, 0.25));
transform-origin: top right; }
.fa-layers-top-left {
left: var(--fa-left, 0);
right: auto;
top: var(--fa-top, 0);
transform: scale(var(--fa-layers-scale, 0.25));
transform-origin: top left; }
.fa-1x {
font-size: 1em; }
.fa-2x {
font-size: 2em; }
.fa-3x {
font-size: 3em; }
.fa-4x {
font-size: 4em; }
.fa-5x {
font-size: 5em; }
.fa-6x {
font-size: 6em; }
.fa-7x {
font-size: 7em; }
.fa-8x {
font-size: 8em; }
.fa-9x {
font-size: 9em; }
.fa-10x {
font-size: 10em; }
.fa-2xs {
font-size: 0.625em;
line-height: 0.1em;
vertical-align: 0.225em; }
.fa-xs {
font-size: 0.75em;
line-height: 0.08333em;
vertical-align: 0.125em; }
.fa-sm {
font-size: 0.875em;
line-height: 0.07143em;
vertical-align: 0.05357em; }
.fa-lg {
font-size: 1.25em;
line-height: 0.05em;
vertical-align: -0.075em; }
.fa-xl {
font-size: 1.5em;
line-height: 0.04167em;
vertical-align: -0.125em; }
.fa-2xl {
font-size: 2em;
line-height: 0.03125em;
vertical-align: -0.1875em; }
.fa-fw {
text-align: center;
width: 1.25em; }
.fa-ul {
list-style-type: none;
margin-left: var(--fa-li-margin, 2.5em);
padding-left: 0; }
.fa-ul > li {
position: relative; }
.fa-li {
left: calc(-1 * var(--fa-li-width, 2em));
position: absolute;
text-align: center;
width: var(--fa-li-width, 2em);
line-height: inherit; }
.fa-border {
border-color: var(--fa-border-color, #eee);
border-radius: var(--fa-border-radius, 0.1em);
border-style: var(--fa-border-style, solid);
border-width: var(--fa-border-width, 0.08em);
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
.fa-pull-left {
float: left;
margin-right: var(--fa-pull-margin, 0.3em); }
.fa-pull-right {
float: right;
margin-left: var(--fa-pull-margin, 0.3em); }
.fa-beat {
animation-name: fa-beat;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
.fa-bounce {
animation-name: fa-bounce;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
.fa-fade {
animation-name: fa-fade;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
.fa-beat-fade {
animation-name: fa-beat-fade;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
.fa-flip {
animation-name: fa-flip;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
.fa-shake {
animation-name: fa-shake;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, linear); }
.fa-spin {
animation-name: fa-spin;
animation-delay: var(--fa-animation-delay, 0s);
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 2s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, linear); }
.fa-spin-reverse {
--fa-animation-direction: reverse; }
.fa-pulse,
.fa-spin-pulse {
animation-name: fa-spin;
animation-direction: var(--fa-animation-direction, normal);
animation-duration: var(--fa-animation-duration, 1s);
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
animation-timing-function: var(--fa-animation-timing, steps(8)); }
@media (prefers-reduced-motion: reduce) {
.fa-beat,
.fa-bounce,
.fa-fade,
.fa-beat-fade,
.fa-flip,
.fa-pulse,
.fa-shake,
.fa-spin,
.fa-spin-pulse {
animation-delay: -1ms;
animation-duration: 1ms;
animation-iteration-count: 1;
transition-delay: 0s;
transition-duration: 0s; } }
@keyframes fa-beat {
0%, 90% {
transform: scale(1); }
45% {
transform: scale(var(--fa-beat-scale, 1.25)); } }
@keyframes fa-bounce {
0% {
transform: scale(1, 1) translateY(0); }
10% {
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
30% {
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
50% {
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
57% {
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
64% {
transform: scale(1, 1) translateY(0); }
100% {
transform: scale(1, 1) translateY(0); } }
@keyframes fa-fade {
50% {
opacity: var(--fa-fade-opacity, 0.4); } }
@keyframes fa-beat-fade {
0%, 100% {
opacity: var(--fa-beat-fade-opacity, 0.4);
transform: scale(1); }
50% {
opacity: 1;
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
@keyframes fa-flip {
50% {
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
@keyframes fa-shake {
0% {
transform: rotate(-15deg); }
4% {
transform: rotate(15deg); }
8%, 24% {
transform: rotate(-18deg); }
12%, 28% {
transform: rotate(18deg); }
16% {
transform: rotate(-22deg); }
20% {
transform: rotate(22deg); }
32% {
transform: rotate(-12deg); }
36% {
transform: rotate(12deg); }
40%, 100% {
transform: rotate(0deg); } }
@keyframes fa-spin {
0% {
transform: rotate(0deg); }
100% {
transform: rotate(360deg); } }
.fa-rotate-90 {
transform: rotate(90deg); }
.fa-rotate-180 {
transform: rotate(180deg); }
.fa-rotate-270 {
transform: rotate(270deg); }
.fa-flip-horizontal {
transform: scale(-1, 1); }
.fa-flip-vertical {
transform: scale(1, -1); }
.fa-flip-both,
.fa-flip-horizontal.fa-flip-vertical {
transform: scale(-1, -1); }
.fa-rotate-by {
transform: rotate(var(--fa-rotate-angle, 0)); }
.fa-stack {
display: inline-block;
vertical-align: middle;
height: 2em;
position: relative;
width: 2.5em; }
.fa-stack-1x,
.fa-stack-2x {
bottom: 0;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
z-index: var(--fa-stack-z-index, auto); }
.svg-inline--fa.fa-stack-1x {
height: 1em;
width: 1.25em; }
.svg-inline--fa.fa-stack-2x {
height: 2em;
width: 2.5em; }
.fa-inverse {
color: var(--fa-inverse, #fff); }
.sr-only,
.fa-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0; }
.sr-only-focusable:not(:focus),
.fa-sr-only-focusable:not(:focus) {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0; }
.svg-inline--fa .fa-primary {
fill: var(--fa-primary-color, currentColor);
opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa .fa-secondary {
fill: var(--fa-secondary-color, currentColor);
opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-primary {
opacity: var(--fa-secondary-opacity, 0.4); }
.svg-inline--fa.fa-swap-opacity .fa-secondary {
opacity: var(--fa-primary-opacity, 1); }
.svg-inline--fa mask .fa-primary,
.svg-inline--fa mask .fa-secondary {
fill: black; }
.fad.fa-inverse,
.fa-duotone.fa-inverse {
color: var(--fa-inverse, #fff); }

File diff suppressed because one or more lines are too long

26
dist/font-awesome/css/v4-font-face.css vendored Normal file
View file

@ -0,0 +1,26 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
@font-face {
font-family: 'FontAwesome';
font-display: block;
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }

View file

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}

File diff suppressed because one or more lines are too long

22
dist/font-awesome/css/v5-font-face.css vendored Normal file
View file

@ -0,0 +1,22 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face {
font-family: 'Font Awesome 5 Brands';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Free';
font-display: block;
font-weight: 900;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
@font-face {
font-family: 'Font Awesome 5 Free';
font-display: block;
font-weight: 400;
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }

View file

@ -0,0 +1,6 @@
/*!
* Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
* Copyright 2024 Fonticons, Inc.
*/
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}

Some files were not shown because too many files have changed in this diff Show more