Compare commits
1248 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa3949db05 | ||
|
|
0fa7bd2486 | ||
|
|
c5101f6c2d | ||
|
|
ace3368b6a | ||
|
|
458cf609ab | ||
|
|
ec923cfebc | ||
|
|
75bcf5ba60 | ||
|
|
4efc94b8db | ||
|
|
af452adc56 | ||
|
|
0b45ead574 | ||
|
|
a9947f17d5 | ||
|
|
356b9c6888 | ||
|
|
142e67df36 | ||
|
|
21ed86acc2 | ||
|
|
3839732a64 | ||
|
|
a2d0794410 | ||
|
|
4a88478efe | ||
|
|
1720e065cc | ||
|
|
5a08aeeb1d | ||
|
|
bc8d0091c3 | ||
|
|
ce1a325190 | ||
|
|
e09d638c45 | ||
|
|
2469fd93c0 | ||
|
|
a9913d0759 | ||
|
|
0d756c9e70 | ||
|
|
daa03e106b | ||
|
|
e99d26b044 | ||
|
|
42594c0602 | ||
|
|
d96127c93e | ||
|
|
f4718b69c5 | ||
|
|
34af7b25e0 | ||
|
|
11ba11e016 | ||
|
|
f5cfc365d3 | ||
|
|
e2828c3869 | ||
|
|
1e54cd42ce | ||
|
|
0a986a8571 | ||
|
|
85c49398bc | ||
|
|
0a47eca844 | ||
|
|
3aa16f8abf | ||
|
|
c48596e865 | ||
|
|
88982de4f4 | ||
|
|
b0c2c85584 | ||
|
|
65ee425645 | ||
|
|
d26fdb7f50 | ||
|
|
6134324cfd | ||
|
|
61c99a3d8e | ||
|
|
821a166c61 | ||
|
|
5c4914eeec | ||
|
|
b85e8e9f15 | ||
|
|
2a53298fda | ||
|
|
4ac333e067 | ||
|
|
001cb38924 | ||
|
|
10f93d40ff | ||
|
|
0d9b8807b3 | ||
|
|
1b0fb346ef | ||
|
|
700b9ebfec | ||
|
|
2cdf6e9bf3 | ||
|
|
5a8d8f0828 | ||
|
|
246de74ad4 | ||
|
|
ba6f7d5a60 | ||
|
|
f474561593 | ||
|
|
b4e292bf5c | ||
|
|
7d32bbafad | ||
|
|
5e7d640e98 | ||
|
|
cefbf019c6 | ||
|
|
1b877ddcfb | ||
|
|
61f740397b | ||
|
|
ca389e3824 | ||
|
|
4eb955b19a | ||
|
|
08364a26db | ||
|
|
b70b395860 | ||
|
|
169617bdd6 | ||
|
|
3f75ead025 | ||
|
|
37396aad71 | ||
|
|
02de8f39b0 | ||
|
|
b33104fc5d | ||
|
|
13351a5db6 | ||
|
|
d566034421 | ||
|
|
bd58885237 | ||
|
|
508a2d67b9 | ||
|
|
6b39a29838 | ||
|
|
50bcd8813a | ||
|
|
7542761571 | ||
|
|
f80d4eef4a | ||
|
|
02771cf399 | ||
|
|
6c5e0d4907 | ||
|
|
295f5af1eb | ||
|
|
c2446147f6 | ||
|
|
519cf9f69a | ||
|
|
528caa900c | ||
|
|
fc371a6e92 | ||
|
|
476d646d72 | ||
|
|
a0e1d1a404 | ||
|
|
3940761e9e | ||
|
|
722800e9c3 | ||
|
|
cabc1ed81f | ||
|
|
b456748641 | ||
|
|
091dc72f63 | ||
|
|
36e143f262 | ||
|
|
9dbf80ddcf | ||
|
|
47bdf65673 | ||
|
|
d58af0f4e0 | ||
|
|
fd98b52752 | ||
|
|
853a7eebd0 | ||
|
|
de41f02098 | ||
|
|
122edc8003 | ||
|
|
6874d7c111 | ||
|
|
d14957c2b5 | ||
|
|
f5e39b8281 | ||
|
|
7137c6af8e | ||
|
|
a6ac7991e5 | ||
|
|
7250fb490f | ||
|
|
b3e51f7318 | ||
|
|
f51040a589 | ||
|
|
d6e47541a5 | ||
|
|
8260759f12 | ||
|
|
9e66ac78f8 | ||
|
|
7b4b43463a | ||
|
|
4e721fa8c6 | ||
|
|
635d285274 | ||
|
|
b2231a592d | ||
|
|
79f2c4a1b0 | ||
|
|
84dbc37312 | ||
|
|
efef2da546 | ||
|
|
f05c90063c | ||
|
|
e39c36b124 | ||
|
|
131c83826a | ||
|
|
5f5f52251a | ||
|
|
1f9fc71416 | ||
|
|
3577c2143e | ||
|
|
8e603fd5f9 | ||
|
|
1c87fb1284 | ||
|
|
bde1ef93cf | ||
|
|
132d6413b5 | ||
|
|
ca82970070 | ||
|
|
d1e46b29d0 | ||
|
|
8fa5eb9725 | ||
|
|
bb25685691 | ||
|
|
75316a70b9 | ||
|
|
194d996f22 | ||
|
|
64418d11fc | ||
|
|
815c140f11 | ||
|
|
5bc8b51633 | ||
|
|
d807c6d0e5 | ||
|
|
a986b8c3dd | ||
|
|
ee5cf9baa4 | ||
|
|
a6a495d242 | ||
|
|
4486c57b48 | ||
|
|
7347a63f37 | ||
|
|
edb3ee8c86 | ||
|
|
a7227ca715 | ||
|
|
5cfe0bf713 | ||
|
|
d18a59944b | ||
|
|
ba6b971bc4 | ||
|
|
f772bb0e26 | ||
|
|
556ee04eac | ||
|
|
09fc16d873 | ||
|
|
f40f99aac9 | ||
|
|
7e3cc88f2b | ||
|
|
4b556ae8b4 | ||
|
|
8e8d61a0e0 | ||
|
|
d0b7ed4b85 | ||
|
|
4b1c184338 | ||
|
|
508b0c2d83 | ||
|
|
b354e72489 | ||
|
|
90bfa70d1b | ||
|
|
7561a8478d | ||
|
|
b5afdb2bce | ||
|
|
5207162d0a | ||
|
|
8eecc54217 | ||
|
|
ddfd0d3cb3 | ||
|
|
bcc5b2f28a | ||
|
|
2e6be21cd9 | ||
|
|
abb28c4e5b | ||
|
|
44f0ba0924 | ||
|
|
a6f5e6c499 | ||
|
|
d992edf6b4 | ||
|
|
d7ba540377 | ||
|
|
30c95f0d5e | ||
|
|
b670e3a8b1 | ||
|
|
467e24d167 | ||
|
|
7b70d61dd8 | ||
|
|
d530576e9b | ||
|
|
cff6f6393d | ||
|
|
f33d753cc1 | ||
|
|
6809688623 | ||
|
|
68de633143 | ||
|
|
a3e21ac17d | ||
|
|
c8267f75fa | ||
|
|
9e6a52ca4b | ||
|
|
13c68efb8a | ||
|
|
47a3f7073b | ||
|
|
8e0eb6a480 | ||
|
|
911c897b00 | ||
|
|
b9650d3cf5 | ||
|
|
3c959a7920 | ||
|
|
5e170da542 | ||
|
|
63932fb5bc | ||
|
|
741c0f9ede | ||
|
|
08abbabaad | ||
|
|
65c8f81afd | ||
|
|
80958c2e3f | ||
|
|
233873704d | ||
|
|
90322c4747 | ||
|
|
57e6a330be | ||
|
|
0f86b05ce5 | ||
|
|
9dd3a0a2d1 | ||
|
|
20f847c6d8 | ||
|
|
8cd20ab343 | ||
|
|
de5dfa9d06 | ||
|
|
19fe6d53d5 | ||
|
|
37fa7fe8a8 | ||
|
|
5ec13d89ec | ||
|
|
a0a5410af9 | ||
|
|
b234e1c859 | ||
|
|
cd761a058f | ||
|
|
bf137a9755 | ||
|
|
81cfa72b72 | ||
|
|
c15b5bba5c | ||
|
|
c7913c389f | ||
|
|
fc8d17788a | ||
|
|
ff72b45f7c | ||
|
|
692cf9305d | ||
|
|
790e98d8a7 | ||
|
|
0bd985282f | ||
|
|
1e75eeab4c | ||
|
|
a0d34876cc | ||
|
|
c14fa5606d | ||
|
|
aab910f68a | ||
|
|
b9a7516eb8 | ||
|
|
5cf453d4fb | ||
|
|
ff40a5acc0 | ||
|
|
7e2559c229 | ||
|
|
64d6f8be92 | ||
|
|
c91e428e77 | ||
|
|
ee35f35794 | ||
|
|
7492a07244 | ||
|
|
3f3143452e | ||
|
|
e2e5a10e7e | ||
|
|
85335bcdbb | ||
|
|
93420b1f86 | ||
|
|
b7d60ea818 | ||
|
|
0551cd1eea | ||
|
|
b86f1d75b5 | ||
|
|
89fb5c9b3b | ||
|
|
f5d8a9fc8c | ||
|
|
973cd60893 | ||
|
|
da0130da4b | ||
|
|
c8e494596e | ||
|
|
baec65fde7 | ||
|
|
9f5884c4e7 | ||
|
|
4767dec6b8 | ||
|
|
536ef9ec46 | ||
|
|
fd162ff98a | ||
|
|
0ed24dac0a | ||
|
|
e434a686c6 | ||
|
|
138a899e34 | ||
|
|
ae7533cec0 | ||
|
|
55e398dd10 | ||
|
|
fdd199935a | ||
|
|
346a22f2f6 | ||
|
|
5d64433be0 | ||
|
|
1a3cf49c00 | ||
|
|
9dd456bd2c | ||
|
|
1b9d4223c5 | ||
|
|
2a4ac2f2be | ||
|
|
a2f3666134 | ||
|
|
1435ecac67 | ||
|
|
897112e466 | ||
|
|
31e1116483 | ||
|
|
7da9bf03a3 | ||
|
|
8ad63ba07d | ||
|
|
a3702fed94 | ||
|
|
3e3e8fa797 | ||
|
|
f3b64748aa | ||
|
|
257e46df55 | ||
|
|
3c856c010a | ||
|
|
f87ea210c7 | ||
|
|
d433d8e956 | ||
|
|
879d7b674b | ||
|
|
21d47f5d0d | ||
|
|
e7d5c1e5fe | ||
|
|
5c08b06ace | ||
|
|
bb10b865f9 | ||
|
|
557eb8d09e | ||
|
|
a69ce7b85d | ||
|
|
b5649e3c7b | ||
|
|
1ebae57f48 | ||
|
|
6c619bf6f7 | ||
|
|
cfb4bbe907 | ||
|
|
c708718e78 | ||
|
|
1a02d34e85 | ||
|
|
dcf785b900 | ||
|
|
88bbae7c84 | ||
|
|
9485b5adfb | ||
|
|
e2d475100e | ||
|
|
22d3169d07 | ||
|
|
ebe7b9e9e6 | ||
|
|
78c18aa100 | ||
|
|
bd9f68bb27 | ||
|
|
1e693abfc4 | ||
|
|
e4a64a11bd | ||
|
|
43c57f00d0 | ||
|
|
122bb29e99 | ||
|
|
bc8f95d30c | ||
|
|
be4e0acdfc | ||
|
|
79c47015f4 | ||
|
|
d4b590a9fc | ||
|
|
e018fe2995 | ||
|
|
4aad8c12f8 | ||
|
|
93c45d7157 | ||
|
|
695f1593c6 | ||
|
|
eb7b7b57ab | ||
|
|
e8e8260856 | ||
|
|
50b576134a | ||
|
|
2476a36661 | ||
|
|
2aa984b147 | ||
|
|
16de261477 | ||
|
|
9dfc574bde | ||
|
|
9072c37589 | ||
|
|
095a71bc8f | ||
|
|
2b057d339c | ||
|
|
1e0552cc13 | ||
|
|
eea0bf66db | ||
|
|
0741b396ef | ||
|
|
865f3eabd8 | ||
|
|
f5ba9b524d | ||
|
|
654253c953 | ||
|
|
1711cbfe2d | ||
|
|
71c20e159d | ||
|
|
205c143782 | ||
|
|
ed7c919201 | ||
|
|
842014160b | ||
|
|
2a0f464c63 | ||
|
|
c412f025ca | ||
|
|
299371b38c | ||
|
|
d57c38bb3d | ||
|
|
59231739a2 | ||
|
|
7ba6941aed | ||
|
|
95f9b348cd | ||
|
|
ebeeb6c3a5 | ||
|
|
07367a2ca3 | ||
|
|
3d848a70c7 | ||
|
|
c5d1cd919a | ||
|
|
c08b70a38d | ||
|
|
add9800f42 | ||
|
|
1395dd9fb5 | ||
|
|
12b89f7e24 | ||
|
|
0ab5ca32a6 | ||
|
|
19f42e60ba | ||
|
|
a5b952f18c | ||
|
|
80de181827 | ||
|
|
44856f9c04 | ||
|
|
40c6c65ee5 | ||
|
|
6cb4439d59 | ||
|
|
03970f985e | ||
|
|
31a94b779f | ||
|
|
f9a400c34c | ||
|
|
5cea39c9c0 | ||
|
|
99cd07658e | ||
|
|
11fcaa2538 | ||
|
|
8af961ff3f | ||
|
|
10ee4a17a5 | ||
|
|
f029fa1cc8 | ||
|
|
bbe0ba0389 | ||
|
|
7084c69171 | ||
|
|
3ada622bd0 | ||
|
|
93d08de2ab | ||
|
|
64da64105e | ||
|
|
3e448b123b | ||
|
|
bedbebbe04 | ||
|
|
4b3d876fbd | ||
|
|
d52709cb72 | ||
|
|
ed53e59a00 | ||
|
|
0fcf089d39 | ||
|
|
25abc1b59b | ||
|
|
516eef0431 | ||
|
|
5df5bdef59 | ||
|
|
4eddad5bf4 | ||
|
|
794bfcc25c | ||
|
|
0f56f06937 | ||
|
|
78a87c4ed0 | ||
|
|
af41eed26c | ||
|
|
5169ac32a1 | ||
|
|
1e7c50b0fe | ||
|
|
31f7521501 | ||
|
|
a29e700b83 | ||
|
|
04c45bd39f | ||
|
|
524bf1f676 | ||
|
|
ee63f3fe0d | ||
|
|
295db87113 | ||
|
|
1f54292fbc | ||
|
|
eea4e2642c | ||
|
|
8b81501b44 | ||
|
|
148f3198ce | ||
|
|
b7417a07ad | ||
|
|
844311f4e8 | ||
|
|
da45606f64 | ||
|
|
cf0cc4cc17 | ||
|
|
edd8fd0fbc | ||
|
|
05c3613d3f | ||
|
|
ebbbebf352 | ||
|
|
ea478ae5e6 | ||
|
|
be57534b2a | ||
|
|
7c11f0fa38 | ||
|
|
a3b05c3760 | ||
|
|
04a91b2bb7 | ||
|
|
1d81a20e6f | ||
|
|
989ec68666 | ||
|
|
5401e2729b | ||
|
|
5c6bb2fa0d | ||
|
|
858e02f7c6 | ||
|
|
dd65bd5744 | ||
|
|
6ba1bdb7de | ||
|
|
b7e3263b38 | ||
|
|
4830d54229 | ||
|
|
85911c8ff4 | ||
|
|
296891ca67 | ||
|
|
7d0762ff35 | ||
|
|
127d9e6196 | ||
|
|
6c58281c2e | ||
|
|
beeeb4bd33 | ||
|
|
9aa1462e17 | ||
|
|
6637d9c954 | ||
|
|
f1344f16fa | ||
|
|
abbaa1c11f | ||
|
|
87a10a721b | ||
|
|
2230df591e | ||
|
|
2898805514 | ||
|
|
c906ccda91 | ||
|
|
d1101aee47 | ||
|
|
39157360ef | ||
|
|
e4a34ecd2b | ||
|
|
d444ad31ce | ||
|
|
06a11f43ea | ||
|
|
fdcf12fb86 | ||
|
|
59682f6840 | ||
|
|
949052d00c | ||
|
|
e7fd39112e | ||
|
|
028c4a9cb4 | ||
|
|
274f954b8a | ||
|
|
e44bceaed5 | ||
|
|
9fe8d8a3b4 | ||
|
|
ab59d529ec | ||
|
|
7581e4f63a | ||
|
|
8f15579136 | ||
|
|
2b9323ac98 | ||
|
|
8676b7ccde | ||
|
|
cd43935656 | ||
|
|
f6a08fc3d4 | ||
|
|
166af4ce8d | ||
|
|
7943977ff5 | ||
|
|
2e407d9e8f | ||
|
|
04cf16cc94 | ||
|
|
fa6df3cff8 | ||
|
|
0476689c25 | ||
|
|
ce2d955c86 | ||
|
|
d62a1f077a | ||
|
|
14a1d61bb1 | ||
|
|
069522febe | ||
|
|
28df1e6aaf | ||
|
|
bdcef1a37e | ||
|
|
1580810597 | ||
|
|
d4c724e79c | ||
|
|
361952ec5a | ||
|
|
c2a4713024 | ||
|
|
8c60e98852 | ||
|
|
10371e8411 | ||
|
|
053bcff11c | ||
|
|
841bd16701 | ||
|
|
657e6e2f8d | ||
|
|
89ea7c02c6 | ||
|
|
297b9158e1 | ||
|
|
0ab1f9e19a | ||
|
|
25b54d1f62 | ||
|
|
854ef20826 | ||
|
|
bed4e6a152 | ||
|
|
a379054f5b | ||
|
|
b5e933ba12 | ||
|
|
9afed6e43b | ||
|
|
015ce23fe2 | ||
|
|
6dcf09a2f6 | ||
|
|
7391df9f7b | ||
|
|
6032667ea7 | ||
|
|
8ae8d6aa27 | ||
|
|
b281652009 | ||
|
|
82e9a4a8ef | ||
|
|
f9baa603f4 | ||
|
|
f1a553aac6 | ||
|
|
61df3ec581 | ||
|
|
8ffc07a110 | ||
|
|
a794170adf | ||
|
|
6c28c14e7c | ||
|
|
a1b17a238b | ||
|
|
53f41a9434 | ||
|
|
2223050523 | ||
|
|
eb7282201b | ||
|
|
396416ad29 | ||
|
|
9c76c9f79c | ||
|
|
c4adb03c50 | ||
|
|
1d8beb9222 | ||
|
|
e6644ad3ec | ||
|
|
dce40cb9fb | ||
|
|
d6cf983b93 | ||
|
|
0b350b686e | ||
|
|
fa7d2534bf | ||
|
|
3a2afa4bf4 | ||
|
|
57c9c5b23f | ||
|
|
facc6619e2 | ||
|
|
6b0a65c427 | ||
|
|
fb489adc66 | ||
|
|
45c03aee45 | ||
|
|
41cfdcdc00 | ||
|
|
e14475afb0 | ||
|
|
64a3c348bd | ||
|
|
c57513618b | ||
|
|
b114de1fd9 | ||
|
|
ed0276b61e | ||
|
|
6998f11967 | ||
|
|
956fcf65ed | ||
|
|
e32844d2f2 | ||
|
|
3dca9da5e3 | ||
|
|
5a060722a1 | ||
|
|
f3dac743d1 | ||
|
|
a07ed7ee85 | ||
|
|
d54722cf03 | ||
|
|
ba09964eaa | ||
|
|
c0f73a8112 | ||
|
|
06b6ef2889 | ||
|
|
602f0648e0 | ||
|
|
7e2f05866c | ||
|
|
acfc48c82c | ||
|
|
2b8257d866 | ||
|
|
a3bcb3c491 | ||
|
|
658b936a01 | ||
|
|
9b1443423e | ||
|
|
4848ba78d9 | ||
|
|
d16d43de9d | ||
|
|
fa36fb788c | ||
|
|
276214da98 | ||
|
|
1c94328dbd | ||
|
|
7f51fdcfa1 | ||
|
|
541cb2e1b1 | ||
|
|
2396f226dd | ||
|
|
58c26ea055 | ||
|
|
413f869424 | ||
|
|
e1ab0b3ef7 | ||
|
|
0cb7b6c96a | ||
|
|
3f0c899f17 | ||
|
|
a25efc6dd6 | ||
|
|
8038fc9472 | ||
|
|
17c3dc4914 | ||
|
|
2e53da32d1 | ||
|
|
57aefdf332 | ||
|
|
9edbe8affc | ||
|
|
033dacf8be | ||
|
|
b82246595f | ||
|
|
277950fc51 | ||
|
|
0261b8e210 | ||
|
|
445b4de69e | ||
|
|
3b60a3a1ae | ||
|
|
5103e2c229 | ||
|
|
e9dc7de2e8 | ||
|
|
c7d04ddbcf | ||
|
|
af5aecd127 | ||
|
|
ecc297a112 | ||
|
|
1067211033 | ||
|
|
64c3de0450 | ||
|
|
20986852de | ||
|
|
2239aa6c25 | ||
|
|
908789230b | ||
|
|
eb74d7fc14 | ||
|
|
519822c971 | ||
|
|
9be6af6477 | ||
|
|
5838f8be95 | ||
|
|
da8098752e | ||
|
|
0fcd4502bd | ||
|
|
9e768f5be7 | ||
|
|
50fa0677d9 | ||
|
|
3641d2360e | ||
|
|
9eab7640c4 | ||
|
|
8feb7c585f | ||
|
|
654efdc503 | ||
|
|
46b01bcb93 | ||
|
|
4895a61af3 | ||
|
|
c820e2e8f5 | ||
|
|
c9c7f0ada6 | ||
|
|
3069e508f5 | ||
|
|
62601fc4ad | ||
|
|
5d05ede3e6 | ||
|
|
c3982bf747 | ||
|
|
ef97013051 | ||
|
|
07d37cd9b0 | ||
|
|
6b3bed69d3 | ||
|
|
f99f45505d | ||
|
|
7caf1f841a | ||
|
|
8ea45f5295 | ||
|
|
a57669a6e0 | ||
|
|
80a0b889c1 | ||
|
|
57f508f15c | ||
|
|
b732a87409 | ||
|
|
c2b97cbabd | ||
|
|
645e779d7c | ||
|
|
b6a9c788bf | ||
|
|
8bd5c59186 | ||
|
|
22b9ec5a1a | ||
|
|
ed2f6f90eb | ||
|
|
609e118a7a | ||
|
|
8ed1456e02 | ||
|
|
75002f93d3 | ||
|
|
84fb663e09 | ||
|
|
7f051938d0 | ||
|
|
913a1f72b6 | ||
|
|
cb7eeb7d46 | ||
|
|
92c58efd63 | ||
|
|
f5acab8ad8 | ||
|
|
9b2c6b8838 | ||
|
|
33e6fffd5d | ||
|
|
c61caed1af | ||
|
|
474da8f3f0 | ||
|
|
0ed510cfd8 | ||
|
|
5e884dc675 | ||
|
|
fcde1a275e | ||
|
|
bcd804403a | ||
|
|
ef1c3c9674 | ||
|
|
7d995f0735 | ||
|
|
89342ba9ee | ||
|
|
b18bcc7692 | ||
|
|
55d6513853 | ||
|
|
d11972c07d | ||
|
|
b2c798a934 | ||
|
|
200e4c806c | ||
|
|
d96b3519b2 | ||
|
|
6f5c514be3 | ||
|
|
89fe57fbc1 | ||
|
|
f168726778 | ||
|
|
69ff580d4c | ||
|
|
6dfa82bafa | ||
|
|
63c0850352 | ||
|
|
49d1480e15 | ||
|
|
0dd75db4d7 | ||
|
|
2773fc4f83 | ||
|
|
8fc140c16a | ||
|
|
c7a740d51f | ||
|
|
611ae2f154 | ||
|
|
326503bcf9 | ||
|
|
ad4adc742f | ||
|
|
7befc97ab7 | ||
|
|
28f98c159b | ||
|
|
e7ff1a7954 | ||
|
|
f93b8b2e10 | ||
|
|
c64c351a85 | ||
|
|
75c5ec1215 | ||
|
|
7b3a08ef25 | ||
|
|
ef660d49c3 | ||
|
|
bcf4bcc5af | ||
|
|
e8f8296d53 | ||
|
|
c360c80291 | ||
|
|
8b62207b8b | ||
|
|
1a92514253 | ||
|
|
725490c87e | ||
|
|
f811c0a543 | ||
|
|
a26a81beec | ||
|
|
cb5b3d3a8d | ||
|
|
26ee74be6e | ||
|
|
0d1c32a453 | ||
|
|
ab0c9dfeb9 | ||
|
|
0ebd391cd2 | ||
|
|
a0b077b54e | ||
|
|
d78fcd6ae3 | ||
|
|
a397048ea4 | ||
|
|
e4da6c9379 | ||
|
|
be1cdec6fa | ||
|
|
5df4822ef0 | ||
|
|
1a89a14ee3 | ||
|
|
97f7770d98 | ||
|
|
0327f8818a | ||
|
|
b03c6aec57 | ||
|
|
3c9a035249 | ||
|
|
4b075cffe7 | ||
|
|
b85c308e78 | ||
|
|
9e58c8c572 | ||
|
|
5cc08030ce | ||
|
|
50699ed01f | ||
|
|
486e245c14 | ||
|
|
cd9105d0a9 | ||
|
|
99e9f5ca68 | ||
|
|
f35550663d | ||
|
|
39eb7fff1e | ||
|
|
fa6748fe79 | ||
|
|
2c12e625b4 | ||
|
|
49daed828b | ||
|
|
a3359dbec4 | ||
|
|
c8bae60060 | ||
|
|
0f8253241e | ||
|
|
ed9c0c2a2c | ||
|
|
3c5db004c4 | ||
|
|
5eac1e000f | ||
|
|
b42d6feaa0 | ||
|
|
d61d9b1789 | ||
|
|
2c7e14afcd | ||
|
|
58ade8948c | ||
|
|
10e08093c6 | ||
|
|
58bc8bf6ce | ||
|
|
b1e10567f6 | ||
|
|
1a464630f2 | ||
|
|
4aea02e215 | ||
|
|
b1b8d6f090 | ||
|
|
0de1406b5c | ||
|
|
e068b360a4 | ||
|
|
385deb254b | ||
|
|
b28f9ed422 | ||
|
|
117e0366e5 | ||
|
|
6759aa3267 | ||
|
|
aab506fb58 | ||
|
|
b111bbf926 | ||
|
|
8d58f1fe91 | ||
|
|
20871ba401 | ||
|
|
fb121c1df4 | ||
|
|
80888ae910 | ||
|
|
84c74fbb2a | ||
|
|
9caeb0cfdf | ||
|
|
796c02adfb | ||
|
|
0812182fd2 | ||
|
|
8368c3d102 | ||
|
|
dca50f42c7 | ||
|
|
1944c24fe7 | ||
|
|
f136334414 | ||
|
|
c5f99ad701 | ||
|
|
62b3bc6a6a | ||
|
|
e7fe2b808f | ||
|
|
a85f0003e3 | ||
|
|
d6142f7498 | ||
|
|
63661dea5b | ||
|
|
499a798d3e | ||
|
|
23da070784 | ||
|
|
5efc4975c6 | ||
|
|
013262c694 | ||
|
|
12d8d2d2fc | ||
|
|
af83432fdb | ||
|
|
34d3ea9ef0 | ||
|
|
9c2ebd53d7 | ||
|
|
fc569b50d4 | ||
|
|
06873f5054 | ||
|
|
420ee4ac65 | ||
|
|
2659bc1440 | ||
|
|
ded7af9fe3 | ||
|
|
75dd81adcd | ||
|
|
b749199f55 | ||
|
|
731e9be82b | ||
|
|
22844b430e | ||
|
|
dbfb3176f5 | ||
|
|
0591afa80f | ||
|
|
be2f5a9f15 | ||
|
|
633ceb6136 | ||
|
|
7610f3633d | ||
|
|
acf2437020 | ||
|
|
f28733d94d | ||
|
|
8398d73b61 | ||
|
|
46876228ba | ||
|
|
7de5e4db8b | ||
|
|
33273bf83c | ||
|
|
719b3e5705 | ||
|
|
ae5fd47f72 | ||
|
|
57f9728867 | ||
|
|
b07118b298 | ||
|
|
e669ecacf3 | ||
|
|
725032d31f | ||
|
|
ea05fd58c1 | ||
|
|
1ecdc1249c | ||
|
|
b016f6fefe | ||
|
|
8c64b65942 | ||
|
|
e0e1250592 | ||
|
|
64694a1ead | ||
|
|
7c1c33ecdc | ||
|
|
48303fce62 | ||
|
|
67cac33779 | ||
|
|
7c9229e9c9 | ||
|
|
f8b5cc98b2 | ||
|
|
ddde35ec1c | ||
|
|
df7c51d303 | ||
|
|
96de41e4f0 | ||
|
|
eb63964a90 | ||
|
|
00942ba48f | ||
|
|
9735085328 | ||
|
|
367dec4024 | ||
|
|
3200b3bc10 | ||
|
|
e98035e418 | ||
|
|
477d43b675 | ||
|
|
01d7730ffb | ||
|
|
d69227a8f1 | ||
|
|
7e6fa9fcbd | ||
|
|
a58ef98a9c | ||
|
|
5805c94c8a | ||
|
|
df0afdc7be | ||
|
|
5bf12e4e7d | ||
|
|
c9f22aa0c7 | ||
|
|
8c91357fbb | ||
|
|
4a0265ef25 | ||
|
|
d392be05a2 | ||
|
|
824825860f | ||
|
|
0a4261bba4 | ||
|
|
93e76e27d7 | ||
|
|
9812b76138 | ||
|
|
988a323757 | ||
|
|
29fc5c669d | ||
|
|
fbc3c8cede | ||
|
|
11f341366b | ||
|
|
2414498846 | ||
|
|
1977f48eb1 | ||
|
|
dc1c5763aa | ||
|
|
14e16a9d18 | ||
|
|
4505a5a97a | ||
|
|
f076240832 | ||
|
|
086d1c03cf | ||
|
|
c6fab002be | ||
|
|
48be1a9eda | ||
|
|
59e3f45e70 | ||
|
|
294a205dfd | ||
|
|
80500b6ede | ||
|
|
06d9cf2292 | ||
|
|
b7a3ad7044 | ||
|
|
b6df0fb1a8 | ||
|
|
42e0d4330d | ||
|
|
cfae2c3418 | ||
|
|
fd314b5187 | ||
|
|
f6a680730f | ||
|
|
0164f4a9d7 | ||
|
|
b37b4559b0 | ||
|
|
81d9e12c8d | ||
|
|
5aa4450691 | ||
|
|
144b81eab7 | ||
|
|
c2e4d39117 | ||
|
|
5397edc14d | ||
|
|
82d7c28fd7 | ||
|
|
b3159d683c | ||
|
|
56d6190fa3 | ||
|
|
b59d2149b8 | ||
|
|
3ca4ce9c80 | ||
|
|
c3a6b33b33 | ||
|
|
de964eb64a | ||
|
|
e421d84033 | ||
|
|
76e02d691d | ||
|
|
e7a8668420 | ||
|
|
b71da10a80 | ||
|
|
a73f8bf8da | ||
|
|
eae55beccc | ||
|
|
2b9c76efe1 | ||
|
|
b1b3abeb2f | ||
|
|
8d028ad705 | ||
|
|
50098bd092 | ||
|
|
6f45cfc60c | ||
|
|
d3030b8815 | ||
|
|
12e97c6b9a | ||
|
|
a6797d8608 | ||
|
|
640aac54f5 | ||
|
|
89e7ae9593 | ||
|
|
80cc4ec265 | ||
|
|
ffb187dd84 | ||
|
|
48117cc0d6 | ||
|
|
a4c236979f | ||
|
|
73e9748631 | ||
|
|
d46289e59d | ||
|
|
55ab809d5c | ||
|
|
6843668193 | ||
|
|
c6a2f697b8 | ||
|
|
02340feb70 | ||
|
|
42e1030f85 | ||
|
|
221b6349f1 | ||
|
|
ac1dbe4e46 | ||
|
|
75c4b50d96 | ||
|
|
20955e1a8f | ||
|
|
4fa8b8c4ef | ||
|
|
bf29cd42d6 | ||
|
|
d85ecb0d12 | ||
|
|
27519a3966 | ||
|
|
50480b85dd | ||
|
|
14d236cac7 | ||
|
|
220bd6798e | ||
|
|
2003f5a946 | ||
|
|
7e75df6334 | ||
|
|
b4775ae1e7 | ||
|
|
fec1b3f323 | ||
|
|
50aeaa957e | ||
|
|
9a59102f92 | ||
|
|
6b13738ea7 | ||
|
|
3c2dc0dbfb | ||
|
|
243f0034f3 | ||
|
|
1dfe20b0c9 | ||
|
|
d6cffb367f | ||
|
|
2561fccce5 | ||
|
|
3933936aa9 | ||
|
|
12f628aa5d | ||
|
|
5ed95dcd36 | ||
|
|
47ef80cc44 | ||
|
|
832beeef22 | ||
|
|
6598eb9a48 | ||
|
|
4e36f539ef | ||
|
|
93a7da0018 | ||
|
|
622694f405 | ||
|
|
01c5de3620 | ||
|
|
5e1248cc00 | ||
|
|
efecdff59d | ||
|
|
3c5deccb84 | ||
|
|
8e12daf1c7 | ||
|
|
008da18727 | ||
|
|
f108cc86da | ||
|
|
f2b2a25a19 | ||
|
|
82a1a7e5c7 | ||
|
|
e4b61e2667 | ||
|
|
cd4d1ca37b | ||
|
|
d238de9fb1 | ||
|
|
4b07e8bbb6 | ||
|
|
2cb169eff5 | ||
|
|
b53b455719 | ||
|
|
cf51d1f5d7 | ||
|
|
296fd71b5a | ||
|
|
4f17e61e8a | ||
|
|
95126b7c36 | ||
|
|
d2b6e75483 | ||
|
|
320660945c | ||
|
|
a0d02b2aa5 | ||
|
|
19cf64a6f0 | ||
|
|
01017040e3 | ||
|
|
9c7f5ff771 | ||
|
|
3718a06ea9 | ||
|
|
2950d2ce9f | ||
|
|
4f59d0867d | ||
|
|
ee98c7a653 | ||
|
|
af902dae57 | ||
|
|
0e23c6ac61 | ||
|
|
30362bb72e | ||
|
|
dd7f86bfa0 | ||
|
|
b231a06ee8 | ||
|
|
d86a042070 | ||
|
|
b0e34a802d | ||
|
|
3460b88167 | ||
|
|
2668370450 | ||
|
|
42e1e748a3 | ||
|
|
0c620a06f7 | ||
|
|
bae7b0400c | ||
|
|
b87083e6b1 | ||
|
|
db4d81863b | ||
|
|
2c15bc4127 | ||
|
|
f7a8e77cc5 | ||
|
|
7c16bd31a2 | ||
|
|
d5d23c8c60 | ||
|
|
3948557da8 | ||
|
|
8057d49be0 | ||
|
|
22bfb9deef | ||
|
|
c9f4560cf9 | ||
|
|
6dee27e5a5 | ||
|
|
9ddea01f12 | ||
|
|
8a8790d49b | ||
|
|
e74b8d27b6 | ||
|
|
a38d254877 | ||
|
|
3ca4e19199 | ||
|
|
0b3b1e4ed4 | ||
|
|
b068b631be | ||
|
|
9bdac0edbf | ||
|
|
56604f702f | ||
|
|
25bdc36183 | ||
|
|
fa7582135e | ||
|
|
40e94e45a2 | ||
|
|
e119d51d08 | ||
|
|
7c63a5e52f | ||
|
|
3a46c7eb27 | ||
|
|
80bda24b5f | ||
|
|
5f3f4c1a73 | ||
|
|
1bdfc1962a | ||
|
|
ff9245c31d | ||
|
|
085e7c80e7 | ||
|
|
9a13133a5f | ||
|
|
1baeeb99db | ||
|
|
8f1223c55b | ||
|
|
64ad2f6b80 | ||
|
|
39282d51ac | ||
|
|
76c3f7e94e | ||
|
|
2a14d59a45 | ||
|
|
d848e18bc0 | ||
|
|
3430118f09 | ||
|
|
e0c7ffbb12 | ||
|
|
ec669a701e | ||
|
|
8da84e8d64 | ||
|
|
90e94a14fb | ||
|
|
f33262d262 | ||
|
|
2e137b4e07 | ||
|
|
634bc0744d | ||
|
|
8cbca4430a | ||
|
|
6c166908a1 | ||
|
|
42ebb687f8 | ||
|
|
d9761e771f | ||
|
|
2575b79c8b | ||
|
|
6009098c9c | ||
|
|
2946e48321 | ||
|
|
8256a84efe | ||
|
|
c2da5c56b8 | ||
|
|
ef64014100 | ||
|
|
2bb5d332ff | ||
|
|
54d71c7cc9 | ||
|
|
14437f2984 | ||
|
|
928ee52a7e | ||
|
|
82d87db762 | ||
|
|
f26507e540 | ||
|
|
dcd32b9162 | ||
|
|
d59eb03f40 | ||
|
|
d096b36434 | ||
|
|
5624401fcf | ||
|
|
8c4992bf9a | ||
|
|
a4984dc477 | ||
|
|
c2676f9fda | ||
|
|
9bb3820e82 | ||
|
|
72ccaf754f | ||
|
|
da0d387ae0 | ||
|
|
e06fe9146c | ||
|
|
e5eb3ab297 | ||
|
|
012589b848 | ||
|
|
43a2c4870e | ||
|
|
8fe10e6314 | ||
|
|
cab6c0cefb | ||
|
|
07c2c2b9ac | ||
|
|
a4f8cfa287 | ||
|
|
1bafee59c8 | ||
|
|
e8f9608372 | ||
|
|
d8904f7ac8 | ||
|
|
8f8e4334b9 | ||
|
|
293e009321 | ||
|
|
5d53f1f605 | ||
|
|
87212bb25f | ||
|
|
7076c83185 | ||
|
|
ccbf4defe8 | ||
|
|
c3c3de01e0 | ||
|
|
7efe658503 | ||
|
|
88301c97eb | ||
|
|
e68a04ee5b | ||
|
|
655fa96c67 | ||
|
|
ce5d09ed2e | ||
|
|
e34a7c032a | ||
|
|
88ef46b2d4 | ||
|
|
d5f8cdda7d | ||
|
|
4fbaccc0f2 | ||
|
|
b4dd34355e | ||
|
|
2b02e6ee29 | ||
|
|
a262a89e13 | ||
|
|
50233460b2 | ||
|
|
8776fc1356 | ||
|
|
cd793c8e67 | ||
|
|
9a6c5896dd | ||
|
|
43e96a8708 | ||
|
|
38702d03ac | ||
|
|
335fa1b003 | ||
|
|
91140642ef | ||
|
|
eb0c7fbf68 | ||
|
|
d8af423a9c | ||
|
|
8693d4cae9 | ||
|
|
960a3ebe14 | ||
|
|
1105caed16 | ||
|
|
f35bb19f5a | ||
|
|
eee7816a50 | ||
|
|
58bb740e48 | ||
|
|
1101bc9477 | ||
|
|
6fd750e4e1 | ||
|
|
55d7cb0fec | ||
|
|
cc5901ffb0 | ||
|
|
e9c8be78ad | ||
|
|
779ce0e568 | ||
|
|
c351d2e8d4 | ||
|
|
dc2849f296 | ||
|
|
b10d259390 | ||
|
|
aac46f97ce | ||
|
|
46e4857a35 | ||
|
|
35a0a91a02 | ||
|
|
cd164793cc | ||
|
|
56f35f5068 | ||
|
|
e83a622152 | ||
|
|
6cdc0c14df | ||
|
|
d7fb478794 | ||
|
|
2c2bf18562 | ||
|
|
5faf6fb419 | ||
|
|
b1f946e1e6 | ||
|
|
bcea3e1a97 | ||
|
|
bcda186cbe | ||
|
|
02215c87eb | ||
|
|
024e97f138 | ||
|
|
c56c7609cc | ||
|
|
d723b37622 | ||
|
|
b461bf4ef7 | ||
|
|
6e8bb4c2ea | ||
|
|
0446f6302e | ||
|
|
a0b0c0ba19 | ||
|
|
cb0a62396f | ||
|
|
3315994356 | ||
|
|
c3798ff102 | ||
|
|
43c0df086a | ||
|
|
98745805d3 | ||
|
|
1dbdf425d6 | ||
|
|
b3d05332e5 | ||
|
|
98fb02282b | ||
|
|
536d789535 | ||
|
|
d0284a0603 | ||
|
|
4d433b633f | ||
|
|
388844f2bc | ||
|
|
2fc63daf23 | ||
|
|
c9bc3e9447 | ||
|
|
4a754cdae5 | ||
|
|
1bb1d528f4 | ||
|
|
770d9bfe4a | ||
|
|
8e3aa0407a | ||
|
|
acb756a871 | ||
|
|
85e6319760 | ||
|
|
66ffb5ebca | ||
|
|
e548138b9f | ||
|
|
2a5a2693ce | ||
|
|
efee89dcc1 | ||
|
|
74894b519f | ||
|
|
1a08a88b9e | ||
|
|
e3e0e62d77 | ||
|
|
235264ed1e | ||
|
|
a5aa3d550d | ||
|
|
79b5429a01 | ||
|
|
45dd94e5d5 | ||
|
|
e0d5970643 | ||
|
|
1fc11cd49f | ||
|
|
e5be488b3f | ||
|
|
77ba2e1362 | ||
|
|
89aa38ecc1 | ||
|
|
0c35577a68 | ||
|
|
cd9e244efd | ||
|
|
ae876484a4 | ||
|
|
7720bba5dc | ||
|
|
d1b1f078aa | ||
|
|
8839ed5932 | ||
|
|
c5987778b6 | ||
|
|
abe9ff5b2c | ||
|
|
e231600b88 | ||
|
|
3ccad7a564 | ||
|
|
8cf034ed29 | ||
|
|
9784092c7f | ||
|
|
ef3fe4dd52 | ||
|
|
7530fb0e23 | ||
|
|
49211719f0 | ||
|
|
430e53820a | ||
|
|
170772eb7c | ||
|
|
6f1d795c60 | ||
|
|
3d1178bd16 | ||
|
|
17f2421836 | ||
|
|
c61a5bedcf | ||
|
|
a318a15cad | ||
|
|
f430587965 | ||
|
|
de3b0c7ffc | ||
|
|
689f54cdc3 | ||
|
|
cee24e0b6c | ||
|
|
2e713bf1d0 | ||
|
|
d774901b6d | ||
|
|
7d7f3df226 | ||
|
|
07c2cd1af4 | ||
|
|
ddd28a0607 | ||
|
|
fa92df6567 | ||
|
|
76a3efe039 | ||
|
|
601ed15f20 | ||
|
|
2a3b505dff | ||
|
|
9550227672 | ||
|
|
89c0750463 | ||
|
|
0fa71362b8 | ||
|
|
d8df097e83 | ||
|
|
67c20cabc3 | ||
|
|
5867961383 | ||
|
|
649e280ce1 | ||
|
|
9d982eff1b | ||
|
|
6ac8225b19 | ||
|
|
55ed3c4ae0 | ||
|
|
5d0804639c | ||
|
|
6edb623b9c | ||
|
|
8c2a1e17d9 | ||
|
|
2a2f96d726 | ||
|
|
ec705df38b | ||
|
|
cb20fad13b | ||
|
|
969cae0343 | ||
|
|
f9652258e9 | ||
|
|
6bb891f830 | ||
|
|
4659d2c941 | ||
|
|
8644818949 | ||
|
|
de62956c40 | ||
|
|
3547aec75f | ||
|
|
21b5d775d2 | ||
|
|
0973bc538e | ||
|
|
bf2c4b87ab | ||
|
|
b03087c1c5 | ||
|
|
b814a856d0 | ||
|
|
f6b69a63e2 | ||
|
|
df499ea33c | ||
|
|
007611c429 | ||
|
|
12bf4c7bcc | ||
|
|
5b05be24ad | ||
|
|
f50e3d4e92 | ||
|
|
7177cdd51d | ||
|
|
a71f16ee37 | ||
|
|
070e31ef19 | ||
|
|
42df2b255a | ||
|
|
52027c65b3 | ||
|
|
a2f2bce3ab | ||
|
|
ebcf6fa49b | ||
|
|
c14c762bde | ||
|
|
fd50ab7deb | ||
|
|
0db7521bee | ||
|
|
3adfa2c268 | ||
|
|
e27610a199 | ||
|
|
bd43a16975 | ||
|
|
eb56126224 | ||
|
|
7945fce65d | ||
|
|
8a7ddfbb47 | ||
|
|
03163e424f | ||
|
|
d5b7023927 | ||
|
|
884aca149a | ||
|
|
1836567f97 | ||
|
|
78f71abd31 | ||
|
|
0f63497847 | ||
|
|
8a1e472fed | ||
|
|
3831b5a50a | ||
|
|
3756e1a327 | ||
|
|
c9eb866acd | ||
|
|
55530c05f9 | ||
|
|
422997be9b | ||
|
|
13ff086412 | ||
|
|
298b5ac03e | ||
|
|
e9af2efbd1 | ||
|
|
4027970975 | ||
|
|
0ca7116167 | ||
|
|
1474cf424b | ||
|
|
b763d75703 | ||
|
|
a0501d88ec | ||
|
|
f62d94ba61 | ||
|
|
e99d855284 | ||
|
|
31b78ff106 | ||
|
|
ae0c45a716 | ||
|
|
0105844410 | ||
|
|
07e8395536 | ||
|
|
6c8fc093af | ||
|
|
95a7dcc7fc | ||
|
|
c54156ca1e | ||
|
|
941a8ef661 | ||
|
|
fc79ffc956 | ||
|
|
8e86343942 | ||
|
|
bb87e65745 | ||
|
|
d1989acd5c | ||
|
|
e5bc4ad41b | ||
|
|
927bdc2f2b | ||
|
|
2ff57d8272 |
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
38
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Executable file
@@ -0,0 +1,38 @@
|
||||
name: Feature Request
|
||||
description: 'Suggest an idea for PiAlert'
|
||||
labels: ['Feature request➕']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an open or closed issue already exists for the feature you are requesting.
|
||||
options:
|
||||
- label: I have searched the existing open and closed issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe
|
||||
description: A clear and concise description of what the problem is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: true
|
||||
42
.github/ISSUE_TEMPLATE/i-have-an-issue.md
vendored
@@ -1,42 +0,0 @@
|
||||
---
|
||||
name: I have an issue
|
||||
about: Describe this issue template's purpose here.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the issue**
|
||||
|
||||
|
||||
**Paste last few lines from `pialert.log`**
|
||||
|
||||
> You can use `tail -20 /home/pi/pialert/front/log/pialert.log`
|
||||
|
||||
```
|
||||
paste_here
|
||||
```
|
||||
|
||||
**Paste your `pialert.conf` (remove personal info)**
|
||||
|
||||
```
|
||||
paste_here
|
||||
```
|
||||
|
||||
**Paste your `docker-compose.yml` and `.env` (remove personal info)**
|
||||
|
||||
`docker-compose.yml`
|
||||
|
||||
```
|
||||
paste_here
|
||||
```
|
||||
|
||||
`.env`
|
||||
|
||||
```
|
||||
paste_here
|
||||
```
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
76
.github/ISSUE_TEMPLATE/i-have-an-issue.yml
vendored
Executable file
@@ -0,0 +1,76 @@
|
||||
name: Bug Report
|
||||
description: 'When submitting an issue enable debug and have a look at the docs.'
|
||||
labels: ['bug 🐛']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an open or closed issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have searched the existing open and closed issues and I checked the docs https://github.com/jokob-sk/Pi.Alert/tree/main/docs
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: A concise description of what you're experiencing.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: |
|
||||
1. With these settings...
|
||||
2. With this config...
|
||||
3. Run '...'
|
||||
4. See error...
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: pialert.conf
|
||||
description: |
|
||||
Paste your `pialert.conf` (remove personal info)
|
||||
render: python
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: docker-compose.yml
|
||||
description: |
|
||||
Paste your `docker-compose.yml`
|
||||
render: python
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: What branch are you running?
|
||||
options:
|
||||
- Production
|
||||
- Dev
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: pialert.log
|
||||
description: |
|
||||
Logs with debug enabled (https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md) ⚠
|
||||
***Generally speaking, all bug reports should have logs provided.***
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
|
||||
You can use `tail -100 /home/pi/pialert/front/log/pialert.log` in teh container if you have troubles getting to the log files.
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Debug enabled
|
||||
description: I confirm I enabled `debug`
|
||||
options:
|
||||
- label: I have read and followed the steps in the wiki link above and provided the required debug logs and the log section covers the time when the issue occurs.
|
||||
required: true
|
||||
25
.github/workflows/docker_cache-cleaner.yml
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
name: 🤖Automation - ci-package-cleaner
|
||||
|
||||
on:
|
||||
|
||||
workflow_dispatch: # manual option
|
||||
|
||||
schedule:
|
||||
- cron: '15 22 * * 1' # every Monday 10.15pm UTC (~11.15am Tuesday NZT)
|
||||
|
||||
jobs:
|
||||
|
||||
package-cleaner:
|
||||
name: package-cleaner
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
packages: write
|
||||
steps:
|
||||
|
||||
- uses: actions/delete-package-versions@v4
|
||||
with:
|
||||
package-name: pi.alert
|
||||
package-type: container
|
||||
min-versions-to-keep: 0
|
||||
delete-only-untagged-versions: true
|
||||
41
.github/workflows/docker_dev.yml
vendored
@@ -14,21 +14,34 @@ on:
|
||||
jobs:
|
||||
docker_dev:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.head_commit.message, 'PUSHPROD') != 'True'
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
if: >
|
||||
contains(github.event.head_commit.message, 'PUSHPROD') != 'True' &&
|
||||
github.repository == 'jokob-sk/Pi.Alert'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up dynamic build ARGs
|
||||
id: getargs
|
||||
id: getargs
|
||||
run: echo "version=$(cat ./stable/VERSION)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get release version
|
||||
id: get_version
|
||||
run: echo "::set-output name=version::${{ 'Dev' }}"
|
||||
|
||||
- name: Create .VERSION file
|
||||
run: echo "${{ steps.get_version.outputs.version }}" >> .VERSION
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
@@ -47,18 +60,32 @@ jobs:
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
|
||||
- name: Log in to Github Container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: jokob-sk
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
# # Disable this after use
|
||||
# - name: Prune Docker Builder
|
||||
# run: docker builder prune --force
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
# # ⚠ disable cache if build is failing to download debian packages
|
||||
# cache-from: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache
|
||||
# cache-to: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache,mode=max
|
||||
|
||||
30
.github/workflows/docker_prod.yml
vendored
@@ -17,20 +17,31 @@ on:
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up dynamic build ARGs
|
||||
id: getargs
|
||||
run: echo "version=$(cat ./stable/VERSION)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get release version
|
||||
id: get_version
|
||||
run: echo "::set-output name=version::${GITHUB_REF#refs/tags/}"
|
||||
|
||||
- name: Create .VERSION file
|
||||
run: echo "${{ steps.get_version.outputs.version }}" >> .VERSION
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
@@ -46,9 +57,17 @@ jobs:
|
||||
type=ref,event=branch,suffix=-{{ sha }}
|
||||
type=ref,event=pr
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') }}
|
||||
|
||||
- name: Log in to Github Container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: jokob-sk
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
@@ -57,7 +76,10 @@ jobs:
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
# # ⚠ disable cache if build is failing to download debian packages
|
||||
# cache-from: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache
|
||||
# cache-to: type=registry,ref=ghcr.io/jokob-sk/pi.alert:buildcache,mode=max
|
||||
|
||||
29
.github/workflows/update_sponsors_table.yml
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
name: 🤖Automation - Update Sponsors Table
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '50 11 * * *' # Set your preferred schedule (UTC)
|
||||
|
||||
jobs:
|
||||
update-table:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r update_sponsors_requirements.txt # If you have any Python dependencies
|
||||
|
||||
- name: Update Sponsors Table
|
||||
run: |
|
||||
python update_sponsors.py
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
14
.gitignore
vendored
@@ -1,8 +1,20 @@
|
||||
.vscode
|
||||
.DS_Store
|
||||
config/*
|
||||
config/pialert.conf
|
||||
db/*
|
||||
db/pialert.db
|
||||
front/log/*
|
||||
front/plugins/**/*.log
|
||||
front/api/*
|
||||
**/plugins/**/*.log
|
||||
**/%40eaDir/
|
||||
**/@eaDir/
|
||||
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
**/last_result.log
|
||||
**/script.log
|
||||
**/pialert.conf_bak
|
||||
**/pialert.db_bak
|
||||
@@ -6,7 +6,7 @@ The issue tracker is the preferred channel for bug reports, features requests an
|
||||
|
||||
Before submitting a new issue please spend a couple of minutes on research:
|
||||
|
||||
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/tree/main/dockerfiles#-common-issues)
|
||||
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md#common-issues)
|
||||
* Check [💡 Closed issues](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
|
||||
|
||||
## Pull-requests (PRs)
|
||||
|
||||
50
Dockerfile
@@ -1,20 +1,15 @@
|
||||
FROM debian:bullseye-slim
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
# default UID and GID
|
||||
ENV USER=pi USER_ID=1000 USER_GID=1000 TZ=Europe/London PORT=20211
|
||||
ENV USER=pi USER_ID=1000 USER_GID=1000 PORT=20211
|
||||
#TZ=Europe/London
|
||||
|
||||
# Todo, figure out why using a workdir instead of full paths don't work
|
||||
# Todo, do we still need all these packages? I can already see sudo which isn't needed
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools python3 iproute2 nmap python3-pip zip -y \
|
||||
&& pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi \
|
||||
&& update-alternatives --install /usr/bin/python python /usr/bin/python3 10 \
|
||||
&& apt-get clean autoclean \
|
||||
&& apt-get autoremove \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& rm -rf /var/www/html \
|
||||
&& ln -s /home/pi/pialert/front /var/www/html
|
||||
RUN apt-get update
|
||||
RUN apt-get install sudo -y
|
||||
|
||||
|
||||
# create pi user and group
|
||||
# add root and www-data to pi group so they can r/w files and db
|
||||
@@ -30,19 +25,26 @@ RUN groupadd --gid "${USER_GID}" "${USER}" && \
|
||||
|
||||
COPY --chmod=775 --chown=${USER_ID}:${USER_GID} . /home/pi/pialert/
|
||||
|
||||
# Pi.Alert
|
||||
RUN rm /etc/nginx/sites-available/default \
|
||||
&& ln -s /home/pi/pialert/install/default /etc/nginx/sites-available/default \
|
||||
&& sed -ie 's/listen 80/listen '${PORT}'/g' /etc/nginx/sites-available/default \
|
||||
# run the hardware vendors update
|
||||
&& /home/pi/pialert/back/update_vendors.sh \
|
||||
# Create a backup of the pialert.conf to be used if the user didn't supply a configuration file
|
||||
&& cp /home/pi/pialert/config/pialert.conf /home/pi/pialert/back/pialert.conf_bak \
|
||||
# Create a backup of the pialert.db to be used if the user didn't supply a database
|
||||
&& cp /home/pi/pialert/db/pialert.db /home/pi/pialert/back/pialert.db_bak \
|
||||
# Create a buildtimestamp.txt to later check if a new version was released
|
||||
&& date +%s > /home/pi/pialert/front/buildtimestamp.txt
|
||||
|
||||
ENTRYPOINT ["tini", "--"]
|
||||
# ❗ IMPORTANT - if you modify this file modify the /install/install_dependecies.sh file as well ❗
|
||||
|
||||
RUN apt-get install -y \
|
||||
tini snmp ca-certificates curl libwww-perl arp-scan perl apt-utils cron sudo \
|
||||
nginx-light php php-cgi php-fpm php-sqlite3 php-curl sqlite3 dnsutils net-tools \
|
||||
python3 iproute2 nmap python3-pip zip systemctl usbutils traceroute
|
||||
|
||||
# Alternate dependencies
|
||||
RUN apt-get install nginx nginx-core mtr php-fpm php8.2-fpm php-cli php8.2 php8.2-sqlite3 -y
|
||||
RUN phpenmod -v 8.2 sqlite3
|
||||
|
||||
# Setup virtual python environment and use pip3 to install packages
|
||||
RUN apt-get install -y python3-venv
|
||||
RUN python3 -m venv myenv
|
||||
RUN /bin/bash -c "source myenv/bin/activate && update-alternatives --install /usr/bin/python python /usr/bin/python3 10 && pip3 install requests paho-mqtt scapy cron-converter pytz json2table dhcp-leases pyunifi speedtest-cli chardet"
|
||||
|
||||
# Create a buildtimestamp.txt to later check if a new version was released
|
||||
RUN date +%s > /home/pi/pialert/front/buildtimestamp.txt
|
||||
|
||||
CMD ["/home/pi/pialert/dockerfiles/start.sh"]
|
||||
|
||||
|
||||
|
||||
191
README.md
@@ -1,101 +1,136 @@
|
||||
# Pi.Alert
|
||||
<!--- --------------------------------------------------------------------- --->
|
||||
# 💻🔍 Network security scanner & notification framework
|
||||
|
||||
💻🔍 WIFI / LAN intruder detector.
|
||||
Get visibility of what's going on on your WIFI/LAN network. Scan for devices, port changes and get alerts if unknown devices or changes are found. Write your own [Plugins](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) with auto-generated UI and in-build notification system.
|
||||
|
||||
Scans for devices connected to your WIFI / LAN and alerts you if new and unknown devices are found.
|
||||
|
||||
![Main screen][main]
|
||||
|
||||
# 🐳 Docker image
|
||||
[](https://github.com/jokob-sk/Pi.Alert/actions/workflows/docker_prod.yml)
|
||||
[](https://github.com/jokob-sk/Pi.Alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||

|
||||
[](https://github.com/sponsors/jokob-sk)
|
||||
|
||||
🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📄 [Dockerfile](https://github.com/jokob-sk/Pi.Alert/blob/main/Dockerfile) | 📚 [Docker instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) | 🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases)
|
||||
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Docker guide](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [All Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs) |
|
||||
|----------------------|----------------------| ----------------------| ----------------------|
|
||||
|
||||
## 🔍 Scan Methods
|
||||
The system continuously scans the network for, **New devices**, **New connections** (re-connections), **Disconnections**, **"Always Connected" devices down**, Devices **IP changes** and **Internet IP address changes**. Scanning methods are:
|
||||
- **Method 1: arp-scan**. The arp-scan system utility is used to search
|
||||
for devices on the network using arp frames.
|
||||
- **Method 2: Pi-hole**. This method is optional and complementary to
|
||||
method 1. If the Pi-hole DNS server is active, Pi.Alert examines its
|
||||
activity looking for active devices using DNS that have not been
|
||||
detected by method 1.
|
||||
- **Method 3. dnsmasq**. This method is optional and complementary to the
|
||||
previous methods. If the DHCP server dnsmasq is active, Pi.Alert
|
||||
examines the DHCP leases (addresses assigned) to find active devices
|
||||
that were not discovered by the other methods.
|
||||
|
||||
## 🧩 Integrations
|
||||
- [Apprise](https://hub.docker.com/r/caronc/apprise), [Pushsafer](https://www.pushsafer.com/), [NTFY](https://ntfy.sh/)
|
||||
- [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md) ([sample JSON](docs/webhook_json_sample.json))
|
||||
- Home Assistant via [MQTT](https://www.home-assistant.io/integrations/mqtt/) - discovery ~10s per device, use [MQTT Explorer](https://mqtt-explorer.com/) to delete devices
|
||||
- [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md)
|
||||
- [Plugin system](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins) for custom script monitoring
|
||||
| ![Main screen][main] | ![Screen 1][screen1] | ![Screen 5][screen5] |
|
||||
|----------------------|----------------------| ----------------------|
|
||||
|
||||
# 📥 Installation
|
||||
<details>
|
||||
<summary>📷 Click for more screenshots</summary>
|
||||
|
||||
| ![Screen 3][screen3] | ![Screen 4][screen4] | ![Screen 6][screen6] |
|
||||
|----------------------|----------------------|----------------------|
|
||||
| ![Screen 8][screen8] | ![Report 2][report2] | ![Screen 9][screen9] |
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>❓ Why use PiAlert?</summary>
|
||||
|
||||
<hr>
|
||||
|
||||
Most of us don't know what's going on on our home network, but we want our family and data to be safe. _Command-line tools_ are great, but the output can be _hard to understand_ and action if you are not a network specialist.
|
||||
|
||||
PiAlert gives you peace of mind. _Visualize and immediately report 📬_ what is going on in your network - this is the first step to enhance your _network security 🔐_.
|
||||
|
||||
PiAlert combines several network and other scanning tools 🔍 with notifications 📧 into one user-friendly package 📦.
|
||||
|
||||
Setup a _kill switch ☠_ for your network via a smart plug with the available [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md) integration. Implement custom automations with the [CSV device Exports 📤](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins/csv_backup), [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md), or [API endpoints](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) features.
|
||||
|
||||
Extend the app if you want to create your own scanner [Plugin](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) and handle the results and notifications in PiAlert.
|
||||
|
||||
Looking forward to your contributions if you decide to share your work with the community ❤.
|
||||
|
||||
</details>
|
||||
|
||||
## Scan Methods, Notifications, Integration, Extension system
|
||||
|
||||
| Features | Details |
|
||||
|-------------|-------------|
|
||||
| 🔍 | The app scans your network for, **New devices**, **New connections** (re-connections), **Disconnections**, **"Always Connected" devices down**, Devices **IP changes** and **Internet IP address changes**. Discovery & scan methods include: **arp-scan**. **Pi-hole - DB import**, **Pi-hole - DHCP leases import**, **Generic DHCP leases import**. **UNIFI controller import**, **SNMP-enabled router import**. Check the [Plugins](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) docs for more info on individual scans. |
|
||||
|📧 | Send notifications to more than 80+ services, including Telegram via [Apprise](https://hub.docker.com/r/caronc/apprise), or use [Pushsafer](https://www.pushsafer.com/), [Pushover](https://www.pushover.net/), or [NTFY](https://ntfy.sh/). |
|
||||
|🧩 | Feed your data and device changes into [Home Assistant](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HOME_ASSISTANT.md), read [API endpoints](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md), or use [Webhooks](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md) to setup custom automation flows. |
|
||||
|➕ | Build your own scanners with the [Plugin system](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins#readme) |
|
||||
|
||||
|
||||
## Installation & Documentation
|
||||
<!--- --------------------------------------------------------------------- --->
|
||||
|
||||
⚠ Only tested as a [docker container - follow these instructions here](dockerfiles/README.md).
|
||||
> Check out [leiweibau's fork](https://github.com/leiweibau/Pi.Alert/) if you want to install Pi.Alert on the server directly or original instructions for [pucherot's original code](https://github.com/pucherot/Pi.Alert/)
|
||||
|
||||
# 📑 Features
|
||||
- Display:
|
||||
- Sessions, Connected devices, Favorites, Events, Presence, Concurrent devices, Down alerts, IP's
|
||||
- Manual Nmap scans, Optional speedtest for Device "Internet"
|
||||
- Simple Network relationship display
|
||||
- Maintenance tasks and Settings like:
|
||||
- Theme Selection (blue, red, green, yellow, black, purple) and Light/Dark-Mode Switch
|
||||
- DB maintenance, Backup, Restore tools and CSV Export / Import
|
||||
- Simple login Support
|
||||
- 🌟(Experimental) [Plugin system](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins)
|
||||
- Create custom plugins with automatically generated settings and UI.
|
||||
- Monitor anything for changes
|
||||
- Check the [instructions](https://github.com/jokob-sk/Pi.Alert/tree/main/front/plugins) carefully if you are up for a challenge! Current plugins include:
|
||||
- Detecting Rogue DHCP servers via NMAP
|
||||
- Monitoring HTTP status changes of domains/URLs
|
||||
- Import devices from DHCP.leases files, a UniFi controller, or an SNMP enabled router
|
||||
|
||||
| ![Screen 1][screen1] | ![Screen 2][screen2] | ![Screen 5][screen5] |
|
||||
|----------------------|----------------------| ----------------------|
|
||||
| ![Screen 3][screen3] | ![Screen 4][screen4] | ![Screen 6][screen6] |
|
||||
| ![Screen 8][screen8] | ![Report 2][report2] | ![Screen 9][screen9] |
|
||||
| Docs | Link |
|
||||
|-------------|-------------|
|
||||
| 📥🐳 | [Docker instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md)
|
||||
| 📥💻 | [HW install (experimental 🧪)](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HW_INSTALL.md) |
|
||||
| 📚 | [All Documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/README.md) (App Usage and Configuration) |
|
||||
|
||||
> Other Alternatives
|
||||
>
|
||||
> - Check out [leiweibau's on HW installed fork](https://github.com/leiweibau/Pi.Alert/) (maintained)
|
||||
> - Check instructions for [pucherot's original code](https://github.com/pucherot/Pi.Alert/) (unmaintained)
|
||||
> - [WatchYourLAN](https://github.com/aceberg/WatchYourLAN) - Lightweight network IP scanner with web GUI (Open source)
|
||||
> - [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware)
|
||||
|
||||
### 🔗 Other Alternatives
|
||||
## ❤ Support me for...
|
||||
|
||||
- [WatchYourLAN](https://github.com/aceberg/WatchYourLAN) - Lightweight network IP scanner with web GUI (Open source)
|
||||
- [Fing](https://www.fing.com/) - Network scanner app for your Internet security (Commercial, Phone App, Proprietary hardware)
|
||||
- I don't get burned out and the app survives longer🔥🤯
|
||||
- Regular updates to keep your data and family safe 🔄
|
||||
- Better and more functionality➕
|
||||
- Quicker and better support with issues 🆘
|
||||
- Less grumpy me 😄
|
||||
|
||||
### 📚 Documentation
|
||||
| [](https://github.com/sponsors/jokob-sk) | [](https://www.buymeacoffee.com/jokobsk) | [](https://www.patreon.com/user?u=84385063) |
|
||||
| --- | --- | --- |
|
||||
|
||||
- Initial Docker Setup: [Docker instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md)
|
||||
- App Usage and Configuration: [All Documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/README.md)
|
||||
<details>
|
||||
<summary>Click for more ways to donate</summary>
|
||||
|
||||
<hr>
|
||||
|
||||
- Bitcoin: `1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM`
|
||||
- Ethereum: `0x6e2749Cb42F4411bc98501406BdcD82244e3f9C7`
|
||||
|
||||
📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=PiAlert) if you want to get in touch or if I should add other sponsorship platforms.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
||||
### ⭐ Sponsors
|
||||
|
||||
[](https://github.com/sponsors/jokob-sk)
|
||||
|
||||
Thank you to all the wonderful people who are sponsoring this project (=preventing my burnout🔥🤯):
|
||||
|
||||
<!-- SPONSORS-LIST DO NOT MODIFY BELOW -->
|
||||
| All Sponsors |
|
||||
|---|
|
||||
| [dtech77pl](https://github.com/dtech77pl) |
|
||||
| [Tony Hanratty](https://github.com/thanratty) |
|
||||
|
||||
<!-- SPONSORS-LIST DO NOT MODIFY ABOVE -->
|
||||
|
||||
## Everything else
|
||||
<!--- --------------------------------------------------------------------- --->
|
||||
|
||||
### 🌍 Translations
|
||||
|
||||
Proudly using [Weblate](https://hosted.weblate.org/projects/pialert/).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/pialert/">
|
||||
<img src="https://hosted.weblate.org/widget/pialert/core/multi-auto.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
Help out and suggest languages in the [online portal of Weblate](https://hosted.weblate.org/projects/pialert/core/).
|
||||
|
||||
### License
|
||||
GPL 3.0 | [Read more here](LICENSE.txt) | Source of the [animated GIF (Loading Animation)](https://commons.wikimedia.org/wiki/File:Loading_Animation.gif) | Source of the [selfhosted Fonts](https://github.com/adobe-fonts/source-sans)
|
||||
> GPL 3.0 | [Read more here](LICENSE.txt) | Source of the [animated GIF (Loading Animation)](https://commons.wikimedia.org/wiki/File:Loading_Animation.gif) | Source of the [selfhosted Fonts](https://github.com/adobe-fonts/source-sans)
|
||||
|
||||
### 🥇 Special thanks
|
||||
### Special thanks
|
||||
|
||||
This code is a collaborative body of work, with special thanks to:
|
||||
This code is a collaborative body of work, with special thanks to:
|
||||
|
||||
- 🏆 [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert) is the original creator od PiAlert
|
||||
- [leiweibau](https://github.com/leiweibau/Pi.Alert): Dark mode (and much more)
|
||||
- [Macleykun](https://github.com/Macleykun): Help with Dockerfile clean-up
|
||||
- [Final-Hawk](https://github.com/Final-Hawk): Help with NTFY, styling and other fixes
|
||||
- [TeroRERO](https://github.com/terorero): Spanish translation
|
||||
- Please see the [Git contributors](https://github.com/jokob-sk/Pi.Alert/graphs/contributors) for a full list of people and their contributions to the project
|
||||
|
||||
## ☕ Support me
|
||||
|
||||
<a href="https://github.com/sponsors/jokob-sk" target="_blank"><img src="https://i.imgur.com/X6p5ACK.png" alt="Sponsor Me on GitHub" style="height: 30px !important;width: 117px !important;" width="150px" ></a>
|
||||
<a href="https://www.buymeacoffee.com/jokobsk" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 117px !important;" width="117px" height="30px" ></a>
|
||||
<a href="https://www.patreon.com/user?u=84385063" target="_blank"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Patreon_logo_with_wordmark.svg/512px-Patreon_logo_with_wordmark.svg.png" alt="Support me on patreon" style="height: 30px !important;width: 117px !important;" width="117px" ></a>
|
||||
|
||||
BTC: 1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM
|
||||
> [pucherot/Pi.Alert](https://github.com/pucherot/Pi.Alert) (the original creator of PiAlert), [leiweibau](https://github.com/leiweibau/Pi.Alert): Dark mode (and much more), [Macleykun](https://github.com/Macleykun) (Help with Dockerfile clean-up) [Final-Hawk](https://github.com/Final-Hawk) (Help with NTFY, styling and other fixes), [TeroRERO](https://github.com/terorero) (Spanish translations), [Data-Monkey](https://github.com/Data-Monkey), (Split-up of the python.py file and more), [cvc90](https://github.com/cvc90) (Spanish translation and various UI work) to name a few...
|
||||
>
|
||||
> Please see the [Git contributors](https://github.com/jokob-sk/Pi.Alert/graphs/contributors) for a full list of people and their contributions to the project
|
||||
|
||||
<!--- --------------------------------------------------------------------- --->
|
||||
[main]: ./docs/img/devices_split.png "Main screen"
|
||||
@@ -106,7 +141,7 @@ BTC: 1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM
|
||||
[screen5]: ./docs/img/network.png "Screen 5"
|
||||
[screen6]: ./docs/img/settings.png "Screen 6"
|
||||
[screen7]: ./docs/img/help_faq.png "Screen 7"
|
||||
[screen8]: ./docs/img/plugins_webmon.png "Screen 8"
|
||||
[screen8]: ./docs/img/plugins_rogue_dhcp.png "Screen 8"
|
||||
[screen9]: ./docs/img/device_nmap.png "Screen 9"
|
||||
[report1]: ./docs/img/4_report_1.jpg "Report sample 1"
|
||||
[report2]: ./docs/img/4_report_2.jpg "Report sample 2"
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
#
|
||||
# Scan multiple interfaces (eth1 and eth0):
|
||||
# SCAN_SUBNETS = [ '192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0' ]
|
||||
|
||||
SCAN_SUBNETS=['192.168.1.0/24 --interface=eth1']
|
||||
PRINT_LOG=False
|
||||
|
||||
TIMEZONE='Europe/Berlin'
|
||||
PIALERT_WEB_PROTECTION=False
|
||||
PIALERT_WEB_PASSWORD='8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
|
||||
INCLUDED_SECTIONS=['internet','new_devices','down_devices','events']
|
||||
SCAN_CYCLE_MINUTES=5
|
||||
DAYS_TO_KEEP_EVENTS=90
|
||||
# Used for generating links in emails. Make sure not to add a trailing slash!
|
||||
REPORT_DASHBOARD_URL='http://pi.alert'
|
||||
@@ -93,25 +92,6 @@ DDNS_PASSWORD='A0000000B0000000C0000000D0000000'
|
||||
DDNS_UPDATE_URL='https://api.dynu.com/nic/update?'
|
||||
|
||||
|
||||
# PiHole
|
||||
#---------------------------
|
||||
# if enabled you need to map '/etc/pihole/pihole-FTL.db' in docker-compose.yml
|
||||
PIHOLE_ACTIVE=False
|
||||
# if enabled you need to map '/etc/pihole/dhcp.leases' in docker-compose.yml
|
||||
DHCP_ACTIVE=False
|
||||
|
||||
|
||||
# Pholus
|
||||
#---------------------------
|
||||
PHOLUS_ACTIVE=False
|
||||
PHOLUS_TIMEOUT=120
|
||||
PHOLUS_FORCE=False
|
||||
PHOLUS_DAYS_DATA=7
|
||||
PHOLUS_RUN='once'
|
||||
PHOLUS_RUN_TIMEOUT=600
|
||||
PHOLUS_RUN_SCHD='0 4 * * *'
|
||||
|
||||
|
||||
#-------------------IMPORTANT INFO-------------------#
|
||||
# This file is ingested by a python script, so if #
|
||||
# modified it needs to use python syntax #
|
||||
4354
back/pialert.py
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# repot_template.html - Back module. Template to email reporting in HTML format
|
||||
#-------------------------------------------------------------------------------
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3
|
||||
# Puche 2021 GNU GPLv3
|
||||
#--------------------------------------------------------------------------- -->
|
||||
<html>
|
||||
<head></head>
|
||||
@@ -12,7 +12,7 @@
|
||||
<font face=sans-serif>
|
||||
<table align=center width=100% cellpadding=0 cellspacing=0 style="border-radius: 5px;">
|
||||
<tr>
|
||||
<td bgcolor=#EFB956 align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#000000; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
|
||||
<td bgcolor=#3c8dbc align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#ffffff; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
|
||||
Pi.Alert Report
|
||||
</td>
|
||||
</tr>
|
||||
@@ -23,7 +23,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table width=100% border=0 bgcolor=#FFD966 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#404040">
|
||||
<table width=100% border=0 bgcolor=#00c0ef cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#404040">
|
||||
<tr>
|
||||
<td width=100%> Report Date: <b>2023-01-30 22:17</b> </td>
|
||||
</tr>
|
||||
@@ -46,6 +46,7 @@
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Event Type</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device name</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Comments</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device Vendor</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://192.168.1.1:20211/deviceDetails.php?mac=00:00:00:ef:a5:6c">00:00:00:ef:a5:6c</a></td>
|
||||
@@ -54,6 +55,7 @@
|
||||
<td>New Device</td>
|
||||
<td>(name not found)</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://192.168.1.1:20211/deviceDetails.php?mac=00:00:00:ef:a5:6c">00:00:00:ef:a5:6c</a></td>
|
||||
@@ -62,6 +64,7 @@
|
||||
<td>New Device</td>
|
||||
<td>(name not found)</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
@@ -83,6 +86,7 @@
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Event Type</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device name</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Comments</th>
|
||||
<th width='120px' style='color:#F0F0F0' bgcolor='#909090' >Device Vendor</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="http://192.168.1.1:20211/deviceDetails.php?mac=00:00:00:ef:a5:6c">00:00:00:ef:a5:6c</a></td>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<!-- ---------------------------------------------------------------------------
|
||||
# Pi.Alert
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
#
|
||||
# repot_template.html - Back module. Template to email reporting in HTML format
|
||||
#-------------------------------------------------------------------------------
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3
|
||||
#--------------------------------------------------------------------------- -->
|
||||
<!--
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# report_template.html - Back module. Template to email reporting in HTML format #
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
#---------------------------------------------------------------------------------#
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
@@ -16,37 +21,45 @@
|
||||
<font face=sans-serif>
|
||||
<table align=center width=100% cellpadding=0 cellspacing=0 style="border-radius: 5px;">
|
||||
<tr>
|
||||
<td bgcolor=#EFB956 align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#000000; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
|
||||
<td bgcolor=#3c8dbc align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#ffffff; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
|
||||
Pi.Alert Report
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<table width=100% border=0 bgcolor=#FFD966 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#404040"> <tr>
|
||||
<td width=100%> Report Date: <b><REPORT_DATE></b> </td>
|
||||
<table width=100% border=0 bgcolor=#4b99d3 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#ffffff"> <tr>
|
||||
<td width=100% bgcolor="#3c8dbc"> Report Date: <b><REPORT_DATE></b> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td bgcolor=#F5F5F5 height=200 valign=top style="padding: 10px">
|
||||
<td height=200 valign=top style="padding: 10px">
|
||||
|
||||
<INTERNET_TABLE>
|
||||
|
||||
<NEW_DEVICES_TABLE>
|
||||
<DOWN_DEVICES_TABLE>
|
||||
<EVENTS_TABLE>
|
||||
<PORTS_TABLE>
|
||||
<EVENTS_TABLE>
|
||||
<PLUGINS_TABLE>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<table width=100% bgcolor=#46802e cellpadding=5px cellspacing=0 style="font-size: 13px; font-weight: bold; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;">
|
||||
<table width=100% bgcolor=#3c8dbc cellpadding=5px cellspacing=0 style="font-size: 13px; font-weight: bold; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;">
|
||||
<tr>
|
||||
<td width=50% style="text-align:center"> Pi.Alert - <SERVER_NAME></td>
|
||||
<td width=50% style="text-align:center;color: white;" bgcolor="#3c8dbc">
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert" target="_blank" style="color: white">Pi.Alert</a>
|
||||
<a href=".." target="_blank" style="color: white"> (<SERVER_NAME>)</a>
|
||||
<br><span style="display:inline-block;color: white; transform: rotate(180deg)">©</span>2020 Puche (2022+
|
||||
<a style="color: white" href="mailto:jokob@duck.com?subject=PiAlert">jokob-sk</a>) | <b>Built on: <BUILD_PIALERT> </b> | <b> Version: <VERSION_PIALERT> </b> |
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/docs" target="_blank" style="color: white">
|
||||
<span>Docs <i class="fa fa-circle-question"></i>
|
||||
</a><span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
@@ -54,4 +67,4 @@
|
||||
</table>
|
||||
</font>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
Report Date: <REPORT_DATE>
|
||||
Server: <SERVER_NAME>
|
||||
|
||||
<SECTION_NEW_DEVICES>
|
||||
<SECTION_DEVICES_DOWN>
|
||||
<SECTION_EVENTS>
|
||||
<SECTION_INTERNET>
|
||||
<PORTS_TABLE>
|
||||
<NEW_DEVICES_TABLE>
|
||||
<DOWN_DEVICES_TABLE>
|
||||
<EVENTS_TABLE>
|
||||
<PLUGINS_TABLE>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<!-- ---------------------------------------------------------------------------
|
||||
# Pi.Alert
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
#
|
||||
# repot_template.html - Back module. Template to email reporting in HTML format
|
||||
#-------------------------------------------------------------------------------
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3
|
||||
#--------------------------------------------------------------------------- -->
|
||||
<!--
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# report_template_new_version - Back module. Template to email reporting in text #
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
#---------------------------------------------------------------------------------#
|
||||
-->
|
||||
|
||||
<html>
|
||||
|
||||
@@ -16,7 +21,7 @@
|
||||
<font face=sans-serif>
|
||||
<table align=center width=100% cellpadding=0 cellspacing=0 style="border-radius: 5px;">
|
||||
<tr>
|
||||
<td bgcolor=#EFB956 align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#000000; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
|
||||
<td bgcolor=#3c8dbc align=center style="padding: 20px 10px 10px 10px; font-size: 30px; font-weight: bold; color:#ffffff; border-top-right-radius: 5px; border-top-left-radius: 5px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2)">
|
||||
Pi.Alert Report
|
||||
</td>
|
||||
</tr>
|
||||
@@ -25,37 +30,45 @@
|
||||
<a style="color:#ffffff;cursor:pointer;" href="https://github.com/jokob-sk/Pi.Alert/releases">🆕 New version available 🆕</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<table width=100% border=0 bgcolor=#FFD966 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#404040"> <tr>
|
||||
<td width=100%> Report Date: <b><REPORT_DATE></b> </td>
|
||||
<table width=100% border=0 bgcolor=#4b99d3 cellpadding=5px cellspacing=0 style="border-collapse: collapse; font-size: 15px; text-align:center; color:#ffffff"> <tr>
|
||||
<td width=100% bgcolor="#3c8dbc"> Report Date: <b><REPORT_DATE></b> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td bgcolor=#F5F5F5 height=200 valign=top style="padding: 10px">
|
||||
|
||||
<INTERNET_TABLE>
|
||||
<NEW_DEVICES_TABLE>
|
||||
<DOWN_DEVICES_TABLE>
|
||||
<EVENTS_TABLE>
|
||||
<PORTS_TABLE>
|
||||
<PLUGINS_TABLE>
|
||||
<td height=200 valign=top style="padding: 10px">
|
||||
|
||||
<NEW_DEVICES_TABLE>
|
||||
<DOWN_DEVICES_TABLE>
|
||||
<EVENTS_TABLE>
|
||||
<PLUGINS_TABLE>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<table width=100% bgcolor=#46802e cellpadding=5px cellspacing=0 style="font-size: 13px; font-weight: bold; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;">
|
||||
<table width=100% bgcolor=#3c8dbc cellpadding=5px cellspacing=0 style="font-size: 13px; font-weight: bold; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px;">
|
||||
<tr>
|
||||
<td width=50% style="text-align:center"> Pi.Alert - <SERVER_NAME></td>
|
||||
<td width=50% style="text-align:center;color: white;" bgcolor="#3c8dbc">
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert" target="_blank" style="color: white">Pi.Alert</a>
|
||||
<a href=".." target="_blank" style="color: white"> (<SERVER_NAME>)</a>
|
||||
<br><span style="display:inline-block;color: white; transform: rotate(180deg)">©</span>2020 Puche (2022+
|
||||
<a style="color: white" href="mailto:jokob@duck.com?subject=PiAlert">jokob-sk</a>) | <b>Built on: <BUILD_PIALERT> </b> | <b> Version: <VERSION_PIALERT> </b> |
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/docs" target="_blank" style="color: white">
|
||||
<span>Docs <i class="fa fa-circle-question"></i>
|
||||
</a><span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</font>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Pi.Alert
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
@@ -14,22 +15,21 @@
|
||||
# /usr/share/ieee-data
|
||||
# /var/lib/ieee-data
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run update_vendors.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
echo Updating... /usr/share/ieee-data/
|
||||
cd /usr/share/ieee-data/
|
||||
cd /usr/share/ieee-data/ || { echo "could not enter /usr/share/ieee-data directory"; exit 1; }
|
||||
|
||||
sudo mkdir -p 2_backup
|
||||
sudo cp *.txt 2_backup
|
||||
sudo cp *.csv 2_backup
|
||||
sudo cp -- *.txt 2_backup
|
||||
sudo cp -- *.csv 2_backup
|
||||
echo ""
|
||||
echo Download Start
|
||||
echo ""
|
||||
sudo curl $1 -LO https://standards-oui.ieee.org/iab/iab.csv \
|
||||
-LO https://standards-oui.ieee.org/iab/iab.txt \
|
||||
-LO https://standards-oui.ieee.org/oui28/mam.csv \
|
||||
-LO https://standards-oui.ieee.org/iab/iab.txt \
|
||||
sudo curl "$1" -LO https://standards-oui.ieee.org/oui28/mam.csv \
|
||||
-LO https://standards-oui.ieee.org/oui28/mam.csv \
|
||||
-LO https://standards-oui.ieee.org/oui28/mam.txt \
|
||||
-LO https://standards-oui.ieee.org/oui36/oui36.csv \
|
||||
@@ -42,15 +42,18 @@ echo Download Finished
|
||||
# ----------------------------------------------------------------------
|
||||
echo ""
|
||||
echo Updating... /usr/share/arp-scan/
|
||||
cd /usr/share/arp-scan
|
||||
cd /usr/share/arp-scan || { echo "could not enter /usr/share/arp-scan directory"; exit 1; }
|
||||
|
||||
sudo mkdir -p 2_backup
|
||||
sudo cp *.txt 2_backup
|
||||
sudo cp -- *.txt 2_backup
|
||||
|
||||
# Update from /usb/lib/ieee-data
|
||||
sudo get-iab -v
|
||||
sudo get-oui -v
|
||||
|
||||
# make files readable
|
||||
sudo chmod +r /usr/share/arp-scan/ieee-oui.txt
|
||||
|
||||
# Update from ieee website
|
||||
# sudo get-iab -v -u http://standards-oui.ieee.org/iab/iab.txt
|
||||
# sudo get-oui -v -u http://standards-oui.ieee.org/oui/oui.txt
|
||||
|
||||
@@ -1,87 +1,122 @@
|
||||
[
|
||||
{
|
||||
"headers": {
|
||||
"host": "192.168.1.82:5678",
|
||||
"user-agent": "curl/7.74.0",
|
||||
"accept": "*/*",
|
||||
"content-type": "application/json",
|
||||
"content-length": "872"
|
||||
},
|
||||
"params": {},
|
||||
"query": {},
|
||||
"body": {
|
||||
"username": "Pi.Alert",
|
||||
"text": "There are new notifications",
|
||||
"attachments": [
|
||||
{
|
||||
"title": "Pi.Alert Notifications",
|
||||
"title_link": "",
|
||||
"text": {
|
||||
"internet": [],
|
||||
"new_devices": [{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.1",
|
||||
"Event Type": "New Device",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null
|
||||
}],
|
||||
"down_devices": [],
|
||||
"events": [{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.92",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null
|
||||
}, {
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.150",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null
|
||||
}],
|
||||
"ports": [{
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "22/tcp",
|
||||
"State": "open",
|
||||
"Service": "ssh",
|
||||
"Extra": ""
|
||||
}
|
||||
}, {
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "53/tcp",
|
||||
"State": "open",
|
||||
"Service": "domain",
|
||||
"Extra": ""
|
||||
}
|
||||
}, {
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "80/tcp",
|
||||
"State": "open",
|
||||
"Service": "http",
|
||||
"Extra": ""
|
||||
}
|
||||
}, {
|
||||
"new": {
|
||||
"Name": "New device",
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Port": "443/tcp",
|
||||
"State": "open",
|
||||
"Service": "https",
|
||||
"Extra": ""
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
{
|
||||
"headers": {
|
||||
"host": "192.168.1.82:5678",
|
||||
"user-agent": "curl/7.74.0",
|
||||
"accept": "*/*",
|
||||
"content-type": "application/json",
|
||||
"content-length": "872"
|
||||
},
|
||||
"params": {},
|
||||
"query": {},
|
||||
"body": {
|
||||
"username": "Pi.Alert",
|
||||
"text": "There are new notifications",
|
||||
"attachments": [
|
||||
{
|
||||
"title": "Pi.Alert Notifications",
|
||||
"title_link": "",
|
||||
"text": {
|
||||
"new_devices_meta": {
|
||||
"title": "New devices",
|
||||
"columnNames": [
|
||||
"MAC",
|
||||
"Datetime",
|
||||
"IP",
|
||||
"Event Type",
|
||||
"Device name",
|
||||
"Comments"
|
||||
]
|
||||
},
|
||||
"new_devices": [
|
||||
{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.1",
|
||||
"Event Type": "New Device",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null,
|
||||
"Device Vendor": null
|
||||
}
|
||||
],
|
||||
"down_devices_meta": {
|
||||
"title": "Down devices",
|
||||
"columnNames": [
|
||||
"MAC",
|
||||
"Datetime",
|
||||
"IP",
|
||||
"Event Type",
|
||||
"Device name",
|
||||
"Comments"
|
||||
]
|
||||
},
|
||||
"down_devices": [],
|
||||
"events_meta": {
|
||||
"title": "Events",
|
||||
"columnNames": [
|
||||
"MAC",
|
||||
"Datetime",
|
||||
"IP",
|
||||
"Event Type",
|
||||
"Device name",
|
||||
"Comments"
|
||||
]
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.92",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null,
|
||||
"Device Vendor": null
|
||||
},
|
||||
{
|
||||
"MAC": "74:ac:74:ac:74:ac",
|
||||
"Datetime": "2023-01-30 22:15:09",
|
||||
"IP": "192.168.1.150",
|
||||
"Event Type": "Disconnected",
|
||||
"Device name": "(name not found)",
|
||||
"Comments": null,
|
||||
"Device Vendor": null
|
||||
}
|
||||
],
|
||||
"plugins_meta": {
|
||||
"title": "Plugins",
|
||||
"columnNames": [
|
||||
"Plugin",
|
||||
"Object_PrimaryID",
|
||||
"Object_SecondaryID",
|
||||
"DateTimeChanged",
|
||||
"Watched_Value1",
|
||||
"Watched_Value2",
|
||||
"Watched_Value3",
|
||||
"Watched_Value4",
|
||||
"Status"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"Index": 138,
|
||||
"Plugin": "INTRSPD",
|
||||
"Object_PrimaryID": "Speedtest",
|
||||
"Object_SecondaryID": "2023-10-08 02:01:16+02:00",
|
||||
"DateTimeCreated": "2023-10-08 02:01:16",
|
||||
"DateTimeChanged": "2023-10-08 02:32:15",
|
||||
"Watched_Value1": "-1",
|
||||
"Watched_Value2": "-1",
|
||||
"Watched_Value3": "null",
|
||||
"Watched_Value4": "null",
|
||||
"Status": "missing-in-last-scan",
|
||||
"Extra": "null",
|
||||
"UserData": "null",
|
||||
"ForeignKey": "null"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
2
config/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
db/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -2,43 +2,62 @@ version: "3"
|
||||
services:
|
||||
pialert:
|
||||
privileged: true
|
||||
build: .
|
||||
build:
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
cache_from:
|
||||
- type=registry,ref=docker.io/jokob-sk/pi.alert:buildcache
|
||||
container_name: pialert
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
# restart: unless-stopped
|
||||
volumes:
|
||||
- ${APP_DATA_LOCATION}/pialert2/config:/home/pi/pialert/config
|
||||
# - ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db
|
||||
- ${APP_DATA_LOCATION}/pialert2/db:/home/pi/pialert/db
|
||||
- ${APP_DATA_LOCATION}/pialert_dev/config:/home/pi/pialert/config
|
||||
# - ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config
|
||||
- ${APP_DATA_LOCATION}/pialert_dev/db:/home/pi/pialert/db
|
||||
# - ${APP_DATA_LOCATION}/pialert/db:/home/pi/pialert/db
|
||||
# (optional) useful for debugging if you have issues setting up the container
|
||||
- ${LOGS_LOCATION}:/home/pi/pialert/front/log
|
||||
# ---------------------------------------------------------------------------
|
||||
# DELETE START anyone trying to use this file: comment out / delete BELOW lines, they are only for development purposes
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp1.leases:/mnt/dhcp1.leases
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp2.leases:/mnt/dhcp2.leases
|
||||
- ${DEV_LOCATION}/back/pialert.py:/home/pi/pialert/back/pialert.py
|
||||
- ${DEV_LOCATION}/back/report_template.html:/home/pi/pialert/back/report_template.html
|
||||
- ${DEV_LOCATION}/back/report_template_new_version.html:/home/pi/pialert/back/report_template_new_version.html
|
||||
- ${DEV_LOCATION}/back/report_template.txt:/home/pi/pialert/back/report_template.txt
|
||||
- ${DEV_LOCATION}/pholus:/home/pi/pialert/pholus
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/dhcp2.leases:/mnt/dhcp2.leases
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/pihole_dhcp_full.leases:/etc/pihole/dhcp.leases
|
||||
- ${APP_DATA_LOCATION}/pialert/dhcp_samples/pihole_dhcp_2.leases:/etc/pihole/dhcp2.leases
|
||||
- ${APP_DATA_LOCATION}/pihole/etc-pihole/pihole-FTL.db:/etc/pihole/pihole-FTL.db
|
||||
- ${DEV_LOCATION}/pialert:/home/pi/pialert/pialert
|
||||
- ${DEV_LOCATION}/dockerfiles:/home/pi/pialert/dockerfiles
|
||||
- ${APP_DATA_LOCATION}/pialert/php.ini:/etc/php/7.4/fpm/php.ini
|
||||
# - ${DEV_LOCATION}/front/api:/home/pi/pialert/front/api
|
||||
- ${APP_DATA_LOCATION}/pialert/php.ini:/etc/php/8.2/fpm/php.ini
|
||||
- ${DEV_LOCATION}/install:/home/pi/pialert/install
|
||||
- ${DEV_LOCATION}/front/css:/home/pi/pialert/front/css
|
||||
- ${DEV_LOCATION}/back/update_vendors.sh:/home/pi/pialert/back/update_vendors.sh
|
||||
- ${DEV_LOCATION}/front/lib/AdminLTE:/home/pi/pialert/front/lib/AdminLTE
|
||||
- ${DEV_LOCATION}/front/js:/home/pi/pialert/front/js
|
||||
- ${DEV_LOCATION}/front/php:/home/pi/pialert/front/php
|
||||
- ${DEV_LOCATION}/dockerfiles/start.sh:/home/pi/pialert/dockerfiles/start.sh
|
||||
- ${DEV_LOCATION}/dockerfiles/user-mapping.sh:/home/pi/pialert/dockerfiles/user-mapping.sh
|
||||
- ${DEV_LOCATION}/install/install.sh:/home/pi/pialert/install/install.sh
|
||||
- ${DEV_LOCATION}/install/install_dependencies.sh:/home/pi/pialert/install/install_dependencies.sh
|
||||
- ${DEV_LOCATION}/front/api:/home/pi/pialert/front/api
|
||||
- ${DEV_LOCATION}/front/php:/home/pi/pialert/front/php
|
||||
- ${DEV_LOCATION}/front/deviceDetails.php:/home/pi/pialert/front/deviceDetails.php
|
||||
- ${DEV_LOCATION}/front/deviceDetailsTools.php:/home/pi/pialert/front/deviceDetailsTools.php
|
||||
- ${DEV_LOCATION}/front/devices.php:/home/pi/pialert/front/devices.php
|
||||
- ${DEV_LOCATION}/front/events.php:/home/pi/pialert/front/events.php
|
||||
- ${DEV_LOCATION}/front/plugins.php:/home/pi/pialert/front/plugins.php
|
||||
- ${DEV_LOCATION}/front/pluginsCore.php:/home/pi/pialert/front/pluginsCore.php
|
||||
- ${DEV_LOCATION}/front/help_faq.php:/home/pi/pialert/front/help_faq.php
|
||||
- ${DEV_LOCATION}/front/index.php:/home/pi/pialert/front/index.php
|
||||
- ${DEV_LOCATION}/front/maintenance.php:/home/pi/pialert/front/maintenance.php
|
||||
- ${DEV_LOCATION}/front/network.php:/home/pi/pialert/front/network.php
|
||||
- ${DEV_LOCATION}/front/presence.php:/home/pi/pialert/front/presence.php
|
||||
- ${DEV_LOCATION}/front/settings.php:/home/pi/pialert/front/settings.php
|
||||
- ${DEV_LOCATION}/front/plugins:/home/pi/pialert/front/plugins
|
||||
- ${DEV_LOCATION}/front/settings.php:/home/pi/pialert/front/settings.php
|
||||
- ${DEV_LOCATION}/front/systeminfo.php:/home/pi/pialert/front/systeminfo.php
|
||||
- ${DEV_LOCATION}/front/report.php:/home/pi/pialert/front/report.php
|
||||
- ${DEV_LOCATION}/front/workflows.php:/home/pi/pialert/front/workflows.php
|
||||
- ${DEV_LOCATION}/front/appEventsCore.php:/home/pi/pialert/front/appEventsCore.php
|
||||
- ${DEV_LOCATION}/front/donations.php:/home/pi/pialert/front/donations.php
|
||||
- ${DEV_LOCATION}/front/plugins:/home/pi/pialert/front/plugins
|
||||
# DELETE END anyone trying to use this file: comment out / delete ABOVE lines, they are only for development purposes
|
||||
# ---------------------------------------------------------------------------
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- PORT=${PORT}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
[](https://github.com/jokob-sk/Pi.Alert/actions/workflows/docker_prod.yml)
|
||||
[](https://github.com/jokob-sk/Pi.Alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||

|
||||
[](https://github.com/sponsors/jokob-sk)
|
||||
|
||||
# 🐳 A docker image for Pi.Alert
|
||||
# PiAlert 💻🔍 Network security scanner & notification framework
|
||||
|
||||
🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📄 [Dockerfile](https://github.com/jokob-sk/Pi.Alert/blob/main/Dockerfile) | 📚 [Docker instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) | 🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases)
|
||||
| 🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Docker guide](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) |🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [All Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs) |
|
||||
|----------------------|----------------------| ----------------------| ----------------------|
|
||||
|
||||
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" width="300px" />
|
||||
@@ -15,10 +16,12 @@
|
||||
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" width="300px" />
|
||||
</a>
|
||||
|
||||
> [!NOTE]
|
||||
> There is also an experimental 🧪 [bare-metal install](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HW_INSTALL.md) method available.
|
||||
|
||||
## 📕 Basic Usage
|
||||
|
||||
- You will have to run the container on the host network, e.g:
|
||||
- You will have to run the container on the `host` network, e.g:
|
||||
|
||||
```yaml
|
||||
docker run -d --rm --network=host \
|
||||
@@ -27,78 +30,89 @@ docker run -d --rm --network=host \
|
||||
-e TZ=Europe/Berlin \
|
||||
-e PORT=20211 \
|
||||
jokobsk/pi.alert:latest
|
||||
```
|
||||
- The initial scan can take up-to 15min (with 50 devices and MQTT). Subsequent ones 3 and 5 minutes so wait that long for all of the scans to run.
|
||||
```
|
||||
- The initial scan can take up to 15min (with 50 devices and MQTT). Subsequent ones 3 and 5 minutes so wait that long for all of the scans to run.
|
||||
|
||||
### Docker environment variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
| :------------- |:-------------| -----:|
|
||||
| `PORT` |Port of the web interface | `20211` |
|
||||
| `LISTEN_ADDR` |Set the specific IP Address for the listener address for the nginx webserver (web interface). This could be useful when using multiple subnets to hide the web interface from all untrusted networks. | `0.0.0.0` |
|
||||
|`TZ` |Time zone to display stats correctly. Find your time zone [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|
||||
|`HOST_USER_GID` |User ID (UID) to map the user in the container to a server user with sufficient read&write permissions on the mapped files | `1000` |
|
||||
|`HOST_USER_ID` |User Group ID (GID) to map the user group in the container to a server user group with sufficient read&write permissions on the mapped files | `1000` |
|
||||
|
||||
### Docker paths
|
||||
|
||||
| | Path | Description |
|
||||
| :------------- | :------------- |:-------------|
|
||||
| **Required** | `:/home/pi/pialert/config` | Folder which will contain the `pialert.conf` file (see below for details) |
|
||||
| **Required** | `:/home/pi/pialert/db` | Folder which will contain the `pialert.db` file |
|
||||
|Optional| `:/home/pi/pialert/front/log` | Logs folder useful for debugging if you have issues setting up the container |
|
||||
|Optional| `:/etc/pihole/pihole-FTL.db` | PiHole's `pihole-FTL.db` database file. Required if you want to use PiHole |
|
||||
|Optional| `:/etc/pihole/dhcp.leases` | PiHole's `dhcp.leases` file. Required if you want to use PiHole |
|
||||
|Optional| `:/home/pi/pialert/front/api` | A simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) containing static (but regularly updated) json and other files. |
|
||||
| Required | Path | Description |
|
||||
| :------------- | :------------- | :-------------|
|
||||
| ✅ | `:/home/pi/pialert/config` | Folder which will contain the `pialert.conf` file (see below for details) |
|
||||
| ✅ | `:/home/pi/pialert/db` | Folder which will contain the `pialert.db` file |
|
||||
| | `:/home/pi/pialert/front/log` | Logs folder useful for debugging if you have issues setting up the container |
|
||||
| | `:/etc/pihole/pihole-FTL.db` | PiHole's `pihole-FTL.db` database file. Required if you want to use PiHole DB mapping. |
|
||||
| | `:/etc/pihole/dhcp.leases` | PiHole's `dhcp.leases` file. Required if you want to use PiHole `dhcp.leases` file. This has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (the path in the container must contain `pihole`)|
|
||||
| | `:/home/pi/pialert/front/api` | A simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) containing static (but regularly updated) json and other files. |
|
||||
| | `:/home/pi/pialert/front/plugins/<plugin>/ignore_plugin` | Map a file `ignore_plugin` to ignore a plugin. Plugins can be soft-disabled via settings. More in the [Plugin docs](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md). |
|
||||
| | `:/etc/resolv.conf` | Use a custom `resolv.conf` file for [better name resolution](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/REVERSE_DNS.md). |
|
||||
|
||||
|
||||
### Config (`pialert.conf`)
|
||||
### Modify the config (`pialert.conf`) only if UI is not available
|
||||
|
||||
- If unavailable, the app generates a default `pialert.conf` and `pialert.db` file on the first run.
|
||||
- The preferred way is to manage the configuration via the Settings section in the UI.
|
||||
- You can modify [pialert.conf](https://github.com/jokob-sk/Pi.Alert/tree/main/config) directly, if needed.
|
||||
- If unavailable, the app generates a default `pialert.conf` and `pialert.db` file on the first run.
|
||||
|
||||
#### Important settings
|
||||
|
||||
These are the most important settings to get at least some output in your Devices screen. Usually, only one approach is used, but you should be able to combine these approaches.
|
||||
|
||||
##### For arp-scan: ENABLE_ARPSCAN, SCAN_SUBNETS
|
||||
##### For arp-scan: ARPSCAN_RUN, SCAN_SUBNETS
|
||||
|
||||
- ❗ To use the arp-scan method, you need to set the `SCAN_SUBNETS` variable.
|
||||
* The adapter will probably be `eth0` or `eth1`. (Run `iwconfig` to find your interface name(s))
|
||||
* Specify the network filter (which **significantly** speeds up the scan process). For example, the filter `192.168.1.0/24` covers IP ranges 192.168.1.0 to 192.168.1.255.
|
||||
* Examples for one and two subnets (❗ Note the `['...', '...']` format):
|
||||
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
|
||||
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0', '192.168.1.0/24 --interface=eth1 -vlan=107']`
|
||||
* More documentation on how to e.g. [setup vlans & limitations](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
|
||||
- ❗ To use the arp-scan method, you need to set the `SCAN_SUBNETS` variable. See the documentation on how [to setup SUBNETS, VLANs & limitations](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
|
||||
|
||||
##### For pihole: PIHOLE_ACTIVE, DHCP_ACTIVE
|
||||
##### For pihole: PIHOLE_RUN, DHCPLSS_RUN
|
||||
|
||||
* `PIHOLE_ACTIVE`: You need to map `:/etc/pihole/pihole-FTL.db in the docker-compose.yml` file if you enable this setting.
|
||||
* `DHCP_ACTIVE` : You need to map `:/etc/pihole/dhcp.leases in the docker-compose.yml` file if you enable this setting.
|
||||
There are 2 approaches how to get PiHole devices imported. Via the PiHole import (PIHOLE) plugin or DHCP leases (DHCPLSS) plugin.
|
||||
|
||||
**PiHole (Device sync)**
|
||||
|
||||
* `PIHOLE_RUN`: You need to map `:/etc/pihole/pihole-FTL.db` in the `docker-compose.yml` file if you enable this setting.
|
||||
|
||||
**DHCP Leases (Device import)**
|
||||
|
||||
* `DHCPLSS_RUN`: You need to map `:/etc/pihole/dhcp.leases` in the `docker-compose.yml` file if you enable this setting.
|
||||
* The above setting has to be matched with a corresponding `DHCPLSS_paths_to_check` setting entry (the path in the container must contain `pihole` as PiHole uses a different format of the `dhcp.leases` file).
|
||||
|
||||
> [!NOTE]
|
||||
> It's recommended to use the same schedule interval for all plugins responsible for discovering new devices.
|
||||
|
||||
|
||||
#### 🧭 Community guides
|
||||
|
||||
Use the official installation guides at first and use community content as suplementary material. Open an issue if you'd like to add your link to the list 🙏
|
||||
|
||||
- 📄 [How to Install Pi.Alert on Your Synology NAS - Marius hosting (English)](https://mariushosting.com/how-to-install-pi-alert-on-your-synology-nas/) (Updated frequently)
|
||||
- 📄 [Using the PiAlert Network Security Scanner on a Raspberry Pi - PiMyLifeUp (English)](https://pimylifeup.com/raspberry-pi-pialert/)
|
||||
- ▶ [How to Setup Pi.Alert on Your Synology NAS - Digital Aloha (English)](https://www.youtube.com/watch?v=M4YhpuRFaUg)
|
||||
- 📄 [시놀/헤놀에서 네트워크 스캐너 Pi.Alert Docker로 설치 및 사용하기 (Korean)](https://blog.dalso.org/article/%EC%8B%9C%EB%86%80-%ED%97%A4%EB%86%80%EC%97%90%EC%84%9C-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8A%A4%EC%BA%90%EB%84%88-pi-alert-docker%EB%A1%9C-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%82%AC%EC%9A%A9) (July 2023)
|
||||
- 📄 [网络入侵探测器Pi.Alert (Chinese)](https://codeantenna.com/a/VgUvIAjZ7J) (May 2023)
|
||||
- ▶ [Pi.Alert auf Synology & Docker by - Jürgen Barth (German)](https://www.youtube.com/watch?v=-ouvA2UNu-A) (March 2023)
|
||||
- ▶ [Top Docker Container for Home Server Security - VirtualizationHowto (English)](https://www.youtube.com/watch?v=tY-w-enLF6Q) (March 2023)
|
||||
- ▶ [Pi.Alert or WatchYourLAN can alert you to unknown devices appearing on your WiFi or LAN network - Danie van der Merwe (English)](https://www.youtube.com/watch?v=v6an9QG2xF0) (November 2022)
|
||||
|
||||
> Ordered by last update time.
|
||||
|
||||
### **Common issues**
|
||||
|
||||
💡 Before creating a new issue, please check if a similar issue was [already resolved](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed).
|
||||
|
||||
**Permissions**
|
||||
⚠ Check also common issues and [debugging tips](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md).
|
||||
|
||||
* If facing issues (AJAX errors, can't write to DB, empty screen, etc,) make sure permissions are set correctly, and check the logs under `/home/pi/pialert/front/log`.
|
||||
* To solve permission issues you can try setting the owner and group of the `pialert.db` by executing the following on the host system: `docker exec pialert chown -R www-data:www-data /home/pi/pialert/db/pialert.db`.
|
||||
* Map to local User and Group IDs. Specify the enviroment variables `HOST_USER_ID` and `HOST_USER_GID` if needed.
|
||||
* If still facing issues, try to map the pialert.db file (⚠ not folder) to `:/home/pi/pialert/db/pialert.db` (see Examples below for details)
|
||||
> [!NOTE]
|
||||
> You can bulk-update devices via the [CSV import method](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md).
|
||||
|
||||
**Container restarts / crashes**
|
||||
|
||||
* Check the logs for details. Often a required setting for a notification method is missing.
|
||||
|
||||
**unable to resolve host**
|
||||
|
||||
* Check that your `SCAN_SUBNETS` variable is using the correct mask and `--interface` as outlined in the instructions above.
|
||||
|
||||
|
||||
Docker-compose examples can be found below.
|
||||
|
||||
## 📄 Examples
|
||||
## 📄 docker-compose.yml Examples
|
||||
|
||||
### Example 1
|
||||
|
||||
@@ -107,6 +121,8 @@ version: "3"
|
||||
services:
|
||||
pialert:
|
||||
container_name: pialert
|
||||
# use the below line if you want to test the latest dev image
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: "jokobsk/pi.alert:latest"
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
@@ -133,6 +149,8 @@ Example by [SeimuS](https://github.com/SeimusS).
|
||||
container_name: PiAlert
|
||||
hostname: PiAlert
|
||||
privileged: true
|
||||
# use the below line if you want to test the latest dev image
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: jokobsk/pi.alert:latest
|
||||
environment:
|
||||
- TZ=Europe/Bratislava
|
||||
@@ -154,6 +172,8 @@ version: "3"
|
||||
services:
|
||||
pialert:
|
||||
container_name: pialert
|
||||
# use the below line if you want to test the latest dev image
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: "jokobsk/pi.alert:latest"
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
@@ -198,6 +218,8 @@ Courtesy of [pbek](https://github.com/pbek). The volume `pialert_db` is used by
|
||||
|
||||
```yaml
|
||||
pialert:
|
||||
# use the below line if you want to test the latest dev image
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: jokobsk/pi.alert
|
||||
ports:
|
||||
- "80:20211/tcp"
|
||||
@@ -214,16 +236,21 @@ Courtesy of [pbek](https://github.com/pbek). The volume `pialert_db` is used by
|
||||
|
||||
## 🏅 Recognitions
|
||||
|
||||
Big thanks to <a href="https://github.com/Macleykun">@Macleykun</a> for help and tips&tricks for Dockerfile(s):
|
||||
Big thanks to <a href="https://github.com/Macleykun">@Macleykun</a> for help and tips&tricks for Dockerfile(s).
|
||||
|
||||
<a href="https://github.com/Macleykun">
|
||||
<img src="https://avatars.githubusercontent.com/u/26381427?size=50">
|
||||
</a>
|
||||
## ❤ Support me
|
||||
|
||||
## ☕ Support me
|
||||
Get:
|
||||
- Regular updates to keep your data and family safe 🔄
|
||||
- Better and more functionality➕
|
||||
- I don't get burned out and the app survives longer🔥🤯
|
||||
- Quicker and better support with issues 🆘
|
||||
- Less grumpy me 😄
|
||||
|
||||
<a href="https://github.com/sponsors/jokob-sk" target="_blank"><img src="https://i.imgur.com/X6p5ACK.png" alt="Sponsor Me on GitHub" style="height: 30px !important;width: 117px !important;" width="150px" ></a>
|
||||
<a href="https://www.buymeacoffee.com/jokobsk" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 117px !important;" width="117px" height="30px" ></a>
|
||||
<a href="https://www.patreon.com/user?u=84385063" target="_blank"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Patreon_logo_with_wordmark.svg/512px-Patreon_logo_with_wordmark.svg.png" alt="Support me on patreon" style="height: 30px !important;width: 117px !important;" width="117px" ></a>
|
||||
| [](https://github.com/sponsors/jokob-sk) | [](https://www.buymeacoffee.com/jokobsk) | [](https://www.patreon.com/user?u=84385063) |
|
||||
| --- | --- | --- |
|
||||
|
||||
BTC: 1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM
|
||||
- Bitcoin: `1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM`
|
||||
- Ethereum: `0x6e2749Cb42F4411bc98501406BdcD82244e3f9C7`
|
||||
|
||||
> 📧 Email me at [jokob@duck.com](mailto:jokob@duck.com?subject=PiAlert) if you want to get in touch or if I should add other sponsorship platforms.
|
||||
232
dockerfiles/README_ES.md
Executable file
@@ -0,0 +1,232 @@
|
||||
[](https://github.com/jokob-sk/Pi.Alert/actions/workflows/docker_prod.yml)
|
||||
[](https://github.com/jokob-sk/Pi.Alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
[](https://hub.docker.com/r/jokobsk/pi.alert)
|
||||
|
||||
# 🐳 Una imagen docker para Pi.Alert
|
||||
|
||||
🐳 [Docker hub](https://registry.hub.docker.com/r/jokobsk/pi.alert) | 📑 [Instrucciones para Docker](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md) | 🆕 [Release notes](https://github.com/jokob-sk/Pi.Alert/releases) | 📚 [Todos los Docs](https://github.com/jokob-sk/Pi.Alert/tree/main/docs)
|
||||
|
||||
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/devices_split.png" width="300px" />
|
||||
</a>
|
||||
<a href="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/network.png" width="300px" />
|
||||
</a>
|
||||
|
||||
|
||||
## 📕 Uso básico
|
||||
|
||||
- Tendrás que ejecutar el contenedor en la red del host, por ejemplo:
|
||||
|
||||
```yaml
|
||||
docker run -d --rm --network=host \
|
||||
-v local/path/pialert/config:/home/pi/pialert/config \
|
||||
-v local/path/pialert/db:/home/pi/pialert/db \
|
||||
-e TZ=Europe/Berlin \
|
||||
-e PORT=20211 \
|
||||
jokobsk/pi.alert:latest
|
||||
```
|
||||
- El escaneo inicial puede tardar hasta 15 minutos (con 50 dispositivos y MQTT). Los siguientes pueden durar entre 3 y 5 minutos, así que espere a que se ejecuten todos los escaneos.
|
||||
|
||||
### Variables de entorno Docker
|
||||
|
||||
| Variable | Descripción | Predeterminado |
|
||||
| :------------- |:-------------| -----:|
|
||||
| `PORT` |Puerto de la interfaz web | `20211` |
|
||||
|`TZ` |Zona horaria para mostrar correctamente las estadísticas. Encuentre su zona horaria [aquí](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `Europe/Berlin` |
|
||||
|`HOST_USER_GID` |ID de usuario (UID) para asignar el usuario del contenedor a un usuario del servidor con suficientes permisos de lectura y escritura en los archivos asignados | `1000` |
|
||||
|`HOST_USER_ID` |ID de grupo de usuarios (GID) para asignar el grupo de usuarios del contenedor a un grupo de usuarios del servidor con suficientes permisos de lectura y escritura en los archivos asignados | `1000` |
|
||||
|
||||
### Rutas Docker
|
||||
|
||||
| | Ruta | Descripción |
|
||||
| :------------- | :------------- |:-------------|
|
||||
| **Obligatorio** | `:/home/pi/pialert/config` | Carpeta que contendrá el archivo `pialert.conf` (para más detalles, véase más abajo) |
|
||||
| **Obligatorio** | `:/home/pi/pialert/db` | Carpeta que contendrá el archivo `pialert.db` |
|
||||
|Opcional| `:/home/pi/pialert/front/log` | Carpeta de registros útil para depurar si tiene problemas al configurar el contenedor |
|
||||
|Opcional| `:/etc/pihole/pihole-FTL.db` | Archivo de base de datos `pihole-FTL.db` de PiHole. Necesario si desea utilizar PiHole |
|
||||
|Opcional| `:/etc/pihole/dhcp.leases` | Archivo `dhcp.leases` de PiHole. Obligatorio si desea utilizar el archivo `dhcp.leases` de PiHole. Tiene que coincidir con la correspondiente entrada de configuración `DHCPLSS_paths_to_check`. (La ruta en el contenedor debe contener `pihole`)|
|
||||
|Opcional| `:/home/pi/pialert/front/api` | Una simple [API endpoint](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md) que contiene archivos json estáticos (pero actualizados regularmente) y otros archivos. |
|
||||
|
||||
|
||||
### Configurar (`pialert.conf`)
|
||||
|
||||
- Si no está disponible, la aplicación genera un archivo `pialert.conf` y `pialert.db` por defecto en la primera ejecución.
|
||||
- La forma preferida es gestionar la configuración a través de la sección "Configuración" de la interfaz de usuario.
|
||||
- Puede modificar [pialert.conf](https://github.com/jokob-sk/Pi.Alert/tree/main/config) directamente, si es necesario.
|
||||
|
||||
#### Ajustes importantes
|
||||
|
||||
Estos son los ajustes más importantes para obtener al menos alguna salida en la pantalla de tus Dispositivos. Por lo general, sólo se utiliza un enfoque, pero usted debe ser capaz de combinar estos enfoques.
|
||||
|
||||
##### Para arp-scan: ARPSCAN_RUN, SCAN_SUBNETS
|
||||
|
||||
- ❗ Para usar el método arp-scan, necesitas configurar la variable `SCAN_SUBNETS`. Consulte la documentación sobre cómo [configurar SUBNETS, VLANs y limitaciones](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/SUBNETS.md)
|
||||
|
||||
##### Para pihole: PIHOLE_RUN, DHCPLSS_RUN
|
||||
|
||||
Hay dos maneras de importar dispositivos PiHole. A través del plugin de importación PiHole (PIHOLE) o del plugin DHCP leases (DHCPLSS).
|
||||
|
||||
**PiHole (Sincronización de dispositivos)**
|
||||
|
||||
* `PIHOLE_RUN`: Necesitas mapear `:/etc/pihole/pihole-FTL.db` en el fichero `docker-compose.yml` si activas esta opción.
|
||||
|
||||
**DHCP Leases (Importación de dispositivos)**
|
||||
|
||||
* `DHCPLSS_RUN`: Es necesario mapear `:/etc/pihole/dhcp.leases` en el fichero `docker-compose.yml` si se activa esta opción.
|
||||
* La configuración anterior tiene que coincidir con una entrada de configuración correspondiente `DHCPLSS_paths_to_check` (la ruta en el contenedor debe contener `pihole` ya que PiHole utiliza un formato diferente del archivo `dhcp.leases`).
|
||||
|
||||
> Se recomienda utilizar el mismo intervalo de programación para todos los plugins responsables de descubrir nuevos dispositivos.
|
||||
|
||||
### **Problemas comunes**
|
||||
|
||||
💡 Antes de crear una nueva incidencia, comprueba si ya se ha resuelto una [incidencia similar](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed).
|
||||
|
||||
⚠ Compruebe también los problemas comunes y los [consejos de depuración](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md).
|
||||
|
||||
## 📄 Ejemplos
|
||||
|
||||
### Ejemplo 1
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
pialert:
|
||||
container_name: pialert
|
||||
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: "jokobsk/pi.alert:latest"
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- local/path/pialert/config:/home/pi/pialert/config
|
||||
- local/path/pialert/db:/home/pi/pialert/db
|
||||
# (optional) useful for debugging if you have issues setting up the container
|
||||
- local/path/logs:/home/pi/pialert/front/log
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- HOST_USER_ID=1000
|
||||
- HOST_USER_GID=1000
|
||||
- PORT=20211
|
||||
```
|
||||
|
||||
Para ejecutar el contenedor ejecute: `sudo docker-compose up -d`
|
||||
|
||||
### Ejemplo 2
|
||||
|
||||
Ejemplo de [SeimuS](https://github.com/SeimusS).
|
||||
|
||||
```yaml
|
||||
pialert:
|
||||
container_name: PiAlert
|
||||
hostname: PiAlert
|
||||
privileged: true
|
||||
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: jokobsk/pi.alert:latest
|
||||
environment:
|
||||
- TZ=Europe/Bratislava
|
||||
restart: always
|
||||
volumes:
|
||||
- ./pialert/pialert_db:/home/pi/pialert/db
|
||||
- ./pialert/pialert_config:/home/pi/pialert/config
|
||||
network_mode: host
|
||||
```
|
||||
|
||||
Para ejecutar el contenedor ejecute: `sudo docker-compose up -d`
|
||||
|
||||
### Ejemplo 3
|
||||
|
||||
`docker-compose.yml`
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
pialert:
|
||||
container_name: pialert
|
||||
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: "jokobsk/pi.alert:latest"
|
||||
network_mode: "host"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ${APP_DATA_LOCATION}/pialert/config:/home/pi/pialert/config
|
||||
- ${APP_DATA_LOCATION}/pialert/db/pialert.db:/home/pi/pialert/db/pialert.db
|
||||
# (optional) useful for debugging if you have issues setting up the container
|
||||
- ${LOGS_LOCATION}:/home/pi/pialert/front/log
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- HOST_USER_ID=${HOST_USER_ID}
|
||||
- HOST_USER_GID=${HOST_USER_GID}
|
||||
- PORT=${PORT}
|
||||
```
|
||||
|
||||
`.env` file
|
||||
|
||||
```yaml
|
||||
#VARIABLES DE RUTA GLOBAL
|
||||
|
||||
APP_DATA_LOCATION=/path/to/docker_appdata
|
||||
APP_CONFIG_LOCATION=/path/to/docker_config
|
||||
LOGS_LOCATION=/path/to/docker_logs
|
||||
|
||||
#VARIABLES DE ENTORNO
|
||||
|
||||
TZ=Europe/Paris
|
||||
HOST_USER_ID=1000
|
||||
HOST_USER_GID=1000
|
||||
PORT=20211
|
||||
|
||||
#VARIABLES DE DESARROLLO
|
||||
|
||||
DEV_LOCATION=/path/to/local/source/code
|
||||
```
|
||||
|
||||
Para ejecutar el contenedor ejecute: `sudo docker-compose --env-file /path/to/.env up`
|
||||
|
||||
### Example 4
|
||||
|
||||
Por cortesía de [pbek](https://github.com/pbek). El volumen `pialert_db` es utilizado por el directorio db. Los dos archivos de configuración se montan directamente desde una carpeta local a sus lugares en la carpeta config. Puedes hacer una copia de seguridad de la carpeta `docker-compose.yaml` y de la carpeta docker volumes.
|
||||
|
||||
|
||||
```yaml
|
||||
pialert:
|
||||
# Utilice la siguiente línea si desea probar la última imagen de desarrollo
|
||||
# image: "jokobsk/pi.alert_dev:latest"
|
||||
image: jokobsk/pi.alert
|
||||
ports:
|
||||
- "80:20211/tcp"
|
||||
environment:
|
||||
- TZ=Europe/Vienna
|
||||
networks:
|
||||
local:
|
||||
ipv4_address: 192.168.1.2
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- pialert_db:/home/pi/pialert/db
|
||||
- ./pialert/pialert.conf:/home/pi/pialert/config/pialert.conf
|
||||
```
|
||||
|
||||
## 🏅 Reconocimientos
|
||||
|
||||
Muchas gracias a <a href="https://github.com/Macleykun">@Macleykun</a> por ayudarme en consejos y trucos para Dockerfile(s):
|
||||
|
||||
<a href="https://github.com/Macleykun">
|
||||
<img src="https://avatars.githubusercontent.com/u/26381427?size=50">
|
||||
</a>
|
||||
|
||||
Muchas gracias a <a href="https://github.com/cvc90">@cvc90</a> por ayudarme y realizar esta traduccion:
|
||||
|
||||
<a href="https://github.com/cvc90">
|
||||
<img src="https://avatars.githubusercontent.com/u/76731844?size=50">
|
||||
</a>
|
||||
|
||||
## ☕ Apóyame
|
||||
|
||||
<a href="https://github.com/sponsors/jokob-sk" target="_blank"><img src="https://i.imgur.com/X6p5ACK.png" alt="Sponsor Me on GitHub" style="height: 30px !important;width: 117px !important;" width="150px" ></a>
|
||||
<a href="https://www.buymeacoffee.com/jokobsk" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 117px !important;" width="117px" height="30px" ></a>
|
||||
<a href="https://www.patreon.com/user?u=84385063" target="_blank"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Patreon_logo_with_wordmark.svg/512px-Patreon_logo_with_wordmark.svg.png" alt="Support me on patreon" style="height: 30px !important;width: 117px !important;" width="117px" ></a>
|
||||
|
||||
BTC: 1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM
|
||||
@@ -1,31 +1,154 @@
|
||||
#!/bin/sh
|
||||
/home/pi/pialert/dockerfiles/user-mapping.sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run start.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
|
||||
INSTALL_DIR=/home/pi # Specify the installation directory here
|
||||
|
||||
# DO NOT CHANGE ANYTHING BELOW THIS LINE!
|
||||
WEB_UI_DIR=/var/www/html/pialert
|
||||
NGINX_CONFIG_FILE=/etc/nginx/conf.d/pialert.conf
|
||||
OUI_FILE="/usr/share/arp-scan/ieee-oui.txt" # Define the path to ieee-oui.txt and ieee-iab.txt
|
||||
FILEDB=$INSTALL_DIR/pialert/db/pialert.db
|
||||
# DO NOT CHANGE ANYTHING ABOVE THIS LINE!
|
||||
|
||||
# if custom variables not set we do not need to do anything
|
||||
if [ -n "${TZ}" ]; then
|
||||
FILECONF=/home/pi/pialert/config/pialert.conf
|
||||
FILECONF=$INSTALL_DIR/pialert/config/pialert.conf
|
||||
if [ -f "$FILECONF" ]; then
|
||||
sed -ie "s|Europe/Berlin|${TZ}|g" /home/pi/pialert/config/pialert.conf
|
||||
sed -ie "s|Europe/Berlin|${TZ}|g" $INSTALL_DIR/pialert/config/pialert.conf
|
||||
else
|
||||
sed -ie "s|Europe/Berlin|${TZ}|g" /home/pi/pialert/back/pialert.conf_bak
|
||||
sed -ie "s|Europe/Berlin|${TZ}|g" $INSTALL_DIR/pialert/back/pialert.conf_bak
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${PORT}" ]; then
|
||||
sed -ie 's/listen 20211/listen '${PORT}'/g' /etc/nginx/sites-available/default
|
||||
fi
|
||||
|
||||
# I hope this will fix DB permission issues going forward
|
||||
FILEDB=/home/pi/pialert/db/pialert.db
|
||||
if [ -f "$FILEDB" ]; then
|
||||
chown -R www-data:www-data /home/pi/pialert/db/pialert.db
|
||||
# Check if script is run as root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root. Please use 'sudo'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod -R a+rw /home/pi/pialert/front/log
|
||||
chmod -R a+rw /home/pi/pialert/config
|
||||
# Run setup scripts
|
||||
echo "[INSTALL] Run setup scripts"
|
||||
|
||||
/etc/init.d/php7.4-fpm start
|
||||
"$INSTALL_DIR/pialert/dockerfiles/user-mapping.sh"
|
||||
"$INSTALL_DIR/pialert/install/install_dependencies.sh" # if modifying this file transfer the chanegs into the root Dockerfile as well!
|
||||
|
||||
echo "[INSTALL] Setup NGINX"
|
||||
|
||||
# Remove default NGINX site if it is symlinked, or backup it otherwise
|
||||
if [ -L /etc/nginx/sites-enabled/default ] ; then
|
||||
echo "Disabling default NGINX site, removing sym-link in /etc/nginx/sites-enabled"
|
||||
sudo rm /etc/nginx/sites-enabled/default
|
||||
elif [ -f /etc/nginx/sites-enabled/default ]; then
|
||||
echo "Disabling default NGINX site, moving config to /etc/nginx/sites-available"
|
||||
sudo mv /etc/nginx/sites-enabled/default /etc/nginx/sites-available/default.bkp_pialert
|
||||
fi
|
||||
|
||||
# Clear existing directories and files
|
||||
if [ -d $WEB_UI_DIR ]; then
|
||||
echo "Removing existing PiAlert web-UI"
|
||||
sudo rm -R $WEB_UI_DIR
|
||||
fi
|
||||
|
||||
if [ -f $NGINX_CONFIG_FILE ]; then
|
||||
echo "Removing existing PiAlert NGINX config"
|
||||
sudo rm $NGINX_CONFIG_FILE
|
||||
fi
|
||||
|
||||
# create symbolic link to the pialert install directory
|
||||
ln -s $INSTALL_DIR/pialert/front $WEB_UI_DIR
|
||||
# create symbolic link to NGINX configuaration coming with PiAlert
|
||||
sudo ln -s "$INSTALL_DIR/pialert/install/pialert.conf" /etc/nginx/conf.d/pialert.conf
|
||||
|
||||
# Use user-supplied port if set
|
||||
if [ -n "${PORT}" ]; then
|
||||
echo "Setting webserver to user-supplied port ($PORT)"
|
||||
sudo sed -i 's/listen 20211/listen '"$PORT"'/g' /etc/nginx/conf.d/pialert.conf
|
||||
fi
|
||||
|
||||
# Change web interface address if set
|
||||
if [ -n "${LISTEN_ADDR}" ]; then
|
||||
echo "Setting webserver to user-supplied address ($LISTEN_ADDR)"
|
||||
sed -ie 's/listen /listen '"${LISTEN_ADDR}":'/g' /etc/nginx/conf.d/pialert.conf
|
||||
fi
|
||||
|
||||
# Run the hardware vendors update at least once
|
||||
echo "[INSTALL] Run the hardware vendors update"
|
||||
|
||||
# Check if ieee-oui.txt or ieee-iab.txt exist
|
||||
if [ -f "$OUI_FILE" ]; then
|
||||
echo "The file ieee-oui.txt exists. Skipping update_vendors.sh..."
|
||||
else
|
||||
echo "The file ieee-oui.txt does not exist. Running update_vendors..."
|
||||
|
||||
# Run the update_vendors.sh script
|
||||
if [ -f "$INSTALL_DIR/pialert/back/update_vendors.sh" ]; then
|
||||
"$INSTALL_DIR/pialert/back/update_vendors.sh"
|
||||
else
|
||||
echo "update_vendors.sh script not found in $INSTALL_DIR."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create an empty log files
|
||||
|
||||
# Create the execution_queue.log file if it doesn't exist
|
||||
touch "$INSTALL_DIR/pialert/front/log/execution_queue.log"
|
||||
# Create the pialert_front.log file if it doesn't exist
|
||||
touch "$INSTALL_DIR/pialert/front/log/pialert_front.log"
|
||||
|
||||
|
||||
# Fixing file permissions
|
||||
echo "[INSTALL] Fixing file permissions"
|
||||
|
||||
echo "[INSTALL] Fixing WEB_UI_DIR: $WEB_UI_DIR"
|
||||
|
||||
chmod -R a+rwx $WEB_UI_DIR
|
||||
|
||||
echo "[INSTALL] Fixing INSTALL_DIR: $INSTALL_DIR"
|
||||
|
||||
chmod -R a+rw $INSTALL_DIR/pialert/front/log
|
||||
chmod -R a+rwx $INSTALL_DIR
|
||||
|
||||
echo "[INSTALL] Copy starter pialert.db and pialert.conf if they don't exist"
|
||||
|
||||
# Copy starter pialert.db and pialert.conf if they don't exist
|
||||
cp -n "$INSTALL_DIR/pialert/back/pialert.conf" "$INSTALL_DIR/pialert/config/pialert.conf"
|
||||
cp -n "$INSTALL_DIR/pialert/back/pialert.db" "$FILEDB"
|
||||
|
||||
echo "[INSTALL] Fixing permissions after copied starter config & DB"
|
||||
|
||||
if [ -f "$FILEDB" ]; then
|
||||
chown -R www-data:www-data $FILEDB
|
||||
fi
|
||||
|
||||
chmod -R a+rwx $INSTALL_DIR # second time after we copied the files
|
||||
chmod -R a+rw $INSTALL_DIR/pialert/config
|
||||
sudo chgrp -R www-data $INSTALL_DIR/pialert
|
||||
|
||||
# Check if buildtimestamp.txt doesn't exist
|
||||
if [ ! -f "$INSTALL_DIR/pialert/front/buildtimestamp.txt" ]; then
|
||||
# Create buildtimestamp.txt
|
||||
date +%s > "$INSTALL_DIR/pialert/front/buildtimestamp.txt"
|
||||
fi
|
||||
|
||||
# start PHP
|
||||
/etc/init.d/php8.2-fpm start
|
||||
/etc/init.d/nginx start
|
||||
|
||||
# cron -f
|
||||
python /home/pi/pialert/back/pialert.py
|
||||
# Start Nginx and your application to start at boot (if needed)
|
||||
# systemctl start nginx
|
||||
# systemctl enable nginx
|
||||
|
||||
# # systemctl enable pi-alert
|
||||
# sudo systemctl restart nginx
|
||||
|
||||
# Activate the virtual python environment
|
||||
source myenv/bin/activate
|
||||
|
||||
echo "[INSTALL] 🚀 Starting app - navigate to your <server IP>:$PORT"
|
||||
|
||||
# Start the PiAlert python script
|
||||
python $INSTALL_DIR/pialert/pialert/
|
||||
|
||||
@@ -1,29 +1,39 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "[INSTALL] Run user-mapping.sh"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
if [ -z "${USER}" ]; then
|
||||
echo "We need USER to be set!"; exit 100
|
||||
fi
|
||||
|
||||
# if both not set we do not need to do anything
|
||||
if [ -z "${HOST_USER_ID}" -a -z "${HOST_USER_GID}" ]; then
|
||||
if [ -z "${HOST_USER_ID}" ] && [ -z "${HOST_USER_GID}" ]; then
|
||||
echo "Nothing to do here." ; exit 0
|
||||
fi
|
||||
|
||||
# reset user_?id to either new id or if empty old (still one of above
|
||||
# reset user_id to either new id or if empty old (still one of above
|
||||
# might not be set)
|
||||
USER_ID=${HOST_USER_ID:=$USER_ID}
|
||||
USER_GID=${HOST_USER_GID:=$USER_GID}
|
||||
|
||||
LINE=$(grep -F "${USER}" /etc/passwd)
|
||||
# replace all ':' with a space and create array
|
||||
array=( ${LINE//:/ } )
|
||||
array=( "${LINE//:/ }" )
|
||||
|
||||
# home is 5th element
|
||||
USER_HOME=${array[4]}
|
||||
|
||||
# print debug output
|
||||
echo USER_ID" ": "${USER_ID}";
|
||||
echo USER_GID : "${USER_GID}";
|
||||
echo USER_HOME: "${USER_HOME}";
|
||||
echo TZ" ": "${TZ}";
|
||||
|
||||
sed -i -e "s/^${USER}:\([^:]*\):[0-9]*:[0-9]*/${USER}:\1:${USER_ID}:${USER_GID}/" /etc/passwd
|
||||
sed -i -e "s/^${USER}:\([^:]*\):[0-9]*/${USER}:\1:${USER_GID}/" /etc/group
|
||||
|
||||
chown -R ${USER_ID}:${USER_GID} ${USER_HOME}
|
||||
chown -R "${USER_ID}:${USER_GID} ${USER_HOME}"
|
||||
|
||||
exec su - "${USER}"
|
||||
exec su - "${USER}"
|
||||
|
||||
@@ -5,7 +5,7 @@ PiAlert comes with a simple API. These API endpoints are static files, that are
|
||||
|
||||
### When are the endpoints updated
|
||||
|
||||
Once you enable the API (`ENABLE_API` setting), the endpoints are updated when objects in the API endpoints are changed:
|
||||
The endpoints are updated when objects in the API endpoints are changed.
|
||||
|
||||
### Location of the endpoints
|
||||
|
||||
@@ -20,8 +20,7 @@ You can access the following files:
|
||||
| `notification_text.txt` | The plain text version of the last notification. |
|
||||
| `notification_text.html` | The full HTML of the last email notification. |
|
||||
| `notification_json_final.json` | The json version of the last notification (e.g. used for webhooks - [sample JSON](https://github.com/jokob-sk/Pi.Alert/blob/main/back/webhook_json_sample.json)). |
|
||||
| `table_devices.json` | The current (at the time of the last update as mentioned above on this page) state of all of the available Devices detected by the app. |
|
||||
| `table_nmap_scan.json` | The current state of the discovered ports by the regular NMAP scans. |
|
||||
| `table_devices.json` | The current (at the time of the last update as mentioned above on this page) state of all of the available Devices detected by the app. |
|
||||
| `table_pholus_scan.json` | The latest state of the [pholus](https://github.com/jokob-sk/Pi.Alert/tree/main/pholus) (A multicast DNS and DNS Service Discovery Security Assessment Tool) scan results. |
|
||||
| `table_plugins_events.json` | The list of the unprocessed (pending) notification events (plugins_events DB table). |
|
||||
| `table_plugins_history.json` | The list of notification events history. |
|
||||
@@ -29,6 +28,7 @@ You can access the following files:
|
||||
| `language_strings.json` | The content of the language_strings table, which in turn is loaded from the plugins `config.json` definitions. |
|
||||
| `table_custom_endpoint.json` | A custom endpoint generated by the SQL query specified by the `API_CUSTOM_SQL` setting. |
|
||||
| `table_settings.json` | The content of the settings table. |
|
||||
| `app_state.json` | Contains the current application state. |
|
||||
|
||||
Current/latest state of the aforementioned files depends on your settings.
|
||||
|
||||
|
||||
39
docs/DATABASE.md
Executable file
@@ -0,0 +1,39 @@
|
||||
|
||||
# A high-level description of the datbase structure
|
||||
|
||||
⚠ Disclaimer: As I'm not the original author, some of the information might be inaccurate. Feel free to submit a PR to correct anything within this page or documentation in general.
|
||||
|
||||
The MAC address is used as a foreign key in most cases.
|
||||
|
||||
## 🔍Tables overview
|
||||
|
||||
| Table name | Description | Sample data |
|
||||
|----------------------|----------------------| ----------------------|
|
||||
| CurrentScan | Result of the current scan | ![Screen1][screen1] |
|
||||
| Devices | The main devices database that also contains the Network tree mappings. If `ScanCycle` is set to `0` device is not scanned. | ![Screen2][screen2] |
|
||||
| Events | Used to collect connection/disconnection events. | ![Screen4][screen4] |
|
||||
| Online_History | Used to display the `Device presence` chart | ![Screen6][screen6] |
|
||||
| Parameters | Used to pass values between the frontend and backend. | ![Screen7][screen7] |
|
||||
| Pholus_Scan | Scan results of the Pholus python network penetration script. | ![Screen8][screen8] |
|
||||
| Plugins_Events | For capturing events exposed by a plugin via the `last_result.log` file. If unique then saved into the `Plugins_Objects` table. Entries are deleted once processed and stored in the `Plugins_History` and/or `Plugins_Objects` tables. | ![Screen10][screen10] |
|
||||
| Plugins_History | History of all entries from the `Plugins_Events` table | ![Screen11][screen11] |
|
||||
| Plugins_Language_Strings | Language strings colelcted from the plugin `config.json` files used for string resolution in the frontend. | ![Screen12][screen12] |
|
||||
| Plugins_Objects | Unique objects detected by individual plugins. | ![Screen13][screen13] |
|
||||
| Sessions | Used to display sessions in the charts | ![Screen15][screen15] |
|
||||
| Settings | Database representation of the sum of all settings from `pialert.conf` and plugins coming from `config.json` files. | ![Screen16][screen16] |
|
||||
|
||||
|
||||
|
||||
[screen1]: /docs/img/DATABASE/CurrentScan.png
|
||||
[screen2]: /docs/img/DATABASE/Devices.png
|
||||
[screen4]: /docs/img/DATABASE/Events.png
|
||||
[screen6]: /docs/img/DATABASE/Online_History.png
|
||||
[screen7]: /docs/img/DATABASE/Parameters.png
|
||||
[screen8]: /docs/img/DATABASE/Pholus_Scan.png
|
||||
[screen10]: /docs/img/DATABASE/Plugins_Events.png
|
||||
[screen11]: /docs/img/DATABASE/Plugins_History.png
|
||||
[screen12]: /docs/img/DATABASE/Plugins_Language_Strings.png
|
||||
[screen13]: /docs/img/DATABASE/Plugins_Objects.png
|
||||
[screen15]: /docs/img/DATABASE/Sessions.png
|
||||
[screen16]: /docs/img/DATABASE/Settings.png
|
||||
|
||||
@@ -8,22 +8,27 @@ Check the the HTTP response of the failing backend call by following these steps
|
||||
![F12DeveloperConsole][F12DeveloperConsole]
|
||||
|
||||
- Copy the URL causing the error and enter it in the address bar of your browser directly and hit enter. The copied URLs could look something like this (notice the query strings at the end):
|
||||
- `http://<pialert URL>:20211/api/table_devices.json?nocache=1704141103121`
|
||||
- `http://<pialert URL>:20211/php/server/devices.php?action=getDevicesTotals`
|
||||
- `http://<pialert URL>:20211/php/server/devices.php?action=getDevicesList&status=all`
|
||||
- `http://<pialert URL>:20211/php/server/devices.php?action=getDevicesList&status=all`
|
||||
|
||||
- Post the error response in the existing issue thread on GitHub or create a new issue and include the redacted response of the failing query.
|
||||
|
||||
For reference, the above queries should return results in the following format:
|
||||
|
||||
First URL:
|
||||
## First URL:
|
||||
|
||||
- Should yield a valid JSON file
|
||||
|
||||
## Second URL:
|
||||
|
||||
![array][array]
|
||||
|
||||
Second URL:
|
||||
## Third URL:
|
||||
|
||||
![json][json]
|
||||
|
||||
You can copy and paste any JSON result (result of the second query) into an online JSON checker, such as [this one](https://jsonchecker.com/) to check if it's valid.
|
||||
You can copy and paste any JSON result (result of the First and Third query) into an online JSON checker, such as [this one](https://jsonchecker.com/) to check if it's valid.
|
||||
|
||||
|
||||
[F12DeveloperConsole]: ./img/DEBUG/Invalid_JSON_repsonse_debug.png "F12DeveloperConsole"
|
||||
|
||||
74
docs/DEBUG_PLUGINS.md
Executable file
@@ -0,0 +1,74 @@
|
||||
# Troubleshooting plugins
|
||||
|
||||
## High-level overview
|
||||
|
||||
If a Plugin supplies data to the main app it's doine either vie a SQL query or via a script that updates the `last_result.log` file in the plugin folder (`front/plugins/<plugin>`).
|
||||
|
||||
For a more in-depth overview on how plugins work check the [Plugins development docs](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md).
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Make sure you read and followed the specific plugin setup instructions.
|
||||
- Ensure you have [debug enabled (see More Logging)](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md#1-more-logging-)
|
||||
|
||||
### Potential issues
|
||||
|
||||
- Bugs
|
||||
- Unexpected input (e.g. special characters in names)
|
||||
- Dependencies changed how data is output
|
||||
|
||||
#### Incorrect input data
|
||||
|
||||
Input data from the plugin might cause mapping issues in specific edge cases. Look for a corresponding section in the `pialert.log` file, for example notice the first line of the execution run of the `PIHOLE` plugin below:
|
||||
|
||||
```
|
||||
17:31:05 [Scheduler] - Scheduler run for PIHOLE: YES
|
||||
17:31:05 [Plugin utils] ---------------------------------------------
|
||||
17:31:05 [Plugin utils] display_name: PiHole (Device sync)
|
||||
17:31:05 [Plugins] CMD: SELECT n.hwaddr AS Object_PrimaryID, {s-quote}null{s-quote} AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, {s-quote}null{s-quote} AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE {s-quote}ip-%{s-quote} AND n.hwaddr is not {s-quote}00:00:00:00:00:00{s-quote} AND na.ip is not null
|
||||
17:31:05 [Plugins] setTyp: subnets
|
||||
17:31:05 [Plugin utils] Flattening the below array
|
||||
17:31:05 ['192.168.1.0/24 --interface=eth1']
|
||||
17:31:05 [Plugin utils] isinstance(arr, list) : False | isinstance(arr, str) : True
|
||||
17:31:05 [Plugins] Resolved value: 192.168.1.0/24 --interface=eth1
|
||||
17:31:05 [Plugins] Convert to Base64: True
|
||||
17:31:05 [Plugins] base64 value: b'MTkyLjE2OC4xLjAvMjQgLS1pbnRlcmZhY2U9ZXRoMQ=='
|
||||
17:31:05 [Plugins] Timeout: 10
|
||||
17:31:05 [Plugins] Executing: SELECT n.hwaddr AS Object_PrimaryID, 'null' AS Object_SecondaryID, datetime() AS DateTime, na.ip AS Watched_Value1, n.lastQuery AS Watched_Value2, na.name AS Watched_Value3, n.macVendor AS Watched_Value4, 'null' AS Extra, n.hwaddr AS ForeignKey FROM EXTERNAL_PIHOLE.Network AS n LEFT JOIN EXTERNAL_PIHOLE.Network_Addresses AS na ON na.network_id = n.id WHERE n.hwaddr NOT LIKE 'ip-%' AND n.hwaddr is not '00:00:00:00:00:00' AND na.ip is not null
|
||||
17:31:05 [Plugins] SUCCESS, received 2 entries
|
||||
17:31:05 [Plugins] sqlParam entries: [(0, 'PIHOLE', '01:01:01:01:01:01', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.1', 0, 'aaaa', 'vvvvvvvvv', 'not-processed', 'null', 'null', '01:01:01:01:01:01'), (0, 'PIHOLE', '02:42:ac:1e:00:02', 'null', 'null', '2023-12-25 06:31:05', '172.30.0.2', 0, 'dddd', 'vvvvv2222', 'not-processed', 'null', 'null', '02:42:ac:1e:00:02')]
|
||||
17:31:05 [Plugins] Processing : PIHOLE
|
||||
17:31:05 [Plugins] Existing objects from Plugins_Objects: 4
|
||||
17:31:05 [Plugins] Logged events from the plugin run : 2
|
||||
17:31:05 [Plugins] pluginEvents count: 2
|
||||
17:31:05 [Plugins] pluginObjects count: 4
|
||||
17:31:05 [Plugins] events_to_insert count: 0
|
||||
17:31:05 [Plugins] history_to_insert count: 4
|
||||
17:31:05 [Plugins] objects_to_insert count: 0
|
||||
17:31:05 [Plugins] objects_to_update count: 4
|
||||
17:31:05 [Plugin utils] In pluginEvents there are 2 events with the status "watched-not-changed"
|
||||
17:31:05 [Plugin utils] In pluginObjects there are 2 events with the status "missing-in-last-scan"
|
||||
17:31:05 [Plugin utils] In pluginObjects there are 2 events with the status "watched-not-changed"
|
||||
17:31:05 [Plugins] Mapping objects to database table: CurrentScan
|
||||
17:31:05 [Plugins] SQL query for mapping: INSERT into CurrentScan ( "cur_MAC", "cur_IP", "cur_LastQuery", "cur_Name", "cur_Vendor", "cur_ScanMethod") VALUES ( ?, ?, ?, ?, ?, ?)
|
||||
17:31:05 [Plugins] SQL sqlParams for mapping: [('01:01:01:01:01:01', '172.30.0.1', 0, 'aaaa', 'vvvvvvvvv', 'PIHOLE'), ('02:42:ac:1e:00:02', '172.30.0.2', 0, 'dddd', 'vvvvv2222', 'PIHOLE')]
|
||||
17:31:05 [API] Update API starting
|
||||
17:31:06 [API] Updating table_plugins_history.json file in /front/api
|
||||
```
|
||||
|
||||
In the above output notice the section logging how many events are produced by the plugin:
|
||||
|
||||
```
|
||||
17:31:05 [Plugins] Existing objects from Plugins_Objects: 4
|
||||
17:31:05 [Plugins] Logged events from the plugin run : 2
|
||||
17:31:05 [Plugins] pluginEvents count: 2
|
||||
17:31:05 [Plugins] pluginObjects count: 4
|
||||
17:31:05 [Plugins] events_to_insert count: 0
|
||||
17:31:05 [Plugins] history_to_insert count: 4
|
||||
17:31:05 [Plugins] objects_to_insert count: 0
|
||||
17:31:05 [Plugins] objects_to_update count: 4
|
||||
```
|
||||
|
||||
These values, if formatted correctly, will also show up in the UI:
|
||||
|
||||

|
||||
84
docs/DEBUG_TIPS.md
Executable file
@@ -0,0 +1,84 @@
|
||||
# Debugging and troubleshooting
|
||||
|
||||
Please follow tips 1 - 4 to get a more detailed error.
|
||||
|
||||
## 1. More Logging 📃
|
||||
|
||||
When debugging an issue always set the highest log level:
|
||||
|
||||
`LOG_LEVEL='debug'`
|
||||
|
||||
|
||||
## 2. Surfacing errors when container restarts 🔁
|
||||
|
||||
Start the container via the **terminal** with a command similar to this one:
|
||||
|
||||
```bash
|
||||
docker run --rm --network=host \
|
||||
-v local/path/pialert/config:/home/pi/pialert/config \
|
||||
-v local/path/pialert/db:/home/pi/pialert/db \
|
||||
-e TZ=Europe/Berlin \
|
||||
-e PORT=20211 \
|
||||
jokobsk/pi.alert:latest
|
||||
|
||||
```
|
||||
|
||||
> ⚠ Please note, don't use the `-d` parameter so you see the error when the container crashes. Use this error in your issue description.
|
||||
|
||||
## 3. Check the _dev image and open issues ❓
|
||||
|
||||
If possible, check if your issue got fixed in the `_dev` image before opening a new issue. The container is:
|
||||
|
||||
`jokobsk/pi.alert_dev:latest`
|
||||
|
||||
> ⚠ Please backup your DB and config beforehand!
|
||||
|
||||
Please also search [open issues](https://github.com/jokob-sk/Pi.Alert/issues).
|
||||
|
||||
## 4. Disable restart behavior 🛑
|
||||
|
||||
To prevent a Docker container from automatically restarting in a Docker Compose file, specify the restart policy as `no`:
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
your-service:
|
||||
image: your-image:tag
|
||||
restart: no
|
||||
# Other service configurations...
|
||||
```
|
||||
|
||||
## 📃Common issues
|
||||
|
||||
### Permissions
|
||||
|
||||
* If facing issues (AJAX errors, can't write to DB, empty screen, etc,) make sure permissions are set correctly, and check the logs under `/home/pi/pialert/front/log`.
|
||||
* To solve permission issues you can try setting the owner and group of the `pialert.db` by executing the following on the host system: `docker exec pialert chown -R www-data:www-data /home/pi/pialert/db/pialert.db`.
|
||||
* Map to local User and Group IDs. Specify the enviroment variables `HOST_USER_ID` and `HOST_USER_GID` if needed.
|
||||
* If still facing issues, try to map the pialert.db file (⚠ not folder) to `:/home/pi/pialert/db/pialert.db` (see [docker-compose Examples](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md#-docker-composeyml-examples) for details)
|
||||
|
||||
### Container restarts / crashes
|
||||
|
||||
* Check the logs for details. Often a required setting for a notification method is missing.
|
||||
|
||||
### unable to resolve host
|
||||
|
||||
* Check that your `SCAN_SUBNETS` variable is using the correct mask and `--interface` as outlined in the instructions above.
|
||||
|
||||
### Invalid JSON
|
||||
|
||||
Check the [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md) docs on how to proceed.
|
||||
|
||||
### sudo execution failing (e.g.: on arpscan) on a Raspberry Pi 4
|
||||
|
||||
> sudo: unexpected child termination condition: 0
|
||||
|
||||
Resolution based on [this issue](https://github.com/linuxserver/docker-papermerge/issues/4#issuecomment-1003657581)
|
||||
|
||||
```
|
||||
wget ftp.us.debian.org/debian/pool/main/libs/libseccomp/libseccomp2_2.5.3-2_armhf.deb
|
||||
sudo dpkg -i libseccomp2_2.5.3-2_armhf.deb
|
||||
```
|
||||
|
||||
The link above will probably break in time too. Go to https://packages.debian.org/sid/armhf/libseccomp2/download to find the new version number and put that in the url.
|
||||
24
docs/DEVICES_BULK_EDITING.md
Executable file
@@ -0,0 +1,24 @@
|
||||
# 📝Bulk-edit devices via CSV Export/Import
|
||||
|
||||
> [!NOTE]
|
||||
> As always, backup everything, just in case.
|
||||
|
||||
1. In `Maintenance` > `Backup / Restore` click the `CSV Export` button.
|
||||
2. A `devices.csv` is generated in the `/config` folder
|
||||
3. Edit the `devices.csv` file however you like.
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
> The file containing a list of Devices including the Network relationships between Network Nodes and connected devices. You can also trigger this by acessing this URL: `<your pialert url>/php/server/devices.php?action=ExportCSV` or via the `CSV Backup` plugin. (💡 You can schedule this)
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
> Keep Linux line endings (suggested editors: Nano, Notepad++)
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@ To edit device information:
|
||||
- Press the "Save" button
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> [Bulk-edit devices](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEVICES_BULK_EDITING.md) by using the `CSV Export` functionality in the `Maintenance` section.
|
||||
|
||||
|
||||
![Device Details][screen1]
|
||||
|
||||
|
||||
@@ -41,8 +46,7 @@ To edit device information:
|
||||
- **Alert All Events**: Send a notification in each event (connection,
|
||||
disconnection, IP Changed, ...)
|
||||
- **Alert Down**: Send a notification when the device is down
|
||||
- *(Userful with "always connected" devices: Router, AP, Camera, Alexa,
|
||||
...)*
|
||||
- *(Userful with "always connected" devices: Camera, Alexa,...)*
|
||||
- **Skip repeated notifications during**: Do not send more than one
|
||||
notification to this device for X hours
|
||||
- *(Useful to avoid notification saturation on devices that frequently
|
||||
@@ -81,9 +85,17 @@ decides to change the MAC).
|
||||
GPL 3.0
|
||||
[Read more here](../LICENSE.txt)
|
||||
|
||||
### Contact
|
||||
pi.alert.application@gmail.com
|
||||
### Contact
|
||||
|
||||
Always use the Issue tracker for the correct fork, for example:
|
||||
|
||||
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
|
||||
|
||||
- ➕ [Pull Request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-pull-requests-prs)
|
||||
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-feature-requests)
|
||||
- 🐛 [Issue guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-submitting-an-issue-or-bug)
|
||||
|
||||
|
||||
***Suggestions and comments are welcome***
|
||||
|
||||
|
||||
|
||||
46
docs/FRONTEND_DEVELOPMENT.md
Executable file
@@ -0,0 +1,46 @@
|
||||
# 🖼 Frontend development
|
||||
|
||||
This page contains tips for frontend development when extending PiAlert. Guiding principles are:
|
||||
|
||||
1. Maintainability
|
||||
2. Extendability
|
||||
3. Reusability
|
||||
4. Placing more functionality into Plugins and enhancing core Plugins functionality
|
||||
|
||||
That means that, when writing code, focus on reusing what's available instead of writing quick fixes. Or creating reusable functions, instead of bespoke functionaility.
|
||||
|
||||
## 🔍 Examples
|
||||
|
||||
Some examples how to apply the above:
|
||||
|
||||
> Example 1
|
||||
>
|
||||
> I want to implement a scan fucntion. Options would be:
|
||||
>
|
||||
> 1. To add a manual scan functionality to the `deviceDetails.php` page.
|
||||
> 2. To create a separate page that handles the execution of the scan.
|
||||
> 3. To create a configurable Plugin.
|
||||
>
|
||||
> From the above, number 3 would be the most appropriate solution. Then followed by number 2. Number 1 would be approved only in special circumstances.
|
||||
|
||||
> Example 2
|
||||
>
|
||||
> I want to change the behavior of the application. Options to implement this could be:
|
||||
>
|
||||
> 1. Hard-code the changes in the code.
|
||||
> 2. Implement the changes and add settings to influence the behavior in the `initialize.py` file so the user can adjust these.
|
||||
> 3. Implement the changes and add settings via a setting-only plugin.
|
||||
> 4. Implement the changes in a way so the behavior can be toggled on each plugin so the core capabilities of Plugins get extended.
|
||||
>
|
||||
> From the above, number 4 would be the most appropriate solution. Then followed by number 3. Number 1 or 2 would be approved only in special circumstances.
|
||||
|
||||
## 💡 Frontend tips
|
||||
|
||||
Some useful frontend JavaScript functions:
|
||||
|
||||
- `getDeviceDataByMacAddress(macAddress, devicesColumn)` - method to retrieve any device data (database column) based on MAC address in the frontend
|
||||
- `getString(string stringKey)` - method to retrieve translated strings in the frontend
|
||||
- `getSetting(string stringKey)` - method to retrieve settings in the frontend
|
||||
|
||||
|
||||
Check the [pialert_common.js](https://github.com/jokob-sk/Pi.Alert/blob/main-2023-06-10/front/js/pialert_common.js) file for more frontend functions.
|
||||
42
docs/HOME_ASSISTANT.md
Executable file
@@ -0,0 +1,42 @@
|
||||
# Overview
|
||||
|
||||
PiAlert comes with MQTT support, allowing you to show all detected devices as devices in Home Assistant. It also supplies a collection of stats, such as number of online devices.
|
||||
|
||||
## ⚠ Note
|
||||
|
||||
- Please note that discovery takes about ~10s per device.
|
||||
- Deleting of devices is not handled automatically. Please use [MQTT Explorer](https://mqtt-explorer.com/) to delete devices in the broker (Home Assistant), if needed.
|
||||
|
||||
|
||||
## 🧭 Guide
|
||||
|
||||
> 💡 This guide was tested only with the Mosquitto MQTT broker
|
||||
|
||||
1. Enable Mosquitto MQTT in Home Assistant by following the [documentation](https://www.home-assistant.io/integrations/mqtt/)
|
||||
|
||||
2. Configure a user name and password on your broker.
|
||||
|
||||
3. Note down the following details that you will need to configure PiAlert:
|
||||
- MQTT host url (usually your Home Assistant IP)
|
||||
- MQTT broker port
|
||||
- User
|
||||
- Password
|
||||
|
||||
4. Ope the `PiAlert` > `Settings` > `MQTT` settings group
|
||||
- Enable MQTT
|
||||
- Fill in the details from above
|
||||
- Fill in remaining settings as per description
|
||||
|
||||
|
||||
## 📷 Screenshots
|
||||
|
||||
| ![Screen 1][sensors] | ![Screen 2][history] |
|
||||
|----------------------|----------------------|
|
||||
| ![Screen 3][list] | ![Screen 4][overview] |
|
||||
|
||||
|
||||
[sensors]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Device-as-Sensors.png "sensors"
|
||||
[history]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Device-Presence-History.png "history"
|
||||
[list]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Devices-List.png "list"
|
||||
[overview]: /docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Overview-Card.png "overview"
|
||||
|
||||
49
docs/HW_INSTALL.md
Executable file
@@ -0,0 +1,49 @@
|
||||
# How to install PiAlert on the server hardware
|
||||
|
||||
To download and install PiAlert on the hardware/server directly use the `curl` or `wget` commands at the bottom of this page.
|
||||
|
||||
> [!NOTE]
|
||||
> This is an Experimental feature 🧪 and it relies on community support.
|
||||
>
|
||||
> There is no guarantee that the install script or any other script will gracefully handle other installed software.
|
||||
> Data loss is a possibility, **it is recommended to install PiAlert using the supplied Docker image**.
|
||||
|
||||
A warning to the installation method below: Piping to bash is [controversial](https://pi-hole.net/2016/07/25/curling-and-piping-to-bash) and may
|
||||
be dangerous, as you cannot see the code that's about to be executed on your system.
|
||||
|
||||
Alternatively you can download the installation script `install/install.sh` from the repository and check the code yourself (beware other scripts are
|
||||
downloaded too - only from this repo).
|
||||
|
||||
PiAlert will be installed in `home/pi/pialert/` and run on port number `20211`.
|
||||
|
||||
Some facts about what and where something will be changed/installed by the HW install setup (may not contain everything!):
|
||||
|
||||
- `/home/pi/pialert` directory will be deleted and newly created
|
||||
- `/home/pi/pialert` will contain the whole repository (downloaded by `install/install.sh`)
|
||||
- The default NGINX site `/etc/nginx/sites-enabled/default` will be disabled (sym-link deleted or backed up to `sites-available`)
|
||||
- `/var/www/html/pialert` directory will be deleted and newly created
|
||||
- `/etc/nginx/conf.d/pialert.conf` will be sym-linked to `/home/pi/pialert/install/pialert.conf`
|
||||
- Some files (IEEE device vendors info, ...) will be created in the directory where the installation script is executed
|
||||
|
||||
## Limitations
|
||||
|
||||
- No system service is provided. PiAlert must be started using `/home/pi/pialert/dockerfiles/start.sh`.
|
||||
- No checks for other running software is done.
|
||||
- Only tested to work on Debian Bookworm (Debian 12).
|
||||
- **EXPERIMENTAL** and not recommended way to install PiAlert.
|
||||
|
||||
## 📥 Installation via CURL
|
||||
|
||||
```bash
|
||||
curl -o install.sh https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/install/install.sh && sudo chmod +x install.sh && sudo ./install.sh
|
||||
```
|
||||
|
||||
## 📥 Installation via WGET
|
||||
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/install/install.sh -O install.sh && sudo chmod +x install.sh && sudo ./install.sh
|
||||
```
|
||||
|
||||
These commands will download the `install.sh` script from the GitHub repository, make it executable with `chmod`, and then run it using `./install.sh`.
|
||||
|
||||
Make sure you have the necessary permissions to execute the script.
|
||||
@@ -1,6 +1,6 @@
|
||||
## Icons overview
|
||||
|
||||
Icons are used to visually distinguish devices in the app in most of the device listing tables and the [network tree](/docs/NETWORK_TREE.md). Currently only free [Font Awesome](https://fontawesome.com/search?o=r&m=free) icons (up-to v 6.4.0) are supported (I have an unblockable [sponsorship goal](https://github.com/sponsors/jokob-sk) to add the material design icon pack).
|
||||
Icons are used to visually distinguish devices in the app in most of the device listing tables and the [network tree](/docs/NETWORK_TREE.md). Currently only free [Font Awesome](https://fontawesome.com/search?o=r&m=free) icons (up-to v 6.4.0) are supported.
|
||||
|
||||

|
||||
|
||||
@@ -8,6 +8,8 @@ Icons are used to visually distinguish devices in the app in most of the device
|
||||
|
||||
You can assign icons individually on each device in the Details tab.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- You can click into the `Icon` field or click the Pencil (2) icon in the above screenshot to enter any text. Only [free Font Awesome](https://fontawesome.com/search?o=r&m=free) icons in the following format will work:
|
||||
@@ -18,3 +20,13 @@ You can assign icons individually on each device in the Details tab.
|
||||
- If you want to mass-apply an icon to all devices of the same device type (Field marked (4) in the above screenshot), you can click the copy button (Marked (1) in the above screenshot). A confirmation prompt is displayed. If you proceed, icons of all devices set to the same device type as the current device, will be overwritten with the current device's icon.
|
||||
|
||||
- The dropdown (3) contains all icons already used in the app for device icons. You need to navigate away or refresh the page once you add a new icon.
|
||||
|
||||
## 🌟 Pro Font Awesome icons
|
||||
|
||||
If you own the premium package of Font Awesome icons you can mount it in your Docker container the following way:
|
||||
|
||||
```yaml
|
||||
/font-awesome:/home/pi/pialert/front/lib/AdminLTE/bower_components/font-awesome:ro
|
||||
```
|
||||
|
||||
You can use the full range of Font Awesome icons afterwards.
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
## How to setup your Network page
|
||||
|
||||
Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node).
|
||||
Make sure you have a root device with the MAC `Internet` (No other MAC addresses are currently supported as the root node) set to a network device type (e.g.: **Type**:`Router`).
|
||||
|
||||
> 💡 Tip: You can add dummy devices via the [Undiscoverables plugin](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/undiscoverables/README.md)
|
||||
|
||||
> 💡 Tip: Export your configuration of the Network and Devices once in a while via the Export CSV feature under **Maintenance** -> **Backup/Restore** -> **CSV Export**.
|
||||
|
||||
## ⚡Quick setup:
|
||||
|
||||
* Go to Devices > Device Details.
|
||||
* Find the device(s) you want to use as network devices (network nodes).
|
||||
* Set the Type of such a device to one of the following: AP, Firewall, Gateway, PLC, Powerline, Router, Switch, USB LAN Adapter, USB WIFI Adapter and WLAN.
|
||||
* Go to a Device you want to use as network device (network nodes, such as a Switch).
|
||||
* Set the **Type** of such a device to one of the following: AP, Firewall, Gateway, PLC, Powerline, Router, Switch, USB LAN Adapter, USB WIFI Adapter and WLAN (you can create a custom network type device with in Settings -> General -> `NETWORK_DEVICE_TYPES`).
|
||||
* Save and go to Network where the devices you've marked as network devices (by selecting the Type as mentioned above) will show up as tabs.
|
||||
* You can now assign the Unassigend devices to the correct network node.
|
||||
* You can now assign the Unassigend devices to the network node.
|
||||
* If port is empty or 0 a wifi icon is rendered, otherwise a ethernet port icon.
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
>
|
||||
> [Bulk-edit devices](/docs/DEVICES_BULK_EDITING.md) by using the `CSV Export` functionality in the `Maintenance` section. You can use this to fix `Internet` node assignment issues.
|
||||
|
||||
## 🔍Detailed example:
|
||||
|
||||
In this example you will setup a device named `rapberrypi` as a `Switch` in our network.
|
||||
|
||||
### 1) Device details page
|
||||
### 1. Device details page
|
||||
|
||||
- Go to the `Devices` (1) page:
|
||||
|
||||
@@ -24,23 +32,23 @@ In this example you will setup a device named `rapberrypi` as a `Switch` in our
|
||||
- In the (2) `Details` tab navigate to the the `Type` (3) dropdown and select the type `Switch` (4).
|
||||
|
||||
> Note: Only the following device types will show up as selectable Network nodes ( = devices you can connect other devices to):
|
||||
> AP, Firewall, Gateway, PLC, Powerline, Router, Switch, USB LAN Adapter, USB WIFI Adapter and WLAN.
|
||||
> AP, Firewall, Gateway, Hypervisor, PLC, Powerline, Router, Switch, USB LAN Adapter, USB WIFI Adapter and WLAN. Custom types can be added via the `NETWORK_DEVICE_TYPES` setting.
|
||||
|
||||
- Assign a device to your root device from the `Node` (5) dropdown which has the MAC `Internet` (6) (Your name may differ, but the MAC needs to be set to `Internet` - this is done by default).
|
||||
|
||||
- Save your changes (7)
|
||||
|
||||
### 1) Network page
|
||||
### 2. Network page
|
||||
|
||||
- Navigate to your `Network` (1) page:
|
||||
|
||||

|
||||
|
||||
- Notice the newly added `raspberrypi` (2) tab which now represents a network node, also showing up in the tree (3).
|
||||
- As we asssigned the `raspberrypi` in the previous 1) Device details page section to the `Internet` parent network node in step (6), the link is also showing up in the tree diagram (4)
|
||||
- As we asssigned the `raspberrypi` in the previous (1) Device details page section to the `Internet` parent network node in step (6), the link is also showing up in the tree diagram (4)
|
||||
- We can now assign the device `(AppleTV)` (5) to this `raspberrypi` node, representing a network Switch in this example
|
||||
|
||||
### 1) Network page with 2 levels
|
||||
### 3. Network page with 2 levels
|
||||
|
||||
- After clicking the `Assign` button in the previous section, the `(AppleTV)` (1) device is now connected to our `raspberrypi` (2).
|
||||
|
||||
@@ -52,3 +60,4 @@ In this example you will setup a device named `rapberrypi` as a `Switch` in our
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ WIFI's**, in this way, Pi.Alert will be able to identify the device, and it
|
||||
will not identify it as a new device every so often (every time IOS or Android
|
||||
decides to change the MAC).
|
||||
|
||||
**Random MACs** are recognized by the characters "2", "6", "A", or "E" as the 2nd character in the Mac address. You can disable specific prefixes to be detected as random MAC addresses by specifying the `UI_NOT_RANDOM_MAC` setting.
|
||||
|
||||
## IOS
|
||||
![ios][ios]
|
||||
|
||||
@@ -33,7 +35,14 @@ decides to change the MAC).
|
||||
[Read more here](../LICENSE.txt)
|
||||
|
||||
### Contact
|
||||
pi.alert.application@gmail.com
|
||||
Always use the Issue tracker for the correct fork, for example:
|
||||
|
||||
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
|
||||
|
||||
- ➕ [Pull Request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-pull-requests-prs)
|
||||
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-feature-requests)
|
||||
- 🐛 [Issue guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-submitting-an-issue-or-bug)
|
||||
|
||||
|
||||
***Suggestions and comments are welcome***
|
||||
|
||||
|
||||
104
docs/README.md
@@ -1,72 +1,105 @@
|
||||
## Documentation overview
|
||||
|
||||
In the app hover-over settings or fields/labels or click blue in-app ❔ (question-mark) icons to get to relevant documentation pages.
|
||||
<details>
|
||||
<summary>:information_source: In the app hover over settings or fields/labels or click blue in-app ❔ (question-mark) icons to get to relevant documentation pages.</summary>
|
||||
|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
There is also an in-app Help / FAQ section that should be answering frequently asked questions.
|
||||
|
||||
### 📥 Installation
|
||||
|
||||
⚠ Only tested as a [docker container - follow these instructions here](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md).
|
||||
> Check out [leiweibau's fork](https://github.com/leiweibau/Pi.Alert/) if you want to install Pi.Alert on the server directly or original instructions for [pucherot's original code](https://github.com/pucherot/Pi.Alert/)
|
||||
#### 🐳 Docker (Fully supported)
|
||||
|
||||
- The main installation method is as a [docker container - follow these instructions here](https://github.com/jokob-sk/Pi.Alert/blob/main/dockerfiles/README.md).
|
||||
|
||||
#### 💻 Bare-metal / On-server (Experimental/community supported 🧪)
|
||||
|
||||
- [(Experimental 🧪) On-hardware instructions](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/HW_INSTALL.md)
|
||||
|
||||
- Alternative bare-metal install forks:
|
||||
- [leiweibau's fork](https://github.com/leiweibau/Pi.Alert/) (maintained)
|
||||
- [pucherot's original code](https://github.com/pucherot/Pi.Alert/) (un-maintained)
|
||||
|
||||
### 📚 Table of contents
|
||||
|
||||
#### Popular/Suggested
|
||||
#### 📥 Initial Setup
|
||||
|
||||
- [API endpoints details](/docs/API.md)
|
||||
- [Plugin system details and how to develop your own](/front/plugins/README.md)
|
||||
- [Network tree map configuration](/docs/NETWORK_TREE.md)
|
||||
- [Gmail as SMTP server for sending emails](/docs/SMTP_GMAIL.md)
|
||||
- [Subnets and vlans configuration for arp-scan](/docs/SUBNETS.md)
|
||||
- [Subnets and VLANs configuration for arp-scan](/docs/SUBNETS.md)
|
||||
- [SMTP server config](/docs/SMTP.md)
|
||||
- [Custom Icon configuration and support](/docs/ICONS.md)
|
||||
- [Better name resolution with Reverse DNS](/docs/REVERSE_DNS.md)
|
||||
- [Network treemap configuration](/docs/NETWORK_TREE.md)
|
||||
|
||||
#### System Management
|
||||
#### 🐛 Debugging help & tips
|
||||
|
||||
- [Debugging tips](/docs/DEBUG_TIPS.md)
|
||||
- [Debugging UI not showing](/docs/WEB_UI_PORT_DEBUG.md)
|
||||
- [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md)
|
||||
- [Troubleshooting Plugins](/docs/DEBUG_PLUGINS.md)
|
||||
|
||||
#### 🔝 Popular/Suggested
|
||||
|
||||
- [Home Assistant](/docs/HOME_ASSISTANT.md)
|
||||
- [Bulk edit devices](/docs/DEVICES_BULK_EDITING.md)
|
||||
|
||||
#### ⚙ System Management
|
||||
|
||||
- [Manage devices (legacy docs)](/docs/DEVICE_MANAGEMENT.md)
|
||||
- [Random MAC/MAC icon meaning (legacy docs)](/docs/RANDOM_MAC.md)
|
||||
- [Custom Icons configuration and support](/docs/ICONS.md)
|
||||
|
||||
#### Examples
|
||||
|
||||
#### 🔎 Examples
|
||||
|
||||
- [N8N webhook example](/docs/WEBHOOK_N8N.md)
|
||||
|
||||
#### Misc
|
||||
#### ♻ Misc
|
||||
|
||||
- [New Version notifications](/docs/VERSIONS.md)
|
||||
- [Version history (legacy)](/docs/VERSIONS_HISTORY.md)
|
||||
- [Invalid JSON errors debug help](/docs/DEBUG_INVALID_JSON.md)
|
||||
- [Reverse proxy (Nginx, Apache, SWAG)](/docs/REVERSE_PROXY.md)
|
||||
|
||||
#### 👩💻For Developers👨💻
|
||||
|
||||
- [APP code structure](/pialert/README.md)
|
||||
- [Database structure](/docs/DATABASE.md)
|
||||
- [API endpoints details](/docs/API.md)
|
||||
- [Plugin system details and how to develop your own](/front/plugins/README.md)
|
||||
- [Settings system](/docs/SETTINGS_SYSTEM.md)
|
||||
- [New Version notifications](/docs/VERSIONS.md)
|
||||
- [Frontend development tips](/docs/FRONTEND_DEVELOPMENT.md)
|
||||
- [Webhook secrets](/docs/WEBHOOK_SECRET.md)
|
||||
|
||||
Feel free to suggest or submit new docs via a PR.
|
||||
|
||||
## 👨💻 Development priorities
|
||||
|
||||
Highest to lowest:
|
||||
Priorities from highest to lowest:
|
||||
|
||||
* Fixing core functionality bugs not solvable with workarounds
|
||||
* New core functionality unlocking other opportunities (e.g.: plugins)
|
||||
* Refactoring enabling faster implementation of future functionality
|
||||
* UI improvements
|
||||
* 🔼 Fixing core functionality bugs not solvable with workarounds
|
||||
* 🔵 New core functionality unlocking other opportunities (e.g.: plugins)
|
||||
* 🔵 Refactoring enabling faster implementation of future functionality
|
||||
* 🔽 (low) UI functionality & improvements (PRs welcome 😉)
|
||||
|
||||
Design philosophy: Focus on core functionality and leverage existing apps and tools to make PiAlert integratable into other workflows.
|
||||
Design philosophy: Focus on core functionality and leverage existing apps and tools to make PiAlert integrate into other workflows.
|
||||
|
||||
Examples:
|
||||
|
||||
1. Supporting apprise makes more sense than implementing multiple individual notification gateways
|
||||
2. Implementing regular expressions support across settings for validation makes more sense than validating one setting with a specific expression.
|
||||
2. Implementing regular expression support across settings for validation makes more sense than validating one setting with a specific expression.
|
||||
|
||||
UI specific requests are low priority as the framework picked by the original developer is not very extensible (and afaik doesn't support components) and has limited mobile support. Also I argue the value proposition is smaller than working on something else.
|
||||
UI-specific requests are a low priority as the framework picked by the original developer is not very extensible (and afaik doesn't support components) and has limited mobile support. Also, I argue the value proposition is smaller than working on something else.
|
||||
|
||||
Feel free to submit PRs if interested. try to **keep the PRs small/on topic** so they are easier to review and approve.
|
||||
Feel free to submit PRs if interested. try to **keep the PRs small/on-topic** so they are easier to review and approve.
|
||||
|
||||
That being said, I'd reconsider if more people and or recurring sponsors file a request 😉.
|
||||
|
||||
## 🙏 Feature requests
|
||||
|
||||
Please be as detailed as possible with **workarounds** you considered and why a native feature is the better way. This gives me better context and will make it more likely to be implemented. Ideally a feature request should be in the format "I want to be able to do XYZ so that ZYX. I considered these approaches XYZ".
|
||||
Please be as detailed as possible with **workarounds** you considered and why a native feature is the better way. This gives me better context and will make it more likely to be implemented. Ideally, a feature request should be in the format "I want to be able to do XYZ so that ZYX. I considered these approaches XYZ".
|
||||
|
||||
## ➕ Pull-requests (PRs)
|
||||
## ➕ Pull requests (PRs)
|
||||
|
||||
If you submit a PR please:
|
||||
|
||||
@@ -76,16 +109,27 @@ If you submit a PR please:
|
||||
4. New features code should ideally be re-usable for different purposes, not be for a very narrow use-case.
|
||||
5. New functionality should ideally be implemented via the Plugins system, if possible.
|
||||
|
||||
Soem additional context:
|
||||
Suggested test cases:
|
||||
|
||||
- Blank setup with no DB or config
|
||||
- Existing DB / config
|
||||
- Sending a notification (e. g. Delete a device and wait for a scan to run) and testing all notification gateways, especially:
|
||||
- Email, Apprise (e.g. via Telegram), webhook (e.g. via Discord), MQTT (e.g. via Home Assistant)
|
||||
- Saving settings
|
||||
- Test a couple of plugins
|
||||
- Check the Error log for anything unusual
|
||||
|
||||
Some additional context:
|
||||
|
||||
* Permanent settings/config is stored in the `pialert.conf` file
|
||||
* Currently temporary (session?) settings are stored in the `Parameters` DB table as key - value pairs. This table is wiped during a container rebuild/restart and it's values re-initialized from cookies / session data from the browser.
|
||||
* Currently temporary (session?) settings are stored in the `Parameters` DB table as key-value pairs. This table is wiped during a container rebuild/restart and its values are re-initialized from cookies/session data from the browser.
|
||||
|
||||
## 🐛 Submitting an issue or bug
|
||||
|
||||
Before submitting a new issue please spend a couple of minutes on research:
|
||||
|
||||
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/tree/main/dockerfiles#-common-issues)
|
||||
* Check [🛑 Common issues](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md#common-issues)
|
||||
* Check [💡 Closed issues](https://github.com/jokob-sk/Pi.Alert/issues?q=is%3Aissue+is%3Aclosed) if a similar issue was solved in the past.
|
||||
* When submitting an issue ❗[enable debug](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md)❗
|
||||
|
||||
⚠ Please follow the pre-defined issue template to resolve your issue faster.
|
||||
|
||||
66
docs/REVERSE_DNS.md
Executable file
@@ -0,0 +1,66 @@
|
||||
## Setting up better name discovery with Reverse DNS
|
||||
|
||||
If you are running a DNS server, such as **AdGuard**, set up **Private reverse DNS servers** for a better name resolution on your network. Enabling this setting will enable PiAlert to execute dig and nslookup commands to automatically resolve device names based on their IP addresses.
|
||||
|
||||
|
||||
> Example 1: Reverse DNS `disabled`
|
||||
>
|
||||
> ```
|
||||
> jokob@Synology-NAS:/$ nslookup 192.168.1.58
|
||||
> ** server can't find 58.1.168.192.in-addr.arpa: NXDOMAIN
|
||||
>
|
||||
> ```
|
||||
|
||||
> Example 2: Reverse DNS `enabled`
|
||||
>
|
||||
> ```
|
||||
> jokob@Synology-NAS:/$ nslookup 192.168.1.58
|
||||
> 45.1.168.192.in-addr.arpa name = jokob-NUC.localdomain.
|
||||
> ```
|
||||
|
||||
### Enabling reverse DNS in AdGuard
|
||||
|
||||
1. Navigate to **Settings** -> **DNS Settings**
|
||||
2. Locate **Private reverse DNS servers**
|
||||
3. Enter your router IP address, such as `192.168.1.1`
|
||||
4. Make sure you have **Use private reverse DNS resolvers** ticked.
|
||||
5. Click **Apply** to save your settings.
|
||||
|
||||
|
||||
### Using a custom resolv.conf file
|
||||
|
||||
You can configure a custom **/etc/resolv.conf** file in **docker-compose.yml** and set the nameserver to your LAN DNS server (e.g.: Pi-Hole). See the relevant [resolv.conf man](https://www.man7.org/linux/man-pages/man5/resolv.conf.5.html) entry for details.
|
||||
|
||||
#### docker-compose.yml:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
pialert:
|
||||
container_name: pialert
|
||||
image: "jokobsk/pi.alert:latest"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./config/pialert.conf:/home/pi/pialert/config/pialert.conf
|
||||
- ./pialert_db:/home/pi/pialert/db
|
||||
- ./log:/home/pi/pialert/front/log
|
||||
- ./config/resolv.conf:/etc/resolv.conf # Mapping the /resolv.conf file for better name resolution
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- PORT=20211
|
||||
- HOST_USER_ID=1000
|
||||
- HOST_USER_GID=1000
|
||||
ports:
|
||||
- "20211:20211"
|
||||
network_mode: host
|
||||
```
|
||||
|
||||
#### ./config/resolv.conf:
|
||||
|
||||
The most important below is the `nameserver` entry (you can add multiple):
|
||||
|
||||
```
|
||||
nameserver 192.168.178.11
|
||||
options edns0 trust-ad
|
||||
search example.com
|
||||
```
|
||||
479
docs/REVERSE_PROXY.md
Executable file
@@ -0,0 +1,479 @@
|
||||
# Reverse Proxy Configuration
|
||||
|
||||
> Submitted by amazing [cvc90](https://github.com/cvc90) 🙏
|
||||
|
||||
## NGINX HTTP Configuration (Direct Path)
|
||||
|
||||
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
server_name pi.alert;
|
||||
proxy_preserve_host on;
|
||||
proxy_pass http://localhost:20211/;
|
||||
proxy_pass_reverse http://localhost:20211/;
|
||||
}
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`nginx -s reload` or `systemctl restart nginx`
|
||||
|
||||
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## NGINX HTTP Configuration (Sub Path)
|
||||
|
||||
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
server_name pi.alert;
|
||||
proxy_preserve_host on;
|
||||
location ^~ /pi.alert/ {
|
||||
proxy_pass http://localhost:20211/;
|
||||
proxy_pass_reverse http://localhost:20211/;
|
||||
proxy_redirect ~^/(.*)$ /pi.alert/$1;
|
||||
rewrite ^/pi.alert/?(.*)$ /$1 break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`nginx -s reload` or `systemctl restart nginx`
|
||||
|
||||
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## NGINX HTTP Configuration (Sub Path) with module ngx_http_sub_module
|
||||
|
||||
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
server_name pi.alert;
|
||||
proxy_preserve_host on;
|
||||
location ^~ /pi.alert/ {
|
||||
proxy_pass http://localhost:20211/;
|
||||
proxy_pass_reverse http://localhost:20211/;
|
||||
proxy_redirect ~^/(.*)$ /pi.alert/$1;
|
||||
rewrite ^/pi.alert/?(.*)$ /$1 break;
|
||||
sub_filter_once off;
|
||||
sub_filter_types *;
|
||||
sub_filter 'href="/' 'href="/pi.alert/';
|
||||
sub_filter '(?>$host)/css' '/pi.alert/css';
|
||||
sub_filter '(?>$host)/js' '/pi.alert/js';
|
||||
sub_filter '/img' '/pi.alert/img';
|
||||
sub_filter '/lib' '/pi.alert/lib';
|
||||
sub_filter '/php' '/pi.alert/php';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`nginx -s reload` or `systemctl restart nginx`
|
||||
|
||||
4. Once NGINX restarts, you should be able to access the proxy website at http://pi.alert/pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
**NGINX HTTPS Configuration (Direct Path)**
|
||||
|
||||
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 443;
|
||||
server_name pi.alert;
|
||||
SSLEngine On;
|
||||
SSLCertificateFile /etc/ssl/certs/pi.alert.pem;
|
||||
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key;
|
||||
proxy_preserve_host on;
|
||||
proxy_pass http://localhost:20211/;
|
||||
proxy_pass_reverse http://localhost:20211/;
|
||||
}
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`nginx -s reload` or `systemctl restart nginx`
|
||||
|
||||
4. Once NGINX restarts, you should be able to access the proxy website at https://pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
**NGINX HTTPS Configuration (Sub Path)**
|
||||
|
||||
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 443;
|
||||
server_name pi.alert;
|
||||
SSLEngine On;
|
||||
SSLCertificateFile /etc/ssl/certs/pi.alert.pem;
|
||||
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key;
|
||||
location ^~ /pi.alert/ {
|
||||
proxy_pass http://localhost:20211/;
|
||||
proxy_pass_reverse http://localhost:20211/;
|
||||
proxy_redirect ~^/(.*)$ /pi.alert/$1;
|
||||
rewrite ^/pi.alert/?(.*)$ /$1 break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`nginx -s reload` or `systemctl restart nginx`
|
||||
|
||||
4. Once NGINX restarts, you should be able to access the proxy website at https://pi.alert/pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## NGINX HTTPS Configuration (Sub Path) with module ngx_http_sub_module
|
||||
|
||||
1. On your NGINX server, create a new file called /etc/nginx/sites-available/pialert
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 443;
|
||||
server_name pi.alert;
|
||||
SSLEngine On;
|
||||
SSLCertificateFile /etc/ssl/certs/pi.alert.pem;
|
||||
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key;
|
||||
location ^~ /pi.alert/ {
|
||||
proxy_pass http://localhost:20211/;
|
||||
proxy_pass_reverse http://localhost:20211/;
|
||||
proxy_redirect ~^/(.*)$ /pi.alert/$1;
|
||||
rewrite ^/pi.alert/?(.*)$ /$1 break;
|
||||
sub_filter_once off;
|
||||
sub_filter_types *;
|
||||
sub_filter 'href="/' 'href="/pi.alert/';
|
||||
sub_filter '(?>$host)/css' '/pi.alert/css';
|
||||
sub_filter '(?>$host)/js' '/pi.alert/js';
|
||||
sub_filter '/img' '/pi.alert/img';
|
||||
sub_filter '/lib' '/pi.alert/lib';
|
||||
sub_filter '/php' '/pi.alert/php';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`nginx -s reload` or `systemctl restart nginx`
|
||||
|
||||
4. Once NGINX restarts, you should be able to access the proxy website at https://pi.alert/pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## Apache HTTP Configuration (Direct Path)
|
||||
|
||||
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerName pi.alert
|
||||
ProxyPreserveHost On
|
||||
ProxyPass / http://localhost:20211/
|
||||
ProxyPassReverse / http://localhost:20211/
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`a2ensite pialert` or `service apache2 reload`
|
||||
|
||||
4. Once Apache restarts, you should be able to access the proxy website at http://pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## Apache HTTP Configuration (Sub Path)
|
||||
|
||||
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerName pi.alert
|
||||
location ^~ /pi.alert/ {
|
||||
ProxyPreserveHost On
|
||||
ProxyPass / http://localhost:20211/
|
||||
ProxyPassReverse / http://localhost:20211/
|
||||
}
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`a2ensite pialert` or `service apache2 reload`
|
||||
|
||||
4. Once Apache restarts, you should be able to access the proxy website at http://pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## Apache HTTPS Configuration (Direct Path)
|
||||
|
||||
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
<VirtualHost *:443>
|
||||
ServerName pi.alert
|
||||
SSLEngine On
|
||||
SSLCertificateFile /etc/ssl/certs/pi.alert.pem
|
||||
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key
|
||||
ProxyPreserveHost On
|
||||
ProxyPass / http://localhost:20211/
|
||||
ProxyPassReverse / http://localhost:20211/
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`a2ensite pialert` or `service apache2 reload`
|
||||
|
||||
4. Once Apache restarts, you should be able to access the proxy website at https://pi.alert/
|
||||
|
||||
<br>
|
||||
|
||||
## Apache HTTPS Configuration (Sub Path)
|
||||
|
||||
1. On your Apache server, create a new file called /etc/apache2/sites-available/pialert.conf.
|
||||
|
||||
2. In this file, paste the following code:
|
||||
|
||||
```
|
||||
<VirtualHost *:443>
|
||||
ServerName pi.alert
|
||||
SSLEngine On
|
||||
SSLCertificateFile /etc/ssl/certs/pi.alert.pem
|
||||
SSLCertificateKeyFile /etc/ssl/private/pi.alert.key
|
||||
location ^~ /pi.alert/ {
|
||||
ProxyPreserveHost On
|
||||
ProxyPass / http://localhost:20211/
|
||||
ProxyPassReverse / http://localhost:20211/
|
||||
}
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
3. Activate the new website by running the following command:
|
||||
|
||||
`a2ensite pialert` or `service apache2 reload`
|
||||
|
||||
4. Once Apache restarts, you should be able to access the proxy website at https://pi.alert/pi.alert/
|
||||
|
||||
## Reverse proxy example by using LinuxServer's SWAG container.
|
||||
|
||||
> Submitted by [s33d1ing](https://github.com/s33d1ing). 🙏
|
||||
|
||||
## [linuxserver/swag](https://github.com/linuxserver/docker-swag)
|
||||
|
||||
In the SWAG container create `/config/nginx/proxy-confs/pialert.subfolder.conf` with the following contents:
|
||||
|
||||
``` nginx
|
||||
## Version 2023/02/05
|
||||
# make sure that your pialert container is named pialert
|
||||
# pialert does not require a base url setting
|
||||
|
||||
# Since Pi.Alert uses a Host network, you may need to use the IP address of the system running Pi.Alert for $upstream_app.
|
||||
|
||||
location /pialert {
|
||||
return 301 $scheme://$host/pialert/;
|
||||
}
|
||||
|
||||
location ^~ /pialert/ {
|
||||
# enable the next two lines for http auth
|
||||
#auth_basic "Restricted";
|
||||
#auth_basic_user_file /config/nginx/.htpasswd;
|
||||
|
||||
# enable for ldap auth (requires ldap-server.conf in the server block)
|
||||
#include /config/nginx/ldap-location.conf;
|
||||
|
||||
# enable for Authelia (requires authelia-server.conf in the server block)
|
||||
#include /config/nginx/authelia-location.conf;
|
||||
|
||||
# enable for Authentik (requires authentik-server.conf in the server block)
|
||||
#include /config/nginx/authentik-location.conf;
|
||||
|
||||
include /config/nginx/proxy.conf;
|
||||
include /config/nginx/resolver.conf;
|
||||
|
||||
set $upstream_app pialert;
|
||||
set $upstream_port 20211;
|
||||
set $upstream_proto http;
|
||||
|
||||
proxy_pass $upstream_proto://$upstream_app:$upstream_port;
|
||||
proxy_set_header Accept-Encoding "";
|
||||
|
||||
proxy_redirect ~^/(.*)$ /pialert/$1;
|
||||
rewrite ^/pialert/?(.*)$ /$1 break;
|
||||
|
||||
sub_filter_once off;
|
||||
sub_filter_types *;
|
||||
|
||||
sub_filter 'href="/' 'href="/pialert/';
|
||||
|
||||
sub_filter '(?>$host)/css' '/pialert/css';
|
||||
sub_filter '(?>$host)/js' '/pialert/js';
|
||||
|
||||
sub_filter '/img' '/pialert/img';
|
||||
sub_filter '/lib' '/pialert/lib';
|
||||
sub_filter '/php' '/pialert/php';
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Traefik
|
||||
|
||||
> Submitted by [Isegrimm](https://github.com/Isegrimm) 🙏 (based on this [discussion](https://github.com/jokob-sk/Pi.Alert/discussions/449#discussioncomment-7281442))
|
||||
|
||||
Asuming the user already has a working Traefik setup, this is what's needed to make Pi.Alert work at a URL like www.domain.com/pialert/.
|
||||
|
||||
Note: Everything in these configs assumes '**www.domain.com**' as your domainname and '**section31**' as an arbitrary name for your certificate setup. You will have to substitute these with your own.
|
||||
|
||||
Also, I use the prefix '**pialert**'. If you want to use another prefix, change it in these files: dynamic.toml and default.
|
||||
|
||||
Content of my yaml-file (this is the generic Traefik config, which defines which ports to listen on, redirect http to https and sets up the certificate process).
|
||||
It also contains Authelia, which I use for authentication.
|
||||
This part contains nothing specific to Pi.Alert.
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
traefik:
|
||||
image: traefik
|
||||
container_name: traefik
|
||||
command:
|
||||
- "--api=true"
|
||||
- "--api.insecure=true"
|
||||
- "--api.dashboard=true"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
|
||||
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
- "--providers.file.filename=/traefik-config/dynamic.toml"
|
||||
- "--providers.file.watch=true"
|
||||
- "--log.level=ERROR"
|
||||
- "--certificatesresolvers.section31.acme.email=postmaster@domain.com"
|
||||
- "--certificatesresolvers.section31.acme.storage=/traefik-config/acme.json"
|
||||
- "--certificatesresolvers.section31.acme.httpchallenge=true"
|
||||
- "--certificatesresolvers.section31.acme.httpchallenge.entrypoint=web"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
- /appl/docker/traefik/config:/traefik-config
|
||||
depends_on:
|
||||
- authelia
|
||||
restart: unless-stopped
|
||||
authelia:
|
||||
container_name: authelia
|
||||
image: authelia/authelia:latest
|
||||
ports:
|
||||
- "9091:9091"
|
||||
volumes:
|
||||
- /appl/docker/authelia:/config
|
||||
restart: u
|
||||
nless-stopped
|
||||
```
|
||||
Snippet of the dynamic.toml file (referenced in the yml-file above) that defines the config for Pi.Alert:
|
||||
The following are self-defined keywords, everything else is traefik keywords:
|
||||
- pialert-router
|
||||
- pialert-service
|
||||
- auth
|
||||
- pialert-stripprefix
|
||||
|
||||
|
||||
```toml
|
||||
[http.routers]
|
||||
[http.routers.pialert-router]
|
||||
entryPoints = ["websecure"]
|
||||
rule = "Host(`www.domain.com`) && PathPrefix(`/pialert`)"
|
||||
service = "pialert-service"
|
||||
middlewares = "auth,pialert-stripprefix"
|
||||
[http.routers.pialert-router.tls]
|
||||
certResolver = "section31"
|
||||
[[http.routers.pialert-router.tls.domains]]
|
||||
main = "www.domain.com"
|
||||
|
||||
[http.services]
|
||||
[http.services.pialert-service]
|
||||
[[http.services.pialert-service.loadBalancer.servers]]
|
||||
url = "http://internal-ip-address:20211/"
|
||||
|
||||
[http.middlewares]
|
||||
[http.middlewares.auth.forwardAuth]
|
||||
address = "http://authelia:9091/api/verify?rd=https://www.domain.com/authelia/"
|
||||
trustForwardHeader = true
|
||||
authResponseHeaders = ["Remote-User", "Remote-Groups", "Remote-Name", "Remote-Email"]
|
||||
[http.middlewares.pialert-stripprefix.stripprefix]
|
||||
prefixes = "/pialert"
|
||||
forceSlash = false
|
||||
|
||||
```
|
||||
To make Pi.Alert work with this setup I modified the default file at `/etc/nginx/sites-available/default` in the docker container by copying it to my local filesystem, adding the changes as specified by [cvc90](https://github.com/cvc90) and mounting the new file into the docker container, overwriting the original one. By mapping the file instead of changing the file in-place, the changes persist if an updated dockerimage is pulled. This is also a downside when the default file is updated, so I only use this as a temporary solution, until the dockerimage is updated with this change.
|
||||
|
||||
Default-file:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80 default_server;
|
||||
root /var/www/html;
|
||||
index index.php;
|
||||
#rewrite /pialert/(.*) / permanent;
|
||||
add_header X-Forwarded-Prefix "/pialert" always;
|
||||
proxy_set_header X-Forwarded-Prefix "/pialert";
|
||||
|
||||
location ~* \.php$ {
|
||||
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_connect_timeout 75;
|
||||
fastcgi_send_timeout 600;
|
||||
fastcgi_read_timeout 600;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Mapping the updated file (on the local filesystem at `/appl/docker/pialert/default`) into the docker container:
|
||||
|
||||
|
||||
```bash
|
||||
docker run -d --rm --network=host \
|
||||
--name=pi.alert \
|
||||
-v /appl/docker/pialert/config:/home/pi/pialert/config \
|
||||
-v /appl/docker/pialert/db:/home/pi/pialert/db \
|
||||
-v /appl/docker/pialert/default:/etc/nginx/sites-available/default \
|
||||
-e TZ=Europe/Amsterdam \
|
||||
-e PORT=20211 \
|
||||
jokobsk/pi.alert:latest
|
||||
|
||||
```
|
||||
|
||||
77
docs/SETTINGS_SYSTEM.md
Executable file
@@ -0,0 +1,77 @@
|
||||
## ⚙ Setting system
|
||||
|
||||
This is an explanation how settings are handled intended for anyone thinking about writing their own plugin or contributing to the project.
|
||||
|
||||
If you are a user of the app, settings should be described in the `Settings` section of the app. Open an issue if you'd like to clarify any of the settings.
|
||||
|
||||
### 🛢 Data storage
|
||||
|
||||
The source of truth for user-defined values is the `pialert.conf` file. Editing the file makes the App overwrite values in the `Settings` database table and in the `table_settings.json` file.
|
||||
|
||||
#### Settings database table
|
||||
|
||||
The `Settings` database table contains settings for App run purposes. The table is recreated every time the App restarts. The settings are loaded from the source-of-truth, that is the `pialert.conf` file. A high-level overview on the database structure can be found in the [database documentation](/docs/DATABASE.md).
|
||||
|
||||
#### table_settings.json
|
||||
|
||||
This is the [API endpoint](/docs/API.md) that reflects the state of the `Settings` database table. Settings can be accessed with the:
|
||||
|
||||
* `getSetting(key)` JavaScript method
|
||||
|
||||
The json file is also cached on the client-side local storage of the browser.
|
||||
|
||||
#### pialert.conf
|
||||
|
||||
> [!NOTE]
|
||||
> This is the source of truth for settings. User-defined values in this files always override default values specified in the Plugin definition.
|
||||
|
||||
The App generates two `pialert.conf` entries for every setting (Since version 23.8+). One entry is the setting value, the second is the `__metadata` associated with the setting. This `__metadata` entry contains the full setting definition in JSON format. Currently unused, but intended to be used in future to extend the Settings system.
|
||||
|
||||
#### Plugin settings
|
||||
|
||||
> [!NOTE]
|
||||
> This is the preferred way adding settings going forward. I'll be likely migrating all app settings into plugin-based settings.
|
||||
|
||||
Plugin settings are loaded dynamically from the `config.json` of individual plugins. If a setting isn't defined in the `pialert.conf` file, it is initialized via the `default_value` property of a setting from the `config.json` file. Check the [Plugins documentation](https://github.com/jokob-sk/Pi.Alert/blob/main/front/plugins/README.md#-setting-object-structure), section `⚙ Setting object structure` for details on the structure of the setting.
|
||||
|
||||
![Screen 1][screen1]
|
||||
|
||||
### Settings Process flow
|
||||
|
||||
The process flow is mostly managed by the [initialise.py](/pialert/initialise.py) file.
|
||||
|
||||
The script is responsible for reading user-defined values from a configuration file (`pialert.conf`), initializing settings, and importing them into a database. It also handles plugins and their configurations.
|
||||
|
||||
Here's a high-level description of the code:
|
||||
|
||||
1. Function Definitions:
|
||||
- `ccd`: This function is used to handle user-defined settings and configurations. It takes several parameters related to the setting's name, default value, input type, options, group, and more. It saves the settings and their metadata in different lists (`conf.mySettingsSQLsafe` and `conf.mySettings`).
|
||||
|
||||
- `importConfigs`: This function is the main entry point of the script. It imports user settings from a configuration file, processes them, and saves them to the database.
|
||||
|
||||
- `read_config_file`: This function reads the configuration file (`pialert.conf`) and returns a dictionary containing the key-value pairs from the file.
|
||||
|
||||
2. Importing Configuration and Initializing Settings:
|
||||
- The `importConfigs` function starts by checking the modification time of the configuration file to determine if it needs to be re-imported. If the file has not been modified since the last import, the function skips the import process.
|
||||
|
||||
- The function reads the configuration file using the `read_config_file` function, which returns a dictionary of settings.
|
||||
|
||||
- The script then initializes various user-defined settings using the `ccd` function, based on the values read from the configuration file. These settings are categorized into groups such as "General," "Email," "Webhooks," "Apprise," and more.
|
||||
|
||||
3. Plugin Handling:
|
||||
- The script loads and handles plugins dynamically. It retrieves plugin configurations and iterates through each plugin.
|
||||
- For each plugin, it extracts the prefix and settings related to that plugin and processes them similarly to other user-defined settings.
|
||||
- It also handles scheduling for plugins with specific `RUN_SCHD` settings.
|
||||
|
||||
4. Saving Settings to the Database:
|
||||
- The script clears the existing settings in the database and inserts the updated settings into the database using SQL queries.
|
||||
|
||||
5. Updating the API and Performing Cleanup:
|
||||
- After importing the configurations, the script updates the API to reflect the changes in the settings.
|
||||
- It saves the current timestamp to determine the next import time.
|
||||
- Finally, it logs the successful import of the new configuration.
|
||||
|
||||
|
||||
_____________________
|
||||
|
||||
[screen1]: https://raw.githubusercontent.com/jokob-sk/Pi.Alert/main/docs/img/plugins_json_settings.png "Screen 1"
|
||||
41
docs/SMTP.md
Executable file
@@ -0,0 +1,41 @@
|
||||
# 📧 SMTP guides
|
||||
|
||||
## Using the GMX SMTP server
|
||||
|
||||
1. Go to your GMX account https://account.gmx.com
|
||||
2. Under Security Options enable 2FA (Two-factor authentication)
|
||||
3. Under Security Options generate an Application-specific password
|
||||
4. Home -> Email Settings -> POP3 & IMAP -> Enable access to this account via POP3 and IMAP
|
||||
5. In PiAlert specify these settings:
|
||||
|
||||
```python
|
||||
REPORT_MAIL=True
|
||||
SMTP_SERVER='mail.gmx.com'
|
||||
SMTP_PORT=465
|
||||
SMTP_USER='gmx_email@gmx.com'
|
||||
SMTP_PASS='<your Application-specific password>'
|
||||
SMTP_SKIP_TLS=True
|
||||
SMTP_FORCE_SSL=True
|
||||
SMTP_SKIP_LOGIN=False
|
||||
REPORT_FROM='gmx_email@gmx.com' # this has to be the same email as in SMTP_USER
|
||||
REPORT_TO='some_target_email@gmail.com'
|
||||
```
|
||||
|
||||
|
||||
## Using the Gmail SMTP server
|
||||
|
||||
1. Create an app password by following the instructions from Google, you need to Enable 2FA for this to work.
|
||||
[https://support.google.com/accounts/answer/185833](https://support.google.com/accounts/answer/185833)
|
||||
|
||||
2. Specify the following settings:
|
||||
|
||||
```python
|
||||
REPORT_MAIL=True
|
||||
SMTP_SKIP_TLS=True
|
||||
SMTP_FORCE_SSL=True
|
||||
SMTP_PORT=465
|
||||
SMTP_SERVER='smtp.gmail.com'
|
||||
SMTP_PASS='16-digit passcode from google'
|
||||
REPORT_TO='some_target_email@gmail.com'
|
||||
```
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
## Use the Gmail SMTP server
|
||||
|
||||
1) Create an app password by following the instructions from Google, you need to Enable 2FA for this to work.
|
||||
[https://support.google.com/accounts/answer/185833](https://support.google.com/accounts/answer/185833)
|
||||
|
||||
2) Specify the following settings:
|
||||
|
||||
```python
|
||||
SMTP_SKIP_TLS=True
|
||||
SMTP_FORCE_SSL=True
|
||||
SMTP_PORT=465
|
||||
SMTP_SERVER='smtp.gmail.com'
|
||||
SMTP_PASS='16-digit passcode from google'
|
||||
```
|
||||
|
||||
@@ -1,21 +1,100 @@
|
||||
## Subnets configuration
|
||||
# Subnets configuration for arp-scan
|
||||
|
||||
You need to specify the network interface and the network mask. You can also configure multiple subnets and specify VLANS (see exceptions below).
|
||||
|
||||
## Examples
|
||||
|
||||
> [!NOTE]
|
||||
> Please use the UI to configure settings as that ensures that the config file is in the correct format. Edit `pialert.conf` directly only when really necessary.
|
||||
> 
|
||||
|
||||
* Examples for one and two subnets (❗ Note the `['...', '...']` format):
|
||||
* One subnet: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0']`
|
||||
* Two subnets: `SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth0', '192.168.1.0/24 --interface=eth1 -vlan=107']`
|
||||
|
||||
## Explanation
|
||||
|
||||
### Network mask
|
||||
|
||||
**Example value: `192.168.1.0/24`**
|
||||
|
||||
The arp-scan time itself depends on the number of IP addresses to check.
|
||||
The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set on the `SCAN_SUBNETS` setting.
|
||||
|
||||
For example, a `/24` mask results in 256 IPs to check, where as a `/16` mask checks around 65,536. Every IP takes a couple seconds. This means that with an incorrect configuration the arp-scan will take hours to complete instead of seconds.
|
||||
> The number of IPs to check depends on the [network mask](https://www.calculator.net/ip-subnet-calculator.html) you set on the `SCAN_SUBNETS` setting.
|
||||
> For example, a `/24` mask results in 256 IPs to check, whereas a `/16` mask checks around 65,536. Every IP takes a couple of seconds. This means that with an incorrect configuration, the arp-scan will take hours to complete instead of seconds.
|
||||
|
||||
Specify the network filter (which **significantly** speeds up the scan process). For example, the filter `192.168.1.0/24` covers IP ranges 192.168.1.0 to 192.168.1.255.
|
||||
|
||||
### Network interface (adapter)
|
||||
|
||||
**Example value: `--interface=eth0`**
|
||||
|
||||
The adapter will probably be `eth0` or `eth1`. (Check `System info` > `Network Hardware` or run `iwconfig` in the container to find your interface name(s))
|
||||
|
||||
> Run `ip -o link show | awk -F': ' '!/lo|vir|docker/ {print $2}'` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
|
||||
|
||||
### VLANs
|
||||
|
||||
**Example value: `-vlan=107`**
|
||||
|
||||
- Specify the network mask. For example, the filter `192.168.1.0/24` covers IP ranges 192.168.1.0 to 192.168.1.255
|
||||
- Run `iwconfig` in your container to find your interface name(s) (e.g.: `eth0`, `eth1`).
|
||||
- Append e.g.: ` -vlan=107` to the interface field (e.g.: `eth0 -vlan=107`) for multiple vlans. More details in this [comment in this issue](https://github.com/jokob-sk/Pi.Alert/issues/170#issuecomment-1419902988)
|
||||
|
||||
### 🔍Example:
|
||||
|
||||
#### VLANs on a Hyper-V setup
|
||||
|
||||
> Community sourced content by [mscreations](https://github.com/mscreations) from this [discussion](https://github.com/jokob-sk/Pi.Alert/discussions/404).
|
||||
|
||||
> [!NOTE]
|
||||
> The setup this was tested on: Bare Metal -> Hyper-V on Win Server 2019 -> Ubuntu 22.04 VM -> Docker -> PiAlert.
|
||||
|
||||
**Approach 1 (may cause issues):**
|
||||
|
||||
Configure multiple network adapters in Hyper-V with distinct VLANs connected to each one using Hyper-V's network setup. However, this action can potentially lead to the Docker host's inability to handle network traffic correctly. The issue may stem from the creation of routes for network time servers or domain controllers on every interface, thereby preventing proper synchronization of the underlying Ubuntu VM. This interference can affect the performance of other applications such as Authentik.
|
||||
|
||||
**Approach 2 (working example)**
|
||||
|
||||
Network connections to switches are configured as trunk and allow all VLANs access to the server.
|
||||
|
||||
By default Hyper-V only allows untagged packets through to the VM interface and no VLAN tagged packets get through. In order to fix this follow these steps:
|
||||
|
||||
1) Run the following command in Powershell on the Hyper-V machine:
|
||||
|
||||
```shell
|
||||
Set-VMNetworkAdapterVlan -VMName <Docker VM Name> -Trunk -NativeVlanId 0 -AllowedVlanIdList "<comma separated list of vlans>"
|
||||
```
|
||||
|
||||
(There might be other ways how adjust this.)
|
||||
|
||||
2) Within the VM, set up sub-interfaces for each of the VLANs so they can be scanned. On Ubuntu 22.04 Netplan can be used.
|
||||
|
||||
In /etc/netplan/00-installer-config.yaml, add vlan definitions:
|
||||
|
||||
```
|
||||
network:
|
||||
ethernets:
|
||||
eth0:
|
||||
dhcp4: yes
|
||||
vlans:
|
||||
eth0.2:
|
||||
id: 2
|
||||
link: eth0
|
||||
addresses: [ "192.168.2.2/24" ]
|
||||
routes:
|
||||
- to: 192.168.2.0/24
|
||||
via: 192.168.1.1
|
||||
```
|
||||
|
||||
3) Run `sudo netplan apply` and the interfaces are then available to scan in PiAlert.
|
||||
4) In this case, use `192.168.2.0/24 --interface=eth0.2` in PiAlert
|
||||
|
||||
#### VLAN 🔍Example:
|
||||
|
||||

|
||||
|
||||
### Support for VLANS
|
||||
#### Support for VLANS (& exceptions)
|
||||
|
||||
Please note about the accessibility of the macvlans when they are configured on the same computer. My understanding this is a general networking behavior, but feel free to clarify via a PR/issue.
|
||||
Please note the accessibility of the macvlans when they are configured on the same computer. My understanding this is a general networking behavior, but feel free to clarify via a PR/issue.
|
||||
|
||||
- Pi.Alert does not detect the macvlan container when it is running on the same computer.
|
||||
- Pi.Alert recognizes the macvlan container when it is running on a different computer.
|
||||
|
||||
|
||||
@@ -77,4 +77,11 @@
|
||||
[Read more here](../LICENSE.txt)
|
||||
|
||||
### Contact
|
||||
pi.alert.application@gmail.com
|
||||
Always use the Issue tracker for the correct fork, for example:
|
||||
|
||||
[jokob-sk/Pi.Alert](https://github.com/jokob-sk/Pi.Alert/issues). Please also follow the guidelines on:
|
||||
|
||||
- ➕ [Pull Request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-pull-requests-prs)
|
||||
- 🙏 [Feature request guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-feature-requests)
|
||||
- 🐛 [Issue guidelines](https://github.com/jokob-sk/Pi.Alert/tree/main/docs#-submitting-an-issue-or-bug)
|
||||
|
||||
|
||||
38
docs/WEBHOOK_SECRET.md
Executable file
@@ -0,0 +1,38 @@
|
||||
# Webhook Secrets
|
||||
|
||||
## How does the signing work?
|
||||
|
||||
Pi.Alert will use the configured secret to create a hash signature of the request body. This SHA256-HMAC signature will appear in the `X-Webhook-Signature` header of each request to the webhook target URL. You can use the value of this header to validate the request was sent by Pi.Alert.
|
||||
|
||||
## Activating webhook signatures
|
||||
|
||||
All you need to do in order to add a signature to the request headers is to set the `WEBHOOK_SECRET` config value to a non-empty string.
|
||||
|
||||
## Validating webhook deliveries
|
||||
|
||||
There are a few things to keep in mind when validating the webhook delivery:
|
||||
|
||||
- Pi.Alert uses an HMAC hex digest to compute the hash
|
||||
- The signature in the `X-Webhook-Signature` header always starts with `sha256=`
|
||||
- The hash signature is generated using the configured `WEBHOOK_SECRET` and the request body.
|
||||
- Never use a plain `==` operator. Instead, consider using a method like [`secure_compare`](https://www.rubydoc.info/gems/rack/Rack%2FUtils:secure_compare) or [`crypto.timingSafeEqual`](https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b), which performs a "constant time" string comparison to help mitigate certain timing attacks against regular equality operators, or regular loops in JIT-optimized languages.
|
||||
|
||||
## Testing the webhook payload validation
|
||||
|
||||
You can use the following secret and payload to verify that your implementation is working correctly.
|
||||
|
||||
`secret`: 'this is my secret'
|
||||
|
||||
`payload`: '{"test":"this is a test body"}'
|
||||
|
||||
If your implementation is correct, the signature you generated should match the following:
|
||||
|
||||
`signature`: bed21fcc34f98e94fd71c7edb75e51a544b4a3b38b069ebaaeb19bf4be8147e9
|
||||
|
||||
`X-Webhook-Signature`: sha256=bed21fcc34f98e94fd71c7edb75e51a544b4a3b38b069ebaaeb19bf4be8147e9
|
||||
|
||||
## More information
|
||||
|
||||
If you want to learn more about webhook security, take a look at [GitHub's webhook documentation](https://docs.github.com/en/webhooks/about-webhooks).
|
||||
|
||||
You can find examples for validating a webhook delivery [here](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries#examples).
|
||||
12
docs/WEB_UI_PORT_DEBUG.md
Executable file
@@ -0,0 +1,12 @@
|
||||
# Debugging inaccessible UI
|
||||
|
||||
When opening an issue please :
|
||||
|
||||
1. Include a screenshot of what you see when accessing `HTTP://<your rpi IP>/20211` (or your custom port)
|
||||
1. [Follow steps 1, 2, 3, 4 on this page](https://github.com/jokob-sk/Pi.Alert/blob/main/docs/DEBUG_TIPS.md)
|
||||
1. Execute the following in the container to see the processes and their ports and submit a screenshot of the result:
|
||||
1. `sudo apt-get install lsof`
|
||||
1. `sudo lsof -i`
|
||||
|
||||
|
||||

|
||||
BIN
docs/img/DATABASE/CurrentScan.png
Executable file
|
After Width: | Height: | Size: 58 KiB |
BIN
docs/img/DATABASE/DHCP_Leases.png
Executable file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
docs/img/DATABASE/Devices.png
Executable file
|
After Width: | Height: | Size: 85 KiB |
BIN
docs/img/DATABASE/Events.png
Executable file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/img/DATABASE/Nmap_Scan.png
Executable file
|
After Width: | Height: | Size: 44 KiB |
BIN
docs/img/DATABASE/Online_History.png
Executable file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/img/DATABASE/Parameters.png
Executable file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/img/DATABASE/Pholus_Scan.png
Executable file
|
After Width: | Height: | Size: 92 KiB |
BIN
docs/img/DATABASE/PiHole_Network.png
Executable file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
docs/img/DATABASE/Plugins_Events.png
Executable file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/img/DATABASE/Plugins_History.png
Executable file
|
After Width: | Height: | Size: 72 KiB |
BIN
docs/img/DATABASE/Plugins_Language_Strings.png
Executable file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/img/DATABASE/Plugins_Objects.png
Executable file
|
After Width: | Height: | Size: 65 KiB |
BIN
docs/img/DATABASE/ScanCycles.png
Executable file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/img/DATABASE/Sessions.png
Executable file
|
After Width: | Height: | Size: 61 KiB |
BIN
docs/img/DATABASE/Settings.png
Executable file
|
After Width: | Height: | Size: 52 KiB |
BIN
docs/img/DEBUG_PLUGINS/plugin_objects_pihole.png
Executable file
|
After Width: | Height: | Size: 127 KiB |
BIN
docs/img/DEVICES_BULK_EDITING/CSV_BACKUP_SETTINGS.png
Executable file
|
After Width: | Height: | Size: 131 KiB |
BIN
docs/img/DEVICES_BULK_EDITING/MAINTENANCE_CSV_EXPORT.png
Executable file
|
After Width: | Height: | Size: 163 KiB |
BIN
docs/img/DEVICES_BULK_EDITING/NOTEPAD++.png
Executable file
|
After Width: | Height: | Size: 55 KiB |
BIN
docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Device-Presence-History.png
Executable file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Device-as-Sensors.png
Executable file
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Devices-List.png
Executable file
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/img/HOME_ASISSTANT/PiAlert-HomeAssistant-Overview-Card.png
Executable file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/img/ICONS/device_icons_preview.gif
Executable file
|
After Width: | Height: | Size: 112 KiB |
BIN
docs/img/WEB_UI_PORT_DEBUG/container_port.png
Executable file
|
After Width: | Height: | Size: 104 KiB |
BIN
docs/img/plugins_device_details.png
Executable file
|
After Width: | Height: | Size: 202 KiB |
BIN
docs/img/plugins_rogue_dhcp.png
Executable file
|
After Width: | Height: | Size: 116 KiB |
95
front/appEventsCore.php
Executable file
@@ -0,0 +1,95 @@
|
||||
<section class="content">
|
||||
<div class="nav-tabs-custom app-event-content" style="margin-bottom: 0px;">
|
||||
<ul id="tabs-location" class="nav nav-tabs col-sm-2">
|
||||
<li class="left-nav"><a class="col-sm-12" href="#" id="" data-toggle="tab">Events</a></li>
|
||||
</ul>
|
||||
<div id="tabs-content-location" class="tab-content col-sm-10">
|
||||
<table class="table table-striped" id="appevents-table" data-my-dbtable="AppEvents"></table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
|
||||
// show loading dialog
|
||||
showSpinner()
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
// Load JSON data from the provided URL
|
||||
$.getJSON('/api/table_appevents.json', function(data) {
|
||||
// Process the JSON data and generate UI dynamically
|
||||
processData(data)
|
||||
|
||||
// hide loading dialog
|
||||
hideSpinner()
|
||||
});
|
||||
});
|
||||
|
||||
function processData(data) {
|
||||
// Create an object to store unique ObjectType values as app event identifiers
|
||||
var appEventIdentifiers = {};
|
||||
|
||||
// Array to accumulate data for DataTable
|
||||
var allData = [];
|
||||
|
||||
// Iterate through the data and generate tabs and content dynamically
|
||||
$.each(data.data, function(index, item) {
|
||||
|
||||
// Accumulate data for DataTable
|
||||
allData.push(item);
|
||||
|
||||
});
|
||||
|
||||
// Initialize DataTable for all app events
|
||||
|
||||
$('#appevents-table').DataTable({
|
||||
data: allData,
|
||||
paging: true,
|
||||
lengthChange: true,
|
||||
lengthMenu: [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, 'All']],
|
||||
searching: true,
|
||||
ordering: true,
|
||||
info: true,
|
||||
autoWidth: false,
|
||||
pageLength: 25, // Set the default paging to 25
|
||||
columns: [
|
||||
{ data: 'DateTimeCreated', title: getString('AppEvents_DateTimeCreated') },
|
||||
{ data: 'AppEventType', title: getString('AppEvents_Type') },
|
||||
{ data: 'ObjectType', title: getString('AppEvents_ObjectType') },
|
||||
{ data: 'ObjectPrimaryID', title: getString('AppEvents_ObjectPrimaryID') },
|
||||
{ data: 'ObjectSecondaryID', title: getString('AppEvents_ObjectSecondaryID') },
|
||||
{ data: 'ObjectStatus', title: getString('AppEvents_ObjectStatus') },
|
||||
{ data: 'Extra', title: getString('AppEvents_Extra') },
|
||||
{ data: 'ObjectPlugin', title: getString('AppEvents_Plugin') },
|
||||
// Add other columns as needed
|
||||
],
|
||||
// Add column-specific configurations if needed
|
||||
columnDefs: [
|
||||
{ className: 'text-center', targets: [3] },
|
||||
{ width: '80px', targets: [6] },
|
||||
// ... Add other columnDefs as needed
|
||||
// Full MAC
|
||||
{targets: [3, 4],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html (createDeviceLink(cellData));
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
// Activate the first tab
|
||||
$('#tabs-location li:first-child').addClass('active');
|
||||
$('#tabs-content-location .tab-pane:first-child').addClass('active');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!-- Datatable -->
|
||||
<link rel="stylesheet" href="lib/AdminLTE/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css"/>
|
||||
<script src="lib/AdminLTE/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
|
||||
<script src="lib/AdminLTE/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
|
||||
@@ -723,3 +723,6 @@ input[type="password"]::-webkit-caps-lock-indicator {
|
||||
top: 0.01em;
|
||||
font-size: 3.25em;
|
||||
}
|
||||
.pa_semitransparent-panel{
|
||||
background-color: #000 !important;
|
||||
}
|
||||
@@ -173,6 +173,7 @@
|
||||
@media (max-width: 767px) {
|
||||
.main-header .logo {
|
||||
width: 100%;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.main-header .navbar {
|
||||
@@ -459,35 +460,7 @@
|
||||
border-right: 5px solid #606060;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Spin
|
||||
----------------------------------------------------------------------------- */
|
||||
.pa_semitransparent-panel {
|
||||
position: absolute;
|
||||
width: 100%; /*calc (100% -40px);*/
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: block;
|
||||
|
||||
opacity: 0.8;
|
||||
background-color: #fff;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.pa_spinner {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 20px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
width: 200px;
|
||||
|
||||
background-color: #fff;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Notification float banner
|
||||
@@ -612,8 +585,24 @@ height: 50px;
|
||||
.infobox_label {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
/* --------------------------------------------------------- */
|
||||
/* report */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/*settings*/
|
||||
#notificationData textarea{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#notificationData pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
|
||||
.string { color: green; }
|
||||
.number { color: darkorange; }
|
||||
.boolean { color: blue; }
|
||||
.null { color: magenta; }
|
||||
.key { color: red; }
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* settings */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
/* hide on mobile */
|
||||
@@ -646,6 +635,57 @@ height: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.settingswrap .metadata
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.settingswrap .enabled-disabled-icon
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
.settings-group
|
||||
{
|
||||
font-size: 20px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 9px;
|
||||
}
|
||||
|
||||
.overview-section .small-box .icon
|
||||
{
|
||||
font-size: 38px;
|
||||
top:0px;
|
||||
}
|
||||
|
||||
.overview-section
|
||||
{
|
||||
border: solid;
|
||||
border-width: medium;
|
||||
border-width: medium;
|
||||
border-width: 1px;
|
||||
border-radius: 15px;
|
||||
margin-bottom: 3px;
|
||||
|
||||
}
|
||||
|
||||
.settings-group i{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.overview-group
|
||||
{
|
||||
font-size: 20px;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 9px;
|
||||
|
||||
}
|
||||
|
||||
.overview-group i{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
.table_row {
|
||||
padding: 3px;
|
||||
width:100%;
|
||||
@@ -693,6 +733,20 @@ height: 50px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
/* Settings */
|
||||
|
||||
#settingsPage .overview-setting-value{
|
||||
display:unset;
|
||||
}
|
||||
#settingsPage .panel-title{
|
||||
/* display: inline-block; */
|
||||
/* width: 120px; */
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.settings_content {
|
||||
padding: 10px;
|
||||
/* background-color: #272c30; */
|
||||
@@ -715,14 +769,36 @@ height: 50px;
|
||||
width: auto
|
||||
}
|
||||
|
||||
|
||||
/* Devices */
|
||||
.drp-edit
|
||||
{
|
||||
cursor: pointer;
|
||||
.override{
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.new-version
|
||||
.override .override-text
|
||||
{
|
||||
float:left;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.override .override-check
|
||||
{
|
||||
float:left;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
input[readonly] {
|
||||
/* Apply styles to the readonly input */
|
||||
background-color: #646566 !important;
|
||||
color: #000;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Devices */
|
||||
#txtIconFA {
|
||||
min-width: 18px;
|
||||
}
|
||||
|
||||
|
||||
.info-icon-nav
|
||||
{
|
||||
top: -6px;
|
||||
position: absolute;
|
||||
@@ -733,8 +809,17 @@ height: 50px;
|
||||
|
||||
.pointer
|
||||
{
|
||||
cursor:pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drag
|
||||
{
|
||||
cursor: move; /* fallback if grab cursor is unsupported */
|
||||
cursor: grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: -webkit-grab;
|
||||
}
|
||||
|
||||
.db_info_table_row .select2-container--default .select2-selection--multiple .select2-selection__choice
|
||||
{
|
||||
background-color:#258744;
|
||||
@@ -761,38 +846,60 @@ height: 50px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
/* NETWORK page */
|
||||
|
||||
/* AdminLTE overrides */
|
||||
#networkTree .box
|
||||
{
|
||||
padding:2px;
|
||||
margin:2px;
|
||||
border-top:1px;
|
||||
border-top-color:grey;
|
||||
padding:0px;
|
||||
padding-top:6px;
|
||||
margin:0px;
|
||||
align-items:center;
|
||||
border-radius:20px;
|
||||
width:180px;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
justify-content:center;
|
||||
}
|
||||
#networkTree .netNodeText
|
||||
{
|
||||
top: 2px;
|
||||
margin: 2px;
|
||||
{
|
||||
position: absolute;
|
||||
}
|
||||
#networkTree .netPort
|
||||
{
|
||||
float:left;
|
||||
display:inline;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#networkTree .portBckgIcon
|
||||
{
|
||||
opacity: 0.3;
|
||||
display: initial;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#networkTree
|
||||
{
|
||||
margin-left: 16px;
|
||||
/* border: solid;
|
||||
border-color:#606060; */
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
position: relative;
|
||||
}
|
||||
#networkTree .netIcon
|
||||
{
|
||||
width: 25px;;
|
||||
float:left;
|
||||
display:inline;
|
||||
display:inline;
|
||||
text-align: center;
|
||||
}
|
||||
#networkTree .netCollapse
|
||||
{
|
||||
display: block;
|
||||
position: absolute;
|
||||
margin-left: 156px;
|
||||
top: -3px;
|
||||
margin-left: 170px;
|
||||
font-size: large;
|
||||
left: -15px;
|
||||
}
|
||||
@@ -814,28 +921,128 @@ height: 50px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.plugin-content
|
||||
{
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
.plugin-content #tabs-content-location
|
||||
{
|
||||
margin-top: 20px;
|
||||
margin-left: 7px;
|
||||
.plugin-filters
|
||||
{
|
||||
margin: 7px;
|
||||
margin-right: 7px;
|
||||
margin-bottom: 9px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.plugin-content
|
||||
{
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
.plugin-content .left-nav{
|
||||
width: 100%;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.plugin-content #tabs-content-location
|
||||
{
|
||||
margin: 0px;
|
||||
|
||||
}
|
||||
|
||||
.plugins-description
|
||||
{
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.login-page .login-custom
|
||||
{
|
||||
width:480px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*Hidden special button*/
|
||||
|
||||
@media (max-width: 365px) {
|
||||
#back-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 335px) {
|
||||
#next-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 300px) {
|
||||
#reload-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 300px) {
|
||||
#fullscreen-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.header-server-time {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#settingsPage .small-box .inner .card-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Spin
|
||||
----------------------------------------------------------------------------- */
|
||||
.pa_semitransparent-panel {
|
||||
position: absolute;
|
||||
width: 100%; /*calc (100% -40px);*/
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: block;
|
||||
|
||||
opacity: 0.8;
|
||||
background-color: #fff;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.pa_spinner {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 100px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 15px;
|
||||
width: 200px;
|
||||
background-color: #fff;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#loadingSpinner
|
||||
{
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Donations
|
||||
----------------------------------------------------------------------------- */
|
||||
.donations .box
|
||||
{
|
||||
padding:15px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.donations .box-header
|
||||
{
|
||||
color:15px;
|
||||
}
|
||||
.donations h3
|
||||
{
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<!-- ---------------------------------------------------------------------------
|
||||
# Pi.Alert
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
#
|
||||
# deviceDetails.php - Front module. Device management page
|
||||
#-------------------------------------------------------------------------------
|
||||
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
||||
#--------------------------------------------------------------------------- -->
|
||||
<!--
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# deviceDetails.php - Front module. Device management page #
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
#---------------------------------------------------------------------------------#
|
||||
-->
|
||||
|
||||
<?php
|
||||
require 'php/templates/header.php';
|
||||
@@ -94,19 +99,14 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-sm-12 col-xs-12">
|
||||
<!-- <div class="box-transparent"> -->
|
||||
|
||||
|
||||
<div id="navDevice" class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs" style="fon t-size:16px;">
|
||||
<li> <a id="tabDetails" href="#panDetails" data-toggle="tab"> <?= lang('DevDetail_Tab_Details');?> </a></li>
|
||||
<?php
|
||||
if ($_REQUEST['mac'] == 'Internet') { $DevDetail_Tap_temp = "Tools"; } else { $DevDetail_Tap_temp = lang('DevDetail_Tab_Nmap');}
|
||||
?>
|
||||
<li> <a id="tabNmap" href="#panNmap" data-toggle="tab"> <?php echo $DevDetail_Tap_temp;?> </a></li>
|
||||
<li> <a id="tabTools" href="#panTools" data-toggle="tab"> <?= lang('DevDetail_Tab_Tools');?> </a></li>
|
||||
<li> <a id="tabSessions" href="#panSessions" data-toggle="tab"> <?= lang('DevDetail_Tab_Sessions');?> </a></li>
|
||||
<li> <a id="tabPresence" href="#panPresence" data-toggle="tab"> <?= lang('DevDetail_Tab_Presence');?> </a></li>
|
||||
<li> <a id="tabEvents" href="#panEvents" data-toggle="tab"> <?= lang('DevDetail_Tab_Events');?> </a></li>
|
||||
<li> <a id="tabPholus" href="#panPholus" data-toggle="tab"> <?= lang('DevDetail_Tab_Pholus');?> </a></li>
|
||||
<li> <a id="tabEvents" href="#panEvents" data-toggle="tab"> <?= lang('DevDetail_Tab_Events');?> </a></li>
|
||||
<li> <a id="tabPlugins" href="#panPlugins" data-toggle="tab"> <?= lang('DevDetail_Tab_Plugins');?> </a></li>
|
||||
|
||||
<div class="btn-group pull-right">
|
||||
<button type="button" class="btn btn-default" style="padding: 10px; min-width: 30px;"
|
||||
@@ -119,9 +119,7 @@
|
||||
id="btnNext" onclick="recordSwitch('next')"> <i class="fa fa-chevron-right"></i> </button>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="tab-content" style="min-height: 430px;">
|
||||
|
||||
<!-- tab page 1 ------------------------------------------------------------ -->
|
||||
@@ -151,12 +149,12 @@
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="txtName" type="text" value="--">
|
||||
<span class="input-group-addon"><i class="fa fa-pencil pointer" onclick="editDrp('txtName');"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Owner -->
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_Owner_hover');?>">
|
||||
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Owner');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
@@ -173,7 +171,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Type -->
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_Type_hover');?>">
|
||||
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Type');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
@@ -191,16 +189,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Icon -->
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_Icon_Descr');?>">
|
||||
<label class="col-sm-3 control-label">
|
||||
<?= lang('DevDetail_Icon');?>
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/ICONS.md" target="_blank"> <span><i class="fa fa-circle-question"></i></a><span>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input class="form-control" title="<?= lang('DevDetail_Icon_Descr');?>" id="txtIcon" type="text" value="--">
|
||||
<span class="input-group-addon"><i class="fa" id="txtIconFA" onclick="editDrp('txtIcon');"></i></span>
|
||||
<input class="form-control" id="txtIcon" type="text" value="--">
|
||||
<span class="input-group-addon" title='<?= lang('DevDetail_button_OverwriteIcons_Tooltip');?>'><i class="fa fa-copy pointer" onclick="askOverwriteIconType();"></i></span>
|
||||
<span class="input-group-addon"><i class="fa fa-pencil pointer" onclick="editDrp('txtIcon');"></i></span>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="fa fa-caret-down"></span>
|
||||
@@ -213,7 +211,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Vendor -->
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_Vendor_hover');?>">
|
||||
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Vendor');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" id="txtVendor" type="text" value="--">
|
||||
@@ -324,10 +322,10 @@
|
||||
|
||||
<!-- Network -->
|
||||
<h4 class="bottom-border-aqua"><?= lang('DevDetail_MainInfo_Network_Title');?><span class="networkPageHelp"> <a target="_blank" href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/NETWORK_TREE.md"><i class="fa fa-circle-question"></i></a><span></h4>
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_Network_Node_hover');?>">
|
||||
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<div class="input-group parentNetworkNode">
|
||||
|
||||
<input class="form-control" id="txtNetworkNodeMac" type="text" value="--">
|
||||
<span class="input-group-addon"><i title="<?= lang('DevDetail_GoToNetworkNode');?>" class="fa fa-square-up-right pointer" onclick="goToNetworkNode('txtNetworkNodeMac');"></i></span>
|
||||
@@ -341,12 +339,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_Network_Port_hover');?>">
|
||||
<label class="col-sm-3 control-label"><?= lang('DevDetail_MainInfo_Network_Port');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input class="form-control" id="txtNetworkPort" type="text" value="--">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -412,10 +412,10 @@
|
||||
</div>
|
||||
|
||||
<!-- New Device -->
|
||||
<div class="form-group">
|
||||
<div class="form-group" title="<?= lang('DevDetail_EveandAl_NewDevice_Tooltip');?>">
|
||||
<label class="col-sm-5 control-label"><?= lang('DevDetail_EveandAl_NewDevice');?>:</label>
|
||||
<div class="col-sm-7" style="padding-top:6px;">
|
||||
<input class="checkbox orange hidden" id="chkNewDevice" type="checkbox">
|
||||
<input class="checkbox orange hidden" id="chkNewDevice" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -428,7 +428,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Randomized MAC -->
|
||||
<div class="form-group" >
|
||||
<div class="form-group" title="<?= lang('RandomMAC_hover');?>" >
|
||||
<label class="col-sm-5 control-label"><?= lang('DevDetail_EveandAl_RandomMAC');?>:</label>
|
||||
<div class="col-sm-7" style="padding-top:6px;">
|
||||
<span id="iconRandomMACinactive" data-toggle="tooltip" data-placement="right" title="Random MAC is Inactive">
|
||||
@@ -463,11 +463,35 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="bottom-border-aqua"><?= lang('DevDetail_Copy_Device_Title');?></h4>
|
||||
<div class="box-body form-horizontal">
|
||||
<label class="col-sm-3 control-label">
|
||||
<?= lang('Navigation_Devices');?>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input class="form-control" title="<?= lang('DevDetail_Copy_Device_Tooltip');?>" id="txtFromDevice" type="text" value="--">
|
||||
<span class="input-group-addon" title='<?= lang('Gen_Copy');?>'><i class="fa fa-copy pointer" onclick="askCopyFromDevice();"></i></span>
|
||||
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="fa fa-caret-down"></span>
|
||||
</button>
|
||||
<ul id="dropdownDevices" class="dropdown-menu dropdown-menu-right">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Buttons -->
|
||||
<div class="col-xs-12">
|
||||
<div class="pull-right">
|
||||
@@ -503,126 +527,20 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- tab page "Tools" ------------------------------------------------------------ -->
|
||||
|
||||
<!-- tab page 5 ------------------------------------------------------------ -->
|
||||
<div class="tab-pane fade" id="panTools">
|
||||
|
||||
|
||||
<div class="tab-pane fade" id="panNmap">
|
||||
|
||||
<?php
|
||||
if ($_REQUEST['mac'] == 'Internet') {
|
||||
?>
|
||||
<h4 class="">Online Speedtest</h4>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button" id="speedtestcli" class="btn btn-primary pa-btn" style="margin: auto;" onclick="speedtestcli()">Start Speedtest</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function speedtestcli() {
|
||||
$( "#scanoutput" ).empty();
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "./php/server/speedtestcli.php",
|
||||
beforeSend: function() { $('#scanoutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#scanoutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
$("#scanoutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<h4 class="">Nmap Scans</h4>
|
||||
<div style="width:100%; text-align: center;">
|
||||
<script>
|
||||
setTimeout(function(){
|
||||
document.getElementById('piamanualnmap_fast').innerHTML='<?= lang('DevDetail_Nmap_buttonFast');?> (' + document.getElementById('txtLastIP').value +')';
|
||||
document.getElementById('piamanualnmap_normal').innerHTML='<?= lang('DevDetail_Nmap_buttonDefault');?> (' + document.getElementById('txtLastIP').value +')';
|
||||
document.getElementById('piamanualnmap_detail').innerHTML='<?= lang('DevDetail_Nmap_buttonDetail');?> (' + document.getElementById('txtLastIP').value +')';
|
||||
document.getElementById('piamanualnmap_skipdiscovery').innerHTML='<?= lang('DevDetail_Nmap_buttonSkipDiscovery');?> (' + document.getElementById('txtLastIP').value +')';
|
||||
}, 2000);
|
||||
</script>
|
||||
|
||||
<button type="button" id="piamanualnmap_fast" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(document.getElementById('txtLastIP').value, 'fast')">Loading...</button>
|
||||
<button type="button" id="piamanualnmap_normal" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(document.getElementById('txtLastIP').value, 'normal')">Loading...</button>
|
||||
<button type="button" id="piamanualnmap_detail" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(document.getElementById('txtLastIP').value, 'detail')">Loading...</button>
|
||||
<button type="button" id="piamanualnmap_skipdiscovery" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(document.getElementById('txtLastIP').value, 'skipdiscovery')">Loading...</button>
|
||||
|
||||
<div style="text-align: left;">
|
||||
<ul style="padding:20px;">
|
||||
<li><?= lang('DevDetail_Nmap_buttonFast_text');?></li>
|
||||
<li><?= lang('DevDetail_Nmap_buttonDefault_text');?></li>
|
||||
<li><?= lang('DevDetail_Nmap_buttonDetail_text');?></li>
|
||||
<li><?= lang('DevDetail_Nmap_buttonSkipDiscovery_text');?></li>
|
||||
<li><a onclick="setCache('activeMaintenanceTab', 'tab_Logging_id')" href="/maintenance.php#tab_Logging"><?= lang('DevDetail_Nmap_resultsLink');?></a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="scanoutput" style="margin-top: 30px;"></div>
|
||||
|
||||
<script>
|
||||
function manualnmapscan(targetip, mode) {
|
||||
$( "#scanoutput" ).empty();
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "./php/server/nmap_scan.php",
|
||||
data: { scan: targetip, mode: mode },
|
||||
beforeSend: function() { $('#scanoutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#scanoutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
console.log(data);
|
||||
$("#scanoutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<h3><?= lang("DevDetail_Tab_NmapTableHeader");?></h3>
|
||||
|
||||
<div><?= lang("DevDetail_Tab_NmapTableText");?></div>
|
||||
|
||||
<table id="tableNmap" class="table table-bordered table-hover table-striped ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Index</th>
|
||||
<th>Time</th>
|
||||
<th>Port</th>
|
||||
<th>State</th>
|
||||
<th>Service</th>
|
||||
<th>Extra (Notes)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- Comment out tbody when trying to implement better table with datatables here -->
|
||||
<!-- IDEA: Show unmatched pholus entries? -->
|
||||
<tbody id="tableNmapBody">
|
||||
<tr id="tableNmapPlc" class="text-center"><td colspan='7'><span><?= lang("DevDetail_Tab_NmapEmpty"); ?></span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
require 'deviceDetailsTools.php';
|
||||
?>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ----------------------------------------------------------------------- -->
|
||||
|
||||
|
||||
<!-- tab page 3 ------------------------------------------------------------ -->
|
||||
<div class="tab-pane fade table-responsive" id="panPresence">
|
||||
|
||||
<!-- spinner -->
|
||||
<div id="loading" style="display: none">
|
||||
<div class="pa_semitransparent-panel"></div>
|
||||
<div class="panel panel-default pa_spinner">
|
||||
<table><td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td></table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade table-responsive" id="panPresence">
|
||||
|
||||
<!-- Calendar -->
|
||||
<div id="calendar">
|
||||
@@ -644,35 +562,24 @@
|
||||
<table id="tableEvents" class="table table-bordered table-hover table-striped ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Event type</th>
|
||||
<th>IP</th>
|
||||
<th>Additional info</th>
|
||||
<th><?= lang("DevDetail_Tab_EventsTableDate");?></th>
|
||||
<th><?= lang("DevDetail_Tab_EventsTableEvent");?></th>
|
||||
<th><?= lang("DevDetail_Tab_EventsTableIP");?></th>
|
||||
<th><?= lang("DevDetail_Tab_EventsTableInfo");?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<!-- tab page 6 ------------------------------------------------------------ -->
|
||||
<div class="tab-pane fade table-responsive" id="panPholus">
|
||||
<!-- Datatable Events -->
|
||||
<table id="tablePholus" class="table table-bordered table-hover table-striped ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Index</th>
|
||||
<th>Info</th>
|
||||
<th>Time</th>
|
||||
<th>IP</th>
|
||||
<th>Entry Type</th>
|
||||
<th>Value</th>
|
||||
<th>Extra</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- Comment out tbody when trying to implement better table with datatables here -->
|
||||
<!-- IDEA: Show unmatched pholus entries? -->
|
||||
<tbody id="tablePholusBody">
|
||||
<tr id="tablePholusPlc" class="text-center"><td colspan='7'><span><?= lang("DevDetail_Tab_PholusEmpty"); ?></span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- tab page 7 ------------------------------------------------------------ -->
|
||||
<div class="tab-pane fade table-responsive" id="panPlugins">
|
||||
|
||||
|
||||
<?php
|
||||
// Include the other page
|
||||
include 'pluginsCore.php';
|
||||
?>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -734,61 +641,27 @@ if ($ENABLED_DARKMODE === True) {
|
||||
return params.mac
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function getDevicesListValue(idColumn, idValue, returnColumn)
|
||||
{
|
||||
// Read cache
|
||||
devicesListAll = JSON.parse(getCache('devicesListAll'));
|
||||
|
||||
if(emptyArr.includes(devicesListAll) || emptyArr.includes(idValue))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
return devicesListAll.find((item) => {return item[idColumn] == idValue})[returnColumn]
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
function getDevicesList()
|
||||
{
|
||||
// Read cache
|
||||
devicesList = getCache('devicesList');
|
||||
// Read cache (skip cookie expiry check)
|
||||
devicesList = getCache('devicesListAll_JSON', true);
|
||||
|
||||
if (devicesList != '') {
|
||||
devicesList = JSON.parse (devicesList);
|
||||
} else {
|
||||
devicesList = [];
|
||||
}
|
||||
|
||||
return devicesList;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
mac = getMac() // can also be rowID!! not only mac
|
||||
var devicesList = []; // this will contain a list the database row IDs of the devices ordered by the position displayed in the UI
|
||||
var devicesListAll = []; // this will contain a list off all devices
|
||||
|
||||
|
||||
$.get('php/server/devices.php?action=getDevicesList&status=all&forceDefaultOrder', function(data) {
|
||||
|
||||
rawData = JSON.parse (data)
|
||||
|
||||
devicesListAll = rawData["data"].map(item => { return {
|
||||
"name":item[0],
|
||||
"type":item[2],
|
||||
"icon":item[3],
|
||||
"mac":item[11],
|
||||
"parentMac":item[14],
|
||||
"rowid":item[13],
|
||||
"status":item[10]
|
||||
}})
|
||||
|
||||
setCache('devicesListAll', JSON.stringify(devicesListAll))
|
||||
|
||||
// Read parameters & Initialize components
|
||||
main();
|
||||
});
|
||||
var devicesList = []; // this will contain a list the database row IDs of the devices ordered by the position displayed in the UI
|
||||
|
||||
main();
|
||||
|
||||
var pos = -1;
|
||||
var parPeriod = 'Front_Details_Period';
|
||||
@@ -807,13 +680,13 @@ if ($ENABLED_DARKMODE === True) {
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function main () {
|
||||
// Initialize MAC
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has ('mac') == true) {
|
||||
mac = urlParams.get ('mac');
|
||||
setCache("piaDeviceDetailsMac", mac); // set cookie
|
||||
} else {
|
||||
$('#pageTitle').html ('Device not found');
|
||||
}
|
||||
@@ -877,6 +750,11 @@ function main () {
|
||||
}
|
||||
});
|
||||
|
||||
// Show device icon as it changes
|
||||
$('#txtIcon').on('change input', function() {
|
||||
$('#txtIconFA').removeClass().addClass(`fa fa-${$(this).val()} pointer`)
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -949,6 +827,7 @@ function initializeCombos () {
|
||||
initializeCombo ( '#dropdownNetworkNodeMac', 'getNetworkNodes', 'txtNetworkNodeMac', false);
|
||||
initializeCombo ( '#dropdownIcon', 'getIcons', 'txtIcon', false);
|
||||
initializeCombo ( '#dropdownAction', 'getActions', 'txtAction', false);
|
||||
initializeCombo ( '#dropdownDevices', 'getDevices', 'txtFromDevice', false);
|
||||
|
||||
// Initialize static combos
|
||||
initializeComboSkipRepeated ();
|
||||
@@ -963,6 +842,8 @@ function initializeCombo (dropdownId, queryAction, txtDataField, useCache) {
|
||||
{
|
||||
// get data from server
|
||||
$.get('php/server/devices.php?action='+queryAction, function(data) {
|
||||
|
||||
console.log(data)
|
||||
var listData = JSON.parse(data);
|
||||
var order = 1;
|
||||
|
||||
@@ -1084,7 +965,7 @@ function initializeDatatables () {
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table><td width="130px" align="middle">Loading...</td>'+
|
||||
processing: '<table><td width="130px" align="middle"><?= lang("DevDetail_Loading");?></td>'+
|
||||
'<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw">'+
|
||||
'</td></table>',
|
||||
emptyTable: 'No data',
|
||||
@@ -1123,7 +1004,7 @@ function initializeDatatables () {
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table><td width="130px" align="middle">Loading...</td>'+
|
||||
processing: '<table><td width="130px" align="middle"><?= lang("DevDetail_Loading");?></td>'+
|
||||
'<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw">'+
|
||||
'</td></table>',
|
||||
emptyTable: 'No data',
|
||||
@@ -1192,6 +1073,16 @@ function initializeCalendar () {
|
||||
duration : { month: 1 },
|
||||
buttonText : '<?= lang('Presence_CalHead_month');?>',
|
||||
columnHeaderFormat : 'D'
|
||||
},
|
||||
agendaWeek: {
|
||||
buttonText : '<?= lang('Presence_CalHead_week');?>',
|
||||
},
|
||||
agendaDay: {
|
||||
type : 'agenda',
|
||||
duration : { day: 1 },
|
||||
buttonText : '<?= lang('Presence_CalHead_day');?>',
|
||||
slotLabelFormat : 'H',
|
||||
slotDuration : '01:00:00'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1238,16 +1129,16 @@ function initializeCalendar () {
|
||||
},
|
||||
|
||||
eventRender: function (event, element) {
|
||||
$(element).tooltip({container: 'body', placement: 'right',
|
||||
$(element).tooltip({container: 'body', placement: 'bottom',
|
||||
title: event.tooltip});
|
||||
// element.attr ('title', event.tooltip); // Alternative tooltip
|
||||
},
|
||||
|
||||
loading: function( isLoading, view ) {
|
||||
if (isLoading) {
|
||||
$('#loading').show();
|
||||
showSpinner()
|
||||
} else {
|
||||
$('#loading').hide();
|
||||
hideSpinner()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,7 +1180,7 @@ function getDeviceData (readAllData=false) {
|
||||
$("body").css ("cursor", "progress");
|
||||
}
|
||||
|
||||
// get data from server
|
||||
// get data from server
|
||||
$.get('php/server/devices.php?action=getDeviceData&mac='+ mac + '&period='+ period, function(data) {
|
||||
|
||||
var deviceData = JSON.parse(data);
|
||||
@@ -1350,7 +1241,7 @@ function getDeviceData (readAllData=false) {
|
||||
|
||||
// Name
|
||||
if (deviceData['dev_Owner'] == null || deviceData['dev_Owner'] == '' ||
|
||||
(deviceData['dev_Name']).indexOf (deviceData['dev_Owner']) != -1 ) {
|
||||
(deviceData['dev_Name'].toString()).indexOf (deviceData['dev_Owner']) != -1 ) {
|
||||
$('#pageTitle').html (deviceData['dev_Name']);
|
||||
} else {
|
||||
$('#pageTitle').html (deviceData['dev_Name'] + ' ('+ deviceData['dev_Owner'] +')');
|
||||
@@ -1395,22 +1286,26 @@ function getDeviceData (readAllData=false) {
|
||||
history.pushState(null, '', newRelativePathQuery);
|
||||
getSessionsPresenceEvents();
|
||||
|
||||
devicesList = getDevicesList();
|
||||
devicesList = getDevicesList();
|
||||
|
||||
$('#txtMAC').val (deviceData['dev_MAC']);
|
||||
$('#txtName').val (deviceData['dev_Name']);
|
||||
$('#txtOwner').val (deviceData['dev_Owner']);
|
||||
$('#txtDeviceType').val (deviceData['dev_DeviceType']);
|
||||
$('#txtVendor').val (deviceData['dev_Vendor']);
|
||||
$('#txtIcon').val (initDefault(deviceData['dev_Icon'], 'laptop'));
|
||||
$('#txtIcon').val (initDefault(deviceData['dev_Icon'], 'laptop'));
|
||||
$('#txtIcon').trigger('change')
|
||||
|
||||
if (deviceData['dev_Favorite'] == 1) {$('#chkFavorite').iCheck('check');} else {$('#chkFavorite').iCheck('uncheck');}
|
||||
$('#txtGroup').val (deviceData['dev_Group']);
|
||||
$('#txtLocation').val (deviceData['dev_Location']);
|
||||
$('#txtComments').val (deviceData['dev_Comments']);
|
||||
$('#txtNetworkNodeMac').val (getDevicesListValue('mac', deviceData['dev_Network_Node_MAC_ADDR'] ,'name'));
|
||||
$('#txtNetworkNodeMac').val ( getDeviceDataByMacAddress(deviceData['dev_Network_Node_MAC_ADDR'], "dev_Name")) ;
|
||||
$('#txtNetworkNodeMac').attr ('data-mynodemac', deviceData['dev_Network_Node_MAC_ADDR']);
|
||||
$('#txtNetworkPort').val (deviceData['dev_Network_Node_port']);
|
||||
// disabling network node configuration if root Internet node
|
||||
toggleNetworkConfiguration(mac == 'Internet')
|
||||
|
||||
|
||||
$('#txtFirstConnection').val (deviceData['dev_FirstConnection']);
|
||||
$('#txtLastConnection').val (deviceData['dev_LastConnection']);
|
||||
@@ -1432,7 +1327,8 @@ function getDeviceData (readAllData=false) {
|
||||
}
|
||||
|
||||
// Check if device is part of the devicesList
|
||||
pos = devicesList.findIndex(item => item.rowid == deviceData['rowid']);
|
||||
pos = devicesList.findIndex(item => item.rowid == deviceData['rowid']);
|
||||
|
||||
if (pos == -1) {
|
||||
devicesList.push({"rowid" : deviceData['rowid'], "mac" : deviceData['dev_MAC'], "name": deviceData['dev_Name'], "type": deviceData['dev_DeviceType']});
|
||||
pos=0;
|
||||
@@ -1505,12 +1401,13 @@ function performSwitch(direction)
|
||||
|
||||
// get new mac from the devicesList. Don't change to the commented out line below, the mac query string in the URL isn't updated yet!
|
||||
// mac = params.mac;
|
||||
mac = devicesList[pos].mac.toString();
|
||||
|
||||
mac = devicesList[pos].dev_MAC.toString();
|
||||
|
||||
setCache("piaDeviceDetailsMac", mac);
|
||||
|
||||
getDeviceData (true);
|
||||
|
||||
// reload current tab
|
||||
reloadTab()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1564,6 +1461,9 @@ function setDeviceData (direction='', refreshCallback='') {
|
||||
window.onbeforeunload = null;
|
||||
somethingChanged = false;
|
||||
|
||||
// refresh API
|
||||
updateApi()
|
||||
|
||||
// Callback fuction
|
||||
if (typeof refreshCallback == 'function') {
|
||||
refreshCallback(direction);
|
||||
@@ -1571,6 +1471,25 @@ function setDeviceData (direction='', refreshCallback='') {
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Calls a backend function to add a front-end event to an execution queue
|
||||
function updateApi()
|
||||
{
|
||||
|
||||
// value has to be in format event|param. e.g. run|ARPSCAN
|
||||
action = `update_api|devices,appevents`
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "php/server/util.php",
|
||||
data: { function: "addToExecutionQueue", action: action },
|
||||
success: function(data, textStatus) {
|
||||
console.log(data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askSkipNotifications () {
|
||||
// Check MAC
|
||||
@@ -1623,6 +1542,29 @@ function deleteDeviceEvents () {
|
||||
$('#panDetails :input').attr('disabled', true);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askCopyFromDevice() {
|
||||
// Ask
|
||||
showModalWarning('<?= lang('BackDevDetail_Copy_Title');?>', '<?= lang('BackDevDetail_Copy_Ask');?>',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Run');?>', 'copyFromDevice');
|
||||
}
|
||||
|
||||
function copyFromDevice() {
|
||||
|
||||
// Execute
|
||||
$.get('php/server/devices.php?action=copyFromDevice&'
|
||||
+ '&macTo=' + $('#txtMAC').val()
|
||||
+ '&macFrom=' + $('#txtFromDevice').val()
|
||||
, function(msg) {
|
||||
showMessage (msg);
|
||||
|
||||
setTimeout(function() {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function askRunAction() {
|
||||
// Ask
|
||||
@@ -1714,36 +1656,10 @@ function deleteDevice () {
|
||||
|
||||
// Deactivate controls
|
||||
$('#panDetails :input').attr('disabled', true);
|
||||
|
||||
// refresh API
|
||||
updateApi()
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
function askDeleteDevice () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask delete device
|
||||
showModalWarning ('Delete Device', 'Are you sure you want to delete this device?<br>(maybe you prefer to archive it)',
|
||||
'<?= lang('Gen_Cancel');?>', '<?= lang('Gen_Delete');?>', 'deleteDevice');
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function deleteDevice () {
|
||||
// Check MAC
|
||||
if (mac == '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete device
|
||||
$.get('php/server/devices.php?action=deleteDevice&mac='+ mac, function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
|
||||
// Deactivate controls
|
||||
$('#panDetails :input').attr('disabled', true);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getSessionsPresenceEvents () {
|
||||
@@ -1784,12 +1700,13 @@ function setTextValue (textElement, textValue) {
|
||||
if(textElement == "txtNetworkNodeMac")
|
||||
{
|
||||
$('#'+textElement).attr ('data-mynodemac', textValue);
|
||||
$('#'+textElement).val (getDevicesListValue('mac', textValue ,'name') );
|
||||
$('#'+textElement).val (getDeviceDataByMacAddress(textValue, "dev_Name"));
|
||||
} else
|
||||
{
|
||||
$('#'+textElement).attr ('data-myvalue', textValue);
|
||||
$('#'+textElement).val (textValue);
|
||||
}
|
||||
$('#'+textElement).trigger('change')
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -1813,102 +1730,14 @@ function initializeTabsNew () {
|
||||
// events on tab change
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var target = $(e.target).attr("href") // activated tab
|
||||
|
||||
// load tab data only when needed (tab change)
|
||||
if(target == "#panPholus")
|
||||
{
|
||||
loadPholus();
|
||||
}
|
||||
if(target == "#panNmap")
|
||||
{
|
||||
loadNmap();
|
||||
}
|
||||
|
||||
// if(target == "#panTools")
|
||||
// {
|
||||
// // loadTools();
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
function loadNmap()
|
||||
{
|
||||
$(".deviceSpecific").remove(); // remove any previous data listed in the table
|
||||
|
||||
$.get('php/server/devices.php?action=getNmap&mac='+ mac, function(data) {
|
||||
|
||||
data = sanitize(data);
|
||||
|
||||
if(data != "false" && $.trim(data) != [])
|
||||
{
|
||||
var listData = JSON.parse(data);
|
||||
var order = 1;
|
||||
|
||||
tableRows = "";
|
||||
|
||||
// for each item
|
||||
listData.forEach(function (item, index) {
|
||||
tableRows += '<tr class="deviceSpecific">\
|
||||
<td>'+item.Index+'</td>\
|
||||
<td>'+item.Time+'</td>\
|
||||
<td>\
|
||||
<a href="http://'+item.IP+':'+item.Port.split('/')[0]+'" target="_blank">'+item.Port+'</a>\
|
||||
<a href="https://'+item.IP+':'+item.Port.split('/')[0]+'" target="_blank">\
|
||||
<span style="padding-left:5px"><i class="fa fa-lock "></i></a></span>\
|
||||
</td>\
|
||||
<td>'+item.State+'</td>\
|
||||
<td>'+item.Service+'</td>\
|
||||
<td>\
|
||||
<div class="input-group">\
|
||||
<input class="form-control" id="port_'+item.Index+'" type="text" value="'+item.Extra+'">\
|
||||
<span class="input-group-addon"><i class="fa fa-save pointer" onclick="saveNmapPort('+item.Index+')"></i></span>\
|
||||
</div>\
|
||||
</td>\
|
||||
</tr>';
|
||||
});
|
||||
|
||||
$("#tableNmapBody").html($("#tableNmapBody").html()+tableRows);
|
||||
$("#tableNmapPlc").hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
// console.log("else")
|
||||
$("#tableNmapPlc").show();
|
||||
$(".deviceSpecific").remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
function loadPholus()
|
||||
{
|
||||
$(".deviceSpecific").remove(); // remove any previous data listed in teh table
|
||||
|
||||
$.get('php/server/devices.php?action=getPholus&mac='+ mac, function(data) {
|
||||
|
||||
data = sanitize(data);
|
||||
|
||||
if(data != "false" && $.trim(data) != [])
|
||||
{
|
||||
var listData = JSON.parse(data);
|
||||
var order = 1;
|
||||
|
||||
tableRows = "";
|
||||
|
||||
// for each item
|
||||
listData.forEach(function (item, index) {
|
||||
tableRows += '<tr class="deviceSpecific"><td>'+item.Index+'</td><td>'+item.Info+'</td><td>'+item.Time+'</td><td>'+item.IP_v4_or_v6+'</td><td>'+item.Record_Type+'</td><td>'+item.Value+'</td><td>'+ item.Extra +'</td></tr>';
|
||||
});
|
||||
|
||||
$("#tablePholusBody").html($("#tablePholusBody").html()+tableRows);
|
||||
$("#tablePholusPlc").hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
// console.log("else")
|
||||
$("#tablePholusPlc").show();
|
||||
$(".deviceSpecific").remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
@@ -1942,7 +1771,7 @@ function initTable(tableId, mac){
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table><td width="130px" align="middle">Loading...</td>'+
|
||||
processing: '<table><td width="130px" align="middle"><?= lang("DevDetail_Loading");?></td>'+
|
||||
'<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw">'+
|
||||
'</td></table>',
|
||||
emptyTable: 'No data',
|
||||
@@ -1972,31 +1801,27 @@ window.onload = function async()
|
||||
{
|
||||
initializeTabsNew();
|
||||
|
||||
reloadTab();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
function reloadTab()
|
||||
{
|
||||
// tab loaded without switching
|
||||
if(getCache("activeDevicesTab") == "tabPholus")
|
||||
{
|
||||
loadPholus();
|
||||
}
|
||||
|
||||
if(getCache("activeDevicesTab") == "tabNmap")
|
||||
{
|
||||
loadNmap();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
function saveNmapPort(index)
|
||||
// Disables network configuration for the root node
|
||||
function toggleNetworkConfiguration(disable)
|
||||
{
|
||||
saveData('saveNmapPort', index, $('#port_'+index).val())
|
||||
}
|
||||
$('#txtNetworkNodeMac').prop('readonly', true ); // disable direct input as should only be selected via the dropdown
|
||||
|
||||
if(disable)
|
||||
{
|
||||
// $('#txtNetworkNodeMac').val(getString('Network_Root_Unconfigurable'));
|
||||
// $('#txtNetworkPort').val(getString('Network_Root_Unconfigurable'));
|
||||
$('#txtNetworkPort').prop('readonly', true );
|
||||
$('.parentNetworkNode .input-group-btn').hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#txtNetworkPort').prop('readonly', false );
|
||||
$('.parentNetworkNode .input-group-btn').show();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
214
front/deviceDetailsTools.php
Executable file
@@ -0,0 +1,214 @@
|
||||
<script>
|
||||
deviceIP = getDeviceDataByMacAddress("<?php echo $_REQUEST["mac"]?>", "dev_LastIP")
|
||||
</script>
|
||||
|
||||
<?php if ($_REQUEST["mac"] == "Internet") { ?>
|
||||
|
||||
<h4 class=""><i class="fa-solid fa-globe"></i>
|
||||
<?= lang("DevDetail_Tab_Tools_Internet_Info_Title") ?>
|
||||
</h4>
|
||||
<h5 class="">
|
||||
<?= lang("DevDetail_Tab_Tools_Internet_Info_Description") ?>
|
||||
</h5>
|
||||
<br>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button" id="internetinfo" class="btn btn-primary pa-btn" style="margin: auto;" onclick="internetinfo()">
|
||||
<?= lang("DevDetail_Tab_Tools_Internet_Info_Start") ?></button>
|
||||
<br>
|
||||
<div id="internetinfooutput" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($_REQUEST["mac"] == "Internet") { ?>
|
||||
<h4 class=""><i class="fa-solid fa-gauge-high"></i>
|
||||
<?= lang("DevDetail_Tab_Tools_Speedtest_Title") ?>
|
||||
</h4>
|
||||
<h5 class="">
|
||||
<?= lang("DevDetail_Tab_Tools_Speedtest_Description") ?>
|
||||
</h5>
|
||||
<br>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button" id="speedtestcli" class="btn btn-primary pa-btn" style="margin: auto;" onclick="speedtestcli()">
|
||||
<?= lang("DevDetail_Tab_Tools_Speedtest_Start") ?></button>
|
||||
<br>
|
||||
<div id="speedtestoutput" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($_REQUEST["mac"] != "Internet") { ?>
|
||||
<h4 class=""><i class="fa-solid fa-route"></i>
|
||||
<?= lang("DevDetail_Tab_Tools_Traceroute_Title") ?>
|
||||
</h4>
|
||||
<h5 class="">
|
||||
<?= lang("DevDetail_Tab_Tools_Traceroute_Description") ?>
|
||||
</h5>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button" id="traceroute" class="btn btn-primary pa-btn" style="margin: auto;" onclick="traceroute()">
|
||||
<?= lang("DevDetail_Tab_Tools_Traceroute_Start") ?>
|
||||
</button>
|
||||
<br>
|
||||
<div id="tracerouteoutput" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($_REQUEST["mac"] != "Internet") { ?>
|
||||
<h4 class=""><i class="fa-solid fa-magnifying-glass"></i>
|
||||
<?= lang("DevDetail_Tab_Tools_Nslookup_Title") ?>
|
||||
</h4>
|
||||
<h5 class="">
|
||||
<?= lang("DevDetail_Tab_Tools_Nslookup_Description") ?>
|
||||
</h5>
|
||||
<div style="width:100%; text-align: center; margin-bottom: 50px;">
|
||||
<button type="button" id="nslookup" class="btn btn-primary pa-btn" style="margin: auto;" onclick="nslookup()">
|
||||
<?= lang("DevDetail_Tab_Tools_Nslookup_Start") ?>
|
||||
</button>
|
||||
<br>
|
||||
<div id="nslookupoutput" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<h4 class=""><i class="fa-solid fa-ethernet"></i>
|
||||
<?= lang("DevDetail_Nmap_Scans") ?>
|
||||
</h4>
|
||||
<div style="width:100%; text-align: center;">
|
||||
<div>
|
||||
<?= lang("DevDetail_Nmap_Scans_desc") ?>
|
||||
</div>
|
||||
|
||||
<button type="button" id="piamanualnmap_fast" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'fast')">
|
||||
<?= lang("DevDetail_Loading") ?>
|
||||
</button>
|
||||
<button type="button" id="piamanualnmap_normal" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'normal')">
|
||||
<?= lang("DevDetail_Loading") ?>
|
||||
</button>
|
||||
<button type="button" id="piamanualnmap_detail" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'detail')">
|
||||
<?= lang("DevDetail_Loading") ?>
|
||||
</button>
|
||||
<button type="button" id="piamanualnmap_skipdiscovery" class="btn btn-primary pa-btn" style="margin-bottom: 20px; margin-left: 10px; margin-right: 10px;" onclick="manualnmapscan(deviceIP, 'skipdiscovery')">
|
||||
<?= lang("DevDetail_Loading") ?>
|
||||
</button>
|
||||
|
||||
<div style="text-align: left;">
|
||||
<ul style="padding:20px;">
|
||||
<li>
|
||||
<?= lang("DevDetail_Nmap_buttonFast_text") ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= lang("DevDetail_Nmap_buttonDefault_text") ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= lang("DevDetail_Nmap_buttonDetail_text") ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= lang("DevDetail_Nmap_buttonSkipDiscovery_text") ?>
|
||||
</li>
|
||||
<li>
|
||||
<a onclick="setCache('activeMaintenanceTab', 'tab_Logging_id')" href="/maintenance.php#tab_Logging">
|
||||
<?= lang("DevDetail_Nmap_resultsLink") ?>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="scanoutput" style="margin-top: 30px;"></div>
|
||||
|
||||
<script>
|
||||
// ----------------------------------------------------------------
|
||||
function manualnmapscan(targetip, mode) {
|
||||
$( "#scanoutput" ).empty();
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "./php/server/nmap_scan.php",
|
||||
data: { scan: targetip, mode: mode },
|
||||
beforeSend: function() { $('#scanoutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#scanoutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
console.log(data);
|
||||
$("#scanoutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
function speedtestcli() {
|
||||
$( "#speedtestoutput" ).empty();
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "./php/server/speedtestcli.php",
|
||||
beforeSend: function() { $('#speedtestoutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#speedtestoutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
$("#speedtestoutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
function traceroute() {
|
||||
|
||||
$( "#tracerouteoutput" ).empty();
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "./php/server/traceroute.php?action=get&ip=" + deviceIP + "",
|
||||
beforeSend: function() { $('#tracerouteoutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#tracerouteoutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
$("#tracerouteoutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
function nslookup() {
|
||||
|
||||
$( "#nslookupoutput" ).empty();
|
||||
$.ajax({
|
||||
method: "GET",
|
||||
url: "./php/server/nslookup.php?action=get&ip=" + deviceIP + "",
|
||||
beforeSend: function() { $('#nslookupoutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#nslookupoutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
$("#nslookupoutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
setTimeout(function(){
|
||||
document.getElementById('piamanualnmap_fast').innerHTML='<?= lang(
|
||||
"DevDetail_Nmap_buttonFast"
|
||||
) ?> (' + deviceIP +')';
|
||||
document.getElementById('piamanualnmap_normal').innerHTML='<?= lang(
|
||||
"DevDetail_Nmap_buttonDefault"
|
||||
) ?> (' + deviceIP +')';
|
||||
document.getElementById('piamanualnmap_detail').innerHTML='<?= lang(
|
||||
"DevDetail_Nmap_buttonDetail"
|
||||
) ?> (' + deviceIP +')';
|
||||
document.getElementById('piamanualnmap_skipdiscovery').innerHTML='<?= lang(
|
||||
"DevDetail_Nmap_buttonSkipDiscovery"
|
||||
) ?> (' + deviceIP +')';
|
||||
}, 2000);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
function internetinfo() {
|
||||
$( "#internetinfooutput" ).empty();
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "./php/server/internetinfo.php",
|
||||
beforeSend: function() { $('#internetinfooutput').addClass("ajax_scripts_loading"); },
|
||||
complete: function() { $('#internetinfooutput').removeClass("ajax_scripts_loading"); },
|
||||
success: function(data, textStatus) {
|
||||
$("#internetinfooutput").html(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,11 +1,16 @@
|
||||
<!-- ---------------------------------------------------------------------------
|
||||
# Pi.Alert
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
#
|
||||
# devices.php - Front module. Devices list page
|
||||
#-------------------------------------------------------------------------------
|
||||
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
||||
#--------------------------------------------------------------------------- -->
|
||||
<!--
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# devices.php - Front module. Devices list page #
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
#---------------------------------------------------------------------------------#
|
||||
-->
|
||||
|
||||
<?php
|
||||
|
||||
@@ -26,7 +31,8 @@
|
||||
<!-- Content header--------------------------------------------------------- -->
|
||||
<section class="content-header">
|
||||
<h1 id="pageTitle">
|
||||
<?= lang('Device_Title');?>
|
||||
<i class="fa fa-laptop"></i>
|
||||
<?= lang('Device_Title');?>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
@@ -36,9 +42,9 @@
|
||||
<!-- top small box 1 ------------------------------------------------------- -->
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('all');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('my');">
|
||||
<div class="small-box bg-aqua">
|
||||
<div class="inner"><h3 id="devicesAll"> -- </h3>
|
||||
<div class="inner"><h3 id="devicesMy"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_AllDevices');?></p>
|
||||
</div>
|
||||
<div class="icon"><i class="fa fa-laptop text-aqua-40"></i></div>
|
||||
@@ -48,7 +54,7 @@
|
||||
|
||||
<!-- top small box 2 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('connected');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('connected');">
|
||||
<div class="small-box bg-green">
|
||||
<div class="inner"><h3 id="devicesConnected"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_Connected');?></p>
|
||||
@@ -60,7 +66,7 @@
|
||||
|
||||
<!-- top small box 3 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('favorites');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('favorites');">
|
||||
<div class="small-box bg-yellow">
|
||||
<div class="inner"><h3 id="devicesFavorites"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_Favorites');?></p>
|
||||
@@ -72,7 +78,7 @@
|
||||
|
||||
<!-- top small box 4 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('new');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('new');">
|
||||
<div class="small-box bg-yellow">
|
||||
<div class="inner"><h3 id="devicesNew"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_NewDevices');?></p>
|
||||
@@ -84,7 +90,7 @@
|
||||
|
||||
<!-- top small box 5 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('down');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('down');">
|
||||
<div class="small-box bg-red">
|
||||
<div class="inner"><h3 id="devicesDown"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_DownAlerts');?></p>
|
||||
@@ -96,7 +102,7 @@
|
||||
|
||||
<!-- top small box 6 ------------------------------------------------------- -->
|
||||
<div class="col-lg-2 col-sm-4 col-xs-6">
|
||||
<a href="#" onclick="javascript: getDevicesList('archived');">
|
||||
<a href="#" onclick="javascript: initializeDatatable('archived');">
|
||||
<div class="small-box bg-gray top_small_box_gray_text">
|
||||
<div class="inner"><h3 id="devicesArchived"> -- </h3>
|
||||
<p class="infobox_label"><?= lang('Device_Shortcut_Archived');?></p>
|
||||
@@ -192,9 +198,32 @@
|
||||
var tableRows = 10;
|
||||
var tableOrder = [[3,'desc'], [0,'asc']];
|
||||
|
||||
var columnsStr = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]';
|
||||
var tableColumnOrder = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17] ;
|
||||
var tableColumnHide = [];
|
||||
var columnsStr = '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]';
|
||||
var tableColumnOrder = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
|
||||
var tableColumnVisible = tableColumnOrder;
|
||||
//initialize the table headers in the correct order
|
||||
var headersDefaultOrder = [
|
||||
getString('Device_TableHead_Name'),
|
||||
getString('Device_TableHead_Owner'),
|
||||
getString('Device_TableHead_Type'),
|
||||
getString('Device_TableHead_Icon'),
|
||||
getString('Device_TableHead_Favorite'),
|
||||
getString('Device_TableHead_Group'),
|
||||
getString('Device_TableHead_FirstSession'),
|
||||
getString('Device_TableHead_LastSession'),
|
||||
getString('Device_TableHead_LastIP'),
|
||||
getString('Device_TableHead_MAC'),
|
||||
getString('Device_TableHead_Status'),
|
||||
getString('Device_TableHead_MAC_full'),
|
||||
getString('Device_TableHead_LastIPOrder'),
|
||||
getString('Device_TableHead_Rowid'),
|
||||
getString('Device_TableHead_Parent_MAC'),
|
||||
getString('Device_TableHead_Connected_Devices'),
|
||||
getString('Device_TableHead_Location'),
|
||||
getString('Device_TableHead_Vendor'),
|
||||
getString('Device_TableHead_Port')
|
||||
];
|
||||
|
||||
// Read parameters & Initialize components
|
||||
main();
|
||||
@@ -203,6 +232,8 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
function main () {
|
||||
|
||||
handleLoadingDialog()
|
||||
|
||||
// get from cookie if available (need to use decodeURI as saved as part of URI in PHP)
|
||||
cookieColumnsVisibleStr = decodeURI(getCookie("Front_Devices_Columns_Visible")).replaceAll('%2C',',')
|
||||
|
||||
@@ -210,6 +241,8 @@ function main () {
|
||||
|
||||
// get visible columns
|
||||
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'¶meter=Front_Devices_Columns_Visible&skipcache', function(data) {
|
||||
|
||||
handle_locked_DB(data)
|
||||
|
||||
// save which columns are in the Devices page visible
|
||||
tableColumnVisible = numberArrayFromString(data);
|
||||
@@ -221,33 +254,12 @@ function main () {
|
||||
|
||||
// get the custom order specified by the user
|
||||
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+defaultValue+'¶meter=Front_Devices_Columns_Order&skipcache', function(data) {
|
||||
|
||||
handle_locked_DB(data)
|
||||
|
||||
// save the columns order in the Devices page
|
||||
tableColumnOrder = numberArrayFromString(data);
|
||||
|
||||
|
||||
|
||||
//initialize the table headers in the correct order
|
||||
var headersDefaultOrder = [ '<?= lang('Device_TableHead_Name');?>',
|
||||
'<?= lang('Device_TableHead_Owner');?>',
|
||||
'<?= lang('Device_TableHead_Type');?>',
|
||||
'<?= lang('Device_TableHead_Icon');?>',
|
||||
'<?= lang('Device_TableHead_Favorite');?>',
|
||||
'<?= lang('Device_TableHead_Group');?>',
|
||||
'<?= lang('Device_TableHead_FirstSession');?>',
|
||||
'<?= lang('Device_TableHead_LastSession');?>',
|
||||
'<?= lang('Device_TableHead_LastIP');?>',
|
||||
'<?= lang('Device_TableHead_MAC');?>',
|
||||
'<?= lang('Device_TableHead_Status');?>',
|
||||
'<?= lang('Device_TableHead_MAC_full');?>',
|
||||
'<?= lang('Device_TableHead_LastIPOrder');?>',
|
||||
'<?= lang('Device_TableHead_Rowid');?>',
|
||||
'<?= lang('Device_TableHead_Parent_MAC');?>',
|
||||
'<?= lang('Device_TableHead_Connected_Devices');?>',
|
||||
'<?= lang('Device_TableHead_Location');?>',
|
||||
'<?= lang('Device_TableHead_Vendor');?>'
|
||||
];
|
||||
|
||||
html = '';
|
||||
|
||||
for(index = 0; index < tableColumnOrder.length; index++)
|
||||
@@ -279,11 +291,14 @@ function main () {
|
||||
}
|
||||
|
||||
// Initialize components with parameters
|
||||
initializeDatatable();
|
||||
initializeDatatable('my');
|
||||
|
||||
|
||||
|
||||
// check if dat outdated and show spinner if so
|
||||
handleLoadingDialog()
|
||||
|
||||
|
||||
// query data
|
||||
getDevicesTotals();
|
||||
getDevicesList (deviceStatus);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -291,8 +306,6 @@ function main () {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
var tableColumnHide = [];
|
||||
|
||||
// mapping the default order to the user specified one
|
||||
function mapIndx(oldIndex)
|
||||
{
|
||||
@@ -305,9 +318,129 @@ function mapIndx(oldIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
// Query total numbers of Devices by status
|
||||
//------------------------------------------------------------------------------
|
||||
function getDevicesTotals(devicesData) {
|
||||
|
||||
let resultJSON = "";
|
||||
|
||||
if (getCache("getDevicesTotals") !== "") {
|
||||
resultJSON = getCache("getDevicesTotals");
|
||||
} else {
|
||||
// combined query
|
||||
const devices = filterDataByStatus(devicesData, 'my');
|
||||
const connectedDevices = filterDataByStatus(devicesData, 'connected');
|
||||
const favoritesDevices = filterDataByStatus(devicesData, 'favorites');
|
||||
const newDevices = filterDataByStatus(devicesData, 'new');
|
||||
const downDevices = filterDataByStatus(devicesData, 'down');
|
||||
const archivedDevices = filterDataByStatus(devicesData, 'archived');
|
||||
|
||||
|
||||
$('#devicesMy').html (devices.length);
|
||||
$('#devicesConnected').html (connectedDevices.length);
|
||||
$('#devicesFavorites').html (favoritesDevices.length);
|
||||
$('#devicesNew').html (newDevices.length);
|
||||
$('#devicesDown').html (downDevices.length);
|
||||
$('#devicesArchived').html (archivedDevices.length);
|
||||
|
||||
// save to cache
|
||||
setCache("getDevicesTotals", resultJSON);
|
||||
}
|
||||
|
||||
console.log(resultJSON);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Define a function to filter data based on deviceStatus
|
||||
function filterDataByStatus(data, status) {
|
||||
return data.filter(function(item) {
|
||||
switch (status) {
|
||||
case 'my':
|
||||
to_display = getSetting('UI_MY_DEVICES');
|
||||
|
||||
let result = false;
|
||||
|
||||
if (to_display.includes('online') && item.dev_PresentLastScan === 1) {
|
||||
result = true;
|
||||
} else if (to_display.includes('offline') && item.dev_PresentLastScan === 0) {
|
||||
result = true;
|
||||
} else if (to_display.includes('archived') && item.dev_Archived === 1) {
|
||||
result = true;
|
||||
} else if (to_display.includes('new') && item.dev_NewDevice === 1) {
|
||||
result = true;
|
||||
} else if (to_display.includes('down') && item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown !== 0) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result; // Include all items for 'my' status
|
||||
case 'connected':
|
||||
return item.dev_PresentLastScan === 1;
|
||||
case 'favorites':
|
||||
return item.dev_Favorite === 1;
|
||||
case 'new':
|
||||
return item.dev_NewDevice === 1;
|
||||
case 'down':
|
||||
return item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown !== 0;
|
||||
case 'archived':
|
||||
return item.dev_Archived === 1;
|
||||
default:
|
||||
return true; // Include all items for unknown statuses
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDeviceStatus(item)
|
||||
{
|
||||
|
||||
if(item.dev_NewDevice === 1)
|
||||
{
|
||||
return 'New';
|
||||
}
|
||||
else if(item.dev_PresentLastScan === 1)
|
||||
{
|
||||
return 'On-line';
|
||||
}
|
||||
else if(item.dev_PresentLastScan === 0 && item.dev_AlertDeviceDown !== 0)
|
||||
{
|
||||
return 'Down';
|
||||
}
|
||||
else if(item.dev_Archived === 1)
|
||||
{
|
||||
return 'Archived';
|
||||
}
|
||||
else if(item.dev_PresentLastScan === 0)
|
||||
{
|
||||
return 'Off-line';
|
||||
}
|
||||
|
||||
return "Unknown status"
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function initializeDatatable (status) {
|
||||
|
||||
// Save status selected
|
||||
deviceStatus = status;
|
||||
|
||||
// Define color & title for the status selected
|
||||
switch (deviceStatus) {
|
||||
case 'my': tableTitle = getString('Device_Shortcut_AllDevices'); color = 'aqua'; break;
|
||||
case 'connected': tableTitle = getString('Device_Shortcut_Connected'); color = 'green'; break;
|
||||
case 'favorites': tableTitle = getString('Device_Shortcut_Favorites'); color = 'yellow'; break;
|
||||
case 'new': tableTitle = getString('Device_Shortcut_NewDevices'); color = 'yellow'; break;
|
||||
case 'down': tableTitle = getString('Device_Shortcut_DownAlerts'); color = 'red'; break;
|
||||
case 'archived': tableTitle = getString('Device_Shortcut_Archived'); color = 'gray'; break;
|
||||
default: tableTitle = getString('Device_Shortcut_Devices'); color = 'gray'; break;
|
||||
}
|
||||
|
||||
// Set title and color
|
||||
$('#tableDevicesTitle')[0].className = 'box-title text-'+ color;
|
||||
$('#tableDevicesBox')[0].className = 'box box-'+ color;
|
||||
$('#tableDevicesTitle').html (tableTitle);
|
||||
|
||||
|
||||
function initializeDatatable () {
|
||||
for(i = 0; i < tableColumnOrder.length; i++)
|
||||
{
|
||||
// hide this column if not in the tableColumnVisible variable (we need to keep the MAC address (index 11) for functionality reasons)
|
||||
@@ -317,150 +450,214 @@ function initializeDatatable () {
|
||||
}
|
||||
}
|
||||
|
||||
// If the device has a small width (mobile) only show name, ip, and status columns.
|
||||
if (window.screen.width < 400) {
|
||||
tableColumnHide = [11,12,13,1,2,4,5,6,7,9];
|
||||
}
|
||||
// else {
|
||||
// // var tableColumnHide = [11, 12, 13];
|
||||
// tableColumnHide = [11, 12, 13];
|
||||
// };
|
||||
var table=
|
||||
$('#tableDevices').DataTable({
|
||||
'paging' : true,
|
||||
'lengthChange' : true,
|
||||
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, '<?= lang('Device_Tablelenght_all');?>']],
|
||||
'searching' : true,
|
||||
|
||||
'ordering' : true,
|
||||
'info' : true,
|
||||
'autoWidth' : false,
|
||||
|
||||
// Parameters
|
||||
'pageLength' : tableRows,
|
||||
'order' : tableOrder,
|
||||
// 'order' : [[3,'desc'], [0,'asc']],
|
||||
|
||||
'columnDefs' : [
|
||||
{visible: false, targets: tableColumnHide },
|
||||
{className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15)] },
|
||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
||||
{width: '30px', targets: [mapIndx(10), mapIndx(13)] },
|
||||
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
||||
|
||||
// Device Name
|
||||
{targets: [mapIndx(0)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Connected Devices
|
||||
{targets: [mapIndx(15)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html ('<b><a href="./network.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Icon
|
||||
{targets: [mapIndx(3)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<i class="fa fa-'+cellData+' " style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Full MAC
|
||||
{targets: [mapIndx(11)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeMac">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// IP address
|
||||
{targets: [mapIndx(12)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeIp">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Favorite
|
||||
{targets: [mapIndx(4)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i class="fa fa-star text-yellow" style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Dates
|
||||
{targets: [mapIndx(6), mapIndx(7)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html (translateHTMLcodes (cellData));
|
||||
} },
|
||||
|
||||
// Random MAC
|
||||
{targets: [mapIndx(9)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i data-toggle="tooltip" data-placement="right" title="Random MAC" style="font-size: 16px;" class="text-yellow glyphicon glyphicon-random"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Status color
|
||||
{targets: [mapIndx(10)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
switch (cellData) {
|
||||
case 'Down': color='red'; break;
|
||||
case 'New': color='yellow'; break;
|
||||
case 'On-line': color='green'; break;
|
||||
case 'Off-line': color='gray text-white'; break;
|
||||
case 'Archived': color='gray text-white'; break;
|
||||
default: color='aqua'; break;
|
||||
};
|
||||
|
||||
$(td).html ('<a href="deviceDetails.php?mac='+ rowData[10] +'" class="badge bg-'+ color +'">'+ cellData.replace('-', '') +'</a>');
|
||||
} },
|
||||
],
|
||||
$.get('api/table_devices.json?nocache=' + Date.now(), function(result) {
|
||||
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table> <td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td> </table>',
|
||||
emptyTable: 'No data',
|
||||
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
||||
"search": "<?= lang('Device_Searchbox');?>: ",
|
||||
"paginate": {
|
||||
"next": "<?= lang('Device_Table_nav_next');?>",
|
||||
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
||||
},
|
||||
"info": "<?= lang('Device_Table_info');?>",
|
||||
// query data
|
||||
getDevicesTotals(result.data);
|
||||
|
||||
// Filter the data based on deviceStatus
|
||||
var filteredData = filterDataByStatus(result.data, deviceStatus);
|
||||
|
||||
// Convert JSON data into the desired format
|
||||
var dataArray = {
|
||||
data: filteredData.map(function(item) {
|
||||
var originalRow = [
|
||||
item.dev_Name || "",
|
||||
item.dev_Owner || "",
|
||||
item.dev_DeviceType || "",
|
||||
item.dev_Icon || "",
|
||||
item.dev_Favorite || "",
|
||||
item.dev_Group || "",
|
||||
// ---
|
||||
item.dev_FirstConnection || "",
|
||||
item.dev_LastConnection || "",
|
||||
item.dev_LastIP || "",
|
||||
(isRandomMAC(item.dev_MAC)) || "", // Check if randomized MAC
|
||||
getDeviceStatus(item) || "",
|
||||
item.dev_MAC || "", // hidden
|
||||
formatIPlong(item.dev_LastIP) || "", // IP orderable
|
||||
item.rowid || "",
|
||||
item.dev_Network_Node_MAC_ADDR || "",
|
||||
getNumberOfChildren(item.dev_MAC, result.data) || 0,
|
||||
item.dev_Location || "",
|
||||
item.dev_Vendor || "",
|
||||
item.dev_Network_Node_port || 0
|
||||
];
|
||||
|
||||
var newRow = [];
|
||||
|
||||
// reorder data based on user-defined columns order
|
||||
for (index = 0; index < tableColumnOrder.length; index++) {
|
||||
newRow.push(originalRow[tableColumnOrder[index]]);
|
||||
}
|
||||
|
||||
return newRow;
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
// TODO displayed columns
|
||||
|
||||
|
||||
// Check if the DataTable already exists
|
||||
if ($.fn.dataTable.isDataTable('#tableDevices')) {
|
||||
// The DataTable exists, so destroy it
|
||||
var table = $('#tableDevices').DataTable();
|
||||
table.clear().destroy();
|
||||
}
|
||||
});
|
||||
|
||||
// Save cookie Rows displayed, and Parameters rows & order
|
||||
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parTableRows, len);
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'order.dt', function () {
|
||||
setParameter (parTableOrder, JSON.stringify (table.order()) );
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
var table=
|
||||
$('#tableDevices').DataTable({
|
||||
'data' : dataArray["data"],
|
||||
'paging' : true,
|
||||
'lengthChange' : true,
|
||||
'lengthMenu' : [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, getString('Device_Tablelenght_all')]],
|
||||
'searching' : true,
|
||||
|
||||
$('#tableDevices').on( 'search.dt', function () {
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
'ordering' : true,
|
||||
'info' : true,
|
||||
'autoWidth' : false,
|
||||
|
||||
// Parameters
|
||||
'pageLength' : tableRows,
|
||||
'order' : tableOrder,
|
||||
|
||||
'columnDefs' : [
|
||||
{visible: false, targets: tableColumnHide },
|
||||
{className: 'text-center', targets: [mapIndx(3), mapIndx(4), mapIndx(9), mapIndx(10), mapIndx(15), mapIndx(18)] },
|
||||
{width: '80px', targets: [mapIndx(6), mapIndx(7), mapIndx(15)] },
|
||||
{width: '30px', targets: [mapIndx(10), mapIndx(13), mapIndx(18)] },
|
||||
{orderData: [mapIndx(12)], targets: mapIndx(8) },
|
||||
|
||||
// Device Name
|
||||
{targets: [mapIndx(0)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
|
||||
// console.log(cellData)
|
||||
$(td).html ('<b class="anonymizeDev"><a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
} },
|
||||
|
||||
// Connected Devices
|
||||
{targets: [mapIndx(15)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
// check if this is a network device
|
||||
if(getSetting("NETWORK_DEVICE_TYPES").includes(`'${rowData[mapIndx(2)]}'`) )
|
||||
{
|
||||
$(td).html ('<b><a href="./network.php?mac='+ rowData[mapIndx(11)] +'" class="">'+ cellData +'</a></b>');
|
||||
}
|
||||
else
|
||||
{
|
||||
$(td).html (`<i class="fa-solid fa-xmark" title="${getString("Device_Table_Not_Network_Device")}"></i>`)
|
||||
}
|
||||
|
||||
} },
|
||||
|
||||
// Icon
|
||||
{targets: [mapIndx(3)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<i class="fa fa-'+cellData+' " style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Full MAC
|
||||
{targets: [mapIndx(11)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeMac">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// IP address
|
||||
{targets: [mapIndx(12)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (!emptyArr.includes(cellData)){
|
||||
$(td).html ('<span class="anonymizeIp">'+cellData+'</span>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Favorite
|
||||
{targets: [mapIndx(4)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i class="fa fa-star text-yellow" style="font-size:16px"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Dates
|
||||
{targets: [mapIndx(6), mapIndx(7)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
$(td).html (translateHTMLcodes (cellData));
|
||||
} },
|
||||
|
||||
// Random MAC
|
||||
{targets: [mapIndx(9)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
// console.log(cellData)
|
||||
if (cellData == 1){
|
||||
$(td).html ('<i data-toggle="tooltip" data-placement="right" title="Random MAC" style="font-size: 16px;" class="text-yellow glyphicon glyphicon-random"></i>');
|
||||
} else {
|
||||
$(td).html ('');
|
||||
}
|
||||
} },
|
||||
|
||||
// Status color
|
||||
{targets: [mapIndx(10)],
|
||||
'createdCell': function (td, cellData, rowData, row, col) {
|
||||
|
||||
// console.log(cellData)
|
||||
switch (cellData) {
|
||||
case 'Down': color='red'; break;
|
||||
case 'New': color='yellow'; break;
|
||||
case 'On-line': color='green'; break;
|
||||
case 'Off-line': color='gray text-white'; break;
|
||||
case 'Archived': color='gray text-white'; break;
|
||||
default: color='aqua'; break;
|
||||
};
|
||||
|
||||
$(td).html ('<a href="deviceDetails.php?mac='+ rowData[mapIndx(11)] +'" class="badge bg-'+ color +'">'+ cellData.replace('-', '') +'</a>');
|
||||
} },
|
||||
],
|
||||
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table> <td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td> </table>',
|
||||
emptyTable: 'No data',
|
||||
"lengthMenu": "<?= lang('Device_Tablelenght');?>",
|
||||
"search": "<?= lang('Device_Searchbox');?>: ",
|
||||
"paginate": {
|
||||
"next": "<?= lang('Device_Table_nav_next');?>",
|
||||
"previous": "<?= lang('Device_Table_nav_prev');?>"
|
||||
},
|
||||
"info": "<?= lang('Device_Table_info');?>",
|
||||
}
|
||||
});
|
||||
|
||||
// Save cookie Rows displayed, and Parameters rows & order
|
||||
$('#tableDevices').on( 'length.dt', function ( e, settings, len ) {
|
||||
setParameter (parTableRows, len);
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'order.dt', function () {
|
||||
setParameter (parTableOrder, JSON.stringify (table.order()) );
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
|
||||
$('#tableDevices').on( 'search.dt', function () {
|
||||
setCache ('devicesList', getDevicesFromTable(table) );
|
||||
} );
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -492,57 +689,45 @@ function getDevicesFromTable(table)
|
||||
return JSON.stringify (result)
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDevicesTotals () {
|
||||
// stop timer
|
||||
stopTimerRefreshData();
|
||||
function getNumberOfChildren(mac, devices)
|
||||
{
|
||||
childrenCount = 0;
|
||||
|
||||
// get totals and put in boxes
|
||||
$.get('php/server/devices.php?action=getDevicesTotals', function(data) {
|
||||
var totalsDevices = JSON.parse(data);
|
||||
$.each(devices, function(index, dev) {
|
||||
|
||||
$('#devicesAll').html (totalsDevices[0].toLocaleString());
|
||||
$('#devicesConnected').html (totalsDevices[1].toLocaleString());
|
||||
$('#devicesFavorites').html (totalsDevices[2].toLocaleString());
|
||||
$('#devicesNew').html (totalsDevices[3].toLocaleString());
|
||||
$('#devicesDown').html (totalsDevices[4].toLocaleString());
|
||||
$('#devicesArchived').html (totalsDevices[5].toLocaleString());
|
||||
if(dev.dev_Network_Node_MAC_ADDR.trim() == mac.trim())
|
||||
{
|
||||
childrenCount++;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Timer for refresh data
|
||||
newTimerRefreshData (getDevicesTotals);
|
||||
} );
|
||||
return childrenCount;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDeviceColumns () {
|
||||
function handleLoadingDialog()
|
||||
{
|
||||
$.get('log/execution_queue.log?nocache=' + Date.now(), function(data) {
|
||||
|
||||
|
||||
if(data.includes("update_api|devices"))
|
||||
{
|
||||
showSpinner("devices_old")
|
||||
|
||||
setTimeout("handleLoadingDialog()", 1000);
|
||||
|
||||
} else if ($("#loadingSpinner").is(":visible"))
|
||||
{
|
||||
hideSpinner();
|
||||
location.reload();
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
function getDevicesList (status) {
|
||||
// Save status selected
|
||||
deviceStatus = status;
|
||||
|
||||
// Define color & title for the status selected
|
||||
switch (deviceStatus) {
|
||||
case 'all': tableTitle = '<?= lang('Device_Shortcut_AllDevices');?>'; color = 'aqua'; break;
|
||||
case 'connected': tableTitle = '<?= lang('Device_Shortcut_Connected');?>'; color = 'green'; break;
|
||||
case 'favorites': tableTitle = '<?= lang('Device_Shortcut_Favorites');?>'; color = 'yellow'; break;
|
||||
case 'new': tableTitle = '<?= lang('Device_Shortcut_NewDevices');?>'; color = 'yellow'; break;
|
||||
case 'down': tableTitle = '<?= lang('Device_Shortcut_DownAlerts');?>'; color = 'red'; break;
|
||||
case 'archived': tableTitle = '<?= lang('Device_Shortcut_Archived');?>'; color = 'gray'; break;
|
||||
default: tableTitle = '<?= lang('Device_Shortcut_Devices');?>'; color = 'gray'; break;
|
||||
}
|
||||
|
||||
// Set title and color
|
||||
$('#tableDevicesTitle')[0].className = 'box-title text-'+ color;
|
||||
$('#tableDevicesBox')[0].className = 'box box-'+ color;
|
||||
$('#tableDevicesTitle').html (tableTitle);
|
||||
|
||||
// Define new datasource URL and reload
|
||||
$('#tableDevices').DataTable().ajax.url(
|
||||
'php/server/devices.php?action=getDevicesList&status=' + deviceStatus).load();
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
70
front/donations.php
Executable file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
require 'php/templates/header.php';
|
||||
?>
|
||||
<script src="js/pialert_common.js"></script>
|
||||
<div id="donationsPage" class="content-wrapper">
|
||||
<!-- Content header--------------------------------------------------------- -->
|
||||
<section class="content-header">
|
||||
<h1 id="pageTitle">
|
||||
<i class="fa fa-heart"></i>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<!-- Main content ---------------------------------------------------------- -->
|
||||
<section class="content donations">
|
||||
<div id="donationsText" class="box box-solid"></div>
|
||||
<div class="content-header">
|
||||
<h3 class="box-title " id="donationsPlatforms"></h3>
|
||||
</div>
|
||||
<div class="box box-solid">
|
||||
<div class="box-body">
|
||||
<div class="col-sm-2">
|
||||
<a target="_blank" href="https://github.com/sponsors/jokob-sk">
|
||||
<img alt="Sponsor Me on GitHub" src="https://i.imgur.com/X6p5ACK.png" width="150px">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<a target="_blank" href="https://www.buymeacoffee.com/jokobsk">
|
||||
<img alt="Buy Me A Coffee" src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" width="117px" height="30px">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<a target="_blank" href="https://www.patreon.com/user?u=84385063">
|
||||
<img alt="Support me on patreon" src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Patreon_logo_with_wordmark.svg/512px-Patreon_logo_with_wordmark.svg.png" width="117px">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-header">
|
||||
<h3 class="box-title " id="donationsOthers"></h3>
|
||||
</div>
|
||||
<div class="box box-solid">
|
||||
<div class="box-body">
|
||||
<div class="col-sm-12">
|
||||
<ul>
|
||||
<li>Bitcoin: <code>1N8tupjeCK12qRVU2XrV17WvKK7LCawyZM</code></li>
|
||||
<li>Ethereum: <code>0x6e2749Cb42F4411bc98501406BdcD82244e3f9C7</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
</section>
|
||||
|
||||
</div> <!-- End of class="content-wrapper" -->
|
||||
|
||||
<script>
|
||||
function init()
|
||||
{
|
||||
$("#donationsText").html(getString("Donations_Text"))
|
||||
$("#pageTitle").append(getString("Donations_Title"))
|
||||
$("#donationsPlatforms").append(getString("Donations_Platforms"))
|
||||
$("#donationsOthers").append(getString("Donations_Others"))
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
<?php
|
||||
require 'php/templates/footer.php';
|
||||
?>
|
||||
@@ -1,14 +1,19 @@
|
||||
<!-- ---------------------------------------------------------------------------
|
||||
# Pi.Alert
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
#
|
||||
# events.php - Front module. Events page
|
||||
#-------------------------------------------------------------------------------
|
||||
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
||||
#--------------------------------------------------------------------------- -->
|
||||
<!--
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# events.php - Front module. Events page #
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
#---------------------------------------------------------------------------------#
|
||||
-->
|
||||
|
||||
<?php
|
||||
require 'php/templates/header.php';
|
||||
require 'php/templates/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page ------------------------------------------------------------------ -->
|
||||
@@ -17,7 +22,8 @@
|
||||
<!-- Content header--------------------------------------------------------- -->
|
||||
<section class="content-header">
|
||||
<h1 id="pageTitle">
|
||||
<?= lang('Events_Title');?>
|
||||
<i class="fa fa-bolt"></i>
|
||||
<?= lang('Events_Title');?>
|
||||
</h1>
|
||||
|
||||
<!-- period selector -->
|
||||
@@ -251,7 +257,7 @@ function initializeDatatable () {
|
||||
// Processing
|
||||
'processing' : true,
|
||||
'language' : {
|
||||
processing: '<table><td width="130px" align="middle">Loading...</td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td></table>',
|
||||
processing: '<table><td width="130px" align="middle"><?= lang("Events_Loading");?></td><td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td></table>',
|
||||
emptyTable: 'No data',
|
||||
"lengthMenu": "<?= lang('Events_Tablelenght');?>",
|
||||
"search": "<?= lang('Events_Searchbox');?>: ",
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
<section class="content-header">
|
||||
<?php require 'php/templates/notification.php'; ?>
|
||||
<h1 id="pageTitle">
|
||||
<?= lang('HelpFAQ_Title');?>
|
||||
<i class="fa fa-question"></i>
|
||||
<?= lang('HelpFAQ_Title');?>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
<!-- Main content ---------------------------------------------------------- -->
|
||||
<section class="content">
|
||||
<h4><?= lang('HelpFAQ_Cat_General');?></h4>
|
||||
<h4>
|
||||
<i class="fa fa-question"></i>
|
||||
<?= lang('HelpFAQ_Cat_General');?>
|
||||
</h4>
|
||||
|
||||
<div class="panel-group" id="accordion_gen">
|
||||
<div class="panel panel-default">
|
||||
@@ -89,10 +93,26 @@
|
||||
<?= lang('HelpFAQ_Cat_General_103_text');?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion_net" href="#collapse601">
|
||||
<?= lang('HelpFAQ_Cat_Network_601_head');?></a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapse601" class="panel-collapse collapse" style="font-size: 16px;">
|
||||
<div class="panel-body">
|
||||
<?= lang('HelpFAQ_Cat_Network_601_text');?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><?= lang('Navigation_Devices');?></h4>
|
||||
<h4>
|
||||
<i class="fa fa-laptop"></i>
|
||||
<?= lang('Navigation_Devices');?>
|
||||
</h4>
|
||||
<div class="panel-group" id="accordion_dev">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -110,7 +130,8 @@
|
||||
</div>
|
||||
|
||||
|
||||
<h4><?= lang('HelpFAQ_Cat_Detail');?></h4>
|
||||
<h4>
|
||||
<i class="fa fa-info-circle"></i><?= lang('HelpFAQ_Cat_Detail');?></h4>
|
||||
<div class="panel-group" id="accordion_det">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -164,10 +185,14 @@
|
||||
<?= lang('HelpFAQ_Cat_Detail_303_text');?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><?= lang('Navigation_Presence');?></h4>
|
||||
<h4>
|
||||
<i class="fa fa-calendar"></i>
|
||||
<?= lang('Navigation_Presence');?>
|
||||
</h4>
|
||||
<div class="panel-group" id="accordion_pre">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -197,7 +222,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><?= lang('Navigation_Network');?></h4>
|
||||
<h4>
|
||||
<i class="fa fa-network-wired"></i><?= lang('Navigation_Network');?></h4>
|
||||
<div class="panel-group" id="accordion_net">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -211,10 +237,11 @@
|
||||
<?= lang('HelpFAQ_Cat_Network_600_text');?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<br>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
|
||||
@@ -2,6 +2,7 @@ function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_
|
||||
var xValues = pia_js_graph_online_history_time;
|
||||
new Chart("OnlineChart", {
|
||||
type: "bar",
|
||||
scaleIntegersOnly: true,
|
||||
data: {
|
||||
labels: xValues,
|
||||
datasets: [{
|
||||
@@ -60,4 +61,4 @@ function pia_draw_graph_online_history(pia_js_graph_online_history_time, pia_js_
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,51 @@
|
||||
function handleVersion(){
|
||||
//--------------------------------------------------------------
|
||||
// Handle the UI changes to show or hide notifications about a new version
|
||||
function versionUpdateUI(){
|
||||
|
||||
release_timestamp = getCookie("release_timestamp")
|
||||
isNewVersion = getCookie("isNewVersion")
|
||||
|
||||
if(release_timestamp != "")
|
||||
{
|
||||
console.log(isNewVersion)
|
||||
|
||||
build_timestamp = parseInt($('#version').attr("data-build-time").match( /\d+/g ).join(''))
|
||||
|
||||
// if the release_timestamp is older by 10 min or more as the build timestamp then there is a new release available
|
||||
if(release_timestamp > build_timestamp + 600 )
|
||||
{
|
||||
console.log("New release!")
|
||||
// handling the navigation menu icon
|
||||
$('#version').attr("class", $('#version').attr("class").replace("myhidden", ""))
|
||||
|
||||
maintenanceDiv = $('#new-version-text')
|
||||
}
|
||||
else{
|
||||
console.log("All up-to-date!")
|
||||
|
||||
maintenanceDiv = $('#current-version-text')
|
||||
}
|
||||
|
||||
// handling the maintenance section message
|
||||
if(emptyArr.includes(maintenanceDiv) == false && $(maintenanceDiv).length != 0)
|
||||
{
|
||||
$(maintenanceDiv).attr("class", $(maintenanceDiv).attr("class").replace("myhidden", ""))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
|
||||
function getVersion()
|
||||
// if the release_timestamp is older by 10 min or more as the build timestamp then there is a new release available
|
||||
if(isNewVersion != "false")
|
||||
{
|
||||
release_timestamp = getCookie("release_timestamp")
|
||||
console.log("New release!")
|
||||
// handling the navigation menu icon
|
||||
$('#version').attr("class", $('#version').attr("class").replace("myhidden", ""))
|
||||
|
||||
// no cached value available
|
||||
if(release_timestamp == "")
|
||||
{
|
||||
// get parameter value
|
||||
$.get('https://api.github.com/repos/jokob-sk/Pi.Alert/releases', function(data) {
|
||||
|
||||
var releases = data;
|
||||
maintenanceDiv = $('#new-version-text')
|
||||
}
|
||||
else{
|
||||
console.log("All up-to-date!")
|
||||
|
||||
if(releases.length > 0)
|
||||
{
|
||||
release_datetime = releases[0].published_at;
|
||||
release_timestamp = new Date(release_datetime).getTime() / 1000;
|
||||
|
||||
// cache value
|
||||
setCookie("release_timestamp", release_timestamp, 30);
|
||||
|
||||
handleVersion();
|
||||
}
|
||||
});
|
||||
} else
|
||||
{
|
||||
// cache is available, just call the handler
|
||||
handleVersion()
|
||||
}
|
||||
maintenanceDiv = $('#current-version-text')
|
||||
}
|
||||
|
||||
// handling the maintenance section message
|
||||
if(emptyArr.includes(maintenanceDiv) == false && $(maintenanceDiv).length != 0)
|
||||
{
|
||||
$(maintenanceDiv).attr("class", $(maintenanceDiv).attr("class").replace("myhidden", ""))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Checks if a new version is available via the global app_state.json
|
||||
function checkIfNewVersionAvailable()
|
||||
{
|
||||
$.get('api/app_state.json?nocache=' + Date.now(), function(appState) {
|
||||
|
||||
console.log(appState["isNewVersionChecked"])
|
||||
console.log(appState["isNewVersion"])
|
||||
|
||||
// cache value
|
||||
setCookie("isNewVersion", appState["isNewVersion"], 30);
|
||||
setCookie("isNewVersionChecked", appState["isNewVersionChecked"], 30);
|
||||
|
||||
versionUpdateUI();
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// handle the dispaly of the NEW icon
|
||||
getVersion()
|
||||
checkIfNewVersionAvailable()
|
||||
@@ -11,6 +11,9 @@
|
||||
var timerRefreshData = ''
|
||||
var modalCallbackFunction = '';
|
||||
var emptyArr = ['undefined', "", undefined, null, 'null'];
|
||||
var UI_LANG = "English";
|
||||
var settingsJSON = {}
|
||||
|
||||
|
||||
// urlParams = new Proxy(new URLSearchParams(window.location.search), {
|
||||
// get: (searchParams, prop) => searchParams.get(prop.toString()),
|
||||
@@ -20,13 +23,13 @@ var emptyArr = ['undefined', "", undefined, null, 'null'];
|
||||
// -----------------------------------------------------------------------------
|
||||
// Simple session cache withe expiration managed via cookies
|
||||
// -----------------------------------------------------------------------------
|
||||
function getCache(key)
|
||||
function getCache(key, noCookie = false)
|
||||
{
|
||||
// check cache
|
||||
if(sessionStorage.getItem(key))
|
||||
{
|
||||
// check if not expired
|
||||
if(getCookie(key + '_session_expiry') != "")
|
||||
if(noCookie || getCookie(key + '_session_expiry') != "")
|
||||
{
|
||||
return sessionStorage.getItem(key);
|
||||
}
|
||||
@@ -38,8 +41,13 @@ function getCache(key)
|
||||
// -----------------------------------------------------------------------------
|
||||
function setCache(key, data, expirationMinutes='')
|
||||
{
|
||||
sessionStorage.setItem(key, data);
|
||||
setCookie (key + '_session_expiry', 'OK', expirationMinutes='')
|
||||
sessionStorage.setItem(key, data);
|
||||
|
||||
// create cookie if expiration set to handle refresh of data
|
||||
if (expirationMinutes != '')
|
||||
{
|
||||
setCookie (key + '_session_expiry', 'OK', expirationMinutes='')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,10 +104,107 @@ function deleteAllCookies() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Get settings from the .json file generated by the python backend
|
||||
// -----------------------------------------------------------------------------
|
||||
function cacheSettings()
|
||||
{
|
||||
|
||||
$.get('api/table_settings.json', function(res) {
|
||||
|
||||
settingsJSON = res;
|
||||
|
||||
data = settingsJSON["data"];
|
||||
|
||||
data.forEach((set) => {
|
||||
setCache(`pia_set_${set.Code_Name}`, set.Value)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function getSetting (key) {
|
||||
|
||||
result = getCache(`pia_set_${key}`, true);
|
||||
|
||||
if (result == "")
|
||||
{
|
||||
console.log(`Setting with key "${key}" not found`)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Get language string
|
||||
// -----------------------------------------------------------------------------
|
||||
function cacheStrings()
|
||||
{
|
||||
|
||||
// handle core strings and translations
|
||||
var allLanguages = ["en_us", "es_es", "de_de"]; // needs to be same as in lang.php
|
||||
|
||||
allLanguages.forEach(function (language_code) {
|
||||
$.get(`php/templates/language/${language_code}.json`, function (res) {
|
||||
// Iterate over each language
|
||||
Object.entries(res).forEach(([key, value]) => {
|
||||
// Store translations for each key-value pair
|
||||
setCache(`pia_lang_${key}_${language_code}`, value)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// handle strings and translations from plugins
|
||||
$.get('api/table_plugins_language_strings.json', function(res) {
|
||||
|
||||
data = res["data"];
|
||||
|
||||
data.forEach((langString) => {
|
||||
setCache(`pia_lang_${langString.String_Key}_${langString.Language_Code}`, langString.String_Value)
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Get translated language string
|
||||
function getString (key) {
|
||||
|
||||
UI_LANG = getSetting("UI_LANG");
|
||||
|
||||
lang_code = 'en_us';
|
||||
|
||||
switch(UI_LANG)
|
||||
{
|
||||
case 'English':
|
||||
lang_code = 'en_us';
|
||||
break;
|
||||
case 'Spanish':
|
||||
lang_code = 'es_es';
|
||||
break;
|
||||
case 'German':
|
||||
lang_code = 'de_de';
|
||||
break;
|
||||
}
|
||||
result = getCache(`pia_lang_${key}_${lang_code}`, true);
|
||||
|
||||
|
||||
if(isEmpty(result))
|
||||
{
|
||||
result = getCache(`pia_lang_${key}_en_us`, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Modal dialog handling
|
||||
// -----------------------------------------------------------------------------
|
||||
function showModalOk (title, message, callbackFunction = null) {
|
||||
function showModalOK (title, message, callbackFunction) {
|
||||
showModalOk (title, message, callbackFunction)
|
||||
}
|
||||
function showModalOk (title, message, callbackFunction) {
|
||||
// set captions
|
||||
$('#modal-ok-title').html (title);
|
||||
$('#modal-ok-message').html (message);
|
||||
@@ -115,6 +220,8 @@ function showModalOk (title, message, callbackFunction = null) {
|
||||
// Show modal
|
||||
$('#modal-ok').modal('show');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function showModalDefault (title, message, btnCancel, btnOK, callbackFunction) {
|
||||
// set captions
|
||||
$('#modal-default-title').html (title);
|
||||
@@ -146,13 +253,17 @@ function showModalDefaultStrParam (title, message, btnCancel, btnOK, callbackFun
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function showModalWarning (title, message, btnCancel, btnOK, callbackFunction) {
|
||||
function showModalWarning (title, message, btnCancel=getString('Gen_Cancel'), btnOK=getString('Gen_Okay'), callbackFunction=null) {
|
||||
// set captions
|
||||
$('#modal-warning-title').html (title);
|
||||
$('#modal-warning-message').html (message);
|
||||
$('#modal-warning-cancel').html (btnCancel);
|
||||
$('#modal-warning-OK').html (btnOK);
|
||||
modalCallbackFunction = callbackFunction;
|
||||
|
||||
if ( callbackFunction != null)
|
||||
{
|
||||
modalCallbackFunction = callbackFunction;
|
||||
}
|
||||
|
||||
// Show modal
|
||||
$('#modal-warning').modal('show');
|
||||
@@ -197,18 +308,69 @@ function showMessage (textMessage="") {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// String utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
function jsonSyntaxHighlight(json) {
|
||||
if (typeof json != 'string') {
|
||||
json = JSON.stringify(json, undefined, 2);
|
||||
}
|
||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||
var cls = 'number';
|
||||
if (/^"/.test(match)) {
|
||||
if (/:$/.test(match)) {
|
||||
cls = 'key';
|
||||
} else {
|
||||
cls = 'string';
|
||||
}
|
||||
} else if (/true|false/.test(match)) {
|
||||
cls = 'boolean';
|
||||
} else if (/null/.test(match)) {
|
||||
cls = 'null';
|
||||
}
|
||||
return '<span class="' + cls + '">' + match + '</span>';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// General utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// check if JSON object
|
||||
function isJsonObject(value) {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
|
||||
// remove unnecessary lines from the result
|
||||
function sanitize(data)
|
||||
{
|
||||
return data.replace(/(\r\n|\n|\r)/gm,"").replace(/[^\x00-\x7F]/g, "")
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Check and handle locked database
|
||||
function handle_locked_DB(data)
|
||||
{
|
||||
if(data.includes('database is locked'))
|
||||
{
|
||||
console.log(data)
|
||||
showSpinner()
|
||||
|
||||
setTimeout(function() {
|
||||
location.reload();
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function numberArrayFromString(data)
|
||||
{
|
||||
|
||||
|
||||
data = JSON.parse(sanitize(data));
|
||||
return data.replace(/\[|\]/g, '').split(',').map(Number);
|
||||
}
|
||||
@@ -260,6 +422,19 @@ function saveData(functionName, id, value) {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// create a link to the device
|
||||
function createDeviceLink(input)
|
||||
{
|
||||
if(checkMacOrInternet(input))
|
||||
{
|
||||
return `<span class="anonymizeMac"><a href="/deviceDetails.php?mac=${input}" target="_blank">${getNameByMacAddress(input)}</a><span>`
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// remove an item from an array
|
||||
function removeItemFromArray(arr, value) {
|
||||
@@ -363,12 +538,245 @@ function navigateToDeviceWithIp (ip) {
|
||||
window.open(window.location.origin +'/deviceDetails.php?mac=' + mac , "_blank");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function getNameByMacAddress(macAddress) {
|
||||
return getDeviceDataByMacAddress(macAddress, "dev_Name")
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Check if MAC or Internet
|
||||
function checkMacOrInternet(inputStr) {
|
||||
// Regular expression pattern for matching a MAC address
|
||||
const macPattern = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
||||
|
||||
if (inputStr.toLowerCase() === 'internet') {
|
||||
return true;
|
||||
} else if (macPattern.test(inputStr)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// A function used to make the IP address orderable
|
||||
function isValidIPv6(ipAddress) {
|
||||
// Regular expression for IPv6 validation
|
||||
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,7}:|^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$|^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$|^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$|^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$/;
|
||||
|
||||
return ipv6Regex.test(ipAddress);
|
||||
}
|
||||
|
||||
function formatIPlong(ipAddress) {
|
||||
if (ipAddress.includes(':') && isValidIPv6(ipAddress)) {
|
||||
const parts = ipAddress.split(':');
|
||||
|
||||
return parts.reduce((acc, part, index) => {
|
||||
if (part === '') {
|
||||
const remainingGroups = 8 - parts.length + 1;
|
||||
return acc << (16 * remainingGroups);
|
||||
}
|
||||
|
||||
const hexValue = parseInt(part, 16);
|
||||
return acc | (hexValue << (112 - index * 16));
|
||||
}, 0);
|
||||
} else {
|
||||
// Handle IPv4 address
|
||||
const parts = ipAddress.split('.');
|
||||
|
||||
if (parts.length !== 4) {
|
||||
console.log("⚠ Invalid IPv4 address: " + ipAddress);
|
||||
return -1; // or any other default value indicating an error
|
||||
}
|
||||
|
||||
return (parseInt(parts[0]) << 24) |
|
||||
(parseInt(parts[1]) << 16) |
|
||||
(parseInt(parts[2]) << 8) |
|
||||
parseInt(parts[3]);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Check if MAC is a random one
|
||||
function isRandomMAC(mac)
|
||||
{
|
||||
isRandom = false;
|
||||
|
||||
isRandom = ["2", "6", "A", "E", "a", "e"].includes(mac[1]);
|
||||
|
||||
// if detected as random, make sure it doesn't start with a prefix which teh suer doesn't want to mark as random
|
||||
if(isRandom)
|
||||
{
|
||||
$.each(createArray(getSetting("UI_NOT_RANDOM_MAC")), function(index, prefix) {
|
||||
|
||||
if(mac.startsWith(prefix))
|
||||
{
|
||||
isRandom = false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return isRandom;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Generate an array object from a string representation of an array
|
||||
function createArray(input) {
|
||||
// Empty array
|
||||
if (input === '[]') {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Regex patterns
|
||||
const patternBrackets = /(^\s*\[)|(\]\s*$)/g;
|
||||
const patternQuotes = /(^\s*')|('\s*$)/g;
|
||||
const replacement = '';
|
||||
|
||||
// Remove brackets
|
||||
const noBrackets = input.replace(patternBrackets, replacement);
|
||||
|
||||
const options = [];
|
||||
|
||||
// Create array
|
||||
const optionsTmp = noBrackets.split(',');
|
||||
|
||||
// Handle only one item in array
|
||||
if (optionsTmp.length === 0) {
|
||||
return [noBrackets.replace(patternQuotes, replacement)];
|
||||
}
|
||||
|
||||
// Remove quotes
|
||||
optionsTmp.forEach(item => {
|
||||
options.push(item.replace(patternQuotes, replacement).trim());
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// A function to get a device property using the mac address as key and DB column nakme as parameter
|
||||
// for the value to be returned
|
||||
function getDeviceDataByMacAddress(macAddress, dbColumn) {
|
||||
|
||||
const sessionDataKey = 'devicesListAll_JSON';
|
||||
const sessionData = sessionStorage.getItem(sessionDataKey);
|
||||
|
||||
if (!sessionData) {
|
||||
console.log(`Session variable "${sessionDataKey}" not found.`);
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const devices = JSON.parse(sessionData);
|
||||
|
||||
for (const device of devices) {
|
||||
if (device["dev_MAC"].toLowerCase() === macAddress.toLowerCase()) {
|
||||
|
||||
return device[dbColumn];
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown"; // Return a default value if MAC address is not found
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
function initDeviceListAll_JSON()
|
||||
{
|
||||
|
||||
$.get('api/table_devices.json', function(data) {
|
||||
|
||||
console.log(data)
|
||||
|
||||
devicesListAll_JSON = data["data"]
|
||||
|
||||
setCache('devicesListAll_JSON', JSON.stringify(devicesListAll_JSON))
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
var devicesListAll_JSON = []; // this will contain a list off all devices
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
function isEmpty(value)
|
||||
{
|
||||
return emptyArr.includes(value)
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Generate a GUID
|
||||
function getGuid() {
|
||||
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
|
||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// UI
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// Genrate work-in-progress icons
|
||||
function workInProgress() {
|
||||
console.log()
|
||||
if($(".work-in-progress").html().trim() == "")
|
||||
{
|
||||
$(".work-in-progress").append(`
|
||||
<a href="https://github.com/jokob-sk/Pi.Alert/issues" target="_blank">
|
||||
<b class="pointer" title="${getString("Gen_Work_In_Progress")}">🦺</b>
|
||||
</a>
|
||||
`)
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Loading Spinner overlay
|
||||
// -----------------------------------------------------------------------------
|
||||
function showSpinner(stringKey='Loading')
|
||||
{
|
||||
if($("#loadingSpinner").length)
|
||||
{
|
||||
|
||||
$("#loadingSpinner").show();
|
||||
}
|
||||
else{
|
||||
html = `
|
||||
<!-- spinner -->
|
||||
<div id="loadingSpinner" style="display: block">
|
||||
<div class="pa_semitransparent-panel"></div>
|
||||
<div class="panel panel-default pa_spinner">
|
||||
<table>
|
||||
<td width="130px" align="middle">${getString(stringKey)}</td>
|
||||
<td><i class="ion ion-ios-loop-strong fa-spin fa-2x fa-fw"></td>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
$(".wrapper").append(html)
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
function hideSpinner()
|
||||
{
|
||||
$("#loadingSpinner").hide()
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// initialize
|
||||
// -----------------------------------------------------------------------------
|
||||
cacheSettings()
|
||||
cacheStrings()
|
||||
initDeviceListAll_JSON()
|
||||
workInProgress()
|
||||
|
||||
|
||||
console.log("init pialert_common.js")
|
||||
|
||||
|
||||
|
||||
166
front/js/settings_utils.js
Executable file
@@ -0,0 +1,166 @@
|
||||
// -------------------------------------------------------------------
|
||||
// Get all plugin prefixes of a given type
|
||||
function getPluginsByType(pluginsData, pluginType, onlyEnabled)
|
||||
{
|
||||
|
||||
var result = []
|
||||
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if(plug.plugin_type == pluginType)
|
||||
{
|
||||
// collect all, or if only enabled, check if NOT disabled
|
||||
if (onlyEnabled == false || (onlyEnabled && getSetting(plug.unique_prefix + '_RUN') != 'disabled')) {
|
||||
result.push(plug.unique_prefix)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get plugin type base on prefix
|
||||
function getPluginCodeName(pluginsData, prefix)
|
||||
{
|
||||
var result = ""
|
||||
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if (plug.unique_prefix == prefix ) {
|
||||
id = plug.code_name;
|
||||
|
||||
// console.log(id)
|
||||
result = plug.code_name;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Get plugin type base on prefix
|
||||
function getPluginType(pluginsData, prefix)
|
||||
{
|
||||
var result = "core"
|
||||
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if (plug.unique_prefix == prefix ) {
|
||||
id = plug.plugin_type;
|
||||
|
||||
// console.log(id)
|
||||
result = plug.plugin_type;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Generate plugin HTML card based on prefixes in an array
|
||||
function pluginCards(prefixesOfEnabledPlugins, includeSettings)
|
||||
{
|
||||
html = ""
|
||||
|
||||
prefixesOfEnabledPlugins.forEach((prefix) => {
|
||||
|
||||
includeSettings_html = ''
|
||||
|
||||
includeSettings.forEach((set) => {
|
||||
|
||||
includeSettings_html += `
|
||||
<a href="#${prefix + '_' + set}" onclick="toggleAllSettings()">
|
||||
<div class="overview-setting-value pointer" title="${prefix + '_' + set}">
|
||||
<code>${getSetting(prefix + '_' + set)}</code>
|
||||
</div>
|
||||
</a>
|
||||
`
|
||||
|
||||
});
|
||||
|
||||
html += `
|
||||
<div class="col-sm-4 ">
|
||||
<div class="small-box bg-green " >
|
||||
<div class="inner ">
|
||||
<a href="#${prefix}_header" onclick="toggleAllSettings('open')">
|
||||
<h5 class="card-title">
|
||||
<b>${getString(prefix+"_display_name")}</b>
|
||||
</h5>
|
||||
</a>
|
||||
${includeSettings_html}
|
||||
</div>
|
||||
<a href="#${prefix}_header" onclick="toggleAllSettings('open')">
|
||||
<div class="icon"> ${getString(prefix+"_icon")} </div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Open or close all settings
|
||||
// -----------------------------------------------------------------------------
|
||||
function toggleAllSettings(openOrClose = '')
|
||||
{
|
||||
inStr = ' in';
|
||||
allOpen = true;
|
||||
openIcon = 'fa-angle-double-down';
|
||||
closeIcon = 'fa-angle-double-up';
|
||||
|
||||
$('.panel-collapse').each(function(){
|
||||
if($(this).attr('class').indexOf(inStr) == -1)
|
||||
{
|
||||
allOpen = false;
|
||||
}
|
||||
})
|
||||
|
||||
if(allOpen == false || openOrClose == 'open')
|
||||
{
|
||||
// open all
|
||||
$('div[data-myid="collapsible"]').each(function(){$(this).attr('class', 'panel-collapse collapse in')})
|
||||
$('div[data-myid="collapsible"]').each(function(){$(this).attr('style', 'height:inherit')})
|
||||
$('#toggleSettings').attr('class', $('#toggleSettings').attr('class').replace(openIcon, closeIcon))
|
||||
|
||||
}
|
||||
else{
|
||||
// close all
|
||||
$('div[data-myid="collapsible"]').each(function(){$(this).attr('class', 'panel-collapse collapse ')})
|
||||
$('#toggleSettings').attr('class', $('#toggleSettings').attr('class').replace(closeIcon, openIcon))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Checks if all schedules are the same
|
||||
function schedulesAreSynchronized(prefixesOfEnabledPlugins, pluginsData)
|
||||
{
|
||||
plug_schedules = []
|
||||
|
||||
prefixesOfEnabledPlugins.forEach((prefix) => {
|
||||
pluginsData.forEach((plug) => {
|
||||
|
||||
if (plug.unique_prefix == prefix) {
|
||||
|
||||
plug_schedules.push(getSetting(prefix+"_RUN_SCHD").replace(/\s/g, "")) // replace all white characters to compare them easier
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// Check if all plug_schedules are the same
|
||||
if (plug_schedules.length > 0) {
|
||||
const firstSchedule = plug_schedules[0];
|
||||
return plug_schedules.every((schedule) => schedule === firstSchedule);
|
||||
}
|
||||
|
||||
return true; // Return true if no schedules are found
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
<?php
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Pi.Alert
|
||||
// Open Source Network Guard / WIFI & LAN intrusion detector
|
||||
//
|
||||
// devices.php - Front module. Server side. Manage Devices
|
||||
//------------------------------------------------------------------------------
|
||||
// Puche 2021 pi.alert.application@gmail.com GNU GPLv3
|
||||
// jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3
|
||||
// leiweibau 2022 https://github.com/leiweibau GNU GPLv3
|
||||
//------------------------------------------------------------------------------
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# maintenance.php - Front module. Server side. Maintenance #
|
||||
#---------------------------------------------------------------------------------#
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
#---------------------------------------------------------------------------------#
|
||||
|
||||
// Skin selector config ----------------------------------------------------
|
||||
//
|
||||
@@ -44,7 +44,8 @@ $pia_installed_skins = array('skin-black-light',
|
||||
<section class="content-header">
|
||||
<?php require 'php/templates/notification.php'; ?>
|
||||
<h1 id="pageTitle">
|
||||
<?= lang('Maintenance_Title');?>
|
||||
<i class="fa fa-wrench"></i>
|
||||
<?= lang('Maintenance_Title');?>
|
||||
</h1>
|
||||
</section>
|
||||
|
||||
@@ -118,6 +119,30 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Table sizes -----------------------------------------------------------------
|
||||
|
||||
$tableSizesHTML = "";
|
||||
|
||||
// Open a connection to the SQLite database
|
||||
$db = new SQLite3($pia_db);
|
||||
|
||||
// Retrieve the table names from sqlite_master
|
||||
$query = "SELECT name FROM sqlite_master WHERE type='table'";
|
||||
$result = $db->query($query);
|
||||
|
||||
// Iterate over the tables and get the row counts
|
||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||
$tableName = $row['name'];
|
||||
$query = "SELECT COUNT(*) FROM $tableName";
|
||||
$countResult = $db->querySingle($query);
|
||||
$tableSizesHTML = $tableSizesHTML . "$tableName (<b>$countResult</b>), ";
|
||||
}
|
||||
|
||||
// Close the database connection
|
||||
$db->close();
|
||||
|
||||
|
||||
|
||||
|
||||
// Language selector -----------------------------------------------------------------
|
||||
|
||||
@@ -127,7 +152,10 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
<div class="col-md-12">
|
||||
<div class="box" id="Maintain-Status">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Status</h3>
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-display"></i></i>
|
||||
<?= lang('Maintenance_Status');?>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body" style="padding-bottom: 5px;">
|
||||
<div class="db_info_table">
|
||||
@@ -140,6 +168,18 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
<div class="version" id="version" data-build-time="<?php echo file_get_contents( "buildtimestamp.txt");?>"><?php echo '<span id="new-version-text" class="myhidden">' .lang('Maintenance_new_version').'</span>'.'<span id="current-version-text" class="myhidden">' .lang('Maintenance_current_version').'</span>';?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_built_on');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo date("Y-m-d", ((int)file_get_contents( "buildtimestamp.txt")));?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_Running_Version');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php include 'php/templates/version.php'; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell" style="min-width: 140px"><?= lang('Maintenance_database_path');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
@@ -150,7 +190,13 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
<div class="db_info_table_cell"><?= lang('Maintenance_database_size');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo $pia_db_size;?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell"><?= lang('Maintenance_database_rows');?></div>
|
||||
<div class="db_info_table_cell">
|
||||
<?php echo $tableSizesHTML;?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="db_info_table_row">
|
||||
<div class="db_info_table_cell"><?= lang('Maintenance_database_lastmod');?></div>
|
||||
@@ -173,17 +219,29 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
|
||||
<div class="nav-tabs-custom">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a id="tab_Settings_id" href="#tab_Settings" data-toggle="tab"><?= lang('Maintenance_Tools_Tab_UISettings');?></a>
|
||||
<li class="active">
|
||||
<a id="tab_Settings_id" href="#tab_Settings" data-toggle="tab">
|
||||
<i class="fa fa-cogs"></i>
|
||||
<?= lang('Maintenance_Tools_Tab_UISettings');?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="tab_DBTools_id" href="#tab_DBTools" data-toggle="tab"><?= lang('Maintenance_Tools_Tab_Tools');?></a>
|
||||
<a id="tab_DBTools_id" href="#tab_DBTools" data-toggle="tab">
|
||||
<i class="fa fa-toolbox"></i>
|
||||
<?= lang('Maintenance_Tools_Tab_Tools');?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="tab_BackupRestore_id" href="#tab_BackupRestore" data-toggle="tab"><?= lang('Maintenance_Tools_Tab_BackupRestore');?></a>
|
||||
<a id="tab_BackupRestore_id" href="#tab_BackupRestore" data-toggle="tab">
|
||||
<i class="fa fa-file-shield"></i>
|
||||
<?= lang('Maintenance_Tools_Tab_BackupRestore');?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="tab_Logging_id" href="#tab_Logging" data-toggle="tab"><?= lang('Maintenance_Tools_Tab_Logging');?></a>
|
||||
<a id="tab_Logging_id" href="#tab_Logging" data-toggle="tab">
|
||||
<i class="fa fa-triangle-exclamation"></i>
|
||||
<?= lang('Maintenance_Tools_Tab_Logging');?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
@@ -246,6 +304,7 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
<option value="15"><?= lang('Device_TableHead_Connected_Devices');?></option>
|
||||
<option value="16"><?= lang('Device_TableHead_Location');?></option>
|
||||
<option value="17"><?= lang('Device_TableHead_Vendor');?></option>
|
||||
<option value="18"><?= lang('Device_TableHead_Port');?></option>
|
||||
</select>
|
||||
<span class="input-group-addon"><i title="<?= lang('Gen_Save');?>" class="fa fa-save pointer" onclick="saveSelectedColumns();"></i></span>
|
||||
</div>
|
||||
@@ -336,9 +395,19 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
<!-- ---------------------------Logging-------------------------------------------- -->
|
||||
<div class="tab-pane" id="tab_Logging">
|
||||
<div class="db_info_table">
|
||||
<div class="log-area">
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_log" class="logs" cols="70" rows="10" wrap='off' readonly ><?php echo file_get_contents( "./log/pialert.log" ); ?>
|
||||
<textarea id="pialert_log" class="logs" cols="70" rows="10" wrap='off' readonly >
|
||||
<?php
|
||||
if(filesize("./log/pialert.log") > 2000000)
|
||||
{
|
||||
echo file_get_contents( "./log/pialert.log", false, null, -2000000);
|
||||
}
|
||||
else{
|
||||
echo file_get_contents( "./log/pialert.log" );
|
||||
}
|
||||
|
||||
?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
@@ -351,8 +420,8 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area">
|
||||
</div>
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_front_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert_front.log" ); ?>
|
||||
</textarea>
|
||||
@@ -367,44 +436,35 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area">
|
||||
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_pholus_lastrun_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert_pholus_lastrun.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file">pialert_pholus_lastrun.log<div class="logs-size"><?php echo number_format((filesize("./log/pialert_pholus_lastrun.log") / 1000000),2,",",".") . ' MB';?>
|
||||
<span class="span-padding"><a href="./log/pialert_pholus_lastrun.log"><i class="fa fa-download"></i> </a></span>
|
||||
</div></div>
|
||||
<div class="log-purge">
|
||||
<button class="btn btn-primary" onclick="logManage('pialert_pholus_lastrun.log','cleanLog')"><?= lang('Gen_Purge');?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="log-area">
|
||||
|
||||
<div class="row logs-row">
|
||||
<textarea id="IP_changes_log" class="logs logs-small" cols="70" rows="10" readonly><?php echo file_get_contents( "./log/IP_changes.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file">IP_changes.log<div class="logs-size"><?php echo number_format((filesize("./log/IP_changes.log") / 1000000),2,",",".") . ' MB';?>
|
||||
<span class="span-padding"><a href="./log/IP_changes.log"><i class="fa fa-download"></i> </a></span>
|
||||
</div></div>
|
||||
<div class="log-purge">
|
||||
<button class="btn btn-primary" onclick="logManage('IP_changes.log','cleanLog')"><?= lang('Gen_Purge');?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="log-area">
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="pialert_php_log" class="logs" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/pialert.php_errors.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file">pialert.php_errors.log<div class="logs-size"><?php echo number_format((filesize("./log/pialert.php_errors.log") / 1000000),2,",",".") . ' MB';?>
|
||||
<span class="span-padding"><a href="./log/pialert.php_errors.log"><i class="fa fa-download"></i> </a></span>
|
||||
</div></div>
|
||||
<div class="log-purge">
|
||||
<button class="btn btn-primary" onclick="logManage('pialert.php_errors.log','cleanLog')"><?= lang('Gen_Purge');?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area box box-solid box-primary ">
|
||||
<div class="row logs-row">
|
||||
<textarea id="nginx_error_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "/var/log/nginx/error.log" ); ?>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="row logs-row" >
|
||||
<div>
|
||||
<div class="log-file" title="/var/log/nginx/error.log">nginx/error.log</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="stdout_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/stdout.log" ); ?>
|
||||
</textarea>
|
||||
@@ -421,7 +481,7 @@ if (isset($_POST['submit']) && submit && isset($_POST['skinselector_set'])) {
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="log-area">
|
||||
<div class="log-area box box-solid box-primary">
|
||||
<div class="row logs-row">
|
||||
<textarea id="stderr_log" class="logs logs-small" cols="70" rows="10" wrap='off' readonly><?php echo file_get_contents( "./log/stderr.log" ); ?>
|
||||
</textarea>
|
||||
@@ -615,7 +675,7 @@ function askExportCSV() {
|
||||
function ExportCSV()
|
||||
{
|
||||
// Execute
|
||||
openInNewTab(window.location.origin + "/php/server/devices.php?action=ExportCSV")
|
||||
openInNewTab("php/server/devices.php?action=ExportCSV")
|
||||
}
|
||||
|
||||
// Import CSV
|
||||
@@ -627,7 +687,7 @@ function askImportCSV() {
|
||||
function ImportCSV()
|
||||
{
|
||||
// Execute
|
||||
$.get('/php/server/devices.php?action=ImportCSV', function(msg) {
|
||||
$.get('php/server/devices.php?action=ImportCSV', function(msg) {
|
||||
showMessage (msg);
|
||||
});
|
||||
}
|
||||
@@ -700,12 +760,12 @@ function performLogManage() {
|
||||
showModalOk ('Result', data );
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
function scrollDown()
|
||||
{
|
||||
var areaIDs = ['pialert_log', 'pialert_front_log', 'IP_changes_log', 'stdout_log', 'stderr_log', 'pialert_pholus_log', 'pialert_pholus_lastrun_log'];
|
||||
var areaIDs = ['pialert_log', 'pialert_front_log', 'IP_changes_log', 'stdout_log', 'stderr_log', 'pialert_pholus_log', 'pialert_pholus_lastrun_log', 'pialert_php_log'];
|
||||
|
||||
for (let i = 0; i < areaIDs.length; i++) {
|
||||
|
||||
@@ -756,6 +816,8 @@ function saveSelectedColumns () {
|
||||
function initializeSelectedColumns () {
|
||||
$.get('php/server/parameters.php?action=get&expireMinutes=525600&defaultValue='+colDefaultOrderTxt+'¶meter=Front_Devices_Columns_Visible', function(data) {
|
||||
|
||||
handle_locked_DB(data)
|
||||
|
||||
tableColumnShow = numberArrayFromString(data);
|
||||
|
||||
for(i=0; i < tableColumnShow.length; i++)
|
||||
@@ -774,24 +836,30 @@ function initializeSelectedColumns () {
|
||||
// --------------------------------------------------------
|
||||
//Initialize Select2 Elements and make them sortable
|
||||
|
||||
$(function () {
|
||||
selectEl = $('.select2').select2();
|
||||
|
||||
$(function () {
|
||||
var selectEl = $('.select2').select2();
|
||||
|
||||
selectEl.next().children().children().children().sortable({
|
||||
containment: 'parent', stop: function (event, ui) {
|
||||
ui.item.parent().children('[title]').each(function () {
|
||||
var title = $(this).attr('title');
|
||||
var original = $( 'option:contains(' + title + ')', selectEl ).first();
|
||||
original.detach();
|
||||
selectEl.append(original)
|
||||
});
|
||||
selectEl.change();
|
||||
}
|
||||
containment: 'parent',
|
||||
update: function () {
|
||||
var sortedValues = $(this).children().map(function() {
|
||||
return $(this).attr('title');
|
||||
}).get();
|
||||
|
||||
var sortedOptions = selectEl.find('option').sort(function(a, b) {
|
||||
return sortedValues.indexOf($(a).text()) - sortedValues.indexOf($(b).text());
|
||||
});
|
||||
|
||||
// Replace all options in selectEl
|
||||
selectEl.empty().append(sortedOptions);
|
||||
|
||||
// Trigger change event on Select2
|
||||
selectEl.trigger('change');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
// General initialization
|
||||
// --------------------------------------------------------
|
||||
@@ -872,4 +940,4 @@ window.onload = function asyncFooter()
|
||||
|
||||
|
||||
<!-- ----------------------------------------------------------------------- -->
|
||||
<script src="js/pialert_common.js"></script>
|
||||
<script src="js/pialert_common.js"></script>
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
define('badge_online', '<div class="badge bg-green text-white" style="width: 60px;">Online</div>');
|
||||
define('badge_offline', '<div class="badge bg-red text-white" style="width: 60px;">Offline</div>');
|
||||
define('circle_online', '<div class="badge bg-green text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;"> </div>');
|
||||
define('circle_offline', '<div class="badge bg-red text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;"> </div>');
|
||||
define('circle_offline', '<div class="badge bg-red text-white" style="width: 10px; height: 10px; padding:2px; margin-top: -25px;"> </div>');
|
||||
|
||||
$NETWORKTYPES = getNetworkTypes();
|
||||
?>
|
||||
|
||||
<!-- Page ------------------------------------------------------------------ -->
|
||||
@@ -24,8 +23,7 @@
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<div id="networkTree" ></div>
|
||||
<div id="networkTree" class="drag"></div>
|
||||
|
||||
<!-- Main content ---------------------------------------------------------- -->
|
||||
<section class="content">
|
||||
@@ -126,7 +124,10 @@
|
||||
</td>
|
||||
<td>
|
||||
<a href="./network.php?mac='.$idParentMac.'">
|
||||
<b class="anonymize">'.$idParentMac.' <i class="fa fa-square-up-right"></i></b>
|
||||
<b class="anonymize">
|
||||
<span class="mac-to-name" my-data-mac="'.$node_parent_mac.'">'.$node_parent_mac.' </span>
|
||||
<i class="fa fa-square-up-right"></i>
|
||||
</b>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -267,7 +268,9 @@
|
||||
// / \
|
||||
// Smart TV (leaf) Switch 2 (node (for the PC) and leaf (for Switch 1))
|
||||
// \
|
||||
// PC (leaf)
|
||||
// PC (leaf) <------- leafs are not included in this SQL query
|
||||
|
||||
$networkDeviceTypes = str_replace("]", "",(str_replace("[", "", getSettingValue("NETWORK_DEVICE_TYPES"))));
|
||||
|
||||
$sql = "SELECT node_name, node_mac, online, node_type, node_ports_count, parent_mac, node_icon
|
||||
FROM
|
||||
@@ -279,7 +282,7 @@
|
||||
a.dev_Network_Node_MAC_ADDR as parent_mac,
|
||||
a.dev_Icon as node_icon
|
||||
FROM Devices a
|
||||
WHERE a.dev_DeviceType in ('AP', 'Gateway', 'Firewall', 'Powerline', 'Switch', 'WLAN', 'PLC', 'Router','USB LAN Adapter', 'USB WIFI Adapter', 'Internet')
|
||||
WHERE a.dev_DeviceType in (".$networkDeviceTypes.")
|
||||
) t1
|
||||
LEFT JOIN
|
||||
(
|
||||
@@ -448,6 +451,7 @@
|
||||
require 'php/templates/footer.php';
|
||||
?>
|
||||
|
||||
|
||||
<script src="lib/treeviz/index.js"></script>
|
||||
<script src="lib/treeviz/require.js"></script>
|
||||
<script src="js/pialert_common.js"></script>
|
||||
@@ -455,27 +459,39 @@
|
||||
<script>
|
||||
$.get('php/server/devices.php?action=getDevicesList&status=all&forceDefaultOrder', function(data) {
|
||||
|
||||
rawData = JSON.parse (data)
|
||||
rawData = JSON.parse (data)
|
||||
|
||||
devicesListnew = rawData["data"].map(item => { return {
|
||||
"name":item[0],
|
||||
"type":item[2],
|
||||
"icon":item[3],
|
||||
"mac":item[11],
|
||||
"parentMac":item[14],
|
||||
"rowid":item[13],
|
||||
"status":item[10],
|
||||
"childrenQty":item[15]
|
||||
}})
|
||||
if(rawData["data"] == "")
|
||||
{
|
||||
showModalOK (getString('Gen_Warning'), getString('Network_NoDevices'))
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setCache('devicesListNew', JSON.stringify(devicesListnew))
|
||||
devicesListnew = rawData["data"].map(item => { return {
|
||||
"name":item[0],
|
||||
"type":item[2],
|
||||
"icon":item[3],
|
||||
"mac":item[11],
|
||||
"parentMac":item[14],
|
||||
"rowid":item[13],
|
||||
"status":item[10],
|
||||
"childrenQty":item[15],
|
||||
"port":item[18]
|
||||
}})
|
||||
|
||||
// create tree
|
||||
initTree(getHierarchy());
|
||||
setCache('devicesListNew', JSON.stringify(devicesListnew))
|
||||
|
||||
// attach on-click events
|
||||
attachTreeEvents();
|
||||
});
|
||||
// init global variable
|
||||
deviceListGlobal = devicesListnew;
|
||||
|
||||
|
||||
// create tree
|
||||
initTree(getHierarchy());
|
||||
|
||||
// attach on-click events
|
||||
attachTreeEvents();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -483,20 +499,6 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tree functionality
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
function getDevicesList()
|
||||
{
|
||||
// Read cache
|
||||
devicesList = getCache('devicesListNew');
|
||||
|
||||
if (devicesList != '') {
|
||||
devicesList = JSON.parse (devicesList);
|
||||
} else {
|
||||
devicesList = [];
|
||||
}
|
||||
return devicesList;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
var leafNodesCount = 0;
|
||||
@@ -504,6 +506,7 @@
|
||||
var parentNodesCount = 0;
|
||||
var hiddenMacs = []; // hidden children
|
||||
var hiddenChildren = [];
|
||||
var deviceListGlobal = null;
|
||||
|
||||
|
||||
|
||||
@@ -541,6 +544,7 @@
|
||||
name: node.name,
|
||||
path: path,
|
||||
mac: node.mac,
|
||||
port: node.port,
|
||||
id: node.mac,
|
||||
parentMac: node.parentMac,
|
||||
icon: node.icon,
|
||||
@@ -557,14 +561,13 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getHierarchy()
|
||||
{
|
||||
list = getDevicesList();
|
||||
|
||||
for(i in list)
|
||||
{
|
||||
|
||||
for(i in deviceListGlobal)
|
||||
{
|
||||
if(list[i].mac == 'Internet')
|
||||
if(deviceListGlobal[i].mac == 'Internet')
|
||||
{
|
||||
return (getChildren(list[i], list, ''))
|
||||
return (getChildren(deviceListGlobal[i], deviceListGlobal, ''))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -585,8 +588,6 @@
|
||||
removeItemFromArray(hiddenMacs, parentMac)
|
||||
}
|
||||
|
||||
list = getDevicesList();
|
||||
|
||||
// updatedTree = myHierarchy;
|
||||
updatedTree = getHierarchy()
|
||||
|
||||
@@ -605,74 +606,124 @@
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handle network node click - select correct tab in teh bottom table
|
||||
function handleNodeClick(event)
|
||||
{
|
||||
console.log(event.target.offsetParent.offsetParent)
|
||||
|
||||
const targetTabMAC = $(event.target.offsetParent.offsetParent).attr("data-mytreemacmain");
|
||||
|
||||
var targetTab = $(`a[data-mytabmac="${targetTabMAC}"]`);
|
||||
|
||||
// Simulate a click event on the target tab
|
||||
targetTab.click();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
var myTree;
|
||||
var treeAreaHeight = 600;
|
||||
var visibleTreeArea = $(window).height()-135;
|
||||
var treeAreaHeight = visibleTreeArea > 800 ? 800 : visibleTreeArea;
|
||||
var emSize;
|
||||
var nodeHeight;
|
||||
var sizeCoefficient = 1
|
||||
|
||||
function initTree(myHierarchy)
|
||||
{
|
||||
{
|
||||
|
||||
if(myHierarchy.type == "")
|
||||
{
|
||||
showModalOk(getString('Network_Configuration_Error'), getString('Network_Root_Not_Configured'))
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// calculate the font size of the leaf nodes to fit everything into the tree area
|
||||
leafNodesCount == 0 ? 1 : leafNodesCount;
|
||||
emSize = ((600/(20*leafNodesCount)).toFixed(2));
|
||||
emSize = emSize > 1 ? 1 : emSize;
|
||||
|
||||
emSize = ((treeAreaHeight/(25*leafNodesCount)).toFixed(2));
|
||||
emSize = emSize > 1 ? 1 : emSize;
|
||||
|
||||
// nodeHeight = ((emSize*100*0.30).toFixed(0))
|
||||
nodeHeight = ((emSize*100*0.30).toFixed(0))
|
||||
|
||||
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${$('.content-header').width()}px`)
|
||||
|
||||
myTree = Treeviz.create({
|
||||
htmlId: "networkTree",
|
||||
|
||||
renderNode: nodeData => {
|
||||
renderNode: nodeData => {
|
||||
var fontSize = "font-size:"+emSize+"em;";
|
||||
|
||||
deviceIcon = (!emptyArr.includes(nodeData.data.icon )) ? "<div class='netIcon ' ><i class='fa fa-"+nodeData.data.icon +"'></i></div>" : "";
|
||||
collapseExpandIcon = nodeData.data.hiddenChildren ? "square-plus" :"square-minus";
|
||||
collapseExpandHtml = (nodeData.data.hasChildren) ? "<div class='netCollapse' style='font-size:"+emSize*2.5+"em;' data-mytreepath='"+nodeData.data.path+"' data-mytreemac='"+nodeData.data.mac+"'><i class='fa fa-"+ collapseExpandIcon +" pointer'></i></div>" : "";
|
||||
statusCss = " netStatus-" + nodeData.data.status;
|
||||
(!emptyArr.includes(nodeData.data.port )) ? port = nodeData.data.port : port = "";
|
||||
|
||||
(port == "" || port == 0 ) ? portBckgIcon = `<i class="fa fa-wifi"></i>` : portBckgIcon = `<i class="fa fa-ethernet"></i>`;
|
||||
|
||||
// Build HTML for individual nodes in the network diagram
|
||||
deviceIcon = (!emptyArr.includes(nodeData.data.icon )) ?
|
||||
`<div class="netIcon">
|
||||
<i class="fa fa-${nodeData.data.icon}"></i>
|
||||
</div>` : "";
|
||||
devicePort = `<div class="netPort"
|
||||
style="width:${emSize*sizeCoefficient}em;height:${emSize*sizeCoefficient}em">
|
||||
${port}</div>
|
||||
<div class="portBckgIcon"
|
||||
style="margin-left:-${emSize*sizeCoefficient}em;">
|
||||
${portBckgIcon}
|
||||
</div>`;
|
||||
collapseExpandIcon = nodeData.data.hiddenChildren ?
|
||||
"square-plus" : "square-minus";
|
||||
|
||||
// generate +/- icon if node has children nodes
|
||||
collapseExpandHtml = nodeData.data.hasChildren ?
|
||||
`<div class="netCollapse"
|
||||
style="font-size:${emSize*sizeCoefficient}em;top:${1/2*emSize*sizeCoefficient}em"
|
||||
data-mytreepath="${nodeData.data.path}"
|
||||
data-mytreemac="${nodeData.data.mac}">
|
||||
<i class="fa fa-${collapseExpandIcon} pointer"></i>
|
||||
</div>` : "";
|
||||
|
||||
selectedNodeMac = $(".nav-tabs-custom .active a").attr('data-mytabmac')
|
||||
|
||||
highlightedCss = nodeData.data.mac == selectedNodeMac ? " highlightedNode" : "";
|
||||
highlightedCss = nodeData.data.mac == selectedNodeMac ?
|
||||
" highlightedNode" : "";
|
||||
|
||||
return result = "<div class='box "+statusCss+" "+highlightedCss+"' data-mytreemacmain='"+nodeData.data.mac+"' \
|
||||
style='height:"+nodeData.settings.nodeHeight+"px;\
|
||||
width:180px;\
|
||||
display:flex;\
|
||||
flex-direction:column;\
|
||||
justify-content:center;\
|
||||
" + fontSize + "\
|
||||
align-items:center;\
|
||||
border-radius:5px;'\
|
||||
>\
|
||||
<div class='netNodeText '>\
|
||||
<strong>" + deviceIcon +
|
||||
"<span class='spanNetworkTree anonymizeDev'>"+nodeData.data.name+"</span>\
|
||||
</strong>"
|
||||
+collapseExpandHtml+
|
||||
"</div></div>";
|
||||
},
|
||||
// css indicating online/offline status
|
||||
statusCss = ` netStatus-${nodeData.data.status}`;
|
||||
|
||||
onNodeClick: nodeData => {
|
||||
// console.log(this)
|
||||
},
|
||||
return result = `<div class="box ${nodeData.data.hasChildren ? "pointer":""} ${statusCss} ${highlightedCss}"
|
||||
data-mytreemacmain="${nodeData.data.mac}"
|
||||
style="height:${nodeData.settings.nodeHeight}px;${fontSize}"
|
||||
>
|
||||
<div class="netNodeText">
|
||||
<strong>${devicePort} ${deviceIcon}
|
||||
<span class="spanNetworkTree anonymizeDev">${nodeData.data.name}</span>
|
||||
</strong>
|
||||
${collapseExpandHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
|
||||
onNodeClick: nodeData => {
|
||||
console.log(this)
|
||||
},
|
||||
mainAxisNodeSpacing: 'auto',
|
||||
// mainAxisNodeSpacing: 3,
|
||||
secondaryAxisNodeSpacing: 0.3,
|
||||
nodeHeight: nodeHeight.toString(),
|
||||
nodeHeight: nodeHeight.toString(),
|
||||
marginTop: '5',
|
||||
hasZoom: false,
|
||||
hasPan: false,
|
||||
// marginLeft: '15',
|
||||
idKey: "id",
|
||||
hasFlatData: false,
|
||||
hasFlatData: false,
|
||||
linkWidth: (nodeData) => 3,
|
||||
relationnalField: "children",
|
||||
linkColor: (nodeData) => "#ffcc80",
|
||||
onNodeClick: (nodeData) => handleNodeClick(nodeData),
|
||||
relationnalField: "children",
|
||||
});
|
||||
|
||||
myTree.refresh(myHierarchy);
|
||||
|
||||
console.log(myHierarchy)
|
||||
|
||||
myTree.refresh(myHierarchy);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -720,6 +771,25 @@
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
function initDeviceNamesFromMACs()
|
||||
{
|
||||
$('.mac-to-name').each(function() {
|
||||
var dataMacValue = $(this).attr('my-data-mac');
|
||||
|
||||
if(dataMacValue =="" )
|
||||
{
|
||||
$(this).html(getString("Network_Root"))
|
||||
}
|
||||
else{
|
||||
$(this).html(getNameByMacAddress(dataMacValue));
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
function initButtons()
|
||||
{
|
||||
@@ -743,25 +813,37 @@
|
||||
|
||||
// init the Assign buttons
|
||||
$('#unassignedDevices button[data-myleafmac]').each(function(){
|
||||
$(this).attr('onclick', 'updateLeaf("'+$(this).attr('data-myleafmac')+'","'+currentNodeMac+'")')
|
||||
$(this).attr('onclick', `updateLeaf("${$(this).attr('data-myleafmac')}","${currentNodeMac}")`)
|
||||
});
|
||||
|
||||
// init Unassign buttons
|
||||
$('#assignedDevices button[data-myleafmac]').each(function(){
|
||||
$(this).attr('onclick', 'updateLeaf("'+$(this).attr('data-myleafmac')+'","")')
|
||||
$(this).attr('onclick', `updateLeaf("${$(this).attr('data-myleafmac')}","")`)
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
function updateLeaf(leafMac,nodeMac)
|
||||
{
|
||||
console.log(leafMac)
|
||||
console.log(nodeMac)
|
||||
saveData('updateNetworkLeaf', leafMac, nodeMac);
|
||||
setTimeout("location.reload();", 1000); // refresh page after 1s
|
||||
console.log(leafMac) // child
|
||||
console.log(nodeMac) // parent
|
||||
console.log(nodeMac != "") // parent
|
||||
|
||||
// prevent the assignment of the Internet root node avoiding recursion when generating the network tree topology
|
||||
if(leafMac.toLowerCase().includes('internet') && nodeMac != "")
|
||||
{
|
||||
showMessage(getString('Network_Cant_Assign'))
|
||||
}
|
||||
else{
|
||||
saveData('updateNetworkLeaf', leafMac, nodeMac);
|
||||
setTimeout("location.reload();", 500); // refresh page
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// init device names where macs are used
|
||||
initDeviceNamesFromMACs();
|
||||
|
||||
// init selected (first) tab
|
||||
initTab();
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ function OpenDB (...$DBPath) {
|
||||
die ('<div style="padding-left:150px">Error connecting to the database</div>');
|
||||
}
|
||||
|
||||
$db->exec('PRAGMA journal_mode = wal;');
|
||||
$db->exec('PRAGMA journal_mode = wal;');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,14 +50,13 @@
|
||||
case 'getOwners': getOwners(); break;
|
||||
case 'getDeviceTypes': getDeviceTypes(); break;
|
||||
case 'getGroups': getGroups(); break;
|
||||
case 'getLocations': getLocations(); break;
|
||||
case 'getPholus': getPholus(); break;
|
||||
case 'getNmap': getNmap(); break;
|
||||
case 'saveNmapPort': saveNmapPort(); break;
|
||||
case 'getLocations': getLocations(); break;
|
||||
case 'updateNetworkLeaf': updateNetworkLeaf(); break;
|
||||
case 'overwriteIconType': overwriteIconType(); break;
|
||||
case 'getIcons': getIcons(); break;
|
||||
case 'getActions': getActions(); break;
|
||||
case 'getDevices': getDevices(); break;
|
||||
case 'copyFromDevice': copyFromDevice(); break;
|
||||
case 'wakeonlan': wakeonlan(); break;
|
||||
|
||||
default: logServerConsole ('Action: '. $action); break;
|
||||
@@ -78,7 +77,7 @@ function getDeviceData() {
|
||||
|
||||
// Device Data
|
||||
$sql = 'SELECT rowid, *,
|
||||
CASE WHEN dev_AlertDeviceDown=1 AND dev_PresentLastScan=0 THEN "Down"
|
||||
CASE WHEN dev_AlertDeviceDown !=0 AND dev_PresentLastScan=0 THEN "Down"
|
||||
WHEN dev_PresentLastScan=1 THEN "On-line"
|
||||
ELSE "Off-line" END as dev_Status
|
||||
FROM Devices
|
||||
@@ -93,7 +92,7 @@ function getDeviceData() {
|
||||
$deviceData['dev_FirstConnection'] = formatDate ($row['dev_FirstConnection']); // Date formated
|
||||
$deviceData['dev_LastConnection'] = formatDate ($row['dev_LastConnection']); // Date formated
|
||||
|
||||
$deviceData['dev_RandomMAC'] = ( in_array($mac[1], array("2","6","A","E","a","e")) ? 1 : 0);
|
||||
$deviceData['dev_RandomMAC'] = isRandomMAC($mac);
|
||||
|
||||
// Count Totals
|
||||
$condition = ' WHERE eve_MAC="'. $mac .'" AND eve_DateTime >= '. $periodDate;
|
||||
@@ -226,7 +225,7 @@ function deleteUnknownDevices() {
|
||||
global $db;
|
||||
|
||||
// sql
|
||||
$sql = 'DELETE FROM Devices WHERE dev_Name="(unknown)"';
|
||||
$sql = 'DELETE FROM Devices WHERE dev_Name="(unknown)" OR dev_Name="(name not found)"';
|
||||
// execute sql
|
||||
$result = $db->query($sql);
|
||||
|
||||
@@ -469,71 +468,66 @@ function ExportCSV() {
|
||||
// Import CSV of devices
|
||||
//------------------------------------------------------------------------------
|
||||
function ImportCSV() {
|
||||
|
||||
|
||||
$file = '../../../config/devices.csv';
|
||||
|
||||
if (file_exists($file)) {
|
||||
|
||||
global $db;
|
||||
|
||||
$skipped = "";
|
||||
$error = "";
|
||||
|
||||
// sql
|
||||
$sql = 'DELETE FROM Devices';
|
||||
|
||||
// execute sql
|
||||
$result = $db->query($sql);
|
||||
|
||||
// Read the CSV file
|
||||
$data = file_get_contents($file);
|
||||
$data = explode("\n", $data);
|
||||
$lines = explode("\n", $data);
|
||||
|
||||
$columns = getDevicesColumns();
|
||||
// Get the column headers from the first line of the CSV
|
||||
$header = str_getcsv(array_shift($lines));
|
||||
$header = array_map('trim', $header);
|
||||
|
||||
// Delete everything form the DB table
|
||||
$sql = 'DELETE FROM Devices';
|
||||
$result = $db->query($sql);
|
||||
|
||||
// Build the SQL statement
|
||||
$sql = "INSERT INTO Devices (" . implode(', ', $header) . ") VALUES ";
|
||||
|
||||
|
||||
// Parse data from CSV file line by line (max 10000 lines)
|
||||
foreach($data as $row)
|
||||
{
|
||||
// Check if not empty and skipping first line
|
||||
$rowArray = explode(',',$row);
|
||||
$index = 0;
|
||||
foreach($lines as $row) {
|
||||
$rowArray = str_getcsv($row);
|
||||
|
||||
if(count($rowArray) > 20)
|
||||
{
|
||||
$cleanMac = str_replace("\"","",$rowArray[0]);
|
||||
|
||||
if(filter_var($cleanMac , FILTER_VALIDATE_MAC) == True || $cleanMac == "Internet")
|
||||
{
|
||||
$sql = "INSERT INTO Devices (".implode(',', $columns).") VALUES (" . $row.")";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// check result
|
||||
if ($result != TRUE) {
|
||||
$error = $db->lastErrorMsg();
|
||||
// break the while loop on error
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count($rowArray) === count($header)) {
|
||||
// Make sure the number of columns matches the header
|
||||
$rowArray = array_map(function ($value) {
|
||||
return "'" . SQLite3::escapeString(trim($value)) . "'";
|
||||
}, $rowArray);
|
||||
|
||||
$sql .= "(" . implode(', ', $rowArray) . "), ";
|
||||
} else {
|
||||
$skipped .= ($index + 1) . ",";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if($error == "")
|
||||
{
|
||||
// import succesful
|
||||
echo lang('BackDevices_DBTools_ImportCSV');
|
||||
|
||||
$index++;
|
||||
}
|
||||
else{
|
||||
// an error occurred while writing to the DB, display the last error message
|
||||
echo lang('BackDevices_DBTools_ImportCSVError')."\n\n$sql \n\n".$result;
|
||||
|
||||
// Remove the trailing comma and space from SQL
|
||||
$sql = rtrim($sql, ', ');
|
||||
|
||||
// Execute the SQL query
|
||||
$result = $db->query($sql);
|
||||
|
||||
if($error === "") {
|
||||
// Import successful
|
||||
echo lang('BackDevices_DBTools_ImportCSV') . " (Skipped lines: " . $skipped . ") ";
|
||||
} else {
|
||||
// An error occurred while writing to the DB, display the last error message
|
||||
echo lang('BackDevices_DBTools_ImportCSVError') . "\n" . $error . "\n" . $sql . "\n\n" . $result;
|
||||
}
|
||||
|
||||
} else {
|
||||
} else {
|
||||
echo lang('BackDevices_DBTools_ImportCSVMissing');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Query total numbers of Devices by status
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -551,7 +545,7 @@ function getDevicesTotals() {
|
||||
// combined query
|
||||
$result = $db->query(
|
||||
'SELECT
|
||||
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('all').') as devices,
|
||||
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('my').') as devices,
|
||||
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('connected').') as connected,
|
||||
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('favorites').') as favorites,
|
||||
(SELECT COUNT(*) FROM Devices '. getDeviceCondition ('new').') as new,
|
||||
@@ -602,7 +596,8 @@ function getDevicesList() {
|
||||
array("dev_Network_Node_MAC_ADDR", 14, 14),
|
||||
array("connected_devices", 15, 15),
|
||||
array("dev_Location", 16, 16),
|
||||
array("dev_Vendor", 17, 17)
|
||||
array("dev_Vendor", 17, 17),
|
||||
array("dev_Network_Node_port", 18, 18)
|
||||
);
|
||||
|
||||
if($forceDefaultOrder == FALSE)
|
||||
@@ -631,7 +626,7 @@ function getDevicesList() {
|
||||
|
||||
$sql = 'SELECT * FROM (
|
||||
SELECT rowid, *, CASE
|
||||
WHEN t1.dev_AlertDeviceDown=1 AND t1.dev_PresentLastScan=0 THEN "Down"
|
||||
WHEN t1.dev_AlertDeviceDown !=0 AND t1.dev_PresentLastScan=0 THEN "Down"
|
||||
WHEN t1.dev_NewDevice=1 THEN "New"
|
||||
WHEN t1.dev_PresentLastScan=1 THEN "On-line"
|
||||
ELSE "Off-line" END AS dev_Status
|
||||
@@ -651,16 +646,18 @@ function getDevicesList() {
|
||||
$tableData = array();
|
||||
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
|
||||
$defaultOrder = array ($row['dev_Name'],
|
||||
$defaultOrder = array (
|
||||
$row['dev_Name'],
|
||||
$row['dev_Owner'],
|
||||
handleNull($row['dev_DeviceType']),
|
||||
handleNull($row['dev_Icon'], "laptop"),
|
||||
$row['dev_Favorite'],
|
||||
$row['dev_Group'],
|
||||
// ----
|
||||
formatDate ($row['dev_FirstConnection']),
|
||||
formatDate ($row['dev_LastConnection']),
|
||||
$row['dev_LastIP'],
|
||||
( in_array($row['dev_MAC'][1], array("2","6","A","E","a","e")) ? 1 : 0),
|
||||
( isRandomMAC($row['dev_MAC']) ),
|
||||
$row['dev_Status'],
|
||||
$row['dev_MAC'], // MAC (hidden)
|
||||
formatIPlong ($row['dev_LastIP']), // IP orderable
|
||||
@@ -668,7 +665,8 @@ function getDevicesList() {
|
||||
handleNull($row['dev_Network_Node_MAC_ADDR']),
|
||||
handleNull($row['connected_devices']),
|
||||
handleNull($row['dev_Location']),
|
||||
handleNull($row['dev_Vendor'])
|
||||
handleNull($row['dev_Vendor']),
|
||||
handleNull($row['dev_Network_Node_port'])
|
||||
);
|
||||
|
||||
$newOrder = array();
|
||||
@@ -692,6 +690,32 @@ function getDevicesList() {
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Determine if Random MAC
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
function isRandomMAC($mac) {
|
||||
$isRandom = false;
|
||||
|
||||
// if detected as random, make sure it doesn't start with a prefix which teh suer doesn't want to mark as random
|
||||
$setting = getSettingValue("UI_NOT_RANDOM_MAC");
|
||||
$prefixes = createArray($setting);
|
||||
|
||||
$isRandom = in_array($mac[1], array("2", "6", "A", "E", "a", "e"));
|
||||
|
||||
// If detected as random, make sure it doesn't start with a prefix which the user doesn't want to mark as random
|
||||
if ($isRandom) {
|
||||
foreach ($prefixes as $prefix) {
|
||||
if (strpos($mac, $prefix) === 0) {
|
||||
$isRandom = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $isRandom;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Query the List of devices for calendar
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -758,8 +782,13 @@ function getOwners() {
|
||||
function getNetworkNodes() {
|
||||
global $db;
|
||||
|
||||
// Device Data
|
||||
$sql = 'SELECT * FROM Devices WHERE dev_DeviceType in ( "AP", "Gateway", "Firewall", "Powerline", "Switch", "WLAN", "PLC", "Router","USB LAN Adapter", "USB WIFI Adapter")';
|
||||
// Device Data
|
||||
$networkDeviceTypes = str_replace("]", "",(str_replace("[", "", getSettingValue("NETWORK_DEVICE_TYPES"))));
|
||||
|
||||
|
||||
$sql = 'SELECT * FROM Devices WHERE dev_DeviceType in ( '. $networkDeviceTypes .' )';
|
||||
|
||||
// echo $sql;
|
||||
|
||||
$result = $db->query($sql);
|
||||
|
||||
@@ -819,6 +848,36 @@ function getActions() {
|
||||
echo (json_encode ($tableData));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
function getDevices() {
|
||||
|
||||
global $db;
|
||||
|
||||
// Device Data
|
||||
$sql = 'select dev_MAC, dev_Name from Devices';
|
||||
|
||||
$result = $db->query($sql);
|
||||
|
||||
// arrays of rows
|
||||
$tableData = array();
|
||||
|
||||
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
|
||||
$name = handleNull($row['dev_Name'], "(unknown)");
|
||||
$mac = handleNull($row['dev_MAC'], "(unknown)");
|
||||
// Push row data
|
||||
$tableData[] = array('id' => $mac,
|
||||
'name' => $name );
|
||||
}
|
||||
|
||||
// Control no rows
|
||||
if (empty($tableData)) {
|
||||
$tableData = [];
|
||||
}
|
||||
|
||||
// Return json
|
||||
echo (json_encode ($tableData));
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Query the List of types
|
||||
@@ -826,8 +885,6 @@ function getActions() {
|
||||
function getDeviceTypes() {
|
||||
global $db;
|
||||
|
||||
$networkTypes = getNetworkTypes();
|
||||
|
||||
// SQL
|
||||
$sql = 'SELECT DISTINCT 9 as dev_Order, dev_DeviceType
|
||||
FROM Devices
|
||||
@@ -836,7 +893,7 @@ function getDeviceTypes() {
|
||||
"Laptop", "Mini PC", "PC", "Printer", "Server", "Singleboard Computer (SBC)", "NAS",
|
||||
"Domotic", "IP Camera", "Game Console", "SmartTV", "TV Decoder", "Virtual Assistance",
|
||||
"Clock", "House Appliance", "Phone", "Radio",
|
||||
"AP", "Gateway", "Firewall", "Powerline", "Switch", "WLAN", "PLC", "Router","USB LAN Adapter", "USB WIFI Adapter" )
|
||||
"AP", "Gateway", "Firewall", "Hypervisor", "Powerline", "Switch", "WLAN", "PLC", "Router","USB LAN Adapter", "USB WIFI Adapter" )
|
||||
|
||||
UNION SELECT 1 as dev_Order, "Smartphone"
|
||||
UNION SELECT 1 as dev_Order, "Tablet"
|
||||
@@ -865,6 +922,7 @@ function getDeviceTypes() {
|
||||
UNION SELECT 5 as dev_Order, "AP"
|
||||
UNION SELECT 5 as dev_Order, "Gateway"
|
||||
UNION SELECT 5 as dev_Order, "Firewall"
|
||||
UNION SELECT 5 as dev_Order, "Hypervisor"
|
||||
UNION SELECT 5 as dev_Order, "Powerline"
|
||||
UNION SELECT 5 as dev_Order, "Switch"
|
||||
UNION SELECT 5 as dev_Order, "WLAN"
|
||||
@@ -971,134 +1029,11 @@ function getLocations() {
|
||||
echo (json_encode ($tableData));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Query the List of Pholus entries
|
||||
//------------------------------------------------------------------------------
|
||||
function getPholus() {
|
||||
global $db;
|
||||
|
||||
// SQL
|
||||
$mac = $_REQUEST['mac'];
|
||||
|
||||
if ($mac == "Internet") // Not performing data lookup for router (improvement idea for later maybe)
|
||||
{
|
||||
echo "false";
|
||||
return;
|
||||
}
|
||||
|
||||
if (false === filter_var($mac , FILTER_VALIDATE_MAC)) {
|
||||
throw new Exception('Invalid mac address');
|
||||
}
|
||||
else{
|
||||
$sql = 'SELECT * from Pholus_Scan where MAC ="'.$mac.'" and Record_Type not in ("Question")';
|
||||
|
||||
// array
|
||||
$tableData = array();
|
||||
|
||||
// execute query
|
||||
$result = $db->query($sql);
|
||||
while ($row = $result -> fetchArray (SQLITE3_ASSOC)){
|
||||
// Push row data
|
||||
$tableData[] = array( 'Index' => $row['Index'],
|
||||
'Info' => $row['Info'],
|
||||
'Time' => $row['Time'],
|
||||
'MAC' => $row['MAC'],
|
||||
'IP_v4_or_v6' => $row['IP_v4_or_v6'],
|
||||
'Record_Type' => $row['Record_Type'],
|
||||
'Value' => $row['Value'],
|
||||
'Extra' => $row['Extra']);
|
||||
}
|
||||
|
||||
if(count($tableData) == 0)
|
||||
{
|
||||
echo "false";
|
||||
} else{
|
||||
// Return json
|
||||
echo (json_encode ($tableData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Query the List of Nmap entries
|
||||
//------------------------------------------------------------------------------
|
||||
function getNmap() {
|
||||
global $db;
|
||||
|
||||
// SQL
|
||||
$mac = $_REQUEST['mac'];
|
||||
|
||||
if ($mac == "Internet") // Not performing data lookup for router (improvement idea for later maybe)
|
||||
{
|
||||
echo "false";
|
||||
return;
|
||||
}
|
||||
|
||||
if (false === filter_var($mac , FILTER_VALIDATE_MAC)) {
|
||||
throw new Exception('Invalid mac address');
|
||||
}
|
||||
else{
|
||||
// $sql = 'SELECT * from Nmap_Scan where MAC ="'.$mac.'" ';
|
||||
$sql = 'select * from (select * from Nmap_Scan INNER JOIN Devices on Nmap_Scan.MAC = Devices.dev_MAC) where MAC = "'.$mac.'" ';
|
||||
|
||||
// array
|
||||
$tableData = array();
|
||||
|
||||
// execute query
|
||||
$result = $db->query($sql);
|
||||
while ($row = $result -> fetchArray (SQLITE3_ASSOC)){
|
||||
// Push row data
|
||||
$tableData[] = array( 'Index' => $row['Index'],
|
||||
'MAC' => $row['MAC'],
|
||||
'Port' => $row['Port'],
|
||||
'Time' => $row['Time'],
|
||||
'State' => $row['State'],
|
||||
'Service' => $row['Service'],
|
||||
'IP' => $row['dev_LastIP'],
|
||||
'Extra' => $row['Extra']);
|
||||
}
|
||||
|
||||
if(count($tableData) == 0)
|
||||
{
|
||||
echo "false";
|
||||
} else{
|
||||
// Return json
|
||||
echo (json_encode ($tableData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
|
||||
function saveNmapPort()
|
||||
{
|
||||
|
||||
$portIndex = $_REQUEST['id'];
|
||||
$value = $_REQUEST['value'];
|
||||
|
||||
if(is_integer((int)$portIndex))
|
||||
{
|
||||
global $db;
|
||||
// sql
|
||||
$sql = 'UPDATE Nmap_Scan SET "Extra" = "'. $value .'" WHERE "Index"=' . $portIndex ;
|
||||
// update Data
|
||||
$result = $db->query($sql);
|
||||
|
||||
// check result
|
||||
if ($result == TRUE) {
|
||||
echo 'OK';
|
||||
} else {
|
||||
echo 'KO';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
function updateNetworkLeaf()
|
||||
{
|
||||
$nodeMac = $_REQUEST['value'];
|
||||
$leafMac = $_REQUEST['id'];
|
||||
$nodeMac = $_REQUEST['value']; // parent
|
||||
$leafMac = $_REQUEST['id']; // child
|
||||
|
||||
if ((false === filter_var($nodeMac , FILTER_VALIDATE_MAC) && $nodeMac != "Internet" && $nodeMac != "") || false === filter_var($leafMac , FILTER_VALIDATE_MAC) ) {
|
||||
throw new Exception('Invalid mac address');
|
||||
@@ -1169,19 +1104,70 @@ function wakeonlan() {
|
||||
echo lang('BackDevDetail_Tools_WOL_okay');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Copy from device
|
||||
//------------------------------------------------------------------------------
|
||||
function copyFromDevice() {
|
||||
|
||||
$MAC_FROM = $_REQUEST['macFrom'];
|
||||
$MAC_TO = $_REQUEST['macTo'];
|
||||
|
||||
if ((false === filter_var($MAC_FROM , FILTER_VALIDATE_MAC) && $MAC_FROM != "Internet" && $MAC_FROM != "") ) {
|
||||
throw new Exception('Invalid mac address');
|
||||
}
|
||||
if ((false === filter_var($MAC_TO , FILTER_VALIDATE_MAC) && $MAC_TO != "Internet" && $MAC_TO != "") ) {
|
||||
throw new Exception('Invalid mac address');
|
||||
}
|
||||
|
||||
global $db;
|
||||
|
||||
// clean-up temporary table
|
||||
$sql = "DROP TABLE temp_devices ";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// create temporary table with the source data
|
||||
$sql = "CREATE TABLE temp_devices AS SELECT * FROM Devices WHERE dev_MAC = '". $MAC_FROM . "';";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// update temporary table with the correct target MAC
|
||||
$sql = "UPDATE temp_devices SET dev_MAC = '". $MAC_TO . "';";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// delete previous entry
|
||||
$sql = "DELETE FROM Devices WHERE dev_MAC = '". $MAC_TO . "';";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// insert new entry with the correct target MAC from the temporary table
|
||||
$sql = "INSERT INTO Devices SELECT * FROM temp_devices WHERE dev_MAC = '".$MAC_TO."'";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// clean-up temporary table
|
||||
$sql = "DROP TABLE temp_devices ";
|
||||
$result = $db->query($sql);
|
||||
|
||||
// check result
|
||||
if ($result == TRUE) {
|
||||
echo 'OK';
|
||||
} else {
|
||||
echo lang('BackDevices_Device_UpdDevError');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Status Where conditions
|
||||
//------------------------------------------------------------------------------
|
||||
function getDeviceCondition ($deviceStatus) {
|
||||
switch ($deviceStatus) {
|
||||
case 'all': return 'WHERE dev_Archived=0'; break;
|
||||
case 'connected': return 'WHERE dev_Archived=0 AND dev_PresentLastScan=1'; break;
|
||||
case 'favorites': return 'WHERE dev_Archived=0 AND dev_Favorite=1'; break;
|
||||
case 'new': return 'WHERE dev_Archived=0 AND dev_NewDevice=1'; break;
|
||||
case 'down': return 'WHERE dev_Archived=0 AND dev_AlertDeviceDown=1 AND dev_PresentLastScan=0'; break;
|
||||
case 'archived': return 'WHERE dev_Archived=1'; break;
|
||||
default: return 'WHERE 1=0'; break;
|
||||
}
|
||||
case 'all': return 'WHERE dev_Archived=0'; break;
|
||||
case 'my': return 'WHERE dev_Archived=0'; break;
|
||||
case 'connected': return 'WHERE dev_Archived=0 AND dev_PresentLastScan=1'; break;
|
||||
case 'favorites': return 'WHERE dev_Archived=0 AND dev_Favorite=1'; break;
|
||||
case 'new': return 'WHERE dev_Archived=0 AND dev_NewDevice=1'; break;
|
||||
case 'down': return 'WHERE dev_Archived=0 AND dev_AlertDeviceDown !=0 AND dev_PresentLastScan=0'; break;
|
||||
case 'archived': return 'WHERE dev_Archived=1'; break;
|
||||
default: return 'WHERE 1=0'; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
49
front/php/server/internetinfo.php
Executable file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
###################################################################################
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# internetinfo.php # Front module. Server side. System Information #
|
||||
###################################################################################
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob#sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
###################################################################################
|
||||
|
||||
// Get init.php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
// Perform a test with the PING command
|
||||
$output = shell_exec("curl ipinfo.io");
|
||||
|
||||
// Check if there is error
|
||||
if (!isset($output) || empty($output)) {
|
||||
// Error message
|
||||
$output = lang('DevDetail_Tab_Tool_Internet_Info_Error');
|
||||
// Show the result
|
||||
echo "<pre>";
|
||||
echo $output;
|
||||
echo "</pre>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Replace "{" with ""
|
||||
$output = str_replace("{", "", $output);
|
||||
|
||||
// Replace "}" with ""
|
||||
$output = str_replace("}", "", $output);
|
||||
|
||||
// Replace "," with ""
|
||||
$output = str_replace(",", "", $output);
|
||||
|
||||
// Replace '"' with ""
|
||||
$output = str_replace('"', "", $output);
|
||||
|
||||
// Show the result
|
||||
echo "<pre>";
|
||||
echo $output;
|
||||
echo "</pre>";
|
||||
|
||||
?>
|
||||
40
front/php/server/nslookup.php
Executable file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
###################################################################################
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# nslookup.php # Front module. Server side. System Information #
|
||||
###################################################################################
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob#sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
###################################################################################
|
||||
|
||||
// Get init.php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
// Get IP
|
||||
$ip = $_GET['ip'];
|
||||
|
||||
// Check if IP is valid
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
// Error message
|
||||
$output = lang('DevDetail_Tab_Tools_Nslookup_Error');
|
||||
// Show the result
|
||||
echo "<pre>";
|
||||
echo $output;
|
||||
echo "</pre>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Test with the "nslookup" command
|
||||
$output = shell_exec("nslookup $ip");
|
||||
|
||||
// Show the result
|
||||
echo "<pre>";
|
||||
echo $output;
|
||||
echo "</pre>";
|
||||
|
||||
?>
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
exec('../../../back/speedtest-cli --secure --simple', $output);
|
||||
|
||||
echo '<h4>Speedtest Results</h4>';
|
||||
echo '<h4>'. lang('Speedtest_Results') .'</h4>';
|
||||
echo '<pre style="border: none;">';
|
||||
foreach($output as $line){
|
||||
echo $line . "\n";
|
||||
}
|
||||
echo '</pre>';
|
||||
?>
|
||||
?>
|
||||
|
||||
40
front/php/server/traceroute.php
Executable file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
###################################################################################
|
||||
# Pi.Alert #
|
||||
# Open Source Network Guard / WIFI & LAN intrusion detector #
|
||||
# #
|
||||
# traceroute.php # Front module. Server side. System Information #
|
||||
###################################################################################
|
||||
# Puche 2021 pi.alert.application@gmail.com GNU GPLv3 #
|
||||
# jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 #
|
||||
# leiweibau 2022 https://github.com/leiweibau GNU GPLv3 #
|
||||
# cvc90 2023 https://github.com/cvc90 GNU GPLv3 #
|
||||
###################################################################################
|
||||
|
||||
// Get init.php
|
||||
require dirname(__FILE__).'/../server/init.php';
|
||||
|
||||
// Get IP
|
||||
$ip = $_GET['ip'];
|
||||
|
||||
// Check if IP is valid
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
// Error message
|
||||
$output = lang('DevDetail_Tab_Tools_Traceroute_Error');
|
||||
// Show the result
|
||||
echo "<pre>";
|
||||
echo $output;
|
||||
echo "</pre>";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Test with the "Traceroute" command
|
||||
$output = shell_exec("traceroute $ip");
|
||||
|
||||
// Show the result
|
||||
echo "<pre>";
|
||||
echo $output;
|
||||
echo "</pre>";
|
||||
|
||||
?>
|
||||