mirror of
https://github.com/RaspAP/raspap-webgui.git
synced 2025-04-21 19:23:25 +00:00
Compare commits
843 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c3175459ab | ||
![]() |
3bf682d752 | ||
![]() |
9e0801aa0c | ||
![]() |
a21b0a8f99 | ||
![]() |
5f1b16bc74 | ||
![]() |
deba5e1e74 | ||
![]() |
0960e8bac9 | ||
![]() |
4a4506a913 | ||
![]() |
bfab3d7441 | ||
![]() |
47d7c121de | ||
![]() |
484b89718a | ||
![]() |
d6c8ac32a7 | ||
![]() |
3d6b4e1f15 | ||
![]() |
8d482845b0 | ||
![]() |
a1550d8049 | ||
![]() |
5584e3b72c | ||
![]() |
b0ba029c66 | ||
![]() |
48e492bf10 | ||
![]() |
821ac9c1f8 | ||
![]() |
49cb3911b8 | ||
![]() |
8ad582b3b2 | ||
![]() |
bbf1caf777 | ||
![]() |
b3c6178274 | ||
![]() |
a5907d8f7f | ||
![]() |
8569c2b4d5 | ||
![]() |
2a70f6ee11 | ||
![]() |
c8b0408bd5 | ||
![]() |
125ae7a39a | ||
![]() |
20fe5fc5a7 | ||
![]() |
168ed2448f | ||
![]() |
a2b8dfe551 | ||
![]() |
4aee1e49d9 | ||
![]() |
16d92bb486 | ||
![]() |
de376d04d1 | ||
![]() |
d730c174d4 | ||
![]() |
c798f5fd69 | ||
![]() |
3a73916206 | ||
![]() |
f46be0139e | ||
![]() |
a6295aef6e | ||
![]() |
556c2be855 | ||
![]() |
80e8178384 | ||
![]() |
b1c429f404 | ||
![]() |
f0b992b9be | ||
![]() |
084b2e1268 | ||
![]() |
0fd60e3730 | ||
![]() |
cfc6644087 | ||
![]() |
2cd4abc3c2 | ||
![]() |
8bd5b1b988 | ||
![]() |
2b8f7fd6d8 | ||
![]() |
b99addef4a | ||
![]() |
96ada80ce1 | ||
![]() |
5d33c79369 | ||
![]() |
645ab89437 | ||
![]() |
62b342cdbb | ||
![]() |
c235a4ff16 | ||
![]() |
a24516a4d5 | ||
![]() |
483b1fc27d | ||
![]() |
4d0de82986 | ||
![]() |
85663341eb | ||
![]() |
734043dee6 | ||
![]() |
af2927f05b | ||
![]() |
3e54b1d7bb | ||
![]() |
51a0ce220c | ||
![]() |
05e20e3bab | ||
![]() |
03fc2c42ad | ||
![]() |
401172eb36 | ||
![]() |
71f1132bc8 | ||
![]() |
605486feda | ||
![]() |
23597e800d | ||
![]() |
3218d87b1b | ||
![]() |
0c58a6c92c | ||
![]() |
afa3006de2 | ||
![]() |
03b9bf9e7a | ||
![]() |
028c0d3e06 | ||
![]() |
0005488884 | ||
![]() |
f73f25708c | ||
![]() |
4e411aaa6b | ||
![]() |
6adeab7586 | ||
![]() |
16f6b7f979 | ||
![]() |
068f363f09 | ||
![]() |
d4554c6429 | ||
![]() |
a3caa6485c | ||
![]() |
795d55a2cd | ||
![]() |
c53c1a27a4 | ||
![]() |
903cc6bd8e | ||
![]() |
13929acbd1 | ||
![]() |
f6da130fce | ||
![]() |
1fc793c3fd | ||
![]() |
4b6ac1a415 | ||
![]() |
304010db40 | ||
![]() |
66563c9d95 | ||
![]() |
5eca4c045b | ||
![]() |
fd953e7a71 | ||
![]() |
52b20cb491 | ||
![]() |
c987d2800d | ||
![]() |
6d6bacd6a1 | ||
![]() |
f0a0c9228f | ||
![]() |
dfef9e5233 | ||
![]() |
ab77af9e5d | ||
![]() |
5ce06c6214 | ||
![]() |
d5cc80d1f2 | ||
![]() |
e3f04192b8 | ||
![]() |
cfb8435373 | ||
![]() |
615f2abed1 | ||
![]() |
ac926e84d7 | ||
![]() |
8846b96905 | ||
![]() |
677e99ffd9 | ||
![]() |
a82b30179b | ||
![]() |
ae4e9be739 | ||
![]() |
7091a4016a | ||
![]() |
24b292bf33 | ||
![]() |
c00f006cdd | ||
![]() |
ed47a41c9c | ||
![]() |
39cc92853a | ||
![]() |
34f7563bed | ||
![]() |
964d7b38a8 | ||
![]() |
17fbbca046 | ||
![]() |
64faf296a6 | ||
![]() |
f1c404a443 | ||
![]() |
5ed1312406 | ||
![]() |
00c18451cc | ||
![]() |
b737b5c748 | ||
![]() |
d852990314 | ||
![]() |
182073f41e | ||
![]() |
64d3a11866 | ||
![]() |
4865e85655 | ||
![]() |
3d6095d652 | ||
![]() |
bd0e379d01 | ||
![]() |
93395a8aa5 | ||
![]() |
339437f47f | ||
![]() |
80db7edf18 | ||
![]() |
41e86a9e51 | ||
![]() |
ef04678947 | ||
![]() |
1a964a283f | ||
![]() |
6c47375d18 | ||
![]() |
c2abce1e35 | ||
![]() |
b4b715f6e4 | ||
![]() |
8a7c954d88 | ||
![]() |
639f7605d1 | ||
![]() |
fbcf9809c5 | ||
![]() |
2474765820 | ||
![]() |
ba4507bd22 | ||
![]() |
2610c44ac9 | ||
![]() |
f608282aa5 | ||
![]() |
781f376bea | ||
![]() |
6e1c3b95c2 | ||
![]() |
0331eb7b25 | ||
![]() |
c3a210907a | ||
![]() |
3e0f1f16c1 | ||
![]() |
c2be25271b | ||
![]() |
bb131a7f53 | ||
![]() |
c753865305 | ||
![]() |
0bac7deccc | ||
![]() |
9ada9f9e68 | ||
![]() |
02b9e20ce3 | ||
![]() |
3c8cf996b5 | ||
![]() |
313e2eb06f | ||
![]() |
41fcbba5cc | ||
![]() |
ce9916a792 | ||
![]() |
3f830458b1 | ||
![]() |
a8e24b7629 | ||
![]() |
80f5cb5f46 | ||
![]() |
d45aa752c6 | ||
![]() |
2a1e39a880 | ||
![]() |
8f402ab303 | ||
![]() |
644d2fe6cb | ||
![]() |
b3fe781c19 | ||
![]() |
69510a4e92 | ||
![]() |
163d727ee1 | ||
![]() |
20fdd9024d | ||
![]() |
23e0a6601a | ||
![]() |
47d0305bec | ||
![]() |
f28c5533bc | ||
![]() |
b89fe7c6b8 | ||
![]() |
71ed223cf5 | ||
![]() |
335491124f | ||
![]() |
e45c00b83c | ||
![]() |
aa5fcef2d4 | ||
![]() |
01ddf6f4ea | ||
![]() |
bbac9a8802 | ||
![]() |
4374e78bbb | ||
![]() |
6e0cf0b085 | ||
![]() |
867a46bee9 | ||
![]() |
4a89cb3b07 | ||
![]() |
dc86f15b59 | ||
![]() |
91c535ddbb | ||
![]() |
f576b02858 | ||
![]() |
eb27ba2c66 | ||
![]() |
362a08c00f | ||
![]() |
43ae90bd34 | ||
![]() |
c34cbeca8d | ||
![]() |
33f66fdae5 | ||
![]() |
cc9720e8ef | ||
![]() |
74b1b10e31 | ||
![]() |
41ce72775e | ||
![]() |
9876ab1e3e | ||
![]() |
bd0b226f61 | ||
![]() |
3417115a84 | ||
![]() |
7a880d563f | ||
![]() |
32e191e55d | ||
![]() |
58501a74a7 | ||
![]() |
80c1a04797 | ||
![]() |
af3abe66f4 | ||
![]() |
8a8be213f7 | ||
![]() |
0efbe2b326 | ||
![]() |
624e43f954 | ||
![]() |
55b6c81eca | ||
![]() |
aa49dcf32c | ||
![]() |
10d5c4a8a6 | ||
![]() |
2f205fe9e4 | ||
![]() |
6b7b8ef8d0 | ||
![]() |
a9804b2f9c | ||
![]() |
484d40f455 | ||
![]() |
18114df2bd | ||
![]() |
e61dac332c | ||
![]() |
b9842b5462 | ||
![]() |
739057c7ac | ||
![]() |
d689024c1f | ||
![]() |
c1975a78a1 | ||
![]() |
5fbafeb455 | ||
![]() |
7def2d6da1 | ||
![]() |
538e37ceb7 | ||
![]() |
5d01fa59b1 | ||
![]() |
0b0f4bc06d | ||
![]() |
a619e7a25b | ||
![]() |
a8bd85cc80 | ||
![]() |
e423b7f4d3 | ||
![]() |
47c509277c | ||
![]() |
a6fdb63dd2 | ||
![]() |
75bb3e4a34 | ||
![]() |
36c3e5036f | ||
![]() |
a9021c89f4 | ||
![]() |
77f183817a | ||
![]() |
97bc8174b4 | ||
![]() |
83ed9b5c19 | ||
![]() |
0871601b31 | ||
![]() |
eb25142e03 | ||
![]() |
42b6c8fce3 | ||
![]() |
7a9e5169f6 | ||
![]() |
2ca7448bd3 | ||
![]() |
cd3fde71e3 | ||
![]() |
ec0dd304ee | ||
![]() |
50ed5f9f4b | ||
![]() |
259fac717f | ||
![]() |
0fd65fdbc2 | ||
![]() |
2b92d028f6 | ||
![]() |
9c4f8be363 | ||
![]() |
21b9feb0ef | ||
![]() |
bc7d4ef1c1 | ||
![]() |
bc23dfc130 | ||
![]() |
9042ee8c01 | ||
![]() |
effcb5e48e | ||
![]() |
111c9581a3 | ||
![]() |
6cb0be96b4 | ||
![]() |
6dbdf89760 | ||
![]() |
792ce0c956 | ||
![]() |
3f883a70de | ||
![]() |
187041b030 | ||
![]() |
c51b520b8d | ||
![]() |
866d8eb5b0 | ||
![]() |
3cf22a9cbb | ||
![]() |
6f1c34f28d | ||
![]() |
41a138026b | ||
![]() |
0c31b5ba71 | ||
![]() |
2bab11b951 | ||
![]() |
b52bd84ea4 | ||
![]() |
ff7e674b2e | ||
![]() |
3e91f50966 | ||
![]() |
7dcc177424 | ||
![]() |
94b502a336 | ||
![]() |
bfd5859ce1 | ||
![]() |
13cdfbd8cb | ||
![]() |
531970d9c6 | ||
![]() |
5902a8d6a0 | ||
![]() |
9bb2075b77 | ||
![]() |
3c61954971 | ||
![]() |
361a2f7531 | ||
![]() |
ad36695224 | ||
![]() |
92ba7df9c6 | ||
![]() |
ae7b03857e | ||
![]() |
2c0ace4500 | ||
![]() |
759e5dcf5d | ||
![]() |
bf0d9f88e2 | ||
![]() |
bf74ff7057 | ||
![]() |
4328f54270 | ||
![]() |
efd67fb698 | ||
![]() |
44c99dacdf | ||
![]() |
048d4ab3e6 | ||
![]() |
801ca5a788 | ||
![]() |
e5987a6b59 | ||
![]() |
2cb66660c5 | ||
![]() |
c3968ba42e | ||
![]() |
edb86d7781 | ||
![]() |
6785cc1104 | ||
![]() |
ee38614334 | ||
![]() |
9b087f88a7 | ||
![]() |
247b35b254 | ||
![]() |
89c4f16e45 | ||
![]() |
117370efcf | ||
![]() |
66e35c564c | ||
![]() |
36b0285158 | ||
![]() |
07ec56227d | ||
![]() |
cf78f5dc94 | ||
![]() |
daa6bfd460 | ||
![]() |
6a85ac9b93 | ||
![]() |
cc85c556a1 | ||
![]() |
80be4d34af | ||
![]() |
3898b82287 | ||
![]() |
26c64d42e6 | ||
![]() |
168dd18679 | ||
![]() |
b7a6d334e3 | ||
![]() |
f811d21dc7 | ||
![]() |
26bd632bab | ||
![]() |
5020e8b5a0 | ||
![]() |
b5179f3991 | ||
![]() |
86e8b208e0 | ||
![]() |
a7ac30f548 | ||
![]() |
7684a4932d | ||
![]() |
4d1b746932 | ||
![]() |
dc922bab30 | ||
![]() |
66f5cd4183 | ||
![]() |
50d0e0be82 | ||
![]() |
83d9248249 | ||
![]() |
72475b16ef | ||
![]() |
12b0d9f6c8 | ||
![]() |
68d47f9a41 | ||
![]() |
4bba3384e4 | ||
![]() |
0e39896f3d | ||
![]() |
90bac7f10f | ||
![]() |
0e6f0f6df7 | ||
![]() |
7037214f23 | ||
![]() |
6294a620c0 | ||
![]() |
1ce4c207a6 | ||
![]() |
88806ec01a | ||
![]() |
a4b26da5ec | ||
![]() |
b74db9464e | ||
![]() |
6fa4f3d5a6 | ||
![]() |
6e5ef8a866 | ||
![]() |
4e71a6e753 | ||
![]() |
b33ac6ffa3 | ||
![]() |
ce72d2a0ab | ||
![]() |
39a8a58f38 | ||
![]() |
0bcc396b78 | ||
![]() |
04a6d007fd | ||
![]() |
7d4e6c1eaa | ||
![]() |
05126fbbf8 | ||
![]() |
3c59ce9d7e | ||
![]() |
63924c26ac | ||
![]() |
3a19ed9c3d | ||
![]() |
3af68ca9a9 | ||
![]() |
2ec0738455 | ||
![]() |
316543cfa7 | ||
![]() |
6b3455345d | ||
![]() |
8021099f49 | ||
![]() |
262ff6a00e | ||
![]() |
a86c637f04 | ||
![]() |
4d208d0bf9 | ||
![]() |
fbf3129ef4 | ||
![]() |
80d2e6b801 | ||
![]() |
8ae468376f | ||
![]() |
90794c8828 | ||
![]() |
28d1395bef | ||
![]() |
8048fcf5c4 | ||
![]() |
710a8dab4e | ||
![]() |
274b42d225 | ||
![]() |
69d58f4713 | ||
![]() |
d90ccf4277 | ||
![]() |
a1b0ade0a5 | ||
![]() |
f1a5b9163b | ||
![]() |
cb4fc2ac54 | ||
![]() |
0a32215b39 | ||
![]() |
f7e8f4d6eb | ||
![]() |
40a526f217 | ||
![]() |
cf529fa0fb | ||
![]() |
54cf3132ad | ||
![]() |
2f4680bc23 | ||
![]() |
a12c3ce384 | ||
![]() |
f1e093404c | ||
![]() |
9e52cda593 | ||
![]() |
54a90353f8 | ||
![]() |
13b894d411 | ||
![]() |
95b44aed5e | ||
![]() |
7e1fd32edc | ||
![]() |
3004ce49cc | ||
![]() |
eb3873ac3f | ||
![]() |
23dbbd8ea8 | ||
![]() |
80fbb9aaed | ||
![]() |
6c20740ffd | ||
![]() |
4876d3f04a | ||
![]() |
61ca5d31be | ||
![]() |
26d2f244f9 | ||
![]() |
b9c7108fd7 | ||
![]() |
2d4960a3ab | ||
![]() |
80aca6a971 | ||
![]() |
bc1c7803e0 | ||
![]() |
6ee1b84489 | ||
![]() |
ce46f87459 | ||
![]() |
8087ae3ab1 | ||
![]() |
c928629fc6 | ||
![]() |
f9c91c2125 | ||
![]() |
c74c4deb63 | ||
![]() |
6cd18ad571 | ||
![]() |
9a1d362d30 | ||
![]() |
87f95ab9f9 | ||
![]() |
29ca176e49 | ||
![]() |
4e76445dab | ||
![]() |
063a2b1eaf | ||
![]() |
ec11a527d7 | ||
![]() |
177f42e12b | ||
![]() |
e00b2fcfde | ||
![]() |
7ddf16da6a | ||
![]() |
3dbc83e635 | ||
![]() |
4860b237a1 | ||
![]() |
3f8dea4053 | ||
![]() |
363bcba144 | ||
![]() |
4f14502bac | ||
![]() |
4799825738 | ||
![]() |
bf22668284 | ||
![]() |
0bb8a5400e | ||
![]() |
ba0bff9b9c | ||
![]() |
5f8f91e7e4 | ||
![]() |
246fd32058 | ||
![]() |
5fa8107fe7 | ||
![]() |
20ce71070c | ||
![]() |
7ad71a916d | ||
![]() |
5b88728ec1 | ||
![]() |
677fe42d84 | ||
![]() |
56e5f6f778 | ||
![]() |
74c7fb8c7a | ||
![]() |
3889e2f04d | ||
![]() |
fa42e0c3f1 | ||
![]() |
57199def06 | ||
![]() |
85c38f2a9a | ||
![]() |
8f033e5920 | ||
![]() |
0e31670d25 | ||
![]() |
d9f1a4dcfe | ||
![]() |
9543587786 | ||
![]() |
a5e2d832ef | ||
![]() |
484820f324 | ||
![]() |
90d63a679d | ||
![]() |
3a5766dcc0 | ||
![]() |
4afd67f0b0 | ||
![]() |
0f78411efe | ||
![]() |
98c2a7cb34 | ||
![]() |
534b4df01a | ||
![]() |
a0d8f22742 | ||
![]() |
ed008730e6 | ||
![]() |
828a463888 | ||
![]() |
6541e9b2e1 | ||
![]() |
4175303cf8 | ||
![]() |
e386cc8dfe | ||
![]() |
543a5e098a | ||
![]() |
884d4d95c5 | ||
![]() |
e8a8ca6b65 | ||
![]() |
f76cb71086 | ||
![]() |
2d1d6fb566 | ||
![]() |
41bca8e581 | ||
![]() |
9fc38ffd0c | ||
![]() |
87143e174a | ||
![]() |
655b126a59 | ||
![]() |
5930a123d2 | ||
![]() |
69387f196c | ||
![]() |
5cbe66d99b | ||
![]() |
48e7b7abb7 | ||
![]() |
5717d2f4a8 | ||
![]() |
fc77f79441 | ||
![]() |
f4017ef29a | ||
![]() |
ee915f95a2 | ||
![]() |
02ac421010 | ||
![]() |
5b27f528c9 | ||
![]() |
d1fb8f69d6 | ||
![]() |
820621d301 | ||
![]() |
d0592b63de | ||
![]() |
c98d2b0c15 | ||
![]() |
e92835f89d | ||
![]() |
603038efb1 | ||
![]() |
2de012cc85 | ||
![]() |
d1be0caf54 | ||
![]() |
8d6b8174d1 | ||
![]() |
c408a6f5f8 | ||
![]() |
220709b698 | ||
![]() |
3262e3030f | ||
![]() |
f81c68de26 | ||
![]() |
1e840abbaf | ||
![]() |
95f74c560e | ||
![]() |
d5009e0c1e | ||
![]() |
9c5c0cfb88 | ||
![]() |
f61e1b5c1a | ||
![]() |
19fe43466e | ||
![]() |
49780d8ec9 | ||
![]() |
79d33db2bf | ||
![]() |
2cdf6ef53e | ||
![]() |
ef7b67a445 | ||
![]() |
87216bdc02 | ||
![]() |
5d8fed824a | ||
![]() |
282b839f45 | ||
![]() |
95ad90063b | ||
![]() |
b567f565d9 | ||
![]() |
00f90f1f73 | ||
![]() |
b80151be28 | ||
![]() |
75be1bf04e | ||
![]() |
2365c4e251 | ||
![]() |
edc3a421ca | ||
![]() |
95acd497df | ||
![]() |
5b7b968676 | ||
![]() |
2b2cb8fa40 | ||
![]() |
0b9cbee210 | ||
![]() |
cfa916632b | ||
![]() |
b835243e57 | ||
![]() |
5150224e66 | ||
![]() |
4bf514c992 | ||
![]() |
def8be88fb | ||
![]() |
eabd356bcb | ||
![]() |
c8ed440c68 | ||
![]() |
a55b7d0605 | ||
![]() |
1e6b604e7f | ||
![]() |
e2530bbbbf | ||
![]() |
55508262de | ||
![]() |
cffcac0c52 | ||
![]() |
ae44f5476d | ||
![]() |
8ecd542eae | ||
![]() |
7dc2fd6538 | ||
![]() |
9d7058527d | ||
![]() |
2d41f74b6a | ||
![]() |
4e258b3981 | ||
![]() |
bf41d88340 | ||
![]() |
2e4d76a419 | ||
![]() |
1f1fa3711a | ||
![]() |
35bb48d050 | ||
![]() |
c50d01d972 | ||
![]() |
4c6b01729e | ||
![]() |
910616ef43 | ||
![]() |
aec0279135 | ||
![]() |
8eae2d1606 | ||
![]() |
ccd0d62a5a | ||
![]() |
8c82c41330 | ||
![]() |
08db1e5b66 | ||
![]() |
c43d2ea7ab | ||
![]() |
8357fcb5e4 | ||
![]() |
2ac9ba580f | ||
![]() |
04a443a514 | ||
![]() |
2ce8351b1a | ||
![]() |
3e4857dc67 | ||
![]() |
ce63e48445 | ||
![]() |
631b6b36af | ||
![]() |
67caedc992 | ||
![]() |
becaa209f2 | ||
![]() |
06a3b9386f | ||
![]() |
d296c67373 | ||
![]() |
20bc1830b4 | ||
![]() |
2f2330497d | ||
![]() |
cd7820ddd2 | ||
![]() |
56b9ff5a3b | ||
![]() |
804034a871 | ||
![]() |
3f11ac165b | ||
![]() |
0610848a25 | ||
![]() |
a1b610b92d | ||
![]() |
4dd409211d | ||
![]() |
38a84fc258 | ||
![]() |
ccbdf8dccf | ||
![]() |
3ee4ea90f5 | ||
![]() |
224f4ca784 | ||
![]() |
54aca14d2c | ||
![]() |
e6d4f761bd | ||
![]() |
ef1dc5dae0 | ||
![]() |
bdda08b53e | ||
![]() |
45159c7407 | ||
![]() |
89187b7e44 | ||
![]() |
97adaf88bf | ||
![]() |
68a5085e87 | ||
![]() |
c304f10f81 | ||
![]() |
d56870e2db | ||
![]() |
bb23dc79f6 | ||
![]() |
e5c7ca4053 | ||
![]() |
f778cd78a7 | ||
![]() |
effa38c0a0 | ||
![]() |
c594b8f4a9 | ||
![]() |
320379e449 | ||
![]() |
b2c78ff12c | ||
![]() |
ebfb1384a4 | ||
![]() |
ca9c0471b6 | ||
![]() |
fd38a22c4f | ||
![]() |
e24b4cbdfa | ||
![]() |
ccbfa1a853 | ||
![]() |
939092d673 | ||
![]() |
ee29a4fa0a | ||
![]() |
405ae0bf17 | ||
![]() |
41bba09f42 | ||
![]() |
adf44d462b | ||
![]() |
36a6572971 | ||
![]() |
cb456246ca | ||
![]() |
e93b793686 | ||
![]() |
27bc1d65af | ||
![]() |
627e99b0e9 | ||
![]() |
61ba236424 | ||
![]() |
14f3a4dc09 | ||
![]() |
581622ef0c | ||
![]() |
3cb578ab30 | ||
![]() |
79dbb6d2ea | ||
![]() |
8d99be5092 | ||
![]() |
f05cd43b5c | ||
![]() |
eed05c7d6b | ||
![]() |
243a5e49fa | ||
![]() |
fc58d5037a | ||
![]() |
ce62edc698 | ||
![]() |
5ca9465e83 | ||
![]() |
9fe7bad7b1 | ||
![]() |
959f85e63d | ||
![]() |
692c7d1506 | ||
![]() |
7e39bc0d35 | ||
![]() |
0a547442a4 | ||
![]() |
e0751d6f90 | ||
![]() |
781a292b67 | ||
![]() |
69b629a59b | ||
![]() |
e71042cb63 | ||
![]() |
1bf7a32bd5 | ||
![]() |
c5ffab8332 | ||
![]() |
79c61d383b | ||
![]() |
b5d861a2b9 | ||
![]() |
84dc44d944 | ||
![]() |
478c3fea5c | ||
![]() |
3717249f6a | ||
![]() |
20589bacf3 | ||
![]() |
0cb3128158 | ||
![]() |
89cb4621fa | ||
![]() |
93f6069dc3 | ||
![]() |
ff7f1f01b4 | ||
![]() |
194ca3a295 | ||
![]() |
1a16f3c8a3 | ||
![]() |
ba03688230 | ||
![]() |
cf63cfe63b | ||
![]() |
034a0b8f63 | ||
![]() |
54ec50c27f | ||
![]() |
7818462f56 | ||
![]() |
74656c63ed | ||
![]() |
05210e8967 | ||
![]() |
2a5241fb62 | ||
![]() |
cf53c575ff | ||
![]() |
8cbfaed989 | ||
![]() |
7858bb5739 | ||
![]() |
4705cc5ec1 | ||
![]() |
21ee31b8ce | ||
![]() |
fd3034e976 | ||
![]() |
f4b9eeb313 | ||
![]() |
0246761609 | ||
![]() |
7ac8d8b9f3 | ||
![]() |
61a1f063ea | ||
![]() |
9a709b3ded | ||
![]() |
2102fb9043 | ||
![]() |
c0bf18bf50 | ||
![]() |
484a1e8702 | ||
![]() |
d6a4d33758 | ||
![]() |
aa3a88e9b1 | ||
![]() |
99fd2f8ce7 | ||
![]() |
ffafcf2c83 | ||
![]() |
ea5ee29d4a | ||
![]() |
387d779bdf | ||
![]() |
fec2c283c1 | ||
![]() |
1e4fe3b002 | ||
![]() |
61c05d93d8 | ||
![]() |
f6d7e9a2d1 | ||
![]() |
37dcaa41f1 | ||
![]() |
44c8b7c1ae | ||
![]() |
d14040d3a7 | ||
![]() |
e2111fdf1f | ||
![]() |
5fbcabd3c2 | ||
![]() |
90456e601e | ||
![]() |
7b3662fb2b | ||
![]() |
e55f4e2395 | ||
![]() |
61cf109f11 | ||
![]() |
ba67d327af | ||
![]() |
51e05dd270 | ||
![]() |
ba45daad19 | ||
![]() |
2151a44729 | ||
![]() |
026a385add | ||
![]() |
366e0447ab | ||
![]() |
dea5759514 | ||
![]() |
7e8f63863d | ||
![]() |
7782956917 | ||
![]() |
e6a90e728f | ||
![]() |
387f52a2e4 | ||
![]() |
4c6455f1d9 | ||
![]() |
bfe62fb2c9 | ||
![]() |
4c6ec03ea9 | ||
![]() |
167face986 | ||
![]() |
bc6ec3a9bf | ||
![]() |
f0f8c4275f | ||
![]() |
b828c2641c | ||
![]() |
b1c9bdb6c7 | ||
![]() |
20fbda85e3 | ||
![]() |
58077162a9 | ||
![]() |
7aee28dacb | ||
![]() |
7e85af6597 | ||
![]() |
211d09e67b | ||
![]() |
0b114ecab7 | ||
![]() |
86a8e0e41d | ||
![]() |
d874668ce1 | ||
![]() |
774d7e90ef | ||
![]() |
e90f87ac63 | ||
![]() |
fc12951e88 | ||
![]() |
7f7b688ab9 | ||
![]() |
ac339d16ef | ||
![]() |
36e8eecbea | ||
![]() |
7479bcba0e | ||
![]() |
a95b43e23e | ||
![]() |
9ba2719969 | ||
![]() |
a3230d0684 | ||
![]() |
1d5ee03324 | ||
![]() |
ef084ef537 | ||
![]() |
458bde86b2 | ||
![]() |
4f954f4d8f | ||
![]() |
0684c46b23 | ||
![]() |
e86e52f471 | ||
![]() |
273f2ce22e | ||
![]() |
b2117ac492 | ||
![]() |
645c336c97 | ||
![]() |
4f6a28a81f | ||
![]() |
f6113c47ce | ||
![]() |
6f454294df | ||
![]() |
de38aa0f9e | ||
![]() |
f9b1eab556 | ||
![]() |
a6959d4eca | ||
![]() |
068f81c8ee | ||
![]() |
fbec4501ed | ||
![]() |
f131c8463d | ||
![]() |
6383f9b88b | ||
![]() |
b24c0ff862 | ||
![]() |
03c819fee2 | ||
![]() |
080e5140cf | ||
![]() |
6731f3a784 | ||
![]() |
be1feb22e8 | ||
![]() |
b31b1a7773 | ||
![]() |
5a6d76defd | ||
![]() |
78d587c5a1 | ||
![]() |
9343b11cc9 | ||
![]() |
1ee31d9221 | ||
![]() |
59ad100b47 | ||
![]() |
f20e4a879a | ||
![]() |
cbc8e2fdec | ||
![]() |
c39f19db15 | ||
![]() |
639592a706 | ||
![]() |
40dc86cc21 | ||
![]() |
0751fc7ba4 | ||
![]() |
2abe94b796 | ||
![]() |
fee5a69342 | ||
![]() |
df7fd21cc5 | ||
![]() |
14f9482859 | ||
![]() |
5e802e8a0b | ||
![]() |
e16c69c446 | ||
![]() |
25cc92b593 | ||
![]() |
7a612592c2 | ||
![]() |
648465f6c6 | ||
![]() |
1b155dbf58 | ||
![]() |
55a8eb85eb | ||
![]() |
66f8cc0b75 | ||
![]() |
be25ffd06f | ||
![]() |
51673aef32 | ||
![]() |
48d29d368a | ||
![]() |
99b3767fd6 | ||
![]() |
77eb23b0e8 | ||
![]() |
c2d04a98a7 | ||
![]() |
0fbccabaf5 | ||
![]() |
5685a4f107 | ||
![]() |
e046a11f56 | ||
![]() |
21b588282f | ||
![]() |
3eb8e5ae3f | ||
![]() |
c3d97182cb | ||
![]() |
5e5eb7d04f | ||
![]() |
22cd0ae017 | ||
![]() |
9663832f0d | ||
![]() |
54e154c01a | ||
![]() |
5e46cd407c | ||
![]() |
86ac3e2ff6 | ||
![]() |
98d5f5b64b | ||
![]() |
97a9cac5e8 | ||
![]() |
e99e98d8ca | ||
![]() |
00792501fd | ||
![]() |
15632a60df | ||
![]() |
d619269df4 | ||
![]() |
362feae185 | ||
![]() |
11e17a8895 | ||
![]() |
0176f71944 | ||
![]() |
2b543c605f | ||
![]() |
94174a3920 | ||
![]() |
ce001aeffa | ||
![]() |
4f3e00fe56 | ||
![]() |
516de1f080 | ||
![]() |
5ec7d4908e | ||
![]() |
f481b51c9d | ||
![]() |
6ba718985d | ||
![]() |
574113bf28 | ||
![]() |
0136c32403 | ||
![]() |
bc03b329ca | ||
![]() |
601f587cb0 | ||
![]() |
63f2c38f4c | ||
![]() |
20e3633541 | ||
![]() |
3008f51450 | ||
![]() |
c4947eacba | ||
![]() |
f254c01549 | ||
![]() |
b93a12fcf4 | ||
![]() |
a8f541c659 | ||
![]() |
65578d33eb | ||
![]() |
45dc1142cb | ||
![]() |
43d4bb2a2f | ||
![]() |
ada6cbf4d3 | ||
![]() |
1b3e1c3372 | ||
![]() |
a26a3b665e | ||
![]() |
dc65af9045 | ||
![]() |
6cad8606c6 | ||
![]() |
fc75567b0d | ||
![]() |
d75908ce40 | ||
![]() |
23d48b902f | ||
![]() |
32a6110d3d | ||
![]() |
3fe3a8db1d | ||
![]() |
e85e403169 | ||
![]() |
c3935103bb | ||
![]() |
9dcdd2ca7a | ||
![]() |
ee662ada09 | ||
![]() |
3e404b0202 | ||
![]() |
42ff260d63 | ||
![]() |
4973d794a6 | ||
![]() |
4cc88a881f | ||
![]() |
a527221247 | ||
![]() |
1e6d94585a | ||
![]() |
8124f63fa3 | ||
![]() |
e51c6b0968 | ||
![]() |
9a1457c6c8 | ||
![]() |
99f8838fe2 | ||
![]() |
47f983a361 | ||
![]() |
53f4645c2f | ||
![]() |
ac863f5c8a | ||
![]() |
f535acc18c | ||
![]() |
ab0568875d | ||
![]() |
a09ee1e86b | ||
![]() |
f7bdcb4e63 | ||
![]() |
72cac43c0f | ||
![]() |
a2394c0742 | ||
![]() |
5123ab4599 | ||
![]() |
ac7b4ccb28 | ||
![]() |
d3c9b00e89 | ||
![]() |
7a1d6492b2 | ||
![]() |
ca157b1789 | ||
![]() |
bbc5013617 |
1858 changed files with 61481 additions and 58905 deletions
59
.github/ISSUE_TEMPLATE/bug_report.md
vendored
59
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,59 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve RaspAP
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- These comments will NOT appear in your issue, so it's OK to ignore them -->
|
||||
<!--
|
||||
Thanks for reporting a bug for RaspAP.
|
||||
|
||||
Important: If you are NOT using a clean installation of a compatible OS, start with a fresh SD card, install RaspAP and replicate your bug BEFORE reporting an issue.
|
||||
|
||||
All submitters MUST read the issue policy and reporting guidelines:
|
||||
https://docs.raspap.com/issues/
|
||||
|
||||
Refer to the frequently asked questions (FAQ) and official documentation:
|
||||
https://docs.raspap.com/faq/
|
||||
|
||||
Do you have a question or want to suggest a new feature? Start a Discussion here:
|
||||
https://github.com/RaspAP/raspap-webgui/discussions
|
||||
|
||||
Be sure there are no issues similar to yours that are already open. You can check this by searching the issues in this repository. If there is a duplicate issue, please close this one and add a comment to the existing issue instead.
|
||||
-->
|
||||
<!-- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## Checklist
|
||||
<!-- IMPORTANT! Fill in the boxes that apply by marking them like so: [x] -->
|
||||
- [ ] This is a bug report
|
||||
- [ ] I observed this bug on a clean install of the OS
|
||||
- [ ] I have followed the project prerequisites
|
||||
- [ ] I have searched this repository for existing issues
|
||||
- [ ] I checked the FAQ and official documentation before creating this issue
|
||||
- [ ] I have read and understand the issue reporting guidelines
|
||||
|
||||
## Bug description
|
||||
<!-- Provide a detailed description of the issue -->
|
||||
|
||||
## Your environment
|
||||
1. Operating System: **ENTER HERE** <!-- RPi OS 32-bit Lite, Armbian, Debian, etc. -->
|
||||
2. Hardware and version: <!-- RPi Zero/3B+/4, OrangePi 3, etc. -->
|
||||
3. RaspAP version: <!-- reported by the Quick Installer or About page -->
|
||||
4. Clean install of a compatible operating system? <!-- Yes/No -->
|
||||
5. RaspAP Quick Install or Manual setup? <!-- Quick Install/Manual -->
|
||||
6. Using default configuration? <!-- Yes/No -->
|
||||
7. Simultaneous AP and managed mode? <!-- Yes/No -->
|
||||
8. Onboard wireless chipset or external adapter? <!-- Onboard/External -->
|
||||
9. Other software or services running with RaspAP?
|
||||
|
||||
## Steps to reproduce
|
||||
<!-- Tell us how to reproduce this issue. Provide as much detailed information as possible -->
|
||||
|
||||
## Screenshots
|
||||
<!-- If applicable, add screenshots to help explain your problem -->
|
||||
|
||||
## Additional context
|
||||
<!-- Add any other context about the problem here -->
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1 +1,5 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: RaspAP Community Support
|
||||
url: https://github.com/RaspAP/raspap-webgui/discussions
|
||||
about: Please ask and answer questions here.
|
||||
|
|
169
.github/ISSUE_TEMPLATE/issue_form.yml
vendored
Normal file
169
.github/ISSUE_TEMPLATE/issue_form.yml
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
name: Bug Report
|
||||
description: Create a report to help us improve RaspAP
|
||||
title: "[Bug]: "
|
||||
labels: ["bug-report", "triage"]
|
||||
projects: ["RaspAP-webgui"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for reporting a bug for RaspAP.
|
||||
|
||||
**Important:** If you are NOT using a clean installation of a compatible OS, start with a fresh SD card, install RaspAP and replicate your bug BEFORE reporting an issue.
|
||||
|
||||
All submitters MUST read the [issue policy and reporting guidelines](https://docs.raspap.com/issues/). Bug reports that do not follow the issue policy will be marked as `invalid` and closed. Likewise, bug reports missing required fields will be marked `incomplete` and closed (no hard feelings).
|
||||
In this event, we ask you to re-submit a complete bug report.
|
||||
|
||||
Be sure there are no issues similar to yours that are already open. You can check this by searching the issues in this repository.
|
||||
If there is a duplicate issue, please comment on the existing issue instead.
|
||||
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Code of Conduct
|
||||
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/RaspAP/raspap-webgui/blob/master/CODE_OF_CONDUCT.md).
|
||||
options:
|
||||
- label: I agree to follow this project's Code of Conduct.
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: policies
|
||||
attributes:
|
||||
label: Issue reporting checklist
|
||||
options:
|
||||
- label: I have read and understand the [issue reporting policy](https://docs.raspap.com/issues/).
|
||||
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/#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 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
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
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
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: install
|
||||
attributes:
|
||||
label: Installation method
|
||||
options:
|
||||
- Pre-built image
|
||||
- Quick install
|
||||
- Manual setup
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: adapter
|
||||
attributes:
|
||||
label: Onboard wireless chipset or external adapter?
|
||||
options:
|
||||
- Onboard wireless chipset
|
||||
- External adapter
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: hardware
|
||||
attributes:
|
||||
label: Hardware
|
||||
options:
|
||||
- Raspberry Pi 5
|
||||
- Raspberry Pi 4 Model B
|
||||
- Raspberry Pi 3 Model B+
|
||||
- Raspberry Pi 3 Model A+
|
||||
- Raspberry Pi 3 Model B
|
||||
- Raspberry Pi Zero 2 W
|
||||
- Raspberry Pi Zero W
|
||||
- Raspberry Pi Compute Module
|
||||
- Orange Pi family
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: RaspAP version
|
||||
options:
|
||||
- Latest
|
||||
- Other (specify below)
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: software
|
||||
attributes:
|
||||
label: Other software or services running with RaspAP?
|
||||
options:
|
||||
- Yes (specify below)
|
||||
- No other software
|
||||
- Not sure
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: contact
|
||||
attributes:
|
||||
label: Contact details (optional)
|
||||
description: How can we get in touch with you if we need more info?
|
||||
placeholder: ex. email@example.com
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: bug-description
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: Also tell us, what did you expect to happen?
|
||||
placeholder: Provide a detailed description of the issue.
|
||||
value:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps-to-reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Tell us how to reproduce this issue.
|
||||
placeholder: Provide as much detailed information as possible.
|
||||
value:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
placeholder: Upload your screenshot(s) here.
|
||||
value:
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description:
|
||||
placeholder: Add any other context about the problem here.
|
||||
value:
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
validations:
|
||||
required: false
|
||||
|
18
.github/stale.yml
vendored
18
.github/stale.yml
vendored
|
@ -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
|
23
.github/workflows/codesee-arch-diagram.yml
vendored
Normal file
23
.github/workflows/codesee-arch-diagram.yml
vendored
Normal 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
|
16
.github/workflows/main.yml
vendored
16
.github/workflows/main.yml
vendored
|
@ -1,16 +0,0 @@
|
|||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
|
||||
jobs:
|
||||
auto_close_issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Automatically close issues that don't follow the issue template
|
||||
uses: lucasbento/auto-close-issues@v1.0.2
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-close-message: "@${issue.user.login}: hello! :wave:\n\nThis issue is being automatically closed because it does not follow the issue template.\nPlease review this project's issue policy https://docs.raspap.com/issues" # optional property
|
||||
closed-issues-label: "invalid" # optional property
|
80
.github/workflows/release.yml
vendored
Normal file
80
.github/workflows/release.yml
vendored
Normal 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
23
.github/workflows/stale.yml
vendored
Normal 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
2
.gitignore
vendored
|
@ -5,3 +5,5 @@ yarn-error.log
|
|||
includes/config.php
|
||||
rootCA.pem
|
||||
vendor
|
||||
.env
|
||||
locale/**/*.mo
|
||||
|
|
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
[submodule "plugins"]
|
||||
path = plugins
|
||||
url = https://github.com/RaspAP/plugins
|
||||
branch = master
|
20
BACKERS.md
20
BACKERS.md
|
@ -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
|
||||
|
|
64
CODE_OF_CONDUCT.md
Normal file
64
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
# RaspAP Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
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.
|
||||
|
||||
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 (treat others as you wish to be treated)
|
||||
* Giving and accepting constructive feedback
|
||||
* 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 are provided below. Quotes in parantheses
|
||||
are portions of actual comments or issues that have been posted to this project:
|
||||
|
||||
* 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
|
||||
|
||||
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
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
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.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
|
@ -1,13 +1,22 @@
|
|||
## How to contribute
|
||||
Everyone is invited and welcome to contribute to RaspAP. There's a lot to do — if you're not a developer we can always use help with the official [project documentation](https://docs.raspap.com) and language [translations](https://crowdin.com/project/raspap). If you have experience in Linux networking, you can share your knowledge by answering questions from RaspAP users in our [GitHub discussions](https://github.com/RaspAP/raspap-webgui/discussions) and/or the [/r/RaspAP](https://reddit.com/r/RaspAP) subreddit.
|
||||
|
||||
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. This will help us get you started on the right foot.
|
||||
3. Commit changes in your feature branch.
|
||||
4. Open a pull request and reference the initial issue in the pull request message.
|
||||
If you're a devloper, the process of contributing code is straightforward:
|
||||
|
||||
1. Fork the project in your account and create a new branch: `feat/your-feature` or `fix/your-bugfix`.
|
||||
2. Open [an issue](https://github.com/RaspAP/raspap-webgui/issues) describing the feature or bug fix contribution you'd like to make.
|
||||
3. Commit changes in your branch.
|
||||
4. Open a pull request and reference the initial issue in the pull request message, or by linking it in GitHub.
|
||||
|
||||
### Coding standards
|
||||
This project follows the [PSR-2](http://www.php-fig.org/psr/psr-2/) coding style guidelines. There are many ways to check your code for PSR-2. An excellent tool is [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer). The command line tool phpcs can be run against any single file. [Phing](https://www.phing.info/), a PHP build tool, integrates nicely with `phpcs` to automate PSR-2 checks across all source files in a project.
|
||||
|
||||
### Development process
|
||||
Development processes used by contributors to the project are described [on this page](https://docs.raspap.com/developers/). It does not endorse one over the other; rather it is meant to share two different approaches.
|
||||
### RaspAP community
|
||||
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)
|
||||
* [Discord chat](https://discord.gg/KVAsaAR)
|
||||
* [Twitter](https://twitter.com/rasp_ap)
|
||||
* [Reddit](https://www.reddit.com/r/RaspAP/)
|
||||
|
||||
If you enjoy using RaspAP and would like to support our work financially, consider becoming an [Insider](https://github.com/sponsors/RaspAP).
|
||||
|
|
117
README.md
117
README.md
|
@ -1,60 +1,77 @@
|
|||

|
||||
[](https://github.com/raspap/raspap-webgui/releases) [](https://github.com/thibmaek/awesome-raspberry-pi) [](https://github.com/sponsors/RaspAP) [](https://app.travis-ci.com/RaspAP/raspap-webgui) [](https://crowdin.com/project/raspap) [](https://twitter.com/rasp_ap) [](https://www.reddit.com/r/RaspAP/) [](https://app.gitter.im/#/room/#RaspAP:gitter.im)
|
||||

|
||||
[](https://github.com/raspap/raspap-webgui/releases) [](https://github.com/thibmaek/awesome-raspberry-pi) [](https://github.com/sponsors/RaspAP) [](https://app.travis-ci.com/RaspAP/raspap-webgui) [](https://crowdin.com/project/raspap) [](https://twitter.com/rasp_ap) [](https://reddit.com/r/RaspAP) [](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).
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
<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
|
||||
|
@ -62,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.
|
||||
|
||||
|
@ -93,6 +110,11 @@ To configure an OpenVPN client, upload a valid .ovpn file and, optionally, speci
|
|||
|
||||
See our [OpenVPN documentation](https://docs.raspap.com/openvpn/) for more information.
|
||||
|
||||
## VPN provider support
|
||||
|
||||
Several popular VPN providers include a Linux Command Line Interface (CLI) for interacting with their services. As a new beta feature, you may optionally control these VPN services from within RaspAP. After your provider's CLI is installed on your system you may administer it thereafter by using RaspAP's UI.
|
||||
|
||||
See our [VPN provider documentation](https://docs.raspap.com/providers/) for more information.
|
||||
|
||||
## Ad Blocking
|
||||
This feature uses DNS blacklisting to block requests for ads, trackers and other undesirable hosts. To enable ad blocking, simply respond to the prompt during the installation. As a beta release, we encourage testing and feedback from users of RaspAP.
|
||||
|
@ -106,36 +128,28 @@ 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/).
|
||||
|
||||
## 802.11ac 5GHz support
|
||||
RaspAP provides an 802.11ac wireless mode option for supported hardware (currently the RPi 3B+/4 and compatible Orange Pi models) and wireless regulatory domains. See [this FAQ](https://docs.raspap.com/faq/#80211ac) for more information.
|
||||
RaspAP provides an 802.11ac wireless mode option for supported hardware (currently the RPi 3B+/4 and compatible Orange Pi models) and wireless regulatory domains. See [this](https://docs.raspap.com/ap-basics/#80211ac-5-ghz) for more information.
|
||||
|
||||
## Supported operating systems
|
||||
RaspAP was originally made for Raspbian, but now also installs on the following Debian-based distros.
|
||||
|
||||
| Distribution | Release | Architecture | Support |
|
||||
|---|:---:|:---:|:---:|
|
||||
| Raspberry Pi OS | (32-bit) Lite Bullseye | ARM | Official |
|
||||
| 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 |
|
||||
| Armbian | Bullseye | [ARM](https://docs.armbian.com/#supported-socs) | Official |
|
||||
| Debian | Bullseye | ARM / x86_64 | Beta |
|
||||
| Ubuntu | 18.04 LTS / 19.10 | ARM / x86_64 | Beta |
|
||||
| Raspberry Pi OS | (32-bit) Lite Bullseye | ARM | Official |
|
||||
| Armbian | 23.11 (Jammy) | [ARM](https://docs.armbian.com/#supported-socs) | Beta |
|
||||
| Debian | Bookworm | ARM / x86_64 | Beta |
|
||||
|
||||

|
||||
<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.
|
||||
|
@ -148,7 +162,22 @@ curl -sL https://install.raspap.com | bash -s -- --cert
|
|||
|
||||
**Note**: this only installs mkcert and generates an SSL certificate with the input you provide. It does *not* (re)install RaspAP.
|
||||
|
||||
More information on SSL certificates and HTTPS support is available [in our documentation](https://docs.raspap.com/ssl-quick/).
|
||||
More information on SSL certificates and HTTPS support is available [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`.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ' ]';
|
||||
|
||||
|
||||
|
|
|
@ -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') {
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -1,43 +1,15 @@
|
|||
<?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/locale.php';
|
||||
require_once '../../includes/authenticate.php';
|
||||
|
||||
if (isset($_POST['interface'])) {
|
||||
|
||||
define( 'NL80211_BAND_24GHZ', 0x1 );
|
||||
define( 'NL80211_BAND_5GHZ', 0x2 );
|
||||
$iface = escapeshellcmd($_POST['interface']);
|
||||
$flags = 0;
|
||||
$parser = new \RaspAP\Parsers\IwParser($iface);
|
||||
$supportedFrequencies = $parser->parseIwInfo($iface);
|
||||
|
||||
// get physical device for selected interface
|
||||
exec("iw dev | awk '/$iface/ {print line}{line = $0}'", $return);
|
||||
$phy = $return[0];
|
||||
|
||||
// get frequencies supported by device
|
||||
exec('iw '.$phy.' info | sed -rn "s/^.*\*\s([0-9]{4})\sMHz.*/\1/p"', $frequencies);
|
||||
|
||||
if (count(preg_grep('/^24[0-9]{2}/i', $frequencies)) >0) {
|
||||
$flags += NL80211_BAND_24GHZ;
|
||||
}
|
||||
if (count(preg_grep('/^5[0-9]{3}/i', $frequencies)) >0) {
|
||||
$flags += NL80211_BAND_5GHZ;
|
||||
}
|
||||
|
||||
switch ($flags) {
|
||||
case NL80211_BAND_24GHZ:
|
||||
$msg = sprintf(_("The selected interface (%s) has support for the 2.4 GHz wireless band only."), $iface);
|
||||
break;
|
||||
case NL80211_BAND_5GHZ:
|
||||
$msg = sprintf(_("The selected interface (%s) has support for the 5 GHz wireless band only."), $iface);
|
||||
break;
|
||||
case NL80211_BAND_24GHZ | NL80211_BAND_5GHZ:
|
||||
$msg = sprintf(_("The selected interface (%s) has support for both the 2.4 and 5 GHz wireless bands."), $iface);
|
||||
break;
|
||||
default:
|
||||
$msg = sprintf(_("The selected interface (%s) does not support wireless mode operation."), $iface);
|
||||
}
|
||||
echo json_encode($msg);
|
||||
echo json_encode($supportedFrequencies);
|
||||
}
|
||||
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
49
ajax/networking/get_nl80211_band.php
Normal file
49
ajax/networking/get_nl80211_band.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?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;
|
||||
|
||||
// get physical device for selected interface
|
||||
exec("iw dev | awk -v iface=".$iface." '/^phy#/ { phy = $0 } $1 == \"Interface\" { interface = $2 } interface == iface { print phy }'", $return);
|
||||
$phy = $return[0];
|
||||
|
||||
// get frequencies supported by device
|
||||
exec('iw '.$phy.' info | sed -rn "s/^.*\*\s([0-9]{4})\sMHz.*/\1/p"', $frequencies);
|
||||
|
||||
if (count(preg_grep('/^24[0-9]{2}/i', $frequencies)) >0) {
|
||||
$flags += NL80211_BAND_24GHZ;
|
||||
}
|
||||
if (count(preg_grep('/^5[0-9]{3}/i', $frequencies)) >0) {
|
||||
$flags += NL80211_BAND_5GHZ;
|
||||
}
|
||||
|
||||
switch ($flags) {
|
||||
case NL80211_BAND_24GHZ:
|
||||
$msg = sprintf(_("The selected interface (%s) has support for the 2.4 GHz wireless band only."), $iface);
|
||||
break;
|
||||
case NL80211_BAND_5GHZ:
|
||||
$msg = sprintf(_("The selected interface (%s) has support for the 5 GHz wireless band only."), $iface);
|
||||
break;
|
||||
case NL80211_BAND_24GHZ | NL80211_BAND_5GHZ:
|
||||
$msg = sprintf(_("The selected interface (%s) has support for both the 2.4 and 5 GHz wireless bands."), $iface);
|
||||
break;
|
||||
default:
|
||||
$msg = sprintf(_("The selected interface (%s) does not support wireless mode operation."), $iface);
|
||||
}
|
||||
echo json_encode($msg);
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
Save settings of network devices (type, name, PW, APN ...)
|
||||
|
||||
Called by js saveNetDeviceSettings (App/js/custom.js)
|
||||
*/
|
||||
|
||||
|
||||
require '../../includes/csrf.php';
|
||||
|
||||
require_once '../../includes/config.php';
|
||||
require_once '../../includes/functions.php';
|
||||
|
||||
if (isset($_POST['interface'])) {
|
||||
$int = $_POST['interface'];
|
||||
$cfg = [];
|
||||
$file = $RASPI_MOBILEDATA_CONFIG;
|
||||
$cfgfile="/etc/wvdial.conf";
|
||||
if ( $int == "mobiledata") {
|
||||
$cfg['pin'] = $_POST["pin-mobile"];
|
||||
$cfg['apn'] = $_POST["apn-mobile"];
|
||||
$cfg['apn_user'] = $_POST["apn-user-mobile"];
|
||||
$cfg['apn_pw'] = $_POST["apn-pw-mobile"];
|
||||
$cfg['router_user'] = $cfg['apn_user'] ;
|
||||
$cfg['router_pw'] = $cfg['apn_pw'] ;
|
||||
if (file_exists($cfgfile)) {
|
||||
if($cfg["pin"] !== "") exec('sudo /bin/sed -i "s/CPIN=\".*\"/CPIN=\"'.$cfg["pin"].'\"/gi" '.$cfgfile);
|
||||
if($cfg["apn"] !== "") exec('sudo /bin/sed -i "s/\"IP\"\,\".*\"/\"IP\"\,\"'.$cfg["apn"].'\"/gi" '.$cfgfile);
|
||||
if($cfg["apn_user"] !== "") exec('sudo /bin/sed -i "s/^username = .*$/Username = '.$cfg["apn_user"].'/gi" '.$cfgfile);
|
||||
if($cfg["apn_pw"] !== "") exec('sudo /bin/sed -i "s/^password = .*$/Password = '.$cfg["apn_pw"].'/gi" '.$cfgfile);
|
||||
}
|
||||
if (write_php_ini($cfg, RASPI_MOBILEDATA_CONFIG)) {
|
||||
$jsonData = ['return'=>0,'output'=>['Successfully saved mobile data settings']];
|
||||
} else {
|
||||
$jsonData = ['return'=>1,'output'=>['Error saving mobile data settings']];
|
||||
}
|
||||
} else if ( preg_match("/netdevices/",$int)) {
|
||||
if(!isset($_POST['opts']) ) {
|
||||
$jsonData = ['return'=>0,'output'=>['No valid data to add/delete udev rule ']];
|
||||
echo json_encode($jsonData);
|
||||
return;
|
||||
} else {
|
||||
$opts=explode(" ",$_POST['opts'] );
|
||||
$dev=$opts[0];
|
||||
$vid=$_POST["int-vid-".$dev];
|
||||
$pid=$_POST["int-pid-".$dev];
|
||||
$mac=$_POST["int-mac-".$dev];
|
||||
$name=trim($_POST["int-name-".$dev]);
|
||||
// limit device name to letters and numbers. Total length max 20
|
||||
$name=preg_replace("/[^a-z0-9]/", "", strtolower($name));
|
||||
$name=substr($name, 0, min(strlen($name),20));
|
||||
$type=$_POST["int-type-".$dev];
|
||||
$newtype=$_POST["int-new-type-".$dev];
|
||||
$udevfile=$_SESSION["udevrules"]["udev_rules_file"]; // default file /etc/udev/rules.d/80-net-devices.rules";
|
||||
|
||||
// find the rule prototype and prefix
|
||||
$rule = "";
|
||||
foreach($_SESSION["udevrules"]["network_devices"] as $devt) {
|
||||
if($devt["type"]==$newtype) {
|
||||
$rulenew = $devt["udev_rule"];
|
||||
$prefix = $devt["name_prefix"];
|
||||
}
|
||||
}
|
||||
|
||||
// check for an existing rule and delete lines with same MAC or same VID/PID
|
||||
if (!empty($vid) && !empty($pid)) {
|
||||
$rule = '^.*ATTRS{idVendor}==\"' . $vid . '\".*ATTRS{idProduct}==\"' . $pid . '\".*$';
|
||||
exec('sudo sed -i "/'.$rule.'/Id" '.$udevfile); // clear all entries with this VID/PID
|
||||
$rule = '^.*ATTRS{idProduct}==\"' . $pid . '\".*ATTRS{idVendor}==\"' . $vid . '\".*$';
|
||||
exec('sudo sed -i "/'.$rule.'/Id" '.$udevfile); // clear all entries with this VID/PID
|
||||
}
|
||||
if (!empty($mac)) {
|
||||
exec('sudo sed -i "/^.*'.$mac.'.*$/d" '.$udevfile); // clear all entries with same MAC
|
||||
}
|
||||
// create new entry
|
||||
if ( ($type != $newtype) || !empty($name) ) { // new device type or new name
|
||||
if (empty($name)) $name = $prefix."%n";
|
||||
if (!empty($mac)) $rule = preg_replace("/\\\$MAC\\\$/i", $mac, $rulenew);
|
||||
if (!empty($vid)) $rule = preg_replace("/\\\$IDVENDOR\\\$/i", $vid, $rule);
|
||||
if (!empty($pid)) $rule = preg_replace("/\\\$IDPRODUCT\\\$/i", $pid, $rule);
|
||||
if (!empty($name)) $rule = preg_replace("/\\\$DEVNAME\\\$/i",$name,$rule);
|
||||
if (!empty($rule)) exec('echo \''.$rule.'\' | sudo /usr/bin/tee -a '.$udevfile);
|
||||
}
|
||||
$jsonData = ['return'=>0,'output'=>['Settings changed for device '.$dev. '<br>Changes will only be in effect after reconnecting the device' ] ];
|
||||
}
|
||||
} else {
|
||||
$jsonData = ['return'=>1,'output'=>['Unknown network configuration']];
|
||||
}
|
||||
} else {
|
||||
$jsonData = ['return'=>2,'output'=>'Unable to detect interface'];
|
||||
}
|
||||
|
||||
echo json_encode($jsonData);
|
|
@ -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']; } );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
26
ajax/plugins/do_plugin_install.php
Executable file
26
ajax/plugins/do_plugin_install.php
Executable 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;
|
||||
}
|
||||
|
31
ajax/session/do_check_session.php
Executable file
31
ajax/session/do_check_session.php
Executable 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();
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
22
ajax/system/sys_chk_update.php
Normal file
22
ajax/system/sys_chk_update.php
Normal 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);
|
||||
|
18
ajax/system/sys_debug.php
Normal file
18
ajax/system/sys_debug.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?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';
|
||||
|
||||
$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);
|
||||
|
23
ajax/system/sys_get_logfile.php
Normal file
23
ajax/system/sys_get_logfile.php
Normal 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';
|
||||
|
||||
$tempDir = sys_get_temp_dir();
|
||||
$filePath = $tempDir . DIRECTORY_SEPARATOR . RASPI_DEBUG_LOG;
|
||||
|
||||
if (isset($filePath)) {
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename='.basename($filePath));
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: '.filesize($filePath));
|
||||
readfile($filePath);
|
||||
exit();
|
||||
} else {
|
||||
header('Location: '.'/system_info');
|
||||
exit();
|
||||
}
|
23
ajax/system/sys_perform_update.php
Normal file
23
ajax/system/sys_perform_update.php
Normal 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();
|
||||
}
|
47
ajax/system/sys_read_logfile.php
Normal file
47
ajax/system/sys_read_logfile.php
Normal 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
24
api/auth.py
Normal 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
156
api/main.py
Normal 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
64
api/modules/ap.py
Normal 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
38
api/modules/client.py
Normal 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
24
api/modules/ddns.py
Normal 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
30
api/modules/dhcp.py
Normal 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
38
api/modules/dns.py
Normal 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
4
api/modules/firewall.py
Normal 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
68
api/modules/networking.py
Normal 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
41
api/modules/openvpn.py
Normal 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
86
api/modules/system.py
Normal 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
23
api/modules/wireguard.py
Normal 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
5
api/requirements.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
fastapi==0.109.1
|
||||
uvicorn==0.25.0
|
||||
psutil==5.9.8
|
||||
python-dotenv==1.0.1
|
||||
|
478
app/css/all.css
478
app/css/all.css
|
@ -6,24 +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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -42,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 {
|
||||
|
@ -52,7 +70,11 @@ License: GNU General Public License v3.0
|
|||
|
||||
.info-item-xs {
|
||||
font-size: 0.7rem;
|
||||
margin-left: 0.3rem;
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
|
||||
.sb-status {
|
||||
margin-left: 0.75rem!important;
|
||||
}
|
||||
|
||||
.info-item-wifi {
|
||||
|
@ -70,13 +92,13 @@ License: GNU General Public License v3.0
|
|||
}
|
||||
|
||||
.service-status-warn {
|
||||
color: #f6f044 !important;
|
||||
color: #ffbf00 !important;
|
||||
}
|
||||
|
||||
.service-status-down {
|
||||
color: #f80107 !important;
|
||||
animation: flash 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes flash {
|
||||
50% {
|
||||
opacity: 0;
|
||||
|
@ -88,6 +110,8 @@ License: GNU General Public License v3.0
|
|||
height: 20rem;
|
||||
border: 1px solid #d1d3e2;
|
||||
border-radius: .35rem;
|
||||
font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.dhcp-static-leases {
|
||||
|
@ -100,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) {
|
||||
|
@ -124,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 {
|
||||
|
@ -146,7 +186,7 @@ canvas#divDBChartBandwidthhourly {
|
|||
}
|
||||
|
||||
.check-progress {
|
||||
color: #999;
|
||||
color: var(--raspap-text-light);
|
||||
}
|
||||
|
||||
.fa-check {
|
||||
|
@ -174,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%; }
|
||||
|
@ -221,7 +260,7 @@ button.btn.btn-light.js-toggle-password {
|
|||
}
|
||||
|
||||
figcaption.figure-caption a {
|
||||
color: #858796;
|
||||
color: var(--raspap-text-muted);
|
||||
}
|
||||
|
||||
button > i.fas {
|
||||
|
@ -233,3 +272,392 @@ button > i.fas {
|
|||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.input-group>.input-group-append:not(:last-child)>.btn {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,19 +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: 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;
|
||||
|
@ -67,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;
|
||||
}
|
||||
|
@ -80,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 {
|
||||
|
@ -110,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
83
app/css/dark.css
Normal 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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -1,627 +0,0 @@
|
|||
<?php header("Content-Type: text/css; charset=utf-8"); ?>
|
||||
<?php
|
||||
require_once '../../includes/functions.php';
|
||||
$color = getColorOpt();
|
||||
?>
|
||||
|
||||
/*
|
||||
Theme Name: Material Dark
|
||||
Author: @marek-guran
|
||||
Author URI: https://github.com/marek-guran
|
||||
Description: Inspired by Google's Material You Design
|
||||
License: GNU General Public License v3.0
|
||||
*/
|
||||
|
||||
<?php
|
||||
// Base color
|
||||
$baseColor = $color;
|
||||
|
||||
// Function to darken a color by a percentage
|
||||
function darkenColor($color, $percent)
|
||||
{
|
||||
$percent /= 100;
|
||||
$r = hexdec(substr($color, 1, 2));
|
||||
$g = hexdec(substr($color, 3, 2));
|
||||
$b = hexdec(substr($color, 5, 2));
|
||||
|
||||
$r = round($r * (1 - $percent));
|
||||
$g = round($g * (1 - $percent));
|
||||
$b = round($b * (1 - $percent));
|
||||
|
||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
||||
}
|
||||
|
||||
// Function to lighten a color by a percentage
|
||||
function lightenColor($color, $percent)
|
||||
{
|
||||
$percent /= 100;
|
||||
$r = hexdec(substr($color, 1, 2));
|
||||
$g = hexdec(substr($color, 3, 2));
|
||||
$b = hexdec(substr($color, 5, 2));
|
||||
|
||||
$r = round($r + (255 - $r) * $percent);
|
||||
$g = round($g + (255 - $g) * $percent);
|
||||
$b = round($b + (255 - $b) * $percent);
|
||||
|
||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
||||
}
|
||||
|
||||
$textColor = lightenColor($baseColor, 95);
|
||||
// Create other color variables
|
||||
$cardsColor = darkenColor($baseColor, 60);
|
||||
$secondaryColor = lightenColor($baseColor, 30);
|
||||
$primaryColor = $baseColor;
|
||||
$backgroundColor = darkenColor($baseColor, 90);
|
||||
|
||||
?>
|
||||
|
||||
@import url('all.css');
|
||||
|
||||
body {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
html * {
|
||||
font-family: Helvetica,Arial,sans-serif;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.nav-item.active .nav-link {
|
||||
position: relative;
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
||||
border-top-right-radius: 18px;
|
||||
border-bottom-right-radius: 18px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
h5.card-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
border-left: .01rem solid <?php echo $secondaryColor; ?>;
|
||||
border-bottom: .01rem solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light .nav-item.active .nav-link i {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar .nav-item.active .nav-link {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.sidebar .nav-item .nav-link span:hover {
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
#wrapper #content-wrapper #content {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.col {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.card-header .col i.fa-tachometer-alt,
|
||||
.card-header .col i.fa-dot-circle,
|
||||
.card-header .col i.fa-wifi,
|
||||
.card-header .col i.fa-exchange-alt,
|
||||
.card-header .col i.fa-hand-paper,
|
||||
.card-header .col i.fa-network-wired,
|
||||
.card-header .col i.fa-key,
|
||||
.card-header .ra-wireguard,
|
||||
.card-header .ra-wireguard:before,
|
||||
.card-header .col i.fa-user-lock,
|
||||
.card-header .col i.fa-chart-bar,
|
||||
.card-header .col i.fa-cube,
|
||||
.card-header .col i.fa-info-circle,
|
||||
.card-header .col i.fa-globe,
|
||||
.card-header .col i.fa-shield-alt {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
i.fa-bars {
|
||||
color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
.nav-tabs .nav-link.active,
|
||||
.nav-tabs .nav-link {
|
||||
font-size: 1.0rem;
|
||||
border-top-left-radius: 18px;
|
||||
border-top-right-radius: 18px;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link:hover {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand:hover {
|
||||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle .icon-bar {
|
||||
background-color: #d2d2d2;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle:focus,
|
||||
.navbar-default .navbar-toggle:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
#content, .navbar, .sidebar, .footer, .sticky-footer {
|
||||
background-attachment: scroll;
|
||||
background-repeat: repeat;
|
||||
background-size: auto;
|
||||
background-position: 0 0;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
}
|
||||
|
||||
.sticky-footer {
|
||||
background-position: 30px 0;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-position: 0 20px;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
a:focus, a:hover {
|
||||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
.card>.card-header, .modal-content, .modal-header {
|
||||
border-color: transparent;
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
color: <?php echo $textColor; ?>;
|
||||
border-radius: 18px;
|
||||
font-size: 1.0rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
border-bottom-left-radius: 0px!important;
|
||||
border-bottom-right-radius: 0px!important;
|
||||
position: relative;
|
||||
margin-bottom: -18px;
|
||||
}
|
||||
|
||||
.card>.card-header .fa {
|
||||
color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.card-header [class^="fa"] {
|
||||
color: <?php echo $textColor; ?>;
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
.card, .card-body {
|
||||
border-color: transparent;
|
||||
border-radius: 18px;
|
||||
background-color: <?php echo $cardsColor; ?>;
|
||||
box-shadow: 0px -5px 5px rgba(0, 0, 0, 0.1),
|
||||
0px 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding-top: 36px; /* 18px to move down + 18px space at the top */
|
||||
padding-bottom: 36px; /* 18px space at the bottom */
|
||||
}
|
||||
|
||||
.unstyled {
|
||||
background-color: <?php echo $cardsColor; ?>;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: .01rem solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-brand-text {
|
||||
color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.ra-raspap:before {
|
||||
color: #ac1b3d !important;
|
||||
}
|
||||
|
||||
.sidebar-light #sidebarToggle {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>; !important
|
||||
}
|
||||
|
||||
.sidebar-light #sidebarToggle::after {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light .nav-item .nav-link:hover i {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light #sidebarToggle:hover {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar.toggled .nav-item .nav-link span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar.toggled .nav-item .nav-link {
|
||||
text-align: center;
|
||||
padding: .6rem 1rem;
|
||||
width: 6.5rem;
|
||||
}
|
||||
|
||||
.card-footer, .modal-footer {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
color: <?php echo $textColor; ?>;
|
||||
border-top: 0px;
|
||||
border-bottom-right-radius: 18px!important;
|
||||
border-bottom-left-radius: 18px!important;
|
||||
position: relative;
|
||||
margin-top: -18px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.card>.card-header::before, .navbar-default::before {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
background-size: 100% 2px, 3px 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sidebar-light, .sticky-footer {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light .nav-item .nav-link i {
|
||||
color: rgba(230, 230, 230, .3);
|
||||
}
|
||||
|
||||
.sidebar .nav-item .nav-link {
|
||||
padding: 0.6rem;
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
|
||||
.sidebar-light hr.sidebar-divider {
|
||||
border-top: 1px solid <?php echo $secondaryColor; ?>;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item .nav-link span {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
.topbar .topbar-divider {
|
||||
border-right: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.label-warning {
|
||||
background-color: #d2d2d2;
|
||||
}
|
||||
|
||||
span.label.label-warning {
|
||||
color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.table>tbody>tr>td,
|
||||
.table>tbody>tr>th,
|
||||
.table>tfoot>tr>td,
|
||||
.table>tfoot>tr>th,
|
||||
.table>thead>tr>td,
|
||||
.table>thead>tr>th {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border-top: .01rem solid <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.table{
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 0 solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
[class*="btn"], [class*="btn"]:focus, [class*="btn"]:disabled {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-color: transparent;
|
||||
border-radius: 18px;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
[class*="btn"]:hover {
|
||||
border-radius: 18px;
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
[class*="btn"]:hover .disabled {
|
||||
background-color:red;
|
||||
}
|
||||
|
||||
[class*="alert"] {
|
||||
border-radius: 18px;
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 1.2em;
|
||||
font-weight: 400;
|
||||
text-shadow: none;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-control:focus,
|
||||
.custom-select {
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.form-control:disabled,
|
||||
.form-control[readonly] {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.form-control::-webkit-input-placeholder { color: #d2d2d2; }
|
||||
.form-control:-moz-placeholder { color: #d2d2d2; }
|
||||
.form-control::-moz-placeholder { color: #d2d2d2; }
|
||||
.form-control:-ms-input-placeholder { color: #d2d2d2; }
|
||||
.form-control::-ms-input-placeholder { color: #d2d2d2; }
|
||||
|
||||
.form-control option {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
input[type="text"]{
|
||||
color: <?php echo $textColor; ?>; !important
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
#progressBar {
|
||||
background-color: <?php echo $secondaryColor; ?>!important;
|
||||
}
|
||||
|
||||
.progress-bar.bg-success {
|
||||
background-color: <?php echo $primaryColor; ?>!important;
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
.progress .progress-bar {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.progress-bar.progress-bar-info.progress-bar-striped.active {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.figure-img {
|
||||
filter: opacity(0.7);
|
||||
}
|
||||
|
||||
.ra-wireguard:before {
|
||||
color: #404040 !important;
|
||||
}
|
||||
|
||||
.ra-wireguard:hover:before {
|
||||
color: #d1d3e2 !important;
|
||||
}
|
||||
|
||||
.sidebar .nav-item.active .nav-link span.ra-wireguard:before {
|
||||
color: #d2d2d2 !important;
|
||||
}
|
||||
|
||||
.custom-control-input:checked ~ .custom-control-label::before {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.custom-control-input:checked ~ .custom-control-label::before {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.wg-keygen {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid yellow <?php echo $secondaryColor; ?>;
|
||||
border-top-right-radius: 18px !important;
|
||||
border-bottom-right-radius: 18px !important;
|
||||
}
|
||||
|
||||
.btn.btn-outline-secondary.js-add-dhcp-upstream-server {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
border-top-right-radius: 18px !important;
|
||||
border-bottom-right-radius: 18px !important;
|
||||
}
|
||||
|
||||
.btn.btn-outline-success.js-add-dhcp-static-lease {
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.btn.btn-outline-success.js-add-dhcp-static-lease:hover {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.fas.fa-circle {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
button.btn.btn-light.js-toggle-password {
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
border-color: transparent;
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn.service-status {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-success {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-success:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.signal-icon .signal-bar {
|
||||
background: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.figure-img {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.logoutput {
|
||||
border-radius: 18px!important;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: 1px solid <?php echo $primaryColor; ?>!important;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
border-top-right-radius: 18px!important;
|
||||
border-bottom-right-radius: 18px!important;
|
||||
}
|
||||
|
||||
.signal-icon .signal-bar {
|
||||
background: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-warning {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-warning:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;!important
|
||||
}
|
||||
|
||||
button.btn.btn-danger {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
button.btn.btn-danger:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn-group label.active {
|
||||
background-color: <?php echo $primaryColor; ?>!important;
|
||||
border-color:transparent!important;
|
||||
color: <?php echo $textColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
background-color: <?php echo $cardsColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn-group:hover {
|
||||
background-color: <?php echo $cardsColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn.btn-outline-secondary#gen_wpa_passphrase {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
border-top-right-radius: 18px !important;
|
||||
border-bottom-right-radius: 18px !important;
|
||||
}
|
||||
|
||||
a.scroll-to-top.rounded {
|
||||
display: inline;
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-radius: 18px!important;
|
||||
}
|
||||
|
||||
a.scroll-to-top.rounded i.fas.fa-angle-up {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.btn.btn-sm.btn-outline-secondary.rounded-right {
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.info-item.col-xs-3 {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
.grid-stack-item-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -1,633 +0,0 @@
|
|||
<?php header("Content-Type: text/css; charset=utf-8"); ?>
|
||||
<?php
|
||||
require_once '../../includes/functions.php';
|
||||
$color = getColorOpt();
|
||||
?>
|
||||
|
||||
|
||||
/*
|
||||
Theme Name: Material Light
|
||||
Author: @marek-guran
|
||||
Author URI: https://github.com/marek-guran
|
||||
Description: Inspired by Google's Material You Design
|
||||
License: GNU General Public License v3.0
|
||||
*/
|
||||
|
||||
<?php
|
||||
// Base color
|
||||
$baseColor = $color;
|
||||
|
||||
// Function to darken a color by a percentage
|
||||
function darkenColor($color, $percent)
|
||||
{
|
||||
$percent /= 100;
|
||||
$r = hexdec(substr($color, 1, 2));
|
||||
$g = hexdec(substr($color, 3, 2));
|
||||
$b = hexdec(substr($color, 5, 2));
|
||||
|
||||
$r = round($r * (1 - $percent));
|
||||
$g = round($g * (1 - $percent));
|
||||
$b = round($b * (1 - $percent));
|
||||
|
||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
||||
}
|
||||
|
||||
// Function to lighten a color by a percentage
|
||||
function lightenColor($color, $percent)
|
||||
{
|
||||
$percent /= 100;
|
||||
$r = hexdec(substr($color, 1, 2));
|
||||
$g = hexdec(substr($color, 3, 2));
|
||||
$b = hexdec(substr($color, 5, 2));
|
||||
|
||||
$r = round($r + (255 - $r) * $percent);
|
||||
$g = round($g + (255 - $g) * $percent);
|
||||
$b = round($b + (255 - $b) * $percent);
|
||||
|
||||
return sprintf("#%02x%02x%02x", $r, $g, $b);
|
||||
}
|
||||
|
||||
$textColor = lightenColor($baseColor, 95);
|
||||
// Create other color variables
|
||||
$cardsColor = lightenColor($baseColor, 50);
|
||||
$secondaryColor = lightenColor($baseColor, 30);
|
||||
$primaryColor = $baseColor;
|
||||
$backgroundColor = lightenColor($baseColor, 60);
|
||||
|
||||
?>
|
||||
|
||||
@import url('all.css');
|
||||
|
||||
body {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
html * {
|
||||
font-family: Helvetica,Arial,sans-serif;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.nav-item.active .nav-link {
|
||||
position: relative;
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
||||
border-top-right-radius: 18px;
|
||||
border-bottom-right-radius: 18px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
h5.card-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
border-left: .01rem solid <?php echo $secondaryColor; ?>;
|
||||
border-bottom: .01rem solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light .nav-item.active .nav-link i {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar .nav-item.active .nav-link {
|
||||
font-weight: 400;
|
||||
color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
#wrapper #content-wrapper #content {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.col {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.card-header .col i.fa-tachometer-alt,
|
||||
.card-header .col i.fa-dot-circle,
|
||||
.card-header .col i.fa-wifi,
|
||||
.card-header .col i.fa-exchange-alt,
|
||||
.card-header .col i.fa-hand-paper,
|
||||
.card-header .col i.fa-network-wired,
|
||||
.card-header .col i.fa-key,
|
||||
.card-header .ra-wireguard,
|
||||
.card-header .ra-wireguard:before,
|
||||
.card-header .col i.fa-user-lock,
|
||||
.card-header .col i.fa-chart-bar,
|
||||
.card-header .col i.fa-cube,
|
||||
.card-header .col i.fa-info-circle,
|
||||
.card-header .col i.fa-globe,
|
||||
.card-header .col i.fa-shield-alt {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
i.fa-bars {
|
||||
color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
.nav-tabs .nav-link.active,
|
||||
.nav-tabs .nav-link {
|
||||
font-size: 1.0rem;
|
||||
border-top-left-radius: 18px;
|
||||
border-top-right-radius: 18px;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link:hover {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand:hover {
|
||||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle .icon-bar {
|
||||
background-color: #d2d2d2;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle:focus,
|
||||
.navbar-default .navbar-toggle:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
#content, .navbar, .sidebar, .footer, .sticky-footer {
|
||||
background-attachment: scroll;
|
||||
background-repeat: repeat;
|
||||
background-size: auto;
|
||||
background-position: 0 0;
|
||||
background-origin: padding-box;
|
||||
background-clip: border-box;
|
||||
}
|
||||
|
||||
.sticky-footer {
|
||||
background-position: 30px 0;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-position: 0 20px;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
a:focus, a:hover {
|
||||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
.card>.card-header, .modal-content, .modal-header {
|
||||
border-color: transparent;
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
color: <?php echo $textColor; ?>;
|
||||
border-radius: 18px;
|
||||
font-size: 1.0rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
border-bottom-left-radius: 0px!important;
|
||||
border-bottom-right-radius: 0px!important;
|
||||
position: relative;
|
||||
margin-bottom: -18px;
|
||||
}
|
||||
|
||||
.card>.card-header .fa {
|
||||
color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.card-header [class^="fa"] {
|
||||
color: <?php echo $textColor; ?>;
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
.card, .card-body {
|
||||
border-color: transparent;
|
||||
border-radius: 18px;
|
||||
background-color: <?php echo $cardsColor; ?>;
|
||||
box-shadow: 0px -5px 5px rgba(0, 0, 0, 0.1),
|
||||
0px 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding-top: 36px; /* 18px to move down + 18px space at the top */
|
||||
padding-bottom: 36px; /* 18px space at the bottom */
|
||||
}
|
||||
|
||||
.unstyled {
|
||||
background-color: <?php echo $cardsColor; ?>;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: .01rem solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-brand-text {
|
||||
color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.ra-raspap:before {
|
||||
color: #ac1b3d !important;
|
||||
}
|
||||
|
||||
.sidebar-light #sidebarToggle {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>; !important
|
||||
}
|
||||
|
||||
.sidebar-light #sidebarToggle::after {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light .nav-item .nav-link:hover i {
|
||||
color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light #sidebarToggle:hover {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar.toggled .nav-item .nav-link span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar.toggled .nav-item .nav-link {
|
||||
text-align: center;
|
||||
padding: .6rem 1rem;
|
||||
width: 6.5rem;
|
||||
}
|
||||
|
||||
.card-footer, .modal-footer {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
color: <?php echo $textColor; ?>;
|
||||
border-top: 0px;
|
||||
border-bottom-right-radius: 18px!important;
|
||||
border-bottom-left-radius: 18px!important;
|
||||
position: relative;
|
||||
margin-top: -18px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.card>.card-header::before, .navbar-default::before {
|
||||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
background-size: 100% 2px, 3px 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sidebar-light, .sticky-footer {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.sidebar-light .nav-item .nav-link i {
|
||||
color: <?php echo $textColor; ?>;;
|
||||
}
|
||||
|
||||
.sidebar .nav-item .nav-link {
|
||||
padding: 0.6rem;
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
|
||||
.sidebar-light hr.sidebar-divider {
|
||||
border-top: 1px solid <?php echo $secondaryColor; ?>;
|
||||
padding-top: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item .nav-link span {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-item .nav-link span:hover {
|
||||
color: <?php echo $primaryColor; ?>!important;
|
||||
}
|
||||
|
||||
.topbar .topbar-divider {
|
||||
border-right: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.label-warning {
|
||||
background-color: #d2d2d2;
|
||||
}
|
||||
|
||||
span.label.label-warning {
|
||||
color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.table>tbody>tr>td,
|
||||
.table>tbody>tr>th,
|
||||
.table>tfoot>tr>td,
|
||||
.table>tfoot>tr>th,
|
||||
.table>thead>tr>td,
|
||||
.table>thead>tr>th {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border-top: .01rem solid <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
.table{
|
||||
border-radius: 18px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table>thead>tr>th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 0 solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
[class*="btn"], [class*="btn"]:focus, [class*="btn"]:disabled {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-color: transparent;
|
||||
border-radius: 18px;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
[class*="btn"]:hover {
|
||||
border-radius: 18px;
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
[class*="btn"]:hover .disabled {
|
||||
background-color:red;
|
||||
}
|
||||
|
||||
[class*="alert"] {
|
||||
border-radius: 18px;
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
|
||||
.close {
|
||||
font-size: 1.2em;
|
||||
font-weight: 400;
|
||||
text-shadow: none;
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.form-control,
|
||||
.form-control:focus,
|
||||
.custom-select {
|
||||
color: <?php echo $textColor; ?>;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.form-control:disabled,
|
||||
.form-control[readonly] {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.form-control::-webkit-input-placeholder { color: #d2d2d2; }
|
||||
.form-control:-moz-placeholder { color: #d2d2d2; }
|
||||
.form-control::-moz-placeholder { color: #d2d2d2; }
|
||||
.form-control:-ms-input-placeholder { color: #d2d2d2; }
|
||||
.form-control::-ms-input-placeholder { color: #d2d2d2; }
|
||||
|
||||
.form-control option {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.form-control::placeholder {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
input[type="text"]{
|
||||
color: <?php echo $textColor; ?>; !important
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
color: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
#progressBar {
|
||||
background-color: <?php echo $secondaryColor; ?>!important;
|
||||
}
|
||||
|
||||
.progress-bar.bg-success {
|
||||
background-color: <?php echo $primaryColor; ?>!important;
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
.progress .progress-bar {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.progress-bar.progress-bar-info.progress-bar-striped.active {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.figure-img {
|
||||
filter: opacity(0.7);
|
||||
}
|
||||
|
||||
.ra-wireguard:before {
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
.ra-wireguard:hover:before {
|
||||
color: <?php echo $primaryColor; ?>!important;
|
||||
}
|
||||
|
||||
.sidebar .nav-item.active .nav-link span.ra-wireguard:before {
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
.custom-control-input:checked ~ .custom-control-label::before {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.custom-control-input:checked ~ .custom-control-label::before {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.wg-keygen {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid yellow <?php echo $secondaryColor; ?>;
|
||||
border-top-right-radius: 18px !important;
|
||||
border-bottom-right-radius: 18px !important;
|
||||
}
|
||||
|
||||
.btn.btn-outline-secondary.js-add-dhcp-upstream-server {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
border-top-right-radius: 18px !important;
|
||||
border-bottom-right-radius: 18px !important;
|
||||
}
|
||||
|
||||
.btn.btn-outline-success.js-add-dhcp-static-lease {
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.btn.btn-outline-success.js-add-dhcp-static-lease:hover {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.fas.fa-circle {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: <?php echo $backgroundColor; ?>;
|
||||
}
|
||||
|
||||
button.btn.btn-light.js-toggle-password {
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
border-color: transparent;
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn.service-status {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-success {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-success:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.signal-icon .signal-bar {
|
||||
background: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
.figure-img {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.logoutput {
|
||||
border-radius: 18px!important;
|
||||
background-color: <?php echo $backgroundColor; ?>;
|
||||
border: 1px solid <?php echo $primaryColor; ?>!important;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
border-top-right-radius: 18px!important;
|
||||
border-bottom-right-radius: 18px!important;
|
||||
}
|
||||
|
||||
.signal-icon .signal-bar {
|
||||
background: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-warning {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
input.btn.btn-warning:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;!important
|
||||
}
|
||||
|
||||
button.btn.btn-danger {
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
}
|
||||
|
||||
button.btn.btn-danger:hover {
|
||||
background-color: <?php echo $backgroundColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn-group label.active {
|
||||
background-color: <?php echo $primaryColor; ?>!important;
|
||||
border-color:transparent!important;
|
||||
color: <?php echo $textColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
background-color: <?php echo $cardsColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn-group:hover {
|
||||
background-color: <?php echo $cardsColor; ?>;!important
|
||||
}
|
||||
|
||||
.btn.btn-outline-secondary#gen_wpa_passphrase {
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
border-top-right-radius: 18px !important;
|
||||
border-bottom-right-radius: 18px !important;
|
||||
}
|
||||
|
||||
a.scroll-to-top.rounded {
|
||||
display: inline;
|
||||
background-color: <?php echo $secondaryColor; ?>;
|
||||
border-radius: 18px!important;
|
||||
}
|
||||
|
||||
a.scroll-to-top.rounded i.fas.fa-angle-up {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.btn.btn-sm.btn-outline-secondary.rounded-right {
|
||||
border: 1px solid <?php echo $secondaryColor; ?>;
|
||||
background-color: <?php echo $primaryColor; ?>;
|
||||
}
|
||||
|
||||
.info-item.col-xs-3 {
|
||||
color: <?php echo $textColor; ?>;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: <?php echo $textColor; ?>!important;
|
||||
}
|
||||
|
||||
.grid-stack-item-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
}
|
54
app/img/dashed.svg
Normal file
54
app/img/dashed.svg
Normal 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
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
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
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
0
app/img/raspAP-logo.php
Normal file → Executable file
40
app/img/right-dashed.svg
Normal file
40
app/img/right-dashed.svg
Normal 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
46
app/img/right-solid.php
Normal 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
65
app/img/solid.php
Normal 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
29
app/img/uri-qr-code.php
Executable 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
3
app/img/wg-qr-code.php
Normal file → Executable 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
8
app/img/wifi-qr-code.php
Normal file → Executable 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);
|
||||
|
|
643
app/js/custom.js
643
app/js/custom.js
|
@ -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">×</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">×</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) {
|
||||
|
@ -185,7 +189,7 @@ function contentLoaded() {
|
|||
setupBtns();
|
||||
break;
|
||||
case "hostapd_conf":
|
||||
loadChannel();
|
||||
getChannel();
|
||||
setHardwareModeTooltip();
|
||||
break;
|
||||
case "dhcpd_conf":
|
||||
|
@ -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,18 +242,17 @@ 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);
|
||||
setDhcpFieldsDisabled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -259,30 +263,126 @@ function setDHCPToggles(state) {
|
|||
}
|
||||
if ($('#dhcp-iface').is(':checked') && !state) {
|
||||
$('#dhcp-iface').prop('checked', state);
|
||||
setDhcpFieldsDisabled();
|
||||
}
|
||||
|
||||
$('#chkfallback').prop('disabled', state);
|
||||
$('#dhcp-iface').prop('disabled', !state);
|
||||
//$('#dhcp-iface').prop('checked', state);
|
||||
}
|
||||
|
||||
function loadChannel() {
|
||||
$.get('ajax/networking/get_channel.php',function(data){
|
||||
jsonData = JSON.parse(data);
|
||||
loadChannelSelect(jsonData);
|
||||
$('#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){
|
||||
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 = 9;
|
||||
var seconds = 3;
|
||||
var pct = 0;
|
||||
var countDown = setInterval(function(){
|
||||
if(seconds <= 0){
|
||||
clearInterval(countDown);
|
||||
}
|
||||
var pct = Math.floor(100-(seconds*100/9));
|
||||
document.getElementsByClassName('progress-bar').item(0).setAttribute('style','width:'+Number(pct)+'%');
|
||||
seconds --;
|
||||
}, 1000);
|
||||
pct = Math.floor(100-(seconds*100/4));
|
||||
}, 500);
|
||||
});
|
||||
|
||||
$('#configureClientModal').on('shown.bs.modal', function (e) {
|
||||
|
@ -338,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(){
|
||||
|
@ -363,8 +463,166 @@ $('#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();
|
||||
$("#PanelManual").hide();
|
||||
$('.ip_address').mask('0ZZ.0ZZ.0ZZ.0ZZ', {
|
||||
translation: {
|
||||
'Z': {
|
||||
pattern: /[0-9]/, optional: true
|
||||
}
|
||||
},
|
||||
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) {
|
||||
|
@ -377,59 +635,81 @@ $('#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);
|
||||
});
|
||||
|
||||
/*
|
||||
Sets the wirelss channel select options based on hw_mode and country_code.
|
||||
|
||||
Methodology: In North America up to channel 11 is the maximum allowed WiFi 2.4Ghz channel,
|
||||
except for the US that allows channel 12 & 13 in low power mode with additional restrictions.
|
||||
Canada allows channel 12 in low power mode. Because it's unsure if low powered mode can be
|
||||
supported the channels are not selectable for those countries. Also Uzbekistan and Colombia
|
||||
allow up to channel 11 as maximum channel on the 2.4Ghz WiFi band.
|
||||
Source: https://en.wikipedia.org/wiki/List_of_WLAN_channels
|
||||
Additional: https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
|
||||
*/
|
||||
function loadChannelSelect(selected) {
|
||||
// Fetch wireless regulatory data
|
||||
$.getJSON("config/wireless.json", function(json) {
|
||||
var hw_mode = $('#cbxhwmode').val();
|
||||
var country_code = $('#cbxcountries').val();
|
||||
var channel_select = $('#cbxchannel');
|
||||
var data = json["wireless_regdb"];
|
||||
var selectablechannels = Array.range(1,14);
|
||||
|
||||
// Assign array of countries to valid frequencies (channels)
|
||||
var countries_2_4Ghz_max11ch = data["2_4GHz_max11ch"].countries;
|
||||
var countries_2_4Ghz_max14ch = data["2_4GHz_max14ch"].countries;
|
||||
var countries_5Ghz_max48ch = data["5Ghz_max48ch"].countries;
|
||||
|
||||
// Map selected hw_mode and country to determine channel list
|
||||
if (hw_mode === 'a') {
|
||||
selectablechannels = data["5Ghz_max48ch"].channels;
|
||||
} else if (($.inArray(country_code, countries_2_4Ghz_max11ch) !== -1) && (hw_mode !== 'ac') ) {
|
||||
selectablechannels = data["2_4GHz_max11ch"].channels;
|
||||
} else if (($.inArray(country_code, countries_2_4Ghz_max14ch) !== -1) && (hw_mode === 'b')) {
|
||||
selectablechannels = data["2_4GHz_max14ch"].channels;
|
||||
} else if (($.inArray(country_code, countries_5Ghz_max48ch) !== -1) && (hw_mode === 'ac')) {
|
||||
selectablechannels = data["5Ghz_max48ch"].channels;
|
||||
}
|
||||
|
||||
// Set channel select with available values
|
||||
selected = (typeof selected === 'undefined') ? selectablechannels[0] : selected;
|
||||
channel_select.empty();
|
||||
$.each(selectablechannels, function(key,value) {
|
||||
channel_select.append($("<option></option>").attr("value", value).text(value));
|
||||
});
|
||||
channel_select.val(selected);
|
||||
// Retrieves the 'channel' value specified in hostapd.conf
|
||||
function getChannel() {
|
||||
$.get('ajax/networking/get_channel.php',function(data){
|
||||
jsonData = JSON.parse(data);
|
||||
loadChannelSelect(jsonData);
|
||||
});
|
||||
}
|
||||
|
||||
/* Sets hardware mode tooltip text for selected interface.
|
||||
/*
|
||||
Sets the wirelss channel select options based on frequencies reported by iw.
|
||||
|
||||
See: https://git.kernel.org/pub/scm/linux/kernel/git/sforshee/wireless-regdb.git
|
||||
Also: https://en.wikipedia.org/wiki/List_of_WLAN_channels
|
||||
*/
|
||||
function loadChannelSelect(selected) {
|
||||
var iface = $('#cbxinterface').val();
|
||||
var hwmodeText = '';
|
||||
var csrfToken = $('meta[name=csrf_token]').attr('content');
|
||||
|
||||
// update hardware mode tooltip
|
||||
setHardwareModeTooltip();
|
||||
|
||||
$.post('ajax/networking/get_frequencies.php',{'interface': iface, 'csrf_token': csrfToken, 'selected': selected},function(response){
|
||||
var hw_mode = $('#cbxhwmode').val();
|
||||
var country_code = $('#cbxcountries').val();
|
||||
var channel_select = $('#cbxchannel');
|
||||
var btn_save = $('#btnSaveHostapd');
|
||||
var data = JSON.parse(response);
|
||||
var selectableChannels = [];
|
||||
|
||||
// Map selected hw_mode to available channels
|
||||
if (hw_mode === 'a') {
|
||||
selectableChannels = data.filter(item => item.MHz.toString().startsWith('5'));
|
||||
} else if (hw_mode !== 'ac') {
|
||||
selectableChannels = data.filter(item => item.MHz.toString().startsWith('24'));
|
||||
} else if (hw_mode === 'b') {
|
||||
selectableChannels = data.filter(item => item.MHz.toString().startsWith('24'));
|
||||
} else if (hw_mode === 'ac') {
|
||||
selectableChannels = data.filter(item => item.MHz.toString().startsWith('5'));
|
||||
}
|
||||
|
||||
// If selected channel doeesn't exist in allowed channels, set default or null (unsupported)
|
||||
if (!selectableChannels.find(item => item.Channel === selected)) {
|
||||
if (selectableChannels.length === 0) {
|
||||
selectableChannels[0] = { Channel: null };
|
||||
} else {
|
||||
defaultChannel = selectableChannels[0].Channel;
|
||||
selected = defaultChannel
|
||||
}
|
||||
}
|
||||
|
||||
// Set channel select with available values
|
||||
channel_select.empty();
|
||||
if (selectableChannels[0].Channel === null) {
|
||||
channel_select.append($("<option></option>").attr("value", "").text("---"));
|
||||
channel_select.prop("disabled", true);
|
||||
btn_save.prop("disabled", true);
|
||||
} else {
|
||||
channel_select.prop("disabled", false);
|
||||
btn_save.prop("disabled", false);
|
||||
$.each(selectableChannels, function(key,value) {
|
||||
channel_select.append($("<option></option>").attr("value", value.Channel).text(value.Channel));
|
||||
});
|
||||
channel_select.val(selected);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Sets hardware mode tooltip text for selected interface
|
||||
* and calls loadChannelSelect()
|
||||
*/
|
||||
function setHardwareModeTooltip() {
|
||||
var iface = $('#cbxinterface').val();
|
||||
|
@ -439,7 +719,7 @@ function setHardwareModeTooltip() {
|
|||
if ($('#cbxhwmode').find('option[value="ac"]').prop('disabled') == true ) {
|
||||
var hwmodeText = $('#hwmode').attr('data-tooltip');
|
||||
}
|
||||
$.post('ajax/networking/get_frequencies.php?',{'interface': iface, 'csrf_token': csrfToken},function(data){
|
||||
$.post('ajax/networking/get_nl80211_band.php?',{'interface': iface, 'csrf_token': csrfToken},function(data){
|
||||
var responseText = JSON.parse(data);
|
||||
$('#tiphwmode').attr('data-original-title', responseText + '\n' + hwmodeText );
|
||||
});
|
||||
|
@ -470,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(){
|
||||
|
@ -518,24 +798,132 @@ 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) {
|
||||
setStaticFieldsEnabled();
|
||||
}
|
||||
});
|
||||
|
||||
$('#chkdhcp').on('change', function() {
|
||||
this.checked ? setStaticFieldsDisabled() : null;
|
||||
});
|
||||
|
||||
|
||||
$('input[name="dhcp-iface"]').change(function() {
|
||||
if ($('input[name="dhcp-iface"]:checked').val() == '1') {
|
||||
setDhcpFieldsEnabled();
|
||||
} else {
|
||||
setDhcpFieldsDisabled();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function setStaticFieldsEnabled() {
|
||||
$('#txtipaddress').prop('required', true);
|
||||
$('#txtsubnetmask').prop('required', true);
|
||||
$('#txtgateway').prop('required', true);
|
||||
|
||||
$('#txtipaddress').removeAttr('disabled');
|
||||
$('#txtsubnetmask').removeAttr('disabled');
|
||||
$('#txtgateway').removeAttr('disabled');
|
||||
}
|
||||
|
||||
function setStaticFieldsDisabled() {
|
||||
$('#txtipaddress').prop('disabled', true);
|
||||
$('#txtsubnetmask').prop('disabled', true);
|
||||
$('#txtgateway').prop('disabled', true);
|
||||
|
||||
$('#txtipaddress').removeAttr('required');
|
||||
$('#txtsubnetmask').removeAttr('required');
|
||||
$('#txtgateway').removeAttr('required');
|
||||
}
|
||||
|
||||
function setDhcpFieldsEnabled() {
|
||||
$('#txtrangestart').prop('required', true);
|
||||
$('#txtrangeend').prop('required', true);
|
||||
$('#txtrangeleasetime').prop('required', true);
|
||||
$('#cbxrangeleasetimeunits').prop('required', true);
|
||||
|
||||
$('#txtrangestart').removeAttr('disabled');
|
||||
$('#txtrangeend').removeAttr('disabled');
|
||||
$('#txtrangeleasetime').removeAttr('disabled');
|
||||
$('#cbxrangeleasetimeunits').removeAttr('disabled');
|
||||
$('#txtdns1').removeAttr('disabled');
|
||||
$('#txtdns2').removeAttr('disabled');
|
||||
$('#txtmetric').removeAttr('disabled');
|
||||
}
|
||||
|
||||
function setDhcpFieldsDisabled() {
|
||||
$('#txtrangestart').removeAttr('required');
|
||||
$('#txtrangeend').removeAttr('required');
|
||||
$('#txtrangeleasetime').removeAttr('required');
|
||||
$('#cbxrangeleasetimeunits').removeAttr('required');
|
||||
|
||||
$('#txtrangestart').prop('disabled', true);
|
||||
$('#txtrangeend').prop('disabled', true);
|
||||
$('#txtrangeleasetime').prop('disabled', true);
|
||||
$('#cbxrangeleasetimeunits').prop('disabled', true);
|
||||
$('#txtdns1').prop('disabled', true);
|
||||
$('#txtdns2').prop('disabled', true);
|
||||
$('#txtmetric').prop('disabled', true);
|
||||
}
|
||||
|
||||
// Static Array method
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -543,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);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -557,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() {
|
||||
|
@ -566,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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -596,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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -1,11 +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.
|
||||
|
@ -16,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');
|
||||
|
@ -29,9 +37,12 @@ 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');
|
||||
|
||||
// Constants for the 5GHz wireless regulatory domain.
|
||||
define('RASPI_5GHZ_ISO_ALPHA2', array('NL','US'));
|
||||
define('RASPI_5GHZ_MAX_CHANNEL', 165);
|
||||
// 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);
|
||||
|
||||
// Enable basic authentication for the web admin.
|
||||
define('RASPI_AUTH_ENABLED', true);
|
||||
|
@ -43,6 +54,7 @@ define('RASPI_NETWORK_ENABLED', true);
|
|||
define('RASPI_DHCP_ENABLED', true);
|
||||
define('RASPI_ADBLOCK_ENABLED', false);
|
||||
define('RASPI_OPENVPN_ENABLED', false);
|
||||
define('RASPI_VPN_PROVIDER_ENABLED', false);
|
||||
define('RASPI_WIREGUARD_ENABLED', false);
|
||||
define('RASPI_TORPROXY_ENABLED', false);
|
||||
define('RASPI_CONFAUTH_ENABLED', true);
|
||||
|
@ -50,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');
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
"static domain_name_server": [ "1.1.1.1 8.8.8.8" ],
|
||||
"subnetmask": [ "255.255.255.0" ]
|
||||
},
|
||||
"wlan1": {
|
||||
"static ip_address": [ "10.9.141.1/24" ],
|
||||
"static routers": [ "10.9.141.1" ],
|
||||
"static domain_name_server": [ "1.1.1.1 8.8.8.8" ],
|
||||
"subnetmask": [ "255.255.255.0" ]
|
||||
},
|
||||
"uap0": {
|
||||
"static ip_address": [ "192.168.50.1/24" ],
|
||||
"static routers": [ "192.168.50.1" ],
|
||||
|
@ -30,6 +36,9 @@
|
|||
"wlan0": {
|
||||
"dhcp-range": [ "10.3.141.50,10.3.141.254,255.255.255.0,12h" ]
|
||||
},
|
||||
"wlan1": {
|
||||
"dhcp-range": [ "10.9.141.50,10.9.141.254,255.255.255.0,12h" ]
|
||||
},
|
||||
"uap0": {
|
||||
"dhcp-range": [ "192.168.50.50,192.168.50.150,12h" ]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
75
config/vpn-providers.json
Normal file
75
config/vpn-providers.json
Normal file
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"providers": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "ExpressVPN",
|
||||
"bin_path": "/usr/bin/expressvpn",
|
||||
"install_page": "https://www.expressvpn.com/support/vpn-setup/app-for-linux/",
|
||||
"account_page": "https://www.expressvpn.com/subscriptions",
|
||||
"cmd_overrides": {
|
||||
"countries": "list all",
|
||||
"log": "diagnostics",
|
||||
"version": "-v"
|
||||
},
|
||||
"regex": {
|
||||
"status": "\/not connected\/",
|
||||
"pattern": "\/^(.{2,5})\\s(?:.{1,28})(.{1,26}).*$\/",
|
||||
"replace": "$1,$2",
|
||||
"slice": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Mullvad VPN",
|
||||
"bin_path": "/usr/bin/mullvad",
|
||||
"install_page": "https://mullvad.net/en/download/vpn/linux",
|
||||
"account_page": "https://mullvad.net/en/account",
|
||||
"cmd_overrides": {
|
||||
"account": "account get",
|
||||
"countries": "relay list",
|
||||
"log": "status -v",
|
||||
"version": "--version"
|
||||
},
|
||||
"regex": {
|
||||
"status": "\/disconnected\/",
|
||||
"pattern": "\/^(.*),.*$\/",
|
||||
"replace": "$1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "NordVPN",
|
||||
"bin_path": "/usr/bin/nordvpn",
|
||||
"install_page": "https://nordvpn.com/download/linux/",
|
||||
"account_page": "https://my.nordaccount.com/dashboard/",
|
||||
"cmd_overrides": {
|
||||
"log": "status"
|
||||
},
|
||||
"regex": {
|
||||
"status": "\/status: disconnected\/",
|
||||
"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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{"wireless_regdb": {
|
||||
"debug": "off",
|
||||
"2_4GHz_max11ch": {
|
||||
"countries": [ "AG", "BS", "BB", "BZ", "CR", "CU", "DM", "DO", "SV", "GD", "GT",
|
||||
"HT", "HN", "JM", "MX", "NI", "PA", "KN", "LC", "VC", "TT", "US", "CA", "UZ", "CO" ],
|
||||
"channels": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
|
||||
},
|
||||
"2_4GHz_max14ch": {
|
||||
"countries": [ "JP", "NL" ],
|
||||
"channels": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ]
|
||||
},
|
||||
"5Ghz_max48ch": {
|
||||
"countries": [ "NL","US" ],
|
||||
"channels": [ 36, 40, 44, 48 ]
|
||||
}
|
||||
}}
|
||||
|
16724
dist/bootstrap/css/bootstrap.css
vendored
16724
dist/bootstrap/css/bootstrap.css
vendored
File diff suppressed because it is too large
Load diff
1
dist/bootstrap/css/bootstrap.css.map
vendored
Normal file
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
6
dist/bootstrap/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
8
dist/bootstrap/js/bootstrap.bundle.min.js
vendored
8
dist/bootstrap/js/bootstrap.bundle.min.js
vendored
File diff suppressed because one or more lines are too long
7876
dist/font-awesome/css/all.css
vendored
Normal file
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
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
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
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
6215
dist/font-awesome/css/fontawesome.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
9
dist/font-awesome/css/fontawesome.min.css
vendored
Normal file
9
dist/font-awesome/css/fontawesome.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
19
dist/font-awesome/css/regular.css
vendored
Normal file
19
dist/font-awesome/css/regular.css
vendored
Normal 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
6
dist/font-awesome/css/regular.min.css
vendored
Normal 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
19
dist/font-awesome/css/solid.css
vendored
Normal 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
6
dist/font-awesome/css/solid.min.css
vendored
Normal 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
459
dist/font-awesome/css/svg-with-js.css
vendored
Normal 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); }
|
6
dist/font-awesome/css/svg-with-js.min.css
vendored
Normal file
6
dist/font-awesome/css/svg-with-js.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
26
dist/font-awesome/css/v4-font-face.css
vendored
Normal file
26
dist/font-awesome/css/v4-font-face.css
vendored
Normal 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; }
|
6
dist/font-awesome/css/v4-font-face.min.css
vendored
Normal file
6
dist/font-awesome/css/v4-font-face.min.css
vendored
Normal 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}
|
2194
dist/font-awesome/css/v4-shims.css
vendored
Normal file
2194
dist/font-awesome/css/v4-shims.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue