mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Compare commits
1528 commits
MeshCentra
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88a765bb13 | ||
|
|
7ad4b917be | ||
|
|
d10173a018 | ||
|
|
0e3a6b4915 | ||
|
|
b949cecc5f | ||
|
|
c7cbf2f12a | ||
|
|
d49afdd7bf | ||
|
|
133e77c8c6 | ||
|
|
e404e86b9f | ||
|
|
c6da201af8 | ||
|
|
9a27d7637c | ||
|
|
5aa2467409 | ||
|
|
9398afd07e | ||
|
|
b2cd84035b | ||
|
|
97547d72a3 | ||
|
|
7faf043c35 | ||
|
|
9df0330896 | ||
|
|
42f61ea46e | ||
|
|
0d65080a8a | ||
|
|
bd4d8b12d4 | ||
|
|
18ae8bdbf4 | ||
|
|
46c76f7234 | ||
|
|
e65bf77111 | ||
|
|
f19ad6c664 | ||
|
|
fe2f12149d | ||
|
|
91bd5ae702 | ||
|
|
38f5bf2e0f | ||
|
|
79f00bcaab | ||
|
|
c55065505b | ||
|
|
e0e8a3fcaa | ||
|
|
3f77cfa93a | ||
|
|
5ee9aa2410 | ||
|
|
0ab3f01ca6 | ||
|
|
4b621a01fb | ||
|
|
f2681de87d | ||
|
|
c90fa55c99 | ||
|
|
edeef03f00 | ||
|
|
d7fe87d1db | ||
|
|
9d4f51e970 | ||
|
|
0b376fe5a0 | ||
|
|
9fd40751b2 | ||
|
|
d246307fae | ||
|
|
711bb56a93 | ||
|
|
5734bcc33a | ||
|
|
1310c57397 | ||
|
|
854d6c00d2 | ||
|
|
c96d7ff1ca | ||
|
|
712f06db3c | ||
|
|
cac505e2cd | ||
|
|
9d962bc523 | ||
|
|
f079692b16 | ||
|
|
3ee06abfe8 | ||
|
|
b46ddf2f70 | ||
|
|
f7b958d28b | ||
|
|
64c8d2c238 | ||
|
|
31f2224a93 | ||
|
|
de685556c8 | ||
|
|
92375ddc93 | ||
|
|
ea80f8595e | ||
|
|
763f76b68f | ||
|
|
1a02539f23 | ||
|
|
90b71e924f | ||
|
|
73c18c4dd5 | ||
|
|
def62075c7 | ||
|
|
998769a888 | ||
|
|
ca6ec5ebc9 | ||
|
|
0dd56d5708 | ||
|
|
95729d2a88 | ||
|
|
1ae7b9f641 | ||
|
|
c66a9a12ef | ||
|
|
2c310450cf | ||
|
|
b6e022c01e | ||
|
|
e66776c5da | ||
|
|
d1cb184e9e | ||
|
|
6aa60d556f | ||
|
|
8d4e9bcede | ||
|
|
eb0d24cf0b | ||
|
|
fe02d3158d | ||
|
|
61d3487f8a | ||
|
|
a23725eb40 | ||
|
|
9b60271f31 | ||
|
|
31f328086e | ||
|
|
7aa4061cad | ||
|
|
54bb0177ee | ||
|
|
ce70f4ac08 | ||
|
|
f712cd9425 | ||
|
|
c4592dcc4f | ||
|
|
2a274fe569 | ||
|
|
5d0b5acdfb | ||
|
|
f80ba62cfc | ||
|
|
5da849063b | ||
|
|
68ac8cf86c | ||
|
|
8e70cd7187 | ||
|
|
5cf468159d | ||
|
|
c92b88a374 | ||
|
|
1b01b90cd6 | ||
|
|
6a366fe174 | ||
|
|
e2362a0547 | ||
|
|
59fcc0dbc6 | ||
|
|
988983b880 | ||
|
|
a1854fa074 | ||
|
|
22fc95926a | ||
|
|
c2eb1f2516 | ||
|
|
832d11739b | ||
|
|
ab7be919a0 | ||
|
|
624d61db43 | ||
|
|
b0d8e3fe48 | ||
|
|
a33047747a | ||
|
|
39e81befe1 | ||
|
|
8eeb96fb0d | ||
|
|
f9228ad0eb | ||
|
|
ce4217c346 | ||
|
|
d9262f7c9d | ||
|
|
8e8ec4f88a | ||
|
|
18167499d9 | ||
|
|
da5d03b0e7 | ||
|
|
c41eb72a2c | ||
|
|
ef4d764ab4 | ||
|
|
c16ff89902 | ||
|
|
041e8021d1 | ||
|
|
6e31562ecb | ||
|
|
874ef23c40 | ||
|
|
7bd5b66ebc | ||
|
|
975e49a190 | ||
|
|
462c383b77 | ||
|
|
dbb5b4ba11 | ||
|
|
545bf58e8d | ||
|
|
30b390bdbf | ||
|
|
d0a51e90e9 | ||
|
|
c773857b17 | ||
|
|
cae1f7ea14 | ||
|
|
b398cb7fa9 | ||
|
|
5a1a97ca7e | ||
|
|
dd21f14f4e | ||
|
|
3da60b43ac | ||
|
|
727080ab68 | ||
|
|
54170c44a0 | ||
|
|
8a5ad1563d | ||
|
|
911d987a84 | ||
|
|
9a8f4e8ebe | ||
|
|
badee98b71 | ||
|
|
d44faed29e | ||
|
|
01c585f7f1 | ||
|
|
777eb53476 | ||
|
|
b71c69e81d | ||
|
|
7d59210d05 | ||
|
|
fc387ca417 | ||
|
|
fc83211e90 | ||
|
|
9ebd23a518 | ||
|
|
3f8301e9d7 | ||
|
|
b39235643e | ||
|
|
0ec8b061c8 | ||
|
|
e58d659fa9 | ||
|
|
45169b2cfd | ||
|
|
c09d2fad3e | ||
|
|
7928f7fb30 | ||
|
|
438289b2ed | ||
|
|
561fc67f33 | ||
|
|
aa7767f37c | ||
|
|
f23792881e | ||
|
|
c920b28acc | ||
|
|
36f1b4d5be | ||
|
|
141bec559f | ||
|
|
0d885e6fa0 | ||
|
|
e10f5277e9 | ||
|
|
f33768fe32 | ||
|
|
1e565768d1 | ||
|
|
5193fef888 | ||
|
|
63930c4b33 | ||
|
|
ac27034542 | ||
|
|
cfe9345b53 | ||
|
|
1e2d736d6d | ||
|
|
0c825251eb | ||
|
|
ccf00b7d06 | ||
|
|
6d412a7bea | ||
|
|
5a0d3054b8 | ||
|
|
6dbc6d2d07 | ||
|
|
ea8e1b1076 | ||
|
|
d1368791e9 | ||
|
|
590166f847 | ||
|
|
19d0df7e7f | ||
|
|
1d87c42977 | ||
|
|
ec7505987d | ||
|
|
37729269ba | ||
|
|
952bcde25f | ||
|
|
4848df4faf | ||
|
|
41d1f9d26f | ||
|
|
113adb5b85 | ||
|
|
8e5aa35bf3 | ||
|
|
1139a37338 | ||
|
|
b20e51561a | ||
|
|
5ff44bbae8 | ||
|
|
2beeb6f644 | ||
|
|
3eede1bf43 | ||
|
|
9f8ea3a6b5 | ||
|
|
23679d119b | ||
|
|
a3fd6008a0 | ||
|
|
d0014b3f8b | ||
|
|
04c96eb2ff | ||
|
|
df64c750cc | ||
|
|
b90b2ac0bf | ||
|
|
39a1755b3d | ||
|
|
61fb6898c0 | ||
|
|
bc34f140c8 | ||
|
|
0bee2be3cf | ||
|
|
1d67172dd3 | ||
|
|
b99a97eb48 | ||
|
|
a1899a719f | ||
|
|
5fcfa8f369 | ||
|
|
7172d1f701 | ||
|
|
8bc760855e | ||
|
|
5fc3683ebb | ||
|
|
626416a202 | ||
|
|
d84afb939a | ||
|
|
3cd875d6ee | ||
|
|
f5e63b7cbd | ||
|
|
8b20f44dd5 | ||
|
|
59a3a22ea5 | ||
|
|
2f34b7e83b | ||
|
|
4d5ec6cac1 | ||
|
|
7635109f6d | ||
|
|
de60b7f952 | ||
|
|
405261a67e | ||
|
|
4bcec73e07 | ||
|
|
d81c00c0b0 | ||
|
|
d2e4f12ea3 | ||
|
|
f7c79166da | ||
|
|
2b5337329a | ||
|
|
21206b670c | ||
|
|
1d04a13a64 | ||
|
|
9e309584db | ||
|
|
0d56504d96 | ||
|
|
d17918936d | ||
|
|
0a64b80654 | ||
|
|
35e38a71c0 | ||
|
|
6fe30b7730 | ||
|
|
516a14b4ca | ||
|
|
390991123a | ||
|
|
d367b2ed87 | ||
|
|
5a410ccd5b | ||
|
|
ad1d82152a | ||
|
|
7c79dbcda1 | ||
|
|
cf23a3df81 | ||
|
|
e8cbebaffe | ||
|
|
ac0d805378 | ||
|
|
7b48e3b5f5 | ||
|
|
ea6682e06a | ||
|
|
4e37455471 | ||
|
|
b4323223cc | ||
|
|
bf00de4425 | ||
|
|
f95dbdd404 | ||
|
|
e1e59953f4 | ||
|
|
d2d9f7a13e | ||
|
|
21e196e35c | ||
|
|
0ccce62c9d | ||
|
|
3a78cb83c4 | ||
|
|
8dd5545a2b | ||
|
|
2f61e3edad | ||
|
|
7caf2aa05d | ||
|
|
cee181fb61 | ||
|
|
fa39f8a105 | ||
|
|
c1e3354c91 | ||
|
|
aae551dab9 | ||
|
|
3a28e33efb | ||
|
|
92385e3d73 | ||
|
|
adeaac1588 | ||
|
|
77f44fc308 | ||
|
|
3efa680361 | ||
|
|
899ff0c742 | ||
|
|
61f1c22c27 | ||
|
|
08877844c4 | ||
|
|
698b7fb056 | ||
|
|
fbd4533477 | ||
|
|
6f2b57998f | ||
|
|
a6acb35a31 | ||
|
|
fc29e60939 | ||
|
|
5b76a31644 | ||
|
|
41e4213fc5 | ||
|
|
999ae7f67f | ||
|
|
44991975d3 | ||
|
|
6da9222871 | ||
|
|
10b57dcf9e | ||
|
|
1cfe0e2c31 | ||
|
|
7e504a28e6 | ||
|
|
92869ec78b | ||
|
|
9264b9d281 | ||
|
|
d8a91d3150 | ||
|
|
5e71bcc634 | ||
|
|
4d75d48eea | ||
|
|
df6474802d | ||
|
|
31c323583b | ||
|
|
4b891c5be0 | ||
|
|
86713cacac | ||
|
|
95d60fef13 | ||
|
|
b4e7e7384d | ||
|
|
62cae4cf8a | ||
|
|
aaad8b79cc | ||
|
|
b0d9b17e36 | ||
|
|
991c23c5f9 | ||
|
|
87c5745594 | ||
|
|
707982a71b | ||
|
|
a8fc5e1187 | ||
|
|
40ac6aa636 | ||
|
|
1d9de2e144 | ||
|
|
ee0018e4d1 | ||
|
|
721c909158 | ||
|
|
2630931eee | ||
|
|
13b8ca3686 | ||
|
|
a59da2fb9a | ||
|
|
c3470f493b | ||
|
|
3d815824ba | ||
|
|
9619a83ba7 | ||
|
|
f6c7761afb | ||
|
|
9fd3e4c569 | ||
|
|
118b0c58dc | ||
|
|
57442e4988 | ||
|
|
602eb3c64a | ||
|
|
28c522c5bb | ||
|
|
df91c90d33 | ||
|
|
81557ab2d4 | ||
|
|
6b21bacad2 | ||
|
|
46ebadf440 | ||
|
|
6c3e60e13c | ||
|
|
7955bc4954 | ||
|
|
482e79f913 | ||
|
|
0a89d07937 | ||
|
|
c053c14dd0 | ||
|
|
5950b2c829 | ||
|
|
42a07e9d74 | ||
|
|
d7341ab153 | ||
|
|
74d6252699 | ||
|
|
b08f3827f5 | ||
|
|
6976992735 | ||
|
|
b1c3e2a8e7 | ||
|
|
c67a76bcc2 | ||
|
|
62199d8057 | ||
|
|
52a2194116 | ||
|
|
2b3c329a54 | ||
|
|
17cf36edd9 | ||
|
|
a171cde2ff | ||
|
|
5d5e861a4a | ||
|
|
26ac23c80d | ||
|
|
5a7e3d9869 | ||
|
|
abbb0fa9ee | ||
|
|
89b67ff999 | ||
|
|
6c685d5557 | ||
|
|
49b561260a | ||
|
|
aa8f45f4a9 | ||
|
|
7cf14a2b69 | ||
|
|
7e7361de9b | ||
|
|
4cd7b408fa | ||
|
|
bc6451fee5 | ||
|
|
f1ba76a423 | ||
|
|
385a4738cd | ||
|
|
5c13f178be | ||
|
|
323ef2d50a | ||
|
|
dd249938b3 | ||
|
|
30d958fbd9 | ||
|
|
1c8d664962 | ||
|
|
b22e56b6d2 | ||
|
|
bc2f34b629 | ||
|
|
e8da6a607c | ||
|
|
77d268d064 | ||
|
|
23ee76e26a | ||
|
|
be3e333b40 | ||
|
|
e3f68226d2 | ||
|
|
b71b4d04e6 | ||
|
|
bf7957ebff | ||
|
|
19eb1235f5 | ||
|
|
274bb525a5 | ||
|
|
33c0e82286 | ||
|
|
56d6527bf5 | ||
|
|
3ce2fd92c0 | ||
|
|
eb27334b82 | ||
|
|
414d9b9561 | ||
|
|
1747ff7550 | ||
|
|
f39b6f8859 | ||
|
|
ca868afdd1 | ||
|
|
410c84c30b | ||
|
|
18b731fd36 | ||
|
|
832e618602 | ||
|
|
7b8cf85740 | ||
|
|
1dca9e2235 | ||
|
|
30d570f28b | ||
|
|
f854c80421 | ||
|
|
f5891f2946 | ||
|
|
1da33f0ade | ||
|
|
e025e9558b | ||
|
|
ccf57bee1a | ||
|
|
4ba08a96f7 | ||
|
|
548edd13d6 | ||
|
|
31ebb21e0b | ||
|
|
4a3c6db0ea | ||
|
|
f9af1ffc90 | ||
|
|
95e7997e60 | ||
|
|
9081a6aeac | ||
|
|
afc6165827 | ||
|
|
c9c0a6cb67 | ||
|
|
b46c322c41 | ||
|
|
4ff5a5c912 | ||
|
|
65d1346e06 | ||
|
|
5d1c8ca68b | ||
|
|
9294488d4e | ||
|
|
d2a0946f22 | ||
|
|
3be8ec5add | ||
|
|
102489447d | ||
|
|
8e8cc4b327 | ||
|
|
ce93c896ce | ||
|
|
7b67b992e2 | ||
|
|
95bbd7157f | ||
|
|
8e6cc14981 | ||
|
|
862e2ee80b | ||
|
|
81e98033fc | ||
|
|
fbae83dd9f | ||
|
|
8498414ae9 | ||
|
|
d33aa25e5b | ||
|
|
8775b7dcf7 | ||
|
|
e6ee2034d1 | ||
|
|
f874e76f0c | ||
|
|
105612c199 | ||
|
|
4027ee1b28 | ||
|
|
4f11d7fdbc | ||
|
|
b8238ef34d | ||
|
|
4b6da03d2f | ||
|
|
05fca6cb36 | ||
|
|
150e2337f5 | ||
|
|
dfc08b05a9 | ||
|
|
fbe1445691 | ||
|
|
05ee40c591 | ||
|
|
872794e15f | ||
|
|
334fee706e | ||
|
|
e9c28d03b5 | ||
|
|
2d75bbde33 | ||
|
|
ab0d9c188d | ||
|
|
d71ca89b58 | ||
|
|
0e896fe9fe | ||
|
|
0a59f9dbae | ||
|
|
c1bec67839 | ||
|
|
234acd3347 | ||
|
|
473b9d0265 | ||
|
|
6f47f2bc89 | ||
|
|
548c1b9bb4 | ||
|
|
3ffc92e917 | ||
|
|
bab35e7bca | ||
|
|
4be5b7273e | ||
|
|
436a3cb9be | ||
|
|
e6a71d77a1 | ||
|
|
9e9cd821bf | ||
|
|
27f7648953 | ||
|
|
c937764980 | ||
|
|
e8c4f322cb | ||
|
|
fb62df326c | ||
|
|
2318a0bb32 | ||
|
|
636255c8af | ||
|
|
9241c43435 | ||
|
|
0e055ef741 | ||
|
|
ee59e582b6 | ||
|
|
aa87fd61bb | ||
|
|
b4361d1c4e | ||
|
|
3e23741cc8 | ||
|
|
016e43c191 | ||
|
|
5ed0e4f59e | ||
|
|
1b60e4dbfb | ||
|
|
269ec02dc0 | ||
|
|
fce123e971 | ||
|
|
bca1d277a4 | ||
|
|
017f777de2 | ||
|
|
4cbb95a85f | ||
|
|
7912df307a | ||
|
|
82c70659b8 | ||
|
|
0b2368df9d | ||
|
|
26bb350122 | ||
|
|
44926e16d5 | ||
|
|
0f23fa0ade | ||
|
|
a80c0ef48c | ||
|
|
79e137dbe7 | ||
|
|
af3e7f6186 | ||
|
|
936aaa0b2b | ||
|
|
272015483b | ||
|
|
bb93c113bd | ||
|
|
9ef1cc64a4 | ||
|
|
a14390e049 | ||
|
|
a77d40505a | ||
|
|
76485713df | ||
|
|
9ef48eac1f | ||
|
|
7bc28b5dad | ||
|
|
3e04e4d8c6 | ||
|
|
f2bc7d5349 | ||
|
|
e5e86fee19 | ||
|
|
4637e6b3b3 | ||
|
|
fb15d94976 | ||
|
|
a7018e74bc | ||
|
|
a3b3ecd8b1 | ||
|
|
f2e43cc6da | ||
|
|
5c1249ccca | ||
|
|
0232056219 | ||
|
|
6f78f9e276 | ||
|
|
4098805798 | ||
|
|
980eca3765 | ||
|
|
512695df6c | ||
|
|
15ff7d12a1 | ||
|
|
6637f08fe7 | ||
|
|
990da39fde | ||
|
|
ddcff9f0d2 | ||
|
|
bfec20ac81 | ||
|
|
550ee34f00 | ||
|
|
e6f27fca36 | ||
|
|
b887457ec4 | ||
|
|
4648dbeb26 | ||
|
|
cdab553800 | ||
|
|
cd2ede8369 | ||
|
|
97ed6c8285 | ||
|
|
df94b50d5d | ||
|
|
9542e77e1b | ||
|
|
3f8bbe68b0 | ||
|
|
37911d091c | ||
|
|
1855dd1d56 | ||
|
|
9f57c27dd1 | ||
|
|
8547de340c | ||
|
|
cd48909dcb | ||
|
|
ceba76cfde | ||
|
|
c331eca679 | ||
|
|
03cab630c7 | ||
|
|
aaff3abc1a | ||
|
|
b02541cd02 | ||
|
|
18af676c22 | ||
|
|
57f77057b4 | ||
|
|
b9c706cec2 | ||
|
|
b1451a1c8a | ||
|
|
b860981925 | ||
|
|
327f29159e | ||
|
|
a2aed9e772 | ||
|
|
aaff8232b0 | ||
|
|
ab835591db | ||
|
|
6cb05ce009 | ||
|
|
21bd171167 | ||
|
|
c546333cf7 | ||
|
|
1e9607ba8e | ||
|
|
f93bb3a82f | ||
|
|
0d7564d845 | ||
|
|
6e2321b5c6 | ||
|
|
757cef3f29 | ||
|
|
d02b63a4a2 | ||
|
|
1295af4677 | ||
|
|
329ba43e81 | ||
|
|
6cacec010b | ||
|
|
9986567cf0 | ||
|
|
b01078bf55 | ||
|
|
0b0f2999db | ||
|
|
db06c0c925 | ||
|
|
ee7ceb7898 | ||
|
|
0de32f9fee | ||
|
|
a822b88756 | ||
|
|
ef6fd23a4f | ||
|
|
7c2eea68b6 | ||
|
|
775ed95de4 | ||
|
|
227b4c68e7 | ||
|
|
82f10f0193 | ||
|
|
00db0a3a39 | ||
|
|
cb0b02152a | ||
|
|
78a49c504a | ||
|
|
23666fed1f | ||
|
|
64bef74317 | ||
|
|
a57ab97bb1 | ||
|
|
7e2bc8422f | ||
|
|
a5efc5e899 | ||
|
|
275119fc7d | ||
|
|
c248eada46 | ||
|
|
4e580bb74d | ||
|
|
6c4a4e6966 | ||
|
|
b490d6bc15 | ||
|
|
36741c767f | ||
|
|
e967f00977 | ||
|
|
bb616903ee | ||
|
|
c38cb3d46c | ||
|
|
c48447d3e6 | ||
|
|
e4001e67ef | ||
|
|
f33dbd31e5 | ||
|
|
45722c70d4 | ||
|
|
b0bb66fee8 | ||
|
|
97a624e2fc | ||
|
|
10b68408ca | ||
|
|
bfae0d6c6e | ||
|
|
a17fd2f268 | ||
|
|
e488a002da | ||
|
|
4cad780613 | ||
|
|
947d84316b | ||
|
|
91c83e2622 | ||
|
|
6e4c8b0d16 | ||
|
|
532992b03f | ||
|
|
a6640d533c | ||
|
|
0ba8b534e7 | ||
|
|
b17d04ddc5 | ||
|
|
906a42219d | ||
|
|
7e1657d632 | ||
|
|
5581f3ace8 | ||
|
|
0a01c5d4e4 | ||
|
|
712277eb9e | ||
|
|
2cb9d1484e | ||
|
|
409d1d6248 | ||
|
|
d5b79a92c4 | ||
|
|
fb8883a9d9 | ||
|
|
dd92aa6628 | ||
|
|
4a6703b63a | ||
|
|
bc0550a791 | ||
|
|
a3717095e7 | ||
|
|
ed56213d1b | ||
|
|
08d5aef9c9 | ||
|
|
d80a74b915 | ||
|
|
c05cbeae88 | ||
|
|
0ce305ebcf | ||
|
|
a7f996678f | ||
|
|
27b750813e | ||
|
|
c97e9f4f27 | ||
|
|
5c527c4632 | ||
|
|
12c3e4ee53 | ||
|
|
ca64d11552 | ||
|
|
86485cf19f | ||
|
|
55d81e0bf6 | ||
|
|
4f65f88f43 | ||
|
|
eadf6fbaf0 | ||
|
|
c286c21fb6 | ||
|
|
b7385e382c | ||
|
|
6ba4bf7202 | ||
|
|
5c99db9edb | ||
|
|
d3e9616908 | ||
|
|
4790f40179 | ||
|
|
7b016eac58 | ||
|
|
a8aa294199 | ||
|
|
e62bfadb76 | ||
|
|
b4887b7766 | ||
|
|
e04659a63d | ||
|
|
23b78960da | ||
|
|
cb87cc8172 | ||
|
|
13ead1ddeb | ||
|
|
fed8f021f2 | ||
|
|
e0d73b2fcd | ||
|
|
2173921f07 | ||
|
|
6c15bcbe05 | ||
|
|
b52da08c84 | ||
|
|
c6ebcc6e8e | ||
|
|
2117c19717 | ||
|
|
16bb4346e3 | ||
|
|
7c263872b1 | ||
|
|
71e3d788e0 | ||
|
|
b4e0dbcd80 | ||
|
|
aadfbafc33 | ||
|
|
cdde9b5d67 | ||
|
|
25b0ac3a6d | ||
|
|
a60b4cbbea | ||
|
|
e20a585b3a | ||
|
|
58580beb96 | ||
|
|
47767e86a1 | ||
|
|
e35af29ad0 | ||
|
|
1002bbb952 | ||
|
|
0f91268547 | ||
|
|
19e03eaf29 | ||
|
|
c9b47edc75 | ||
|
|
2791e03338 | ||
|
|
4b5b9250f1 | ||
|
|
ad14c83400 | ||
|
|
d095831b6d | ||
|
|
556d72dfad | ||
|
|
9884db3ce0 | ||
|
|
bb7a5e9cce | ||
|
|
b57bb1ad27 | ||
|
|
548d76efed | ||
|
|
a39f874c71 | ||
|
|
5ad481a2e0 | ||
|
|
7c4312f0c6 | ||
|
|
66284e2813 | ||
|
|
467a30ba66 | ||
|
|
6e1138ee5b | ||
|
|
ae55285493 | ||
|
|
553bcc9b8d | ||
|
|
1a34cba9fb | ||
|
|
78ef26ec3e | ||
|
|
d2e52fbbff | ||
|
|
dd172a2b24 | ||
|
|
e1b435fb0c | ||
|
|
484146fb09 | ||
|
|
a0b7280893 | ||
|
|
87382465aa | ||
|
|
932584982c | ||
|
|
62c2ee08b1 | ||
|
|
4171a0766f | ||
|
|
5126c5a1ef | ||
|
|
82c94cdf9d | ||
|
|
8b8ec48430 | ||
|
|
4702926773 | ||
|
|
a397d9a79a | ||
|
|
75a92ce485 | ||
|
|
14c3816fc9 | ||
|
|
2b5e0e23be | ||
|
|
6d27ff5969 | ||
|
|
d8d13bda42 | ||
|
|
31bb6d7864 | ||
|
|
12a248f102 | ||
|
|
49fa88fb69 | ||
|
|
3a3663bb55 | ||
|
|
0e671bbe81 | ||
|
|
2045946eb3 | ||
|
|
a4c0400ba5 | ||
|
|
622d8c2fc7 | ||
|
|
128919b851 | ||
|
|
3d5fc3ae2e | ||
|
|
eb8df307ec | ||
|
|
489f1aa57a | ||
|
|
d19e456efb | ||
|
|
2d8c3cfc64 | ||
|
|
55f16ab0ac | ||
|
|
2547a1fea7 | ||
|
|
7209093767 | ||
|
|
b99fb68675 | ||
|
|
4fb8e4713d | ||
|
|
f057633e14 | ||
|
|
9fc7fd2c5a | ||
|
|
f5c056fdeb | ||
|
|
434bfe1845 | ||
|
|
014e89ea8b | ||
|
|
ea79be0a8f | ||
|
|
972acd5718 | ||
|
|
140b7f3dea | ||
|
|
8bf905e1c2 | ||
|
|
dd279d3ea2 | ||
|
|
1e93057c52 | ||
|
|
b59b76a4f2 | ||
|
|
aed96a84e3 | ||
|
|
43d57597ab | ||
|
|
352b5d4d64 | ||
|
|
dabd0e3808 | ||
|
|
604d50585b | ||
|
|
7c56b722c9 | ||
|
|
ed3f9b65bf | ||
|
|
94812f53b2 | ||
|
|
37b14a6b0b | ||
|
|
b087ed0f50 | ||
|
|
28e3b18256 | ||
|
|
955c6e1888 | ||
|
|
e35e621743 | ||
|
|
4a0a86b83a | ||
|
|
d97e0b1f62 | ||
|
|
86375207cc | ||
|
|
4c6696c0f7 | ||
|
|
0a147a18d4 | ||
|
|
bdc3ef56d1 | ||
|
|
b67b90f197 | ||
|
|
69dfcaf140 | ||
|
|
6e2466046e | ||
|
|
e32cceb1b4 | ||
|
|
545c029752 | ||
|
|
ec25d91544 | ||
|
|
5c2da83cc1 | ||
|
|
04a71800fa | ||
|
|
cf8f4b682a | ||
|
|
42f275ac93 | ||
|
|
2bb65110f8 | ||
|
|
9ffa2bc116 | ||
|
|
fcdac82f53 | ||
|
|
f7f59483a5 | ||
|
|
551a9cb672 | ||
|
|
bca4f1c217 | ||
|
|
53a96fb26b | ||
|
|
3a6e01d08e | ||
|
|
3ce50b5cc1 | ||
|
|
3de12093c6 | ||
|
|
f1c2e307dc | ||
|
|
d5d782094b | ||
|
|
3c6e6fc4bf | ||
|
|
d6a77e5c19 | ||
|
|
277333724b | ||
|
|
14a1639a4f | ||
|
|
62f52e91c7 | ||
|
|
0ee671ac74 | ||
|
|
81b35baa61 | ||
|
|
95dfb608e3 | ||
|
|
f856b96aa5 | ||
|
|
4e6e4fa67e | ||
|
|
a3dfc30607 | ||
|
|
5160926477 | ||
|
|
5824ccd3b4 | ||
|
|
5deceb1a21 | ||
|
|
86ad4bc926 | ||
|
|
819ca16ccd | ||
|
|
93ea293a23 | ||
|
|
23c2627b3b | ||
|
|
7ea744fdfe | ||
|
|
b0dbbf4b5a | ||
|
|
403c313771 | ||
|
|
bed9d8cf33 | ||
|
|
5fa27a0339 | ||
|
|
749d5b0ea5 | ||
|
|
f297857d70 | ||
|
|
200212796a | ||
|
|
a84557ef0c | ||
|
|
68763137e9 | ||
|
|
de46556df7 | ||
|
|
f3cd0a4dda | ||
|
|
b1d2d1aea9 | ||
|
|
ef2f111eb0 | ||
|
|
89cf7d8c1e | ||
|
|
cde1d3c80b | ||
|
|
3e57d2dfa4 | ||
|
|
adbfa6122a | ||
|
|
ecc6ce5617 | ||
|
|
bd26ec32cf | ||
|
|
c19d2c5dd0 | ||
|
|
163f8f80f1 | ||
|
|
be5bfddc04 | ||
|
|
77b0c8ea23 | ||
|
|
d5c662fb74 | ||
|
|
a7aacb8802 | ||
|
|
258d7d1d12 | ||
|
|
94b5f8ced9 | ||
|
|
022ebd7311 | ||
|
|
45411d2e90 | ||
|
|
f67d59cc83 | ||
|
|
11007a8a24 | ||
|
|
6adb037a50 | ||
|
|
a98302e058 | ||
|
|
44071e93e9 | ||
|
|
f715a54354 | ||
|
|
ccf027afe5 | ||
|
|
437011524c | ||
|
|
3971b26797 | ||
|
|
66ced6df27 | ||
|
|
05aeb8a244 | ||
|
|
c244b12ec6 | ||
|
|
1ead77ef8d | ||
|
|
2305323734 | ||
|
|
3ea83158fb | ||
|
|
3f0d9484b7 | ||
|
|
fefce68687 | ||
|
|
43c16d02f9 | ||
|
|
53e2c5cf69 | ||
|
|
89942e0c8c | ||
|
|
f0ada3fed0 | ||
|
|
e4d8c04afe | ||
|
|
02ab92195a | ||
|
|
d7dd9c5fcc | ||
|
|
9d322746e6 | ||
|
|
dc6c815cec | ||
|
|
7087504841 | ||
|
|
0205e4f733 | ||
|
|
5e85eb0bb0 | ||
|
|
2267b8311c | ||
|
|
84bcfc73a9 | ||
|
|
c65bf86305 | ||
|
|
1501c9c483 | ||
|
|
181d4db0fe | ||
|
|
e168db19f3 | ||
|
|
19be5817a9 | ||
|
|
c1ecfc823a | ||
|
|
3dd469f1a0 | ||
|
|
4e67575bdf | ||
|
|
18eaebc217 | ||
|
|
7a38b70506 | ||
|
|
775568c7a7 | ||
|
|
328c7a1ba6 | ||
|
|
97eefa3b4c | ||
|
|
f2ca5c6555 | ||
|
|
19c95070b3 | ||
|
|
6789dda69f | ||
|
|
1fcb9124b6 | ||
|
|
f3d93c882f | ||
|
|
7c011b138a | ||
|
|
b76499c907 | ||
|
|
8918208f89 | ||
|
|
c3a9b67070 | ||
|
|
d2d6e95dd9 | ||
|
|
b818ba3548 | ||
|
|
aca0e7aab4 | ||
|
|
0d97c62ed8 | ||
|
|
618ab19693 | ||
|
|
250f2e1b85 | ||
|
|
f079170b70 | ||
|
|
d9481c4537 | ||
|
|
70a2a6a28c | ||
|
|
9064ebb71e | ||
|
|
b2a55fcfac | ||
|
|
376c4d53ac | ||
|
|
dc4116cff5 | ||
|
|
3b0d2da7e7 | ||
|
|
269d4dfbed | ||
|
|
d6b3d8b53b | ||
|
|
281a0787b7 | ||
|
|
136a805c70 | ||
|
|
e56149f162 | ||
|
|
d698760d30 | ||
|
|
7a5649510d | ||
|
|
cd0c564e9f | ||
|
|
a8f89e1068 | ||
|
|
ab5c1f8f55 | ||
|
|
f5db131693 | ||
|
|
b6d73f3d81 | ||
|
|
783b1f6480 | ||
|
|
bd57601cd8 | ||
|
|
c359254aaf | ||
|
|
209eaeb476 | ||
|
|
27c0a14ec6 | ||
|
|
6590236adb | ||
|
|
211bab8898 | ||
|
|
f66d8616e2 | ||
|
|
ddfc8e8326 | ||
|
|
e40fd1d688 | ||
|
|
a612b5c37b | ||
|
|
c9dddfe126 | ||
|
|
b09f783cef | ||
|
|
b52385406f | ||
|
|
6405066f08 | ||
|
|
7002ce1ea2 | ||
|
|
1df35c13c4 | ||
|
|
8fb616e293 | ||
|
|
5c59dc223e | ||
|
|
e0bea9119b | ||
|
|
1fef0cf780 | ||
|
|
627aa8662f | ||
|
|
42112aed42 | ||
|
|
7dd0772cc6 | ||
|
|
79faaaee1f | ||
|
|
ab7c7dae5a | ||
|
|
37e602e689 | ||
|
|
964fc9fd00 | ||
|
|
1087d7ef7f | ||
|
|
3acccafa27 | ||
|
|
9d18fb623f | ||
|
|
f85f6f29d3 | ||
|
|
4e24783662 | ||
|
|
89956002f8 | ||
|
|
ed3fb2013a | ||
|
|
726797ef29 | ||
|
|
fd68d8bd5b | ||
|
|
2d40878408 | ||
|
|
6ef47df0a7 | ||
|
|
7811b52a59 | ||
|
|
b21c85ad35 | ||
|
|
b4c448e984 | ||
|
|
bfda6b5cc6 | ||
|
|
1b4deddd07 | ||
|
|
4e28672b0a | ||
|
|
9dbe6b1c0a | ||
|
|
c4e6a043b0 | ||
|
|
44affd39bf | ||
|
|
ab2cfb6f7b | ||
|
|
427b5263ba | ||
|
|
b5338b746a | ||
|
|
270b34a068 | ||
|
|
6084182164 | ||
|
|
876641f1ac | ||
|
|
f74cd91438 | ||
|
|
53bdbfb540 | ||
|
|
3515abe063 | ||
|
|
8da8721298 | ||
|
|
b1b8063a71 | ||
|
|
0d8cf153f4 | ||
|
|
490834f369 | ||
|
|
546e1ef090 | ||
|
|
df0a0caa5a | ||
|
|
4c6d3437db | ||
|
|
75cf878dcf | ||
|
|
0ae16c2c84 | ||
|
|
b60e36965b | ||
|
|
3f4465735d | ||
|
|
7c3143242e | ||
|
|
49beea755e | ||
|
|
27e44ec08b | ||
|
|
6620a5773f | ||
|
|
bb9fff4c8d | ||
|
|
b46d5bb988 | ||
|
|
5b06fefdae | ||
|
|
da604d6bc0 | ||
|
|
e189d6785c | ||
|
|
6ec6688851 | ||
|
|
a90d59dc28 | ||
|
|
c1b59294cf | ||
|
|
40e19f0764 | ||
|
|
09bcb739b1 | ||
|
|
4087a02fdb | ||
|
|
9e9b8410c2 | ||
|
|
69364ea2d2 | ||
|
|
17b39fe585 | ||
|
|
477bc3b8e3 | ||
|
|
99fc690f4b | ||
|
|
7f71788a82 | ||
|
|
60af01a165 | ||
|
|
3a22bfbc24 | ||
|
|
fbde2a87a5 | ||
|
|
1a6e78efed | ||
|
|
1e45b69ca7 | ||
|
|
2fa50796da | ||
|
|
2a6e08f663 | ||
|
|
11fd5b39e8 | ||
|
|
a7f5b78139 | ||
|
|
e74a308113 | ||
|
|
390ddd9fd6 | ||
|
|
1ef585613e | ||
|
|
0c2c55726e | ||
|
|
aa42b9e7f5 | ||
|
|
275cc04e03 | ||
|
|
e19caeefe4 | ||
|
|
7f183ac2fd | ||
|
|
6b8acc1675 | ||
|
|
8f84c5d2d3 | ||
|
|
e2b442ae66 | ||
|
|
9a3da5a2fd | ||
|
|
6d69521b71 | ||
|
|
e59fac4884 | ||
|
|
3ea653cd03 | ||
|
|
caaef24bc7 | ||
|
|
2267066df2 | ||
|
|
963ec003cf | ||
|
|
2e217feaca | ||
|
|
598a73d57b | ||
|
|
ae09ea9346 | ||
|
|
56bab319e8 | ||
|
|
0b1bf704aa | ||
|
|
d9938c5be3 | ||
|
|
65c4b9c50a | ||
|
|
33b61bc3ee | ||
|
|
b9aace76fc | ||
|
|
527f224810 | ||
|
|
cbc26b3a43 | ||
|
|
8f84fa3a5b | ||
|
|
2aa370df76 | ||
|
|
c94ddfcf5c | ||
|
|
3761a93961 | ||
|
|
6f234f83fc | ||
|
|
7f986bd7c4 | ||
|
|
23e197dcc9 | ||
|
|
73dca2ba82 | ||
|
|
60af1b6a24 | ||
|
|
072924ce69 | ||
|
|
2bf3cb13b3 | ||
|
|
613489e9ca | ||
|
|
36256c392c | ||
|
|
41fb7d4f42 | ||
|
|
909f9f862e | ||
|
|
2981217a2e | ||
|
|
cc7670cc31 | ||
|
|
ab02ffad4d | ||
|
|
6b7e964f64 | ||
|
|
b420da573b | ||
|
|
e440d3885e | ||
|
|
d07ca171f9 | ||
|
|
2b04eebcab | ||
|
|
72e64506e1 | ||
|
|
d88cb67dbc | ||
|
|
392c34bbd0 | ||
|
|
d99755f223 | ||
|
|
90e271df97 | ||
|
|
f8cccb4757 | ||
|
|
b57224996a | ||
|
|
794c5aae0e | ||
|
|
ea40dcfe0b | ||
|
|
a94d7fa233 | ||
|
|
b7f8e5238b | ||
|
|
e2cf723c6a | ||
|
|
c62bc9c962 | ||
|
|
0bd154a937 | ||
|
|
68504f36ed | ||
|
|
7e3dce0ef7 | ||
|
|
9c0f44fc96 | ||
|
|
a40e40757c | ||
|
|
63cca7bb4b | ||
|
|
3c5bc7ef3c | ||
|
|
06ec0caec4 | ||
|
|
601d5e5fcb | ||
|
|
01fc105099 | ||
|
|
64c81569c3 | ||
|
|
dee3f58892 | ||
|
|
e7574b5089 | ||
|
|
c605418fa7 | ||
|
|
dd938c8a96 | ||
|
|
7353de17b9 | ||
|
|
6c34978488 | ||
|
|
4294e55fdb | ||
|
|
c7a505a986 | ||
|
|
334c03ab4e | ||
|
|
21d94a87b0 | ||
|
|
d5ca347dbe | ||
|
|
32e86cef66 | ||
|
|
d1f19b762f | ||
|
|
1a061ca38f | ||
|
|
a2236c2ca7 | ||
|
|
4cdfd23147 | ||
|
|
7c31245aa8 | ||
|
|
1ee2dea319 | ||
|
|
5b9f1cfdc1 | ||
|
|
c8508f1c94 | ||
|
|
6a31e3fc02 | ||
|
|
883f9ffd6e | ||
|
|
c745a5e31e | ||
|
|
30753982ff | ||
|
|
b51108ab6f | ||
|
|
2fff692eae | ||
|
|
e84c79fa27 | ||
|
|
35fc2fd410 | ||
|
|
1e7fabf511 | ||
|
|
d02f72ec4e | ||
|
|
5ba4636b9e | ||
|
|
41e67b0961 | ||
|
|
02e4ac5678 | ||
|
|
9eab6881ca | ||
|
|
ddccca9fd8 | ||
|
|
7a95191b0d | ||
|
|
e7602f424a | ||
|
|
638825eb55 | ||
|
|
d42fe91eca | ||
|
|
808345eb3f | ||
|
|
b533f75993 | ||
|
|
49f2bd3e13 | ||
|
|
da5deb7379 | ||
|
|
1ebb0b50ec | ||
|
|
e0192acc6f | ||
|
|
9af9742f5a | ||
|
|
510b7fe51a | ||
|
|
474ee853ef | ||
|
|
2103727b88 | ||
|
|
73a569ae6b | ||
|
|
982b8aa5c4 | ||
|
|
0b53ad3273 | ||
|
|
0c1aa2379c | ||
|
|
6561386c01 | ||
|
|
c86466210b | ||
|
|
3829dbcf41 | ||
|
|
1abaa54b62 | ||
|
|
47dceea585 | ||
|
|
8a34b88151 | ||
|
|
597c67bb1f | ||
|
|
b0ec3af9bb | ||
|
|
d25bfeafa5 | ||
|
|
4b470d4e32 | ||
|
|
e756b7e802 | ||
|
|
25345fe6b5 | ||
|
|
c8335f94d4 | ||
|
|
e8187cb8e6 | ||
|
|
baab42655f | ||
|
|
21992672e3 | ||
|
|
e50c15919e | ||
|
|
5e07d0e84d | ||
|
|
d433d5bcee | ||
|
|
428d9c649a | ||
|
|
51eba3a142 | ||
|
|
8f89665421 | ||
|
|
1ae01b2113 | ||
|
|
ee11ef1b33 | ||
|
|
86060d7c5b | ||
|
|
cd1a753e4c | ||
|
|
5619948d31 | ||
|
|
c4fb0c23e1 | ||
|
|
b62e555c58 | ||
|
|
03ad19e56b | ||
|
|
faa46dcc5c | ||
|
|
c28014bdbb | ||
|
|
43abf32dba | ||
|
|
4befb83b75 | ||
|
|
60ee315b79 | ||
|
|
7ec476ec4d | ||
|
|
77405a7232 | ||
|
|
6393f5b029 | ||
|
|
c8774e700b | ||
|
|
cae47b89a4 | ||
|
|
a0395e862d | ||
|
|
fb5aeeaf37 | ||
|
|
9d3828302b | ||
|
|
804311dd51 | ||
|
|
d1e04a7ca7 | ||
|
|
3dc9caeb0f | ||
|
|
4e86b319f7 | ||
|
|
9738848dc5 | ||
|
|
2045ebc110 | ||
|
|
2eb8cbf2d6 | ||
|
|
55f56a1145 | ||
|
|
49e04bd454 | ||
|
|
2689f4e22a | ||
|
|
3c697d4d6e | ||
|
|
dce036658e | ||
|
|
e704614320 | ||
|
|
32b194fa50 | ||
|
|
90dab68802 | ||
|
|
ad22876219 | ||
|
|
7296206aa6 | ||
|
|
03e15c6be1 | ||
|
|
25020ffd18 | ||
|
|
26f134c95d | ||
|
|
7ea293df60 | ||
|
|
cc444c606e | ||
|
|
46e7464b49 | ||
|
|
15c882f24e | ||
|
|
d4d1f7d454 | ||
|
|
860b9b8606 | ||
|
|
0bf459bb51 | ||
|
|
ad7cd67c02 | ||
|
|
2a201630e9 | ||
|
|
b193ee5521 | ||
|
|
ea58334db9 | ||
|
|
9042f1282c | ||
|
|
57bc21a1d1 | ||
|
|
a3d66b60fc | ||
|
|
70448ac197 | ||
|
|
0add5f8c7c | ||
|
|
fc2beda196 | ||
|
|
f7dc1d749b | ||
|
|
15ee1feca5 | ||
|
|
b0733a85de | ||
|
|
7404dcd40c | ||
|
|
4fe394226c | ||
|
|
5d7fabfc21 | ||
|
|
d6a1f04d4a | ||
|
|
6b1b034c61 | ||
|
|
a357f0d13f | ||
|
|
f1b8af8ac4 | ||
|
|
cd6cc53533 | ||
|
|
cb00ba600d | ||
|
|
192e7eb9d1 | ||
|
|
692e359235 | ||
|
|
e265716652 | ||
|
|
2fc5dfba70 | ||
|
|
41c252ea13 | ||
|
|
0607992e39 | ||
|
|
dc94043954 | ||
|
|
39dbf81dbf | ||
|
|
f7bb53970b | ||
|
|
e68425f0f9 | ||
|
|
2ab6a6d6b3 | ||
|
|
571d9d3c7b | ||
|
|
fcfe4d964e | ||
|
|
334a9b8321 | ||
|
|
00765288e6 | ||
|
|
0ce946bd90 | ||
|
|
af1e5f52ca | ||
|
|
57d37b7c8a | ||
|
|
9d21823e5f | ||
|
|
47eb6fd048 | ||
|
|
494c7da0a7 | ||
|
|
6b4179c20c | ||
|
|
8dd07495f5 | ||
|
|
2a42639f39 | ||
|
|
daa4c60b77 | ||
|
|
9a28f6252d | ||
|
|
8d1eab20e5 | ||
|
|
93efc2e6a0 | ||
|
|
41f8e9fe9e | ||
|
|
880c65f827 | ||
|
|
f6c3883735 | ||
|
|
d171d2af82 | ||
|
|
ab84719afe | ||
|
|
b54d0130f7 | ||
|
|
bb8b5fed82 | ||
|
|
44af3a2408 | ||
|
|
1b67b84369 | ||
|
|
3aca17ea6d | ||
|
|
115d80113a | ||
|
|
0646dc5cc0 | ||
|
|
0ae91ede62 | ||
|
|
49cf4434ad | ||
|
|
7c27537c20 | ||
|
|
4092615c63 | ||
|
|
161f6977b4 | ||
|
|
a775a754e2 | ||
|
|
c90acfc62b | ||
|
|
1ae6b47c9e | ||
|
|
2aefae912f | ||
|
|
7295747e8a | ||
|
|
0edf6883f2 | ||
|
|
15a76d3932 | ||
|
|
9ef31ce418 | ||
|
|
8c9067ed4a | ||
|
|
fa33595700 | ||
|
|
1680138e8d | ||
|
|
0f3e1c2c3a | ||
|
|
c9244a662f | ||
|
|
0fd8b17f5e | ||
|
|
c4b8f179a0 | ||
|
|
670aeea10d | ||
|
|
6c60214209 | ||
|
|
e88b6cadac | ||
|
|
c913826fc4 | ||
|
|
450124eb6b | ||
|
|
d2ff69fb0f | ||
|
|
62868d6681 | ||
|
|
1f239481b7 | ||
|
|
7d731c978a | ||
|
|
5e1664c700 | ||
|
|
5cdd08ee1d | ||
|
|
92e3d2e528 | ||
|
|
630cfdda1e | ||
|
|
f4b5318741 | ||
|
|
40efd67402 | ||
|
|
d519546a6c | ||
|
|
e306af5fc9 | ||
|
|
37bcae368b | ||
|
|
d2abcdc9d5 | ||
|
|
ff67f6abc3 | ||
|
|
e0817fd354 | ||
|
|
ad5e95f4ea | ||
|
|
48c6b42a0b | ||
|
|
f5f893ff8c | ||
|
|
b349c599fe | ||
|
|
730bcb034e | ||
|
|
c5315ba0fc | ||
|
|
a3f1c0fa24 | ||
|
|
1257c4bc3a | ||
|
|
b96df86296 | ||
|
|
62502b9d53 | ||
|
|
ae0e4895c1 | ||
|
|
76bfb4e7cc | ||
|
|
4e2c15458c | ||
|
|
fe24dccd8c | ||
|
|
046dd30786 | ||
|
|
fda71bf1e7 | ||
|
|
8ac4281989 | ||
|
|
13c0afbc1e | ||
|
|
8b81ee564c | ||
|
|
d705da13f7 | ||
|
|
b760bb6116 | ||
|
|
4d55780ec3 | ||
|
|
ac1158f55d | ||
|
|
f735693d75 | ||
|
|
6ddb7d16bc | ||
|
|
4cd99c5b2f | ||
|
|
254d25b4cc | ||
|
|
2939503ffc | ||
|
|
e5b0460a78 | ||
|
|
9b05b27e06 | ||
|
|
be187e28c6 | ||
|
|
1237304d4f | ||
|
|
370c2d46f6 | ||
|
|
22351762b4 | ||
|
|
be0101d343 | ||
|
|
356f2f5680 | ||
|
|
5f04c7a5d2 | ||
|
|
9b69b9949d | ||
|
|
64ed0e8ca7 | ||
|
|
ce735b5e38 | ||
|
|
09c4641e4d | ||
|
|
2e2d2e9541 | ||
|
|
70bc23a55b | ||
|
|
9d17736304 | ||
|
|
f05eb9a198 | ||
|
|
2c9fcdbfd0 | ||
|
|
722cb83bf1 | ||
|
|
4dcf339428 | ||
|
|
b0fc3b770b | ||
|
|
18fcc684c1 | ||
|
|
4e50a7a2a9 | ||
|
|
69b616bf76 | ||
|
|
1d2f3bf178 | ||
|
|
f6df573f54 | ||
|
|
338d5b2061 | ||
|
|
f57730f8ae | ||
|
|
4dea7e435c | ||
|
|
994ed714da | ||
|
|
fce2914f7a | ||
|
|
6086f3d0ab | ||
|
|
7e48087db8 | ||
|
|
b2b9befad9 | ||
|
|
ae112c64e3 | ||
|
|
4f89501285 | ||
|
|
c8d8fc422c | ||
|
|
2229237470 | ||
|
|
32549e3514 | ||
|
|
c6a0bb8bb8 | ||
|
|
f628c57eea | ||
|
|
22b2451de0 | ||
|
|
a24006324d | ||
|
|
db206b3381 | ||
|
|
96b0bdabda | ||
|
|
4a99484c32 | ||
|
|
a365f7d6b4 | ||
|
|
7872d5f68a | ||
|
|
f48d5bfedf | ||
|
|
c1401cf6db | ||
|
|
558fe0ad64 | ||
|
|
e913928d78 | ||
|
|
6815c5d83d | ||
|
|
11612d5028 | ||
|
|
821d790588 | ||
|
|
2dfbfc5aaf | ||
|
|
60e7509881 | ||
|
|
9c2086e444 | ||
|
|
6d1dc263f4 | ||
|
|
ddbd76e254 | ||
|
|
d7e59b4868 | ||
|
|
51f5268fb9 | ||
|
|
456b876ff7 | ||
|
|
da4f192b7a | ||
|
|
a4bb51fd55 | ||
|
|
3dd8531ef9 | ||
|
|
46e511ef95 | ||
|
|
4db8ff3946 | ||
|
|
60701f5b7c | ||
|
|
c26d32d810 | ||
|
|
e319b56f56 | ||
|
|
034ebc986c | ||
|
|
61e486ba38 | ||
|
|
b7bc172c40 | ||
|
|
58cd5e3bea | ||
|
|
2894b362ac | ||
|
|
2529b35094 | ||
|
|
e3600aa59a | ||
|
|
a895cd3f6e | ||
|
|
315a5a4209 | ||
|
|
a3719b2a78 | ||
|
|
b0b372a4fa | ||
|
|
d4eecf6299 | ||
|
|
466c765df5 | ||
|
|
ff288bb0e8 | ||
|
|
83f5a95e5c | ||
|
|
311965089e | ||
|
|
ea51ae8dcb | ||
|
|
37617e40f2 | ||
|
|
b88690b05b | ||
|
|
b98a14d085 | ||
|
|
73e5f39897 | ||
|
|
0489e2d571 | ||
|
|
49cac98430 | ||
|
|
a3ebfa69b5 | ||
|
|
954e5cde32 | ||
|
|
b3dd3d3613 | ||
|
|
7e28bdd5a9 | ||
|
|
12aa42f4bf | ||
|
|
f36da0a94a | ||
|
|
b24d9afab3 | ||
|
|
50b98708de | ||
|
|
579eb704a7 | ||
|
|
51e0adc7d8 | ||
|
|
babc1999c7 | ||
|
|
ea977d8c0d | ||
|
|
cd99f81064 | ||
|
|
9f4c2cc53e | ||
|
|
7e042930fa | ||
|
|
acb9a5bb6e | ||
|
|
410ead461d | ||
|
|
c7561b5dd8 | ||
|
|
138fc507c8 | ||
|
|
636f801bd7 | ||
|
|
501b6ab326 | ||
|
|
66b0315624 | ||
|
|
9cc451a941 | ||
|
|
dc5b48ecce | ||
|
|
ef41a18269 | ||
|
|
7bd76bef50 | ||
|
|
0147da4ccd | ||
|
|
5a00b22238 | ||
|
|
bcc2a8607e | ||
|
|
e1a6091f94 | ||
|
|
ab804807da | ||
|
|
9286e539b6 | ||
|
|
04fb1f2bf0 | ||
|
|
4382899468 | ||
|
|
626c490771 | ||
|
|
a151dcbfe6 | ||
|
|
5eca4eecee | ||
|
|
1a72126c4f | ||
|
|
a0ea6ead09 | ||
|
|
1bec66a241 | ||
|
|
bd9739e106 | ||
|
|
2107a1c5c0 | ||
|
|
9dac8b7807 | ||
|
|
3b16b51b08 | ||
|
|
257175d458 | ||
|
|
ecdf0e450a | ||
|
|
40bc91b6f3 | ||
|
|
32d3d24649 | ||
|
|
aec9455e73 | ||
|
|
09b1caf8d2 | ||
|
|
d9daad6372 | ||
|
|
e72614296c | ||
|
|
57e77baed1 | ||
|
|
2f90b85641 | ||
|
|
695e3068de | ||
|
|
947d9094cb | ||
|
|
79d32b62e3 | ||
|
|
8deca986bd | ||
|
|
13c2a3d14d | ||
|
|
0adfd19860 | ||
|
|
22495b4350 | ||
|
|
2189b92745 | ||
|
|
08feb51616 | ||
|
|
4c45dca3d6 | ||
|
|
e08088c4e1 | ||
|
|
73b052eacb | ||
|
|
e89effac46 | ||
|
|
6f11af7cf4 | ||
|
|
acd281c990 | ||
|
|
b8fa2c9b37 | ||
|
|
f2c5f4efdb | ||
|
|
6920134caf | ||
|
|
680c303ee3 | ||
|
|
568097597c | ||
|
|
e6c98d20c8 | ||
|
|
07aa35898a | ||
|
|
e71ebdcb15 | ||
|
|
8047cdccb1 | ||
|
|
d16523af7b | ||
|
|
1f3635ef69 | ||
|
|
2d9e1ae5c6 | ||
|
|
18f4fe9c3a | ||
|
|
a0ae340e6e | ||
|
|
aa21baa563 | ||
|
|
513e5b5ade | ||
|
|
0d61ce572b | ||
|
|
b33900dfbf | ||
|
|
99c69e30d2 | ||
|
|
ecf5c74fa3 | ||
|
|
0f85b186cc | ||
|
|
5ba9d7e503 | ||
|
|
4662a0a0b9 | ||
|
|
ef46d7c051 | ||
|
|
83b2cc9df0 | ||
|
|
0ad93f85ec | ||
|
|
00f3e816b7 | ||
|
|
e44c21fa36 | ||
|
|
3347646178 | ||
|
|
cd5fabf53e | ||
|
|
7c2bd29052 | ||
|
|
8d6f21b5a1 | ||
|
|
bbe5208413 | ||
|
|
5c48aea58e | ||
|
|
bed1c0c20e | ||
|
|
56f1702cac | ||
|
|
5846e5e1e4 | ||
|
|
18eb3ebc1a | ||
|
|
a3bcb3fcac | ||
|
|
36acb98618 | ||
|
|
7a2b1c73cd | ||
|
|
2a179e76a5 |
608 changed files with 145205 additions and 41816 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
*.sh text eol=lf
|
||||
12
.github/ISSUE_TEMPLATE/bug_report.md
vendored
12
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -29,12 +29,18 @@ If applicable, add screenshots to help explain your problem.
|
|||
- Network: [e.g. LAN/WAN, reverse proxy, cloudflare, ssl offload, etc...]
|
||||
- Version: [e.g. 1.0.43]
|
||||
- Node: [e.g. 18.4.0]
|
||||
|
||||
**Client Device (please complete the following information):**
|
||||
- Device: [e.g. Laptop]
|
||||
- OS: [e.g. Ubuntu]
|
||||
- Network: [e.g. Local to Meshcentral, Remote over WAN]
|
||||
- Browser: [e.g. Google Chrome]
|
||||
- MeshCentralRouter Version: [if applicable]
|
||||
|
||||
**Remote Device (please complete the following information):**
|
||||
- Device: [e.g. Laptop]
|
||||
- OS: [e.g. Windows 10]
|
||||
- Version: [e.g. 21H2]
|
||||
- OS: [e.g. Windows 10 21H2]
|
||||
- Network: [e.g. Local to Meshcentral, Remote over WAN]
|
||||
- Current Core Version (if known): [**HINT**: Go to a device then `console` Tab then type `info`]
|
||||
|
||||
**Additional context**
|
||||
|
|
@ -43,7 +49,7 @@ Add any other context about the problem here.
|
|||
**Your config.json file**
|
||||
```
|
||||
{
|
||||
"$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json",
|
||||
"__comment1__": "This is a simple configuration file, all values and sections that start with underscore (_) are ignored. Edit a section and remove the _ in front of the name. Refer to the user's guide for details.",
|
||||
"__comment2__": "See node_modules/meshcentral/sample-config-advanced.json for a more advanced example.",
|
||||
"settings": {
|
||||
|
|
|
|||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question
|
||||
url: https://github.com/Ylianst/MeshCentral/discussions
|
||||
about: Ask a question in discussions.
|
||||
- name: Unofficial Discord Server
|
||||
url: https://discord.gg/8wHC6ASWAc
|
||||
about: Please ask here for support questions.
|
||||
- name: Unoffical Telegram Channel
|
||||
url: https://t.me/meshcentral
|
||||
about: Please ask here for support questions.
|
||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
|
@ -48,4 +48,4 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
|
|
|||
4
.github/workflows/deploy-docs.yml
vendored
4
.github/workflows/deploy-docs.yml
vendored
|
|
@ -14,8 +14,8 @@ jobs:
|
|||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- run: pip install --upgrade pip
|
||||
|
|
|
|||
67
.github/workflows/docker.yml
vendored
Normal file
67
.github/workflows/docker.yml
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
name: Docker
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
check-token:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
token_defined: ${{ steps.token_check.outputs.token_defined }}
|
||||
steps:
|
||||
- name: Check token
|
||||
id: token_check
|
||||
env:
|
||||
MY_TOKEN: ${{ secrets.MY_TOKEN }}
|
||||
if: "${{ env.MY_TOKEN != '' }}"
|
||||
run: echo "token_defined=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
build:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check-token]
|
||||
if: needs.check-token.outputs.token_defined == 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.MY_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: |
|
||||
INCLUDE_MONGODBTOOLS=true
|
||||
PREINSTALL_LIBS=true
|
||||
25
.github/workflows/release.yml
vendored
Normal file
25
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
name: Release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'package.json'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Release
|
||||
uses: justincy/github-action-npm-release@2.0.2
|
||||
id: release
|
||||
with:
|
||||
token: ${{ secrets.MY_TOKEN }}
|
||||
- name: Print release output
|
||||
if: ${{ steps.release.outputs.released == 'true' }}
|
||||
run: echo Release ID ${{ steps.release.outputs.release_id }}
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -3,7 +3,6 @@
|
|||
[Tt]yping/
|
||||
[Ii]mages-spare/
|
||||
[Dd]aemon/
|
||||
[Bb]in/
|
||||
[Aa]gent/
|
||||
[Aa]gents/modules_meshcmd_min/
|
||||
[Aa]gents/modules_meshcore_min/
|
||||
|
|
@ -11,12 +10,12 @@
|
|||
[Aa]gents/meshcore.min.js
|
||||
[Pp]ublic/translations/
|
||||
[Vv]iews/translations/
|
||||
[Ee]mails/translations/
|
||||
[Pp]ublic/*-min.htm
|
||||
[Vv]iews/*-min.handlebars
|
||||
meshcentral.db
|
||||
meshcentral.db.json
|
||||
mesherrors.txt
|
||||
package-lock.json
|
||||
bob.json
|
||||
.greenlockrc
|
||||
|
||||
|
|
@ -42,7 +41,6 @@ bob.json
|
|||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
|
|
|
|||
2
.npmrc
2
.npmrc
|
|
@ -1 +1 @@
|
|||
engine-strict=true
|
||||
engine-strict = true
|
||||
922
.vscode/settings.json
vendored
Normal file
922
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,922 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"abcdf",
|
||||
"accountchange",
|
||||
"accountcreate",
|
||||
"accountid",
|
||||
"accountremove",
|
||||
"acebase",
|
||||
"acmd",
|
||||
"acmepath",
|
||||
"actiontype",
|
||||
"adddevicegroup",
|
||||
"adddeviceuser",
|
||||
"adddomain",
|
||||
"addmeshuser",
|
||||
"addtousergroup",
|
||||
"adduser",
|
||||
"addusergroup",
|
||||
"addusertodevice",
|
||||
"addusertodevicegroup",
|
||||
"addusertousergroup",
|
||||
"adminaccount",
|
||||
"adminname",
|
||||
"agentaliasdns",
|
||||
"agentaliasport",
|
||||
"agentallowedip",
|
||||
"agentapp",
|
||||
"agentblockedip",
|
||||
"agentconfig",
|
||||
"agentconsole",
|
||||
"agentcoredump",
|
||||
"agentcoredumpusers",
|
||||
"agentcustomization",
|
||||
"agentdownload",
|
||||
"agenterrorlogs",
|
||||
"agentid",
|
||||
"agentidletimeout",
|
||||
"agentinfo",
|
||||
"agentinvite",
|
||||
"agentinvitecodes",
|
||||
"agentkey",
|
||||
"Agentless",
|
||||
"agentnoproxy",
|
||||
"agentport",
|
||||
"agentportbind",
|
||||
"agentporttls",
|
||||
"agenttransfer",
|
||||
"agenttype",
|
||||
"agentupdateblocksize",
|
||||
"agentupdatetest",
|
||||
"agentwscompression",
|
||||
"aliasport",
|
||||
"allevents",
|
||||
"allowaccountreset",
|
||||
"allowframing",
|
||||
"allowfullscreen",
|
||||
"allowhighqualitydesktop",
|
||||
"allowsavingdevicecredentials",
|
||||
"allusers",
|
||||
"alreadyinstalled",
|
||||
"amtacmactivation",
|
||||
"amtevents",
|
||||
"amthost",
|
||||
"amtmanager",
|
||||
"amtoff",
|
||||
"amton",
|
||||
"amtonly",
|
||||
"amtpass",
|
||||
"amtreset",
|
||||
"amtscanner",
|
||||
"amtscanoptions",
|
||||
"anewaccountcaptcha",
|
||||
"apassword",
|
||||
"apasswordhint",
|
||||
"apikey",
|
||||
"apos",
|
||||
"appmetrics",
|
||||
"apprelays",
|
||||
"ashx",
|
||||
"assistantconfig",
|
||||
"assistantcustomization",
|
||||
"assistantnoproxy",
|
||||
"atag",
|
||||
"authcookie",
|
||||
"authenticode",
|
||||
"authfail",
|
||||
"authlog",
|
||||
"authlogfile",
|
||||
"Authn",
|
||||
"authorizationurl",
|
||||
"authstr",
|
||||
"authstrategies",
|
||||
"autofido",
|
||||
"awsrds",
|
||||
"backgroundcolor",
|
||||
"backgroundonly",
|
||||
"backupcode",
|
||||
"backuppath",
|
||||
"badargs",
|
||||
"badtlscert",
|
||||
"bancommonpasswords",
|
||||
"batchupload",
|
||||
"bitmask",
|
||||
"Bounser",
|
||||
"callbackurl",
|
||||
"captchaargs",
|
||||
"ccmp",
|
||||
"Centralv",
|
||||
"certbot",
|
||||
"certfiles",
|
||||
"certhash",
|
||||
"certkeyhash",
|
||||
"certpfx",
|
||||
"certpfxpass",
|
||||
"certurl",
|
||||
"cfile",
|
||||
"changedevice",
|
||||
"changenode",
|
||||
"changepassword",
|
||||
"chatnotify",
|
||||
"checkemail",
|
||||
"checkmail",
|
||||
"chnl",
|
||||
"CIRA",
|
||||
"ciraconn",
|
||||
"ciralocalfqdn",
|
||||
"ckey",
|
||||
"clearpower",
|
||||
"clientid",
|
||||
"clientsecret",
|
||||
"clipboardget",
|
||||
"clipboardset",
|
||||
"cmdoptions",
|
||||
"cmds",
|
||||
"cnonce",
|
||||
"companyname",
|
||||
"configfile",
|
||||
"configfiles",
|
||||
"configkey",
|
||||
"connectionstring",
|
||||
"Consts",
|
||||
"cookieipcheck",
|
||||
"cookiesamesite",
|
||||
"coolofftime",
|
||||
"coredump",
|
||||
"coredumps",
|
||||
"createaccount",
|
||||
"createmesh",
|
||||
"createusergroup",
|
||||
"crowdsec",
|
||||
"crypted",
|
||||
"cscli",
|
||||
"curloptionshttp",
|
||||
"curloptionshttps",
|
||||
"cuser",
|
||||
"cuserid",
|
||||
"customui",
|
||||
"datafile",
|
||||
"datapath",
|
||||
"datas",
|
||||
"datastr",
|
||||
"dbconfig",
|
||||
"dbdeleteconfigfiles",
|
||||
"dbencryptkey",
|
||||
"dbexport",
|
||||
"dbexportmin",
|
||||
"dbimport",
|
||||
"dblistconfigfiles",
|
||||
"dbmerge",
|
||||
"dbpullconfigfiles",
|
||||
"dbpulldatafiles",
|
||||
"dbpushconfigfiles",
|
||||
"dbshowconfigfile",
|
||||
"debuglevel",
|
||||
"defaultuserwebstate",
|
||||
"deldump",
|
||||
"deleteaccount",
|
||||
"deletedefaultdomain",
|
||||
"deletedomain",
|
||||
"deletemesh",
|
||||
"deleteuser",
|
||||
"deleteusergroup",
|
||||
"deluser",
|
||||
"deluserpath",
|
||||
"DESKLIMITEDINPUT",
|
||||
"desktopmultiplex",
|
||||
"desktopnotify",
|
||||
"desktopprivacybar",
|
||||
"desktopprompt",
|
||||
"desktoprelays",
|
||||
"desktopviewonly",
|
||||
"devbox",
|
||||
"devicefile",
|
||||
"deviceid",
|
||||
"deviceinfo",
|
||||
"deviceinfocount",
|
||||
"devicemessage",
|
||||
"deviceopenurl",
|
||||
"devicepower",
|
||||
"devicepowerevents",
|
||||
"devicesearchbarserverandclientname",
|
||||
"deviceshare",
|
||||
"devicesharing",
|
||||
"devicetoast",
|
||||
"devid",
|
||||
"Digesthash",
|
||||
"disablerequestedauthncontext",
|
||||
"displayname",
|
||||
"dlccore",
|
||||
"dlcore",
|
||||
"dldump",
|
||||
"dnscount",
|
||||
"dnssuffix",
|
||||
"domaindefaults",
|
||||
"domainid",
|
||||
"domainname",
|
||||
"domainurl",
|
||||
"domainx",
|
||||
"dont",
|
||||
"dontlognull",
|
||||
"downloadfile",
|
||||
"dumpcores",
|
||||
"dumpfile",
|
||||
"editdevice",
|
||||
"editdevicegroup",
|
||||
"editgroup",
|
||||
"editmesh",
|
||||
"edituser",
|
||||
"emailaddress",
|
||||
"emailcheck",
|
||||
"emaildomain",
|
||||
"emailexists",
|
||||
"emailok",
|
||||
"emailvalidation",
|
||||
"emailvalidationrequired",
|
||||
"emailverified",
|
||||
"entityid",
|
||||
"entrypoints",
|
||||
"errdesc",
|
||||
"errlogpath",
|
||||
"esversion",
|
||||
"etype",
|
||||
"eventlogger",
|
||||
"exactport",
|
||||
"exactports",
|
||||
"exphbs",
|
||||
"extractall",
|
||||
"extrakey",
|
||||
"extralinks",
|
||||
"extrascriptsrc",
|
||||
"factorauth",
|
||||
"factorwarning",
|
||||
"fadev",
|
||||
"fahold",
|
||||
"fasent",
|
||||
"fastcert",
|
||||
"fchallenge",
|
||||
"fileaccess",
|
||||
"filedata",
|
||||
"filefullpath",
|
||||
"filenotify",
|
||||
"fileprompt",
|
||||
"filesize",
|
||||
"filespath",
|
||||
"filestats",
|
||||
"fileurl",
|
||||
"filteredusers",
|
||||
"filterid",
|
||||
"firebaserelay",
|
||||
"firstname",
|
||||
"forceduserwebstate",
|
||||
"foregroundcolor",
|
||||
"forwardclient",
|
||||
"forwardfor",
|
||||
"forwardwrite",
|
||||
"forwardwsocket",
|
||||
"fpath",
|
||||
"Freemonitoring",
|
||||
"frontends",
|
||||
"ftarget",
|
||||
"fullpath",
|
||||
"fullrights",
|
||||
"fullscreen",
|
||||
"gatewaymac",
|
||||
"generateinvitelink",
|
||||
"geourl",
|
||||
"getnetworkinfo",
|
||||
"getsysinfo",
|
||||
"getwspass",
|
||||
"googleusercontent",
|
||||
"gotodevicename",
|
||||
"gotonode",
|
||||
"groupid",
|
||||
"guestdevicesharing",
|
||||
"guestname",
|
||||
"GUESTSHARING",
|
||||
"hashhex",
|
||||
"Hashi",
|
||||
"hashpass",
|
||||
"hashpasssplit",
|
||||
"hashpassword",
|
||||
"Hashs",
|
||||
"healthcheck",
|
||||
"Hilaire",
|
||||
"hkey",
|
||||
"httpheaders",
|
||||
"httplog",
|
||||
"httpport",
|
||||
"hwchallenge",
|
||||
"hwotp",
|
||||
"hwstate",
|
||||
"hwtoken",
|
||||
"Ider",
|
||||
"idexists",
|
||||
"idhex",
|
||||
"idpurl",
|
||||
"idsplit",
|
||||
"iframe",
|
||||
"ignoreagenthashcheck",
|
||||
"iishash",
|
||||
"imagebase",
|
||||
"imagefile",
|
||||
"indexagenterrorlog",
|
||||
"indexmcrec",
|
||||
"installflags",
|
||||
"installsize",
|
||||
"installtext",
|
||||
"intelamt",
|
||||
"interactiveonly",
|
||||
"interuser",
|
||||
"invitecodes",
|
||||
"ipaddr",
|
||||
"ipblockeduserredirect",
|
||||
"ipcheck",
|
||||
"ipex",
|
||||
"ipkvm",
|
||||
"iplayer",
|
||||
"ipranges",
|
||||
"isaml",
|
||||
"Jitsi",
|
||||
"jumpcloud",
|
||||
"keyfile",
|
||||
"keygrip",
|
||||
"keyid",
|
||||
"lanonly",
|
||||
"LAPI",
|
||||
"lastaddr",
|
||||
"lastconnect",
|
||||
"lastname",
|
||||
"ldapauth",
|
||||
"ldapobj",
|
||||
"ldapoptions",
|
||||
"ldapsaveusertofile",
|
||||
"ldapsyncwithusergroups",
|
||||
"ldapuserbinarykey",
|
||||
"ldapuseremail",
|
||||
"ldapusergroups",
|
||||
"ldapuserimage",
|
||||
"ldapuserkey",
|
||||
"ldapusername",
|
||||
"ldapuserphonenumber",
|
||||
"ldapuserrealname",
|
||||
"ldapuserrequiredgroupmembership",
|
||||
"ldapusers",
|
||||
"leok",
|
||||
"letsencrypt",
|
||||
"lightgray",
|
||||
"limiteddesktop",
|
||||
"limitedevents",
|
||||
"LIMITEVENTS",
|
||||
"Linaro",
|
||||
"linuxpath",
|
||||
"listdevicegroups",
|
||||
"listdevices",
|
||||
"listdomains",
|
||||
"listevents",
|
||||
"listusergroups",
|
||||
"listuserids",
|
||||
"listusers",
|
||||
"listusersessions",
|
||||
"listusersofdevicegroup",
|
||||
"loadconfigfromdb",
|
||||
"localdiscovery",
|
||||
"localfile",
|
||||
"localpath",
|
||||
"localrelay",
|
||||
"localsessionrecording",
|
||||
"localurl",
|
||||
"lockagentdownload",
|
||||
"locksettings",
|
||||
"logfile",
|
||||
"logincodeb",
|
||||
"logindomain",
|
||||
"loginfooter",
|
||||
"loginkey",
|
||||
"loginkeyfile",
|
||||
"loginlogo",
|
||||
"loginmode",
|
||||
"loginpass",
|
||||
"loginpicture",
|
||||
"loginscreen",
|
||||
"logintoken",
|
||||
"logintokengen",
|
||||
"logintokenkey",
|
||||
"logintokens",
|
||||
"loginuser",
|
||||
"logoback",
|
||||
"logoutcontrols",
|
||||
"logouturl",
|
||||
"macrouter",
|
||||
"magenturl",
|
||||
"mailserver",
|
||||
"mailtokengen",
|
||||
"maintenancemode",
|
||||
"mainwelcome",
|
||||
"MANAGECOMPUTERS",
|
||||
"managedevices",
|
||||
"manageusers",
|
||||
"markcoredump",
|
||||
"maxfidokeys",
|
||||
"maxlen",
|
||||
"maxuseraccounts",
|
||||
"mcpath",
|
||||
"mcrdesktop",
|
||||
"mcrec",
|
||||
"mcrfiles",
|
||||
"mcrouter",
|
||||
"Mebx",
|
||||
"meshaction",
|
||||
"meshadmin",
|
||||
"meshagent",
|
||||
"meshagents",
|
||||
"meshauth",
|
||||
"meshcentral",
|
||||
"meshcentralhost",
|
||||
"meshchange",
|
||||
"meshcmd",
|
||||
"meshcommander",
|
||||
"meshcookie",
|
||||
"meshcore",
|
||||
"meshctrl",
|
||||
"meshdesktopmultiplex",
|
||||
"meshdevicefile",
|
||||
"mesherrorlogpath",
|
||||
"mesherrors",
|
||||
"meshfilename",
|
||||
"meshid",
|
||||
"meshidhex",
|
||||
"meshidname",
|
||||
"meshinstall",
|
||||
"meshmail",
|
||||
"meshmessenger",
|
||||
"meshmessengerid",
|
||||
"meshmessengerpicture",
|
||||
"meshmessengertitle",
|
||||
"meshname",
|
||||
"meshosxagent",
|
||||
"meshquota",
|
||||
"meshrelay",
|
||||
"MESHRIGHT",
|
||||
"meshrights",
|
||||
"meshscanner",
|
||||
"meshserver",
|
||||
"meshsettings",
|
||||
"meshsettingslines",
|
||||
"meshtype",
|
||||
"meshuser",
|
||||
"Messagebox",
|
||||
"messageid",
|
||||
"Messenging",
|
||||
"minfo",
|
||||
"minifyall",
|
||||
"minifycore",
|
||||
"mongodbcol",
|
||||
"mongodump",
|
||||
"mongorestore",
|
||||
"moutput",
|
||||
"movetodevicegroup",
|
||||
"mpkg",
|
||||
"mpsaliasport",
|
||||
"mpscert",
|
||||
"mpsdebug",
|
||||
"mpspass",
|
||||
"mpsport",
|
||||
"mpsserver",
|
||||
"mpsservers",
|
||||
"MPSSSL",
|
||||
"mpstlsoffload",
|
||||
"mqttbroker",
|
||||
"MSCHA",
|
||||
"msgid",
|
||||
"mstsc",
|
||||
"mstscrelay",
|
||||
"mtype",
|
||||
"multiplexor",
|
||||
"multiresponse",
|
||||
"multivalued",
|
||||
"myaccountname",
|
||||
"mycompany",
|
||||
"mydomain",
|
||||
"mypassword",
|
||||
"myserver",
|
||||
"myservername",
|
||||
"nameexists",
|
||||
"nedbtodb",
|
||||
"netif",
|
||||
"newaccountemaildomains",
|
||||
"newaccountname",
|
||||
"newaccountrealms",
|
||||
"newaccounts",
|
||||
"newaccountscaptcha",
|
||||
"newaccountspass",
|
||||
"newaccountsrights",
|
||||
"newaccountsusergroups",
|
||||
"newgroupname",
|
||||
"newobj",
|
||||
"newpass",
|
||||
"newpassword",
|
||||
"NGNIX",
|
||||
"nightmode",
|
||||
"noact",
|
||||
"noagentupdate",
|
||||
"noamt",
|
||||
"noauth",
|
||||
"noav",
|
||||
"nodeconnect",
|
||||
"nodecount",
|
||||
"nodeid",
|
||||
"nodeids",
|
||||
"nodeidsplit",
|
||||
"nodeinfo",
|
||||
"nodekey",
|
||||
"nodepath",
|
||||
"NODESKTOP",
|
||||
"nodewindows",
|
||||
"nofiles",
|
||||
"nofirewall",
|
||||
"nolog",
|
||||
"nologout",
|
||||
"NOMESHCMD",
|
||||
"nominify",
|
||||
"nonalpha",
|
||||
"NONEWDEVICES",
|
||||
"nonewgroups",
|
||||
"noproxy",
|
||||
"noredirect",
|
||||
"nosniff",
|
||||
"noterminal",
|
||||
"notools",
|
||||
"nouser",
|
||||
"nousers",
|
||||
"novnc",
|
||||
"npmjs",
|
||||
"npmpath",
|
||||
"npmproxy",
|
||||
"npmtag",
|
||||
"objid",
|
||||
"ODELAY",
|
||||
"offloader",
|
||||
"offloaders",
|
||||
"oidc",
|
||||
"oldpassword",
|
||||
"oldpasswordban",
|
||||
"oldpasswords",
|
||||
"oneclickrecovery",
|
||||
"onlyselecteddevicegroups",
|
||||
"onlyselectedusers",
|
||||
"openidconnect",
|
||||
"openstreetmap",
|
||||
"openurl",
|
||||
"orphanagentuser",
|
||||
"osdesc",
|
||||
"osinfo",
|
||||
"otpdev",
|
||||
"otpekey",
|
||||
"otpemail",
|
||||
"otphkeys",
|
||||
"otpkeys",
|
||||
"otplib",
|
||||
"otppush",
|
||||
"otpsecret",
|
||||
"otpsms",
|
||||
"parentpath",
|
||||
"passchange",
|
||||
"passhint",
|
||||
"passlogin",
|
||||
"passrequirementstr",
|
||||
"passtype",
|
||||
"passwordrequirements",
|
||||
"passwordrequirementsstr",
|
||||
"pastlogin",
|
||||
"pathx",
|
||||
"peinfo",
|
||||
"phonenumber",
|
||||
"PKCK",
|
||||
"plivo",
|
||||
"pluginadmin",
|
||||
"plusplus",
|
||||
"portbind",
|
||||
"postflight",
|
||||
"poweraction",
|
||||
"powerevents",
|
||||
"Preconfigured",
|
||||
"Proto",
|
||||
"publicid",
|
||||
"pushlogin",
|
||||
"pushrelay",
|
||||
"pushrelayserver",
|
||||
"qport",
|
||||
"randompass",
|
||||
"Raritan",
|
||||
"rauth",
|
||||
"rawdata",
|
||||
"rcookie",
|
||||
"rdpport",
|
||||
"realname",
|
||||
"recordencryptionrecode",
|
||||
"recordpath",
|
||||
"redir",
|
||||
"rediraliasport",
|
||||
"redirections",
|
||||
"redirport",
|
||||
"redirserver",
|
||||
"refreshtoken",
|
||||
"relayaliasport",
|
||||
"relaydns",
|
||||
"relayid",
|
||||
"relayport",
|
||||
"relayserver",
|
||||
"relaysession",
|
||||
"remembertoken",
|
||||
"remoteaddr",
|
||||
"remoteaddrport",
|
||||
"REMOTECOMMAND",
|
||||
"remotecontrol",
|
||||
"remotefile",
|
||||
"remotepath",
|
||||
"REMOTEVIEWONLY",
|
||||
"removeallusersfromusergroup",
|
||||
"removedevicegroup",
|
||||
"removedomain",
|
||||
"removefromdomain",
|
||||
"removefromusergroup",
|
||||
"removemeshuser",
|
||||
"removesubdomain",
|
||||
"removetestagents",
|
||||
"removeuser",
|
||||
"removeuserfromdevice",
|
||||
"removeuserfromdevicegroup",
|
||||
"removeuserfromusergroup",
|
||||
"removeusergroup",
|
||||
"resetaccount",
|
||||
"RESETOFF",
|
||||
"resetpass",
|
||||
"responseid",
|
||||
"restoreserver",
|
||||
"rightsstr",
|
||||
"rname",
|
||||
"rnamel",
|
||||
"rootcert",
|
||||
"rootredirect",
|
||||
"rpassword",
|
||||
"rpasswordhint",
|
||||
"rport",
|
||||
"rtpass",
|
||||
"rtuser",
|
||||
"runas",
|
||||
"runasuser",
|
||||
"runasuseronly",
|
||||
"runcommand",
|
||||
"runcommands",
|
||||
"runmode",
|
||||
"runonservererror",
|
||||
"runonserverupdated",
|
||||
"ruserid",
|
||||
"sameorigin",
|
||||
"selfupdate",
|
||||
"selfurl",
|
||||
"senderid",
|
||||
"sendgrid",
|
||||
"sendinviteemail",
|
||||
"serialtunnel",
|
||||
"SERVERBACKUP",
|
||||
"serverfeatures",
|
||||
"serverfiles",
|
||||
"serverhttps",
|
||||
"serverid",
|
||||
"serveridhex",
|
||||
"serverinfo",
|
||||
"serverkey",
|
||||
"servername",
|
||||
"servernoproxy",
|
||||
"serverpath",
|
||||
"serverpic",
|
||||
"serverport",
|
||||
"SERVERRESTORE",
|
||||
"servertlshash",
|
||||
"serverupdate",
|
||||
"servicename",
|
||||
"servicepath",
|
||||
"sessioncode",
|
||||
"sessionkey",
|
||||
"sessionrecording",
|
||||
"sessionsamesite",
|
||||
"sessiontime",
|
||||
"setbad",
|
||||
"SETNOTES",
|
||||
"settodomain",
|
||||
"sftpconnect",
|
||||
"shareid",
|
||||
"showagents",
|
||||
"showall",
|
||||
"showallmeshes",
|
||||
"showevents",
|
||||
"showiplocations",
|
||||
"showitem",
|
||||
"showmeshes",
|
||||
"shownodes",
|
||||
"showpasswordlogin",
|
||||
"showpower",
|
||||
"showsmbios",
|
||||
"showusergroups",
|
||||
"showusers",
|
||||
"showversion",
|
||||
"siteadmin",
|
||||
"SITERIGHT",
|
||||
"sitestyle",
|
||||
"smsserver",
|
||||
"specificupdate",
|
||||
"splitip",
|
||||
"splitpath",
|
||||
"spliturl",
|
||||
"srights",
|
||||
"sshconnect",
|
||||
"sshfilesrelay",
|
||||
"sshport",
|
||||
"sshrelay",
|
||||
"sshterminalrelay",
|
||||
"ssid",
|
||||
"sspi",
|
||||
"startack",
|
||||
"statsevents",
|
||||
"stricttransportsecurity",
|
||||
"Strs",
|
||||
"subdir",
|
||||
"swarmallowedip",
|
||||
"swarmport",
|
||||
"swarmserver",
|
||||
"sysinfo",
|
||||
"syslogauth",
|
||||
"syslogjson",
|
||||
"syslogtcp",
|
||||
"tcpport",
|
||||
"telnyx",
|
||||
"temail",
|
||||
"tenantid",
|
||||
"terminalnotify",
|
||||
"terminalprompt",
|
||||
"termsize",
|
||||
"timedoc",
|
||||
"titleid",
|
||||
"titlepicture",
|
||||
"tkip",
|
||||
"tlscertcheck",
|
||||
"tlshash",
|
||||
"tlsock",
|
||||
"tlsoffload",
|
||||
"tlsoptions",
|
||||
"tlsrootcert",
|
||||
"tlsstrict",
|
||||
"tmpdl",
|
||||
"tokenemail",
|
||||
"tokenlogin",
|
||||
"tokenpassword",
|
||||
"tokenpush",
|
||||
"tokenrequired",
|
||||
"tokensms",
|
||||
"tokenurl",
|
||||
"tokenuserid",
|
||||
"tokenusername",
|
||||
"totalsize",
|
||||
"TOTP",
|
||||
"tpass",
|
||||
"tpassword",
|
||||
"tpush",
|
||||
"traefik",
|
||||
"translateall",
|
||||
"translationpath",
|
||||
"trustedcert",
|
||||
"trustedproxy",
|
||||
"tsms",
|
||||
"TTLS",
|
||||
"tunnelws",
|
||||
"tunnelwsstate",
|
||||
"tuser",
|
||||
"tuserid",
|
||||
"tusername",
|
||||
"twofactor",
|
||||
"twofactorcookiedurationdays",
|
||||
"twofactortimeout",
|
||||
"tzoffset",
|
||||
"uaparser",
|
||||
"ucookie",
|
||||
"ugroup",
|
||||
"ugroups",
|
||||
"ugrp",
|
||||
"ugrpid",
|
||||
"uicustomevent",
|
||||
"unadmin",
|
||||
"unknownuserrootredirect",
|
||||
"unsealkey",
|
||||
"updatefiles",
|
||||
"uploadack",
|
||||
"uploaderror",
|
||||
"uploadfile",
|
||||
"uploadfilebatch",
|
||||
"uploadmeshcorefile",
|
||||
"uploadstart",
|
||||
"urlpath",
|
||||
"urlswitching",
|
||||
"useid",
|
||||
"userallowedip",
|
||||
"userblockedip",
|
||||
"userbroadcast",
|
||||
"userconsentflags",
|
||||
"usercount",
|
||||
"userex",
|
||||
"userfiles",
|
||||
"userfirst",
|
||||
"usergroupchange",
|
||||
"usergroups",
|
||||
"userid",
|
||||
"userids",
|
||||
"userimage",
|
||||
"userinfourl",
|
||||
"usernameisemail",
|
||||
"userquota",
|
||||
"userrequiredhttpheader",
|
||||
"Usersessionidletimeout",
|
||||
"usersid",
|
||||
"usersplit",
|
||||
"vaultdeleteconfigfiles",
|
||||
"vaultpullconfigfiles",
|
||||
"vaultpushconfigfiles",
|
||||
"verifyemail",
|
||||
"Viewmode",
|
||||
"viewonly",
|
||||
"WAKEDEVICE",
|
||||
"wakedevices",
|
||||
"Walkthru",
|
||||
"wanonly",
|
||||
"Webauthn",
|
||||
"webcerthash",
|
||||
"webdefault",
|
||||
"webemailspath",
|
||||
"webider",
|
||||
"webpublicpath",
|
||||
"webpush",
|
||||
"webrelay",
|
||||
"webrelaydata",
|
||||
"webrelayserver",
|
||||
"webrequest",
|
||||
"webrtc",
|
||||
"webrtconfig",
|
||||
"webserver",
|
||||
"websockets",
|
||||
"WEBSSL",
|
||||
"webstate",
|
||||
"webviewspath",
|
||||
"WELCOMEMSG",
|
||||
"welcomepicture",
|
||||
"welcomepicturefullscreen",
|
||||
"welcometext",
|
||||
"wgetoptionshttp",
|
||||
"wgetoptionshttps",
|
||||
"wildleek",
|
||||
"winassistant",
|
||||
"winpath",
|
||||
"winrouter",
|
||||
"winservice",
|
||||
"wsagents",
|
||||
"wscompression",
|
||||
"wsrelays",
|
||||
"wssessioncount",
|
||||
"wssessions",
|
||||
"xarg",
|
||||
"xbytes",
|
||||
"xcmd",
|
||||
"xdomain",
|
||||
"xdomains",
|
||||
"xenv",
|
||||
"xevents",
|
||||
"xfile",
|
||||
"xfilelen",
|
||||
"xfilepath",
|
||||
"xflags",
|
||||
"xforwardedhost",
|
||||
"xinstall",
|
||||
"xjslint",
|
||||
"xmeshes",
|
||||
"xpad",
|
||||
"xpassword",
|
||||
"xrelay",
|
||||
"xrestart",
|
||||
"xstate",
|
||||
"xtls",
|
||||
"xtransport",
|
||||
"xuninstall",
|
||||
"xuserid",
|
||||
"xusername",
|
||||
"xxdata",
|
||||
"xxprocess",
|
||||
"xxurl",
|
||||
"xxuser",
|
||||
"xxxprocess",
|
||||
"Ylian",
|
||||
"yubikey",
|
||||
"yubikeyotp",
|
||||
"zdata",
|
||||
"zipfile"
|
||||
]
|
||||
}
|
||||
2
LICENSE
2
LICENSE
|
|
@ -186,7 +186,7 @@
|
|||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017-2021 Intel Corporation
|
||||
Copyright 2017-2025 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
<Compile Include="agents\modules_meshcmd\amt-wsman.js" />
|
||||
<Compile Include="agents\modules_meshcmd\amt-xml.js" />
|
||||
<Compile Include="agents\modules_meshcmd\amt.js" />
|
||||
<Compile Include="agents\modules_meshcmd\linux-dhcp.js" />
|
||||
<Compile Include="agents\modules_meshcmd\smbios.js" />
|
||||
<Compile Include="agents\modules_meshcmd\sysinfo.js" />
|
||||
<Compile Include="agents\modules_meshcmd\win-securitycenter.js" />
|
||||
|
|
@ -100,6 +101,7 @@
|
|||
<Compile Include="amt\amt-xml.js" />
|
||||
<Compile Include="amt\amt.js" />
|
||||
<Compile Include="authenticode.js" />
|
||||
<Compile Include="crowdsec.js" />
|
||||
<Compile Include="exeHandler.js" />
|
||||
<Compile Include="amtprovisioningserver.js" />
|
||||
<Compile Include="firebase.js" />
|
||||
|
|
@ -111,6 +113,7 @@
|
|||
<Compile Include="meshdesktopmultiplex.js" />
|
||||
<Compile Include="meshipkvm.js" />
|
||||
<Compile Include="meshmail.js" />
|
||||
<Compile Include="meshmessaging.js" />
|
||||
<Compile Include="meshrelay.js" />
|
||||
<Compile Include="meshsms.js" />
|
||||
<Compile Include="meshscanner.js" />
|
||||
|
|
@ -236,8 +239,8 @@
|
|||
<Compile Include="public\scripts\common-0.0.1.js" />
|
||||
<Compile Include="public\scripts\meshcentral.js" />
|
||||
<Compile Include="redirserver.js" />
|
||||
<Compile Include="taskmanager.js" />
|
||||
<Compile Include="translate\translate.js" />
|
||||
<Compile Include="ua-parser.js" />
|
||||
<Compile Include="webauthn.js" />
|
||||
<Compile Include="webrelayserver.js" />
|
||||
<Compile Include="webserver.js" />
|
||||
|
|
@ -437,7 +440,6 @@
|
|||
<Content Include="LICENSE" />
|
||||
<Content Include="meshcentral-config-schema.json" />
|
||||
<Content Include="package.json" />
|
||||
<Content Include="plugin_development.md" />
|
||||
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.application" />
|
||||
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.config.deploy" />
|
||||
<Content Include="public\clickonce\minirouter\Application Files\MeshMiniRouter_1_0_0_70\MeshMiniRouter.exe.deploy" />
|
||||
|
|
@ -592,12 +594,14 @@
|
|||
<Content Include="readme.md" />
|
||||
<Content Include="sample-config-advanced.json" />
|
||||
<Content Include="sample-config.json" />
|
||||
<Content Include="SECURITY.md" />
|
||||
<Content Include="SourceFileList.txt" />
|
||||
<Content Include="translate\readme.txt" />
|
||||
<Content Include="translate\translate.json" />
|
||||
<Content Include="views\agentinvite.handlebars" />
|
||||
<Content Include="views\default-mobile.handlebars" />
|
||||
<Content Include="views\default.handlebars" />
|
||||
<Content Include="views\default3.handlebars" />
|
||||
<Content Include="views\download.handlebars" />
|
||||
<Content Include="views\download2.handlebars" />
|
||||
<Content Include="views\error404-mobile.handlebars" />
|
||||
|
|
@ -677,6 +681,8 @@
|
|||
<Folder Include="typings\globals\ajv\" />
|
||||
<Folder Include="typings\globals\async\" />
|
||||
<Folder Include="typings\globals\axios\" />
|
||||
<Folder Include="typings\globals\big-integer\" />
|
||||
<Folder Include="typings\globals\busboy\" />
|
||||
<Folder Include="typings\globals\connect-redis\" />
|
||||
<Folder Include="typings\globals\cookie-session\" />
|
||||
<Folder Include="typings\globals\core-js\" />
|
||||
|
|
@ -690,6 +696,7 @@
|
|||
<Folder Include="typings\globals\he\" />
|
||||
<Folder Include="typings\globals\hooker\" />
|
||||
<Folder Include="typings\globals\http-errors\" />
|
||||
<Folder Include="typings\globals\ip\" />
|
||||
<Folder Include="typings\globals\is-plain-object\" />
|
||||
<Folder Include="typings\globals\jsbn\" />
|
||||
<Folder Include="typings\globals\klaw\" />
|
||||
|
|
@ -706,9 +713,12 @@
|
|||
<Folder Include="typings\globals\once\" />
|
||||
<Folder Include="typings\globals\passport\" />
|
||||
<Folder Include="typings\globals\pg-pool\" />
|
||||
<Folder Include="typings\globals\rx-lite\" />
|
||||
<Folder Include="typings\globals\split2\" />
|
||||
<Folder Include="typings\globals\sprintf-js\" />
|
||||
<Folder Include="typings\globals\sqlite3\" />
|
||||
<Folder Include="typings\globals\type-check\" />
|
||||
<Folder Include="typings\globals\ua-parser-js\" />
|
||||
<Folder Include="typings\globals\underscore\" />
|
||||
<Folder Include="typings\globals\uuid\" />
|
||||
<Folder Include="typings\globals\window-size\" />
|
||||
|
|
@ -718,6 +728,8 @@
|
|||
<TypeScriptCompile Include="typings\globals\ajv\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\async\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\axios\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\big-integer\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\busboy\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\connect-redis\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\cookie-session\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\core-js\index.d.ts" />
|
||||
|
|
@ -731,6 +743,7 @@
|
|||
<TypeScriptCompile Include="typings\globals\he\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\hooker\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\http-errors\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\ip\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\is-plain-object\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\jsbn\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\klaw\index.d.ts" />
|
||||
|
|
@ -747,9 +760,12 @@
|
|||
<TypeScriptCompile Include="typings\globals\once\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\passport\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\pg-pool\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\rx-lite\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\split2\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\sprintf-js\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\sqlite3\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\type-check\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\ua-parser-js\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\underscore\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\uuid\index.d.ts" />
|
||||
<TypeScriptCompile Include="typings\globals\window-size\index.d.ts" />
|
||||
|
|
|
|||
49
SECURITY.md
Normal file
49
SECURITY.md
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Any version of MeshCentral 1.x.x is supported.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.x.x | :white_check_mark: |
|
||||
| < 1.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report any concerns or security issue to Ylian Saint-Hilaire (ylianst@gmail.com). If needed, use my PGP key below.
|
||||
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: BCPG v1.56
|
||||
|
||||
mQMuBF2gC4sRCAClFNvMCCVW3ego3UHBQ6LhSenJfaZYhvn8gaGuemSQxqTI6bla
|
||||
BTAv3aMtQnvqlSuadMMegb+FO6hnaQMlGvpVA1qpkSzgrPS5HrBD3H33J2Nj3i93
|
||||
ZpDPpxdI0ehCj6IJPnl0GxGbpKIN8YpJUFl44wv1lMRFI1lgyb+dCoO60irYdNQB
|
||||
PV85BI+DwPfOBFHunwR78nqMvpvsk9HaeHjEP7oXr952/7EazUowZsMlEfkYnw5S
|
||||
+tLfpCoY3QWkektpJP40nMJSKQdV2NEuED99doA0X+7P1vsvFFFyMH69dnU2uSay
|
||||
XCHpkAbntBy0BGmtF1RnTcOMv2V/LPXnlMdvAQCbmLQzNra3r163tcdRY0jSs+pZ
|
||||
1L3w5tHNj2dzhfpa7wf/SIuds6QTr2LCN6miLoSVCRMMpT7d771b16GwQqWEXzN2
|
||||
+h7dYqrssHPOa8FSUrPerz0+0eFcbMSm5/L/4KXWXoQthURv8aMP9E0iVoUYaaKB
|
||||
7U+5vFEZbpoOZyZmTAjXQMSNZCft0azA82Q+G85euyicWtMv48yNVzUhkdh+M2ud
|
||||
ohkXX2Aor1TqpBJoIeWke7j9D+Bo+lu61zPRx5ed9teUeLJCwqNEjlE+6gre5kxF
|
||||
PoreAtn59QYcBIpzQEWVMbNFlDAR4jMyqIoKCGfBPiRw2V+kunbzqiGQEglIFfOt
|
||||
6sTN/+CJh0ei976VDmE0Z1kMN+CNLgIjIw8fl02V9QgAnHcpqtVUxR4dbGOhVDq5
|
||||
lWv+K75QQlWyXC2k+KboXcaCvH0WZEBACYzO0CfrZ5hP9BSkbj5usSUVGGHwEFAJ
|
||||
t+/04KVY71fW281Ej5kGNaIKxeKsx6+hMo+UXb5ZM+6fANNNxs1cK95sTH6PjkyB
|
||||
tsKxLoa3CV2v9mSE5JiKKt74R9nXVo7PXf6DizwAU2l30Lb6y6y0OdXdCCPAG8Ij
|
||||
FrMgPu5MtjgsO5DnkZfUqDPWHhOgEPyOh3Ho+pvDhNYh5cm2eLQ8g5orzs2FHwbZ
|
||||
DpAHwCdqrlcpBlKJ4W/MZdf1fg2PjqaTWm7ZFiGr91P0F6kltTLWbVKTjLdS0T+D
|
||||
L7QnWWxpYW4gU2FpbnQtSGlsYWlyZSA8eWxpYW5zdEBnbWFpbC5jb20+iF4EExEI
|
||||
AAYFAl2gC4sACgkQg7j/r4DH+kD/3gD+MRedlM53VzOtNOpS6mqDAxj1aWP90HN0
|
||||
AqO6zuCTyGgBAJlunLFKH8IUetmQOhiohB8HVhdm/q4lKRDV7sHdplDyuMwEXaAL
|
||||
ixACAJSU/sCV87he4oZUKzg2/IGl3QoDSbTCOd04dE1IjPjjHbi8t9M7Qau55aM8
|
||||
ypFEsc7zMslL8Fc78EejrKmM3zsB/RU9XWFyrbQwRbaK6OHeEHC2E3AFaG0p09c6
|
||||
d0kZloHuWyEsm5a/3PpbIM1eP9IESJXWCc+bQQt6DxLKHLmkKMwB/icWMg8uMJlx
|
||||
aady8TEq7LH5oFVKsglnwuN1nIkecrf77TVkEqTjIxS6TiOup6zOnioFNKLYBAH0
|
||||
WUnJEYFvx4OIXgQYEQgABgUCXaALiwAKCRCDuP+vgMf6QGFTAQCUj2gGwsFlN0eR
|
||||
Wowv4eLcc3FwQ+lBElUctKg8vNFb0gD/ZWVWsWwKerNgNnf7RGD9mt8G2CKvdgGG
|
||||
oZ2hPP2gU9w=
|
||||
=roW4
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
agents/MeshCmdARM64.exe
Normal file
BIN
agents/MeshCmdARM64.exe
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
agents/MeshServiceARM64.exe
Normal file
BIN
agents/MeshServiceARM64.exe
Normal file
Binary file not shown.
|
|
@ -34,10 +34,10 @@
|
|||
"agent": "Agent",
|
||||
"group": "Skupina zařízení",
|
||||
"url": "URL serveru",
|
||||
"meshName": "Název oka",
|
||||
"meshName": "Skupinové jméno",
|
||||
"meshId": "Identifikátor skupiny",
|
||||
"serverId": "Identifikátor serveru",
|
||||
"setup": "Založit",
|
||||
"setup": "Nastavit",
|
||||
"update": "Aktualizace",
|
||||
"install": "Instalace",
|
||||
"uninstall": "Odinstalace",
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
"zenity": "Zkuste nainstalovat / aktualizovat Zenity a spustit znovu",
|
||||
"status": [
|
||||
"NENÍ INSTALOVÁN",
|
||||
"BĚH",
|
||||
"SPUŠTĚNO",
|
||||
"NEFUNGUJE"
|
||||
],
|
||||
"statusDescription": "Aktuální stav agenta",
|
||||
|
|
@ -65,11 +65,11 @@
|
|||
"agent": "Agent",
|
||||
"group": "Gerätegruppe",
|
||||
"url": "Server-URL",
|
||||
"meshName": "MESH Name",
|
||||
"meshName": "Gruppenname",
|
||||
"meshId": "Gruppen-ID",
|
||||
"serverId": "Server-ID",
|
||||
"setup": "Konfiguration",
|
||||
"update": "Updates",
|
||||
"update": "Aktualisierung",
|
||||
"install": "Installieren",
|
||||
"uninstall": "Deinstallation",
|
||||
"connect": "Verbinden",
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
"GESTARTET",
|
||||
"NICHT GESTARTET"
|
||||
],
|
||||
"statusDescription": "Aktueller Agentenstatus",
|
||||
"statusDescription": "Aktueller Agentstatus",
|
||||
"agentVersion": "Neue Version",
|
||||
"elevation": "Zum Installieren/Deinstallieren dieser Software sind erhöhte Berechtigungen erforderlich.",
|
||||
"graphicalerror": "Die grafische Version dieses Installationsprogramms kann auf diesem System nicht ausgeführt werden",
|
||||
|
|
@ -98,7 +98,7 @@
|
|||
"agent": "Agente",
|
||||
"group": "Grupo de Dispositivos",
|
||||
"url": "URL del servidor",
|
||||
"meshName": "Nombre de malla",
|
||||
"meshName": "Nombre del grupo",
|
||||
"meshId": "Identificador del Grupo",
|
||||
"serverId": "Identificador de Servidor",
|
||||
"setup": "Preparar",
|
||||
|
|
@ -129,7 +129,7 @@
|
|||
"agent": "Agentti",
|
||||
"group": "Laiteryhmä",
|
||||
"url": "Palvelimen URL-osoite",
|
||||
"meshName": "Verkon nimi",
|
||||
"meshName": "Ryhmän nimi",
|
||||
"meshId": "Ryhmän tunniste",
|
||||
"serverId": "Palvelimen tunniste",
|
||||
"setup": "Perustaa",
|
||||
|
|
@ -191,7 +191,7 @@
|
|||
"agent": "एजेंट",
|
||||
"group": "डिवाइस समूह",
|
||||
"url": "सर्वर URL",
|
||||
"meshName": "मेष नाम",
|
||||
"meshName": "समूह नाम",
|
||||
"meshId": "समूह पहचानकर्ता",
|
||||
"serverId": "सर्वर पहचानकर्ता",
|
||||
"setup": "सेट अप",
|
||||
|
|
@ -222,7 +222,7 @@
|
|||
"agent": "Agente",
|
||||
"group": "Gruppo di dispositivi",
|
||||
"url": "URL del server",
|
||||
"meshName": "Nome mesh",
|
||||
"meshName": "Nome del gruppo",
|
||||
"meshId": "Identificatore di gruppo",
|
||||
"serverId": "Identificatore del server",
|
||||
"setup": "Impostare",
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
"agent": "エージェント",
|
||||
"group": "デバイスグループ",
|
||||
"url": "サーバーのURL",
|
||||
"meshName": "メッシュ名",
|
||||
"meshName": "그룹 이름",
|
||||
"meshId": "グループ識別子",
|
||||
"serverId": "サーバー識別子",
|
||||
"setup": "セットアップ",
|
||||
|
|
@ -284,7 +284,7 @@
|
|||
"agent": "에이전트",
|
||||
"group": "장치 그룹",
|
||||
"url": "서버의 위치",
|
||||
"meshName": "메시의 이름",
|
||||
"meshName": "그룹 이름",
|
||||
"meshId": "그룹 식별자",
|
||||
"serverId": "서버의 식별자",
|
||||
"setup": "설정하다",
|
||||
|
|
@ -305,7 +305,11 @@
|
|||
"운영",
|
||||
"중지됨"
|
||||
],
|
||||
"statusDescription": "에이전트 상태"
|
||||
"statusDescription": "에이전트 상태",
|
||||
"agentVersion": "새로운 버전",
|
||||
"elevation": "이 소프트웨어를 설치/제거하려면 높은 권한이 필요합니다.",
|
||||
"graphicalerror": "이 설치 프로그램의 그래픽 버전은 이 시스템에서 실행할 수 없습니다.",
|
||||
"description": "이 원격 관리 소프트웨어를 설치하거나 제거하려면 아래 버튼을 클릭하십시오. 이 소프트웨어를 설치하면 백그라운드에서 실행되어 원격 관리자가 이 컴퓨터를 관리하고 제어할 수 있습니다."
|
||||
},
|
||||
"nl": {
|
||||
"agent": "Agent",
|
||||
|
|
@ -342,7 +346,7 @@
|
|||
"agent": "Agente",
|
||||
"group": "Grupo de dispositivos",
|
||||
"url": "URL do servidor",
|
||||
"meshName": "Nome da malha",
|
||||
"meshName": "Nome do grupo",
|
||||
"meshId": "Identificador de Grupo",
|
||||
"serverId": "Identificador de Servidor",
|
||||
"setup": "Configuração",
|
||||
|
|
@ -363,7 +367,11 @@
|
|||
"CORRIDA",
|
||||
"NÃO CORRENDO"
|
||||
],
|
||||
"statusDescription": "Status atual do agente"
|
||||
"statusDescription": "Status atual do agente",
|
||||
"agentVersion": "Nova versão",
|
||||
"elevation": "Permissões elevadas são necessárias para instalar/desinstalar este software.",
|
||||
"graphicalerror": "A versão gráfica deste instalador não pode ser executada neste sistema",
|
||||
"description": "Clique nos botões abaixo para instalar ou desinstalar este software de gerenciamento remoto. Quando instalado, este software é executado em segundo plano, permitindo que este computador seja gerenciado e controlado por um administrador remoto."
|
||||
},
|
||||
"ru": {
|
||||
"agent": "Агент",
|
||||
|
|
@ -400,7 +408,7 @@
|
|||
"agent": "Agent",
|
||||
"group": "Enhetsgrupp",
|
||||
"url": "Serverns URL",
|
||||
"meshName": "Masknamn",
|
||||
"meshName": "Grupp namn",
|
||||
"meshId": "Gruppidentifierare",
|
||||
"serverId": "Serveridentifierare",
|
||||
"setup": "Uppstart",
|
||||
|
|
@ -421,13 +429,17 @@
|
|||
"LÖPNING",
|
||||
"SPRINGER INTE"
|
||||
],
|
||||
"statusDescription": "Aktuell agentstatus"
|
||||
"statusDescription": "Aktuell agentstatus",
|
||||
"agentVersion": "Ny version",
|
||||
"elevation": "Förhöjda behörigheter krävs för att installera/avinstallera denna programvara.",
|
||||
"graphicalerror": "Den grafiska versionen av detta installationsprogram kan inte köras på det här systemet",
|
||||
"description": "Klicka på knapparna nedan för att installera eller avinstallera denna fjärrhanteringsprogramvara. När den är installerad körs den här programvaran i bakgrunden så att den här datorn kan hanteras och kontrolleras av en fjärradministratör."
|
||||
},
|
||||
"tr": {
|
||||
"agent": "Agent",
|
||||
"group": "Cihaz Grubu",
|
||||
"url": "Sunucu URL'si",
|
||||
"meshName": "Mesh Adı",
|
||||
"meshName": "Grup ismi",
|
||||
"meshId": "Grup Tanımlayıcı",
|
||||
"serverId": "Sunucu Tanımlayıcı",
|
||||
"setup": "Kurmak",
|
||||
|
|
@ -458,11 +470,11 @@
|
|||
"agent": "代理",
|
||||
"group": "设备组",
|
||||
"url": "服务器网址",
|
||||
"meshName": "网格名称",
|
||||
"meshName": "团队名字",
|
||||
"meshId": "组标识符",
|
||||
"serverId": "服务器标识符",
|
||||
"setup": "设定",
|
||||
"update": "更新资料",
|
||||
"update": "更新",
|
||||
"install": "安装",
|
||||
"uninstall": "卸载",
|
||||
"connect": "连接",
|
||||
|
|
@ -479,13 +491,17 @@
|
|||
"正在运行",
|
||||
"不在运行"
|
||||
],
|
||||
"statusDescription": "当前代理状态"
|
||||
"statusDescription": "当前代理状态",
|
||||
"agentVersion": "新版本",
|
||||
"elevation": "安装/卸载此软件需要提升权限。",
|
||||
"graphicalerror": "此安装程序的图形版本无法在此系统上运行",
|
||||
"description": "单击下面的按钮以安装或卸载此远程管理软件。安装后,该软件在后台运行,允许远程管理员管理和控制该计算机。"
|
||||
},
|
||||
"zh-cht": {
|
||||
"agent": "代理",
|
||||
"group": "裝置群",
|
||||
"url": "服務器網址",
|
||||
"meshName": "網格名稱",
|
||||
"meshName": "團隊名字",
|
||||
"meshId": "群標識符",
|
||||
"serverId": "服務器標識符",
|
||||
"setup": "設定",
|
||||
|
|
@ -506,13 +522,17 @@
|
|||
"正在運行",
|
||||
"不在運行"
|
||||
],
|
||||
"statusDescription": "當前代理狀態"
|
||||
"statusDescription": "當前代理狀態",
|
||||
"agentVersion": "新版本",
|
||||
"elevation": "安裝/卸載此軟件需要提升權限。",
|
||||
"graphicalerror": "此安裝程序的圖形版本無法在此系統上運行",
|
||||
"description": "單擊下面的按鈕以安裝或卸載此遠程管理軟件。安裝後,該軟件在後台運行,允許遠程管理員管理和控制該計算機。"
|
||||
},
|
||||
"da": {
|
||||
"agent": "Agent",
|
||||
"group": "Enhedsgruppe",
|
||||
"url": "Server URL",
|
||||
"meshName": "Mesh Navn",
|
||||
"meshName": "Gruppe navn",
|
||||
"meshId": "Gruppe-id",
|
||||
"serverId": "Serveridentifikator",
|
||||
"setup": "Opsætning",
|
||||
|
|
@ -600,5 +620,129 @@
|
|||
"elevation": "Permissões Elevadas são necessárias para instalar/desinstalar este software",
|
||||
"graphicalerror": "A versão gráfica do instalador não pode ser executada neste sistema",
|
||||
"description": "Clique nos botões abaixo para instalar ou desinstalar este software de gerenciamento remoto. Quando instalado, este software é executado em segundo plano permitindo que este computador seja gerenciado e controlado por um administrador remoto"
|
||||
},
|
||||
"bs": {
|
||||
"agent": "Agent",
|
||||
"agentVersion": "Nova verzija",
|
||||
"group": "Grupa uređaja",
|
||||
"url": "URL servera",
|
||||
"meshName": "Ime grupe",
|
||||
"meshId": "Grupni identifikator",
|
||||
"serverId": "Identifikator servera",
|
||||
"setup": "Postaviti",
|
||||
"update": "Ažuriraj",
|
||||
"install": "Instaliraj",
|
||||
"uninstall": "Deinstalirati",
|
||||
"connect": "Povežite se",
|
||||
"disconnect": "Prekini vezu",
|
||||
"cancel": "Otkaži",
|
||||
"close": "Zatvori",
|
||||
"pressok": "Pritisnite OK da prekinete vezu",
|
||||
"elevation": "Za instaliranje/deinstaliranje ovog softvera potrebne su povišene dozvole.",
|
||||
"sudo": "Molimo pokušajte ponovo sa sudo.",
|
||||
"ctrlc": "Pritisnite Ctrl-C za izlaz.",
|
||||
"commands": "Možete pokrenuti tekstualnu verziju iz komandne linije sa sljedećim naredbama",
|
||||
"graphicalerror": "Grafička verzija ovog instalatera ne može da radi na ovom sistemu",
|
||||
"zenity": "Pokušajte instalirati/ažurirati Zenity i pokrenite ponovo",
|
||||
"status": [
|
||||
"NIJE INSTALIRANO",
|
||||
"RUNNING",
|
||||
"NOT RUNNING"
|
||||
],
|
||||
"statusDescription": "Trenutni status agenta",
|
||||
"description": "Kliknite na dugmad ispod da instalirate ili deinstalirate ovaj softver za daljinsko upravljanje. Kada je instaliran, ovaj softver radi u pozadini, što omogućava da ovim računarom upravlja i kontroliše udaljeni administrator."
|
||||
},
|
||||
"hu": {
|
||||
"agent": "Agent",
|
||||
"agentVersion": "Új verzió",
|
||||
"group": "Eszköz csoport",
|
||||
"url": "Kiszolgáló URL",
|
||||
"meshName": "Csoport név",
|
||||
"meshId": "Csoport azonosító",
|
||||
"serverId": "Kiszolgáló azonosító",
|
||||
"setup": "Beállítás",
|
||||
"update": "Frissítés",
|
||||
"install": "Telepítés",
|
||||
"uninstall": "Eltávolítás",
|
||||
"connect": "Kapcsolódás",
|
||||
"disconnect": "Lekapcsolódás",
|
||||
"cancel": "Mégse",
|
||||
"close": "Bezár",
|
||||
"pressok": "Press OK to disconnect",
|
||||
"elevation": "A szoftver telepítéséhez/eltávolításához megnövelt jogosultságok szükségesek.",
|
||||
"sudo": "Kérjük, próbálja meg újra a sudo használatával.",
|
||||
"ctrlc": "A kilépéshez nyomja meg a Ctrl-C billentyűt.",
|
||||
"commands": "A szöveges változatot a parancssorból futtathatja a következő parancs(okk)al",
|
||||
"graphicalerror": "A telepítő grafikus verziója nem futtatható ezen a rendszeren.",
|
||||
"zenity": "Próbálja meg telepíteni/frissíteni a Zenity-t, és indítsa újra",
|
||||
"status": [
|
||||
"NINCS TELEPÍTVE",
|
||||
"FUT",
|
||||
"NEM FUT"
|
||||
],
|
||||
"statusDescription": "Jelenlegi agent állapota",
|
||||
"description": "Kattintson a Telepítés vagy Eltávolítás gombokra a Távfelügyeleti alkalmazás telepítéséhez vagy eltávolításához. Telepítés után ez az alkalmazás a háttérben fut, lehetővé téve, hogy a számítógépet egy távoli rendszergazda kezelje."
|
||||
},
|
||||
"ca": {
|
||||
"agent": "Agent",
|
||||
"agentVersion": "Nova versió",
|
||||
"group": "Grup de dispositius",
|
||||
"url": "URL del servidor",
|
||||
"meshName": "Nom del grup",
|
||||
"meshId": "Identificador de grup",
|
||||
"serverId": "Identificador del servidor",
|
||||
"setup": "Configuració",
|
||||
"update": "Actualització",
|
||||
"install": "Instal·lar",
|
||||
"uninstall": "Desinstal·la",
|
||||
"connect": "Connecta't",
|
||||
"disconnect": "Desconnecta",
|
||||
"cancel": "Cancel · lar",
|
||||
"close": "Tanca",
|
||||
"pressok": "Premeu D'acord per desconnectar",
|
||||
"elevation": "Es necessiten permisos elevats per instal·lar/desinstal·lar aquest programari.",
|
||||
"sudo": "Si us plau, torna-ho a provar amb sudo.",
|
||||
"ctrlc": "Premeu Ctrl-C per sortir.",
|
||||
"commands": "Podeu executar la versió de text des de la línia d'ordres amb les següents ordres",
|
||||
"graphicalerror": "La versió gràfica d'aquest instal·lador no pot executar-se en aquest sistema",
|
||||
"zenity": "Proveu d'instal·lar/actualitzar Zenity i torneu a executar-lo",
|
||||
"status": [
|
||||
"NO ESTÀ INSTAL · LAT",
|
||||
"CÓRRER",
|
||||
"NO CORRE"
|
||||
],
|
||||
"statusDescription": "Estat actual de l'agent",
|
||||
"description": "Feu clic als botons següents per instal·lar o desinstal·lar aquest programari de gestió remota. Quan s'instal·la, aquest programari s'executa en segon pla i permet que aquest ordinador sigui gestionat i controlat per un administrador remot."
|
||||
},
|
||||
"uk": {
|
||||
"agent": "Агент",
|
||||
"agentVersion": "Нова Версія",
|
||||
"group": "Група Пристроїв",
|
||||
"url": "URL Сервера",
|
||||
"meshName": "Ім'я Групи",
|
||||
"meshId": "Ідентифікатор групи",
|
||||
"serverId": "Ідентифікатор серверу",
|
||||
"setup": "Налаштувати",
|
||||
"update": "Оновлення",
|
||||
"install": "Інсталювати",
|
||||
"uninstall": "Видалити",
|
||||
"connect": "Підключитися",
|
||||
"disconnect": "Відключити",
|
||||
"cancel": "Скасувати",
|
||||
"close": "Закрити",
|
||||
"pressok": "Натисніть OK, щоб від'єднатися",
|
||||
"elevation": "Для інсталяції/деінсталяції цього програмного забезпечення потрібні підвищені дозволи.",
|
||||
"sudo": "Будь ласка, спробуйте ще раз за допомогою sudo.",
|
||||
"ctrlc": "Натисніть Ctrl-C, щоб вийти",
|
||||
"commands": "Ви можете запустити текстову версію з командного рядка за допомогою таких команд",
|
||||
"graphicalerror": "Графічна версія цього інсталятора не може працювати в цій системі",
|
||||
"zenity": "Спробуйте встановити/оновити Zenity та запустіть наново",
|
||||
"status": [
|
||||
"НЕ ВСТАНОВЛЕНО",
|
||||
"ВИКОНУЄТЬСЯ",
|
||||
"НЕ ПРАЦЮЄ"
|
||||
],
|
||||
"statusDescription": "Поточний Статус Агента",
|
||||
"description": "Клікнути кнопки нижче, щоб інсталювати або видалити це програмне забезпечення для віддаленого керування. Після інсталювання ця програма працює у фоновому режимі, що дозволяє віддаленому адміністратору керувати цим комп'ютером."
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,9 @@
|
|||
@ECHO OFF
|
||||
MD modules_meshcmd_min
|
||||
MD modules_meshcore_min
|
||||
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" compressalljs "modules_meshcore" "modules_meshcore_min"
|
||||
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" compressalljs "modules_meshcmd" "modules_meshcmd_min"
|
||||
|
||||
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" meshcore.js
|
||||
"..\..\WebSiteCompiler\bin\Debug\WebSiteCompiler.exe" meshcmd.js
|
||||
|
||||
REM del meshcore.min.js
|
||||
REM %LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcore.js
|
||||
REM rename meshcore.js.min meshcore.min.js
|
||||
|
||||
REM del meshcmd.min.js
|
||||
REM %LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify meshcmd.js
|
||||
REM rename meshcmd.js.min meshcmd.min.js
|
||||
|
||||
REM Minify the translations
|
||||
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minify modules_meshcore\coretranslations.json
|
||||
COPY modules_meshcore\coretranslations.json.min modules_meshcore_min\coretranslations.json
|
||||
DEL modules_meshcore\coretranslations.json.min
|
||||
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minifydir C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcore C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcore_min
|
||||
%LOCALAPPDATA%\..\Roaming\nvm\v14.16.0\node ..\translate\translate.js minifydir C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcmd C:\Users\Default.DESKTOP-9CGK2DI\Desktop\AmtWebApp\meshcentral\agents\modules_meshcmd_min
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
MeshService-signed.exe hashagents.js > hashagents.json
|
||||
MeshService.exe hashagents.js > hashagents.json
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
var fs = require('fs');
|
||||
|
||||
var agents = {
|
||||
'MeshService-signed.exe': 3,
|
||||
'MeshService64-signed.exe': 4,
|
||||
'MeshService.exe': 3,
|
||||
'MeshService64.exe': 4,
|
||||
'meshagent_x86': 5,
|
||||
'meshagent_x86-64': 6,
|
||||
'meshagent_arm': 9,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
{
|
||||
"3": {
|
||||
"filename": "MeshService.exe",
|
||||
"hash": "33AE44E73CA79EDD443661F8D6205DF59DE7D03B0AC730A37D283C9CE4079E6136FFC30BC1B79DA8FB05F03CBDE75D06",
|
||||
"size": 3793408,
|
||||
"mtime": "2022-08-25T17:55:54Z"
|
||||
},
|
||||
"4": {
|
||||
"filename": "MeshService64.exe",
|
||||
"hash": "C809BAB1F0B988F1436E1033D9F07A782412A6CC7ECCF4AC52CCCBD91D7B56D401F2AB5FABC71A66F91B20E6FCA393D4",
|
||||
"size": 3422720,
|
||||
"mtime": "2022-08-25T17:55:24Z"
|
||||
},
|
||||
"5": {
|
||||
"filename": "meshagent_x86",
|
||||
"hash": "024A8FCE66C277CFAA375B6F5A12E18D08BF2F8EE494C4408544D93F219F7208BACF056F79A2340428C3C34F765E325E",
|
||||
"size": 3666464,
|
||||
"mtime": "2022-08-29T17:48:58Z"
|
||||
},
|
||||
"6": {
|
||||
"filename": "meshagent_x86-64",
|
||||
"hash": "DC5924847AD22C058D1009BE7EDFAFEAF248DEC706C263736B254BA5917D274A21BAE0D025852EC788007EF3688CDC64",
|
||||
"size": 3741136,
|
||||
"mtime": "2022-08-29T17:49:06Z"
|
||||
},
|
||||
"7": {
|
||||
"filename": "meshagent_mips",
|
||||
"hash": "C49212CA4BF2D1F031F376C0157A4B9C5EA5ACD08180662F27F2EA54F990C2A7840B5A3BF7F66D85EE194EF675008D09",
|
||||
"size": 4547696,
|
||||
"mtime": "2022-08-29T17:49:13Z"
|
||||
},
|
||||
"9": {
|
||||
"filename": "meshagent_arm",
|
||||
"hash": "5217EBF6638EDC64FFFBE3B53BF9DC640D630CC69B9CE484C1CA274530C248D248AC4F4E84071A34CD504039D8D0B022",
|
||||
"size": 3148064,
|
||||
"mtime": "2022-08-29T17:49:22Z"
|
||||
},
|
||||
"13": {
|
||||
"filename": "meshagent_pogo",
|
||||
"hash": "1523191069F30678C607E32F557CD5F9125A963C671CE7A7F6FB8ADD9B9BFB890AC1A6248872EAE899737F378F54FFF2",
|
||||
"size": 3156744,
|
||||
"mtime": "2022-08-29T17:49:32Z"
|
||||
},
|
||||
"15": {
|
||||
"filename": "meshagent_poky",
|
||||
"hash": "36090B49C98D7A3E7515EC2D22E5C47A4FD9BA35B517949BAF04B39A7CE91378656A7F3FC132C5E43FD1D087B3C9226E",
|
||||
"size": 3796600,
|
||||
"mtime": "2022-08-29T17:49:42Z"
|
||||
},
|
||||
"16": {
|
||||
"filename": "meshagent_osx-x86-64",
|
||||
"hash": "F7A3EBEC3D855EBFB2C72271C17196C7692EB2685DCBA70B56B63C80D6CF0DAA7DF00657BB4A12F4C0D92281B1BB47FE",
|
||||
"size": 4670736,
|
||||
"mtime": "2022-08-23T03:31:00Z"
|
||||
},
|
||||
"18": {
|
||||
"filename": "meshagent_poky64",
|
||||
"hash": "FD61B913D2239621FDCC2E949BF16FCAE3F9D46D25EEF74DA0A7971F30A44E315A4231AF824241940391A3F112794A27",
|
||||
"size": 3495416,
|
||||
"mtime": "2022-08-29T17:49:52Z"
|
||||
},
|
||||
"19": {
|
||||
"filename": "meshagent_x86_nokvm",
|
||||
"hash": "BF125A52656DFE6665E78AB22ED652F4C65C17624A12BCAC2F0691A255AF208C3E883101266F3E80052F4CFE8602B29B",
|
||||
"size": 3385732,
|
||||
"mtime": "2022-08-29T17:50:00Z"
|
||||
},
|
||||
"20": {
|
||||
"filename": "meshagent_x86-64_nokvm",
|
||||
"hash": "9AB50A5419A2BAFC8DC485C3F24387622689FE3A0C146317CE3EA951F3EE2E4902CCE3878F2098C6EB23A848E510E478",
|
||||
"size": 3446192,
|
||||
"mtime": "2022-08-29T17:50:08Z"
|
||||
},
|
||||
"24": {
|
||||
"filename": "meshagent_arm-linaro",
|
||||
"hash": "DCC5B487A200F9670B33BE603F52088856FB249CC03F5B62D1617CA9A95B55329B120FE4D3FFD72B2E5FE1ADE302CF81",
|
||||
"size": 2211156,
|
||||
"mtime": "2022-08-29T17:50:21Z"
|
||||
},
|
||||
"25": {
|
||||
"filename": "meshagent_armhf",
|
||||
"hash": "1EDCE4E132927B432F60A3D262368B3DF54B012EDD786EAD31139646B5D9168297C32D13C7D822CE5FEF7FE44B65B4A0",
|
||||
"size": 3181452,
|
||||
"mtime": "2022-08-23T03:14:16Z"
|
||||
},
|
||||
"27": {
|
||||
"filename": "meshagent_armhf2",
|
||||
"hash": "0AE840520D3B677B9767EA097F3AA5A1E24212529E688200F43935DB1541AB9FB441EC2C7BA8002D45299B04695FD037",
|
||||
"size": 2837724,
|
||||
"mtime": "1985-10-26T08:15:00Z"
|
||||
},
|
||||
"28": {
|
||||
"filename": "meshagent_mips24kc",
|
||||
"hash": "88A79B78497D1D004E44D02989A3BE3710D3BEE0A129F98579FFAA826FAC6C90CD69B9B218B90377438942BA85DAC81C",
|
||||
"size": 4181416,
|
||||
"mtime": "2022-08-23T03:15:24Z"
|
||||
},
|
||||
"29": {
|
||||
"filename": "meshagent_osx-arm-64",
|
||||
"hash": "CFE022146F2ED61E68F907E57E3704CC7F409D7F2B4D87E64ED6D83C53F41777BCDDCCF42DF8B8BB25CCEC9A93D799C7",
|
||||
"size": 3945576,
|
||||
"mtime": "2022-08-23T03:31:00Z"
|
||||
},
|
||||
"30": {
|
||||
"filename": "meshagent_freebsd_x86-64",
|
||||
"hash": "5C2CDDA2E7AB5068D990FBC725D8D5E3EA2724A0E001C226C0C7BB9F3A46492880BF260B5DD9E733F87EB68BA7494BD6",
|
||||
"size": 4673560,
|
||||
"mtime": "2022-08-23T03:31:12Z"
|
||||
},
|
||||
"32": {
|
||||
"filename": "meshagent_aarch64",
|
||||
"hash": "21C97445FA93C2A42337AD0E336F840A05EC553F8C040F6021C16339567F8A063EB06876D62C2C2924BD9F656434E9DB",
|
||||
"size": 3248496,
|
||||
"mtime": "2022-08-23T03:13:02Z"
|
||||
},
|
||||
"40": {
|
||||
"filename": "meshagent_mipsel24kc",
|
||||
"hash": "A58CF777ACA3E9B3F7C0FC664E5EAC1F95C3FD03ABDE93E2B06547D0BA1C671A9E67F252CACD9BCBD2019561E18ED7DF",
|
||||
"size": 4177288,
|
||||
"mtime": "2022-08-23T03:16:32Z"
|
||||
},
|
||||
"41": {
|
||||
"filename": "meshagent_aarch64-cortex-a53",
|
||||
"hash": "CC84858AD16C644096B87E3686B318F82CD1A39015FF17D93456456F0A51D4A2D4DEC7F6EAA2ABB065D7EAD28CD024A2",
|
||||
"size": 3076424,
|
||||
"mtime": "2022-08-23T03:17:42Z"
|
||||
},
|
||||
"10005": {
|
||||
"filename": "meshagent_osx-universal-64",
|
||||
"hash": "D320CA61D59FD8D76CF681CFE78A94CE37C47DBCAA8B29DF483F42C000EA9B655B5E5909A2AD6699D45D2D7691FF4964",
|
||||
"size": 8647784,
|
||||
"mtime": "2022-08-23T03:31:00Z"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
BIN
agents/meshagent_android.apk
Normal file
BIN
agents/meshagent_android.apk
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -25,7 +25,6 @@ limitations under the License.
|
|||
//console.displayStreamPipeMessages = 1; // Display stream pipe and un-pipes
|
||||
//var __gc = setInterval(function () { console.log('GC'); _debugGC() }, 2000); //
|
||||
|
||||
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var net = require('net');
|
||||
|
|
@ -129,6 +128,7 @@ function run(argv) {
|
|||
if ((typeof args.id) == 'string') { settings.id = args.id; }
|
||||
if ((typeof args.username) == 'string') { settings.username = args.username; }
|
||||
if ((typeof args.password) == 'string') { settings.password = args.password; }
|
||||
if ((typeof args.passwordhex) == 'string') { settings.password = Buffer.from(args.passwordhex, 'hex').toString(); }
|
||||
if ((typeof args.url) == 'string') { settings.url = args.url; }
|
||||
if ((typeof args.type) == 'string') { settings.type = args.type; }
|
||||
if ((typeof args.user) == 'string') { settings.username = args.user; }
|
||||
|
|
@ -172,6 +172,12 @@ function run(argv) {
|
|||
if ((argv.length > 1) && (actions.indexOf(argv[1].toUpperCase()) >= 0)) { settings.action = argv[1]; }
|
||||
if (globalDebugFlags != 0) { console.setInfoLevel(1); }
|
||||
|
||||
if (settings.debuglevel > 1) {
|
||||
if (settings.hostname) { console.log('Hostname HEX: ' + Buffer.from(settings.hostname, 'binary').toString('hex')); }
|
||||
if (settings.username) { console.log('Username HEX: ' + Buffer.from(settings.username, 'binary').toString('hex')); }
|
||||
if (settings.password) { console.log('Password HEX: ' + Buffer.from(settings.password, 'binary').toString('hex')); }
|
||||
}
|
||||
|
||||
// Validate meshaction.txt
|
||||
if (settings.action == null) {
|
||||
console.log('MeshCentral Command (MeshCmd) ' + meshCmdVersion);
|
||||
|
|
@ -206,6 +212,7 @@ function run(argv) {
|
|||
console.log(' AmtWake - Intel AMT Wake Alarms.');
|
||||
console.log(' AmtRPE - Intel AMT Remote Platform Erase.');
|
||||
console.log(' AmtDDNS - Intel AMT DDNS settings.');
|
||||
if (console.canonical != null) { console.log(' AmtTerm - Intel AMT Serial-over-LAN terminal.'); }
|
||||
console.log('\r\nHelp on a specific action using:\r\n');
|
||||
console.log(' meshcmd help [action]');
|
||||
exit(0); return;
|
||||
|
|
@ -379,15 +386,13 @@ function run(argv) {
|
|||
console.log('\r\Required arguments:\r\n');
|
||||
console.log(' --scan [ip range] The IP address range to perform the scan on.');
|
||||
} else if (action == 'amtwifi') {
|
||||
console.log('AmtWifi is used to get/set Intel AMT Wifi configuration. Example usage:\r\n\r\n meshcmd amtwifi --host 1.2.3.4 --user admin --pass mypassword --list');
|
||||
console.log('AmtWifi is used to list, add or delete Intel AMT Wifi configuration. Example usage:\r\n\r\n meshcmd amtwifi --host 1.2.3.4 --user admin --pass mypassword --list');
|
||||
console.log('\r\nRequired arguments:\r\n');
|
||||
console.log(' --host [hostname] The IP address or DNS name of Intel AMT, 127.0.0.1 is default.');
|
||||
console.log(' --pass [password] The Intel AMT login password.');
|
||||
console.log(' --[action] Action options are list, add, del.');
|
||||
console.log('\r\nOptional arguments:\r\n');
|
||||
console.log(' --user [username] The Intel AMT login username, admin is default.');
|
||||
console.log(' --tls Specifies that TLS must be used.');
|
||||
console.log(' --list List Wifi profiles');
|
||||
console.log(' --add Add new Wifi profile');
|
||||
console.log(' --name New Wifi profile name');
|
||||
console.log(' --priority Priority of this profile - default 0');
|
||||
|
|
@ -436,6 +441,13 @@ function run(argv) {
|
|||
console.log(' --set [disabled/dhcp/enabled] Set the dynamic DNS mode.');
|
||||
console.log(' --interval [minutes] Set update interval in minutes, default is 1440, minimum is 20.');
|
||||
console.log(' --ttl [seconds] Set time to live, default is 900.');
|
||||
} else if ((action == 'amtterm') && (console.canonical != null)) {
|
||||
console.log('AmtTerm is used to connect to the Serial-over-LAN port. Example usage:\r\n\r\n meshcmd amtterm --host 1.2.3.4 --user admin --pass mypassword');
|
||||
console.log('\r\nRequired arguments:\r\n');
|
||||
console.log(' --host [hostname] The IP address or DNS name of Intel AMT, 127.0.0.1 is default.');
|
||||
console.log(' --pass [password] The Intel AMT login password.');
|
||||
console.log('\r\nOptional arguments:\r\n');
|
||||
console.log(' --tls Specifies that TLS must be used.');
|
||||
} else {
|
||||
actions.shift();
|
||||
console.log('Invalid action, usage:\r\n\r\n meshcmd help [action]\r\n\r\nValid actions are: ' + actions.join(', ') + '.');
|
||||
|
|
@ -576,7 +588,7 @@ function run(argv) {
|
|||
}
|
||||
amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
|
||||
amtMei.getProvisioningMode(function (result) { if (result) { mestate.ProvisioningMode = result; } });
|
||||
amtMei.getEHBCState(function (result) { mestate.ehbc = ((result === true) || (typeof result == 'object') && (result.EHBC === true)); });
|
||||
amtMei.getEHBCState(function (result) { if (result) { mestate.ehbc = ((result === true) || (typeof result == 'object') && (result.EHBC === true)); } });
|
||||
amtMei.getControlMode(function (result) { if (result) { mestate.controlmode = result; } });
|
||||
amtMei.getMACAddresses(function (result) { if (result) { mestate.mac = result; } });
|
||||
amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } });
|
||||
|
|
@ -707,7 +719,7 @@ function run(argv) {
|
|||
// Start Intel AMT configuration
|
||||
if ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == '')) { console.log('No MeshCentral server URL specified, use --url [url].'); exit(1); return; }
|
||||
if ((settings.id == null) || (typeof settings.id != 'string') || (settings.id == '')) { console.log('No device group identifier specified, use --id [identifier].'); exit(1); return; }
|
||||
settings.id = settings.id.replace('\'', ''); // Remove single quote.
|
||||
settings.id = settings.id.split('\'').join(''); // Remove single quotes.
|
||||
debug(1, "Settings: " + JSON.stringify(settings));
|
||||
configureAmt();
|
||||
} else if (settings.action == 'amtccm') {
|
||||
|
|
@ -824,6 +836,11 @@ function run(argv) {
|
|||
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
|
||||
if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
|
||||
performAmtFeatureConfig(args);
|
||||
} else if ((settings.action == 'amtterm') && (console.canonical != null)) {
|
||||
if (settings.hostname == null) { settings.hostname = '127.0.0.1'; }
|
||||
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
|
||||
if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
|
||||
performAmtTerm(args);
|
||||
} else if (settings.action == 'amtpower') { // Perform remote Intel AMT power operation
|
||||
if ((settings.hostname == null) || (typeof settings.hostname != 'string') || (settings.hostname == '')) { console.log('No or invalid \"hostname\" specified, use --hostname [host].'); exit(1); return; }
|
||||
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
|
||||
|
|
@ -1483,7 +1500,12 @@ function deactivateACMEx() {
|
|||
amtstack = new amt(wsstack);
|
||||
amtstack.Get("AMT_SetupAndConfigurationService", function (stack, name, responses, status) {
|
||||
if (status !== 200) {
|
||||
console.log('Command not allowed. Status: ' + status);
|
||||
if ((responses != null) && (responses.Header != null) && (typeof responses.Header.error == 'string')) {
|
||||
console.log(responses.Header.error + ', Status: ' + status);
|
||||
if (status == 600) { console.log('Check that Intel AMT is in ACM mode and that the password is correct.'); }
|
||||
} else {
|
||||
console.log('Command not allowed, Status: ' + status);
|
||||
}
|
||||
exit(1);
|
||||
} else {
|
||||
var sacs = responses.Body;
|
||||
|
|
@ -2396,8 +2418,8 @@ function OnMulticastMessage(msg, rinfo) {
|
|||
// IDER
|
||||
//
|
||||
|
||||
ider = null;
|
||||
iderIdleTimer = null;
|
||||
var ider = null;
|
||||
var iderIdleTimer = null;
|
||||
|
||||
// Perform IDER
|
||||
function performIder() {
|
||||
|
|
@ -2570,6 +2592,7 @@ function performAmtWifiConfig0(state, args) {
|
|||
}
|
||||
|
||||
function performAmtWifiConfig1(stack, name, response, status, args) {
|
||||
if (status == 600) { console.log('Unable to login, check that Intel AMT password is correct.'); exit(1); return; }
|
||||
if (status == 200) {
|
||||
var wifiAuthMethod = { 1: "Other", 2: "Open", 3: "Shared Key", 4: "WPA PSK", 5: "WPA 802.1x", 6: "WPA2 PSK", 7: "WPA2 802.1x", 32768: "WPA3 802.1x" };
|
||||
var wifiEncMethod = { 1: "Other", 2: "WEP", 3: "TKIP", 4: "CCMP", 5: "None" }
|
||||
|
|
@ -2581,17 +2604,7 @@ function performAmtWifiConfig1(stack, name, response, status, args) {
|
|||
}
|
||||
|
||||
if (args) {
|
||||
if (args.list) {
|
||||
console.log('List of Intel AMT Wifi profiles:');
|
||||
if (wifiProfiles.length == 0) {
|
||||
console.log('No Wifi profiles is stored.');
|
||||
}
|
||||
for (var t in wifiProfiles) {
|
||||
var w = wifiProfiles[t];
|
||||
console.log('Profile Name: ' + t + '; Priority: ' + w['Priority'] + '; SSID: ' + w['SSID'] + '; Security: ' + wifiAuthMethod[w['AuthenticationMethod']] + '/' + wifiEncMethod[w['EncryptionMethod']]);
|
||||
}
|
||||
exit(0);
|
||||
} else if (args.add) {
|
||||
if (args.add) {
|
||||
if (args.auth == null) { args.auth = 6; } // if not set, default to WPA2 PSK
|
||||
if (args.enc == null) { args.enc = 3; } // if not set, default to TKIP
|
||||
if (args.priority == null) { args.priority = 0; } // if not set, default to 0
|
||||
|
|
@ -2637,6 +2650,16 @@ function performAmtWifiConfig1(stack, name, response, status, args) {
|
|||
exit(0);
|
||||
},
|
||||
0, 1);
|
||||
} else {
|
||||
console.log('List of Intel AMT Wifi profiles:');
|
||||
var wikiProfileCount = 0;
|
||||
for (var t in wifiProfiles) {
|
||||
var w = wifiProfiles[t];
|
||||
console.log('Profile Name: ' + t + '; Priority: ' + w['Priority'] + '; SSID: ' + w['SSID'] + '; Security: ' + wifiAuthMethod[w['AuthenticationMethod']] + '/' + wifiEncMethod[w['EncryptionMethod']]);
|
||||
wikiProfileCount++;
|
||||
}
|
||||
if (wikiProfileCount == 0) { console.log(' (No Wifi profiles stored)'); }
|
||||
exit(0);
|
||||
}
|
||||
} else {
|
||||
exit(0);
|
||||
|
|
@ -2970,6 +2993,51 @@ function makeUefiBootParam(type, data, len) {
|
|||
function IntToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }
|
||||
function ShortToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); }
|
||||
|
||||
|
||||
//
|
||||
// Intel AMT Serial-over-LAN
|
||||
//
|
||||
|
||||
var sol = null;
|
||||
|
||||
// Called to start serial-over-lan terminal
|
||||
function performAmtTerm(args) {
|
||||
try {
|
||||
sol = require('amt-redir-duk')(require('amt-sol')());
|
||||
sol.onStateChanged = onSolStateChange;
|
||||
sol.m.onData = onSolData;
|
||||
sol.m.debug = (settings.debuglevel > 0);
|
||||
sol.Start(settings.hostname, (settings.tls == true) ? 16995 : 16994, settings.username ? 'admin' : settings.username, settings.password, settings.tls);
|
||||
} catch (ex) { console.log(ex); }
|
||||
}
|
||||
|
||||
// Called when the serial-over-lan connection state changes
|
||||
function onSolStateChange(stack, state) {
|
||||
console.log(["Disconnected", "Connecting...", "Connected...", "Started Serial-over-LAN..."][state]);
|
||||
if (state == 0)
|
||||
{
|
||||
console.echo = true; // This enables local echo to the console when keys are pressed
|
||||
console.canonical = true; // This puts the console into canonical mode, which means stdin will not process each key press individually, instead it will process line by line.
|
||||
exit(0);
|
||||
}
|
||||
if (state == 3)
|
||||
{
|
||||
console.echo = false; // This disables local echo to the console when keys are pressed
|
||||
console.canonical = false; // This takes the console out of canonical mode, which means stdin will process each key press individually, instead of by line.
|
||||
process.stdin.on('data', function (c) { sol.m.Send(c); });
|
||||
}
|
||||
else
|
||||
{
|
||||
// Serial-over-LAN is not active, stop any stdin key capture
|
||||
console.echo = true; // This enables local echo to the console when keys are pressed
|
||||
console.canonical = true; // This puts the console into canonical mode, which means stdin will not process each key press individually, instead it will process line by line.
|
||||
}
|
||||
}
|
||||
|
||||
// This is called when serial-over-lan data come in from Intel AMT
|
||||
function onSolData(stack, data) { process.stdout.write(data); }
|
||||
|
||||
|
||||
//
|
||||
// Intel AMT feature configuration action
|
||||
//
|
||||
|
|
|
|||
2439
agents/meshcore.js
2439
agents/meshcore.js
File diff suppressed because it is too large
Load diff
|
|
@ -103,14 +103,13 @@ if (msh.agentName) { connectArgs.push('--agentName="' + msh.agentName + '"'); }
|
|||
|
||||
function _install(parms)
|
||||
{
|
||||
var i;
|
||||
var mstr = require('fs').createWriteStream(process.execPath + '.msh', { flags: 'wb' });
|
||||
mstr.write('MeshName=' + msh.MeshName + '\n');
|
||||
mstr.write('MeshType=' + msh.MeshType + '\n');
|
||||
mstr.write('MeshID=' + msh.MeshID + '\n');
|
||||
mstr.write('ServerID=' + msh.ServerID + '\n');
|
||||
mstr.write('MeshServer=' + msh.MeshServer + '\n');
|
||||
if (msh.agentName) { mstr.write('agentName=' + msh.agentName + '\n'); }
|
||||
if (msh.meshServiceName) { mstr.write('meshServiceName=' + msh.meshServiceName + '\n'); }
|
||||
|
||||
for (i in msh)
|
||||
{
|
||||
mstr.write(i + '=' + msh[i] + '\n');
|
||||
}
|
||||
mstr.end();
|
||||
|
||||
if (parms == null) { parms = []; }
|
||||
|
|
@ -156,7 +155,7 @@ if (process.argv.includes('-translations'))
|
|||
console.log(JSON.stringify(translation));
|
||||
process.exit();
|
||||
}
|
||||
if (process.argv.includes('-help'))
|
||||
if (process.argv.includes('-help') || (process.platform == 'linux' && process.env['XAUTHORITY'] == null && process.env['DISPLAY'] == null && process.argv.length == 1))
|
||||
{
|
||||
console.log("\n" + translation[lang].commands + ": ");
|
||||
if ((msh.InstallFlags & 1) == 1)
|
||||
|
|
@ -221,9 +220,7 @@ if ((!skip) && ((msh.InstallFlags & 2) == 2))
|
|||
}
|
||||
}
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
if (process.platform != 'darwin')
|
||||
if (!skip)
|
||||
{
|
||||
if (process.argv.includes('-install') || process.argv.includes('-update'))
|
||||
{
|
||||
|
|
@ -234,6 +231,10 @@ if (!skip)
|
|||
{
|
||||
p.push('--installPath="' + process.argv[i].split('=').pop() + '"');
|
||||
}
|
||||
else if(process.argv[i].startsWith('--'))
|
||||
{
|
||||
p.push(process.argv[i]);
|
||||
}
|
||||
}
|
||||
_install(p);
|
||||
process.exit();
|
||||
|
|
@ -271,12 +272,11 @@ if (!skip)
|
|||
process.exit();
|
||||
}
|
||||
}
|
||||
if (process.platform == 'darwin')
|
||||
{
|
||||
if (!require('user-sessions').isRoot()) { console.log('\n' + translation[lang].elevation); process.exit(); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!require('user-sessions').isRoot()) { console.log('\n' + translation[lang].elevation); process.exit(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!skip)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ module.exports = function CreateAmtRemoteIder() {
|
|||
var IDE_ModeSence_Ls120Error_Recovery_Array = new Buffer([0x00, 0x12, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]);
|
||||
var IDE_ModeSence_CDError_Recovery_Array = new Buffer([0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00]);
|
||||
|
||||
// CD info and performance
|
||||
var RD_CD_DiskInfo = new Buffer([0x00, 0x20, 0x0e, 0x01, 0x01, 0x01, 0x01, 0x20, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
var RD_CD_Performance = new Buffer([0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00]);
|
||||
|
||||
// Private method, called by parent when it change state
|
||||
obj.xxStateChange = function (newstate) {
|
||||
|
|
@ -95,7 +98,7 @@ module.exports = function CreateAmtRemoteIder() {
|
|||
// Private method
|
||||
obj.ProcessData = function (data) {
|
||||
obj.bytesFromAmt += data.length;
|
||||
if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat(obj.acc, data); }
|
||||
if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat([obj.acc, data]); }
|
||||
if (obj.debug) console.log('IDER-ProcessData', obj.acc.length, obj.acc.toString('hex'));
|
||||
|
||||
// Process as many commands as possible
|
||||
|
|
@ -528,6 +531,12 @@ module.exports = function CreateAmtRemoteIder() {
|
|||
obj.SendDataToHost(dev, true, r, featureRegister & 1);
|
||||
}
|
||||
break;
|
||||
case 0x51: // READ_DISK_INFORMATION
|
||||
obj.SendDataToHost(dev, true, RD_CD_DiskInfo, featureRegister & 1);
|
||||
break;
|
||||
case 0xAC: // GET_PERFORMANCE
|
||||
obj.SendDataToHost(dev, true, RD_CD_Performance, featureRegister & 1);
|
||||
break;
|
||||
default: // UNKNOWN COMMAND
|
||||
if (obj.debug) console.log("IDER: Unknown SCSI command", cdb[0]);
|
||||
obj.SendCommandEndResponse(0, 0x05, dev, 0x20, 0x00);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER
|
||||
obj.xtlsoptions = null;
|
||||
|
||||
obj.amtaccumulator = null;
|
||||
obj.amtaccumulator = Buffer.alloc(0);
|
||||
obj.amtsequence = 1;
|
||||
obj.amtkeepalivetimer = null;
|
||||
obj.authuri = "/RedirectionService";
|
||||
obj.authuri = '/RedirectionService';
|
||||
obj.digestRealmMatch = null;
|
||||
|
||||
obj.onStateChanged = null;
|
||||
|
|
@ -80,7 +80,7 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
}
|
||||
*/
|
||||
|
||||
if (urlvars && urlvars['redirtrace']) { console.log("REDIR-CONNECTED"); }
|
||||
if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CONNECTED'); }
|
||||
//obj.Debug("Socket Connected");
|
||||
obj.xxStateChange(2);
|
||||
if (obj.protocol == 1) obj.xxSend(obj.RedirectStartSol); // TODO: Put these strings in higher level module to tighten code
|
||||
|
|
@ -89,14 +89,14 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
}
|
||||
|
||||
obj.xxOnSocketData = function (data) {
|
||||
//console.log('xxOnSocketData: ' + data.toString('hex'), data.length);
|
||||
if (!data || obj.connectstate == -1) return;
|
||||
if (urlvars && urlvars['redirtrace']) { console.log("REDIR-RECV(" + data.length + "): " + data.toString('hex')); }
|
||||
if (urlvars && urlvars['redirtrace']) { console.log('REDIR-RECV(' + data.length + '): ' + data.toString('hex')); }
|
||||
//obj.Debug("Recv(" + data.length + "): " + rstr2hex(data));
|
||||
if ((obj.protocol == 2 || obj.protocol == 3) && obj.connectstate == 1) { return obj.m.ProcessData(data); } // KVM or IDER traffic, forward it directly.
|
||||
if (obj.amtaccumulator == null) { obj.amtaccumulator = data; } else { obj.amtaccumulator = Buffer.concat(obj.amtaccumulator, data); }
|
||||
//obj.Debug("Recv(" + obj.amtaccumulator.length + "): " + rstr2hex(obj.amtaccumulator));
|
||||
while (obj.amtaccumulator != null) {
|
||||
obj.amtaccumulator = Buffer.concat([obj.amtaccumulator, data]);
|
||||
//obj.Debug("Recv(" + obj.amtaccumulator.length + "): " + obj.amtaccumulator.toString('hex'));
|
||||
|
||||
while (obj.amtaccumulator.length > 0) {
|
||||
var cmdsize = 0;
|
||||
//console.log('CMD: ' + obj.amtaccumulator[0]);
|
||||
switch (obj.amtaccumulator[0]) {
|
||||
|
|
@ -170,9 +170,9 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
qoplen = authDataBuf[curptr];
|
||||
qop = authDataBuf.slice(curptr + 1, curptr + 1 + qoplen).toString();
|
||||
curptr += (qoplen + 1);
|
||||
extra = snc + ":" + cnonce + ":" + qop + ":";
|
||||
extra = snc + ':' + cnonce + ':' + qop + ':';
|
||||
}
|
||||
var digest = hex_md5(hex_md5(obj.user + ":" + realm + ":" + obj.pass) + ":" + nonce + ":" + extra + hex_md5("POST:" + obj.authuri));
|
||||
var digest = hex_md5(hex_md5(obj.user + ':' + realm + ':' + obj.pass) + ':' + nonce + ':' + extra + hex_md5('POST:' + obj.authuri));
|
||||
var totallen = obj.user.length + realm.length + nonce.length + obj.authuri.length + cnonce.length + snc.length + digest.length + 7;
|
||||
if (authType == 4) totallen += (qop.length + 1);
|
||||
var buf = Buffer.concat([new Buffer([0x13, 0x00, 0x00, 0x00, authType]), new Buffer([totallen & 0xFF, (totallen >> 8) & 0xFF, 0x00, 0x00]), new Buffer([obj.user.length]), new Buffer(obj.user), new Buffer([realm.length]), new Buffer(realm), new Buffer([nonce.length]), new Buffer(nonce), new Buffer([obj.authuri.length]), new Buffer(obj.authuri), new Buffer([cnonce.length]), new Buffer(cnonce), new Buffer([snc.length]), new Buffer(snc), new Buffer([digest.length]), new Buffer(digest)]);
|
||||
|
|
@ -181,7 +181,6 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
}
|
||||
else if (status == 0) { // Success
|
||||
if (obj.protocol == 1) {
|
||||
/*
|
||||
// Serial-over-LAN: Send Intel AMT serial settings...
|
||||
var MaxTxBuffer = 10000;
|
||||
var TxTimeout = 100;
|
||||
|
|
@ -190,7 +189,6 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
var RxFlushTimeout = 100;
|
||||
var Heartbeat = 0;//5000;
|
||||
obj.xxSend(String.fromCharCode(0x20, 0x00, 0x00, 0x00) + ToIntStr(obj.amtsequence++) + ToShortStr(MaxTxBuffer) + ToShortStr(TxTimeout) + ToShortStr(TxOverflowTimeout) + ToShortStr(RxTimeout) + ToShortStr(RxFlushTimeout) + ToShortStr(Heartbeat) + ToIntStr(0));
|
||||
*/
|
||||
}
|
||||
if (obj.protocol == 2) {
|
||||
// Remote Desktop: Send traffic directly...
|
||||
|
|
@ -219,7 +217,7 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
if (obj.amtaccumulator.length < 10) break;
|
||||
var cs = (10 + ((obj.amtaccumulator[9] & 0xFF) << 8) + (obj.amtaccumulator[8] & 0xFF));
|
||||
if (obj.amtaccumulator.length < cs) break;
|
||||
obj.m.ProcessData(obj.amtaccumulator.substring(10, cs));
|
||||
obj.m.ProcessData(obj.amtaccumulator.slice(10, cs));
|
||||
cmdsize = cs;
|
||||
break;
|
||||
case 0x2B: // Keep alive message (43)
|
||||
|
|
@ -235,21 +233,22 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
cmdsize = obj.amtaccumulator.length;
|
||||
break;
|
||||
default:
|
||||
console.log("Unknown Intel AMT command: " + obj.amtaccumulator[0] + " acclen=" + obj.amtaccumulator.length);
|
||||
console.log('Unknown Intel AMT command: ' + obj.amtaccumulator[0] + ' acclen=' + obj.amtaccumulator.length);
|
||||
obj.Stop();
|
||||
return;
|
||||
}
|
||||
if (cmdsize == 0) return;
|
||||
if (cmdsize == obj.amtaccumulator.length) { obj.amtaccumulator = null; } else { obj.amtaccumulator = obj.amtaccumulator.slice(cmdsize); }
|
||||
obj.amtaccumulator = obj.amtaccumulator.slice(cmdsize);
|
||||
}
|
||||
}
|
||||
|
||||
obj.xxSend = function (x) {
|
||||
if (urlvars && urlvars['redirtrace']) { console.log("REDIR-SEND(" + x.length + "): " + rstr2hex(x)); }
|
||||
//obj.Debug("Send(" + x.length + "): " + Buffer.from(x, "binary").toString('hex'));
|
||||
if (typeof x == 'string') { obj.socket.write(Buffer.from(x, "binary")); } else { obj.socket.write(x); }
|
||||
if (urlvars && urlvars['redirtrace']) { console.log('REDIR-SEND(' + x.length + '): ' + rstr2hex(x)); }
|
||||
//obj.Debug('Send(' + x.length + '): ' + Buffer.from(x, 'binary').toString('hex'));
|
||||
if (typeof x == 'string') { obj.socket.write(Buffer.from(x, 'binary')); } else { obj.socket.write(x); }
|
||||
}
|
||||
|
||||
// Send Serial-over-LAN ASCII characters
|
||||
obj.Send = function (x) {
|
||||
if (obj.socket == null || obj.connectstate != 1) return;
|
||||
if (obj.protocol == 1) { obj.xxSend(String.fromCharCode(0x28, 0x00, 0x00, 0x00) + ToIntStr(obj.amtsequence++) + ToShortStr(x.length) + x); } else { obj.xxSend(x); }
|
||||
|
|
@ -263,14 +262,14 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
// Uses OpenSSL random to generate a hex string
|
||||
obj.xxRandomValueHex = function (len) {
|
||||
var t = [], l = Math.floor(len / 2);
|
||||
for (var i = 0; i < l; i++) { t.push(obj.tls.generateRandomInteger("0", "255")); }
|
||||
for (var i = 0; i < l; i++) { t.push(obj.tls.generateRandomInteger('0', '255')); }
|
||||
return new Buffer(t).toString('hex');
|
||||
}
|
||||
|
||||
obj.xxOnSocketClosed = function () {
|
||||
obj.socket = null;
|
||||
if (urlvars && urlvars['redirtrace']) { console.log("REDIR-CLOSED"); }
|
||||
//obj.Debug("Socket Closed");
|
||||
if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CLOSED'); }
|
||||
//obj.Debug('Socket Closed');
|
||||
obj.Stop();
|
||||
}
|
||||
|
||||
|
|
@ -282,11 +281,11 @@ module.exports = function CreateAmtRedirect(module) {
|
|||
}
|
||||
|
||||
obj.Stop = function () {
|
||||
if (urlvars && urlvars['redirtrace']) { console.log("REDIR-CLOSED"); }
|
||||
//obj.Debug("Socket Stopped");
|
||||
if (urlvars && urlvars['redirtrace']) { console.log('REDIR-CLOSED'); }
|
||||
//obj.Debug('Socket Stopped');
|
||||
obj.xxStateChange(0);
|
||||
obj.connectstate = -1;
|
||||
obj.amtaccumulator = "";
|
||||
obj.amtaccumulator = Buffer.alloc(0);
|
||||
if (obj.socket != null) { obj.socket.destroy(); obj.socket = null; }
|
||||
if (obj.amtkeepalivetimer != null) { clearInterval(obj.amtkeepalivetimer); obj.amtkeepalivetimer = null; }
|
||||
}
|
||||
|
|
|
|||
20
agents/modules_meshcmd/amt-sol.js
Normal file
20
agents/modules_meshcmd/amt-sol.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* @description Serial-over-LAN Handling Module
|
||||
* @author Ylian Saint-Hilaire
|
||||
*/
|
||||
|
||||
// meshservice meshcmd.js amtterm --host 192.168.2.186 --pass P@ssw0rd
|
||||
|
||||
// Construct a Intel AMT Serial-over-LAN object
|
||||
module.exports = function CreateAmtRemoteSol() {
|
||||
var obj = {};
|
||||
obj.protocol = 1; // Serial-over-LAN
|
||||
obj.debug = false;
|
||||
obj.onData = null;
|
||||
obj.xxStateChange = function (newstate) { if (obj.debug) console.log('SOL-StateChange', newstate); if (newstate == 0) { obj.Stop(); } if (newstate == 3) { obj.Start(); } }
|
||||
obj.Start = function () { if (obj.debug) { console.log('SOL-Start'); } }
|
||||
obj.Stop = function () { if (obj.debug) { console.log('SOL-Stop'); } }
|
||||
obj.ProcessData = function (data) { if (obj.debug) { console.log('SOL-ProcessData', data); } if (obj.onData) { obj.onData(obj, data); } }
|
||||
obj.Send = function(text) { if (obj.debug) { console.log('SOL-Send', text); } obj.parent.Send(text); }
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/) {
|
|||
//console.log('Request ' + (obj.RequestCount++));
|
||||
if (globalDebugFlags & 1) { console.log('Request ' + (obj.RequestCount++)); } // DEBUG
|
||||
|
||||
req.on('error', function (e) { obj.gotNextMessagesError({ status: 600 }, 'error', null, [postdata, callback, tag]); });
|
||||
req.on('error', function (err) { obj.gotNextMessagesError({ status: 600, error: '' + err }, 'error', null, [postdata, callback, tag]); });
|
||||
req.on('response', function (response) {
|
||||
//console.log(JSON.stringify(response, null, 2));
|
||||
if (globalDebugFlags & 1) { console.log('Response: ' + response.statusCode); }
|
||||
|
|
@ -126,7 +126,7 @@ function CreateWsmanComm(/*host, port, user, pass, tls, extra*/) {
|
|||
if (obj.FailAllError == 999) return;
|
||||
if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
|
||||
//if (status != 200) { console.log("ERROR, status=" + status + "\r\n\r\nreq=" + callArgs[0]); } // Debug: Display the request & response if something did not work.
|
||||
if (obj.FailAllError != 999) { callArgs[1]({ Header: { HttpError: request.status } }, request.status, callArgs[2]); }
|
||||
if (obj.FailAllError != 999) { callArgs[1]({ Header: { HttpError: request.status, error: request.error } }, request.status, callArgs[2]); }
|
||||
obj.PerformNextAjax();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ function WsmanStackCreateService(/*CreateWsmanComm, host, port, user, pass, tls,
|
|||
obj.PerformAjax = function PerformAjax(postdata, callback, tag, pri, namespaces) {
|
||||
if (namespaces == null) namespaces = '';
|
||||
obj.comm.PerformAjax('<?xml version=\"1.0\" encoding=\"utf-8\"?><Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns=\"http://www.w3.org/2003/05/soap-envelope\" ' + namespaces + '><Header><a:Action>' + postdata, function (data, status, tag) {
|
||||
if (status != 200) { callback(obj, null, { Header: { HttpError: status } }, status, tag); return; }
|
||||
if (status != 200) { callback(obj, null, (data != null) ? data : { Header: { HttpError: status } }, status, tag); return; }
|
||||
var wsresponse = obj.xmlParser.ParseWsman(data);
|
||||
if (!wsresponse || wsresponse == null) { callback(obj, null, { Header: { HttpError: status } }, 601, tag); } else { callback(obj, wsresponse.Header["ResourceURI"], wsresponse, 200, tag); }
|
||||
}, tag, pri);
|
||||
|
|
|
|||
|
|
@ -514,60 +514,98 @@ function AmtStackCreateService(wsmanStack) {
|
|||
var _SystemEntityTypes = "Unspecified|Other|Unknown|Processor|Disk|Peripheral|System management module|System board|Memory module|Processor module|Power supply|Add in card|Front panel board|Back panel board|Power system board|Drive backplane|System internal expansion board|Other system board|Processor board|Power unit|Power module|Power management board|Chassis back panel board|System chassis|Sub chassis|Other chassis board|Disk drive bay|Peripheral bay|Device bay|Fan cooling|Cooling unit|Cable interconnect|Memory device|System management software|BIOS|Intel(r) ME|System bus|Group|Intel(r) ME|External environment|Battery|Processing blade|Connectivity switch|Processor/memory module|I/O module|Processor I/O module|Management controller firmware|IPMI channel|PCI bus|PCI express bus|SCSI bus|SATA/SAS bus|Processor front side bus".split('|');
|
||||
obj.RealmNames = "||Redirection|PT Administration|Hardware Asset|Remote Control|Storage|Event Manager|Storage Admin|Agent Presence Local|Agent Presence Remote|Circuit Breaker|Network Time|General Information|Firmware Update|EIT|LocalUN|Endpoint Access Control|Endpoint Access Control Admin|Event Log Reader|Audit Log|ACL Realm|||Local System".split('|');
|
||||
obj.WatchdogCurrentStates = { 1: 'Not Started', 2: 'Stopped', 4: 'Running', 8: 'Expired', 16: 'Suspended' };
|
||||
var _OCRProgressEvents = ["Boot parameters received from CSME", "CSME Boot Option % added successfully", "HTTPS URI name resolved", "HTTPS connected successfully", "HTTPSBoot download is completed", "Attempt to boot", "Exit boot services"];
|
||||
var _OCRErrorEvents = ['', "No network connection available", "Name resolution of URI failed", "Connect to URI failed", "OEM app not found at local URI", "HTTPS TLS Auth failed", "HTTPS Digest Auth failed", "Verified boot failed (bad image)", "HTTPS Boot File not found"];
|
||||
var _OCRSource = { 1: '', 2: "HTTPS", 4: "Local PBA", 8: "WinRE" };
|
||||
|
||||
function _GetEventDetailStr(eventSensorType, eventOffset, eventDataField, entity) {
|
||||
|
||||
if (eventSensorType == 15)
|
||||
{
|
||||
if (eventSensorType == 15) {
|
||||
if (eventDataField[0] == 235) return "Invalid Data";
|
||||
if (eventOffset == 0) return _SystemFirmwareError[eventDataField[1]];
|
||||
return _SystemFirmwareProgress[eventDataField[1]];
|
||||
if (eventOffset == 0) {
|
||||
return _SystemFirmwareError[eventDataField[1]];
|
||||
} else if (eventOffset == 3) {
|
||||
if ((eventDataField[0] == 170) && (eventDataField[1] == 48)) {
|
||||
return format("One Click Recovery: {0}", _OCRErrorEvents[eventDataField[2]]);
|
||||
} else if ((eventDataField[0] == 170) && (eventDataField[1] == 64)) {
|
||||
if (eventDataField[2] == 1) return "Got an error erasing Device SSD";
|
||||
if (eventDataField[2] == 2) return "Erasing Device TPM is not supported";
|
||||
if (eventDataField[2] == 3) return "Reached Max Counter";
|
||||
} else {
|
||||
return "OEM Specific Firmware Error event";
|
||||
}
|
||||
} else if (eventOffset == 5) {
|
||||
if ((eventDataField[0] == 170) && (eventDataField[1] == 48)) {
|
||||
if (eventDataField[2] == 1) {
|
||||
return format("One Click Recovery: CSME Boot Option {0}:{1} added successfully", (eventDataField[3]), _OCRSource[(eventDataField[3])]);
|
||||
} else if (eventDataField[2] < 7) {
|
||||
return format("One Click Recovery: {0}", _OCRProgressEvents[eventDataField[2]]);
|
||||
} else {
|
||||
return format("One Click Recovery: Unknown progress event {0}", eventDataField[2]);
|
||||
}
|
||||
} else if ((eventDataField[0] == 170) && (eventDataField[1] == 64)) {
|
||||
if (eventDataField[2] == 1) {
|
||||
if (eventDataField[3] == 2) return "Started erasing Device SSD";
|
||||
if (eventDataField[3] == 3) return "Started erasing Device TPM";
|
||||
if (eventDataField[3] == 5) return "Started erasing Device BIOS Reload of Golden Config";
|
||||
}
|
||||
if (eventDataField[2] == 2) {
|
||||
if (eventDataField[3] == 2) return "Erasing Device SSD ended successfully";
|
||||
if (eventDataField[3] == 3) return "Erasing Device TPM ended successfully";
|
||||
if (eventDataField[3] == 5) return "Erasing Device BIOS Reload of Golden Config ended successfully";
|
||||
}
|
||||
if (eventDataField[2] == 3) return "Beginning Platform Erase";
|
||||
if (eventDataField[2] == 4) return "Clear Reserved Parameters";
|
||||
if (eventDataField[2] == 5) return "All setting decremented";
|
||||
} else {
|
||||
return "OEM Specific Firmware Progress event";
|
||||
}
|
||||
} else {
|
||||
return _SystemFirmwareProgress[eventDataField[1]];
|
||||
}
|
||||
}
|
||||
|
||||
if (eventSensorType == 18 && eventDataField[0] == 170) // System watchdog event
|
||||
if ((eventSensorType == 18) && (eventDataField[0] == 170)) // System watchdog event
|
||||
{
|
||||
return "Agent watchdog " + char2hex(eventDataField[4]) + char2hex(eventDataField[3]) + char2hex(eventDataField[2]) + char2hex(eventDataField[1]) + "-" + char2hex(eventDataField[6]) + char2hex(eventDataField[5]) + "-... changed to " + obj.WatchdogCurrentStates[eventDataField[7]];
|
||||
}
|
||||
|
||||
//if (eventSensorType == 5 && eventOffset == 0) // System chassis
|
||||
//{
|
||||
// return "Case intrusion";
|
||||
//}
|
||||
if ((eventSensorType == 5) && (eventOffset == 0)) // System chassis
|
||||
{
|
||||
return "Case intrusion";
|
||||
}
|
||||
|
||||
//if (eventSensorType == 192 && eventOffset == 0 && eventDataField[0] == 170 && eventDataField[1] == 48)
|
||||
//{
|
||||
// if (eventDataField[2] == 0) return "A remote Serial Over LAN session was established.";
|
||||
// if (eventDataField[2] == 1) return "Remote Serial Over LAN session finished. User control was restored.";
|
||||
// if (eventDataField[2] == 2) return "A remote IDE-Redirection session was established.";
|
||||
// if (eventDataField[2] == 3) return "Remote IDE-Redirection session finished. User control was restored.";
|
||||
//}
|
||||
if ((eventSensorType == 192) && (eventOffset == 0) && (eventDataField[0] == 170) && (eventDataField[1] == 48))
|
||||
{
|
||||
if (eventDataField[2] == 0) return "A remote Serial Over LAN session was established.";
|
||||
if (eventDataField[2] == 1) return "Remote Serial Over LAN session finished. User control was restored.";
|
||||
if (eventDataField[2] == 2) return "A remote IDE-Redirection session was established.";
|
||||
if (eventDataField[2] == 3) return "Remote IDE-Redirection session finished. User control was restored.";
|
||||
}
|
||||
|
||||
//if (eventSensorType == 36)
|
||||
//{
|
||||
// long handle = ((long)(eventDataField[1]) << 24) + ((long)(eventDataField[2]) << 16) + ((long)(eventDataField[3]) << 8) + (long)(eventDataField[4]);
|
||||
// string nic = string.Format("#{0}", eventDataField[0]);
|
||||
// if (eventDataField[0] == 0xAA) nic = "wired"; // TODO: Add wireless *****
|
||||
// //if (eventDataField[0] == 0xAA) nic = "wireless";
|
||||
if (eventSensorType == 36)
|
||||
{
|
||||
var handle = (eventDataField[1] << 24) + (eventDataField[2] << 16) + (eventDataField[3] << 8) + eventDataField[4];
|
||||
var nic = '#' + eventDataField[0];
|
||||
if (eventDataField[0] == 0xAA) nic = "wired"; // TODO: Add wireless *****
|
||||
//if (eventDataField[0] == 0xAA) nic = "wireless";
|
||||
|
||||
// if (handle == 4294967293) { return string.Format("All received packet filter was matched on {0} interface.", nic); }
|
||||
// if (handle == 4294967292) { return string.Format("All outbound packet filter was matched on {0} interface.", nic); }
|
||||
// if (handle == 4294967290) { return string.Format("Spoofed packet filter was matched on {0} interface.", nic); }
|
||||
// return string.Format("Filter {0} was matched on {1} interface.", handle, nic);
|
||||
//}
|
||||
if (handle == 4294967293) { return "All received packet filter was matched on " + nic + " interface."; }
|
||||
if (handle == 4294967292) { return "All outbound packet filter was matched on " + nic + " interface."; }
|
||||
if (handle == 4294967290) { return "Spoofed packet filter was matched on " + nic + " interface."; }
|
||||
return "Filter " + handle + " was matched on " + nic + " interface.";
|
||||
}
|
||||
|
||||
//if (eventSensorType == 192)
|
||||
//{
|
||||
// if (eventDataField[2] == 0) return "Security policy invoked. Some or all network traffic (TX) was stopped.";
|
||||
// if (eventDataField[2] == 2) return "Security policy invoked. Some or all network traffic (RX) was stopped.";
|
||||
// return "Security policy invoked.";
|
||||
//}
|
||||
if (eventSensorType == 192) {
|
||||
if (eventDataField[2] == 0) return "Security policy invoked. Some or all network traffic (TX) was stopped.";
|
||||
if (eventDataField[2] == 2) return "Security policy invoked. Some or all network traffic (RX) was stopped.";
|
||||
return "Security policy invoked.";
|
||||
}
|
||||
|
||||
//if (eventSensorType == 193)
|
||||
//{
|
||||
// if (eventDataField[0] == 0xAA && eventDataField[1] == 0x30 && eventDataField[2] == 0x00 && eventDataField[3] == 0x00) { return "User request for remote connection."; }
|
||||
// if (eventDataField[0] == 0xAA && eventDataField[1] == 0x20 && eventDataField[2] == 0x03 && eventDataField[3] == 0x01) { return "EAC error: attempt to get posture while NAC in Intel(r) AMT is disabled."; // eventDataField = 0xAA20030100000000 }
|
||||
// if (eventDataField[0] == 0xAA && eventDataField[1] == 0x20 && eventDataField[2] == 0x04 && eventDataField[3] == 0x00) { return "Certificate revoked. "; }
|
||||
//}
|
||||
if (eventSensorType == 193) {
|
||||
if ((eventDataField[0] == 0xAA) && (eventDataField[1] == 0x30) && (eventDataField[2] == 0x00) && (eventDataField[3] == 0x00)) { return "User request for remote connection."; }
|
||||
if ((eventDataField[0] == 0xAA) && (eventDataField[1] == 0x20) && (eventDataField[2] == 0x03) && (eventDataField[3] == 0x01)) { return "EAC error: attempt to get posture while NAC in Intel(r) AMT is disabled."; } // eventDataField = 0xAA20030100000000
|
||||
if ((eventDataField[0] == 0xAA) && (eventDataField[1] == 0x20) && (eventDataField[2] == 0x04) && (eventDataField[3] == 0x00)) { return "Certificate revoked. "; }
|
||||
}
|
||||
|
||||
if (eventSensorType == 6) return "Authentication failed " + (eventDataField[1] + (eventDataField[2] << 8)) + " times. The system may be under attack.";
|
||||
if (eventSensorType == 30) return "No bootable media";
|
||||
|
|
@ -671,9 +709,12 @@ function AmtStackCreateService(wsmanStack) {
|
|||
2600: 'Agent Watchdog Added',
|
||||
2601: 'Agent Watchdog Removed',
|
||||
2602: 'Agent Watchdog Action Set',
|
||||
2700: 'Wireless Profile Added',
|
||||
2701: 'Wireless Profile Removed',
|
||||
2702: 'Wireless Profile Updated',
|
||||
2700: "Wireless Profile Added",
|
||||
2701: "Wireless Profile Removed",
|
||||
2702: "Wireless Profile Updated",
|
||||
2703: "An existing profile sync was modified",
|
||||
2704: "An existing profile link preference was changed",
|
||||
2705: "Wireless profile share with UEFI enabled setting was changed",
|
||||
2800: 'EAC Posture Signer SET',
|
||||
2801: 'EAC Enabled',
|
||||
2802: 'EAC Disabled',
|
||||
|
|
@ -772,7 +813,6 @@ function AmtStackCreateService(wsmanStack) {
|
|||
// Read network access
|
||||
x['MCLocationType'] = e[ptr++];
|
||||
var netlen = e[ptr++];
|
||||
|
||||
x['NetAddress'] = e.slice(ptr, ptr + netlen).toString();
|
||||
|
||||
// Read extended data
|
||||
|
|
@ -987,8 +1027,8 @@ function AmtStackCreateService(wsmanStack) {
|
|||
|
||||
// Convert a byte array of SID into string
|
||||
function GetSidString(sid) {
|
||||
var r = "S-" + sid.charCodeAt(0) + "-" + sid.charCodeAt(7);
|
||||
for (var i = 2; i < (sid.length / 4); i++) r += "-" + ReadIntX(sid, i * 4);
|
||||
var r = 'S-' + sid[0] + '-' + sid[7];
|
||||
for (var i = 2; i < (sid.length / 4); i++) r += '-' + ReadIntX(sid, i * 4);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -269,15 +269,18 @@ function SMBiosTables()
|
|||
this.amtInfo = function amtInfo(data) {
|
||||
if (!data) { throw ('no data'); }
|
||||
var retVal = { AMT: false };
|
||||
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT') {
|
||||
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT')
|
||||
{
|
||||
var amt = data[130].peek();
|
||||
retVal.AMT = amt[4] ? true : false;
|
||||
if (retVal.AMT) {
|
||||
if (retVal.AMT)
|
||||
{
|
||||
retVal.enabled = amt[5] ? true : false;
|
||||
retVal.storageRedirection = amt[6] ? true : false;
|
||||
retVal.serialOverLan = amt[7] ? true : false;
|
||||
retVal.kvm = amt[14] ? true : false;
|
||||
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro') {
|
||||
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
|
||||
{
|
||||
var settings = data[131].peek();
|
||||
if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
|
||||
if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
|
||||
|
|
@ -295,6 +298,14 @@ function SMBiosTables()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!retVal.AMT)
|
||||
{
|
||||
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
|
||||
{
|
||||
var settings = data[131].peek();
|
||||
if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
|
||||
}
|
||||
}
|
||||
return (retVal);
|
||||
};
|
||||
this.smTableTypes = {
|
||||
|
|
|
|||
|
|
@ -225,19 +225,14 @@ function macos_memUtilization()
|
|||
function windows_thermals()
|
||||
{
|
||||
var ret = [];
|
||||
child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', '/namespace:\\\\root\\wmi', 'PATH', 'MSAcpi_ThermalZoneTemperature', 'get', 'CurrentTemperature']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.waitExit();
|
||||
|
||||
if(child.stdout.str.trim!='')
|
||||
{
|
||||
var lines = child.stdout.str.trim().split('\r\n');
|
||||
for (var i = 1; i < lines.length; ++i)
|
||||
{
|
||||
if (lines[i].trim() != '') { ret.push(((parseFloat(lines[i]) / 10) - 273.15).toFixed(2)); }
|
||||
try {
|
||||
ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']);
|
||||
if (ret[0]) {
|
||||
for (var i = 0; i < ret.length; ++i) {
|
||||
ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) { }
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
|
@ -285,16 +280,10 @@ function macos_thermals()
|
|||
return (ret);
|
||||
}
|
||||
|
||||
switch(process.platform)
|
||||
{
|
||||
case 'linux':
|
||||
module.exports = { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals };
|
||||
break;
|
||||
case 'win32':
|
||||
module.exports = { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals };
|
||||
break;
|
||||
case 'darwin':
|
||||
module.exports = { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals };
|
||||
break;
|
||||
}
|
||||
const platformConfig = {
|
||||
linux: { cpuUtilization: linux_cpuUtilization, memUtilization: linux_memUtilization, thermals: linux_thermals },
|
||||
win32: { cpuUtilization: windows_cpuUtilization, memUtilization: windows_memUtilization, thermals: windows_thermals },
|
||||
darwin: { cpuUtilization: macos_cpuUtilization, memUtilization: macos_memUtilization, thermals: macos_thermals }
|
||||
};
|
||||
|
||||
module.exports = platformConfig[process.platform];
|
||||
|
|
|
|||
902
agents/modules_meshcore/computer-identifiers.js
Normal file
902
agents/modules_meshcore/computer-identifiers.js
Normal file
|
|
@ -0,0 +1,902 @@
|
|||
/*
|
||||
Copyright 2019-2021 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
function trimIdentifiers(val)
|
||||
{
|
||||
for(var v in val)
|
||||
{
|
||||
if (!val[v] || val[v] == 'None' || val[v] == '') { delete val[v]; }
|
||||
}
|
||||
}
|
||||
function trimResults(val)
|
||||
{
|
||||
var i, x;
|
||||
for (i = 0; i < val.length; ++i)
|
||||
{
|
||||
for (x in val[i])
|
||||
{
|
||||
if (x.startsWith('_'))
|
||||
{
|
||||
delete val[i][x];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val[i][x] == null || val[i][x] == 0)
|
||||
{
|
||||
delete val[i][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function brief(headers, obj)
|
||||
{
|
||||
var i, x;
|
||||
for (x = 0; x < obj.length; ++x)
|
||||
{
|
||||
for (i in obj[x])
|
||||
{
|
||||
if (!headers.includes(i))
|
||||
{
|
||||
delete obj[x][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return (obj);
|
||||
}
|
||||
|
||||
function dataHandler(c)
|
||||
{
|
||||
this.str += c.toString();
|
||||
}
|
||||
|
||||
function linux_identifiers()
|
||||
{
|
||||
var identifiers = {};
|
||||
var ret = {};
|
||||
var values = {};
|
||||
|
||||
if (!require('fs').existsSync('/sys/class/dmi/id')) {
|
||||
if (require('fs').existsSync('/sys/firmware/devicetree/base/model')) {
|
||||
if (require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim().startsWith('Raspberry')) {
|
||||
identifiers['board_vendor'] = 'Raspberry Pi';
|
||||
identifiers['board_name'] = require('fs').readFileSync('/sys/firmware/devicetree/base/model').toString().trim();
|
||||
identifiers['board_serial'] = require('fs').readFileSync('/sys/firmware/devicetree/base/serial-number').toString().trim();
|
||||
const memorySlots = [];
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write('vcgencmd get_mem arm && vcgencmd get_mem gpu\nexit\n');
|
||||
child.waitExit();
|
||||
try {
|
||||
const lines = child.stdout.str.trim().split('\n');
|
||||
if (lines.length == 2) {
|
||||
memorySlots.push({ Locator: "ARM Memory", Size: lines[0].split('=')[1].trim() })
|
||||
memorySlots.push({ Locator: "GPU Memory", Size: lines[1].split('=')[1].trim() })
|
||||
ret.memory = { Memory_Device: memorySlots };
|
||||
}
|
||||
} catch (xx) { }
|
||||
} else {
|
||||
throw('Unknown board');
|
||||
}
|
||||
} else {
|
||||
throw ('this platform does not have DMI statistics');
|
||||
}
|
||||
} else {
|
||||
var entries = require('fs').readdirSync('/sys/class/dmi/id');
|
||||
for (var i in entries) {
|
||||
if (require('fs').statSync('/sys/class/dmi/id/' + entries[i]).isFile()) {
|
||||
try {
|
||||
ret[entries[i]] = require('fs').readFileSync('/sys/class/dmi/id/' + entries[i]).toString().trim();
|
||||
} catch(z) { }
|
||||
if (ret[entries[i]] == 'None') { delete ret[entries[i]]; }
|
||||
}
|
||||
}
|
||||
entries = null;
|
||||
|
||||
identifiers['bios_date'] = ret['bios_date'];
|
||||
identifiers['bios_vendor'] = ret['bios_vendor'];
|
||||
identifiers['bios_version'] = ret['bios_version'];
|
||||
identifiers['bios_serial'] = ret['product_serial'];
|
||||
identifiers['board_name'] = ret['board_name'];
|
||||
identifiers['board_serial'] = ret['board_serial'];
|
||||
identifiers['board_vendor'] = ret['board_vendor'];
|
||||
identifiers['board_version'] = ret['board_version'];
|
||||
identifiers['product_uuid'] = ret['product_uuid'];
|
||||
identifiers['product_name'] = ret['product_name'];
|
||||
}
|
||||
|
||||
try {
|
||||
identifiers['bios_mode'] = (require('fs').statSync('/sys/firmware/efi').isDirectory() ? 'UEFI': 'Legacy');
|
||||
} catch (ex) { identifiers['bios_mode'] = 'Legacy'; }
|
||||
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write('cat /proc/cpuinfo | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n");
|
||||
child.waitExit();
|
||||
identifiers['cpu_name'] = child.stdout.str.trim();
|
||||
if (identifiers['cpu_name'] == "") { // CPU BLANK, check lscpu instead
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write('lscpu | grep -i "model name" | ' + "tr '\\n' ':' | awk -F: '{ print $2 }'\nexit\n");
|
||||
child.waitExit();
|
||||
identifiers['cpu_name'] = child.stdout.str.trim();
|
||||
}
|
||||
child = null;
|
||||
|
||||
|
||||
// Fetch GPU info
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write("lspci | grep ' VGA ' | tr '\\n' '`' | awk '{ a=split($0,lines" + ',"`"); printf "["; for(i=1;i<a;++i) { split(lines[i],gpu,"r: "); printf "%s\\"%s\\"", (i==1?"":","),gpu[2]; } printf "]"; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
try { identifiers['gpu_name'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
|
||||
child = null;
|
||||
|
||||
// Fetch Storage Info
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write("lshw -class disk | tr '\\n' '`' | awk '" + '{ len=split($0,lines,"*"); printf "["; for(i=2;i<=len;++i) { model=""; caption=""; size=""; clen=split(lines[i],item,"`"); for(j=2;j<clen;++j) { split(item[j],tokens,":"); split(tokens[1],key," "); if(key[1]=="description") { caption=substr(tokens[2],2); } if(key[1]=="product") { model=substr(tokens[2],2); } if(key[1]=="size") { size=substr(tokens[2],2); } } if(model=="") { model=caption; } if(caption!="" || model!="") { printf "%s{\\"Caption\\":\\"%s\\",\\"Model\\":\\"%s\\",\\"Size\\":\\"%s\\"}",(i==2?"":","),caption,model,size; } } printf "]"; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
try { identifiers['storage_devices'] = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
|
||||
child = null;
|
||||
|
||||
// Fetch storage volumes using df
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write('df -T | awk \'NR==1 || $1 ~ ".+"{print $3, $4, $5, $7, $2}\' | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $1, $2, $3, $4, $5}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n');
|
||||
child.waitExit();
|
||||
try { ret.volumes = JSON.parse(child.stdout.str.trim()); } catch (xx) { }
|
||||
child = null;
|
||||
|
||||
values.identifiers = identifiers;
|
||||
values.linux = ret;
|
||||
trimIdentifiers(values.identifiers);
|
||||
|
||||
var dmidecode = require('lib-finder').findBinary('dmidecode');
|
||||
if (dmidecode != null)
|
||||
{
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stderr.str = ''; child.stderr.on('data', dataHandler);
|
||||
child.stdin.write(dmidecode + " -t memory | tr '\\n' '`' | ");
|
||||
child.stdin.write(" awk '{ ");
|
||||
child.stdin.write(' printf("[");');
|
||||
child.stdin.write(' comma="";');
|
||||
child.stdin.write(' c=split($0, lines, "``");');
|
||||
child.stdin.write(' for(i=1;i<=c;++i)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' d=split(lines[i], val, "`");');
|
||||
child.stdin.write(' split(val[1], tokens, ",");');
|
||||
child.stdin.write(' split(tokens[2], dmitype, " ");');
|
||||
child.stdin.write(' dmi = dmitype[3]+0; ');
|
||||
child.stdin.write(' if(dmi == 5 || dmi == 6 || dmi == 16 || dmi == 17)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' ccx="";');
|
||||
child.stdin.write(' printf("%s{\\"%s\\": {", comma, val[2]);');
|
||||
child.stdin.write(' for(j=3;j<d;++j)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' sub(/^[ \\t]*/,"",val[j]);');
|
||||
child.stdin.write(' if(split(val[j],tmp,":")>1)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' sub(/^[ \\t]*/,"",tmp[2]);');
|
||||
child.stdin.write(' gsub(/ /,"",tmp[1]);');
|
||||
child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", ccx, tmp[1], tmp[2]);');
|
||||
child.stdin.write(' ccx=",";');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("}}");');
|
||||
child.stdin.write(' comma=",";');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("]");');
|
||||
child.stdin.write("}'\nexit\n");
|
||||
child.waitExit();
|
||||
|
||||
try
|
||||
{
|
||||
var j = JSON.parse(child.stdout.str);
|
||||
var i, key, key2;
|
||||
for (i = 0; i < j.length; ++i)
|
||||
{
|
||||
for (key in j[i])
|
||||
{
|
||||
delete j[i][key]['ArrayHandle'];
|
||||
delete j[i][key]['ErrorInformationHandle'];
|
||||
for (key2 in j[i][key])
|
||||
{
|
||||
if (j[i][key][key2] == 'Unknown' || j[i][key][key2] == 'Not Specified' || j[i][key][key2] == '')
|
||||
{
|
||||
delete j[i][key][key2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(j.length > 0){
|
||||
var mem = {};
|
||||
for (i = 0; i < j.length; ++i)
|
||||
{
|
||||
for (key in j[i])
|
||||
{
|
||||
if (mem[key] == null) { mem[key] = []; }
|
||||
mem[key].push(j[i][key]);
|
||||
}
|
||||
}
|
||||
values.linux.memory = mem;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{ }
|
||||
child = null;
|
||||
}
|
||||
|
||||
var usbdevices = require('lib-finder').findBinary('usb-devices');
|
||||
if (usbdevices != null)
|
||||
{
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stderr.str = ''; child.stderr.on('data', dataHandler);
|
||||
child.stdin.write(usbdevices + " | tr '\\n' '`' | ");
|
||||
child.stdin.write(" awk '");
|
||||
child.stdin.write('{');
|
||||
child.stdin.write(' comma="";');
|
||||
child.stdin.write(' printf("[");');
|
||||
child.stdin.write(' len=split($0, group, "``");');
|
||||
child.stdin.write(' for(i=1;i<=len;++i)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' comma2="";');
|
||||
child.stdin.write(' xlen=split(group[i], line, "`");');
|
||||
child.stdin.write(' scount=0;');
|
||||
child.stdin.write(' for(x=1;x<xlen;++x)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' if(line[x] ~ "^S:")');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' ++scount;');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' if(scount>0)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' printf("%s{", comma); comma=",";');
|
||||
child.stdin.write(' for(x=1;x<xlen;++x)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' if(line[x] ~ "^T:")');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' comma3="";');
|
||||
child.stdin.write(' printf("%s\\"hardware\\": {", comma2); comma2=",";');
|
||||
child.stdin.write(' sub(/^T:[ \\t]*/, "", line[x]);');
|
||||
child.stdin.write(' gsub(/= */, "=", line[x]);');
|
||||
child.stdin.write(' blen=split(line[x], tokens, " ");');
|
||||
child.stdin.write(' for(y=1;y<blen;++y)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' match(tokens[y],/=/);');
|
||||
child.stdin.write(' h=substr(tokens[y],1,RSTART-1);');
|
||||
child.stdin.write(' v=substr(tokens[y],RSTART+1);');
|
||||
child.stdin.write(' sub(/#/, "", h);');
|
||||
child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", comma3, h, v); comma3=",";');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("}");');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' if(line[x] ~ "^S:")');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' sub(/^S:[ \\t]*/, "", line[x]);');
|
||||
child.stdin.write(' match(line[x], /=/);');
|
||||
child.stdin.write(' h=substr(line[x],1,RSTART-1);');
|
||||
child.stdin.write(' v=substr(line[x],RSTART+1);');
|
||||
child.stdin.write(' printf("%s\\"%s\\": \\"%s\\"", comma2, h,v); comma2=",";');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("}");');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("]");');
|
||||
child.stdin.write("}'\nexit\n");
|
||||
child.waitExit();
|
||||
|
||||
try
|
||||
{
|
||||
values.linux.usb = JSON.parse(child.stdout.str);
|
||||
}
|
||||
catch(x)
|
||||
{ }
|
||||
child = null;
|
||||
}
|
||||
|
||||
var pcidevices = require('lib-finder').findBinary('lspci');
|
||||
if (pcidevices != null)
|
||||
{
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stderr.str = ''; child.stderr.on('data', dataHandler);
|
||||
child.stdin.write(pcidevices + " -m | tr '\\n' '`' | ");
|
||||
child.stdin.write(" awk '");
|
||||
child.stdin.write('{');
|
||||
child.stdin.write(' printf("[");');
|
||||
child.stdin.write(' comma="";');
|
||||
child.stdin.write(' alen=split($0, lines, "`");');
|
||||
child.stdin.write(' for(a=1;a<alen;++a)');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' match(lines[a], / /);');
|
||||
child.stdin.write(' blen=split(lines[a], meta, "\\"");');
|
||||
child.stdin.write(' bus=substr(lines[a], 1, RSTART);');
|
||||
child.stdin.write(' gsub(/ /, "", bus);');
|
||||
child.stdin.write(' printf("%s{\\"bus\\": \\"%s\\"", comma, bus); comma=",";');
|
||||
child.stdin.write(' printf(", \\"device\\": \\"%s\\"", meta[2]);');
|
||||
child.stdin.write(' printf(", \\"manufacturer\\": \\"%s\\"", meta[4]);');
|
||||
child.stdin.write(' printf(", \\"description\\": \\"%s\\"", meta[6]);');
|
||||
child.stdin.write(' if(meta[8] != "")');
|
||||
child.stdin.write(' {');
|
||||
child.stdin.write(' printf(", \\"subsystem\\": {");');
|
||||
child.stdin.write(' printf("\\"manufacturer\\": \\"%s\\"", meta[8]);');
|
||||
child.stdin.write(' printf(", \\"description\\": \\"%s\\"", meta[10]);');
|
||||
child.stdin.write(' printf("}");');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("}");');
|
||||
child.stdin.write(' }');
|
||||
child.stdin.write(' printf("]");');
|
||||
child.stdin.write("}'\nexit\n");
|
||||
child.waitExit();
|
||||
|
||||
try
|
||||
{
|
||||
values.linux.pci = JSON.parse(child.stdout.str);
|
||||
}
|
||||
catch (x)
|
||||
{ }
|
||||
child = null;
|
||||
}
|
||||
|
||||
// Linux Last Boot Up Time
|
||||
try {
|
||||
child = require('child_process').execFile('/usr/bin/uptime', ['', '-s']); // must include blank value at begining for some reason?
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.on('data', function () { });
|
||||
child.waitExit();
|
||||
var regex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
|
||||
if (regex.test(child.stdout.str.trim())) {
|
||||
values.linux.LastBootUpTime = child.stdout.str.trim();
|
||||
} else {
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('date -d "@$(( $(date +%s) - $(awk \'{print int($1)}\' /proc/uptime) ))" "+%Y-%m-%d %H:%M:%S"\nexit\n');
|
||||
child.waitExit();
|
||||
if (regex.test(child.stdout.str.trim())) {
|
||||
values.linux.LastBootUpTime = child.stdout.str.trim();
|
||||
}
|
||||
}
|
||||
child = null;
|
||||
} catch (ex) { }
|
||||
|
||||
// Linux TPM
|
||||
try {
|
||||
if (require('fs').statSync('/sys/class/tpm/tpm0').isDirectory()){
|
||||
values.tpm = {
|
||||
SpecVersion: require('fs').readFileSync('/sys/class/tpm/tpm0/tpm_version_major').toString().trim()
|
||||
}
|
||||
}
|
||||
} catch (ex) { }
|
||||
|
||||
return (values);
|
||||
}
|
||||
|
||||
function windows_wmic_results(str)
|
||||
{
|
||||
var lines = str.trim().split('\r\n');
|
||||
var keys = lines[0].split(',');
|
||||
var i, key, keyval;
|
||||
var tokens;
|
||||
var result = [];
|
||||
|
||||
console.log('Lines: ' + lines.length, 'Keys: ' + keys.length);
|
||||
|
||||
for (i = 1; i < lines.length; ++i)
|
||||
{
|
||||
var obj = {};
|
||||
console.log('i: ' + i);
|
||||
tokens = lines[i].split(',');
|
||||
for (key = 0; key < keys.length; ++key)
|
||||
{
|
||||
var tmp = Buffer.from(tokens[key], 'binary').toString();
|
||||
console.log(tokens[key], tmp);
|
||||
tokens[key] = tmp == null ? '' : tmp;
|
||||
if (tokens[key].trim())
|
||||
{
|
||||
obj[keys[key].trim()] = tokens[key].trim();
|
||||
}
|
||||
}
|
||||
delete obj.Node;
|
||||
result.push(obj);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
function windows_identifiers()
|
||||
{
|
||||
var ret = { windows: {} };
|
||||
var items, item, i;
|
||||
|
||||
ret['identifiers'] = {};
|
||||
|
||||
var values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_Bios", ['ReleaseDate', 'Manufacturer', 'SMBIOSBIOSVersion', 'SerialNumber']);
|
||||
if(values[0]){
|
||||
ret['identifiers']['bios_date'] = values[0]['ReleaseDate'];
|
||||
ret['identifiers']['bios_vendor'] = values[0]['Manufacturer'];
|
||||
ret['identifiers']['bios_version'] = values[0]['SMBIOSBIOSVersion'];
|
||||
ret['identifiers']['bios_serial'] = values[0]['SerialNumber'];
|
||||
}
|
||||
ret['identifiers']['bios_mode'] = 'Legacy';
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_BaseBoard", ['Product', 'SerialNumber', 'Manufacturer', 'Version']);
|
||||
if(values[0]){
|
||||
ret['identifiers']['board_name'] = values[0]['Product'];
|
||||
ret['identifiers']['board_serial'] = values[0]['SerialNumber'];
|
||||
ret['identifiers']['board_vendor'] = values[0]['Manufacturer'];
|
||||
ret['identifiers']['board_version'] = values[0]['Version'];
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_ComputerSystemProduct", ['UUID', 'Name']);
|
||||
if(values[0]){
|
||||
ret['identifiers']['product_uuid'] = values[0]['UUID'];
|
||||
ret['identifiers']['product_name'] = values[0]['Name'];
|
||||
trimIdentifiers(ret.identifiers);
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_PhysicalMemory");
|
||||
if(values[0]){
|
||||
trimResults(values);
|
||||
ret.windows.memory = values;
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_OperatingSystem");
|
||||
if(values[0]){
|
||||
trimResults(values);
|
||||
ret.windows.osinfo = values[0];
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_DiskPartition");
|
||||
if(values[0]){
|
||||
trimResults(values);
|
||||
ret.windows.partitions = values;
|
||||
for (var i in values) {
|
||||
if (values[i].Description=='GPT: System') {
|
||||
ret['identifiers']['bios_mode'] = 'UEFI';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_Processor", ['Caption', 'DeviceID', 'Manufacturer', 'MaxClockSpeed', 'Name', 'SocketDesignation']);
|
||||
if(values[0]){
|
||||
ret.windows.cpu = values;
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_VideoController", ['Name', 'CurrentHorizontalResolution', 'CurrentVerticalResolution']);
|
||||
if(values[0]){
|
||||
ret.windows.gpu = values;
|
||||
}
|
||||
|
||||
values = require('win-wmi').query('ROOT\\CIMV2', "SELECT * FROM Win32_DiskDrive", ['Caption', 'DeviceID', 'Model', 'Partitions', 'Size', 'Status']);
|
||||
if(values[0]){
|
||||
ret.windows.drives = values;
|
||||
}
|
||||
|
||||
// Insert GPU names
|
||||
ret.identifiers.gpu_name = [];
|
||||
for (var gpuinfo in ret.windows.gpu)
|
||||
{
|
||||
if (ret.windows.gpu[gpuinfo].Name) { ret.identifiers.gpu_name.push(ret.windows.gpu[gpuinfo].Name); }
|
||||
}
|
||||
|
||||
// Insert Storage Devices
|
||||
ret.identifiers.storage_devices = [];
|
||||
for (var dv in ret.windows.drives)
|
||||
{
|
||||
ret.identifiers.storage_devices.push({ Caption: ret.windows.drives[dv].Caption, Model: ret.windows.drives[dv].Model, Size: ret.windows.drives[dv].Size });
|
||||
}
|
||||
|
||||
try { ret.identifiers.cpu_name = ret.windows.cpu[0].Name; } catch (x) { }
|
||||
|
||||
// Windows TPM
|
||||
IntToStr = function (v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); };
|
||||
try {
|
||||
values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftTpm', "SELECT * FROM Win32_Tpm", ['IsActivated_InitialValue','IsEnabled_InitialValue','IsOwned_InitialValue','ManufacturerId','ManufacturerVersion','SpecVersion']);
|
||||
if(values[0]) {
|
||||
ret.tpm = {
|
||||
SpecVersion: values[0].SpecVersion.split(",")[0],
|
||||
ManufacturerId: IntToStr(values[0].ManufacturerId).replace(/[^\x00-\x7F]/g, ""),
|
||||
ManufacturerVersion: values[0].ManufacturerVersion,
|
||||
IsActivated: values[0].IsActivated_InitialValue,
|
||||
IsEnabled: values[0].IsEnabled_InitialValue,
|
||||
IsOwned: values[0].IsOwned_InitialValue,
|
||||
}
|
||||
}
|
||||
} catch (ex) { }
|
||||
|
||||
return (ret);
|
||||
}
|
||||
function macos_identifiers()
|
||||
{
|
||||
var ret = { identifiers: {}, darwin: {} };
|
||||
var child;
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep board-id | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
ret.identifiers.board_name = child.stdout.str.trim();
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformSerialNumber | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
ret.identifiers.board_serial = child.stdout.str.trim();
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep manufacturer | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
ret.identifiers.board_vendor = child.stdout.str.trim();
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep version | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
ret.identifiers.board_version = child.stdout.str.trim();
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('ioreg -d2 -c IOPlatformExpertDevice | grep IOPlatformUUID | awk -F= \'{ split($2, res, "\\""); print res[2]; }\'\nexit\n');
|
||||
child.waitExit();
|
||||
ret.identifiers.product_uuid = child.stdout.str.trim();
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('sysctl -n machdep.cpu.brand_string\nexit\n');
|
||||
child.waitExit();
|
||||
ret.identifiers.cpu_name = child.stdout.str.trim();
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('system_profiler SPMemoryDataType\nexit\n');
|
||||
child.waitExit();
|
||||
var lines = child.stdout.str.trim().split('\n');
|
||||
if(lines.length > 0) {
|
||||
const memorySlots = [];
|
||||
if(lines[2].trim().includes('Memory Slots:')) { // OLD MACS WITH SLOTS
|
||||
var memorySlots1 = child.stdout.str.split(/\n{2,}/).slice(3);
|
||||
memorySlots1.forEach(function(slot,index) {
|
||||
var lines = slot.split('\n');
|
||||
if(lines.length == 1){ // start here
|
||||
if(lines[0].trim()!=''){
|
||||
var slotObj = { DeviceLocator: lines[0].trim().replace(/:$/, '') }; // Initialize name as an empty string
|
||||
var nextline = memorySlots1[index+1].split('\n');
|
||||
nextline.forEach(function(line) {
|
||||
if (line.trim() !== '') {
|
||||
var parts = line.split(':');
|
||||
var key = parts[0].trim();
|
||||
var value = parts[1].trim();
|
||||
value = (key == 'Part Number' || key == 'Manufacturer') ? hexToAscii(parts[1].trim()) : parts[1].trim();
|
||||
slotObj[key.replace(' ','')] = value; // Store attribute in the slot object
|
||||
}
|
||||
});
|
||||
memorySlots.push(slotObj);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else { // NEW MACS WITHOUT SLOTS
|
||||
memorySlots.push({ DeviceLocator: "Onboard Memory", Size: lines[2].split(":")[1].trim(), PartNumber: lines[3].split(":")[1].trim(), Manufacturer: lines[4].split(":")[1].trim() })
|
||||
}
|
||||
ret.darwin.memory = memorySlots;
|
||||
}
|
||||
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('diskutil info -all\nexit\n');
|
||||
child.waitExit();
|
||||
var sections = child.stdout.str.split('**********\n');
|
||||
if(sections.length > 0){
|
||||
var devices = [];
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
var lines = sections[i].split('\n');
|
||||
var deviceInfo = {};
|
||||
var wholeYes = false;
|
||||
var physicalYes = false;
|
||||
var oldmac = false;
|
||||
for (var j = 0; j < lines.length; j++) {
|
||||
var keyValue = lines[j].split(':');
|
||||
var key = keyValue[0].trim();
|
||||
var value = keyValue[1] ? keyValue[1].trim() : '';
|
||||
if (key === 'Virtual') oldmac = true;
|
||||
if (key === 'Whole' && value === 'Yes') wholeYes = true;
|
||||
if (key === 'Virtual' && value === 'No') physicalYes = true;
|
||||
if(value && key === 'Device / Media Name'){
|
||||
deviceInfo['Caption'] = value;
|
||||
}
|
||||
if(value && key === 'Disk Size'){
|
||||
deviceInfo['Size'] = value.split(' ')[0] + ' ' + value.split(' ')[1];
|
||||
}
|
||||
}
|
||||
if (wholeYes) {
|
||||
if (oldmac) {
|
||||
if (physicalYes) devices.push(deviceInfo);
|
||||
} else {
|
||||
devices.push(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.identifiers.storage_devices = devices;
|
||||
}
|
||||
|
||||
// Fetch storage volumes using df
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write('df -aHY | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\",\\"type\\":\\"%s\\"},", $3, $4, $5, $10, $2}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n');
|
||||
child.waitExit();
|
||||
try {
|
||||
ret.darwin.volumes = JSON.parse(child.stdout.str.trim());
|
||||
for (var index = 0; index < ret.darwin.volumes.length; index++) {
|
||||
if (ret.darwin.volumes[index].type == 'auto_home'){
|
||||
ret.darwin.volumes.splice(index,1);
|
||||
}
|
||||
}
|
||||
if (ret.darwin.volumes.length == 0) { // not sonima OS so dont show type for now
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', dataHandler);
|
||||
child.stdin.write('df -aH | awk \'NR>1 {printf "{\\"size\\":\\"%s\\",\\"used\\":\\"%s\\",\\"available\\":\\"%s\\",\\"mount_point\\":\\"%s\\"},", $2, $3, $4, $9}\' | sed \'$ s/,$//\' | awk \'BEGIN {printf "["} {printf "%s", $0} END {printf "]"}\'\nexit\n');
|
||||
child.waitExit();
|
||||
try {
|
||||
ret.darwin.volumes = JSON.parse(child.stdout.str.trim());
|
||||
for (var index = 0; index < ret.darwin.volumes.length; index++) {
|
||||
if (ret.darwin.volumes[index].size == 'auto_home'){
|
||||
ret.darwin.volumes.splice(index,1);
|
||||
}
|
||||
}
|
||||
} catch (xx) { }
|
||||
}
|
||||
} catch (xx) { }
|
||||
child = null;
|
||||
|
||||
// MacOS Last Boot Up Time
|
||||
try {
|
||||
child = require('child_process').execFile('/usr/sbin/sysctl', ['', 'kern.boottime']); // must include blank value at begining for some reason?
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.on('data', function () { });
|
||||
child.waitExit();
|
||||
const timestampMatch = /\{ sec = (\d+), usec = \d+ \}/.exec(child.stdout.str.trim());
|
||||
if (!ret.darwin) {
|
||||
ret.darwin = { LastBootUpTime: parseInt(timestampMatch[1]) };
|
||||
} else {
|
||||
ret.darwin.LastBootUpTime = parseInt(timestampMatch[1]);
|
||||
}
|
||||
child = null;
|
||||
} catch (ex) { }
|
||||
|
||||
trimIdentifiers(ret.identifiers);
|
||||
|
||||
child = null;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
function hexToAscii(hexString) {
|
||||
if(!hexString.startsWith('0x')) return hexString.trim();
|
||||
hexString = hexString.startsWith('0x') ? hexString.slice(2) : hexString;
|
||||
var str = '';
|
||||
for (var i = 0; i < hexString.length; i += 2) {
|
||||
var hexPair = hexString.substr(i, 2);
|
||||
str += String.fromCharCode(parseInt(hexPair, 16));
|
||||
}
|
||||
str = str.replace(/[\u007F-\uFFFF]/g, ''); // Remove characters from 0x0080 to 0xFFFF
|
||||
return str.trim();
|
||||
}
|
||||
|
||||
function win_chassisType()
|
||||
{
|
||||
// needs to be replaced with win-wmi but due to bug in win-wmi it doesnt handle arrays correctly
|
||||
var child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
|
||||
if (child == null) { return ([]); }
|
||||
child.descriptorMetadata = 'process-manager';
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('Get-WmiObject Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes\r\n');
|
||||
child.stdin.write('exit\r\n');
|
||||
child.waitExit();
|
||||
try {
|
||||
return (parseInt(child.stdout.str));
|
||||
} catch (e) {
|
||||
return (2); // unknown
|
||||
}
|
||||
}
|
||||
|
||||
function win_systemType()
|
||||
{
|
||||
try {
|
||||
var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT PCSystemType FROM Win32_ComputerSystem', ['PCSystemType']);
|
||||
if (tokens[0]) {
|
||||
return (parseInt(tokens[0]['PCSystemType']));
|
||||
} else {
|
||||
return (parseInt(1)); // default is desktop
|
||||
}
|
||||
} catch (ex) {
|
||||
return (parseInt(1)); // default is desktop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function win_formFactor(chassistype)
|
||||
{
|
||||
var ret = 'DESKTOP';
|
||||
switch (chassistype)
|
||||
{
|
||||
case 11: // Handheld
|
||||
case 30: // Tablet
|
||||
case 31: // Convertible
|
||||
case 32: // Detachable
|
||||
ret = 'TABLET';
|
||||
break;
|
||||
case 9: // Laptop
|
||||
case 10: // Notebook
|
||||
case 14: // Sub Notebook
|
||||
ret = 'LAPTOP';
|
||||
break;
|
||||
default:
|
||||
ret = win_systemType() == 2 ? 'MOBILE' : 'DESKTOP';
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
switch(process.platform)
|
||||
{
|
||||
case 'linux':
|
||||
module.exports = { _ObjectID: 'identifiers', get: linux_identifiers };
|
||||
break;
|
||||
case 'win32':
|
||||
module.exports = { _ObjectID: 'identifiers', get: windows_identifiers, chassisType: win_chassisType, formFactor: win_formFactor, systemType: win_systemType };
|
||||
break;
|
||||
case 'darwin':
|
||||
module.exports = { _ObjectID: 'identifiers', get: macos_identifiers };
|
||||
break;
|
||||
default:
|
||||
module.exports = { get: function () { throw ('Unsupported Platform'); } };
|
||||
break;
|
||||
}
|
||||
module.exports.isDocker = function isDocker()
|
||||
{
|
||||
if (process.platform != 'linux') { return (false); }
|
||||
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write("cat /proc/self/cgroup | tr '\n' '`' | awk -F'`' '{ split($1, res, " + '"/"); if(res[2]=="docker"){print "1";} }\'\nexit\n');
|
||||
child.waitExit();
|
||||
return (child.stdout.str != '');
|
||||
};
|
||||
module.exports.isBatteryPowered = function isBatteryOperated()
|
||||
{
|
||||
var ret = false;
|
||||
switch(process.platform)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case 'linux':
|
||||
var devices = require('fs').readdirSync('/sys/class/power_supply');
|
||||
for (var i in devices)
|
||||
{
|
||||
if (require('fs').readFileSync('/sys/class/power_supply/' + devices[i] + '/type').toString().trim() == 'Battery')
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'win32':
|
||||
var GM = require('_GenericMarshal');
|
||||
var stats = GM.CreateVariable(12);
|
||||
var kernel32 = GM.CreateNativeProxy('Kernel32.dll');
|
||||
kernel32.CreateMethod('GetSystemPowerStatus');
|
||||
if (kernel32.GetSystemPowerStatus(stats).Val != 0)
|
||||
{
|
||||
if(stats.toBuffer()[1] != 128 && stats.toBuffer()[1] != 255)
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Battery detected, so lets check if there is supposed to be one
|
||||
var formFactor = win_formFactor(win_chassisType());
|
||||
return (formFactor == 'LAPTOP' || formFactor == 'TABLET' || formFactor == 'MOBILE');
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'darwin':
|
||||
var child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function(c){ this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function(c){ this.str += c.toString(); });
|
||||
child.stdin.write("pmset -g batt | tr '\\n' '`' | awk -F'`' '{ if(NF>2) { print \"true\"; }}'\nexit\n");
|
||||
child.waitExit();
|
||||
if(child.stdout.str.trim() != '') { ret = true; }
|
||||
break;
|
||||
}
|
||||
return (ret);
|
||||
};
|
||||
module.exports.isVM = function isVM()
|
||||
{
|
||||
var ret = false;
|
||||
var id = this.get();
|
||||
if (id.linux && id.linux.sys_vendor)
|
||||
{
|
||||
switch (id.linux.sys_vendor)
|
||||
{
|
||||
case 'VMware, Inc.':
|
||||
case 'QEMU':
|
||||
case 'Xen':
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id.identifiers.bios_vendor)
|
||||
{
|
||||
switch(id.identifiers.bios_vendor)
|
||||
{
|
||||
case 'VMware, Inc.':
|
||||
case 'Xen':
|
||||
case 'SeaBIOS':
|
||||
case 'EFI Development Kit II / OVMF':
|
||||
case 'Proxmox distribution of EDK II':
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id.identifiers.board_vendor && id.identifiers.board_vendor == 'VMware, Inc.') { ret = true; }
|
||||
if (id.identifiers.board_name)
|
||||
{
|
||||
switch (id.identifiers.board_name)
|
||||
{
|
||||
case 'VirtualBox':
|
||||
case 'Virtual Machine':
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform == 'win32' && !ret)
|
||||
{
|
||||
for(var i in id.identifiers.gpu_name)
|
||||
{
|
||||
if(id.identifiers.gpu_name[i].startsWith('VMware '))
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!ret) { ret = this.isDocker(); }
|
||||
return (ret);
|
||||
};
|
||||
|
||||
// bios_date = BIOS->ReleaseDate
|
||||
// bios_vendor = BIOS->Manufacturer
|
||||
// bios_version = BIOS->SMBIOSBIOSVersion
|
||||
// board_name = BASEBOARD->Product = ioreg/board-id
|
||||
// board_serial = BASEBOARD->SerialNumber = ioreg/serial-number | ioreg/IOPlatformSerialNumber
|
||||
// board_vendor = BASEBOARD->Manufacturer = ioreg/manufacturer
|
||||
// board_version = BASEBOARD->Version
|
||||
|
|
@ -110,10 +110,14 @@
|
|||
"ko": {
|
||||
"allow": "허용하다",
|
||||
"deny": "거부",
|
||||
"terminalNotify": "원격 터미널 세션이 시작되었습니다: {0}",
|
||||
"desktopNotify": "원격 데스크톱 세션이 시작되었습니다: {0}",
|
||||
"fileNotify": "원격 파일 전송 세션이 시작되었습니다: {0}",
|
||||
"privacyBar": "다음과 데스크탑 공유: {0}"
|
||||
"terminalNotify": "{0}이(가) 원격 터미널 세션을 시작했습니다.",
|
||||
"desktopNotify": "{0}이(가) 원격 데스크톱 세션을 시작했습니다.",
|
||||
"fileNotify": "{0}이(가) 원격 파일 세션을 시작했습니다.",
|
||||
"privacyBar": "다음과 데스크톱 공유: {0}",
|
||||
"autoAllowForFive": "다음 5분 동안 모든 연결 자동 수락",
|
||||
"terminalConsent": "{0} 원격 터미널 액세스를 요청합니다. 액세스 권한을 부여하시겠습니까?",
|
||||
"desktopConsent": "{0} 원격 데스크톱 액세스를 요청합니다. 액세스 권한을 부여하시겠습니까?",
|
||||
"fileConsent": "{0}이(가) 원격 파일 액세스를 요청합니다. 액세스 권한을 부여하시겠습니까?"
|
||||
},
|
||||
"nl": {
|
||||
"allow": "Toestaan",
|
||||
|
|
@ -129,7 +133,15 @@
|
|||
},
|
||||
"pt": {
|
||||
"allow": "Permitir",
|
||||
"deny": "Negar"
|
||||
"deny": "Negar",
|
||||
"autoAllowForFive": "Aceita automaticamente todas as conexões pelos próximos 5 minutos",
|
||||
"terminalConsent": "{0} está a pedir acesso ao terminal remoto. Conceder acesso?",
|
||||
"desktopConsent": "{0} está a pedir acesso à área de trabalho remota. Conceder acesso?",
|
||||
"fileConsent": "{0} está a pedir acesso remoto aos ficheiros. Conceder acesso?",
|
||||
"terminalNotify": "{0} iniciou uma sessão de terminal remoto.",
|
||||
"desktopNotify": "{0} iniciou uma sessão de área de trabalho remota.",
|
||||
"fileNotify": "{0} iniciou uma sessão de ficheiro remoto.",
|
||||
"privacyBar": "Compartilhando área de trabalho com: {0}"
|
||||
},
|
||||
"ru": {
|
||||
"allow": "Разрешить",
|
||||
|
|
@ -145,7 +157,15 @@
|
|||
},
|
||||
"sv": {
|
||||
"allow": "Tillåta",
|
||||
"deny": "Förneka"
|
||||
"deny": "Förneka",
|
||||
"autoAllowForFive": "Acceptera alla anslutningar automatiskt under de kommande 5 minuterna",
|
||||
"terminalConsent": "{0} begär åtkomst till fjärrterminal. Ge tillgång?",
|
||||
"desktopConsent": "{0} begär åtkomst till fjärrskrivbord. Ge tillgång?",
|
||||
"fileConsent": "{0} begär fjärråtkomst till fil. Ge tillgång?",
|
||||
"terminalNotify": "{0} startade en fjärrterminalsession.",
|
||||
"desktopNotify": "{0} startade en fjärrskrivbordssession.",
|
||||
"fileNotify": "{0} startade en fjärrfilsession.",
|
||||
"privacyBar": "Dela skrivbord med: {0}"
|
||||
},
|
||||
"tr": {
|
||||
"allow": "İzin ver",
|
||||
|
|
@ -161,7 +181,15 @@
|
|||
},
|
||||
"zh-chs": {
|
||||
"allow": "允许",
|
||||
"deny": "否定"
|
||||
"deny": "否定",
|
||||
"autoAllowForFive": "在接下来的 5 分钟内自动接受所有连接",
|
||||
"terminalConsent": "{0} 请求远程终端访问。授予访问权限?",
|
||||
"desktopConsent": "{0} 请求远程桌面访问。授予访问权限?",
|
||||
"fileConsent": "{0} 请求远程文件访问。授予访问权限?",
|
||||
"terminalNotify": "{0} 启动了远程终端会话。",
|
||||
"desktopNotify": "{0} 启动了远程桌面会话。",
|
||||
"fileNotify": "{0} 启动了远程文件会话。",
|
||||
"privacyBar": "与:{0} 共享桌面"
|
||||
},
|
||||
"da": {
|
||||
"allow": "Tillad",
|
||||
|
|
@ -198,5 +226,65 @@
|
|||
"desktopNotify": "{0} iniciou uma sessão de área de trabalho remota.",
|
||||
"fileNotify": "{0} {0} iniciou uma sessão de arquivos.",
|
||||
"privacyBar": "Compartilhando área de trabalho com: {0}"
|
||||
},
|
||||
"zh-cht": {
|
||||
"allow": "允許",
|
||||
"deny": "否定",
|
||||
"autoAllowForFive": "在接下來的 5 分鐘內自動接受所有連接",
|
||||
"terminalConsent": "{0} 請求遠程終端訪問。授予訪問權限?",
|
||||
"desktopConsent": "{0} 請求遠程桌面訪問。授予訪問權限?",
|
||||
"fileConsent": "{0} 請求遠程文件訪問。授予訪問權限?",
|
||||
"terminalNotify": "{0} 啟動了遠程終端會話。",
|
||||
"desktopNotify": "{0} 啟動了遠程桌面會話。",
|
||||
"fileNotify": "{0} 啟動了遠程文件會話。",
|
||||
"privacyBar": "與:{0} 共享桌面"
|
||||
},
|
||||
"bs": {
|
||||
"allow": "Dopustiti",
|
||||
"deny": "Deny",
|
||||
"autoAllowForFive": "Automatski prihvati sve veze u narednih 5 minuta",
|
||||
"terminalConsent": "{0} zahtijeva pristup udaljenom terminalu. Odobriti pristup?",
|
||||
"desktopConsent": "{0} zahtijeva pristup udaljenoj radnoj površini. Odobriti pristup?",
|
||||
"fileConsent": "{0} zahtijeva udaljeni pristup fajlu. Odobriti pristup?",
|
||||
"terminalNotify": "{0} je započeo sesiju udaljenog terminala.",
|
||||
"desktopNotify": "{0} je započeo sesiju udaljene radne površine.",
|
||||
"fileNotify": "{0} je započeo sesiju udaljenog fajla.",
|
||||
"privacyBar": "Dijeljenje radne površine sa: {0}"
|
||||
},
|
||||
"hu": {
|
||||
"allow": "Engedélyezés",
|
||||
"deny": "Elutasítás",
|
||||
"autoAllowForFive": "Csatlakozások automatikus elfogadása a következő 5 percben",
|
||||
"terminalConsent": "{0} távoli parancssor,terminál hozzáférést kér. Engedélyezi a hozzáférést?",
|
||||
"desktopConsent": "{0} távoli asztali hozzáférést kér. Engedélyezi a hozzáférést?",
|
||||
"fileConsent": "{0} távoli fájlhozzáférést kér. Engedélyezi a hozzáférést?",
|
||||
"terminalNotify": "{0} távoli parancssor munkamenetet indított.",
|
||||
"desktopNotify": "{0} távoli asztali munkamenetet indított.",
|
||||
"fileNotify": "{0} távoli fájlmunkamenetet indított.",
|
||||
"privacyBar": "Asztal megosztás aktív: {0} felhasználóval"
|
||||
},
|
||||
"ca": {
|
||||
"allow": "Permetre",
|
||||
"deny": "Negar",
|
||||
"autoAllowForFive": "Accepta automàticament totes les connexions durant els propers 5 minuts",
|
||||
"terminalConsent": "{0} sol·licitant accés al terminal remot. Accés garantit?",
|
||||
"desktopConsent": "{0} sol·licitant accés a l'escriptori remot. Accés garantit?",
|
||||
"fileConsent": "{0} sol·licitant accés remot al fitxer. Accés garantit?",
|
||||
"terminalNotify": "{0} va iniciar una sessió de terminal remota.",
|
||||
"desktopNotify": "{0} va iniciar una sessió d'escriptori remot.",
|
||||
"fileNotify": "{0} va iniciar una sessió de fitxer remota.",
|
||||
"privacyBar": "Compartint escriptori amb: {0}"
|
||||
},
|
||||
"uk": {
|
||||
"allow": "Дозволити",
|
||||
"deny": "Відмовити",
|
||||
"autoAllowForFive": "Автоматично приймати всі підключення впродовж наступних 5 хвилин",
|
||||
"terminalConsent": "{0} запитує доступ до віддаленого терміналу. Надати доступ?",
|
||||
"desktopConsent": "{0} запитує віддалений доступ до стільниці. Надати доступ?",
|
||||
"fileConsent": "{0} запитує віддалений доступ до файлу. Надати доступ?",
|
||||
"terminalNotify": "{0} почав сеанс віддаленого терміналу.",
|
||||
"desktopNotify": "{0} розпочав сеанс віддаленої стільниці.",
|
||||
"fileNotify": "{0} розпочав віддалений файловий сеанс.",
|
||||
"privacyBar": "Поширити доступ до стільниці з: {0}"
|
||||
}
|
||||
}
|
||||
|
|
@ -269,15 +269,18 @@ function SMBiosTables()
|
|||
this.amtInfo = function amtInfo(data) {
|
||||
if (!data) { throw ('no data'); }
|
||||
var retVal = { AMT: false };
|
||||
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT') {
|
||||
if (data[130] && data[130].peek().slice(0, 4).toString() == '$AMT')
|
||||
{
|
||||
var amt = data[130].peek();
|
||||
retVal.AMT = amt[4] ? true : false;
|
||||
if (retVal.AMT) {
|
||||
if (retVal.AMT)
|
||||
{
|
||||
retVal.enabled = amt[5] ? true : false;
|
||||
retVal.storageRedirection = amt[6] ? true : false;
|
||||
retVal.serialOverLan = amt[7] ? true : false;
|
||||
retVal.kvm = amt[14] ? true : false;
|
||||
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro') {
|
||||
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
|
||||
{
|
||||
var settings = data[131].peek();
|
||||
if (settings[0] & 0x04) { retVal.TXT = (settings[0] & 0x08) ? true : false; }
|
||||
if (settings[0] & 0x10) { retVal.VMX = (settings[0] & 0x20) ? true : false; }
|
||||
|
|
@ -295,6 +298,14 @@ function SMBiosTables()
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!retVal.AMT)
|
||||
{
|
||||
if (data[131].peek() && data[131].peek().slice(52, 56).toString() == 'vPro')
|
||||
{
|
||||
var settings = data[131].peek();
|
||||
if ((settings[20] & 0x08) == 0x08) { retVal.AMT = true; }
|
||||
}
|
||||
}
|
||||
return (retVal);
|
||||
};
|
||||
this.smTableTypes = {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ function linux_memUtilization()
|
|||
case 'MemTotal:':
|
||||
ret.total = parseInt(tokens[tokens.length - 2]);
|
||||
break;
|
||||
case 'MemFree:':
|
||||
case 'MemAvailable:':
|
||||
ret.free = parseInt(tokens[tokens.length - 2]);
|
||||
break;
|
||||
}
|
||||
|
|
@ -209,9 +209,13 @@ function macos_memUtilization()
|
|||
{
|
||||
var usage = lines[0].split(':')[1];
|
||||
var bdown = usage.split(',');
|
||||
|
||||
mem.MemTotal = parseInt(bdown[0].trim().split(' ')[0]);
|
||||
mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]);
|
||||
if (bdown.length > 2){ // new style - PhysMem: 5750M used (1130M wired, 634M compressor), 1918M unused.
|
||||
mem.MemFree = parseInt(bdown[2].trim().split(' ')[0]);
|
||||
} else { // old style - PhysMem: 6683M used (1606M wired), 9699M unused.
|
||||
mem.MemFree = parseInt(bdown[1].trim().split(' ')[0]);
|
||||
}
|
||||
mem.MemUsed = parseInt(bdown[0].trim().split(' ')[0]);
|
||||
mem.MemTotal = (mem.MemFree + mem.MemUsed);
|
||||
mem.percentFree = ((mem.MemFree / mem.MemTotal) * 100);//.toFixed(2);
|
||||
mem.percentConsumed = (((mem.MemTotal - mem.MemFree) / mem.MemTotal) * 100);//.toFixed(2);
|
||||
return (mem);
|
||||
|
|
@ -225,31 +229,48 @@ function macos_memUtilization()
|
|||
function windows_thermals()
|
||||
{
|
||||
var ret = [];
|
||||
child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', '/namespace:\\\\root\\wmi', 'PATH', 'MSAcpi_ThermalZoneTemperature', 'get', 'CurrentTemperature']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.waitExit();
|
||||
|
||||
if(child.stdout.str.trim!='')
|
||||
{
|
||||
var lines = child.stdout.str.trim().split('\r\n');
|
||||
for (var i = 1; i < lines.length; ++i)
|
||||
{
|
||||
if (lines[i].trim() != '') { ret.push(((parseFloat(lines[i]) / 10) - 273.15).toFixed(2)); }
|
||||
try {
|
||||
ret = require('win-wmi').query('ROOT\\WMI', 'SELECT CurrentTemperature,InstanceName FROM MSAcpi_ThermalZoneTemperature',['CurrentTemperature','InstanceName']);
|
||||
if (ret[0]) {
|
||||
for (var i = 0; i < ret.length; ++i) {
|
||||
ret[i]['CurrentTemperature'] = ((parseFloat(ret[i]['CurrentTemperature']) / 10) - 273.15).toFixed(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) { }
|
||||
return (ret);
|
||||
}
|
||||
|
||||
function linux_thermals()
|
||||
{
|
||||
var ret = [];
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write("cat /sys/class/thermal/thermal_zone*/temp | awk '{ print $0 / 1000 }'\nexit\n");
|
||||
child.stdin.write("for folder in /sys/class/thermal/thermal_zone*/; do [ -e \"$folder/temp\" ] && echo \"$(cat \"$folder/temp\"),$(cat \"$folder/type\")\"; done\nexit\n");
|
||||
child.waitExit();
|
||||
var ret = child.stdout.str.trim().split('\n');
|
||||
if (ret.length == 1 && ret[0] == '') { ret = []; }
|
||||
if(child.stdout.str.trim()!='')
|
||||
{
|
||||
var lines = child.stdout.str.trim().split('\n');
|
||||
for (var i = 0; i < lines.length; ++i)
|
||||
{
|
||||
var line = lines[i].trim().split(',');
|
||||
ret.push({CurrentTemperature: (parseFloat(line[0])/1000), InstanceName: line[1]});
|
||||
}
|
||||
}
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write("for mon in /sys/class/hwmon/hwmon*; do for label in \"$mon\"/temp*_label; do if [ -f $label ]; then echo $(cat \"$label\")___$(cat \"${label%_*}_input\"); fi; done; done;\nexit\n");
|
||||
child.waitExit();
|
||||
if(child.stdout.str.trim()!='')
|
||||
{
|
||||
var lines = child.stdout.str.trim().split('\n');
|
||||
for (var i = 0; i < lines.length; ++i)
|
||||
{
|
||||
var line = lines[i].trim().split('___');
|
||||
ret.push({ CurrentTemperature: (parseFloat(line[1])/1000), InstanceName: line[0] });
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +282,6 @@ function macos_thermals()
|
|||
child.stderr.on('data', function () { });
|
||||
child.stdin.write('powermetrics --help | grep SMC\nexit\n');
|
||||
child.waitExit();
|
||||
|
||||
if (child.stdout.str.trim() != '')
|
||||
{
|
||||
child = require('child_process').execFile('/bin/sh', ['sh']);
|
||||
|
|
@ -273,14 +293,19 @@ function macos_thermals()
|
|||
{
|
||||
if (tokens[i].split(' die temperature: ').length > 1)
|
||||
{
|
||||
ret.push(tokens[i].split(' ')[3]);
|
||||
ret.push({CurrentTemperature: tokens[i].split(' ')[3], InstanceName: tokens[i].split(' ')[0]});
|
||||
this.parent.kill();
|
||||
}
|
||||
}
|
||||
});
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stdin.write('powermetrics -s smc\n');
|
||||
child.waitExit(5000);
|
||||
child.stderr.on('data', function (c) {
|
||||
if (c.toString().split('unable to get smc values').length > 1) { // error getting sensors so just kill
|
||||
this.parent.kill();
|
||||
return;
|
||||
}
|
||||
});
|
||||
child.stdin.write('powermetrics -s smc -i 500 -n 1\n');
|
||||
child.waitExit(2000);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
|||
194
agents/modules_meshcore/win-deskutils.js
Normal file
194
agents/modules_meshcore/win-deskutils.js
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
Copyright 2022 Intel Corporation
|
||||
@author Bryan Roe
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// win-deskutils is a utility module that exposes various desktop related features for Windows
|
||||
// such as MouseTrails Accessability and Windows Desktop Background
|
||||
//
|
||||
|
||||
//
|
||||
// MSDN documention for the system call this module relies on can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
|
||||
//
|
||||
|
||||
var SPI_GETDESKWALLPAPER = 0x0073;
|
||||
var SPI_SETDESKWALLPAPER = 0x0014;
|
||||
var SPI_GETMOUSETRAILS = 0x005E;
|
||||
var SPI_SETMOUSETRAILS = 0x005D;
|
||||
|
||||
var GM = require('_GenericMarshal');
|
||||
var user32 = GM.CreateNativeProxy('user32.dll');
|
||||
user32.CreateMethod('SystemParametersInfoA');
|
||||
|
||||
//
|
||||
// This function is a helper method to dispatch method calls to different user sessions
|
||||
//
|
||||
function sessionDispatch(tsid, parent, method, args)
|
||||
{
|
||||
//
|
||||
// Check to see if the process owner of the current processor is root
|
||||
//
|
||||
var sid = undefined;
|
||||
var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
|
||||
/*
|
||||
The following is the list of possible values for stype.
|
||||
If the current process owner is root, we set the stype to user,
|
||||
because we cannot set/get any properties from this user, we
|
||||
must switch to a user session.. Default behavior for stype(1)
|
||||
is that it will context switch to the logged in user. If
|
||||
this is not intended, then an actual user TSID must be specified, using
|
||||
ILibProcessPipe_SpawnTypes_SPECIFIED_USER and the actual TSID
|
||||
------------------------------------------------------------------------
|
||||
ILibProcessPipe_SpawnTypes_DEFAULT = 0,
|
||||
ILibProcessPipe_SpawnTypes_USER = 1,
|
||||
ILibProcessPipe_SpawnTypes_WINLOGON = 2,
|
||||
ILibProcessPipe_SpawnTypes_TERM = 3,
|
||||
ILibProcessPipe_SpawnTypes_DETACHED = 4,
|
||||
ILibProcessPipe_SpawnTypes_SPECIFIED_USER = 5,
|
||||
ILibProcessPipe_SpawnTypes_POSIX_DETACHED = 0x8000
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
console.log('stype: ' + stype);
|
||||
if (stype == 1)
|
||||
{
|
||||
if (tsid == null && require('MeshAgent')._tsid != null)
|
||||
{
|
||||
stype = 5; // ILibProcessPipe_SpawnTypes_SPECIFIED_USER
|
||||
sid = require('MeshAgent')._tsid; // If this is set, it was set via user selection UI
|
||||
}
|
||||
else
|
||||
{
|
||||
sid = tsid; // Set the SID to be whatever was passed in
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a child process in the appropriate user session, and relay the response back via stdout
|
||||
var mod = Buffer.from(getJSModule('win-deskutils')).toString('base64');
|
||||
var prog = "try { addModule('win-deskutils', process.env['win_deskutils']);} catch (x) { } var x;try{x=require('win-deskutils').dispatch('" + parent + "', '" + method + "', " + JSON.stringify(args) + ");console.log(x);}catch(z){console.log(z);process.exit(1);}process.exit(0);";
|
||||
var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', Buffer.from(prog).toString('base64')], { type: stype, uid: sid, env: { win_deskutils: getJSModule('win-deskutils') } });
|
||||
|
||||
child.stdout.str = '';
|
||||
child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.on('data', function (c) { });
|
||||
child.on('exit', function (c) { this.exitCode = c; });
|
||||
child.waitExit();
|
||||
if (child.exitCode == 0)
|
||||
{
|
||||
return (child.stdout.str.trim()); // If the return code was 0, then relay the response from stdout
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (child.stdout.str.trim()); // If the return code was nonzero, then the stdout response is the exception that should be bubbled
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// This function gets the path of the windows desktop background of the specified user desktop session
|
||||
//
|
||||
function background_get(tsid)
|
||||
{
|
||||
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
|
||||
{
|
||||
// Need to disatch to different session first
|
||||
return (sessionDispatch(tsid, 'background', 'get', []));
|
||||
}
|
||||
var v = GM.CreateVariable(1024);
|
||||
var ret = user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER, v._size, v, 0);
|
||||
if (ret.Val == 0)
|
||||
{
|
||||
throw ('Error occured trying to fetch wallpaper');
|
||||
}
|
||||
return (v.String);
|
||||
}
|
||||
|
||||
//
|
||||
// This function sets the path for the windows desktop background of the specified user desktop session
|
||||
//
|
||||
function background_set(path, tsid)
|
||||
{
|
||||
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
|
||||
{
|
||||
// Need to disatch to different session first
|
||||
return (sessionDispatch(tsid, 'background', 'set', [path]));
|
||||
}
|
||||
var nb = GM.CreateVariable(path);
|
||||
var ret = user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, nb._size, nb, 0);
|
||||
if (ret.Val == 0)
|
||||
{
|
||||
throw ('Error occured trying to set wallpaper');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// This is a helper function that is called by the child process from sessionDispatch()
|
||||
//
|
||||
function dispatch(parent, method, args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (this[parent][method].apply(this, args));
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
console.log('ERROR: ' + e);
|
||||
throw ('Error occured trying to dispatch: ' + method);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// This function sets the mousetrail accessibility feature, for the specified user desktop session.
|
||||
// Setting value 0 or one disables this feature
|
||||
// Otherwise, value is the number of cursors to render for this feature
|
||||
//
|
||||
function mousetrails_set(value, tsid)
|
||||
{
|
||||
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
|
||||
{
|
||||
// Need to disatch to different session first
|
||||
return (sessionDispatch(tsid, 'mouse', 'setTrails', [value]));
|
||||
}
|
||||
var ret = user32.SystemParametersInfoA(SPI_SETMOUSETRAILS, value, 0, 0);
|
||||
if (ret.Val == 0)
|
||||
{
|
||||
throw ('Error occured trying to fetch wallpaper');
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// This function returns the number of cursors the mousetrail accessibility feature will render
|
||||
// A value of 0 or 1 means the feature is disabled, otherwise it is the number of cursors that will be rendered
|
||||
//
|
||||
function mousetrails_get(tsid)
|
||||
{
|
||||
if (tsid != null || tsid === null) // TSID is not undefined or is explicitly null
|
||||
{
|
||||
// Need to disatch to different session first
|
||||
return (sessionDispatch(tsid, 'mouse', 'getTrails', []));
|
||||
}
|
||||
var v = GM.CreateVariable(4);
|
||||
var ret = user32.SystemParametersInfoA(SPI_GETMOUSETRAILS, v._size, v, 0);
|
||||
if (ret.Val == 0)
|
||||
{
|
||||
throw ('Error occured trying to fetch wallpaper');
|
||||
}
|
||||
return (v.toBuffer().readUInt32LE());
|
||||
}
|
||||
|
||||
module.exports = { background: { get: background_get, set: background_set } };
|
||||
module.exports.mouse = { getTrails: mousetrails_get, setTrails: mousetrails_set };
|
||||
module.exports.dispatch = dispatch;
|
||||
|
|
@ -18,28 +18,21 @@ var promise = require('promise');
|
|||
|
||||
function qfe()
|
||||
{
|
||||
var child = require('child_process').execFile(process.env['windir'] + '\\System32\\wbem\\wmic.exe', ['wmic', 'qfe', 'list', 'full', '/FORMAT:CSV']);
|
||||
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
child.waitExit();
|
||||
|
||||
var lines = child.stdout.str.trim().split('\r\n');
|
||||
var keys = lines[0].split(',');
|
||||
var i, key;
|
||||
var tokens;
|
||||
var result = [];
|
||||
|
||||
for (i = 1; i < lines.length; ++i)
|
||||
{
|
||||
var obj = {};
|
||||
tokens = lines[i].split(',');
|
||||
for (key = 0; key < keys.length; ++key)
|
||||
{
|
||||
if (tokens[key]) { obj[keys[key]] = tokens[key]; }
|
||||
try {
|
||||
var tokens = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_QuickFixEngineering');
|
||||
if (tokens[0]){
|
||||
for (var index = 0; index < tokens.length; index++) {
|
||||
for (var key in tokens[index]) {
|
||||
if (key.startsWith('__')) delete tokens[index][key];
|
||||
}
|
||||
}
|
||||
return (tokens);
|
||||
} else {
|
||||
return ([]);
|
||||
}
|
||||
result.push(obj);
|
||||
} catch (ex) {
|
||||
return ([]);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
function av()
|
||||
{
|
||||
|
|
@ -53,9 +46,23 @@ function av()
|
|||
child.stdin.write('[reflection.Assembly]::LoadWithPartialName("system.core")\r\n');
|
||||
child.stdin.write('Get-WmiObject -Namespace "root/SecurityCenter2" -Class AntiVirusProduct | ');
|
||||
child.stdin.write('ForEach-Object -Process { ');
|
||||
child.stdin.write('$matches = [regex]::Matches($_.pathToSignedProductExe, "%(.*?)%"); ');
|
||||
child.stdin.write('$modifiedPath = $_.pathToSignedProductExe; ');
|
||||
child.stdin.write('foreach ($match in $matches) { ');
|
||||
child.stdin.write('$modifiedPath = $modifiedPath -replace [regex]::Escape($match.Value), [System.Environment]::GetEnvironmentVariable($match.Groups[1].Value, "Process") ');
|
||||
child.stdin.write('} ');
|
||||
child.stdin.write('$flag = $true; ');
|
||||
child.stdin.write('if ($modifiedPath -ne "windowsdefender://"){ ');
|
||||
child.stdin.write('if (-not (Test-Path -Path $modifiedPath -PathType Leaf)) { ');
|
||||
child.stdin.write('$flag = $false; ');
|
||||
child.stdin.write('} ');
|
||||
child.stdin.write('} ');
|
||||
child.stdin.write('if ($flag -eq $true) { ')
|
||||
child.stdin.write('$Bytes = [System.Text.Encoding]::UTF8.GetBytes($_.displayName); ');
|
||||
child.stdin.write('$EncodedText =[Convert]::ToBase64String($Bytes); ');
|
||||
child.stdin.write('Write-Host ("{0},{1}" -f $_.productState,$EncodedText); }\r\n');
|
||||
child.stdin.write('Write-Output ("{0},{1}" -f $_.productState,$EncodedText); ');
|
||||
child.stdin.write('} ');
|
||||
child.stdin.write('}\r\n ');
|
||||
child.stdin.write('exit\r\n');
|
||||
child.waitExit();
|
||||
|
||||
|
|
@ -214,6 +221,14 @@ function installedApps()
|
|||
catch(e)\
|
||||
{\
|
||||
}\
|
||||
try\
|
||||
{\
|
||||
val.installdate = reg.QueryKey(reg.HKEY.LocalMachine, 'SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Uninstall\\\\' + items.subkeys[key], 'InstallDate');\
|
||||
if (val.installdate == '') { delete val.installdate; }\
|
||||
}\
|
||||
catch(e)\
|
||||
{\
|
||||
}\
|
||||
result.push(val);\
|
||||
}\
|
||||
console.log(JSON.stringify(result,'', 1));process.exit();";
|
||||
|
|
@ -225,12 +240,33 @@ function installedApps()
|
|||
return (ret);
|
||||
}
|
||||
|
||||
function defender(){
|
||||
var promise = require('promise');
|
||||
var ret = new promise(function (a, r) { this._resolve = a; this._reject = r; });
|
||||
ret.child = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], {});
|
||||
ret.child.promise = ret;
|
||||
ret.child.stdout.str = ''; ret.child.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
ret.child.stderr.str = ''; ret.child.stderr.on('data', function (c) { this.str += c.toString(); });
|
||||
ret.child.stdin.write('Get-MpComputerStatus | Select-Object RealTimeProtectionEnabled,IsTamperProtected | ConvertTo-JSON\r\n');
|
||||
ret.child.stdin.write('exit\r\n');
|
||||
ret.child.on('exit', function (c) {
|
||||
if (this.stdout.str == '') { this.promise._resolve({}); return; }
|
||||
try {
|
||||
var abc = JSON.parse(this.stdout.str.trim());
|
||||
this.promise._resolve({ RealTimeProtection: abc.RealTimeProtectionEnabled, TamperProtected: abc.IsTamperProtected });
|
||||
} catch (ex) {
|
||||
this.promise._resolve({}); return;
|
||||
}
|
||||
});
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (process.platform == 'win32')
|
||||
{
|
||||
module.exports = { qfe: qfe, av: av, defrag: defrag, pendingReboot: pendingReboot, installedApps: installedApps };
|
||||
module.exports = { qfe: qfe, av: av, defrag: defrag, pendingReboot: pendingReboot, installedApps: installedApps, defender: defender };
|
||||
}
|
||||
else
|
||||
{
|
||||
var not_supported = function () { throw (process.platform + ' not supported'); };
|
||||
module.exports = { qfe: not_supported, av: not_supported, defrag: not_supported, pendingReboot: not_supported, installedApps: not_supported };
|
||||
module.exports = { qfe: not_supported, av: not_supported, defrag: not_supported, pendingReboot: not_supported, installedApps: not_supported, defender: not_supported };
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
Copyright 2018-2022 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
@ -89,21 +89,50 @@ function windows_terminal() {
|
|||
var newCsbi = GM.CreateVariable(22);
|
||||
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, newCsbi).Val == 0) { return; }
|
||||
if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY) {
|
||||
//wchar_t mywbuf[512];
|
||||
//swprintf(mywbuf, 512, TEXT("csbi.dwCursorPosition.X = %d, csbi.dwCursorPosition.Y = %d, newCsbi.dwCursorPosition.X = %d, newCsbi.dwCursorPosition.Y = %d\r\n"), csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y, newCsbi.dwCursorPosition.X, newCsbi.dwCursorPosition.Y);
|
||||
//OutputDebugString(mywbuf);
|
||||
|
||||
//m_viewOffset = newCsbi.srWindow.Top;
|
||||
//WriteMoveCursor((SerialAgent *)this->sa, (char)(newCsbi.dwCursorPosition.Y - m_viewOffset), (char)(newCsbi.dwCursorPosition.X - m_viewOffset));
|
||||
//LowStackSendData((SerialAgent *)(this->sa), "", 0);
|
||||
|
||||
if (newCsbi.Deref(4, 2).toBuffer().readUInt16LE() != this.currentX || newCsbi.Deref(6, 2).toBuffer().readUInt16LE() != this.currentY)
|
||||
{
|
||||
//
|
||||
// Reference for CONSOLE_SCREEN_BUFFER_INFO can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
|
||||
//
|
||||
|
||||
this.currentX = newCsbi.Deref(4, 2).toBuffer().readUInt16LE();
|
||||
this.currentY = newCsbi.Deref(6, 2).toBuffer().readUInt16LE();
|
||||
}
|
||||
}
|
||||
|
||||
this.ClearScreen = function () {
|
||||
this.ClearScreen = function ()
|
||||
{
|
||||
//
|
||||
// Reference for CONSOLE_SCREEN_BUFFER_INFO can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/console-screen-buffer-info-str
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for GetConsoleScreenBufferInfo can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for FillConsoleOutputCharacter can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/fillconsoleoutputcharacter
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for FillConsoleOutputAttribute can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/fillconsoleoutputattribute
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for SetConsoleCursorPosition can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/setconsolecursorposition
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for SetConsoleWindowInfo can be fount at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/setconsolewindowinfo
|
||||
//
|
||||
|
||||
var CONSOLE_SCREEN_BUFFER_INFO = GM.CreateVariable(22);
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, CONSOLE_SCREEN_BUFFER_INFO).Val == 0) { return; }
|
||||
|
||||
|
|
@ -132,6 +161,7 @@ function windows_terminal() {
|
|||
this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect);
|
||||
}
|
||||
|
||||
// This does a rudimentary check if the platform is capable of PowerShell
|
||||
this.PowerShellCapable = function()
|
||||
{
|
||||
if (require('os').arch() == 'x64')
|
||||
|
|
@ -144,6 +174,7 @@ function windows_terminal() {
|
|||
}
|
||||
}
|
||||
|
||||
// Starts a Legacy Windows Terminal Session
|
||||
this.StartEx = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT, terminalTarget)
|
||||
{
|
||||
// The older windows terminal does not support
|
||||
|
|
@ -164,7 +195,9 @@ function windows_terminal() {
|
|||
this._stdinput = this._kernel32.GetStdHandle(STD_INPUT_HANDLE);
|
||||
this._stdoutput = this._kernel32.GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
this._connected = false;
|
||||
var coordScreen = GM.CreateVariable(4);
|
||||
|
||||
// Coord structure can be found at: https://learn.microsoft.com/en-us/windows/console/coord-str
|
||||
var coordScreen = GM.CreateVariable(4);
|
||||
coordScreen.Deref(0, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH);
|
||||
coordScreen.Deref(2, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT);
|
||||
|
||||
|
|
@ -172,10 +205,21 @@ function windows_terminal() {
|
|||
rect.Deref(4, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_WIDTH - 1);
|
||||
rect.Deref(6, 2).toBuffer().writeUInt16LE(CONSOLE_SCREEN_HEIGHT - 1);
|
||||
|
||||
if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0) {
|
||||
//
|
||||
// Reference for SetConsoleWindowInfo can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/setconsolewindowinfo
|
||||
//
|
||||
if (this._kernel32.SetConsoleWindowInfo(this._stdoutput, 1, rect).Val == 0)
|
||||
{
|
||||
throw ('Failed to set Console Screen Size');
|
||||
}
|
||||
if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0) {
|
||||
|
||||
//
|
||||
// Reference for SetConsoleScreenBufferSize can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/setconsolescreenbuffersize
|
||||
//
|
||||
if (this._kernel32.SetConsoleScreenBufferSize(this._stdoutput, coordScreen.Deref(0, 4).toBuffer().readUInt32LE()).Val == 0)
|
||||
{
|
||||
throw ('Failed to set Console Buffer Size');
|
||||
}
|
||||
|
||||
|
|
@ -278,8 +322,16 @@ function windows_terminal() {
|
|||
return (this.stopping);
|
||||
}
|
||||
|
||||
//
|
||||
// This function uses the SetWinEventHook() method, so we can hook
|
||||
// All events between EVENT_CONSOLE_CARET and EVENT_CONSOLE_END_APPLICATION
|
||||
//
|
||||
this._hookThread = function ()
|
||||
{
|
||||
//
|
||||
// Reference for SetWinEventHook() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook
|
||||
//
|
||||
var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });
|
||||
ret.userArgs = [];
|
||||
for (var a in arguments)
|
||||
|
|
@ -292,24 +344,43 @@ function windows_terminal() {
|
|||
var p = this._user32.SetWinEventHook.async(EVENT_CONSOLE_CARET, EVENT_CONSOLE_END_APPLICATION, 0, this._ConsoleWinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
|
||||
p.ready = ret;
|
||||
p.terminal = this;
|
||||
p.then(function (hwinEventHook) {
|
||||
if (hwinEventHook.Val == 0) {
|
||||
p.then(function (hwinEventHook)
|
||||
{
|
||||
if (hwinEventHook.Val == 0)
|
||||
{
|
||||
this.ready._rej('Error calling SetWinEventHook');
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
this.terminal.hwinEventHook = hwinEventHook;
|
||||
this.ready._res();
|
||||
this.terminal._GetMessage();
|
||||
}
|
||||
});
|
||||
|
||||
this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime) {
|
||||
//
|
||||
// This is the WINEVENTPROC callback for the WinEventHook we set
|
||||
//
|
||||
this._ConsoleWinEventProc.on('GlobalCallback', function (hhook, dwEvent, hwnd, idObject, idChild, idEventThread, swmsEventTime)
|
||||
{
|
||||
//
|
||||
// Reference for WINEVENTPROC can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wineventproc
|
||||
//
|
||||
if (!this.terminal.hwinEventHook || this.terminal.hwinEventHook.Val != hhook.Val) { return; }
|
||||
var buffer = null;
|
||||
|
||||
switch (dwEvent.Val) {
|
||||
//
|
||||
// Reference for Console WinEvents can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/console-winevents
|
||||
//
|
||||
|
||||
switch (dwEvent.Val)
|
||||
{
|
||||
case EVENT_CONSOLE_CARET:
|
||||
// The console caret has moved
|
||||
break;
|
||||
case EVENT_CONSOLE_UPDATE_REGION:
|
||||
// More than one character has changed
|
||||
if (!this.terminal.connected) {
|
||||
this.terminal.connected = true;
|
||||
this.terminal._stream._promise._res();
|
||||
|
|
@ -321,25 +392,30 @@ function windows_terminal() {
|
|||
}
|
||||
break;
|
||||
case EVENT_CONSOLE_UPDATE_SIMPLE:
|
||||
// A single character has changed
|
||||
//console.log('UPDATE SIMPLE: [X: ' + LOWORD(idObject.Val) + ' Y: ' + HIWORD(idObject.Val) + ' Char: ' + LOWORD(idChild.Val) + ' Attr: ' + HIWORD(idChild.Val) + ']');
|
||||
var simplebuffer = { data: [ Buffer.alloc(1, LOWORD(idChild.Val)) ], attributes: [ HIWORD(idChild.Val) ], width: 1, height: 1, x: LOWORD(idObject.Val), y: HIWORD(idObject.Val) };
|
||||
this.terminal._SendDataBuffer(simplebuffer);
|
||||
break;
|
||||
case EVENT_CONSOLE_UPDATE_SCROLL:
|
||||
// The console has scrolled
|
||||
//console.log('UPDATE SCROLL: [dx: ' + idObject.Val + ' dy: ' + idChild.Val + ']');
|
||||
this.terminal._SendScroll(idObject.Val, idChild.Val);
|
||||
break;
|
||||
case EVENT_CONSOLE_LAYOUT:
|
||||
// The console layout has changed.
|
||||
//console.log('CONSOLE_LAYOUT');
|
||||
//snprintf( Buf, 512, "Event Console LAYOUT!\r\n");
|
||||
//SendLayout();
|
||||
break;
|
||||
case EVENT_CONSOLE_START_APPLICATION:
|
||||
// A new console process has started
|
||||
//console.log('START APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
|
||||
//snprintf( Buf, 512, "Event Console START APPLICATION!\r\nProcess ID: %d - Child ID: %d\r\n\r\n", (int)idObject, (int)idChild);
|
||||
//SendConsoleEvent(dwEvent, idObject, idChild);
|
||||
break;
|
||||
case EVENT_CONSOLE_END_APPLICATION:
|
||||
// A console process has exited
|
||||
if (idObject.Val == this.terminal._hProcessID)
|
||||
{
|
||||
//console.log('END APPLICATION: [PID: ' + idObject.Val + ' CID: ' + idChild.Val + ']');
|
||||
|
|
@ -360,18 +436,44 @@ function windows_terminal() {
|
|||
return (ret);
|
||||
}
|
||||
|
||||
this._GetMessage = function () {
|
||||
// Retrieves a message from the calling thread's message queue
|
||||
this._GetMessage = function ()
|
||||
{
|
||||
//
|
||||
// Reference for GetMessage() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessage
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for TranslateMessage() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-translatemessage
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for DispatchMessage() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dispatchmessage
|
||||
//
|
||||
|
||||
if (this._user32.abort) { console.log('aborting loop'); return; }
|
||||
this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret) {
|
||||
this._user32.GetMessageA.async(this._user32.SetWinEventHook.async, MSG, 0, 0, 0).then(function (ret)
|
||||
{
|
||||
//console.log('GetMessage Response');
|
||||
if (ret.Val != 0) {
|
||||
if (ret.Val == -1) {
|
||||
if (ret.Val != 0)
|
||||
{
|
||||
if (ret.Val == -1)
|
||||
{
|
||||
// handle the error and possibly exit
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Translates virtual-key messages into character messages
|
||||
//console.log('TranslateMessage');
|
||||
this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () {
|
||||
this.nativeProxy._user32.TranslateMessage.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
|
||||
{
|
||||
// Dispatches a message to a window procedure
|
||||
//console.log('DispatchMessage');
|
||||
this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function () {
|
||||
this.nativeProxy._user32.DispatchMessageA.async(this.nativeProxy.user32.SetWinEventHook.async, MSG).then(function ()
|
||||
{
|
||||
this.nativeProxy.terminal._GetMessage();
|
||||
}, console.log);
|
||||
}, console.log);
|
||||
|
|
@ -384,7 +486,8 @@ function windows_terminal() {
|
|||
if (this.nativeProxy.terminal._hProcess == null) { return; }
|
||||
|
||||
this.nativeProxy.terminal.stopping._res();
|
||||
if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0) {
|
||||
if (this.nativeProxy.terminal._kernel32.TerminateProcess(this.nativeProxy.terminal._hProcess, 1067).Val == 0)
|
||||
{
|
||||
var e = this.nativeProxy.terminal._kernel32.GetLastError().Val;
|
||||
console.log('Unable to kill Terminal Process, error: ' + e);
|
||||
}
|
||||
|
|
@ -394,22 +497,38 @@ function windows_terminal() {
|
|||
console.log('REJECTED_UnhookWinEvent: ' + err);
|
||||
});
|
||||
}
|
||||
}, function (err) {
|
||||
}, function (err)
|
||||
{
|
||||
// Get Message Failed
|
||||
console.log('REJECTED_GETMessage: ' + err);
|
||||
});
|
||||
}
|
||||
this._WriteBuffer = function (buf) {
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
if (typeof (buf) == 'string') {
|
||||
|
||||
this._WriteBuffer = function (buf)
|
||||
{
|
||||
for (var i = 0; i < buf.length; ++i)
|
||||
{
|
||||
if (typeof (buf) == 'string')
|
||||
{
|
||||
this._WriteCharacter(buf.charCodeAt(i), false);
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
this._WriteCharacter(buf[i], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._WriteCharacter = function (key, bControlKey)
|
||||
{
|
||||
//
|
||||
// Reference for WriteConsoleInput() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/writeconsoleinput
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for INPUT_RECORD can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/input-record-str
|
||||
//
|
||||
|
||||
var rec = GM.CreateVariable(20);
|
||||
rec.Deref(0, 2).toBuffer().writeUInt16LE(KEY_EVENT); // rec.EventType
|
||||
rec.Deref(4, 4).toBuffer().writeUInt16LE(1); // rec.Event.KeyEvent.bKeyDown
|
||||
|
|
@ -427,62 +546,78 @@ function windows_terminal() {
|
|||
}
|
||||
|
||||
// Get the current visible screen buffer
|
||||
this._GetScreenBuffer = function (sx, sy, ex, ey) {
|
||||
this._GetScreenBuffer = function (sx, sy, ex, ey)
|
||||
{
|
||||
//
|
||||
// Reference for GetConsoleScreenBufferInfo() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for ReadConsoleOutput() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/readconsoleoutput
|
||||
//
|
||||
|
||||
var info = GM.CreateVariable(22);
|
||||
if (this._kernel32.GetConsoleScreenBufferInfo(this._stdoutput, info).Val == 0) { throw ('Error getting screen buffer info'); }
|
||||
|
||||
|
||||
var nWidth = info.Deref(14, 2).toBuffer().readUInt16LE() - info.Deref(10, 2).toBuffer().readUInt16LE() + 1;
|
||||
var nHeight = info.Deref(16, 2).toBuffer().readUInt16LE() - info.Deref(12, 2).toBuffer().readUInt16LE() + 1;
|
||||
|
||||
if (arguments[3] == null) {
|
||||
|
||||
if (arguments[3] == null)
|
||||
{
|
||||
// Use Default Parameters
|
||||
sx = 0;
|
||||
sy = 0;
|
||||
ex = nWidth - 1;
|
||||
ey = nHeight - 1;
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
if (this._scrx != 0) { sx += this._scrx; ex += this._scrx; }
|
||||
if (this._scry != 0) { sy += this._scry; ey += this._scry; }
|
||||
this._scrx = this._scry = 0;
|
||||
}
|
||||
|
||||
|
||||
var nBuffer = GM.CreateVariable((ex - sx + 1) * (ey - sy + 1) * 4);
|
||||
var size = GM.CreateVariable(4);
|
||||
size.Deref(0, 2).toBuffer().writeUInt16LE(ex - sx + 1, 0);
|
||||
size.Deref(2, 2).toBuffer().writeUInt16LE(ey - sy + 1, 0);
|
||||
|
||||
|
||||
var startCoord = GM.CreateVariable(4);
|
||||
startCoord.Deref(0, 2).toBuffer().writeUInt16LE(0, 0);
|
||||
startCoord.Deref(2, 2).toBuffer().writeUInt16LE(0, 0);
|
||||
|
||||
|
||||
var region = GM.CreateVariable(8);
|
||||
region.buffer = region.toBuffer();
|
||||
region.buffer.writeUInt16LE(sx, 0);
|
||||
region.buffer.writeUInt16LE(sy, 2);
|
||||
region.buffer.writeUInt16LE(ex, 4);
|
||||
region.buffer.writeUInt16LE(ey, 6);
|
||||
|
||||
if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0) {
|
||||
|
||||
if (this._kernel32.ReadConsoleOutputA(this._stdoutput, nBuffer, size.Deref(0, 4).toBuffer().readUInt32LE(), startCoord.Deref(0, 4).toBuffer().readUInt32LE(), region).Val == 0)
|
||||
{
|
||||
throw ('Unable to read Console Output');
|
||||
}
|
||||
|
||||
|
||||
// Lets convert the buffer into something simpler
|
||||
//var retVal = { data: Buffer.alloc((dw - dx + 1) * (dh - dy + 1)), attributes: Buffer.alloc((dw - dx + 1) * (dh - dy + 1)), width: dw - dx + 1, height: dh - dy + 1, x: dx, y: dy };
|
||||
|
||||
|
||||
var retVal = { data: [], attributes: [], width: ex - sx + 1, height: ey - sy + 1, x: sx, y: sy };
|
||||
var x, y, line, ifo, tmp, lineWidth = ex - sx + 1;
|
||||
|
||||
for (y = 0; y <= (ey - sy) ; ++y) {
|
||||
|
||||
for (y = 0; y <= (ey - sy) ; ++y)
|
||||
{
|
||||
retVal.data.push(Buffer.alloc(lineWidth));
|
||||
retVal.attributes.push(Buffer.alloc(lineWidth));
|
||||
|
||||
|
||||
line = nBuffer.Deref(y * lineWidth * 4, lineWidth * 4).toBuffer();
|
||||
for (x = 0; x < lineWidth; ++x) {
|
||||
for (x = 0; x < lineWidth; ++x)
|
||||
{
|
||||
retVal.data.peek()[x] = line[x * 4];
|
||||
retVal.attributes.peek()[x] = line[2 + (x * 4)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
|
||||
|
|
@ -507,6 +642,11 @@ function windows_terminal() {
|
|||
|
||||
this._SendScroll = function _SendScroll(dx, dy)
|
||||
{
|
||||
//
|
||||
// Reference for GetConsoleScreenBufferInfo() can be found at:
|
||||
// https://learn.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo
|
||||
//
|
||||
|
||||
if (this._scrollTimer || this._stream == null) { return; }
|
||||
|
||||
var info = GM.CreateVariable(22);
|
||||
|
|
@ -546,12 +686,15 @@ function LOWORD(val) { return (val & 0xFFFF); }
|
|||
function HIWORD(val) { return ((val >> 16) & 0xFFFF); }
|
||||
function GetEsc(op, args) { return (Buffer.from('\x1B[' + args.join(';') + op)); }
|
||||
function MeshConsole(msg) { require('MeshAgent').SendCommand({ "action": "msg", "type": "console", "value": JSON.stringify(msg) }); }
|
||||
function TranslateLine(x, y, data, attributes) {
|
||||
function TranslateLine(x, y, data, attributes)
|
||||
{
|
||||
var i, fcolor, bcolor, rcolor, fbright, bbright, lastAttr, fc, bc, rc, fb, bb, esc = [], output = [GetEsc('H', [y, x])];
|
||||
if (typeof attributes == 'number') { attributes = [ attributes ]; } // If we get a single attribute, turn it into an array.
|
||||
if (typeof attributes == 'number') { attributes = [attributes]; } // If we get a single attribute, turn it into an array.
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
if (lastAttr != attributes[i]) { // To boost performance, if the attribute is the same as the last one, skip this entire part.
|
||||
for (i = 0; i < data.length; i++)
|
||||
{
|
||||
if (lastAttr != attributes[i])
|
||||
{ // To boost performance, if the attribute is the same as the last one, skip this entire part.
|
||||
fc = (attributes[i] & 0x0007);
|
||||
fc = ((fc & 0x0001) << 2) + (fc & 0x0002) + ((fc & 0x0004) >> 2); // Foreground color
|
||||
bc = (attributes[i] & 0x0070) >> 4;
|
||||
|
|
@ -559,19 +702,19 @@ function TranslateLine(x, y, data, attributes) {
|
|||
rc = (attributes[i] & 0x4000); // Reverse color set
|
||||
fb = (attributes[i] & 0x0008) >> 3; // Bright foreground set
|
||||
bb = (attributes[i] & 0x0080); // Bright background set
|
||||
|
||||
|
||||
if (rc != rcolor) { if (rc != 0) { esc.push(7); } else { esc.push(0); fcolor = 7; bcolor = 0; fbright = 0; bbright = 0; } rcolor = rc; } // Reverse Color
|
||||
if (fc != fcolor) { esc.push(fc + 30); fcolor = fc; } // Set the foreground color if needed
|
||||
if (bc != bcolor) { esc.push(bc + 40); bcolor = bc; } // Set the background color if needed
|
||||
if (fb != fbright) { esc.push(2 - fb); fbright = fb; } // Set the bright foreground color if needed
|
||||
if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed
|
||||
if (bb != bbright) { if (bb == 0) { esc.push(bcolor + 40); } else { esc.push(bcolor + 100); bbright = bb; } } // Set bright Background color if needed
|
||||
|
||||
if (esc.length > 0) { output.push(GetEsc('m', esc)); esc = []; }
|
||||
lastAttr = attributes[i];
|
||||
}
|
||||
output.push(Buffer.from(String.fromCharCode(data[i])));
|
||||
}
|
||||
|
||||
|
||||
return Buffer.concat(output);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,20 +47,20 @@ function vt()
|
|||
|
||||
var GM = require('_GenericMarshal');
|
||||
var k32 = GM.CreateNativeProxy('kernel32.dll');
|
||||
k32.CreateMethod('CancelIoEx');
|
||||
k32.CreateMethod('CreatePipe');
|
||||
k32.CreateMethod('CreateProcessW');
|
||||
k32.CreateMethod('CreatePseudoConsole');
|
||||
k32.CreateMethod('CloseHandle');
|
||||
k32.CreateMethod('ClosePseudoConsole');
|
||||
k32.CreateMethod('GetProcessHeap');
|
||||
k32.CreateMethod('HeapAlloc');
|
||||
k32.CreateMethod('InitializeProcThreadAttributeList');
|
||||
k32.CreateMethod('ResizePseudoConsole');
|
||||
k32.CreateMethod('UpdateProcThreadAttribute');
|
||||
k32.CreateMethod('WriteFile');
|
||||
k32.CreateMethod('ReadFile');
|
||||
k32.CreateMethod('TerminateProcess');
|
||||
k32.CreateMethod('CancelIoEx'); // https://learn.microsoft.com/en-us/windows/win32/fileio/cancelioex-func
|
||||
k32.CreateMethod('CreatePipe'); // https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createpipe
|
||||
k32.CreateMethod('CreateProcessW'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
|
||||
k32.CreateMethod('CreatePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/createpseudoconsole
|
||||
k32.CreateMethod('CloseHandle'); // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
|
||||
k32.CreateMethod('ClosePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/closepseudoconsole
|
||||
k32.CreateMethod('GetProcessHeap'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-getprocessheap
|
||||
k32.CreateMethod('HeapAlloc'); // https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc
|
||||
k32.CreateMethod('InitializeProcThreadAttributeList'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist
|
||||
k32.CreateMethod('ResizePseudoConsole'); // https://learn.microsoft.com/en-us/windows/console/resizepseudoconsole
|
||||
k32.CreateMethod('UpdateProcThreadAttribute'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
|
||||
k32.CreateMethod('WriteFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile
|
||||
k32.CreateMethod('ReadFile'); // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
|
||||
k32.CreateMethod('TerminateProcess'); // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
|
||||
|
||||
var ret = { _h: GM.CreatePointer(), _consoleInput: GM.CreatePointer(), _consoleOutput: GM.CreatePointer(), _input: GM.CreatePointer(), _output: GM.CreatePointer(), k32: k32 };
|
||||
var attrSize = GM.CreateVariable(8);
|
||||
|
|
@ -77,18 +77,31 @@ function vt()
|
|||
throw ('Error calling CreatePseudoConsole()');
|
||||
}
|
||||
|
||||
//
|
||||
// Reference for STARTUPINFOEXW
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-startupinfoexw
|
||||
//
|
||||
|
||||
//
|
||||
// Reference for STARTUPINFOW
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow
|
||||
//
|
||||
|
||||
k32.InitializeProcThreadAttributeList(0, 1, 0, attrSize);
|
||||
attrList = GM.CreateVariable(attrSize.toBuffer().readUInt32LE());
|
||||
var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72);
|
||||
startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0);
|
||||
attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer());
|
||||
var startupinfoex = GM.CreateVariable(GM.PointerSize == 8 ? 112 : 72); // Create Structure, 64 bits is 112 bytes, 32 bits is 72 bytes
|
||||
startupinfoex.toBuffer().writeUInt32LE(GM.PointerSize == 8 ? 112 : 72, 0); // Write buffer size
|
||||
attrList.pointerBuffer().copy(startupinfoex.Deref(GM.PointerSize == 8 ? 104 : 68, GM.PointerSize).toBuffer()); // Write the reference to STARTUPINFOEX
|
||||
|
||||
if (k32.InitializeProcThreadAttributeList(attrList, 1, 0, attrSize).Val != 0)
|
||||
{
|
||||
if (k32.UpdateProcThreadAttribute(attrList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, ret._h.Deref(), GM.PointerSize, 0, 0).Val != 0)
|
||||
{
|
||||
if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0)
|
||||
if (k32.CreateProcessW(0, GM.CreateVariable(path, { wide: true }), 0, 0, 1, EXTENDED_STARTUPINFO_PRESENT, 0, 0, startupinfoex, pi).Val != 0) // Create the process to run in the pseudoconsole
|
||||
{
|
||||
//
|
||||
// Create a Stream Object, to be able to read/write data to the pseudoconsole
|
||||
//
|
||||
ret._startupinfoex = startupinfoex;
|
||||
ret._process = pi.Deref(0);
|
||||
ret._pid = pi.Deref(GM.PointerSize == 4 ? 8 : 16, 4).toBuffer().readUInt32LE();
|
||||
|
|
@ -111,6 +124,10 @@ function vt()
|
|||
flush();
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// The ProcessInfo object is signaled when the process exits
|
||||
//
|
||||
ds._obj = ret;
|
||||
ret._waiter = require('DescriptorEvents').addDescriptor(pi.Deref(0));
|
||||
ret._waiter.ds = ds;
|
||||
|
|
@ -151,6 +168,7 @@ function vt()
|
|||
ds._rpbufRead = GM.CreateVariable(4);
|
||||
ds.__read = function __read()
|
||||
{
|
||||
// Asyncronously read data from the pseudoconsole
|
||||
this._rp = this.terminal.k32.ReadFile.async(this.terminal._output.Deref(), this._rpbuf, this._rpbuf._size, this._rpbufRead, 0);
|
||||
this._rp.then(function ()
|
||||
{
|
||||
|
|
@ -173,6 +191,8 @@ function vt()
|
|||
}
|
||||
throw ('Internal Error');
|
||||
}
|
||||
|
||||
// This evaluates whether or not the powershell binary exists
|
||||
this.PowerShellCapable = function ()
|
||||
{
|
||||
if (require('os').arch() == 'x64')
|
||||
|
|
@ -184,10 +204,14 @@ function vt()
|
|||
return (require('fs').existsSync(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'));
|
||||
}
|
||||
}
|
||||
|
||||
// Start the PseudoConsole with the Command Prompt
|
||||
this.Start = function Start(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
|
||||
{
|
||||
return (this.Create(process.env['windir'] + '\\System32\\cmd.exe', CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT));
|
||||
}
|
||||
|
||||
// Start the PseduoConsole with PowerShell
|
||||
this.StartPowerShell = function StartPowerShell(CONSOLE_SCREEN_WIDTH, CONSOLE_SCREEN_HEIGHT)
|
||||
{
|
||||
if (require('os').arch() == 'x64')
|
||||
|
|
|
|||
|
|
@ -39,17 +39,90 @@ function getVolumes()
|
|||
{
|
||||
ret[v[i].DeviceID] = trimObject(v[i]);
|
||||
}
|
||||
|
||||
v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume');
|
||||
for (i in v)
|
||||
{
|
||||
var tmp = trimObject(v[i]);
|
||||
for (var k in tmp)
|
||||
try {
|
||||
v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume');
|
||||
for (i in v)
|
||||
{
|
||||
ret[tmp.DeviceID][k] = tmp[k];
|
||||
var tmp = trimObject(v[i]);
|
||||
for (var k in tmp)
|
||||
{
|
||||
ret[tmp.DeviceID][k] = tmp[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) { }
|
||||
return (ret);
|
||||
}
|
||||
|
||||
module.exports = { getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } } };
|
||||
function windows_volumes()
|
||||
{
|
||||
var promise = require('promise');
|
||||
var p1 = new promise(function (res, rej) { this._res = res; this._rej = rej; });
|
||||
var ret = {};
|
||||
var values = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_LogicalDisk', ['DeviceID', 'VolumeName', 'FileSystem', 'Size', 'FreeSpace', 'DriveType']);
|
||||
if(values[0]){
|
||||
for (var i = 0; i < values.length; ++i) {
|
||||
var drive = values[i]['DeviceID'].slice(0,-1);
|
||||
ret[drive] = {
|
||||
name: (values[i]['VolumeName'] ? values[i]['VolumeName'] : ""),
|
||||
type: (values[i]['FileSystem'] ? values[i]['FileSystem'] : "Unknown"),
|
||||
size: (values[i]['Size'] ? values[i]['Size'] : 0),
|
||||
sizeremaining: (values[i]['FreeSpace'] ? values[i]['FreeSpace'] : 0),
|
||||
removable: (values[i]['DriveType'] == 2),
|
||||
cdrom: (values[i]['DriveType'] == 5)
|
||||
};
|
||||
}
|
||||
}
|
||||
try {
|
||||
values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume', ['DriveLetter','ConversionStatus','ProtectionStatus']);
|
||||
if(values[0]){
|
||||
for (var i = 0; i < values.length; ++i) {
|
||||
var drive = values[i]['DriveLetter'].slice(0,-1);
|
||||
var statuses = {
|
||||
0: 'FullyDecrypted',
|
||||
1: 'FullyEncrypted',
|
||||
2: 'EncryptionInProgress',
|
||||
3: 'DecryptionInProgress',
|
||||
4: 'EncryptionPaused',
|
||||
5: 'DecryptionPaused'
|
||||
};
|
||||
ret[drive].volumeStatus = statuses.hasOwnProperty(values[i].ConversionStatus) ? statuses[values[i].ConversionStatus] : 'FullyDecrypted';
|
||||
ret[drive].protectionStatus = (values[i].ProtectionStatus == 0 ? 'Off' : (values[i].ProtectionStatus == 1 ? 'On' : 'Unknown'));
|
||||
try {
|
||||
var foundIDMarkedLine = false, foundMarkedLine = false, identifier = '', password = '';
|
||||
var keychild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'manage-bde -protectors -get ' + drive + ': -Type recoverypassword'], {});
|
||||
keychild.stdout.str = ''; keychild.stdout.on('data', function (c) { this.str += c.toString(); });
|
||||
keychild.waitExit();
|
||||
var lines = keychild.stdout.str.trim().split('\r\n');
|
||||
for (var x = 0; x < lines.length; x++) { // Loop each line
|
||||
var abc = lines[x].trim();
|
||||
var englishidpass = (abc !== '' && abc.includes('Numerical Password:')); // English ID
|
||||
var germanidpass = (abc !== '' && abc.includes('Numerisches Kennwort:')); // German ID
|
||||
var frenchidpass = (abc !== '' && abc.includes('Mot de passe num')); // French ID
|
||||
var englishpass = (abc !== '' && abc.includes('Password:') && !abc.includes('Numerical Password:')); // English Password
|
||||
var germanpass = (abc !== '' && abc.includes('Kennwort:') && !abc.includes('Numerisches Kennwort:')); // German Password
|
||||
var frenchpass = (abc !== '' && abc.includes('Mot de passe :') && !abc.includes('Mot de passe num')); // French Password
|
||||
if (englishidpass || germanidpass || frenchidpass|| englishpass || germanpass || frenchpass) {
|
||||
var nextline = lines[x + 1].trim();
|
||||
if (x + 1 < lines.length && (nextline !== '' && (nextline.startsWith('ID:') || nextline.startsWith('ID :')) )) {
|
||||
identifier = nextline.replace('ID:','').replace('ID :', '').trim();
|
||||
foundIDMarkedLine = true;
|
||||
}else if (x + 1 < lines.length && nextline !== '') {
|
||||
password = nextline;
|
||||
foundMarkedLine = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret[drive].identifier = (foundIDMarkedLine ? identifier : ''); // Set Bitlocker Identifier
|
||||
ret[drive].recoveryPassword = (foundMarkedLine ? password : ''); // Set Bitlocker Password
|
||||
} catch(ex) { } // just carry on as we cant get bitlocker key
|
||||
}
|
||||
}
|
||||
p1._res(ret);
|
||||
} catch (ex) { p1._res(ret); } // just return volumes as cant get encryption/bitlocker
|
||||
return (p1);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } },
|
||||
volumes_promise: windows_volumes
|
||||
};
|
||||
|
|
@ -485,8 +485,8 @@ function windows_execve(name, agentfilename, sessionid) {
|
|||
var cmd = require('_GenericMarshal').CreateVariable(process.env['windir'] + '\\system32\\cmd.exe', { wide: true });
|
||||
var args = require('_GenericMarshal').CreateVariable(3 * require('_GenericMarshal').PointerSize);
|
||||
var arg1 = require('_GenericMarshal').CreateVariable('cmd.exe', { wide: true });
|
||||
var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' +
|
||||
' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + cwd + agentfilename + '.update.exe"', { wide: true });
|
||||
var arg2 = require('_GenericMarshal').CreateVariable('/C net stop "' + name + '" & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCkudG9Mb3dlckNhc2UoKTsKICAgIHJlcXVpcmUoJ3Byb2Nlc3MtbWFuYWdlcicpLmVudW1lcmF0ZVByb2Nlc3NlcygpLnRoZW4oZnVuY3Rpb24gKHByb2MpCiAgICB7CiAgICAgICAgZm9yICh2YXIgcCBpbiBwcm9jKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKHByb2NbcF0ucGF0aCAmJiAocHJvY1twXS5wYXRoLnRvTG93ZXJDYXNlKCkgPT0gc2VydmljZUxvY2F0aW9uKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2NbcF0ucGlkKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwcm9jZXNzLmV4aXQoKTsKICAgIH0pOwp9CmNhdGNoIChlKQp7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQ==' +
|
||||
' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & net start "' + name + '" & erase "' + cwd + agentfilename + '.update.exe"', { wide: true });
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
const fs = require('fs');
|
||||
|
||||
var obj = {};
|
||||
obj.debug = false;
|
||||
obj.protocol = 3; // IDER
|
||||
obj.bytesToAmt = 0;
|
||||
obj.bytesFromAmt = 0;
|
||||
|
|
@ -38,7 +37,7 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
obj.tx_timeout = 0; // Default 0
|
||||
obj.heartbeat = 20000; // Default 20000
|
||||
obj.version = 1;
|
||||
obj.acc = "";
|
||||
obj.acc = null;
|
||||
obj.inSequence = 0;
|
||||
obj.outSequence = 0;
|
||||
obj.iderinfo = null;
|
||||
|
|
@ -46,47 +45,50 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
obj.iderStart = 0; // OnReboot = 0, Graceful = 1, Now = 2
|
||||
obj.floppy = null;
|
||||
obj.cdrom = null;
|
||||
obj.floppySize = null;
|
||||
obj.cdromSize = null;
|
||||
obj.floppyReady = false;
|
||||
obj.cdromReady = false;
|
||||
//obj.pingTimer = null;
|
||||
obj.sectorStats = null;
|
||||
obj.debug = false;
|
||||
|
||||
// Private method
|
||||
function debug() { if (obj.debug) { console.log(...arguments); } }
|
||||
|
||||
// Mode Sense
|
||||
var IDE_ModeSence_LS120Disk_Page_Array = String.fromCharCode(0x00, 0x26, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x10, 0xA9, 0x08, 0x20, 0x02, 0x00, 0x03, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00);
|
||||
var IDE_ModeSence_3F_LS120_Array = String.fromCharCode(0x00, 0x5c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x10, 0xA9, 0x08, 0x20, 0x02, 0x00, 0x03, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x11, 0x24, 0x31);
|
||||
var IDE_ModeSence_FloppyDisk_Page_Array = String.fromCharCode(0x00, 0x26, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x04, 0xB0, 0x02, 0x12, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00);
|
||||
var IDE_ModeSence_3F_Floppy_Array = String.fromCharCode(0x00, 0x5c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x04, 0xb0, 0x02, 0x12, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x11, 0x24, 0x31);
|
||||
var IDE_ModeSence_CD_1A_Array = String.fromCharCode(0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
//var IDE_ModeSence_CD_1B_Array = String.fromCharCode(0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_CD_1D_Array = String.fromCharCode(0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_CD_2A_Array = String.fromCharCode(0x00, 0x20, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
//var IDE_ModeSence_CD_01_Array = String.fromCharCode(0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_3F_CD_Array = String.fromCharCode(0x00, 0x28, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_LS120Disk_Page_Array = Buffer.from([0x00, 0x26, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x10, 0xA9, 0x08, 0x20, 0x02, 0x00, 0x03, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00]);
|
||||
var IDE_ModeSence_3F_LS120_Array = Buffer.from([0x00, 0x5c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x10, 0xA9, 0x08, 0x20, 0x02, 0x00, 0x03, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x11, 0x24, 0x31]);
|
||||
var IDE_ModeSence_FloppyDisk_Page_Array = Buffer.from([0x00, 0x26, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x1E, 0x04, 0xB0, 0x02, 0x12, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x00, 0x00]);
|
||||
var IDE_ModeSence_3F_Floppy_Array = Buffer.from([0x00, 0x5c, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x16, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x1e, 0x04, 0xb0, 0x02, 0x12, 0x02, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x00, 0x00, 0x08, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x11, 0x24, 0x31]);
|
||||
var IDE_ModeSence_CD_1A_Array = Buffer.from([0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
//var IDE_ModeSence_CD_1B_Array = Buffer.from([0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
var IDE_ModeSence_CD_1D_Array = Buffer.from([0x00, 0x12, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
var IDE_ModeSence_CD_2A_Array = Buffer.from([0x00, 0x20, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
//var IDE_ModeSence_CD_01_Array = Buffer.from([0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00]);
|
||||
var IDE_ModeSence_3F_CD_Array = Buffer.from([0x00, 0x28, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
|
||||
// 0x46 constant data
|
||||
var IDE_CD_ConfigArrayHeader = String.fromCharCode(0x00, 0x00,0x00, 0x28, 0x00, 0x00, 0x00, 0x08);
|
||||
var IDE_CD_ConfigArrayProfileList = String.fromCharCode(0x00, 0x00, 0x03, 0x04, 0x00, 0x08, 0x01, 0x00);
|
||||
var IDE_CD_ConfigArrayCore = String.fromCharCode(0x00, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, 0x02);
|
||||
var IDE_CD_Morphing = String.fromCharCode(0x00, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00);
|
||||
var IDE_CD_ConfigArrayRemovable = String.fromCharCode(0x00, 0x03, 0x03, 0x04, 0x29, 0x00, 0x00, 0x02);
|
||||
var IDE_CD_ConfigArrayRandom = String.fromCharCode(0x00, 0x10, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00);
|
||||
var IDE_CD_Read = String.fromCharCode(0x00, 0x1E, 0x03, 0x00);
|
||||
var IDE_CD_PowerManagement = String.fromCharCode(0x01, 0x00, 0x03, 0x00);
|
||||
var IDE_CD_Timeout = String.fromCharCode(0x01, 0x05, 0x03, 0x00);
|
||||
var IDE_CD_ConfigArrayHeader = Buffer.from([0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08]);
|
||||
var IDE_CD_ConfigArrayProfileList = Buffer.from([0x00, 0x00, 0x03, 0x04, 0x00, 0x08, 0x01, 0x00]);
|
||||
var IDE_CD_ConfigArrayCore = Buffer.from([0x00, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, 0x02]);
|
||||
var IDE_CD_Morphing = Buffer.from([0x00, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00]);
|
||||
var IDE_CD_ConfigArrayRemovable = Buffer.from([0x00, 0x03, 0x03, 0x04, 0x29, 0x00, 0x00, 0x02]);
|
||||
var IDE_CD_ConfigArrayRandom = Buffer.from([0x00, 0x10, 0x01, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00]);
|
||||
var IDE_CD_Read = Buffer.from([0x00, 0x1E, 0x03, 0x00]);
|
||||
var IDE_CD_PowerManagement = Buffer.from([0x01, 0x00, 0x03, 0x00]);
|
||||
var IDE_CD_Timeout = Buffer.from([0x01, 0x05, 0x03, 0x00]);
|
||||
|
||||
// 0x01 constant data
|
||||
var IDE_ModeSence_FloppyError_Recovery_Array = String.fromCharCode(0x00, 0x12, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_Ls120Error_Recovery_Array = String.fromCharCode(0x00, 0x12, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_CDError_Recovery_Array = String.fromCharCode(0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00);
|
||||
var IDE_ModeSence_FloppyError_Recovery_Array = Buffer.from([0x00, 0x12, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]);
|
||||
var IDE_ModeSence_Ls120Error_Recovery_Array = Buffer.from([0x00, 0x12, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00]);
|
||||
var IDE_ModeSence_CDError_Recovery_Array = Buffer.from([0x00, 0x0E, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00]);
|
||||
|
||||
// CD info and performance
|
||||
var RD_CD_DiskInfo = Buffer.from([0x00, 0x20, 0x0e, 0x01, 0x01, 0x01, 0x01, 0x20, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
var RD_CD_Performance = Buffer.from([0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00]);
|
||||
|
||||
// Private method, called by parent when it change state
|
||||
obj.xxStateChange = function (newstate) {
|
||||
debug("IDER-StateChange", newstate);
|
||||
if (obj.debug) console.log("IDER-StateChange", newstate);
|
||||
if (newstate == 0) { obj.Stop(); }
|
||||
if (newstate == 3) { obj.Start(); }
|
||||
}
|
||||
|
|
@ -100,8 +102,7 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
if (fs.existsSync(floppyPath) == false) { return 1; } // Floppy disk image does not exist
|
||||
var stats = fs.statSync(floppyPath);
|
||||
if ((stats.size % 512) != 0) { return 2; } // Invalid floppy disk image
|
||||
obj.floppySize = stats.size;
|
||||
obj.floppy = fs.openSync(floppyPath, 'r');
|
||||
obj.floppy = { size: stats.size, ptr: fs.openSync(floppyPath, 'r') };
|
||||
} catch (ex) { return 3; } // Unable to open floppy disk image
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +112,7 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
if (fs.existsSync(cdromPath) == false) { return 4; } // CDROM disk image does not exist
|
||||
var stats = fs.statSync(cdromPath);
|
||||
if ((stats.size % 512) != 0) { return 5; } // Invalid CDROM disk image
|
||||
obj.cdromSize = stats.size;
|
||||
obj.cdrom = fs.openSync(cdromPath, 'r');
|
||||
obj.cdrom = { size: stats.size, ptr: fs.openSync(cdromPath, 'r') };
|
||||
} catch (ex) { return 6; } // Unable to open CDROM disk image
|
||||
}
|
||||
|
||||
|
|
@ -122,9 +122,7 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
}
|
||||
|
||||
obj.Start = function () {
|
||||
debug("IDER-Start");
|
||||
|
||||
// Get ready
|
||||
if (obj.debug) { console.log('IDER-Start'); console.log(obj.floppy, obj.cdrom); }
|
||||
obj.bytesToAmt = 0;
|
||||
obj.bytesFromAmt = 0;
|
||||
obj.inSequence = 0;
|
||||
|
|
@ -132,87 +130,80 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
g_readQueue = [];
|
||||
|
||||
// Send first command, OPEN_SESSION
|
||||
obj.SendCommand(0x40, webserver.common.ShortToStrX(obj.rx_timeout) + webserver.common.ShortToStrX(obj.tx_timeout) + webserver.common.ShortToStrX(obj.heartbeat) + webserver.common.IntToStrX(obj.version));
|
||||
obj.SendCommand(0x40, Buffer.concat([ShortToStrX(obj.rx_timeout), ShortToStrX(obj.tx_timeout), ShortToStrX(obj.heartbeat), IntToStrX(obj.version)]));
|
||||
|
||||
// Send sector stats
|
||||
if (obj.sectorStats) {
|
||||
obj.sectorStats(0, 0, obj.floppy ? (obj.floppySize >> 9) : 0);
|
||||
obj.sectorStats(0, 1, obj.cdrom ? (obj.cdromSize >> 11) : 0);
|
||||
obj.sectorStats(0, 0, obj.floppy ? (obj.floppy.size >> 9) : 0);
|
||||
obj.sectorStats(0, 1, obj.cdrom ? (obj.cdrom.size >> 11) : 0);
|
||||
}
|
||||
|
||||
// Setup the ping timer
|
||||
//obj.pingTimer = setInterval(function () { obj.SendCommand(0x44); }, 5000);
|
||||
}
|
||||
|
||||
obj.Stop = function () {
|
||||
debug("IDER-Stop");
|
||||
|
||||
// Close the files
|
||||
if (obj.floppy) { fs.close(obj.floppy); delete obj.floppy; }
|
||||
if (obj.cdrom) { fs.close(obj.cdrom); delete obj.cdrom; }
|
||||
|
||||
// Clean up
|
||||
obj.floppySize = 0;
|
||||
obj.cdromSize = 0;
|
||||
obj.floppyReady = false;
|
||||
obj.cdromReady = false;
|
||||
|
||||
// Stop the redirection connection
|
||||
if (obj.debug) console.log('IDER-Stop');
|
||||
//if (obj.pingTimer) { clearInterval(obj.pingTimer); obj.pingTimer = null; }
|
||||
obj.parent.Stop();
|
||||
}
|
||||
|
||||
// Private method
|
||||
obj.ProcessData = function (data) {
|
||||
data = Buffer.from(data, 'binary');
|
||||
obj.bytesFromAmt += data.length;
|
||||
obj.acc += data;
|
||||
debug('IDER-ProcessData', obj.acc.length, webserver.common.rstr2hex(obj.acc));
|
||||
if (obj.acc == null) { obj.acc = data; } else { obj.acc = Buffer.concat([obj.acc, data]); }
|
||||
if (obj.debug) console.log('IDER-ProcessData', obj.acc.length, obj.acc.toString('hex'));
|
||||
|
||||
// Process as many commands as possible
|
||||
while (true) {
|
||||
while (obj.acc != null) {
|
||||
var len = obj.ProcessDataEx();
|
||||
if (len == 0) return;
|
||||
if (obj.inSequence != webserver.common.ReadIntX(obj.acc, 4)) {
|
||||
debug('ERROR: Out of sequence', obj.inSequence, webserver.common.ReadIntX(obj.acc, 4));
|
||||
if (obj.inSequence != ReadIntX(obj.acc, 4)) {
|
||||
if (obj.debug) console.log('ERROR: Out of sequence', obj.inSequence, ReadIntX(obj.acc, 4));
|
||||
obj.Stop();
|
||||
return;
|
||||
}
|
||||
obj.inSequence++;
|
||||
obj.acc = obj.acc.substring(len);
|
||||
if (len == obj.acc.length) { obj.acc = null; } else { obj.acc = obj.acc.slice(len); }
|
||||
}
|
||||
}
|
||||
|
||||
// Private method
|
||||
obj.SendCommand = function (cmdid, data, completed, dma) {
|
||||
if (data == null) { data = ''; }
|
||||
if (data == null) { data = Buffer.alloc(0); }
|
||||
var attributes = ((cmdid > 50) && (completed == true)) ? 2 : 0;
|
||||
if (dma) { attributes += 1; }
|
||||
var x = String.fromCharCode(cmdid, 0, 0, attributes) + webserver.common.IntToStrX(obj.outSequence++) + data;
|
||||
var x = Buffer.concat([Buffer.from([cmdid, 0, 0, attributes]), IntToStrX(obj.outSequence++), data]);
|
||||
obj.parent.xxSend(x);
|
||||
obj.bytesToAmt += x.length;
|
||||
if (cmdid != 0x4B) { debug('IDER-SendData', x.length, webserver.common.rstr2hex(x)); }
|
||||
//if (cmdid != 0x4B) { console.log('IDER-SendData', x.length, x.toString('hex')); }
|
||||
}
|
||||
|
||||
// CommandEndResponse (SCSI_SENSE)
|
||||
obj.SendCommandEndResponse = function (error, sense, device, asc, asq) {
|
||||
if (error) { obj.SendCommand(0x51, String.fromCharCode(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc5, 0, 3, 0, 0, 0, device, 0x50, 0, 0, 0), true); }
|
||||
else { obj.SendCommand(0x51, String.fromCharCode(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x87, (sense << 4), 3, 0, 0, 0, device, 0x51, sense, asc, asq), true); }
|
||||
if (error) { obj.SendCommand(0x51, Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc5, 0, 3, 0, 0, 0, device, 0x50, 0, 0, 0]), true); }
|
||||
else { obj.SendCommand(0x51, Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x87, (sense << 4), 3, 0, 0, 0, device, 0x51, sense, asc, asq]), true); }
|
||||
}
|
||||
|
||||
// DataToHost (SCSI_READ)
|
||||
obj.SendDataToHost = function (device, completed, data, dma) {
|
||||
var dmalen = (dma) ? 0 : data.length;
|
||||
if (completed == true) {
|
||||
obj.SendCommand(0x54, String.fromCharCode(0, (data.length & 0xff), (data.length >> 8), 0, dma ? 0xb4 : 0xb5, 0, 2, 0, (dmalen & 0xff), (dmalen >> 8), device, 0x58, 0x85, 0, 3, 0, 0, 0, device, 0x50, 0, 0, 0, 0, 0, 0) + data, completed, dma);
|
||||
obj.SendCommand(0x54, Buffer.concat([Buffer.from([0, (data.length & 0xff), (data.length >> 8), 0, dma ? 0xb4 : 0xb5, 0, 2, 0, (dmalen & 0xff), (dmalen >> 8), device, 0x58, 0x85, 0, 3, 0, 0, 0, device, 0x50, 0, 0, 0, 0, 0, 0]), data]), completed, dma);
|
||||
} else {
|
||||
obj.SendCommand(0x54, String.fromCharCode(0, (data.length & 0xff), (data.length >> 8), 0, dma ? 0xb4 : 0xb5, 0, 2, 0, (dmalen & 0xff), (dmalen >> 8), device, 0x58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + data, completed, dma);
|
||||
obj.SendCommand(0x54, Buffer.concat([Buffer.from([0, (data.length & 0xff), (data.length >> 8), 0, dma ? 0xb4 : 0xb5, 0, 2, 0, (dmalen & 0xff), (dmalen >> 8), device, 0x58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), data]), completed, dma);
|
||||
}
|
||||
}
|
||||
|
||||
// GetDataFromHost (SCSI_CHUNK)
|
||||
obj.SendGetDataFromHost = function (device, chunksize) {
|
||||
obj.SendCommand(0x52, String.fromCharCode(0, (chunksize & 0xff), (chunksize >> 8), 0, 0xb5, 0, 0, 0, (chunksize & 0xff), (chunksize >> 8), device, 0x58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), false);
|
||||
obj.SendCommand(0x52, Buffer.from([0, (chunksize & 0xff), (chunksize >> 8), 0, 0xb5, 0, 0, 0, (chunksize & 0xff), (chunksize >> 8), device, 0x58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), false);
|
||||
}
|
||||
|
||||
// DisableEnableFeatures (STATUS_DATA)
|
||||
// If type is REGS_TOGGLE (3), 4 bytes of data must be provided.
|
||||
obj.SendDisableEnableFeatures = function (type, data) { if (data == null) { data = ''; } obj.SendCommand(0x48, String.fromCharCode(type) + data); }
|
||||
obj.SendDisableEnableFeatures = function (type, data) { if (data == null) { data = ''; } obj.SendCommand(0x48, Buffer.concat([Buffer.from([type]), data])); }
|
||||
|
||||
// Private method
|
||||
obj.ProcessDataEx = function () {
|
||||
|
|
@ -220,130 +211,128 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
|
||||
// First 8 bytes are the header
|
||||
// CommandID + 0x000000 + Sequence Number
|
||||
//console.log('ProcessDataEx', obj.acc[0], obj.acc);
|
||||
|
||||
switch(obj.acc.charCodeAt(0)) {
|
||||
switch (obj.acc[0]) {
|
||||
case 0x41: // OPEN_SESSION
|
||||
if (obj.acc.length < 30) return 0;
|
||||
var len = obj.acc.charCodeAt(29);
|
||||
var len = obj.acc[29];
|
||||
if (obj.acc.length < (30 + len)) return 0;
|
||||
obj.iderinfo = {};
|
||||
obj.iderinfo.major = obj.acc.charCodeAt(8);
|
||||
obj.iderinfo.minor = obj.acc.charCodeAt(9);
|
||||
obj.iderinfo.fwmajor = obj.acc.charCodeAt(10);
|
||||
obj.iderinfo.fwminor = obj.acc.charCodeAt(11);
|
||||
obj.iderinfo.readbfr = webserver.common.ReadShortX(obj.acc, 16);
|
||||
obj.iderinfo.writebfr = webserver.common.ReadShortX(obj.acc, 18);
|
||||
obj.iderinfo.proto = obj.acc.charCodeAt(21);
|
||||
obj.iderinfo.iana = webserver.common.ReadIntX(obj.acc, 25);
|
||||
debug(obj.iderinfo);
|
||||
obj.iderinfo.major = obj.acc[8];
|
||||
obj.iderinfo.minor = obj.acc[9];
|
||||
obj.iderinfo.fwmajor = obj.acc[10];
|
||||
obj.iderinfo.fwminor = obj.acc[11];
|
||||
obj.iderinfo.readbfr = ReadShortX(obj.acc, 16);
|
||||
obj.iderinfo.writebfr = ReadShortX(obj.acc, 18);
|
||||
obj.iderinfo.proto = obj.acc[21];
|
||||
obj.iderinfo.iana = ReadIntX(obj.acc, 25);
|
||||
if (obj.debug) console.log(obj.iderinfo);
|
||||
|
||||
if (obj.iderinfo.proto != 0) {
|
||||
debug("Unknown proto", obj.iderinfo.proto);
|
||||
if (obj.debug) console.log("Unknown proto", obj.iderinfo.proto);
|
||||
obj.Stop();
|
||||
}
|
||||
if (obj.iderinfo.readbfr > 8192) {
|
||||
debug("Illegal read buffer size", obj.iderinfo.readbfr);
|
||||
if (obj.debug) console.log("Illegal read buffer size", obj.iderinfo.readbfr);
|
||||
obj.Stop();
|
||||
}
|
||||
if (obj.iderinfo.writebfr > 8192) {
|
||||
debug("Illegal write buffer size", obj.iderinfo.writebfr);
|
||||
if (obj.debug) console.log("Illegal write buffer size", obj.iderinfo.writebfr);
|
||||
obj.Stop();
|
||||
}
|
||||
|
||||
if (obj.iderStart == 0) { obj.SendDisableEnableFeatures(3, webserver.common.IntToStrX(0x01 + 0x08)); } // OnReboot
|
||||
else if (obj.iderStart == 1) { obj.SendDisableEnableFeatures(3, webserver.common.IntToStrX(0x01 + 0x10)); } // Graceful
|
||||
else if (obj.iderStart == 2) { obj.SendDisableEnableFeatures(3, webserver.common.IntToStrX(0x01 + 0x18)); } // Now
|
||||
if (obj.iderStart == 0) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x08)); } // OnReboot
|
||||
else if (obj.iderStart == 1) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x10)); } // Graceful
|
||||
else if (obj.iderStart == 2) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x18)); } // Now
|
||||
//obj.SendDisableEnableFeatures(1); // GetSupportedFeatures
|
||||
return 30 + len;
|
||||
case 0x43: // CLOSE
|
||||
debug('CLOSE');
|
||||
if (obj.debug) console.log('CLOSE');
|
||||
obj.Stop();
|
||||
return 8;
|
||||
case 0x44: // KEEPALIVEPING
|
||||
obj.SendCommand(0x45); // Send PONG back
|
||||
return 8;
|
||||
case 0x45: // KEEPALIVEPONG
|
||||
debug('PONG');
|
||||
if (obj.debug) console.log('PONG');
|
||||
return 8;
|
||||
case 0x46: // RESETOCCURED
|
||||
if (obj.acc.length < 9) return 0;
|
||||
var resetMask = obj.acc.charCodeAt(8);
|
||||
var resetMask = obj.acc[8];
|
||||
if (g_media === null) {
|
||||
// No operations are pending
|
||||
obj.SendCommand(0x47); // Send ResetOccuredResponse
|
||||
debug('RESETOCCURED1', resetMask);
|
||||
if (obj.debug) console.log('RESETOCCURED1', resetMask);
|
||||
} else {
|
||||
// Operations are being done, sent the reset once completed.
|
||||
g_reset = true;
|
||||
debug('RESETOCCURED2', resetMask);
|
||||
if (obj.debug) console.log('RESETOCCURED2', resetMask);
|
||||
}
|
||||
return 9;
|
||||
case 0x49: // STATUS_DATA - DisableEnableFeaturesReply
|
||||
if (obj.acc.length < 13) return 0;
|
||||
var type = obj.acc.charCodeAt(8);
|
||||
var value = webserver.common.ReadIntX(obj.acc, 9);
|
||||
debug('STATUS_DATA', type, value);
|
||||
switch (type)
|
||||
{
|
||||
var type = obj.acc[8];
|
||||
var value = ReadIntX(obj.acc, 9);
|
||||
if (obj.debug) console.log('STATUS_DATA', type, value);
|
||||
switch (type) {
|
||||
case 1: // REGS_AVAIL
|
||||
if (value & 1) {
|
||||
if (obj.iderStart == 0) { obj.SendDisableEnableFeatures(3, webserver.common.IntToStrX(0x01 + 0x08)); } // OnReboot
|
||||
else if (obj.iderStart == 1) { obj.SendDisableEnableFeatures(3, webserver.common.IntToStrX(0x01 + 0x10)); } // Graceful
|
||||
else if (obj.iderStart == 2) { obj.SendDisableEnableFeatures(3, webserver.common.IntToStrX(0x01 + 0x18)); } // Now
|
||||
if (obj.iderStart == 0) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x08)); } // OnReboot
|
||||
else if (obj.iderStart == 1) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x10)); } // Graceful
|
||||
else if (obj.iderStart == 2) { obj.SendDisableEnableFeatures(3, IntToStrX(0x01 + 0x18)); } // Now
|
||||
}
|
||||
break;
|
||||
case 2: // REGS_STATUS
|
||||
obj.enabled = (value & 2) ? true : false;
|
||||
debug("IDER Status: " + obj.enabled);
|
||||
if (obj.debug) console.log("IDER Status: " + obj.enabled);
|
||||
break;
|
||||
case 3: // REGS_TOGGLE
|
||||
if (value != 1) {
|
||||
debug("Register toggle failure");
|
||||
if (obj.debug) console.log("Register toggle failure");
|
||||
} //else { obj.SendDisableEnableFeatures(2); }
|
||||
break;
|
||||
}
|
||||
return 13;
|
||||
case 0x4A: // ERROR OCCURED
|
||||
if (obj.acc.length < 11) return 0;
|
||||
debug('IDER: ABORT', obj.acc.charCodeAt(8));
|
||||
if (obj.debug) console.log('IDER: ABORT', obj.acc[8]);
|
||||
//obj.Stop();
|
||||
return 11;
|
||||
case 0x4B: // HEARTBEAT
|
||||
//debug('HEARTBEAT');
|
||||
//console.log('HEARTBEAT');
|
||||
return 8;
|
||||
case 0x50: // COMMAND WRITTEN
|
||||
if (obj.acc.length < 28) return 0;
|
||||
var device = (obj.acc.charCodeAt(14) & 0x10) ? 0xB0 : 0xA0;
|
||||
var deviceFlags = obj.acc.charCodeAt(14);
|
||||
var cdb = obj.acc.substring(16, 28);
|
||||
var featureRegister = obj.acc.charCodeAt(9);
|
||||
debug('SCSI_CMD', device, webserver.common.rstr2hex(cdb), featureRegister, deviceFlags);
|
||||
var device = (obj.acc[14] & 0x10) ? 0xB0 : 0xA0;
|
||||
var deviceFlags = obj.acc[14];
|
||||
var cdb = obj.acc.slice(16, 28);
|
||||
var featureRegister = obj.acc[9];
|
||||
if (obj.debug) console.log('SCSI_CMD', device, cdb.toString('hex'), featureRegister, deviceFlags);
|
||||
handleSCSI(device, cdb, featureRegister, deviceFlags);
|
||||
return 28;
|
||||
case 0x53: // DATA FROM HOST
|
||||
if (obj.acc.length < 14) return 0;
|
||||
var len = webserver.common.ReadShortX(obj.acc, 9);
|
||||
var len = ReadShortX(obj.acc, 9);
|
||||
if (obj.acc.length < (14 + len)) return 0;
|
||||
debug('SCSI_WRITE, len = ' + (14 + len));
|
||||
obj.SendCommand(0x51, String.fromCharCode(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x70, 0x03, 0x00, 0x00, 0x00, 0xa0, 0x51, 0x07, 0x27, 0x00), true);
|
||||
if (obj.debug) console.log('SCSI_WRITE, len = ' + (14 + len));
|
||||
obj.SendCommand(0x51, Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x70, 0x03, 0x00, 0x00, 0x00, 0xa0, 0x51, 0x07, 0x27, 0x00]), true);
|
||||
return 14 + len;
|
||||
default:
|
||||
debug('Unknown IDER command', obj.acc[0]);
|
||||
if (obj.debug) console.log('Unknown IDER command', obj.acc[0]);
|
||||
obj.Stop();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function handleSCSI(dev, cdb, featureRegister, deviceFlags)
|
||||
{
|
||||
function handleSCSI(dev, cdb, featureRegister, deviceFlags) {
|
||||
var lba;
|
||||
var len;
|
||||
|
||||
switch(cdb.charCodeAt(0))
|
||||
{
|
||||
switch (cdb[0]) {
|
||||
case 0x00: // TEST_UNIT_READY:
|
||||
debug("SCSI: TEST_UNIT_READY", dev);
|
||||
if (obj.debug) console.log("SCSI: TEST_UNIT_READY", dev);
|
||||
switch (dev) {
|
||||
case 0xA0: // DEV_FLOPPY
|
||||
if (obj.floppy == null) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
|
|
@ -354,34 +343,34 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
if (obj.cdromReady == false) { obj.cdromReady = true; obj.SendCommandEndResponse(1, 0x06, dev, 0x28, 0x00); return -1; } // Switch to ready
|
||||
break;
|
||||
default:
|
||||
debug("SCSI Internal error 3", dev);
|
||||
if (obj.debug) console.log("SCSI Internal error 3", dev);
|
||||
return -1;
|
||||
}
|
||||
obj.SendCommandEndResponse(1, 0x00, dev, 0x00, 0x00); // Indicate ready
|
||||
break;
|
||||
case 0x08: // READ_6
|
||||
lba = ((cdb.charCodeAt(1) & 0x1f) << 16) + (cdb.charCodeAt(2) << 8) + cdb.charCodeAt(3);
|
||||
len = cdb.charCodeAt(4);
|
||||
lba = ((cdb[1] & 0x1f) << 16) + (cdb[2] << 8) + cdb[3];
|
||||
len = cdb[4];
|
||||
if (len == 0) { len = 256; }
|
||||
debug("SCSI: READ_6", dev, lba, len);
|
||||
if (obj.debug) console.log("SCSI: READ_6", dev, lba, len);
|
||||
sendDiskData(dev, lba, len, featureRegister);
|
||||
break;
|
||||
case 0x0a: // WRITE_6
|
||||
lba = ((cdb.charCodeAt(1) & 0x1f) << 16) + (cdb.charCodeAt(2) << 8) + cdb.charCodeAt(3);
|
||||
len = cdb.charCodeAt(4);
|
||||
lba = ((cdb[1] & 0x1f) << 16) + (cdb[2] << 8) + cdb[3];
|
||||
len = cdb[4];
|
||||
if (len == 0) { len = 256; }
|
||||
debug("SCSI: WRITE_6", dev, lba, len);
|
||||
if (obj.debug) console.log("SCSI: WRITE_6", dev, lba, len);
|
||||
obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); // Write is not supported, remote no medium.
|
||||
return -1;
|
||||
/*
|
||||
case 0x15: // MODE_SELECT_6:
|
||||
debug("SCSI ERROR: MODE_SELECT_6", dev);
|
||||
obj.SendCommandEndResponse(1, 0x05, dev, 0x20, 0x00);
|
||||
return -1;
|
||||
*/
|
||||
/*
|
||||
case 0x15: // MODE_SELECT_6:
|
||||
console.log("SCSI ERROR: MODE_SELECT_6", dev);
|
||||
obj.SendCommandEndResponse(1, 0x05, dev, 0x20, 0x00);
|
||||
return -1;
|
||||
*/
|
||||
case 0x1a: // MODE_SENSE_6
|
||||
debug("SCSI: MODE_SENSE_6", dev);
|
||||
if ((cdb.charCodeAt(2) == 0x3f) && (cdb.charCodeAt(3) == 0x00)) {
|
||||
if (obj.debug) console.log("SCSI: MODE_SENSE_6", dev);
|
||||
if ((cdb[2] == 0x3f) && (cdb[3] == 0x00)) {
|
||||
var a = 0, b = 0;
|
||||
switch (dev) {
|
||||
case 0xA0: // DEV_FLOPPY
|
||||
|
|
@ -395,90 +384,89 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
b = 0x80;
|
||||
break;
|
||||
default:
|
||||
debug("SCSI Internal error 6", dev);
|
||||
if (obj.debug) console.log("SCSI Internal error 6", dev);
|
||||
return -1;
|
||||
}
|
||||
obj.SendDataToHost(dev, true, String.fromCharCode(0, a, b, 0), featureRegister & 1);
|
||||
obj.SendDataToHost(dev, true, Buffer.from([0, a, b, 0]), featureRegister & 1);
|
||||
return;
|
||||
}
|
||||
obj.SendCommandEndResponse(1, 0x05, dev, 0x24, 0x00);
|
||||
break;
|
||||
case 0x1b: // START_STOP (Called when you eject the CDROM)
|
||||
//var immediate = cdb.charCodeAt(1) & 0x01;
|
||||
//var loej = cdb.charCodeAt(4) & 0x02;
|
||||
//var start = cdb.charCodeAt(4) & 0x01;
|
||||
//var immediate = cdb[1] & 0x01;
|
||||
//var loej = cdb[4] & 0x02;
|
||||
//var start = cdb[4] & 0x01;
|
||||
obj.SendCommandEndResponse(1, 0, dev);
|
||||
break;
|
||||
case 0x1e: // LOCK_UNLOCK - ALLOW_MEDIUM_REMOVAL
|
||||
debug("SCSI: ALLOW_MEDIUM_REMOVAL", dev);
|
||||
if (obj.debug) console.log("SCSI: ALLOW_MEDIUM_REMOVAL", dev);
|
||||
if ((dev == 0xA0) && (obj.floppy == null)) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
if ((dev == 0xB0) && (obj.cdrom == null)) { obj.SendCommandEndResponse(1, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
obj.SendCommandEndResponse(1, 0x00, dev, 0x00, 0x00);
|
||||
break;
|
||||
case 0x23: // READ_FORMAT_CAPACITIES (Floppy only)
|
||||
debug("SCSI: READ_FORMAT_CAPACITIES", dev);
|
||||
var buflen = webserver.common.ReadShort(cdb, 7);
|
||||
if (obj.debug) console.log("SCSI: READ_FORMAT_CAPACITIES", dev);
|
||||
var buflen = ReadShort(cdb, 7);
|
||||
var mediaStatus = 0, sectors;
|
||||
var mcSize = buflen / 8; // Capacity descriptor size is 8
|
||||
|
||||
switch (dev) {
|
||||
case 0xA0: // DEV_FLOPPY
|
||||
if ((obj.floppy == null) || (obj.floppySize == 0)) { obj.SendCommandEndResponse(0, 0x05, dev, 0x24, 0x00); return -1; }
|
||||
sectors = (obj.floppySize >> 9) - 1;
|
||||
if ((obj.floppy == null) || (obj.floppy.size == 0)) { obj.SendCommandEndResponse(0, 0x05, dev, 0x24, 0x00); return -1; }
|
||||
sectors = (obj.floppy.size >> 9) - 1;
|
||||
break;
|
||||
case 0xB0: // DEV_CDDVD
|
||||
if ((obj.cdrom == null) || (obj.cdromSize == 0)) { obj.SendCommandEndResponse(0, 0x05, dev, 0x24, 0x00); return -1; }
|
||||
sectors = (obj.cdromSize >> 11) - 1; // Number 2048 byte blocks
|
||||
if ((obj.cdrom == null) || (obj.cdrom.size == 0)) { obj.SendCommandEndResponse(0, 0x05, dev, 0x24, 0x00); return -1; }
|
||||
sectors = (obj.cdrom.size >> 11) - 1; // Number 2048 byte blocks
|
||||
break;
|
||||
default:
|
||||
debug("SCSI Internal error 4", dev);
|
||||
if (obj.debug) console.log("SCSI Internal error 4", dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
obj.SendDataToHost(dev, true, webserver.common.IntToStr(8) + String.fromCharCode(0x00, 0x00, 0x0b, 0x40, 0x02, 0x00, 0x02, 0x00), featureRegister & 1);
|
||||
obj.SendDataToHost(dev, true, Buffer.concat([IntToStr(8), Buffer.from([0x00, 0x00, 0x0b, 0x40, 0x02, 0x00, 0x02, 0x00])]), featureRegister & 1);
|
||||
break;
|
||||
case 0x25: // READ_CAPACITY
|
||||
debug("SCSI: READ_CAPACITY", dev);
|
||||
if (obj.debug) console.log("SCSI: READ_CAPACITY", dev);
|
||||
var len = 0;
|
||||
switch(dev)
|
||||
{
|
||||
switch (dev) {
|
||||
case 0xA0: // DEV_FLOPPY
|
||||
if ((obj.floppy == null) || (obj.floppySize == 0)) { obj.SendCommandEndResponse(0, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
if (obj.floppy != null) { len = (obj.floppySize >> 9) - 1; }
|
||||
debug('DEV_FLOPPY', len); // Number 512 byte blocks
|
||||
if ((obj.floppy == null) || (obj.floppy.size == 0)) { obj.SendCommandEndResponse(0, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
if (obj.floppy != null) { len = (obj.floppy.size >> 9) - 1; }
|
||||
if (obj.debug) console.log('DEV_FLOPPY', len); // Number 512 byte blocks
|
||||
break;
|
||||
case 0xB0: // DEV_CDDVD
|
||||
if ((obj.floppy == null) || (obj.floppySize == 0)) { obj.SendCommandEndResponse(0, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
if (obj.cdrom != null) { len = (obj.cdromSize >> 11) - 1; } // Number 2048 byte blocks
|
||||
debug('DEV_CDDVD', len);
|
||||
if ((obj.cdrom == null) || (obj.cdrom.size == 0)) { obj.SendCommandEndResponse(0, 0x02, dev, 0x3a, 0x00); return -1; }
|
||||
if (obj.cdrom != null) { len = (obj.cdrom.size >> 11) - 1; } // Number 2048 byte blocks
|
||||
if (obj.debug) console.log('DEV_CDDVD', len);
|
||||
break;
|
||||
default:
|
||||
debug("SCSI Internal error 4", dev);
|
||||
if (obj.debug) console.log("SCSI Internal error 4", dev);
|
||||
return -1;
|
||||
}
|
||||
//if (dev == 0xA0) { dev = 0x00; } else { dev = 0x10; } // Weird but seems to work.
|
||||
debug("SCSI: READ_CAPACITY2", dev, deviceFlags);
|
||||
obj.SendDataToHost(deviceFlags, true, webserver.common.IntToStr(len) + String.fromCharCode(0, 0, ((dev == 0xB0) ? 0x08 : 0x02), 0), featureRegister & 1);
|
||||
if (obj.debug) console.log("SCSI: READ_CAPACITY2", dev, deviceFlags);
|
||||
obj.SendDataToHost(deviceFlags, true, Buffer.concat([IntToStr(len), Buffer.from([0, 0, ((dev == 0xB0) ? 0x08 : 0x02), 0])]), featureRegister & 1);
|
||||
break;
|
||||
case 0x28: // READ_10
|
||||
lba = webserver.common.ReadInt(cdb, 2);
|
||||
len = webserver.common.ReadShort(cdb, 7);
|
||||
debug("SCSI: READ_10", dev, lba, len);
|
||||
lba = ReadInt(cdb, 2);
|
||||
len = ReadShort(cdb, 7);
|
||||
if (obj.debug) console.log("SCSI: READ_10", dev, lba, len);
|
||||
sendDiskData(dev, lba, len, featureRegister);
|
||||
break;
|
||||
case 0x2a: // WRITE_10 (Floppy only)
|
||||
case 0x2e: // WRITE_AND_VERIFY (Floppy only)
|
||||
lba = webserver.common.ReadInt(cdb, 2);
|
||||
len = webserver.common.ReadShort(cdb, 7);
|
||||
debug("SCSI: WRITE_10", dev, lba, len);
|
||||
lba = ReadInt(cdb, 2);
|
||||
len = ReadShort(cdb, 7);
|
||||
if (obj.debug) console.log("SCSI: WRITE_10", dev, lba, len);
|
||||
obj.SendGetDataFromHost(dev, 512 * len); // Floppy writes only, accept sectors of 512 bytes
|
||||
break;
|
||||
case 0x43: // READ_TOC (CD Audio only)
|
||||
var buflen = webserver.common.ReadShort(cdb, 7);
|
||||
var msf = cdb.charCodeAt(1) & 0x02;
|
||||
var format = cdb.charCodeAt(2) & 0x07;
|
||||
if (format == 0) { format = cdb.charCodeAt(9) >> 6; }
|
||||
debug("SCSI: READ_TOC, dev=" + dev + ", buflen=" + buflen + ", msf=" + msf + ", format=" + format);
|
||||
var buflen = ReadShort(cdb, 7);
|
||||
var msf = cdb[1] & 0x02;
|
||||
var format = cdb[2] & 0x07;
|
||||
if (format == 0) { format = cdb[9] >> 6; }
|
||||
if (obj.debug) console.log("SCSI: READ_TOC, dev=" + dev + ", buflen=" + buflen + ", msf=" + msf + ", format=" + format);
|
||||
|
||||
switch (dev) {
|
||||
case 0xA0: // DEV_FLOPPY
|
||||
|
|
@ -488,96 +476,100 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
// NOP
|
||||
break;
|
||||
default:
|
||||
debug("SCSI Internal error 9", dev);
|
||||
if (obj.debug) console.log("SCSI Internal error 9", dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (format == 1) { obj.SendDataToHost(dev, true, String.fromCharCode(0x00, 0x0a, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00), featureRegister & 1); }
|
||||
if (format == 1) { obj.SendDataToHost(dev, true, Buffer.from([0x00, 0x0a, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00]), featureRegister & 1); }
|
||||
else if (format == 0) {
|
||||
if (msf) {
|
||||
obj.SendDataToHost(dev, true, String.fromCharCode(0x00, 0x12, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0xaa, 0x00, 0x00, 0x00, 0x34, 0x13), featureRegister & 1);
|
||||
obj.SendDataToHost(dev, true, Buffer.from([0x00, 0x12, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0xaa, 0x00, 0x00, 0x00, 0x34, 0x13]), featureRegister & 1);
|
||||
} else {
|
||||
obj.SendDataToHost(dev, true, String.fromCharCode(0x00, 0x12, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00), featureRegister & 1);
|
||||
obj.SendDataToHost(dev, true, Buffer.from([0x00, 0x12, 0x01, 0x01, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00]), featureRegister & 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x46: // GET_CONFIGURATION
|
||||
var sendall = (cdb.charCodeAt(1) != 2);
|
||||
var firstcode = webserver.common.ReadShort(cdb, 2);
|
||||
var buflen = webserver.common.ReadShort(cdb, 7);
|
||||
var sendall = (cdb[1] != 2);
|
||||
var firstcode = ReadShort(cdb, 2);
|
||||
var buflen = ReadShort(cdb, 7);
|
||||
|
||||
debug("SCSI: GET_CONFIGURATION", dev, sendall, firstcode, buflen);
|
||||
|
||||
if (buflen == 0) { obj.SendDataToHost(dev, true, webserver.common.IntToStr(0x003c) + webserver.common.IntToStr(0x0008), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
|
||||
if (obj.debug) console.log("SCSI: GET_CONFIGURATION", dev, sendall, firstcode, buflen);
|
||||
if (buflen == 0) { obj.SendDataToHost(dev, true, Buffer.concat([IntToStr(0x003c), IntToStr(0x0008)]), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
|
||||
|
||||
// Set the header
|
||||
var r = webserver.common.IntToStr(0x0008);
|
||||
var r = null;
|
||||
|
||||
// Add the data
|
||||
if (firstcode == 0) { r += IDE_CD_ConfigArrayProfileList; }
|
||||
if ((firstcode == 0x1) || (sendall && (firstcode < 0x1))) { r += IDE_CD_ConfigArrayCore; }
|
||||
if ((firstcode == 0x2) || (sendall && (firstcode < 0x2))) { r += IDE_CD_Morphing; }
|
||||
if ((firstcode == 0x3) || (sendall && (firstcode < 0x3))) { r += IDE_CD_ConfigArrayRemovable; }
|
||||
if ((firstcode == 0x10) || (sendall && (firstcode < 0x10))) { r += IDE_CD_ConfigArrayRandom; }
|
||||
if ((firstcode == 0x1E) || (sendall && (firstcode < 0x1E))) { r += IDE_CD_Read; }
|
||||
if ((firstcode == 0x100) || (sendall && (firstcode < 0x100))) { r += IDE_CD_PowerManagement; }
|
||||
if ((firstcode == 0x105) || (sendall && (firstcode < 0x105))) { r += IDE_CD_Timeout; }
|
||||
if (firstcode == 0) { r = IDE_CD_ConfigArrayProfileList; }
|
||||
if ((firstcode == 0x1) || (sendall && (firstcode < 0x1))) { r = IDE_CD_ConfigArrayCore; }
|
||||
if ((firstcode == 0x2) || (sendall && (firstcode < 0x2))) { r = IDE_CD_Morphing; }
|
||||
if ((firstcode == 0x3) || (sendall && (firstcode < 0x3))) { r = IDE_CD_ConfigArrayRemovable; }
|
||||
if ((firstcode == 0x10) || (sendall && (firstcode < 0x10))) { r = IDE_CD_ConfigArrayRandom; }
|
||||
if ((firstcode == 0x1E) || (sendall && (firstcode < 0x1E))) { r = IDE_CD_Read; }
|
||||
if ((firstcode == 0x100) || (sendall && (firstcode < 0x100))) { r = IDE_CD_PowerManagement; }
|
||||
if ((firstcode == 0x105) || (sendall && (firstcode < 0x105))) { r = IDE_CD_Timeout; }
|
||||
|
||||
// Set the length
|
||||
r = webserver.common.IntToStr(r.length) + r;
|
||||
if (r == null) {
|
||||
//console.log('NOT RIGHT', sendall, firstcode, cdb[2], cdb[3]);
|
||||
//process.exit(0);
|
||||
r = Buffer.concat([IntToStr(0x0008), IntToStr(4)]);
|
||||
} else {
|
||||
r = Buffer.concat([IntToStr(0x0008), IntToStr(r.length + 4), r]);
|
||||
}
|
||||
|
||||
// Cut the length to buflen if needed
|
||||
if (r.length > buflen) { r = r.substring(0, buflen); }
|
||||
if (r.length > buflen) { r = r.slice(0, buflen); }
|
||||
|
||||
obj.SendDataToHost(dev, true, r, featureRegister & 1);
|
||||
return -1;
|
||||
case 0x4a: // GET_EV_STATUS - GET_EVENT_STATUS_NOTIFICATION
|
||||
//var buflen = (cdb.charCodeAt(7) << 8) + cdb.charCodeAt(8);
|
||||
//if (buflen == 0) { obj.SendDataToHost(dev, true, webserver.common.IntToStr(0x003c) + webserver.common.IntToStr(0x0008), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
|
||||
debug("SCSI: GET_EVENT_STATUS_NOTIFICATION", dev, cdb.charCodeAt(1), cdb.charCodeAt(4), cdb.charCodeAt(9));
|
||||
if ((cdb.charCodeAt(1) != 0x01) && (cdb.charCodeAt(4) != 0x10)) {
|
||||
debug('SCSI ERROR');
|
||||
//var buflen = (cdb[7] << 8) + cdb[8];
|
||||
//if (buflen == 0) { obj.SendDataToHost(dev, true, Buffer.concat([IntToStr(0x003c), IntToStr(0x0008)]), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
|
||||
if (obj.debug) console.log("SCSI: GET_EVENT_STATUS_NOTIFICATION", dev, cdb[1], cdb[4], cdb[9]);
|
||||
if ((cdb[1] != 0x01) && (cdb[4] != 0x10)) {
|
||||
if (obj.debug) console.log('SCSI ERROR');
|
||||
obj.SendCommandEndResponse(1, 0x05, dev, 0x26, 0x01);
|
||||
break;
|
||||
}
|
||||
var present = 0x00;
|
||||
if ((dev == 0xA0) && (obj.floppy != null)) { present = 0x02; }
|
||||
else if ((dev == 0xB0) && (obj.cdrom != null)) { present = 0x02; }
|
||||
obj.SendDataToHost(dev, true, String.fromCharCode(0x00, present, 0x80, 0x00), featureRegister & 1); // This is the original version, 4 bytes long
|
||||
obj.SendDataToHost(dev, true, Buffer.from([0x00, present, 0x80, 0x00]), featureRegister & 1); // This is the original version, 4 bytes long
|
||||
break;
|
||||
case 0x4c:
|
||||
obj.SendCommand(0x51, webserver.common.IntToStrX(0) + webserver.common.IntToStrX(0) + webserver.common.IntToStrX(0) + String.fromCharCode(0x87, 0x50, 0x03, 0x00, 0x00, 0x00, 0xb0, 0x51, 0x05, 0x20, 0x00), true);
|
||||
obj.SendCommand(0x51, Buffer.concat([IntToStrX(0), IntToStrX(0), IntToStrX(0), Buffer.from([0x87, 0x50, 0x03, 0x00, 0x00, 0x00, 0xb0, 0x51, 0x05, 0x20, 0x00])]), true);
|
||||
break;
|
||||
case 0x51: // READ_DISC_INFO
|
||||
debug("SCSI READ_DISC_INFO", dev);
|
||||
if (obj.debug) console.log("SCSI READ_DISC_INFO", dev);
|
||||
obj.SendCommandEndResponse(0, 0x05, dev, 0x20, 0x00); // Correct
|
||||
return -1;
|
||||
case 0x55: // MODE_SELECT_10:
|
||||
debug("SCSI ERROR: MODE_SELECT_10", dev);
|
||||
if (obj.debug) console.log("SCSI ERROR: MODE_SELECT_10", dev);
|
||||
obj.SendCommandEndResponse(1, 0x05, dev, 0x20, 0x00);
|
||||
return -1;
|
||||
case 0x5a: // MODE_SENSE_10
|
||||
debug("SCSI: MODE_SENSE_10", dev, cdb.charCodeAt(2) & 0x3f);
|
||||
var buflen = webserver.common.ReadShort(cdb, 7);
|
||||
//var pc = cdb.charCodeAt(2) & 0xc0;
|
||||
if (obj.debug) console.log("SCSI: MODE_SENSE_10", dev, cdb[2] & 0x3f);
|
||||
var buflen = ReadShort(cdb, 7);
|
||||
//var pc = cdb[2] & 0xc0;
|
||||
var r = null;
|
||||
|
||||
if (buflen == 0) { obj.SendDataToHost(dev, true, webserver.common.IntToStr(0x003c) + webserver.common.IntToStr(0x0008), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
|
||||
|
||||
if (buflen == 0) { obj.SendDataToHost(dev, true, Buffer.concat([IntToStr(0x003c), IntToStr(0x0008)]), featureRegister & 1); return -1; } // TODO: Fixed this return, it's not correct.
|
||||
|
||||
// 1.44 mb floppy or LS120 (sectorCount == 0x3c300)
|
||||
var sectorCount = 0;
|
||||
if (dev == 0xA0) {
|
||||
if (obj.floppy != null) { sectorCount = (obj.floppySize >> 9); }
|
||||
if (obj.floppy != null) { sectorCount = (obj.floppy.size >> 9); }
|
||||
} else {
|
||||
if (obj.cdrom != null) { sectorCount = (obj.cdromSize >> 11); }
|
||||
if (obj.cdrom != null) { sectorCount = (obj.cdrom.size >> 11); }
|
||||
}
|
||||
|
||||
switch (cdb.charCodeAt(2) & 0x3f) {
|
||||
case 0x01: if (dev == 0xA0) { r = (sectorCount <= 0xb40)?IDE_ModeSence_FloppyError_Recovery_Array:IDE_ModeSence_Ls120Error_Recovery_Array; } else { r = IDE_ModeSence_CDError_Recovery_Array; } break;
|
||||
case 0x05: if (dev == 0xA0) { r = (sectorCount <= 0xb40)?IDE_ModeSence_FloppyDisk_Page_Array:IDE_ModeSence_LS120Disk_Page_Array; } break;
|
||||
case 0x3f: if (dev == 0xA0) { r = (sectorCount <= 0xb40)?IDE_ModeSence_3F_Floppy_Array:IDE_ModeSence_3F_LS120_Array; } else { r = IDE_ModeSence_3F_CD_Array; } break;
|
||||
switch (cdb[2] & 0x3f) {
|
||||
case 0x01: if (dev == 0xA0) { r = (sectorCount <= 0xb40) ? IDE_ModeSence_FloppyError_Recovery_Array : IDE_ModeSence_Ls120Error_Recovery_Array; } else { r = IDE_ModeSence_CDError_Recovery_Array; } break;
|
||||
case 0x05: if (dev == 0xA0) { r = (sectorCount <= 0xb40) ? IDE_ModeSence_FloppyDisk_Page_Array : IDE_ModeSence_LS120Disk_Page_Array; } break;
|
||||
case 0x3f: if (dev == 0xA0) { r = (sectorCount <= 0xb40) ? IDE_ModeSence_3F_Floppy_Array : IDE_ModeSence_3F_LS120_Array; } else { r = IDE_ModeSence_3F_CD_Array; } break;
|
||||
case 0x1A: if (dev == 0xB0) { r = IDE_ModeSence_CD_1A_Array; } break;
|
||||
case 0x1D: if (dev == 0xB0) { r = IDE_ModeSence_CD_1D_Array; } break;
|
||||
case 0x1D: if (dev == 0xB0) { r = IDE_ModeSence_CD_1D_Array; } break;
|
||||
case 0x2A: if (dev == 0xB0) { r = IDE_ModeSence_CD_2A_Array; } break;
|
||||
}
|
||||
|
||||
|
|
@ -589,8 +581,14 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
obj.SendDataToHost(dev, true, r, featureRegister & 1);
|
||||
}
|
||||
break;
|
||||
case 0x51: // READ_DISK_INFORMATION
|
||||
obj.SendDataToHost(dev, true, RD_CD_DiskInfo, featureRegister & 1);
|
||||
break;
|
||||
case 0xAC: // GET_PERFORMANCE
|
||||
obj.SendDataToHost(dev, true, RD_CD_Performance, featureRegister & 1);
|
||||
break;
|
||||
default: // UNKNOWN COMMAND
|
||||
debug("IDER: Unknown SCSI command", cdb.charCodeAt(0));
|
||||
if (obj.debug) console.log("IDER: Unknown SCSI command", cdb[0]);
|
||||
obj.SendCommandEndResponse(0, 0x05, dev, 0x20, 0x00);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -600,8 +598,8 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
function sendDiskData(dev, lba, len, featureRegister) {
|
||||
var media = null;
|
||||
var mediaBlocks = 0;
|
||||
if (dev == 0xA0) { media = obj.floppy; if (obj.floppy != null) { mediaBlocks = (obj.floppySize >> 9); } }
|
||||
if (dev == 0xB0) { media = obj.cdrom; if (obj.cdrom != null) { mediaBlocks = (obj.cdromSize >> 11); } }
|
||||
if (dev == 0xA0) { media = obj.floppy; if (obj.floppy != null) { mediaBlocks = (obj.floppy.size >> 9); } }
|
||||
if (dev == 0xB0) { media = obj.cdrom; if (obj.cdrom != null) { mediaBlocks = (obj.cdrom.size >> 11); } }
|
||||
if ((len < 0) || (lba + len > mediaBlocks)) { obj.SendCommandEndResponse(1, 0x05, dev, 0x21, 0x00); return 0; }
|
||||
if (len == 0) { obj.SendCommandEndResponse(1, 0x00, dev, 0x00, 0x00); return 0; }
|
||||
if (media != null) {
|
||||
|
|
@ -628,9 +626,10 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
if (g_len > obj.iderinfo.readbfr) { len = obj.iderinfo.readbfr; }
|
||||
g_len -= len;
|
||||
g_lba += len;
|
||||
|
||||
var buffer = Buffer.alloc(len);
|
||||
fs.read(g_media, buffer, 0, len, lba, function (error, bytesRead, buffer) {
|
||||
obj.SendDataToHost(g_dev, (g_len == 0), buffer.toString('binary'), featureRegister & 1);
|
||||
fs.read(g_media.ptr, buffer, 0, len, lba, function (error, bytesRead, buffer) {
|
||||
obj.SendDataToHost(g_dev, (g_len == 0), buffer, featureRegister & 1);
|
||||
if ((g_len > 0) && (g_reset == false)) {
|
||||
sendDiskDataEx(featureRegister);
|
||||
} else {
|
||||
|
|
@ -643,3 +642,13 @@ module.exports.CreateAmtRemoteIder = function (webserver, meshcentral) {
|
|||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function ShortToStr(v) { return Buffer.from([(v >> 8) & 0xFF, v & 0xFF]); }
|
||||
function ShortToStrX(v) { return Buffer.from([v & 0xFF, (v >> 8) & 0xFF]); }
|
||||
function IntToStr(v) { return Buffer.from([(v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF]); }
|
||||
function IntToStrX(v) { return Buffer.from([v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF]); }
|
||||
function ReadShort(v, p) { return (v[p] << 8) + v[p + 1]; }
|
||||
function ReadShortX(v, p) { return (v[p + 1] << 8) + v[p]; }
|
||||
function ReadInt(v, p) { return (v[p] * 0x1000000) + (v[p + 1] << 16) + (v[p + 2] << 8) + v[p + 3]; } // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
|
||||
function ReadSInt(v, p) { return (v[p] << 24) + (v[p + 1] << 16) + (v[p + 2] << 8) + v[p + 3]; }
|
||||
function ReadIntX(v, p) { return (v[p + 3] * 0x1000000) + (v[p + 2] << 16) + (v[p + 1] << 8) + v[p]; }
|
||||
|
|
@ -127,8 +127,8 @@ module.exports.CreateAmtIderSession = function (parent, db, ws, req, args, domai
|
|||
if ((command.args.floppyPath != null) && (typeof command.args.floppyPath != 'string')) { command.args.floppyPath = null; } else { command.args.floppyPath = decodeURIComponent(command.args.floppyPath); }
|
||||
if ((command.args.cdromPath != null) && (typeof command.args.cdromPath != 'string')) { command.args.cdromPath = null; } else { command.args.cdromPath = decodeURIComponent(command.args.cdromPath); }
|
||||
// TODO: Double check that "." or ".." are not used.
|
||||
if ((command.args.floppyPath != null) && (command.args.floppyPath.indexOf("..") >= 0)) { delete command.args.floppyPath; }
|
||||
if ((command.args.cdromPath != null) && (command.args.cdromPath.indexOf("..") >= 0)) { delete command.args.cdromPath; }
|
||||
if ((command.args.floppyPath != null) && (command.args.floppyPath.indexOf('..') >= 0)) { delete command.args.floppyPath; }
|
||||
if ((command.args.cdromPath != null) && (command.args.cdromPath.indexOf('..') >= 0)) { delete command.args.cdromPath; }
|
||||
|
||||
// Get the disk image paths
|
||||
var domainx = 'domain' + ((domain.id == '') ? '' : ('-' + domain.id));
|
||||
|
|
@ -148,7 +148,7 @@ module.exports.CreateAmtIderSession = function (parent, db, ws, req, args, domai
|
|||
var iderError = obj.ider.m.diskSetup(floppyPath, cdromPath);
|
||||
|
||||
// Error with the disk images, unable to start IDER
|
||||
if (iderError != 0) { try { ws.send(JSON.stringify({ action: "error", code: iderError })); } catch (ex) { } break; }
|
||||
if (iderError != 0) { try { ws.send(JSON.stringify({ action: 'error', code: iderError })); } catch (ex) { } break; }
|
||||
|
||||
// Start the IDER session
|
||||
obj.ider.Start(req.query.host, req.query.port, req.query.tls);
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
|
|||
obj.redirTrace = false;
|
||||
obj.tls1only = 0; // TODO
|
||||
|
||||
obj.amtaccumulator = "";
|
||||
obj.amtaccumulator = '';
|
||||
obj.amtsequence = 1;
|
||||
obj.amtkeepalivetimer = null;
|
||||
obj.authuri = "/RedirectionService";
|
||||
obj.authuri = '/RedirectionService';
|
||||
|
||||
obj.onStateChanged = null;
|
||||
obj.forwardclient = null;
|
||||
|
|
@ -71,7 +71,7 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
|
|||
const SITERIGHT_LOCKED = 32;
|
||||
|
||||
function Debug(lvl) {
|
||||
if ((arguments.length < 2) || (lvl > meshcentral.debugLevel)) return;
|
||||
if ((arguments.length < 2) || (meshcentral.debugLevel == null) || (lvl > meshcentral.debugLevel)) return;
|
||||
var a = []; for (var i = 1; i < arguments.length; i++) { a.push(arguments[i]); } console.log(...a);
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
|
|||
var obj = new require('stream').Duplex(options);
|
||||
obj.forwardwrite = null;
|
||||
obj.updateBuffer = function (chunk) { this.push(chunk); };
|
||||
obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.err("Failed to fwd _write."); } if (callback) callback(); }; // Pass data written to forward
|
||||
obj._write = function (chunk, encoding, callback) { if (obj.forwardwrite != null) { obj.forwardwrite(chunk); } else { console.err('Failed to fwd _write.'); } if (callback) callback(); }; // Pass data written to forward
|
||||
obj._read = function (size) { }; // Push nothing, anything to read should be pushed from updateBuffer()
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -478,10 +478,17 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
|
|||
}
|
||||
|
||||
obj.xxSend = function (x) {
|
||||
if (obj.redirTrace) { console.log("REDIR-SEND(" + x.length + "): " + Buffer.from(x, "binary").toString('hex'), typeof x); }
|
||||
//obj.Debug("Send(" + x.length + "): " + webserver.common.rstr2hex(x));
|
||||
//obj.forwardclient.write(x); // FIXES CIRA
|
||||
obj.forwardclient.write(Buffer.from(x, "binary"));
|
||||
if (typeof x == 'string') {
|
||||
if (obj.redirTrace) { console.log("REDIR-SEND(" + x.length + "): " + Buffer.from(x, 'binary').toString('hex'), typeof x); }
|
||||
//obj.Debug("Send(" + x.length + "): " + webserver.common.rstr2hex(x));
|
||||
//obj.forwardclient.write(x); // FIXES CIRA
|
||||
obj.forwardclient.write(Buffer.from(x, 'binary'));
|
||||
} else {
|
||||
if (obj.redirTrace) { console.log("REDIR-SEND(" + x.length + "): " + x.toString('hex'), typeof x); }
|
||||
//obj.Debug("Send(" + x.length + "): " + webserver.common.rstr2hex(x));
|
||||
//obj.forwardclient.write(x); // FIXES CIRA
|
||||
obj.forwardclient.write(x);
|
||||
}
|
||||
}
|
||||
|
||||
obj.Send = function (x) {
|
||||
|
|
@ -497,7 +504,7 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
|
|||
obj.xxRandomValueHex = function(len) { return obj.crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len); }
|
||||
|
||||
obj.xxOnSocketClosed = function () {
|
||||
if (obj.redirTrace) { console.log("REDIR-CLOSED"); }
|
||||
if (obj.redirTrace) { console.log('REDIR-CLOSED'); }
|
||||
//obj.Debug("Socket Closed");
|
||||
obj.Stop();
|
||||
}
|
||||
|
|
@ -510,12 +517,12 @@ module.exports.CreateAmtRedirect = function (module, domain, user, webserver, me
|
|||
}
|
||||
|
||||
obj.Stop = function () {
|
||||
if (obj.redirTrace) { console.log("REDIR-CLOSED"); }
|
||||
if (obj.redirTrace) { console.log('REDIR-CLOSED'); }
|
||||
//obj.Debug("Socket Stopped");
|
||||
obj.xxStateChange(0);
|
||||
obj.connectstate = -1;
|
||||
obj.amtaccumulator = "";
|
||||
if (obj.forwardclient != null) { try { obj.forwardclient.close(); } catch (ex) { } delete obj.forwardclient; }
|
||||
obj.amtaccumulator = '';
|
||||
if (obj.forwardclient != null) { try { obj.forwardclient.destroy(); } catch (ex) { } delete obj.forwardclient; }
|
||||
if (obj.amtkeepalivetimer != null) { clearInterval(obj.amtkeepalivetimer); delete obj.amtkeepalivetimer; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,13 +170,11 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
|
|||
//console.log('SEND: ' + h); // Display send packet
|
||||
}
|
||||
|
||||
// NODE.js specific private method
|
||||
obj.parseDigest = function (header) {
|
||||
var t = header.substring(7).split(',');
|
||||
for (var i in t) t[i] = t[i].trim();
|
||||
return t.reduce(function (obj, s) { var parts = s.split('='); obj[parts[0]] = parts[1].replace(new RegExp('\"', 'g'), ''); return obj; }, {})
|
||||
}
|
||||
// Parse the HTTP digest header and return a list of key & values.
|
||||
obj.parseDigest = function (header) { return correctedQuoteSplit(header.substring(7)).reduce(function (obj, s) { var parts = s.trim().split('='); obj[parts[0]] = parts[1].replace(new RegExp('\"', 'g'), ''); return obj; }, {}) }
|
||||
|
||||
// Split a string on quotes but do not do it when in quotes
|
||||
function correctedQuoteSplit(str) { return str.split(',').reduce(function (a, c) { if (a.ic) { a.st[a.st.length - 1] += ',' + c } else { a.st.push(c) } if (c.split('"').length % 2 == 0) { a.ic = !a.ic } return a; }, { st: [], ic: false }).st }
|
||||
function nonceHex(v) { var s = ('00000000' + v.toString(16)); return s.substring(s.length - 8); }
|
||||
|
||||
// NODE.js specific private method
|
||||
|
|
@ -276,7 +274,7 @@ var CreateWsmanComm = function (host, port, user, pass, tls, tlsoptions, mpsConn
|
|||
obj.socket.connect(obj.port, obj.host, obj.xxOnSocketConnected);
|
||||
} else {
|
||||
// Direct connect with TLS
|
||||
var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false };
|
||||
var options = { ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION, rejectUnauthorized: false };
|
||||
if (obj.xtlsMethod != 0) { options.secureProtocol = 'TLSv1_method'; }
|
||||
if (obj.xtlsoptions) {
|
||||
if (obj.xtlsoptions.ca) { options.ca = obj.xtlsoptions.ca; }
|
||||
|
|
|
|||
136
amtmanager.js
136
amtmanager.js
|
|
@ -707,7 +707,15 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
dev.aquired.controlMode = responses['IPS_HostBasedSetupService'].response.CurrentControlMode; // 1 = CCM, 2 = ACM
|
||||
if (typeof stack.wsman.comm.amtVersion == 'string') { // Set the Intel AMT version using the HTTP header if present
|
||||
var verSplit = stack.wsman.comm.amtVersion.split('.');
|
||||
if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); }
|
||||
if (verSplit.length >= 2) {
|
||||
dev.aquired.version = verSplit[0] + '.' + verSplit[1];
|
||||
dev.aquired.majorver = parseInt(verSplit[0]);
|
||||
dev.aquired.minorver = parseInt(verSplit[1]);
|
||||
if (verSplit.length >= 3) {
|
||||
dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
|
||||
dev.aquired.maintenancever = parseInt(verSplit[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
dev.aquired.realm = stack.wsman.comm.digestRealm;
|
||||
dev.aquired.user = dev.intelamt.user = stack.wsman.comm.user;
|
||||
|
|
@ -750,7 +758,8 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
// Start power polling if not connected to LMS
|
||||
var ppfunc = function powerPoleFunction() { fetchPowerState(powerPoleFunction.dev); }
|
||||
ppfunc.dev = dev;
|
||||
dev.polltimer = new setTimeout(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
|
||||
if(dev.polltimer){ clearInterval(dev.polltimer); delete dev.polltimer; }
|
||||
dev.polltimer = new setInterval(ppfunc, 290000); // Poll for power state every 4 minutes 50 seconds.
|
||||
fetchPowerState(dev);
|
||||
} else {
|
||||
// For LMS connections, close now.
|
||||
|
|
@ -930,8 +939,8 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
if (response.Body.OSPowerSavingState == 2) { meshPowerState = 1; } // Fully powered (S0);
|
||||
else if (response.Body.OSPowerSavingState == 3) { meshPowerState = 2; } // Modern standby (We are going to call this S1);
|
||||
|
||||
// Set OS power state
|
||||
if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), 4, meshPowerState, null, { name: dev.name }); }
|
||||
// Set OS power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
|
||||
if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); }
|
||||
});
|
||||
} else {
|
||||
// Convert the power state
|
||||
|
|
@ -940,28 +949,83 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
var meshPowerState = -1, powerConversionTable = [-1, -1, 1, 2, 3, 6, 6, 5, 6];
|
||||
if (powerstate < powerConversionTable.length) { meshPowerState = powerConversionTable[powerstate]; } else { powerstate = 6; }
|
||||
|
||||
// Set power state
|
||||
if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), 4, meshPowerState, null, { name: dev.name }); }
|
||||
// Set power state - connType: 0 = CIRA, 1 = CIRA-Relay, 2 = CIRA-LMS, 3 = LAN
|
||||
if (meshPowerState >= 0) { parent.SetConnectivityState(dev.meshid, dev.nodeid, Date.now(), (dev.connType == 3 ? 4 : 2), meshPowerState, null, { name: dev.name }); }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset
|
||||
// Perform a power action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset, 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE
|
||||
function performPowerAction(nodeid, action) {
|
||||
console.log('performPowerAction', nodeid, action);
|
||||
var devices = obj.amtDevices[nodeid];
|
||||
if (devices == null) return;
|
||||
for (var i in devices) {
|
||||
var dev = devices[i];
|
||||
// If not LMS, has a AMT stack present and is in connected state, perform power operation.
|
||||
if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) {
|
||||
// Action: 2 = Power on, 8 = Power down, 10 = reset
|
||||
parent.debug('amt', dev.name, "performPowerAction", action);
|
||||
dev.powerAction = action;
|
||||
try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { }
|
||||
if (action <= 10) {
|
||||
// Action: 2 = Power up, 5 = Power cycle, 8 = Power down, 10 = Reset
|
||||
try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { }
|
||||
} else {
|
||||
// 11 = Power on to BIOS, 12 = Reset to BIOS, 13 = Power on to BIOS with SOL, 14 = Reset to BIOS with SOL, 15 = Power on to PXE, 16 = Reset to PXE
|
||||
dev.amtstack.BatchEnum(null, ['*AMT_BootSettingData'], performAdvancedPowerActionResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Response to Intel AMT advanced power action
|
||||
function performAdvancedPowerActionResponse(stack, name, responses, status) {
|
||||
const dev = stack.dev;
|
||||
const action = dev.powerAction;
|
||||
delete dev.powerAction;
|
||||
if (obj.amtDevices[dev.nodeid] == null) return; // Device no longer exists, ignore this response.
|
||||
if (status != 200) return;
|
||||
if ((responses['AMT_BootSettingData'] == null) || (responses['AMT_BootSettingData'].response == null)) return;
|
||||
var bootSettingData = responses['AMT_BootSettingData'].response;
|
||||
|
||||
// Clean up parameters
|
||||
bootSettingData['ConfigurationDataReset'] = false;
|
||||
delete bootSettingData['WinREBootEnabled'];
|
||||
delete bootSettingData['UEFILocalPBABootEnabled'];
|
||||
delete bootSettingData['UEFIHTTPSBootEnabled'];
|
||||
delete bootSettingData['SecureBootControlEnabled'];
|
||||
delete bootSettingData['BootguardStatus'];
|
||||
delete bootSettingData['OptionsCleared'];
|
||||
delete bootSettingData['BIOSLastStatus'];
|
||||
delete bootSettingData['UefiBootParametersArray'];
|
||||
delete bootSettingData['RPEEnabled'];
|
||||
delete bootSettingData['RSEPassword']
|
||||
|
||||
// Ready boot parameters
|
||||
bootSettingData['BIOSSetup'] = ((action >= 11) && (action <= 14));
|
||||
bootSettingData['UseSOL'] = ((action >= 13) && (action <= 14));
|
||||
if ((action == 11) || (action == 13) || (action == 15)) { dev.powerAction = 2; } // Power on
|
||||
if ((action == 12) || (action == 14) || (action == 16)) { dev.powerAction = 10; } // Reset
|
||||
|
||||
// Set boot parameters
|
||||
dev.amtstack.Put('AMT_BootSettingData', bootSettingData, function (stack, name, response, status, tag) {
|
||||
const dev = stack.dev;
|
||||
if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
|
||||
// Set boot config
|
||||
dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status, tag) {
|
||||
const dev = stack.dev;
|
||||
if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
|
||||
// Set boot order
|
||||
var bootDevice = (action === 15 || action === 16) ? '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force PXE Boot</Selector></SelectorSet></ReferenceParameters>' : null;
|
||||
dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder(bootDevice, function (stack, name, response, status) {
|
||||
const dev = stack.dev;
|
||||
if ((obj.amtDevices[dev.nodeid] == null) || (status != 200)) return; // Device no longer exists or error
|
||||
// Perform power action
|
||||
try { dev.amtstack.RequestPowerStateChange(dev.powerAction, performPowerActionResponse); } catch (ex) { }
|
||||
}, 0, 1);
|
||||
}, 0, 1);
|
||||
}, 0, 1);
|
||||
}
|
||||
|
||||
// Response to Intel AMT power action
|
||||
function performPowerActionResponse(stack, name, responses, status) {
|
||||
const dev = stack.dev;
|
||||
|
|
@ -1005,7 +1069,7 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
if (status != 200) { dev.consoleMsg("Failed to get security information (" + status + ")."); delete dev.ocrfile; return; }
|
||||
|
||||
// Check if this Intel AMT device supports OCR
|
||||
if (responses['AMT_PublicKeyCertificate'].responses['ForceUEFIHTTPSBoot'] !== true) {
|
||||
if (responses['AMT_BootCapabilities'].response['ForceUEFIHTTPSBoot'] !== true) {
|
||||
dev.consoleMsg("This Intel AMT device does not support UEFI HTTPS boot (" + status + ")."); delete dev.ocrfile; return;
|
||||
}
|
||||
|
||||
|
|
@ -1035,11 +1099,14 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
|
||||
// Generate the one-time URL.
|
||||
var cookie = obj.parent.encodeCookie({ a: 'f', f: dev.ocrfile }, obj.parent.loginCookieEncryptionKey)
|
||||
var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.iso';
|
||||
var url = 'https://' + parent.webserver.certificates.AmtMpsName + ':' + ((parent.args.mpsaliasport != null) ? parent.args.mpsaliasport : parent.args.mpsport) + '/c/' + cookie + '.efi';
|
||||
delete dev.ocrfile;
|
||||
|
||||
// Generate the boot data for OCR with URL
|
||||
var r = response.Body;
|
||||
r['BIOSPause'] = false;
|
||||
r['BIOSSetup'] = false;
|
||||
r['EnforceSecureBoot'] = false;
|
||||
r['UefiBootParametersArray'] = Buffer.from(makeUefiBootParam(1, url) + makeUefiBootParam(20, 1, 1) + makeUefiBootParam(30, 0, 2), 'binary').toString('base64');
|
||||
r['UefiBootNumberOfParams'] = 3;
|
||||
r['BootMediaIndex'] = 0; // Do not use boot media index for One Click Recovery (OCR)
|
||||
|
|
@ -1060,8 +1127,7 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
dev.amtstack.SetBootConfigRole(1, function (stack, name, response, status) {
|
||||
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
|
||||
if (status != 200) { dev.consoleMsg("Failed to set boot config role (" + status + ")."); return; }
|
||||
var bootSource = 'Force OCR UEFI HTTPS Boot';
|
||||
dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder((bootSource == null) ? bootSource : '<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: ' + bootSource + '</Selector></SelectorSet></ReferenceParameters>', function (stack, name, response, status) {
|
||||
dev.amtstack.CIM_BootConfigSetting_ChangeBootOrder('<Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing</Address><ReferenceParameters xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><ResourceURI xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_BootSourceSetting</ResourceURI><SelectorSet xmlns="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"><Selector Name="InstanceID">Intel(r) AMT: Force OCR UEFI HTTPS Boot</Selector></SelectorSet></ReferenceParameters>', function (stack, name, response, status) {
|
||||
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
|
||||
if (status != 200) { dev.consoleMsg("Failed to set boot config (" + status + ")."); return; }
|
||||
dev.amtstack.RequestPowerStateChange(10, function (stack, name, response, status) { // 10 = Reset, 2 = Power Up
|
||||
|
|
@ -1264,7 +1330,7 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
}
|
||||
|
||||
// Figure out what index is local & remote
|
||||
var localNdx = ((dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);
|
||||
var localNdx = ((dev.policy != null) && (dev.policy.tlsSettings != null) && (dev.policy.tlsSettings[0] != null) && (dev.policy.tlsSettings[0]['InstanceID'] == 'Intel(r) AMT LMS TLS Settings')) ? 0 : 1, remoteNdx = (1 - localNdx);
|
||||
|
||||
// Remote TLS settings
|
||||
var xxTlsSettings2 = Clone(dev.policy.tlsSettings);
|
||||
|
|
@ -1377,11 +1443,11 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
const dev = stack.dev;
|
||||
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
|
||||
const domain = parent.config.domains[dev.domainid];
|
||||
if ((responses['AMT_PublicKeyCertificate'].status != 200) || (responses['AMT_PublicKeyCertificate'].status != 200)) { devTaskCompleted(dev); return; } // We can't get the certificate list, fail and carry on.
|
||||
if ((responses['AMT_PublicKeyCertificate'] == null) || (responses['AMT_PublicKeyCertificate'].status != 200) || (responses['AMT_PublicPrivateKeyPair'] == null) || (responses['AMT_PublicPrivateKeyPair'].status != 200)) { devTaskCompleted(dev); return; } // We can't get the certificate list, fail and carry on.
|
||||
|
||||
// See if we need to perform wired or wireless 802.1x configuration
|
||||
var wiredConfig = ((parent.config.domains[dev.domainid].amtmanager['802.1x'] != null) && (responses['AMT_8021XProfile'].status == 200));
|
||||
const wirelessConfig = ((responses['CIM_WiFiEndpointSettings'].status == 200) && (responses['AMT_WiFiPortConfigurationService'].status == 200) && (responses['CIM_WiFiPort'].status == 200) && (responses['CIM_IEEE8021xSettings'].status == 200));
|
||||
var wiredConfig = ((parent.config.domains[dev.domainid].amtmanager['802.1x'] != null) && (responses['AMT_8021XProfile'] != null) && (responses['AMT_8021XProfile'].status == 200));
|
||||
const wirelessConfig = ((responses['CIM_WiFiEndpointSettings'] != null) && (responses['CIM_WiFiEndpointSettings'].status == 200) && (responses['AMT_WiFiPortConfigurationService'] != null) && (responses['AMT_WiFiPortConfigurationService'].status == 200) && (responses['CIM_WiFiPort'] != null) && (responses['CIM_WiFiPort'].status == 200) && (responses['CIM_IEEE8021xSettings'] != null) && (responses['CIM_IEEE8021xSettings'].status == 200));
|
||||
if (!wiredConfig && !wirelessConfig) { devTaskCompleted(dev); return; } // We can't get wired or wireless settings, ignore and carry on.
|
||||
|
||||
// Sort out the certificates
|
||||
|
|
@ -2184,7 +2250,6 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
dev.amtstack.BatchEnum('', query, attemptSettingsSyncResponse);
|
||||
}
|
||||
|
||||
|
||||
function attemptSettingsSyncResponse(stack, name, responses, status) {
|
||||
const dev = stack.dev;
|
||||
if (isAmtDeviceValid(dev) == false) return; // Device no longer exists, ignore this request.
|
||||
|
|
@ -2239,7 +2304,7 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
|
||||
// Check KVM state
|
||||
if ((dev.aquired.majorver != null) && (dev.aquired.majorver > 5) && (responses['CIM_KVMRedirectionSAP'] != null)) {
|
||||
var kvm = (((responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6) && (responses['CIM_KVMRedirectionSAP'].response['RequestedState'] == 2)) || (responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 2) || (responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6));
|
||||
const kvm = ((responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 2) || (responses['CIM_KVMRedirectionSAP'].response['EnabledState'] == 6));
|
||||
if (kvm == false) {
|
||||
// Enable KVM
|
||||
dev.taskCount++;
|
||||
|
|
@ -2567,7 +2632,14 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
if (domain && domain.amtmanager && (domain.amtmanager.tlsacmactivation == true)) { TlsAcmActivation = true; }
|
||||
|
||||
// Check Intel AMT version
|
||||
if (typeof dev.intelamt.ver == 'string') { var verSplit = dev.intelamt.ver.split('.'); if (verSplit.length >= 3) { dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); } }
|
||||
if (typeof dev.intelamt.ver == 'string') {
|
||||
var verSplit = dev.intelamt.ver.split('.');
|
||||
if (verSplit.length >= 2) {
|
||||
dev.aquired.majorver = parseInt(verSplit[0]);
|
||||
dev.aquired.minorver = parseInt(verSplit[1]);
|
||||
if (verSplit.length >= 3) { dev.aquired.maintenancever = parseInt(verSplit[2]); }
|
||||
}
|
||||
}
|
||||
|
||||
// If this is Intel AMT 14 or better and allowed, we are going to attempt a host-based end-to-end TLS activation.
|
||||
if (TlsAcmActivation && (dev.aquired.majorver >= 14)) {
|
||||
|
|
@ -2623,7 +2695,15 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
dev.aquired.controlMode = 1; // 1 = CCM, 2 = ACM
|
||||
if (typeof dev.amtstack.wsman.comm.amtVersion == 'string') {
|
||||
var verSplit = dev.amtstack.wsman.comm.amtVersion.split('.');
|
||||
if (verSplit.length >= 3) { dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2]; dev.aquired.majorver = parseInt(verSplit[0]); dev.aquired.minorver = parseInt(verSplit[1]); }
|
||||
if (verSplit.length >= 2) {
|
||||
dev.aquired.version = verSplit[0] + '.' + verSplit[1];
|
||||
dev.aquired.majorver = parseInt(verSplit[0]);
|
||||
dev.aquired.minorver = parseInt(verSplit[1]);
|
||||
if (verSplit.length >= 3) {
|
||||
dev.aquired.version = verSplit[0] + '.' + verSplit[1] + '.' + verSplit[2];
|
||||
dev.aquired.maintenancever = parseInt(verSplit[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((typeof dev.mpsConnection.tag.meiState.OsHostname == 'string') && (typeof dev.mpsConnection.tag.meiState.OsDnsSuffix == 'string')) {
|
||||
dev.aquired.host = dev.mpsConnection.tag.meiState.OsHostname + '.' + dev.mpsConnection.tag.meiState.OsDnsSuffix;
|
||||
|
|
@ -2758,8 +2838,10 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
var vs = getInstance(amtlogicalelements, 'AMT')['VersionString'];
|
||||
if (vs != null) {
|
||||
dev.aquired.version = vs;
|
||||
dev.aquired.versionmajor = parseInt(dev.aquired.version.split('.')[0]);
|
||||
dev.aquired.versionminor = parseInt(dev.aquired.version.split('.')[1]);
|
||||
version = dev.aquired.version.split('.')
|
||||
dev.aquired.versionmajor = parseInt(version[0]);
|
||||
dev.aquired.versionminor = parseInt(version[1]);
|
||||
if (version.length > 2) { dev.aquired.versionmaintenance = parseInt(version[2]); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2767,10 +2849,14 @@ module.exports.CreateAmtManager = function (parent) {
|
|||
// Fetch the Intel AMT version from HTTP stack
|
||||
if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) {
|
||||
var s = stack.wsman.comm.amtVersion.split('.');
|
||||
if (s.length >= 3) {
|
||||
dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
|
||||
if (s.length >= 2) {
|
||||
dev.aquired.version = s[0] + '.' + s[1] + '.';
|
||||
dev.aquired.versionmajor = parseInt(s[0]);
|
||||
dev.aquired.versionminor = parseInt(s[1]);
|
||||
if (s.length >= 3) {
|
||||
dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
|
||||
dev.aquired.versionmaintenance = parseInt(s[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -201,8 +201,10 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) {
|
|||
var vs = getInstance(amtlogicalelements, 'AMT')['VersionString'];
|
||||
if (vs != null) {
|
||||
dev.aquired.version = vs;
|
||||
dev.aquired.versionmajor = parseInt(dev.aquired.version.split('.')[0]);
|
||||
dev.aquired.versionminor = parseInt(dev.aquired.version.split('.')[1]);
|
||||
const versionSplit = parseInt(dev.aquired.version.split('.'));
|
||||
dev.aquired.versionmajor = parseInt(versionSplit[0]);
|
||||
dev.aquired.versionminor = parseInt(versionSplit[1]);
|
||||
if (versionSplit.length >= 3) { dev.aquired.versionmaintenance = parseInt(versionSplit[2]); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -210,10 +212,14 @@ module.exports.CreateAmtProvisioningServer = function (parent, config) {
|
|||
// Fetch the Intel AMT version from HTTP stack
|
||||
if ((dev.amtversionstr == null) && (stack.wsman.comm.amtVersion != null)) {
|
||||
var s = stack.wsman.comm.amtVersion.split('.');
|
||||
if (s.length >= 3) {
|
||||
dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
|
||||
if (s.length >= 2) {
|
||||
dev.aquired.version = s[0] + '.' + s[1];
|
||||
dev.aquired.versionmajor = parseInt(s[0]);
|
||||
dev.aquired.versionminor = parseInt(s[1]);
|
||||
if (s.length >= 3) {
|
||||
dev.aquired.version = s[0] + '.' + s[1] + '.' + s[2];
|
||||
dev.aquired.versionmaintenance = parseInt(s[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -362,8 +362,8 @@ module.exports.CreateAmtScanner = function (parent) {
|
|||
if (oldVer == newVer) return false; // Versions are same already, don't update.
|
||||
if (newVer == undefined || newVer == null) return false; // New version is bad, don't update it.
|
||||
if (oldVer == undefined || oldVer == null) return true; // Old version is no good anyway, update it.
|
||||
var oldVerArr = oldVer.split('.');
|
||||
var newVerArr = newVer.split('.');
|
||||
var oldVerArr = oldVer.toString().split('.');
|
||||
var newVerArr = newVer.toString().split('.');
|
||||
if ((oldVerArr.length < 2) || (newVerArr.length < 2)) return false;
|
||||
if ((oldVerArr[0] != newVerArr[0]) || (oldVerArr[1] != newVerArr[1])) return true;
|
||||
if (newVerArr.length > oldVerArr.length) return true;
|
||||
|
|
|
|||
342
apprelays.js
342
apprelays.js
|
|
@ -1,4 +1,4 @@
|
|||
/**
|
||||
/**
|
||||
* @description MeshCentral MSTSC & SSH relay
|
||||
* @author Ylian Saint-Hilaire & Bryan Roe
|
||||
* @copyright Intel Corporation 2018-2022
|
||||
|
|
@ -35,28 +35,29 @@ const PROTOCOL_WEBSFTP = 203;
|
|||
const PROTOCOL_WEBVNC = 204;
|
||||
|
||||
// Mesh Rights
|
||||
const MESHRIGHT_EDITMESH = 0x00000001; // 1
|
||||
const MESHRIGHT_MANAGEUSERS = 0x00000002; // 2
|
||||
const MESHRIGHT_MANAGECOMPUTERS = 0x00000004; // 4
|
||||
const MESHRIGHT_REMOTECONTROL = 0x00000008; // 8
|
||||
const MESHRIGHT_AGENTCONSOLE = 0x00000010; // 16
|
||||
const MESHRIGHT_SERVERFILES = 0x00000020; // 32
|
||||
const MESHRIGHT_WAKEDEVICE = 0x00000040; // 64
|
||||
const MESHRIGHT_SETNOTES = 0x00000080; // 128
|
||||
const MESHRIGHT_REMOTEVIEWONLY = 0x00000100; // 256
|
||||
const MESHRIGHT_NOTERMINAL = 0x00000200; // 512
|
||||
const MESHRIGHT_NOFILES = 0x00000400; // 1024
|
||||
const MESHRIGHT_NOAMT = 0x00000800; // 2048
|
||||
const MESHRIGHT_DESKLIMITEDINPUT = 0x00001000; // 4096
|
||||
const MESHRIGHT_LIMITEVENTS = 0x00002000; // 8192
|
||||
const MESHRIGHT_CHATNOTIFY = 0x00004000; // 16384
|
||||
const MESHRIGHT_UNINSTALL = 0x00008000; // 32768
|
||||
const MESHRIGHT_NODESKTOP = 0x00010000; // 65536
|
||||
const MESHRIGHT_REMOTECOMMAND = 0x00020000; // 131072
|
||||
const MESHRIGHT_RESETOFF = 0x00040000; // 262144
|
||||
const MESHRIGHT_GUESTSHARING = 0x00080000; // 524288
|
||||
const MESHRIGHT_DEVICEDETAILS = 0x00100000; // 1048576
|
||||
const MESHRIGHT_ADMIN = 0xFFFFFFFF;
|
||||
const MESHRIGHT_EDITMESH = 0x00000001; // 1
|
||||
const MESHRIGHT_MANAGEUSERS = 0x00000002; // 2
|
||||
const MESHRIGHT_MANAGECOMPUTERS = 0x00000004; // 4
|
||||
const MESHRIGHT_REMOTECONTROL = 0x00000008; // 8
|
||||
const MESHRIGHT_AGENTCONSOLE = 0x00000010; // 16
|
||||
const MESHRIGHT_SERVERFILES = 0x00000020; // 32
|
||||
const MESHRIGHT_WAKEDEVICE = 0x00000040; // 64
|
||||
const MESHRIGHT_SETNOTES = 0x00000080; // 128
|
||||
const MESHRIGHT_REMOTEVIEWONLY = 0x00000100; // 256
|
||||
const MESHRIGHT_NOTERMINAL = 0x00000200; // 512
|
||||
const MESHRIGHT_NOFILES = 0x00000400; // 1024
|
||||
const MESHRIGHT_NOAMT = 0x00000800; // 2048
|
||||
const MESHRIGHT_DESKLIMITEDINPUT = 0x00001000; // 4096
|
||||
const MESHRIGHT_LIMITEVENTS = 0x00002000; // 8192
|
||||
const MESHRIGHT_CHATNOTIFY = 0x00004000; // 16384
|
||||
const MESHRIGHT_UNINSTALL = 0x00008000; // 32768
|
||||
const MESHRIGHT_NODESKTOP = 0x00010000; // 65536
|
||||
const MESHRIGHT_REMOTECOMMAND = 0x00020000; // 131072
|
||||
const MESHRIGHT_RESETOFF = 0x00040000; // 262144
|
||||
const MESHRIGHT_GUESTSHARING = 0x00080000; // 524288
|
||||
const MESHRIGHT_DEVICEDETAILS = 0x00100000; // 1048576
|
||||
const MESHRIGHT_RELAY = 0x00200000; // 2097152
|
||||
const MESHRIGHT_ADMIN = 0xFFFFFFFF;
|
||||
|
||||
// SerialTunnel object is used to embed TLS within another connection.
|
||||
function SerialTunnel(options) {
|
||||
|
|
@ -69,7 +70,7 @@ function SerialTunnel(options) {
|
|||
}
|
||||
|
||||
// Construct a Web relay object
|
||||
module.exports.CreateWebRelaySession = function (parent, db, req, args, domain, userid, nodeid, addr, port, appid) {
|
||||
module.exports.CreateWebRelaySession = function (parent, db, req, args, domain, userid, nodeid, addr, port, appid, sessionid, expire, mtype) {
|
||||
const obj = {};
|
||||
obj.parent = parent;
|
||||
obj.lastOperation = Date.now();
|
||||
|
|
@ -79,14 +80,27 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
|
|||
obj.addr = addr;
|
||||
obj.port = port;
|
||||
obj.appid = appid;
|
||||
obj.sessionid = sessionid;
|
||||
obj.expireTimer = null;
|
||||
obj.mtype = mtype;
|
||||
var pendingRequests = [];
|
||||
var nextTunnelId = 1;
|
||||
var tunnels = {};
|
||||
var errorCount = 0; // If we keep closing tunnels without processing requests, fail the requests
|
||||
|
||||
parent.parent.debug('webrelay', 'CreateWebRelaySession, userid:' + userid + ', addr:' + addr + ', port:' + port);
|
||||
|
||||
// Any HTTP cookie set by the device is going to be shared between all tunnels to that device.
|
||||
obj.webCookies = {};
|
||||
|
||||
// Setup an expire time if needed
|
||||
if (expire != null) {
|
||||
var timeout = (expire - Date.now());
|
||||
if (timeout < 10) { timeout = 10; }
|
||||
parent.parent.debug('webrelay', 'timeout set to ' + Math.floor(timeout / 1000) + ' second(s).');
|
||||
obj.expireTimer = setTimeout(function () { parent.parent.debug('webrelay', 'timeout'); close(); }, timeout);
|
||||
}
|
||||
|
||||
// Events
|
||||
obj.closed = false;
|
||||
obj.onclose = null;
|
||||
|
|
@ -110,18 +124,22 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
|
|||
|
||||
// Handle new HTTP request
|
||||
obj.handleRequest = function (req, res) {
|
||||
parent.parent.debug('webrelay', 'handleRequest, url:' + req.url);
|
||||
pendingRequests.push([req, res, false]);
|
||||
handleNextRequest();
|
||||
}
|
||||
|
||||
// Handle new websocket request
|
||||
obj.handleWebSocket = function (ws, req) {
|
||||
parent.parent.debug('webrelay', 'handleWebSocket, url:' + req.url);
|
||||
pendingRequests.push([req, ws, true]);
|
||||
handleNextRequest();
|
||||
}
|
||||
|
||||
// Handle request
|
||||
function handleNextRequest() {
|
||||
if (obj.closed == true) return;
|
||||
|
||||
// if there are not pending requests, do nothing
|
||||
if (pendingRequests.length == 0) return;
|
||||
|
||||
|
|
@ -131,51 +149,77 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
|
|||
// Check to see if any of the tunnels are free
|
||||
var count = 0;
|
||||
for (var i in tunnels) {
|
||||
count += (tunnels[i].isWebSocket ? 0 : 1);
|
||||
if ((tunnels[i].relayActive == true) && (tunnels[i].res == null) && (tunnels[i].isWebSocket == false)) {
|
||||
count += ((tunnels[i].isWebSocket || tunnels[i].isStreaming) ? 0 : 1);
|
||||
if ((tunnels[i].relayActive == true) && (tunnels[i].res == null) && (tunnels[i].isWebSocket == false) && (tunnels[i].isStreaming == false)) {
|
||||
// Found a free tunnel, use it
|
||||
const x = pendingRequests.shift();
|
||||
if (x[2] == true) { tunnels[i].processWebSocket(x[0], x[1]); } else { tunnels[i].processRequest(x[0], x[1]); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (count > 0) return;
|
||||
launchNewTunnel();
|
||||
}
|
||||
|
||||
function launchNewTunnel() {
|
||||
// Launch a new tunnel
|
||||
const tunnel = module.exports.CreateWebRelay(obj, db, args, domain);
|
||||
if (obj.closed == true) return;
|
||||
parent.parent.debug('webrelay', 'launchNewTunnel');
|
||||
const tunnel = module.exports.CreateWebRelay(obj, db, args, domain, obj.mtype);
|
||||
tunnel.onclose = function (tunnelId, processedCount) {
|
||||
if (tunnels == null) return;
|
||||
parent.parent.debug('webrelay', 'tunnel-onclose');
|
||||
if (processedCount == 0) { errorCount++; } // If this tunnel closed without processing any requests, mark this as an error
|
||||
delete tunnels[tunnelId];
|
||||
handleNextRequest();
|
||||
}
|
||||
tunnel.onconnect = function (tunnelId) {
|
||||
if (tunnels == null) return;
|
||||
parent.parent.debug('webrelay', 'tunnel-onconnect');
|
||||
if (pendingRequests.length > 0) {
|
||||
const x = pendingRequests.shift();
|
||||
if (x[2] == true) { tunnels[tunnelId].processWebSocket(x[0], x[1]); } else { tunnels[tunnelId].processRequest(x[0], x[1]); }
|
||||
}
|
||||
}
|
||||
tunnel.oncompleted = function (tunnelId) {
|
||||
errorCount = 0; // Something got completed, clear any error count
|
||||
if (pendingRequests.length > 0) {
|
||||
const x = pendingRequests.shift();
|
||||
if (x[2] == true) { tunnels[tunnelId].processWebSocket(x[0], x[1]); } else { tunnels[tunnelId].processRequest(x[0], x[1]); }
|
||||
tunnel.oncompleted = function (tunnelId, closed) {
|
||||
if (tunnels == null) return;
|
||||
if (closed === true) {
|
||||
parent.parent.debug('webrelay', 'tunnel-oncompleted and closed');
|
||||
} else {
|
||||
parent.parent.debug('webrelay', 'tunnel-oncompleted');
|
||||
}
|
||||
if (closed !== true) {
|
||||
errorCount = 0; // Something got completed, clear any error count
|
||||
if (pendingRequests.length > 0) {
|
||||
const x = pendingRequests.shift();
|
||||
if (x[2] == true) { tunnels[tunnelId].processWebSocket(x[0], x[1]); } else { tunnels[tunnelId].processRequest(x[0], x[1]); }
|
||||
}
|
||||
}
|
||||
}
|
||||
tunnel.onNextRequest = function () {
|
||||
if (tunnels == null) return;
|
||||
parent.parent.debug('webrelay', 'tunnel-onNextRequest');
|
||||
handleNextRequest();
|
||||
}
|
||||
tunnel.connect(userid, nodeid, addr, port, appid);
|
||||
tunnel.tunnelId = nextTunnelId++;
|
||||
tunnels[tunnel.tunnelId] = tunnel;
|
||||
}
|
||||
|
||||
// Close all tunnels
|
||||
obj.close = function () { close(); }
|
||||
|
||||
// Close all tunnels
|
||||
function close() {
|
||||
// Set the session as closed
|
||||
if (obj.closed == true) return;
|
||||
parent.parent.debug('webrelay', 'tunnel-close');
|
||||
obj.closed = true;
|
||||
|
||||
// Clear the time if present
|
||||
if (obj.expireTimer != null) { clearTimeout(obj.expireTimer); delete obj.expireTimer; }
|
||||
|
||||
// Close all tunnels
|
||||
for (var i in tunnels) { tunnels[i].close(); }
|
||||
tunnels = null;
|
||||
|
|
@ -184,7 +228,7 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
|
|||
for (var i in pendingRequests) { if (pendingRequests[i][2] == true) { pendingRequests[i][1].close(); } else { pendingRequests[i][1].end(); } }
|
||||
|
||||
// Notify of session closure
|
||||
if (obj.onclose) { obj.onclose(obj.userid + '/' + obj.sessionId); }
|
||||
if (obj.onclose) { obj.onclose(obj.sessionid); }
|
||||
|
||||
// Cleanup
|
||||
delete obj.userid;
|
||||
|
|
@ -196,7 +240,7 @@ module.exports.CreateWebRelaySession = function (parent, db, req, args, domain,
|
|||
|
||||
|
||||
// Construct a Web relay object
|
||||
module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
||||
module.exports.CreateWebRelay = function (parent, db, args, domain, mtype) {
|
||||
//const Net = require('net');
|
||||
const WebSocket = require('ws')
|
||||
|
||||
|
|
@ -204,26 +248,49 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
obj.lastOperation = Date.now();
|
||||
obj.relayActive = false;
|
||||
obj.closed = false;
|
||||
obj.isWebSocket = false;
|
||||
obj.isWebSocket = false; // If true, this request will not close and so, it can't be allowed to hold up other requests
|
||||
obj.isStreaming = false; // If true, this request will not close and so, it can't be allowed to hold up other requests
|
||||
obj.processedRequestCount = 0;
|
||||
obj.mtype = mtype;
|
||||
const constants = (require('crypto').constants ? require('crypto').constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
|
||||
|
||||
// Events
|
||||
obj.onclose = null;
|
||||
obj.oncompleted = null;
|
||||
obj.onconnect = null;
|
||||
obj.onNextRequest = null;
|
||||
|
||||
// Called when we need to close the tunnel because the response stream has closed
|
||||
function handleResponseClosure() { obj.close(); }
|
||||
|
||||
// Return cookie name and values
|
||||
function parseRequestCookies(cookiesString) {
|
||||
var r = {};
|
||||
if (typeof cookiesString != 'string') return r;
|
||||
var cookieString = cookiesString.split('; ');
|
||||
for (var i in cookieString) { var j = cookieString[i].indexOf('='); if (j > 0) { r[cookieString[i].substring(0, j)] = cookieString[i].substring(j + 1); } }
|
||||
return r;
|
||||
}
|
||||
|
||||
// Process a HTTP request
|
||||
obj.processRequest = function (req, res) {
|
||||
if (obj.relayActive == false) { console.log("ERROR: Attempt to use an unconnected tunnel"); return false; }
|
||||
parent.lastOperation = obj.lastOperation = Date.now();
|
||||
|
||||
// Check if this is a websocket
|
||||
if (req.headers['upgrade'] == 'websocket') { console.log('Attempt to process a websocket in HTTP tunnel method.'); res.end(); return false; }
|
||||
|
||||
// If the response stream is closed, close this tunnel right away
|
||||
res.socket.on('end', handleResponseClosure);
|
||||
|
||||
// Construct the HTTP request
|
||||
var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n';
|
||||
const blockedHeaders = ['origin', 'cookie']; // These are headers we do not forward
|
||||
const blockedHeaders = ['cookie', 'upgrade-insecure-requests', 'sec-ch-ua', 'sec-ch-ua-mobile', 'dnt', 'sec-fetch-user', 'sec-ch-ua-platform', 'sec-fetch-site', 'sec-fetch-mode', 'sec-fetch-dest']; // These are headers we do not forward
|
||||
for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } }
|
||||
var cookieStr = '';
|
||||
for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); }
|
||||
var reqCookies = parseRequestCookies(req.headers.cookie);
|
||||
for (var i in reqCookies) { if ((i != 'xid') && (i != 'xid.sig')) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + reqCookies[i]); } }
|
||||
if (cookieStr.length > 0) { request += 'cookie: ' + cookieStr + '\r\n' } // If we have session cookies, set them in the header here
|
||||
request += '\r\n';
|
||||
|
||||
|
|
@ -257,6 +324,9 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
// Pause the websocket until we get a tunnel connected
|
||||
obj.ws._socket.pause();
|
||||
|
||||
// If the response stream is closed, close this tunnel right away
|
||||
obj.ws._socket.on('end', function () { obj.close(); });
|
||||
|
||||
// Remove the trailing '/.websocket' if needed
|
||||
var baseurl = req.url, i = req.url.indexOf('?');
|
||||
if (i > 0) { baseurl = req.url.substring(0, i); }
|
||||
|
|
@ -264,7 +334,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
|
||||
// Construct the HTTP request
|
||||
var request = req.method + ' ' + req.url + ' HTTP/' + req.httpVersion + '\r\n';
|
||||
const blockedHeaders = ['origin', 'cookie', 'sec-websocket-extensions']; // These are headers we do not forward
|
||||
const blockedHeaders = ['cookie', 'sec-websocket-extensions']; // These are headers we do not forward
|
||||
for (var i in req.headers) { if (blockedHeaders.indexOf(i) == -1) { request += i + ': ' + req.headers[i] + '\r\n'; } }
|
||||
var cookieStr = '';
|
||||
for (var i in parent.webCookies) { if (cookieStr != '') { cookieStr += '; ' } cookieStr += (i + '=' + parent.webCookies[i].value); }
|
||||
|
|
@ -288,7 +358,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
|
||||
function sendWebSocketFrameToDevice(op, payload) {
|
||||
// Select a random mask
|
||||
const mask = parent.parent.crypto.randomBytes(4)
|
||||
const mask = parent.parent.parent.crypto.randomBytes(4)
|
||||
|
||||
// Setup header and mask
|
||||
var header = null;
|
||||
|
|
@ -324,6 +394,13 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
if (obj.closed == true) return;
|
||||
obj.closed = true;
|
||||
|
||||
// If we are processing a http response that terminates when it closes, do this now.
|
||||
if ((obj.socketParseState == 1) && (obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close')) {
|
||||
processHttpResponse(null, obj.socketAccumulator, true, true); // Indicate this tunnel is done and also closed, do not put a new request on this tunnel.
|
||||
obj.socketAccumulator = '';
|
||||
obj.socketParseState = 0;
|
||||
}
|
||||
|
||||
if (obj.tls) {
|
||||
try { obj.tls.end(); } catch (ex) { console.log(ex); }
|
||||
delete obj.tls;
|
||||
|
|
@ -354,7 +431,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
}
|
||||
|
||||
// Close any pending request
|
||||
if (obj.res) { obj.res.end(); delete obj.res; }
|
||||
if (obj.res) { obj.res.socket.removeListener('end', handleResponseClosure); obj.res.end(); delete obj.res; }
|
||||
if (obj.ws) { obj.ws.close(); delete obj.ws; }
|
||||
|
||||
// Event disconnection
|
||||
|
|
@ -363,7 +440,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
obj.relayActive = false;
|
||||
};
|
||||
|
||||
// Start the looppback server
|
||||
// Start the loopback server
|
||||
obj.connect = function (userid, nodeid, addr, port, appid) {
|
||||
if (obj.relayActive || obj.closed) return;
|
||||
obj.addr = addr;
|
||||
|
|
@ -373,7 +450,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
// Encode a cookie for the mesh relay
|
||||
const cookieContent = { userid: userid, domainid: domain.id, nodeid: nodeid, tcpport: port };
|
||||
if (addr != null) { cookieContent.tcpaddr = addr; }
|
||||
const cookie = parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey);
|
||||
const cookie = parent.parent.parent.encodeCookie(cookieContent, parent.parent.parent.loginCookieEncryptionKey);
|
||||
|
||||
try {
|
||||
// Setup the correct URL with domain and use TLS only if needed.
|
||||
|
|
@ -381,10 +458,11 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
const protocol = (args.tlsoffload) ? 'ws' : 'wss';
|
||||
var domainadd = '';
|
||||
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
|
||||
const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + cookie; // Protocol 14 is Web-TCP
|
||||
parent.parent.debug('relay', 'TCP: Connection websocket to ' + url);
|
||||
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=14&auth=' + cookie; // Protocol 14 is Web-TCP
|
||||
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
|
||||
parent.parent.parent.debug('relay', 'TCP: Connection websocket to ' + url);
|
||||
obj.wsClient = new WebSocket(url, options);
|
||||
obj.wsClient.on('open', function () { parent.parent.debug('relay', 'TCP: Relay websocket open'); });
|
||||
obj.wsClient.on('open', function () { parent.parent.parent.debug('relay', 'TCP: Relay websocket open'); });
|
||||
obj.wsClient.on('message', function (data) { // Make sure to handle flow control.
|
||||
if (obj.tls) {
|
||||
// WS --> TLS
|
||||
|
|
@ -399,13 +477,13 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
// TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel
|
||||
const tlsoptions = { socket: obj.ser, rejectUnauthorized: false };
|
||||
obj.tls = require('tls').connect(tlsoptions, function () {
|
||||
parent.parent.debug('relay', "Web Relay Secure TLS Connection");
|
||||
parent.parent.parent.debug('relay', "Web Relay Secure TLS Connection");
|
||||
obj.relayActive = true;
|
||||
parent.lastOperation = obj.lastOperation = Date.now(); // Update time of last opertion performed
|
||||
if (obj.onconnect) { obj.onconnect(obj.tunnelId); } // Event connection
|
||||
});
|
||||
obj.tls.setEncoding('binary');
|
||||
obj.tls.on('error', function (err) { parent.parent.debug('relay', "Web Relay TLS Connection Error", err); obj.close(); });
|
||||
obj.tls.on('error', function (err) { parent.parent.parent.debug('relay', "Web Relay TLS Connection Error", err); obj.close(); });
|
||||
|
||||
// Decrypted tunnel from TLS communcation to be forwarded to the browser
|
||||
obj.tls.on('data', function (data) { processHttpData(data); }); // TLS ---> Browser
|
||||
|
|
@ -420,8 +498,8 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
processRawHttpData(data);
|
||||
}
|
||||
});
|
||||
obj.wsClient.on('close', function () { parent.parent.debug('relay', 'TCP: Relay websocket closed'); obj.close(); });
|
||||
obj.wsClient.on('error', function (err) { parent.parent.debug('relay', 'TCP: Relay websocket error: ' + err); obj.close(); });
|
||||
obj.wsClient.on('close', function () { parent.parent.parent.debug('relay', 'TCP: Relay websocket closed'); obj.close(); });
|
||||
obj.wsClient.on('error', function (err) { parent.parent.parent.debug('relay', 'TCP: Relay websocket error: ' + err); obj.close(); });
|
||||
} catch (ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
|
|
@ -449,6 +527,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
obj.socketParseState = 0;
|
||||
obj.socketContentLengthRemaining = 0;
|
||||
function processHttpData(data) {
|
||||
//console.log('processHttpData', data.length);
|
||||
obj.socketAccumulator += data;
|
||||
while (true) {
|
||||
//console.log('ACC(' + obj.socketAccumulator + '): ' + obj.socketAccumulator);
|
||||
|
|
@ -472,9 +551,15 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check if this is a streaming response
|
||||
if ((obj.socketXHeader['content-type'] != null) && (obj.socketXHeader['content-type'].toLowerCase().indexOf('text/event-stream') >= 0)) {
|
||||
obj.isStreaming = true; // This tunnel is now a streaming tunnel and will not close anytime soon.
|
||||
if (obj.onNextRequest != null) obj.onNextRequest(); // Call this so that any HTTP requests that are waitting for this one to finish get handled by a new tunnel.
|
||||
}
|
||||
|
||||
// Check if this HTTP request has a body
|
||||
if ((obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close')) { obj.socketParseState = 1; }
|
||||
if (obj.socketXHeader['content-length'] != null) { obj.socketParseState = 1; }
|
||||
if ((obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close')) { obj.socketParseState = 1; }
|
||||
if ((obj.socketXHeader['transfer-encoding'] != null) && (obj.socketXHeader['transfer-encoding'].toLowerCase() == 'chunked')) { obj.socketParseState = 1; }
|
||||
if (obj.isWebSocket) {
|
||||
if ((obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'upgrade')) {
|
||||
|
|
@ -491,21 +576,35 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
}
|
||||
if (obj.socketParseState == 1) {
|
||||
var csize = -1;
|
||||
if ((obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close')) {
|
||||
// The body ends with a close, in this case, we will only process the header
|
||||
processHttpResponse(null, null, true);
|
||||
csize = 0;
|
||||
} else if (obj.socketXHeader['content-length'] != null) {
|
||||
if (obj.socketXHeader['content-length'] != null) {
|
||||
// The body length is specified by the content-length
|
||||
if (obj.socketContentLengthRemaining == 0) { obj.socketContentLengthRemaining = parseInt(obj.socketXHeader['content-length']); } // Set the remaining content-length if not set
|
||||
var data = obj.socketAccumulator.substring(0, obj.socketContentLengthRemaining); // Grab the available data, not passed the expected content-length
|
||||
obj.socketAccumulator = obj.socketAccumulator.substring(data.length); // Remove the data from the accumulator
|
||||
obj.socketContentLengthRemaining -= data.length; // Substract the obtained data from the expected size
|
||||
processHttpResponse(null, data, (obj.socketContentLengthRemaining == 0)); // Send any data we have, if we are done, signal the end of the response
|
||||
if (obj.socketContentLengthRemaining > 0) return; // If more data is needed, return now so we exit the while() loop.
|
||||
if (obj.socketContentLengthRemaining > 0) {
|
||||
// Send any data we have, if we are done, signal the end of the response
|
||||
processHttpResponse(null, data, false);
|
||||
return; // More data is needed, return now so we exit the while() loop.
|
||||
} else {
|
||||
// We are done with this request
|
||||
const closing = (obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close');
|
||||
if (closing) {
|
||||
// We need to close this tunnel.
|
||||
processHttpResponse(null, data, false);
|
||||
obj.close();
|
||||
} else {
|
||||
// Proceed with the next request.
|
||||
processHttpResponse(null, data, true);
|
||||
}
|
||||
}
|
||||
csize = 0; // We are done
|
||||
}
|
||||
else if ((obj.socketXHeader['transfer-encoding'] != null) && (obj.socketXHeader['transfer-encoding'].toLowerCase() == 'chunked')) {
|
||||
} else if ((obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close')) {
|
||||
// The body ends with a close, in this case, we will only process the header
|
||||
processHttpResponse(null, obj.socketAccumulator, false);
|
||||
obj.socketAccumulator = '';
|
||||
return;
|
||||
} else if ((obj.socketXHeader['transfer-encoding'] != null) && (obj.socketXHeader['transfer-encoding'].toLowerCase() == 'chunked')) {
|
||||
// The body is chunked
|
||||
var clen = obj.socketAccumulator.indexOf('\r\n');
|
||||
if (clen < 0) { return; } // Chunk length not found, exit now and get more data.
|
||||
|
|
@ -583,16 +682,17 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
}
|
||||
|
||||
// This is a fully parsed HTTP response from the remote device
|
||||
function processHttpResponse(header, data, done) {
|
||||
//console.log('processHttpResponse');
|
||||
function processHttpResponse(header, data, done, closed) {
|
||||
//console.log('processHttpResponse', header, data ? data.length : 0, done, closed);
|
||||
if (obj.isWebSocket == false) {
|
||||
if (obj.res == null) return;
|
||||
parent.lastOperation = obj.lastOperation = Date.now(); // Update time of last opertion performed
|
||||
|
||||
// If there is a header, send it
|
||||
if (header != null) {
|
||||
obj.res.status(parseInt(header.Directive[1])); // Set the status
|
||||
const blockHeaders = ['Directive', 'sec-websocket-extensions']; // We do not forward these headers
|
||||
const statusCode = parseInt(header.Directive[1]);
|
||||
if ((!isNaN(statusCode)) && (statusCode > 0) && (statusCode <= 999)) { obj.res.status(statusCode); } // Set the status
|
||||
const blockHeaders = ['Directive', 'sec-websocket-extensions', 'connection', 'transfer-encoding', 'last-modified', 'content-security-policy', 'cache-control']; // We do not forward these headers
|
||||
for (var i in header) {
|
||||
if (i == 'set-cookie') {
|
||||
for (var ii in header[i]) {
|
||||
|
|
@ -617,33 +717,38 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i, header[i]); } // Set the headers if not blocked
|
||||
else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i.trim(), header[i]); } // Set the headers if not blocked
|
||||
}
|
||||
obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future
|
||||
obj.res.set('Cache-Control', 'no-cache'); // Tell the browser not to cache the responses since since the relay port can be used for many relays
|
||||
// Dont set any Content-Security-Policy at all because some applications like Node-Red, access external websites from there javascript which would be forbidden by the below CSP
|
||||
//obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future
|
||||
//obj.res.set('Content-Security-Policy', "default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline';"); // Set an "allow all" policy, see if the can restrict this in the future
|
||||
obj.res.set('Cache-Control', 'no-store'); // Tell the browser not to cache the responses since since the relay port can be used for many relays
|
||||
}
|
||||
|
||||
// If there is data, send it
|
||||
if (data != null) { obj.res.write(data, 'binary'); }
|
||||
if (data != null) { try { obj.res.write(data, 'binary'); } catch (ex) { } }
|
||||
|
||||
// If we are done, close the response
|
||||
if (done == true) {
|
||||
// Close the response
|
||||
obj.res.socket.removeListener('end', handleResponseClosure);
|
||||
obj.res.end();
|
||||
delete obj.res;
|
||||
|
||||
// Event completion
|
||||
obj.processedRequestCount++;
|
||||
if (obj.oncompleted) { obj.oncompleted(obj.tunnelId); }
|
||||
if (obj.oncompleted) { obj.oncompleted(obj.tunnelId, closed); }
|
||||
}
|
||||
} else {
|
||||
// Tunnel is now in web socket pass-thru mode
|
||||
if ((typeof header.connection == 'string') && (header.connection.toLowerCase() == 'upgrade')) {
|
||||
// Websocket upgrade succesful
|
||||
obj.socketParseState = 2;
|
||||
} else {
|
||||
// Unable to upgrade to web socket
|
||||
obj.close();
|
||||
if (header != null) {
|
||||
if ((typeof header.connection == 'string') && (header.connection.toLowerCase() == 'upgrade')) {
|
||||
// Websocket upgrade succesful
|
||||
obj.socketParseState = 2;
|
||||
} else {
|
||||
// Unable to upgrade to web socket
|
||||
obj.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -651,7 +756,7 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
|
|||
// Send data thru the relay tunnel. Written to use TLS if needed.
|
||||
function send(data) { try { if (obj.tls) { obj.tls.write(data); } else { obj.wsClient.send(data); } } catch (ex) { } }
|
||||
|
||||
parent.parent.debug('relay', 'TCP: Request for web relay');
|
||||
parent.parent.parent.debug('relay', 'TCP: Request for web relay');
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
|
@ -716,7 +821,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
|
|||
obj.relaySocket = socket;
|
||||
obj.relaySocket.pause();
|
||||
obj.relaySocket.on('data', function (chunk) { // Make sure to handle flow control.
|
||||
if (obj.relayActive == true) { obj.relaySocket.pause(); obj.wsClient.send(chunk, function () { obj.relaySocket.resume(); }); }
|
||||
if (obj.relayActive == true) { obj.relaySocket.pause(); if (obj.wsClient != null) { obj.wsClient.send(chunk, function () { obj.relaySocket.resume(); }); } }
|
||||
});
|
||||
obj.relaySocket.on('end', function () { obj.close(); });
|
||||
obj.relaySocket.on('error', function (err) { obj.close(); });
|
||||
|
|
@ -726,7 +831,8 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
|
|||
const protocol = (args.tlsoffload) ? 'ws' : 'wss';
|
||||
var domainadd = '';
|
||||
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
|
||||
const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=10&auth=' + obj.infos.ip; // Protocol 10 is Web-RDP
|
||||
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=10&auth=' + obj.infos.ip; // Protocol 10 is Web-RDP
|
||||
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
|
||||
parent.parent.debug('relay', 'RDP: Connection websocket to ' + url);
|
||||
obj.wsClient = new WebSocket(url, options);
|
||||
obj.wsClient.on('open', function () { parent.parent.debug('relay', 'RDP: Relay websocket open'); });
|
||||
|
|
@ -737,22 +843,21 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
|
|||
obj.relaySocket.resume();
|
||||
}
|
||||
} else {
|
||||
if (typeof data == 'string') {
|
||||
// Forward any ping/pong commands to the browser
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (ex) { }
|
||||
try { // Forward any ping/pong commands to the browser
|
||||
var cmd = JSON.parse(data);
|
||||
if ((cmd != null) && (cmd.ctrlChannel == '102938')) {
|
||||
if (cmd.type == 'ping') { send(['ping']); }
|
||||
else if (cmd.type == 'pong') { send(['pong']); }
|
||||
}
|
||||
return;
|
||||
} catch (ex) { // You are not JSON data so just send over relaySocket
|
||||
obj.wsClient._socket.pause();
|
||||
try {
|
||||
obj.relaySocket.write(data, function () {
|
||||
if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } }
|
||||
});
|
||||
} catch (ex) { console.log(ex); obj.close(); }
|
||||
}
|
||||
obj.wsClient._socket.pause();
|
||||
try {
|
||||
obj.relaySocket.write(data, function () {
|
||||
if (obj.wsClient && obj.wsClient._socket) { try { obj.wsClient._socket.resume(); } catch (ex) { console.log(ex); } }
|
||||
});
|
||||
} catch (ex) { console.log(ex); obj.close(); }
|
||||
}
|
||||
});
|
||||
obj.wsClient.on('close', function () { parent.parent.debug('relay', 'RDP: Relay websocket closed'); obj.close(); });
|
||||
|
|
@ -785,7 +890,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
|
|||
rdpClient = require('./rdp').createClient(args).on('connect', function () {
|
||||
send(['rdp-connect']);
|
||||
if ((typeof obj.infos.options == 'object') && (obj.infos.options.savepass == true)) { saveRdpCredentials(); } // Save the credentials if needed
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.startTime = Date.now();
|
||||
|
||||
// Event session start
|
||||
|
|
@ -879,6 +984,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
|
|||
if ((node == null) || (visible == false) || ((rights & MESHRIGHT_REMOTECONTROL) == 0)) { obj.close(); return; }
|
||||
if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_REMOTEVIEWONLY) != 0)) { obj.viewonly = true; }
|
||||
if ((rights != MESHRIGHT_ADMIN) && ((rights & MESHRIGHT_DESKLIMITEDINPUT) != 0)) { obj.limitedinput = true; }
|
||||
node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials
|
||||
obj.mtype = node.mtype; // Store the device group type
|
||||
obj.meshid = node.meshid; // Store the MeshID
|
||||
|
||||
|
|
@ -941,7 +1047,11 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) {
|
|||
if ((k == 14) || (k == 28)) { ok = true; } // Enter and backspace
|
||||
if (ok == false) return;
|
||||
}
|
||||
if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventScancode(msg[1], msg[2]); } break;
|
||||
var extended = false;
|
||||
var extendedkeys = [57419,57421,57416,57424,57426,57427,57417,57425,57372,57397,57415,57423,57373,57400,57399];
|
||||
// left,right,up,down,insert,delete,pageup,pagedown,numpadenter,numpaddivide,home,end,controlright,altright,printscreen
|
||||
if (extendedkeys.includes(msg[1])) extended=true;
|
||||
if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventScancode(msg[1], msg[2], extended); } break;
|
||||
}
|
||||
case 'unicode': { if (rdpClient && (obj.viewonly != true)) { rdpClient.sendKeyEventUnicode(msg[1], msg[2]); } break; }
|
||||
case 'utype': {
|
||||
|
|
@ -1105,7 +1215,8 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
|
|||
const protocol = (args.tlsoffload) ? 'ws' : 'wss';
|
||||
var domainadd = '';
|
||||
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
|
||||
const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + obj.xcookie; // Protocol 11 is Web-SSH
|
||||
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + obj.xcookie; // Protocol 11 is Web-SSH
|
||||
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
|
||||
parent.parent.debug('relay', 'SSH: Connection websocket to ' + url);
|
||||
obj.wsClient = new WebSocket(url, options);
|
||||
obj.wsClient.on('open', function () { parent.parent.debug('relay', 'SSH: Relay websocket open'); });
|
||||
|
|
@ -1121,7 +1232,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
|
|||
obj.sshClient.on('ready', function () { // Authentication was successful.
|
||||
// If requested, save the credentials
|
||||
saveSshCredentials(obj.keep);
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.startTime = Date.now();
|
||||
|
||||
// Event start of session
|
||||
|
|
@ -1171,16 +1282,14 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
|
|||
ws._socket.resume();
|
||||
}
|
||||
} else {
|
||||
if (typeof data == 'string') {
|
||||
// Forward any ping/pong commands to the browser
|
||||
try { // Forward any ping/pong commands to the browser
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (ex) { }
|
||||
cmd = JSON.parse(data);
|
||||
if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); }
|
||||
return;
|
||||
} catch(ex) { // Relay WS --> SSH instead
|
||||
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
|
||||
}
|
||||
|
||||
// Relay WS --> SSH
|
||||
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
|
||||
}
|
||||
});
|
||||
obj.wsClient.on('close', function () { parent.parent.debug('relay', 'SSH: Relay websocket closed'); obj.close(); });
|
||||
|
|
@ -1208,7 +1317,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
|
|||
// Check if we have SSH credentials for this device
|
||||
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
|
||||
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
|
||||
const node = nodes[0];
|
||||
const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials
|
||||
if ((domain.allowsavingdevicecredentials === false) || (node.ssh == null) || (typeof node.ssh != 'object') || (node.ssh[obj.userid] == null) || (typeof node.ssh[obj.userid].u != 'string') || ((typeof node.ssh[obj.userid].p != 'string') && (typeof node.ssh[obj.userid].k != 'string'))) {
|
||||
// Send a request for SSH authentication
|
||||
try { ws.send(JSON.stringify({ action: 'sshauth' })) } catch (ex) { }
|
||||
|
|
@ -1256,7 +1365,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
|
|||
obj.termSize = msg;
|
||||
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
|
||||
if ((err != null) || (nodes == null) || (nodes.length != 1)) return;
|
||||
const node = nodes[0];
|
||||
const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials
|
||||
if (node.ssh != null) {
|
||||
obj.username = node.ssh.u;
|
||||
obj.privateKey = node.ssh.k;
|
||||
|
|
@ -1298,7 +1407,7 @@ module.exports.CreateSshRelay = function (parent, db, ws, req, args, domain) {
|
|||
parent.parent.db.Get(obj.cookie.nodeid, function (err, nodes) {
|
||||
if (obj.cookie == null) return; // obj has been cleaned up, just exit.
|
||||
if ((err != null) || (nodes == null) || (nodes.length != 1)) { parent.parent.debug('relay', 'SSH: Invalid device'); obj.close(); }
|
||||
const node = nodes[0];
|
||||
const node = parent.common.unEscapeLinksFieldName(nodes[0]); // unEscape node data for rdp/ssh credentials
|
||||
obj.nodeid = node._id; // Store the NodeID
|
||||
obj.meshid = node.meshid; // Store the MeshID
|
||||
obj.mtype = node.mtype; // Store the device group type
|
||||
|
|
@ -1443,7 +1552,8 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
|
|||
const protocol = (args.tlsoffload) ? 'ws' : 'wss';
|
||||
var domainadd = '';
|
||||
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
|
||||
const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + authCookie // Protocol 11 is Web-SSH
|
||||
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=11&auth=' + authCookie // Protocol 11 is Web-SSH
|
||||
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
|
||||
parent.parent.debug('relay', 'SSH: Connection websocket to ' + url);
|
||||
obj.wsClient = new WebSocket(url, options);
|
||||
obj.wsClient.on('open', function () { parent.parent.debug('relay', 'SSH: Relay websocket open'); });
|
||||
|
|
@ -1459,7 +1569,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
|
|||
obj.sshClient.on('ready', function () { // Authentication was successful.
|
||||
// If requested, save the credentials
|
||||
saveSshCredentials(obj.keep);
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.startTime = Date.now();
|
||||
|
||||
try {
|
||||
|
|
@ -1510,16 +1620,14 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
|
|||
ws._socket.resume();
|
||||
}
|
||||
} else {
|
||||
if (typeof data == 'string') {
|
||||
// Forward any ping/pong commands to the browser
|
||||
try { // Forward any ping/pong commands to the browser
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (ex) { }
|
||||
cmd = JSON.parse(data);
|
||||
if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { try { obj.ws.send(data); } catch (ex) { console.log(ex); } }
|
||||
return;
|
||||
} catch (ex) { // Relay WS --> SSH
|
||||
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
|
||||
}
|
||||
|
||||
// Relay WS --> SSH
|
||||
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
|
||||
}
|
||||
});
|
||||
obj.wsClient.on('close', function () {
|
||||
|
|
@ -1632,6 +1740,7 @@ module.exports.CreateSshTerminalRelay = function (parent, db, ws, req, domain, u
|
|||
if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid
|
||||
parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) {
|
||||
if (obj.ws == null) return; // obj has been cleaned up, just exit.
|
||||
node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials
|
||||
|
||||
// Check permissions
|
||||
if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights
|
||||
|
|
@ -1796,7 +1905,8 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
|
|||
const protocol = (args.tlsoffload) ? 'ws' : 'wss';
|
||||
var domainadd = '';
|
||||
if ((domain.dns == null) && (domain.id != '')) { domainadd = domain.id + '/' }
|
||||
const url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=13&auth=' + authCookie // Protocol 13 is Web-SSH-Files
|
||||
var url = protocol + '://localhost:' + args.port + '/' + domainadd + (((obj.mtype == 3) && (obj.relaynodeid == null)) ? 'local' : 'mesh') + 'relay.ashx?p=13&auth=' + authCookie // Protocol 13 is Web-SSH-Files
|
||||
if (domain.id != '') { url += '&domainid=' + domain.id; } // Since we are using "localhost", we are going to signal what domain we are on using a URL argument.
|
||||
parent.parent.debug('relay', 'SSH: Connection websocket to ' + url);
|
||||
obj.wsClient = new WebSocket(url, options);
|
||||
obj.wsClient.on('open', function () { parent.parent.debug('relay', 'SSH: Relay websocket open'); });
|
||||
|
|
@ -1812,7 +1922,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
|
|||
obj.sshClient.on('ready', function () { // Authentication was successful.
|
||||
// If requested, save the credentials
|
||||
saveSshCredentials(obj.keep);
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64');
|
||||
obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$');
|
||||
obj.startTime = Date.now();
|
||||
|
||||
// Event start of session
|
||||
|
|
@ -1857,16 +1967,15 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
|
|||
ws._socket.resume();
|
||||
}
|
||||
} else {
|
||||
if (typeof data == 'string') {
|
||||
try {
|
||||
// Forward any ping/pong commands to the browser
|
||||
var cmd = null;
|
||||
try { cmd = JSON.parse(data); } catch (ex) { }
|
||||
cmd = JSON.parse(data);
|
||||
if ((cmd != null) && (cmd.ctrlChannel == '102938') && ((cmd.type == 'ping') || (cmd.type == 'pong'))) { obj.ws.send(data); }
|
||||
return;
|
||||
} catch (ex) { // Relay WS --> SSH
|
||||
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
|
||||
}
|
||||
|
||||
// Relay WS --> SSH
|
||||
if ((data.length > 0) && (obj.ser != null)) { try { obj.ser.updateBuffer(data); } catch (ex) { console.log(ex); } }
|
||||
}
|
||||
});
|
||||
obj.wsClient.on('close', function () {
|
||||
|
|
@ -2161,6 +2270,7 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
|
|||
if ((user == null) || (req.query.nodeid == null)) { obj.close(); return; } // Invalid nodeid
|
||||
parent.GetNodeWithRights(domain, user, req.query.nodeid, function (node, rights, visible) {
|
||||
if (obj.ws == null) return; // obj has been cleaned up, just exit.
|
||||
node = parent.common.unEscapeLinksFieldName(node); // unEscape node data for rdp/ssh credentials
|
||||
|
||||
// Check permissions
|
||||
if ((rights & 8) == 0) { obj.close(); return; } // No MESHRIGHT_REMOTECONTROL rights
|
||||
|
|
@ -2225,6 +2335,6 @@ module.exports.CreateSshFilesRelay = function (parent, db, ws, req, domain, user
|
|||
function checkRelayRights(parent, domain, user, relayNodeId, func) {
|
||||
if (relayNodeId == null) { func(true); return; } // No relay, do nothing.
|
||||
parent.GetNodeWithRights(domain, user, relayNodeId, function (node, rights, visible) {
|
||||
func((node != null) && (rights == 0xFFFFFFFF));
|
||||
func((node != null) && ((rights & 0x00200008) != 0)); // MESHRIGHT_REMOTECONTROL or MESHRIGHT_RELAY rights
|
||||
});
|
||||
}
|
||||
|
|
|
|||
585
authenticode.js
585
authenticode.js
|
|
@ -50,6 +50,47 @@ function createOutFile(args, filename) {
|
|||
args.out = outputFileName.join('.');
|
||||
}
|
||||
|
||||
// Hash an object
|
||||
function hashObject(obj) {
|
||||
if (obj == null) { return null; }
|
||||
const hash = crypto.createHash('sha384');
|
||||
if (Buffer.isBuffer(obj)) { hash.update(obj); } else { hash.update(JSON.stringify(obj)); }
|
||||
return hash.digest().toString('hex');
|
||||
}
|
||||
|
||||
// Load a .bmp file.
|
||||
function loadBitmap(bitmapFile) {
|
||||
var bitmapData = null;
|
||||
try { bitmapData = fs.readFileSync(bitmapFile); } catch (ex) { }
|
||||
if ((bitmapData == null) || (bitmapData.length < 14) || (bitmapData[0] != 0x42) || (bitmapData[1] != 0x4D)) return null;
|
||||
return bitmapData.slice(14);
|
||||
}
|
||||
|
||||
// Load a .ico file. This will load all icons in the file into a icon group object
|
||||
function loadIcon(iconFile) {
|
||||
var iconData = null;
|
||||
try { iconData = fs.readFileSync(iconFile); } catch (ex) { }
|
||||
if ((iconData == null) || (iconData.length < 6) || (iconData[0] != 0) || (iconData[1] != 0)) return null;
|
||||
const r = { resType: iconData.readUInt16LE(2), resCount: iconData.readUInt16LE(4), icons: {} };
|
||||
if (r.resType != 1) return null;
|
||||
var ptr = 6;
|
||||
for (var i = 1; i <= r.resCount; i++) {
|
||||
var icon = {};
|
||||
icon.width = iconData[ptr + 0];
|
||||
icon.height = iconData[ptr + 1];
|
||||
icon.colorCount = iconData[ptr + 2];
|
||||
icon.planes = iconData.readUInt16LE(ptr + 4);
|
||||
icon.bitCount = iconData.readUInt16LE(ptr + 6);
|
||||
icon.bytesInRes = iconData.readUInt32LE(ptr + 8);
|
||||
icon.iconCursorId = i;
|
||||
const offset = iconData.readUInt32LE(ptr + 12);
|
||||
icon.icon = iconData.slice(offset, offset + icon.bytesInRes);
|
||||
r.icons[i] = icon;
|
||||
ptr += 16;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Load certificates and private key from PEM files
|
||||
function loadCertificates(pemFileNames) {
|
||||
var certs = [], keys = [];
|
||||
|
|
@ -257,7 +298,7 @@ function createAuthenticodeHandler(path) {
|
|||
for (var i = 0; i < obj.header.coff.numberOfSections; i++) {
|
||||
var section = {};
|
||||
buf = readFileSlice(obj.header.SectionHeadersPtr + (i * 40), 40);
|
||||
if (buf[0] != 46) { obj.close(); return false; }; // Name of the section must start with a dot. If not, something is wrong.
|
||||
if ((buf[0] != 46) && (buf[0] != 95)) { obj.close(); return false; }; // Name of the section must start with a dot or underscore. If not, something is wrong.
|
||||
var sectionName = buf.slice(0, 8).toString().trim('\0');
|
||||
var j = sectionName.indexOf('\0');
|
||||
if (j >= 0) { sectionName = sectionName.substring(0, j); } // Trim any trailing zeroes
|
||||
|
|
@ -568,16 +609,17 @@ function createAuthenticodeHandler(path) {
|
|||
// Pad the resource section & allocate the buffer
|
||||
const fileAlign = obj.header.peWindows.fileAlignment
|
||||
var resSizeTotal = resSizes.tables + resSizes.items + resSizes.names + resSizes.data;
|
||||
var resNoPadding = resSizeTotal + 4; // TODO: Not sure why this is off by 4
|
||||
if ((resSizeTotal % fileAlign) != 0) { resSizeTotal += (fileAlign - (resSizeTotal % fileAlign)); }
|
||||
const resSectionBuffer = Buffer.alloc(resSizeTotal);
|
||||
|
||||
// Write the resource section, calling a recusrize method
|
||||
// Write the resource section, calling a recursive method
|
||||
const resPointers = { tables: 0, items: resSizes.tables, names: resSizes.tables + resSizes.items, data: resSizes.tables + resSizes.items + resSizes.names };
|
||||
createResourceSection(resources, resSectionBuffer, resPointers);
|
||||
//console.log('generateResourceSection', resPointers);
|
||||
|
||||
// Done, return the result
|
||||
return resSectionBuffer;
|
||||
return { size: resNoPadding, data: resSectionBuffer };
|
||||
}
|
||||
|
||||
// Return the total size of a resource header, this is a recursive method
|
||||
|
|
@ -720,6 +762,28 @@ function createAuthenticodeHandler(path) {
|
|||
return pkcs7raw;
|
||||
}
|
||||
|
||||
|
||||
// Get bitmaps information from resource
|
||||
obj.getBitmapInfo = function () {
|
||||
const r = {}, ptr = obj.header.sections['.rsrc'].rawAddr;
|
||||
|
||||
// Find and parse each icon
|
||||
const bitmaps = {}
|
||||
for (var i = 0; i < obj.resources.entries.length; i++) {
|
||||
if (obj.resources.entries[i].name == resourceDefaultNames.bitmaps) {
|
||||
for (var j = 0; j < obj.resources.entries[i].table.entries.length; j++) {
|
||||
const bitmapName = obj.resources.entries[i].table.entries[j].name;
|
||||
const offsetToData = obj.resources.entries[i].table.entries[j].table.entries[0].item.offsetToData;
|
||||
const size = obj.resources.entries[i].table.entries[j].table.entries[0].item.size;
|
||||
const actualPtr = (offsetToData - obj.header.sections['.rsrc'].virtualAddr) + ptr;
|
||||
bitmaps[bitmapName] = readFileSlice(actualPtr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bitmaps;
|
||||
}
|
||||
|
||||
// Get icon information from resource
|
||||
obj.getIconInfo = function () {
|
||||
const r = {}, ptr = obj.header.sections['.rsrc'].rawAddr;
|
||||
|
|
@ -777,9 +841,126 @@ function createAuthenticodeHandler(path) {
|
|||
return r;
|
||||
}
|
||||
|
||||
// Set bitmap information
|
||||
obj.setBitmapInfo = function (bitmapInfo) {
|
||||
// Delete all bitmaps resources
|
||||
var resourcesEntries = [];
|
||||
for (var i = 0; i < obj.resources.entries.length; i++) {
|
||||
if (obj.resources.entries[i].name != resourceDefaultNames.bitmaps) {
|
||||
resourcesEntries.push(obj.resources.entries[i]);
|
||||
}
|
||||
}
|
||||
obj.resources.entries = resourcesEntries;
|
||||
|
||||
// Add all bitmap entries
|
||||
const bitmapEntry = { name: resourceDefaultNames.bitmaps, table: { characteristics: 0, timeDateStamp: 0, majorVersion: 0, minorVersion: 0, entries: [] } };
|
||||
for (var i in bitmapInfo) {
|
||||
var name = i;
|
||||
if (parseInt(i) == name) { name = parseInt(i); }
|
||||
const bitmapItemEntry = { name: name, table: { characteristics: 0, timeDateStamp: 0, majorVersion: 0, minorVersion: 0, entries: [{ name: 1033, item: { buffer: bitmapInfo[i], codePage: 0 } }] } }
|
||||
bitmapEntry.table.entries.push(bitmapItemEntry);
|
||||
}
|
||||
obj.resources.entries.push(bitmapEntry);
|
||||
|
||||
// Sort the resources by name. This is required.
|
||||
function resSort(a, b) {
|
||||
if ((typeof a == 'string') && (typeof b == 'string')) { if (a < b) return -1; if (a > b) return 1; return 0; }
|
||||
if ((typeof a == 'number') && (typeof b == 'number')) { return a - b; }
|
||||
if ((typeof a == 'string') && (typeof b == 'number')) { return -1; }
|
||||
return 1;
|
||||
}
|
||||
const names = [];
|
||||
for (var i = 0; i < obj.resources.entries.length; i++) { names.push(obj.resources.entries[i].name); }
|
||||
names.sort(resSort);
|
||||
var newEntryOrder = [];
|
||||
for (var i in names) {
|
||||
for (var j = 0; j < obj.resources.entries.length; j++) {
|
||||
if (obj.resources.entries[j].name == names[i]) { newEntryOrder.push(obj.resources.entries[j]); }
|
||||
}
|
||||
}
|
||||
obj.resources.entries = newEntryOrder;
|
||||
}
|
||||
|
||||
// Set icon information
|
||||
obj.setIconInfo = function (iconInfo) {
|
||||
// Delete all icon and icon groups resources
|
||||
var resourcesEntries = [];
|
||||
for (var i = 0; i < obj.resources.entries.length; i++) {
|
||||
if ((obj.resources.entries[i].name != resourceDefaultNames.icon) && (obj.resources.entries[i].name != resourceDefaultNames.iconGroups)) {
|
||||
resourcesEntries.push(obj.resources.entries[i]);
|
||||
}
|
||||
}
|
||||
obj.resources.entries = resourcesEntries;
|
||||
|
||||
// Count the icon groups and re-number all icons
|
||||
var iconGroupCount = 0, nextIconNumber = 1;
|
||||
for (var i in iconInfo) {
|
||||
iconGroupCount++;
|
||||
var xicons = {};
|
||||
for (var j in iconInfo[i].icons) { xicons[nextIconNumber++] = iconInfo[i].icons[j]; }
|
||||
iconInfo[i].icons = xicons;
|
||||
}
|
||||
if (iconGroupCount == 0) return; // If there are no icon groups, we are done
|
||||
|
||||
// Add the new icons entry
|
||||
const iconsEntry = { name: resourceDefaultNames.icon, table: { characteristics: 0, timeDateStamp: 0, majorVersion: 0, minorVersion: 0, entries: [] } };
|
||||
for (var i in iconInfo) {
|
||||
for (var j in iconInfo[i].icons) {
|
||||
var name = j;
|
||||
if (parseInt(j) == name) { name = parseInt(j); }
|
||||
const iconItemEntry = { name: name, table: { characteristics: 0, timeDateStamp: 0, majorVersion: 0, minorVersion: 0, entries: [{ name: 1033, item: { buffer: iconInfo[i].icons[j].icon, codePage: 0 } }] } }
|
||||
iconsEntry.table.entries.push(iconItemEntry);
|
||||
}
|
||||
}
|
||||
obj.resources.entries.push(iconsEntry);
|
||||
|
||||
// Add the new icon group entry
|
||||
const groupEntry = { name: resourceDefaultNames.iconGroups, table: { characteristics: 0, timeDateStamp: 0, majorVersion: 0, minorVersion: 0, entries: [] } };
|
||||
for (var i in iconInfo) {
|
||||
// Build icon group struct
|
||||
var iconCount = 0, p = 6;
|
||||
for (var j in iconInfo[i].icons) { iconCount++; }
|
||||
const buf = Buffer.alloc(6 + (iconCount * 14));
|
||||
buf.writeUInt16LE(iconInfo[i].resType, 2);
|
||||
buf.writeUInt16LE(iconCount, 4);
|
||||
for (var j in iconInfo[i].icons) {
|
||||
buf[p] = iconInfo[i].icons[j].width;
|
||||
buf[p + 1] = iconInfo[i].icons[j].height;
|
||||
buf[p + 2] = iconInfo[i].icons[j].colorCount;
|
||||
buf.writeUInt16LE(iconInfo[i].icons[j].planes, p + 4);
|
||||
buf.writeUInt16LE(iconInfo[i].icons[j].bitCount, p + 6);
|
||||
buf.writeUInt32LE(iconInfo[i].icons[j].bytesInRes, p + 8);
|
||||
buf.writeUInt16LE(j, p + 12);
|
||||
p += 14;
|
||||
}
|
||||
var name = i;
|
||||
if (parseInt(i) == name) { name = parseInt(i); }
|
||||
const groupItemEntry = { name: name, table: { characteristics: 0, timeDateStamp: 0, majorVersion: 0, minorVersion: 0, entries: [{ name: 1033, item: { buffer: buf, codePage: 0 } }] } }
|
||||
groupEntry.table.entries.push(groupItemEntry);
|
||||
}
|
||||
obj.resources.entries.push(groupEntry);
|
||||
|
||||
// Sort the resources by name. This is required.
|
||||
function resSort(a, b) {
|
||||
if ((typeof a == 'string') && (typeof b == 'string')) { if (a < b) return -1; if (a > b) return 1; return 0; }
|
||||
if ((typeof a == 'number') && (typeof b == 'number')) { return a - b; }
|
||||
if ((typeof a == 'string') && (typeof b == 'number')) { return -1; }
|
||||
return 1;
|
||||
}
|
||||
const names = [];
|
||||
for (var i = 0; i < obj.resources.entries.length; i++) { names.push(obj.resources.entries[i].name); }
|
||||
names.sort(resSort);
|
||||
var newEntryOrder = [];
|
||||
for (var i in names) {
|
||||
for (var j = 0; j < obj.resources.entries.length; j++) {
|
||||
if (obj.resources.entries[j].name == names[i]) { newEntryOrder.push(obj.resources.entries[j]); }
|
||||
}
|
||||
}
|
||||
obj.resources.entries = newEntryOrder;
|
||||
}
|
||||
|
||||
// Decode the version information from the resource
|
||||
obj.getVersionInfo = function () {
|
||||
//console.log('READ', getVersionInfoData().toString('hex'));
|
||||
var r = {}, info = readVersionInfo(getVersionInfoData(), 0);
|
||||
if ((info == null) || (info.stringFiles == null)) return null;
|
||||
var StringFileInfo = null;
|
||||
|
|
@ -787,6 +968,8 @@ function createAuthenticodeHandler(path) {
|
|||
if ((StringFileInfo == null) || (StringFileInfo.stringTable == null) || (StringFileInfo.stringTable.strings == null)) return null;
|
||||
const strings = StringFileInfo.stringTable.strings;
|
||||
for (var i in strings) { r[strings[i].key] = strings[i].value; }
|
||||
r['~FileVersion'] = (info.fixedFileInfo.dwFileVersionMS >> 16) + '.' + (info.fixedFileInfo.dwFileVersionMS & 0xFFFF) + '.' + (info.fixedFileInfo.dwFileVersionLS >> 16) + '.' + (info.fixedFileInfo.dwFileVersionLS & 0xFFFF);
|
||||
r['~ProductVersion'] = (info.fixedFileInfo.dwProductVersionMS >> 16) + '.' + (info.fixedFileInfo.dwProductVersionMS & 0xFFFF) + '.' + (info.fixedFileInfo.dwProductVersionLS >> 16) + '.' + (info.fixedFileInfo.dwProductVersionLS & 0xFFFF);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -794,7 +977,7 @@ function createAuthenticodeHandler(path) {
|
|||
obj.setVersionInfo = function (versions) {
|
||||
// Convert the version information into a string array
|
||||
const stringArray = [];
|
||||
for (var i in versions) { stringArray.push({ key: i, value: versions[i] }); }
|
||||
for (var i in versions) { if (!i.startsWith('~')) { stringArray.push({ key: i, value: versions[i] }); } }
|
||||
|
||||
// Get the existing version data and switch the strings to the new strings
|
||||
var r = {}, info = readVersionInfo(getVersionInfoData(), 0);
|
||||
|
|
@ -804,6 +987,20 @@ function createAuthenticodeHandler(path) {
|
|||
if ((StringFileInfo == null) || (StringFileInfo.stringTable == null) || (StringFileInfo.stringTable.strings == null)) return;
|
||||
StringFileInfo.stringTable.strings = stringArray;
|
||||
|
||||
// Set the file version
|
||||
if (versions['~FileVersion'] != null) {
|
||||
const FileVersionSplit = versions['~FileVersion'].split('.');
|
||||
info.fixedFileInfo.dwFileVersionMS = (parseInt(FileVersionSplit[0]) << 16) + parseInt(FileVersionSplit[1]);
|
||||
info.fixedFileInfo.dwFileVersionLS = (parseInt(FileVersionSplit[2]) << 16) + parseInt(FileVersionSplit[3]);
|
||||
}
|
||||
|
||||
// Set the product version
|
||||
if (versions['~ProductVersion'] != null) {
|
||||
const ProductVersionSplit = versions['~ProductVersion'].split('.');
|
||||
info.fixedFileInfo.dwProductVersionMS = (parseInt(ProductVersionSplit[0]) << 16) + parseInt(ProductVersionSplit[1]);
|
||||
info.fixedFileInfo.dwProductVersionLS = (parseInt(ProductVersionSplit[2]) << 16) + parseInt(ProductVersionSplit[3]);
|
||||
}
|
||||
|
||||
// Re-encode the version information into a buffer
|
||||
var verInfoResBufArray = [];
|
||||
writeVersionInfo(verInfoResBufArray, info);
|
||||
|
|
@ -1142,6 +1339,21 @@ function createAuthenticodeHandler(path) {
|
|||
return hash.digest();
|
||||
}
|
||||
|
||||
// Hash the file using the selected hashing system skipping resource section
|
||||
// This hash skips the executables CRC, sections table, resource section, code signing data and signing block
|
||||
obj.getHashOfSection = function (algo, sectionName) {
|
||||
if (obj.header.sections[sectionName] == null) return null;
|
||||
|
||||
// Get the section start and size
|
||||
const sectionPtr = obj.header.sections[sectionName].rawAddr;
|
||||
const sectionSize = obj.header.sections[sectionName].rawSize;
|
||||
|
||||
// Hash the remaining data
|
||||
const hash = crypto.createHash(algo);
|
||||
runHash(hash, sectionPtr, sectionPtr + sectionSize);
|
||||
return hash.digest();
|
||||
}
|
||||
|
||||
// Hash the file from start to end loading 64k chunks
|
||||
function runHash(hash, start, end) {
|
||||
var ptr = start;
|
||||
|
|
@ -1235,7 +1447,7 @@ function createAuthenticodeHandler(path) {
|
|||
if (args.hash == 'sha512') { hashOid = forge.pki.oids.sha512; fileHash = obj.getHash('sha512'); }
|
||||
if (args.hash == 'sha224') { hashOid = forge.pki.oids.sha224; fileHash = obj.getHash('sha224'); }
|
||||
if (args.hash == 'md5') { hashOid = forge.pki.oids.md5; fileHash = obj.getHash('md5'); }
|
||||
if (hashOid == null) { func(false); return; };
|
||||
if (hashOid == null) { func('Invalid signing hash: ' + args.hash); return; };
|
||||
|
||||
// Create the signature block
|
||||
var xp7 = forge.pkcs7.createSignedData();
|
||||
|
|
@ -1354,7 +1566,11 @@ function createAuthenticodeHandler(path) {
|
|||
options.protocol = timeServerUrl.protocol;
|
||||
options.hostname = timeServerUrl.hostname;
|
||||
options.path = timeServerUrl.pathname;
|
||||
options.port = ((timeServerUrl.port == '') ? 80 : parseInt(timeServerUrl.port));
|
||||
let http = require("http")
|
||||
if (options.protocol === "https:"){
|
||||
http = require("https")
|
||||
}
|
||||
options.port = ((timeServerUrl.port == '') ? (options.protocol === "https:" ? 443 : 80) : parseInt(timeServerUrl.port));
|
||||
|
||||
if (options.proxy == null) {
|
||||
// No proxy needed
|
||||
|
|
@ -1372,7 +1588,7 @@ function createAuthenticodeHandler(path) {
|
|||
|
||||
// Set up the request
|
||||
var responseAccumulator = '';
|
||||
var req = require('http').request(options, function (res) {
|
||||
var req = http.request(options, function (res) {
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', function (chunk) { responseAccumulator += chunk; });
|
||||
res.on('end', function () { func(null, responseAccumulator); });
|
||||
|
|
@ -1393,12 +1609,12 @@ function createAuthenticodeHandler(path) {
|
|||
proxyOptions.protocol = proxyUrl.protocol;
|
||||
proxyOptions.hostname = proxyUrl.hostname;
|
||||
proxyOptions.path = options.hostname + ':' + options.port;
|
||||
proxyOptions.port = ((proxyUrl.port == '') ? 80 : parseInt(proxyUrl.port));
|
||||
proxyOptions.port = ((proxyUrl.port == '') ? (options.protocol === "https:" ? 443 : 80) : parseInt(proxyUrl.port));
|
||||
}
|
||||
|
||||
// Set up the proxy request
|
||||
var responseAccumulator = '';
|
||||
var req = require('http').request(proxyOptions);
|
||||
var req = http.request(proxyOptions);
|
||||
req.on('error', function (err) { func('' + err); });
|
||||
req.on('connect', function (res, socket, head) {
|
||||
// Make a request over the HTTP tunnel
|
||||
|
|
@ -1453,7 +1669,7 @@ function createAuthenticodeHandler(path) {
|
|||
// Open the output file
|
||||
var output = null;
|
||||
try { output = fs.openSync(args.out, 'w+'); } catch (ex) { }
|
||||
if (output == null) { func(false); return; }
|
||||
if (output == null) { func('Unable to open output file: ' + args.out); return; }
|
||||
var tmp, written = 0, executableSize = obj.header.sigpos ? obj.header.sigpos : filesize;
|
||||
|
||||
// Compute pre-header length and copy that to the new file
|
||||
|
|
@ -1531,6 +1747,16 @@ function createAuthenticodeHandler(path) {
|
|||
fs.closeSync(output);
|
||||
}
|
||||
|
||||
// Find where a directory value is in the old sections and map it to the new sections
|
||||
function correctDirectoryValue(oldSections, newSections, value) {
|
||||
for (var i in oldSections) {
|
||||
if ((value >= oldSections[i].virtualAddr) && (value < (oldSections[i].virtualAddr + oldSections[i].virtualSize))) {
|
||||
return newSections[i].virtualAddr + (value - oldSections[i].virtualAddr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Save the executable
|
||||
obj.writeExecutable = function (args, cert, func) {
|
||||
// Open the file
|
||||
|
|
@ -1541,52 +1767,91 @@ function createAuthenticodeHandler(path) {
|
|||
var fullHeaderLen = obj.header.SectionHeadersPtr + (obj.header.coff.numberOfSections * 40);
|
||||
var fullHeader = readFileSlice(written, fullHeaderLen);
|
||||
|
||||
// Create the resource section
|
||||
const rsrcSectionX = generateResourceSection(obj.resources); // This section is created with padding already included
|
||||
var rsrcSection = rsrcSectionX.data;
|
||||
var rsrcSectionVirtualSize = rsrcSectionX.size;
|
||||
var rsrcSectionRawSize = rsrcSection.length;
|
||||
|
||||
// Calculate the location and original and new size of the resource segment
|
||||
var fileAlign = obj.header.peWindows.fileAlignment
|
||||
var resPtr = obj.header.sections['.rsrc'].rawAddr;
|
||||
var oldResSize = obj.header.sections['.rsrc'].rawSize;
|
||||
var newResSize = obj.header.sections['.rsrc'].rawSize; // Testing 102400
|
||||
var newResSize = rsrcSection.length;
|
||||
var resDeltaSize = newResSize - oldResSize;
|
||||
|
||||
// Compute the sizeOfInitializedData
|
||||
var sizeOfInitializedData = 0;
|
||||
for (var i in obj.header.sections) {
|
||||
if (i != '.text') {
|
||||
if (i == '.rsrc') {
|
||||
sizeOfInitializedData += rsrcSectionRawSize;
|
||||
} else {
|
||||
sizeOfInitializedData += obj.header.sections[i].rawSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change PE optional header sizeOfInitializedData standard field
|
||||
fullHeader.writeUInt32LE(obj.header.peStandard.sizeOfInitializedData + resDeltaSize, obj.header.peOptionalHeaderLocation + 8);
|
||||
fullHeader.writeUInt32LE(obj.header.peWindows.sizeOfImage, obj.header.peOptionalHeaderLocation + 56); // TODO: resDeltaSize
|
||||
fullHeader.writeUInt32LE(sizeOfInitializedData, obj.header.peOptionalHeaderLocation + 8);
|
||||
|
||||
// Update the checksum to zero
|
||||
fullHeader.writeUInt32LE(0, obj.header.peOptionalHeaderLocation + 64);
|
||||
|
||||
// Make change to the data directories header to fix resource segment size and add/remove signature
|
||||
const pePlusOffset = (obj.header.pe32plus == 0) ? 0 : 16; // This header is the same for 32 and 64 bit, but 64bit is offset by 16 bytes.
|
||||
if (obj.header.dataDirectories.exportTable.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.exportTable.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 96 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.importTable.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.importTable.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 104 + pePlusOffset); }
|
||||
//fullHeader.writeUInt32LE(obj.header.dataDirectories.resourceTable.size + resDeltaSize, obj.header.peOptionalHeaderLocation + 116 + pePlusOffset); // Change the resource segment size
|
||||
if (obj.header.dataDirectories.exceptionTableAddr.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.exceptionTableAddr.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 120 + pePlusOffset); }
|
||||
fullHeader.writeUInt32LE(0, obj.header.peOptionalHeaderLocation + 128 + pePlusOffset); // certificate table addr (TODO)
|
||||
fullHeader.writeUInt32LE(0, obj.header.peOptionalHeaderLocation + 132 + pePlusOffset); // certificate table size (TODO)
|
||||
if (obj.header.dataDirectories.baseRelocationTable.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.baseRelocationTable.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 136 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.debug.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.debug.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 144 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.globalPtr.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.globalPtr.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 160 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.tLSTable.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.tLSTable.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 168 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.loadConfigTable.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.loadConfigTable.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 176 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.boundImport.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.boundImport.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 184 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.iAT.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.iAT.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 192 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.delayImportDescriptor.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.delayImportDescriptor.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 200 + pePlusOffset); }
|
||||
if (obj.header.dataDirectories.clrRuntimeHeader.addr > resPtr) { fullHeader.writeUInt32LE(obj.header.dataDirectories.clrRuntimeHeader.addr + resDeltaSize, obj.header.peOptionalHeaderLocation + 208 + pePlusOffset); }
|
||||
// We are going to setup the old a new sections here, we need this to correct directory values
|
||||
var oldSections = obj.header.sections;
|
||||
var newSections = {};
|
||||
|
||||
// Make changes to the segments table
|
||||
var virtualAddress = 4096;
|
||||
for (var i in obj.header.sections) {
|
||||
const section = obj.header.sections[i];
|
||||
newSections[i] = { virtualSize: section.virtualSize };
|
||||
if (i == '.rsrc') {
|
||||
// Change the size of the resource section
|
||||
fullHeader.writeUInt32LE(section.rawSize + resDeltaSize, section.ptr + 8); // virtualSize (TODO)
|
||||
fullHeader.writeUInt32LE(section.rawSize + resDeltaSize, section.ptr + 16); // rawSize
|
||||
fullHeader.writeUInt32LE(rsrcSectionVirtualSize, section.ptr + 8); // virtualSize
|
||||
fullHeader.writeUInt32LE(rsrcSectionRawSize, section.ptr + 16); // rawSize
|
||||
|
||||
// Set the virtual address of the section
|
||||
fullHeader.writeUInt32LE(virtualAddress, section.ptr + 12); // Virtual address
|
||||
newSections[i].virtualAddr = virtualAddress;
|
||||
var virtualAddressPadding = (rsrcSectionVirtualSize % 4096);
|
||||
virtualAddress += rsrcSectionVirtualSize;
|
||||
if (virtualAddressPadding != 0) { virtualAddress += (4096 - virtualAddressPadding); }
|
||||
} else {
|
||||
// Change the location of any other section if located after the resource section
|
||||
if (section.virtualAddr > resPtr) { fullHeader.writeUInt32LE(section.virtualAddr + resDeltaSize, section.ptr + 12); }
|
||||
if (section.rawAddr > resPtr) { fullHeader.writeUInt32LE(section.rawAddr + resDeltaSize, section.ptr + 20); }
|
||||
|
||||
// Set the virtual address of the section
|
||||
fullHeader.writeUInt32LE(virtualAddress, section.ptr + 12); // Virtual address
|
||||
newSections[i].virtualAddr = virtualAddress;
|
||||
var virtualAddressPadding = (section.virtualSize % 4096);
|
||||
virtualAddress += section.virtualSize;
|
||||
if (virtualAddressPadding != 0) { virtualAddress += (4096 - virtualAddressPadding); }
|
||||
}
|
||||
}
|
||||
|
||||
// Make change to the data directories header to fix resource segment size and add/remove signature
|
||||
const pePlusOffset = (obj.header.pe32plus == 0) ? 0 : 16; // This header is the same for 32 and 64 bit, but 64bit is offset by 16 bytes.
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.exportTable.addr), obj.header.peOptionalHeaderLocation + 96 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.importTable.addr), obj.header.peOptionalHeaderLocation + 104 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(rsrcSectionVirtualSize, obj.header.peOptionalHeaderLocation + 116 + pePlusOffset); // Change the resource segment size
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.exceptionTableAddr.addr), obj.header.peOptionalHeaderLocation + 120 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(0, obj.header.peOptionalHeaderLocation + 128 + pePlusOffset); // certificate table addr (TODO)
|
||||
fullHeader.writeUInt32LE(0, obj.header.peOptionalHeaderLocation + 132 + pePlusOffset); // certificate table size (TODO)
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.baseRelocationTable.addr), obj.header.peOptionalHeaderLocation + 136 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.debug.addr), obj.header.peOptionalHeaderLocation + 144 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.globalPtr.addr), obj.header.peOptionalHeaderLocation + 160 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.tLSTable.addr), obj.header.peOptionalHeaderLocation + 168 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.loadConfigTable.addr), obj.header.peOptionalHeaderLocation + 176 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.boundImport.addr), obj.header.peOptionalHeaderLocation + 184 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.iAT.addr), obj.header.peOptionalHeaderLocation + 192 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.delayImportDescriptor.addr), obj.header.peOptionalHeaderLocation + 200 + pePlusOffset);
|
||||
fullHeader.writeUInt32LE(correctDirectoryValue(oldSections, newSections, obj.header.dataDirectories.clrRuntimeHeader.addr), obj.header.peOptionalHeaderLocation + 208 + pePlusOffset);
|
||||
|
||||
// Write size of image. We put the next virtual address.
|
||||
fullHeader.writeUInt32LE(virtualAddress, obj.header.peOptionalHeaderLocation + 56); // sizeOfImage
|
||||
|
||||
// Write the entire header to the destination file
|
||||
//console.log('Write header', fullHeader.length, written);
|
||||
fs.writeSync(output, fullHeader);
|
||||
|
|
@ -1602,7 +1867,6 @@ function createAuthenticodeHandler(path) {
|
|||
}
|
||||
|
||||
// Write the new resource section
|
||||
var rsrcSection = generateResourceSection(obj.resources);
|
||||
fs.writeSync(output, rsrcSection);
|
||||
written += rsrcSection.length;
|
||||
//console.log('Write res', rsrcSection.length, written);
|
||||
|
|
@ -1806,40 +2070,58 @@ function start() {
|
|||
console.log(" node authenticode.js [command] [options]");
|
||||
console.log("Commands:");
|
||||
console.log(" info: Show information about an executable.");
|
||||
console.log(" --exe [file] Required executable to view information.");
|
||||
console.log(" --json Show information in JSON format.");
|
||||
console.log(" --exe [file] Required executable to view information.");
|
||||
console.log(" --json Show information in JSON format.");
|
||||
console.log(" sign: Sign an executable.");
|
||||
console.log(" --exe [file] Required executable to sign.");
|
||||
console.log(" --out [file] Resulting signed executable.");
|
||||
console.log(" --pem [pemfile] Certificate & private key to sign the executable with.");
|
||||
console.log(" --desc [description] Description string to embbed into signature.");
|
||||
console.log(" --url [url] URL to embbed into signature.");
|
||||
console.log(" --hash [method] Default is SHA384, possible value: MD5, SHA224, SHA256, SHA384 or SHA512.");
|
||||
console.log(" --time [url] The time signing server URL.");
|
||||
console.log(" --proxy [url] The HTTP proxy to use to contact the time signing server, must start with http://");
|
||||
console.log(" --exe [file] Required executable to sign.");
|
||||
console.log(" --out [file] Resulting signed executable.");
|
||||
console.log(" --pem [pemfile] Certificate & private key to sign the executable with.");
|
||||
console.log(" --desc [description] Description string to embbed into signature.");
|
||||
console.log(" --url [url] URL to embbed into signature.");
|
||||
console.log(" --hash [method] Default is SHA384, possible value: MD5, SHA224, SHA256, SHA384 or SHA512.");
|
||||
console.log(" --time [url] The time signing server URL.");
|
||||
console.log(" --proxy [url] The HTTP proxy to use to contact the time signing server, must start with http://");
|
||||
console.log(" unsign: Remove the signature from the executable.");
|
||||
console.log(" --exe [file] Required executable to un-sign.");
|
||||
console.log(" --out [file] Resulting executable with signature removed.");
|
||||
console.log(" --exe [file] Required executable to un-sign.");
|
||||
console.log(" --out [file] Resulting executable with signature removed.");
|
||||
console.log(" createcert: Create a code signging self-signed certificate and key.");
|
||||
console.log(" --out [pemfile] Required certificate file to create.");
|
||||
console.log(" --cn [value] Required certificate common name.");
|
||||
console.log(" --country [value] Certificate country name.");
|
||||
console.log(" --state [value] Certificate state name.");
|
||||
console.log(" --locality [value] Certificate locality name.");
|
||||
console.log(" --org [value] Certificate organization name.");
|
||||
console.log(" --ou [value] Certificate organization unit name.");
|
||||
console.log(" --serial [value] Certificate serial number.");
|
||||
console.log(" --out [pemfile] Required certificate file to create.");
|
||||
console.log(" --cn [value] Required certificate common name.");
|
||||
console.log(" --country [value] Certificate country name.");
|
||||
console.log(" --state [value] Certificate state name.");
|
||||
console.log(" --locality [value] Certificate locality name.");
|
||||
console.log(" --org [value] Certificate organization name.");
|
||||
console.log(" --ou [value] Certificate organization unit name.");
|
||||
console.log(" --serial [value] Certificate serial number.");
|
||||
console.log(" timestamp: Add a signed timestamp to an already signed executable.");
|
||||
console.log(" --exe [file] Required executable to sign.");
|
||||
console.log(" --out [file] Resulting signed executable.");
|
||||
console.log(" --time [url] The time signing server URL.");
|
||||
console.log(" --proxy [url] The HTTP proxy to use to contact the time signing server, must start with http://");
|
||||
console.log(" --exe [file] Required executable to timestamp.");
|
||||
console.log(" --out [file] Resulting signed executable.");
|
||||
console.log(" --time [url] The time signing server URL.");
|
||||
console.log(" --proxy [url] The HTTP proxy to use to contact the time signing server, must start with http://");
|
||||
console.log(" bitmaps: Show bitmap resources in the executable.");
|
||||
console.log(" --exe [file] Input executable.");
|
||||
console.log(" savebitmap: Save a single bitmap to a .bmp file.");
|
||||
console.log(" --exe [file] Input executable.");
|
||||
console.log(" --out [file] Resulting .ico file.");
|
||||
console.log(" --bitmap [number] Bitmap number to save to file.");
|
||||
console.log(" icons: Show the icon resources in the executable.");
|
||||
console.log(" --exe [file] Input executable.");
|
||||
console.log(" saveicon: Save a single icon bitmap to a .ico file.");
|
||||
console.log(" --exe [file] Input executable.");
|
||||
console.log(" --out [file] Resulting .ico file.");
|
||||
console.log(" --icon [number] Icon number to save to file.");
|
||||
console.log(" saveicons: Save an icon group to a .ico file.");
|
||||
console.log(" --exe [file] Input executable.");
|
||||
console.log(" --out [file] Resulting .ico file.");
|
||||
console.log(" --icongroup [groupNumber] Icon groupnumber to save to file.");
|
||||
console.log("");
|
||||
console.log("Note that certificate PEM files must first have the signing certificate,");
|
||||
console.log("followed by all certificates that form the trust chain.");
|
||||
console.log("");
|
||||
console.log("When doing sign/unsign, you can also change resource properties of the generated file.");
|
||||
console.log("");
|
||||
console.log(" --fileversionnumber n.n.n.n");
|
||||
console.log(" --productversionnumber n.n.n.n");
|
||||
console.log(" --filedescription [value]");
|
||||
console.log(" --fileversion [value]");
|
||||
console.log(" --internalname [value]");
|
||||
|
|
@ -1847,11 +2129,15 @@ function start() {
|
|||
console.log(" --originalfilename [value]");
|
||||
console.log(" --productname [value]");
|
||||
console.log(" --productversion [value]");
|
||||
console.log(" --removeicongroup [number]");
|
||||
console.log(" --removebitmap [number]");
|
||||
console.log(" --icon [groupNumber],[filename.ico]");
|
||||
console.log(" --bitmap [number],[filename.bmp]");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that a valid command is passed in
|
||||
if (['info', 'sign', 'unsign', 'createcert', 'icons', 'saveicon', 'header', 'timestamp', 'signblock'].indexOf(process.argv[2].toLowerCase()) == -1) {
|
||||
if (['info', 'sign', 'unsign', 'createcert', 'icons', 'bitmaps', 'saveicon', 'saveicons', 'savebitmap', 'header', 'sections', 'timestamp', 'signblock'].indexOf(process.argv[2].toLowerCase()) == -1) {
|
||||
console.log("Invalid command: " + process.argv[2]);
|
||||
console.log("Valid commands are: info, sign, unsign, createcert, timestamp");
|
||||
return;
|
||||
|
|
@ -1867,7 +2153,7 @@ function start() {
|
|||
if (exe == null) { console.log("Unable to parse executable file: " + args.exe); return; }
|
||||
}
|
||||
|
||||
// Parse the resources and make any required changes
|
||||
// Parse the string resources and make any required changes
|
||||
var resChanges = false, versionStrings = null;
|
||||
if (exe != null) {
|
||||
versionStrings = exe.getVersionInfo();
|
||||
|
|
@ -1876,16 +2162,88 @@ function start() {
|
|||
const prop = versionProperties[i], propl = prop.toLowerCase();
|
||||
if (args[propl] && (args[propl] != versionStrings[prop])) { versionStrings[prop] = args[propl]; resChanges = true; }
|
||||
}
|
||||
if (args['fileversionnumber'] != null) {
|
||||
const fileVerSplit = args['fileversionnumber'].split('.');
|
||||
if (fileVerSplit.length != 4) { console.log("--fileversionnumber must be of format n.n.n.n, for example: 1.2.3.4"); return; }
|
||||
for (var i in fileVerSplit) { var n = parseInt(fileVerSplit[i]); if ((n < 0) || (n > 65535)) { console.log("--fileversionnumber numbers must be between 0 and 65535."); return; } }
|
||||
if (args['fileversionnumber'] != versionStrings['~FileVersion']) { versionStrings['~FileVersion'] = args['fileversionnumber']; resChanges = true; }
|
||||
}
|
||||
if (args['productversionnumber'] != null) {
|
||||
const productVerSplit = args['productversionnumber'].split('.');
|
||||
if (productVerSplit.length != 4) { console.log("--productversionnumber must be of format n.n.n.n, for example: 1.2.3.4"); return; }
|
||||
for (var i in productVerSplit) { var n = parseInt(productVerSplit[i]); if ((n < 0) || (n > 65535)) { console.log("--productversionnumber numbers must be between 0 and 65535."); return; } }
|
||||
if (args['productversionnumber'] != versionStrings['~ProductVersion']) { versionStrings['~ProductVersion'] = args['productversionnumber']; resChanges = true; }
|
||||
}
|
||||
if (resChanges == true) { exe.setVersionInfo(versionStrings); }
|
||||
}
|
||||
|
||||
// Parse the icon changes
|
||||
resChanges = false;
|
||||
var icons = null, bitmaps = null;
|
||||
if (exe != null) {
|
||||
icons = exe.getIconInfo();
|
||||
bitmaps = exe.getBitmapInfo();
|
||||
if (typeof args['removeicongroup'] == 'string') { // If --removeicongroup is used, it's to remove an existing icon group
|
||||
const groupsToRemove = args['removeicongroup'].split(',');
|
||||
for (var i in groupsToRemove) { if (icons[groupsToRemove[i]] != null) { delete icons[groupsToRemove[i]]; resChanges = true; } }
|
||||
} else if (typeof args['removeicongroup'] == 'number') {
|
||||
if (icons[args['removeicongroup']] != null) { delete icons[args['removeicongroup']]; resChanges = true; }
|
||||
}
|
||||
if (typeof args['removebitmap'] == 'string') { // If --removebitmap is used
|
||||
const bitmapsToRemove = args['removebitmap'].split(',');
|
||||
for (var i in bitmapsToRemove) { if (bitmaps[bitmapsToRemove[i]] != null) { delete bitmaps[bitmapsToRemove[i]]; resChanges = true; } }
|
||||
} else if (typeof args['removebitmap'] == 'number') {
|
||||
if (bitmaps[args['removebitmap']] != null) { delete bitmaps[args['removebitmap']]; resChanges = true; }
|
||||
}
|
||||
if (typeof args['icon'] == 'string') { // If --icon is used, it's to add or replace an existing icon group
|
||||
const iconToAddSplit = args['icon'].split(',');
|
||||
if (iconToAddSplit.length != 2) { console.log("The --icon format is: --icon [number],[file]."); return; }
|
||||
const iconName = parseInt(iconToAddSplit[0]);
|
||||
const iconFile = iconToAddSplit[1];
|
||||
const icon = loadIcon(iconFile);
|
||||
if (icon == null) { console.log("Unable to load icon: " + iconFile); return; }
|
||||
if (icons[iconName] != null) {
|
||||
const iconHash = hashObject(icon); // Compute the new icon group hash
|
||||
const iconHash2 = hashObject(icons[iconName]); // Computer the old icon group hash
|
||||
if (iconHash != iconHash2) { icons[iconName] = icon; resChanges = true; } // If different, replace the icon group
|
||||
} else {
|
||||
icons[iconName] = icon; // We are adding an icon group
|
||||
resChanges = true;
|
||||
}
|
||||
}
|
||||
if (typeof args['bitmap'] == 'string') { // If --bitmap is used, it's to add or replace an existing bitmap
|
||||
const bitmapToAddSplit = args['bitmap'].split(',');
|
||||
if (bitmapToAddSplit.length != 2) { console.log("The --bitmap format is: --bitmap [number],[file]."); return; }
|
||||
const bitmapName = parseInt(bitmapToAddSplit[0]);
|
||||
const bitmapFile = bitmapToAddSplit[1];
|
||||
const bitmap = loadBitmap(bitmapFile);
|
||||
if (bitmap == null) { console.log("Unable to load bitmap: " + bitmapFile); return; }
|
||||
if (bitmaps[bitmapName] != null) {
|
||||
const bitmapHash = hashObject(bitmap); // Compute the new bitmap hash
|
||||
const bitmapHash2 = hashObject(bitmaps[bitmapName]); // Computer the old bitmap hash
|
||||
if (bitmapHash != bitmapHash2) { bitmaps[bitmapName] = bitmap; resChanges = true; } // If different, replace the new bitmap
|
||||
} else {
|
||||
bitmaps[bitmapName] = bitmap; // We are adding an new bitmap
|
||||
resChanges = true;
|
||||
}
|
||||
}
|
||||
if (resChanges == true) {
|
||||
exe.setIconInfo(icons);
|
||||
exe.setBitmapInfo(bitmaps);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the command
|
||||
var command = process.argv[2].toLowerCase();
|
||||
if (command == 'info') { // Get signature information about an executable
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
if (args.json) {
|
||||
var r = {}, versionInfo = exe.getVersionInfo();
|
||||
if (versionInfo != null) { r.versionInfo = versionInfo; }
|
||||
var r = {}, stringInfo = exe.getVersionInfo();
|
||||
if (stringInfo != null) {
|
||||
r.versionInfo = {};
|
||||
r.stringInfo = {};
|
||||
for (var i in stringInfo) { if (i.startsWith('~')) { r.versionInfo[i.substring(1)] = stringInfo[i]; } else { r.stringInfo[i] = stringInfo[i]; } }
|
||||
}
|
||||
if (exe.fileHashAlgo != null) {
|
||||
r.signture = {};
|
||||
if (exe.fileHashAlgo != null) { r.signture.hashMethod = exe.fileHashAlgo; }
|
||||
|
|
@ -1896,7 +2254,12 @@ function start() {
|
|||
console.log(JSON.stringify(r, null, 2));
|
||||
} else {
|
||||
var versionInfo = exe.getVersionInfo();
|
||||
if (versionInfo != null) { console.log("Version Information:"); for (var i in versionInfo) { if (versionInfo[i] == null) { console.log(' ' + i + ': (Empty)'); } else { console.log(' ' + i + ': \"' + versionInfo[i] + '\"'); } } }
|
||||
if (versionInfo != null) {
|
||||
console.log("Version Information:");
|
||||
for (var i in versionInfo) { if (i.startsWith('~') == true) { console.log(' ' + i.substring(1) + ': ' + versionInfo[i] + ''); } }
|
||||
console.log("String Information:");
|
||||
for (var i in versionInfo) { if (i.startsWith('~') == false) { if (versionInfo[i] == null) { console.log(' ' + i + ': (Empty)'); } else { console.log(' ' + i + ': \"' + versionInfo[i] + '\"'); } } }
|
||||
}
|
||||
console.log("Checksum Information:");
|
||||
console.log(" Header CheckSum: 0x" + exe.header.peWindows.checkSum.toString(16));
|
||||
console.log(" Actual CheckSum: 0x" + exe.header.peWindows.checkSumActual.toString(16));
|
||||
|
|
@ -1914,6 +2277,26 @@ function start() {
|
|||
if (command == 'header') { // Display the full executable header in JSON format
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
console.log(exe.header);
|
||||
// Check that the header is valid
|
||||
var ptr = 1024, sizeOfCode = 0, sizeOfInitializedData = 0;
|
||||
for (var i in exe.header.sections) {
|
||||
if (i == '.text') { sizeOfCode += exe.header.sections[i].rawSize; } else { sizeOfInitializedData += exe.header.sections[i].rawSize; }
|
||||
if (exe.header.sections[i].rawAddr != ptr) { console.log('WARNING: ' + i + ' section should have a rawAddr or ' + ptr + ', but has ' + exe.header.sections[i].rawAddr + ' instead.'); }
|
||||
ptr += exe.header.sections[i].rawSize;
|
||||
}
|
||||
if (exe.header.peStandard.sizeOfCode != sizeOfCode) { console.log('WARNING: Size of code is ' + exe.header.peStandard.sizeOfCode + ', should be ' + sizeOfCode + '.'); }
|
||||
if (exe.header.peStandard.sizeOfInitializedData != sizeOfInitializedData) { console.log('WARNING: Size of initialized data is ' + exe.header.peStandard.sizeOfInitializedData + ', should be ' + sizeOfInitializedData + '.'); }
|
||||
}
|
||||
if (command == 'sections') { // Display sections in CSV format
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
var csvHeader = 'section';
|
||||
for (var i in exe.header.sections['.text']) { csvHeader += ',' + i; }
|
||||
console.log(csvHeader);
|
||||
for (var i in exe.header.sections) {
|
||||
var csvData = i;
|
||||
for (var j in exe.header.sections[i]) { csvData += ',' + exe.header.sections[i][j]; }
|
||||
console.log(csvData);
|
||||
}
|
||||
}
|
||||
if (command == 'sign') { // Sign an executable
|
||||
if (typeof args.exe != 'string') { console.log("Missing --exe [filename]"); return; }
|
||||
|
|
@ -1944,7 +2327,7 @@ function start() {
|
|||
if (resChanges == false) {
|
||||
if (exe.header.signed) {
|
||||
console.log("Unsigning to " + args.out);
|
||||
exe.unsign(args); // Simple unsign, copy most of the original file.
|
||||
exe.unsign(args); // Simple unsign, copy most of the original file.
|
||||
console.log("Done.");
|
||||
} else {
|
||||
console.log("Executable is not signed.");
|
||||
|
|
@ -1967,6 +2350,32 @@ function start() {
|
|||
fs.writeFileSync(args.out, pki.certificateToPem(cert.cert) + '\r\n' + pki.privateKeyToPem(cert.key));
|
||||
console.log("Done.");
|
||||
}
|
||||
if (command == 'bitmaps') { // Show bitmaps in the executable
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
if (args.json) {
|
||||
var bitmapInfo = exe.getBitmapInfo();
|
||||
console.log(JSON.stringify(bitmapInfo, null, 2));
|
||||
} else {
|
||||
var bitmapInfo = exe.getBitmapInfo();
|
||||
if (bitmapInfo != null) {
|
||||
console.log("Bitmap Information:");
|
||||
for (var i in bitmapInfo) { console.log(' ' + i + ': ' + bitmapInfo[i].length + ' byte' + ((bitmapInfo[i].length > 1) ? 's' : '') + '.'); }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (command == 'savebitmap') { // Save an bitmap to file
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
if (typeof args.out != 'string') { console.log("Missing --out [filename]"); return; }
|
||||
if (typeof args.bitmap != 'number') { console.log("Missing or incorrect --bitmap [number]"); return; }
|
||||
const bitmapInfo = exe.getBitmapInfo();
|
||||
if (bitmapInfo[args.bitmap] == null) { console.log("Unknown bitmap: " + args.bitmap); return; }
|
||||
|
||||
console.log("Writing to " + args.out);
|
||||
var bitmapHeader = Buffer.from('424D000000000000000036000000', 'hex');
|
||||
bitmapHeader.writeUInt32LE(14 + bitmapInfo[args.bitmap].length, 2); // Write the full size of the bitmap file
|
||||
fs.writeFileSync(args.out, Buffer.concat([bitmapHeader, bitmapInfo[args.bitmap]]));
|
||||
console.log("Done.");
|
||||
}
|
||||
if (command == 'icons') { // Show icons in the executable
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
if (args.json) {
|
||||
|
|
@ -2006,6 +2415,48 @@ function start() {
|
|||
fs.writeFileSync(args.out, Buffer.concat([buf, icon.icon]));
|
||||
console.log("Done.");
|
||||
}
|
||||
if (command == 'saveicons') { // Save an icon group to file
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
if (typeof args.out != 'string') { console.log("Missing --out [filename]"); return; }
|
||||
if (typeof args.icongroup != 'number') { console.log("Missing or incorrect --icongroup [number]"); return; }
|
||||
const iconInfo = exe.getIconInfo();
|
||||
const iconGroup = iconInfo[args.icongroup];
|
||||
if (iconGroup == null) { console.log("Invalid or incorrect --icongroup [number]"); return; }
|
||||
|
||||
// Count the number of icons in the group
|
||||
var iconCount = 0;
|
||||
for (var i in iconGroup.icons) { iconCount++; }
|
||||
|
||||
// .ico header: https://en.wikipedia.org/wiki/ICO_(file_format)
|
||||
const iconFileData = [];
|
||||
const header = Buffer.alloc(6);
|
||||
header.writeUInt16LE(1, 2); // 1 = Icon, 2 = Cursor
|
||||
header.writeUInt16LE(iconCount, 4); // Icon Count, always 1 in our case
|
||||
iconFileData.push(header);
|
||||
|
||||
// Store each icon header
|
||||
var offsetPtr = 6 + (16 * iconCount);
|
||||
for (var i in iconGroup.icons) {
|
||||
const buf = Buffer.alloc(16);
|
||||
buf[0] = iconGroup.icons[i].width; // Width (0 = 256)
|
||||
buf[1] = iconGroup.icons[i].height; // Height (0 = 256)
|
||||
buf[2] = iconGroup.icons[i].colorCount; // Colors
|
||||
buf.writeUInt16LE(iconGroup.icons[i].planes, 4); // Color planes
|
||||
buf.writeUInt16LE(iconGroup.icons[i].bitCount, 6); // Bits per pixel
|
||||
buf.writeUInt32LE(iconGroup.icons[i].icon.length, 8); // Size
|
||||
buf.writeUInt32LE(offsetPtr, 12); // Offset
|
||||
offsetPtr += iconGroup.icons[i].icon.length;
|
||||
iconFileData.push(buf);
|
||||
}
|
||||
|
||||
// Store each icon
|
||||
for (var i in iconGroup.icons) { iconFileData.push(iconGroup.icons[i].icon); }
|
||||
|
||||
// Write the .ico file
|
||||
console.log("Writing to " + args.out);
|
||||
fs.writeFileSync(args.out, Buffer.concat(iconFileData));
|
||||
console.log("Done.");
|
||||
}
|
||||
if (command == 'signblock') { // Display the raw signature block of the executable in hex
|
||||
if (exe == null) { console.log("Missing --exe [filename]"); return; }
|
||||
var buf = exe.getRawSignatureBlock();
|
||||
|
|
@ -2034,4 +2485,6 @@ if (require.main === module) { start(); }
|
|||
// Exports
|
||||
module.exports.createAuthenticodeHandler = createAuthenticodeHandler;
|
||||
module.exports.loadCertificates = loadCertificates;
|
||||
|
||||
module.exports.loadIcon = loadIcon;
|
||||
module.exports.loadBitmap = loadBitmap;
|
||||
module.exports.hashObject = hashObject;
|
||||
BIN
bin/Microsoft.NodejsTools.WebRole.dll
Normal file
BIN
bin/Microsoft.NodejsTools.WebRole.dll
Normal file
Binary file not shown.
2
bin/meshcentral
Normal file
2
bin/meshcentral
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#! /usr/bin/env node
|
||||
require("../meshcentral.js");
|
||||
|
|
@ -247,16 +247,25 @@ module.exports.CertificateOperations = function (parent) {
|
|||
// Get the certificate common name
|
||||
var certCommonName = r.certs[0].subject.getField('CN');
|
||||
if (certCommonName == null) { amtacmactivation.acmCertErrors.push("Unable to get Intel AMT activation certificate common name."); continue; }
|
||||
var certCommonNameSplit = certCommonName.value.split('.');
|
||||
var topLevel = certCommonNameSplit[certCommonNameSplit.length - 1].toLowerCase();
|
||||
var topLevelNum = TopLevelDomainExtendedSupport[topLevel];
|
||||
if (topLevelNum != null) {
|
||||
while (certCommonNameSplit.length > topLevelNum) { certCommonNameSplit.shift(); }
|
||||
acmconfig.cn = certCommonNameSplit.join('.');
|
||||
} else {
|
||||
if (amtacmactivation.strictcommonname == true) {
|
||||
// Use the certificate common name exactly
|
||||
acmconfig.cn = certCommonName.value;
|
||||
} else {
|
||||
// Check if Intel AMT will allow some flexibility in the certificate common name
|
||||
var certCommonNameSplit = certCommonName.value.split('.');
|
||||
var topLevel = certCommonNameSplit[certCommonNameSplit.length - 1].toLowerCase();
|
||||
var topLevelNum = TopLevelDomainExtendedSupport[topLevel];
|
||||
if (topLevelNum != null) {
|
||||
while (certCommonNameSplit.length > topLevelNum) { certCommonNameSplit.shift(); }
|
||||
acmconfig.cn = certCommonNameSplit.join('.');
|
||||
} else {
|
||||
acmconfig.cn = certCommonName.value;
|
||||
}
|
||||
}
|
||||
|
||||
if(r.certs[0].md){
|
||||
acmconfig.hashAlgorithm = r.certs[0].md.algorithm;
|
||||
}
|
||||
|
||||
delete acmconfig.cert;
|
||||
delete acmconfig.certpass;
|
||||
acmconfig.certs = orderedCerts;
|
||||
|
|
@ -627,9 +636,16 @@ module.exports.CertificateOperations = function (parent) {
|
|||
};
|
||||
|
||||
// Return the SHA384 hash of the certificate public key
|
||||
obj.getPublicKeyHashBinary = function (cert) {
|
||||
var publickey = obj.pki.certificateFromPem(cert).publicKey;
|
||||
return obj.pki.getPublicKeyFingerprint(publickey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
|
||||
obj.getPublicKeyHashBinary = function (pem) {
|
||||
const { X509Certificate } = require('crypto');
|
||||
if (X509Certificate == null) {
|
||||
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
|
||||
return obj.pki.getPublicKeyFingerprint(obj.pki.certificateFromPem(pem).publicKey, { encoding: 'binary', md: obj.forge.md.sha384.create() });
|
||||
} else {
|
||||
// This version of NodeJS supports x509 certificates
|
||||
var cert = new X509Certificate(pem);
|
||||
return obj.crypto.createHash('sha384').update(cert.publicKey.export({ type: ((cert.publicKey.asymmetricKeyType == 'rsa') ? 'pkcs1' : 'spki'), format: 'der' })).digest('binary');
|
||||
}
|
||||
};
|
||||
|
||||
// Return the SHA384 hash of the certificate, return binary
|
||||
|
|
@ -734,14 +750,17 @@ module.exports.CertificateOperations = function (parent) {
|
|||
}
|
||||
|
||||
// Return true if the name is found in the certificates names, we support wildcard certificates
|
||||
obj.compareCertificateNames = function(certNames, name) {
|
||||
obj.compareCertificateNames = function (certNames, name) {
|
||||
if (certNames == null) return false;
|
||||
if (certNames.indexOf(name.toLowerCase()) >= 0) return true;
|
||||
for (var i in certNames) {
|
||||
if ((certNames[i].startsWith('*.') == true) && (name.endsWith(certNames[i].substring(1)) == true)) { return true; }
|
||||
if (certNames[i].startsWith('http://*.') == true) {
|
||||
if (name.endsWith(certNames[i].substring(8)) == true) { return true; }
|
||||
if ((certNames[i].endsWith('/') == true) && (name.endsWith(certNames[i].substring(8, certNames[i].length - 1)) == true)) { return true; }
|
||||
name = name.toLowerCase();
|
||||
var xcertNames = [];
|
||||
for (var i in certNames) { xcertNames.push(certNames[i].toLowerCase()); }
|
||||
if (xcertNames.indexOf(name) >= 0) return true;
|
||||
for (var i in xcertNames) {
|
||||
if ((xcertNames[i].startsWith('*.') == true) && (name.endsWith(xcertNames[i].substring(1)) == true)) { return true; }
|
||||
if (xcertNames[i].startsWith('http://*.') == true) {
|
||||
if (name.endsWith(xcertNames[i].substring(8)) == true) { return true; }
|
||||
if ((xcertNames[i].endsWith('/') == true) && (name.endsWith(xcertNames[i].substring(8, xcertNames[i].length - 1)) == true)) { return true; }
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -749,12 +768,102 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
// Return true if the certificate is valid
|
||||
obj.checkCertificate = function (pem, key) {
|
||||
var cert = null;
|
||||
try { cert = obj.pki.certificateFromPem(pem); } catch (ex) { return false; } // Unable to decode certificate
|
||||
if (cert.serialNumber == '') return false; // Empty serial number is not allowed.
|
||||
const { X509Certificate } = require('crypto');
|
||||
if (X509Certificate == null) {
|
||||
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
|
||||
var cert = null;
|
||||
try { cert = obj.pki.certificateFromPem(pem); } catch (ex) { return false; } // Unable to decode certificate
|
||||
if (cert.serialNumber == '') return false; // Empty serial number is not allowed.
|
||||
} else {
|
||||
// This version of NodeJS supports x509 certificates
|
||||
try {
|
||||
const cert = new X509Certificate(pem);
|
||||
if ((cert.serialNumber == '') || (cert.serialNumber == null)) return false; // Empty serial number is not allowed.
|
||||
} catch (ex) { return false; } // Unable to decode certificate
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the Common Name from a certificate
|
||||
obj.getCertificateCommonName = function (pem, field) {
|
||||
if (field == null) { field = 'CN'; }
|
||||
const { X509Certificate } = require('crypto');
|
||||
if (X509Certificate == null) {
|
||||
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
|
||||
var cert = obj.pki.certificateFromPem(pem);
|
||||
if (cert.subject.getField(field) != null) return cert.subject.getField(field).value;
|
||||
} else {
|
||||
// This version of NodeJS supports x509 certificates
|
||||
const subjects = new X509Certificate(pem).subject.split('\n');
|
||||
for (var i in subjects) { if (subjects[i].startsWith(field + '=')) { return subjects[i].substring(field.length + 1); } }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the Issuer Common Name from a certificate
|
||||
obj.getCertificateIssuerCommonName = function (pem, field) {
|
||||
if (field == null) { field = 'CN'; }
|
||||
const { X509Certificate } = require('crypto');
|
||||
if (X509Certificate == null) {
|
||||
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
|
||||
var cert = obj.pki.certificateFromPem(pem);
|
||||
if (cert.issuer.getField(field) != null) return cert.issuer.getField(field).value;
|
||||
} else {
|
||||
// This version of NodeJS supports x509 certificates
|
||||
const subjects = new X509Certificate(pem).issuer.split('\n');
|
||||
for (var i in subjects) { if (subjects[i].startsWith(field + '=')) { return subjects[i].substring(field.length + 1); } }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the Common Name and alternate names from a certificate
|
||||
obj.getCertificateAltNames = function (pem) {
|
||||
const altNamesResults = [];
|
||||
const { X509Certificate } = require('crypto');
|
||||
if (X509Certificate == null) {
|
||||
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
|
||||
var cert = obj.pki.certificateFromPem(pem);
|
||||
if (cert.subject.getField('CN') != null) { altNamesResults.push(cert.subject.getField('CN').value); }
|
||||
var altNames = cert.getExtension('subjectAltName');
|
||||
if (altNames) {
|
||||
for (i = 0; i < altNames.altNames.length; i++) {
|
||||
if ((altNames.altNames[i] != null) && (altNames.altNames[i].type === 2) && (typeof altNames.altNames[i].value === 'string')) {
|
||||
var acn = altNames.altNames[i].value.toLowerCase();
|
||||
if (altNamesResults.indexOf(acn) == -1) { altNamesResults.push(acn); }
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This version of NodeJS supports x509 certificates
|
||||
const cert = new X509Certificate(pem);
|
||||
const subjects = cert.subject.split('\n');
|
||||
for (var i in subjects) { if (subjects[i].startsWith('CN=')) { altNamesResults.push(subjects[i].substring(3)); } }
|
||||
var subjectAltNames = cert.subjectAltName;
|
||||
if (subjectAltNames != null) {
|
||||
subjectAltNames = subjectAltNames.split(', ');
|
||||
for (var i = 0; i < subjectAltNames.length; i++) {
|
||||
if (subjectAltNames[i].startsWith('DNS:') && altNamesResults.indexOf(subjectAltNames[i].substring(4)) == -1) {
|
||||
altNamesResults.push(subjectAltNames[i].substring(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return altNamesResults;
|
||||
}
|
||||
|
||||
// Get the expiration time from a certificate
|
||||
obj.getCertificateExpire = function (pem) {
|
||||
const altNamesResults = [];
|
||||
const { X509Certificate } = require('crypto');
|
||||
if (X509Certificate == null) {
|
||||
// This version of NodeJS (<v15.6.0) does not support X509 certs, use Node-Forge instead which only supports RSA certs.
|
||||
return Date.parse(parent.certificateOperations.forge.pki.certificateFromPem(parent.certificates.web.cert).validity.notAfter);
|
||||
} else {
|
||||
// This version of NodeJS supports x509 certificates
|
||||
return Date.parse(new X509Certificate(pem).validTo);
|
||||
}
|
||||
}
|
||||
|
||||
// Decrypt private key if needed
|
||||
obj.decryptPrivateKey = function (key) {
|
||||
if (typeof key != 'string') return key;
|
||||
|
|
@ -809,12 +918,14 @@ module.exports.CertificateOperations = function (parent) {
|
|||
var xext = xroot.getExtension('keyUsage');
|
||||
if ((xext == null) || (xext.keyCertSign !== true) || (xroot.serialNumber == '')) {
|
||||
// We need to fix this certificate
|
||||
parent.common.moveOldFiles(['root-cert-public-backup.crt']);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public-backup.crt'), rootCertificate);
|
||||
if (xroot.serialNumber == '') { console.log("Fixing root certificate to add serial number..."); xroot.serialNumber = '' + require('crypto').randomBytes(4).readUInt32BE(0); }
|
||||
if ((xext == null) || (xext.keyCertSign !== true)) { console.log("Fixing root certificate to add signing key usage..."); xroot.setExtensions([{ name: 'basicConstraints', cA: true }, { name: 'subjectKeyIdentifier' }, { name: 'keyUsage', keyCertSign: true }]); }
|
||||
var xrootPrivateKey = obj.pki.privateKeyFromPem(rootPrivateKey);
|
||||
xroot.sign(xrootPrivateKey, obj.forge.md.sha384.create());
|
||||
r.root.cert = obj.pki.certificateToPem(xroot);
|
||||
parent.common.moveOldFiles([parent.getConfigFilePath('root-cert-public.crt')]);
|
||||
try { obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public.crt'), r.root.cert); } catch (ex) { }
|
||||
}
|
||||
}
|
||||
|
|
@ -855,6 +966,9 @@ module.exports.CertificateOperations = function (parent) {
|
|||
if (obj.fileExists("codesign-cert-public.crt") && obj.fileExists("codesign-cert-private.key")) {
|
||||
r.codesign = { cert: obj.fileLoad("codesign-cert-public.crt", 'utf8'), key: obj.decryptPrivateKey(obj.fileLoad("codesign-cert-private.key", 'utf8')) };
|
||||
if (obj.checkCertificate(r.codesign.cert, r.codesign.key) == false) { delete r.codesign; } else { rcount++; }
|
||||
} else {
|
||||
// If we are reading certificates from a database or vault and are just missing the code signing cert, skip it.
|
||||
if (parent.configurationFiles != null) { rcount++; }
|
||||
}
|
||||
|
||||
// If the swarm server certificate exist, load it (This is an optional certificate)
|
||||
|
|
@ -906,32 +1020,23 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
if (rcount === rcountmax) {
|
||||
// Fetch the certificates names for the main certificate
|
||||
r.AmtMpsName = obj.pki.certificateFromPem(r.mps.cert).subject.getField('CN').value;
|
||||
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
||||
r.WebIssuer = webCertificate.issuer.getField('CN').value;
|
||||
if (commonName == 'un-configured') { // If the "cert" name is not set, try to use the certificate CN instead (ok if the certificate is not wildcard).
|
||||
commonName = webCertificate.subject.getField('CN').value;
|
||||
if (commonName.startsWith('*.')) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||
r.AmtMpsName = obj.getCertificateCommonName(r.mps.cert);
|
||||
r.WebIssuer = obj.getCertificateIssuerCommonName(r.web.cert);
|
||||
r.CommonName = obj.getCertificateCommonName(r.web.cert);
|
||||
r.CommonNames = obj.getCertificateAltNames(r.web.cert);
|
||||
r.RootName = obj.getCertificateCommonName(r.root.cert);
|
||||
|
||||
// If the "cert" name is not set, try to use the certificate CN instead (ok if the certificate is not wildcard).
|
||||
if (commonName == 'un-configured') {
|
||||
if (r.CommonName.startsWith('*.')) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||
commonName = r.CommonName;
|
||||
}
|
||||
r.CommonName = commonName;
|
||||
r.CommonNames = [commonName.toLowerCase()];
|
||||
var altNames = webCertificate.getExtension('subjectAltName');
|
||||
if (altNames) {
|
||||
for (i = 0; i < altNames.altNames.length; i++) {
|
||||
if ((altNames.altNames[i] != null) && (altNames.altNames[i].type === 2) && (typeof altNames.altNames[i].value === 'string')) {
|
||||
var acn = altNames.altNames[i].value.toLowerCase();
|
||||
if (r.CommonNames.indexOf(acn) == -1) { r.CommonNames.push(acn); }
|
||||
}
|
||||
}
|
||||
}
|
||||
var rootCertificate = obj.pki.certificateFromPem(r.root.cert);
|
||||
r.RootName = rootCertificate.subject.getField('CN').value;
|
||||
}
|
||||
|
||||
// Look for domains that have DNS names and load their certificates
|
||||
r.dns = {};
|
||||
for (i in config.domains) {
|
||||
if ((i != "") && (config.domains[i] != null) && (config.domains[i].dns != null)) {
|
||||
if ((i != '') && (config.domains[i] != null) && (config.domains[i].dns != null)) {
|
||||
dnsname = config.domains[i].dns;
|
||||
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
|
||||
if (obj.compareCertificateNames(r.CommonNames, dnsname) == true) {
|
||||
|
|
@ -944,6 +1049,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||
config.domains[i].certs = r.dns[i];
|
||||
} else {
|
||||
console.log("WARNING: File \"webserver-" + i + "-cert-public.crt\" missing, domain \"" + i + "\" will not work correctly.");
|
||||
rcountmax++;
|
||||
}
|
||||
} else {
|
||||
// If the web certificate already exist, load it. Load both certificate and private key
|
||||
|
|
@ -969,25 +1075,35 @@ module.exports.CertificateOperations = function (parent) {
|
|||
}
|
||||
}
|
||||
|
||||
// If we have all the certificates we need, stop here.
|
||||
if (rcount === rcountmax) {
|
||||
if ((certargs == null) && (mpscertargs == null)) { if (func != undefined) { func(r); } return r; } // If no certificate arguments are given, keep the certificate
|
||||
var xcountry, xcountryField = webCertificate.subject.getField('C');
|
||||
if (xcountryField != null) { xcountry = xcountryField.value; }
|
||||
var xorganization, xorganizationField = webCertificate.subject.getField('O');
|
||||
if (xorganizationField != null) { xorganization = xorganizationField.value; }
|
||||
const xcountry = obj.getCertificateCommonName(r.web.cert, 'C');
|
||||
const xorganization = obj.getCertificateCommonName(r.web.cert, 'O');
|
||||
if (certargs == null) { commonName = r.CommonName; country = xcountry; organization = xorganization; }
|
||||
|
||||
// Check if we have correct certificates
|
||||
if (obj.compareCertificateNames(r.CommonNames, commonName) == false) { forceWebCertGen = 1; }
|
||||
// Check if we have correct certificates.
|
||||
if (obj.compareCertificateNames(r.CommonNames, commonName) == false) { console.log("Error: " + commonName + " does not match name in TLS certificate: " + r.CommonNames.join(', ')); forceWebCertGen = 1; } else { r.CommonName = commonName; }
|
||||
if (r.AmtMpsName != mpsCommonName) { forceMpsCertGen = 1; }
|
||||
if (args.keepcerts == true) { forceWebCertGen = 0; forceMpsCertGen = 0; r.CommonName = commonName; }
|
||||
|
||||
// If the certificates matches what we want, use them.
|
||||
if ((forceWebCertGen == 0) && (forceMpsCertGen == 0)) {
|
||||
if (func !== undefined) { func(r); }
|
||||
if (func !== null) { func(r); }
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (parent.configurationFiles != null) { console.log("Error: Vault/Database missing some certificates."); process.exit(0); return null; }
|
||||
|
||||
if (parent.configurationFiles != null) {
|
||||
console.log("Error: Vault/Database missing some certificates.");
|
||||
if (r.root == null) { console.log(' Code signing certificate is missing.'); }
|
||||
if (r.web == null) { console.log(' HTTPS web certificate is missing.'); }
|
||||
if (r.mps == null) { console.log(' Intel AMT MPS certificate is missing.'); }
|
||||
if (r.agent == null) { console.log(' Server agent authentication certificate is missing.'); }
|
||||
if (r.codesign == null) { console.log(' Agent code signing certificate is missing.'); }
|
||||
process.exit(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log("Generating certificates, may take a few minutes...");
|
||||
parent.updateServerState('state', 'generatingcertificates');
|
||||
|
|
@ -1006,9 +1122,16 @@ module.exports.CertificateOperations = function (parent) {
|
|||
if (r.root == null) {
|
||||
// If the root certificate does not exist, create one
|
||||
console.log("Generating root certificate...");
|
||||
rootCertAndKey = obj.GenerateRootCertificate(true, 'MeshCentralRoot', null, null, strongCertificate);
|
||||
if (typeof args.rootcertcommonname == 'string') {
|
||||
// If a root certificate common name is specified, use it.
|
||||
rootCertAndKey = obj.GenerateRootCertificate(false, args.rootcertcommonname, null, null, strongCertificate);
|
||||
} else {
|
||||
// A root certificate common name is not specified, use the default one.
|
||||
rootCertAndKey = obj.GenerateRootCertificate(true, 'MeshCentralRoot', null, null, strongCertificate);
|
||||
}
|
||||
rootCertificate = obj.pki.certificateToPem(rootCertAndKey.cert);
|
||||
rootPrivateKey = obj.pki.privateKeyToPem(rootCertAndKey.key);
|
||||
parent.common.moveOldFiles([parent.getConfigFilePath('root-cert-public.crt'), parent.getConfigFilePath('root-cert-private.key')]);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-public.crt'), rootCertificate);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('root-cert-private.key'), rootPrivateKey);
|
||||
} else {
|
||||
|
|
@ -1021,11 +1144,12 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
// If the web certificate does not exist, create one
|
||||
var webCertAndKey, webCertificate, webPrivateKey;
|
||||
if ((r.web == null) || (forceWebCertGen == 1)) {
|
||||
if ((r.web == null) || (forceWebCertGen === 1)) {
|
||||
console.log("Generating HTTPS certificate...");
|
||||
webCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, commonName, country, organization, null, strongCertificate);
|
||||
webCertificate = obj.pki.certificateToPem(webCertAndKey.cert);
|
||||
webPrivateKey = obj.pki.privateKeyToPem(webCertAndKey.key);
|
||||
parent.common.moveOldFiles([parent.getConfigFilePath('webserver-cert-public.crt'), parent.getConfigFilePath('webserver-cert-private.key')]);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-cert-public.crt'), webCertificate);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-cert-private.key'), webPrivateKey);
|
||||
} else {
|
||||
|
|
@ -1039,7 +1163,8 @@ module.exports.CertificateOperations = function (parent) {
|
|||
webPrivateKey = r.web.key;
|
||||
}
|
||||
}
|
||||
var webIssuer = webCertAndKey.cert.issuer.getField('CN').value;
|
||||
var webIssuer = null;
|
||||
if (webCertAndKey.cert.issuer.getField('CN') != null) { webIssuer = webCertAndKey.cert.issuer.getField('CN').value; }
|
||||
|
||||
// If the mesh agent server certificate does not exist, create one
|
||||
var agentCertAndKey, agentCertificate, agentPrivateKey;
|
||||
|
|
@ -1048,6 +1173,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||
agentCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, true, 'MeshCentralAgentServer', country, organization, { }, strongCertificate);
|
||||
agentCertificate = obj.pki.certificateToPem(agentCertAndKey.cert);
|
||||
agentPrivateKey = obj.pki.privateKeyToPem(agentCertAndKey.key);
|
||||
parent.common.moveOldFiles([parent.getConfigFilePath('agentserver-cert-public.crt'), parent.getConfigFilePath('agentserver-cert-private.key')]);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('agentserver-cert-public.crt'), agentCertificate);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('agentserver-cert-private.key'), agentPrivateKey);
|
||||
} else {
|
||||
|
|
@ -1064,6 +1190,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||
codesignCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, true, commonName, country, organization, { codeSign: true }, strongCertificate);
|
||||
codesignCertificate = obj.pki.certificateToPem(codesignCertAndKey.cert);
|
||||
codesignPrivateKey = obj.pki.privateKeyToPem(codesignCertAndKey.key);
|
||||
parent.common.moveOldFiles([parent.getConfigFilePath('codesign-cert-public.crt'), parent.getConfigFilePath('codesign-cert-private.key')]);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('codesign-cert-public.crt'), codesignCertificate);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('codesign-cert-private.key'), codesignPrivateKey);
|
||||
} else {
|
||||
|
|
@ -1075,11 +1202,12 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
// If the Intel AMT MPS certificate does not exist, create one
|
||||
var mpsCertAndKey, mpsCertificate, mpsPrivateKey;
|
||||
if ((r.mps == null) || (forceMpsCertGen == 1)) {
|
||||
if ((r.mps == null) || (forceMpsCertGen === 1)) {
|
||||
console.log("Generating Intel AMT MPS certificate...");
|
||||
mpsCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, mpsCommonName, mpsCountry, mpsOrganization, null, false);
|
||||
mpsCertificate = obj.pki.certificateToPem(mpsCertAndKey.cert);
|
||||
mpsPrivateKey = obj.pki.privateKeyToPem(mpsCertAndKey.key);
|
||||
parent.common.moveOldFiles([parent.getConfigFilePath('mpsserver-cert-public.crt'), parent.getConfigFilePath('mpsserver-cert-private.key')]);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('mpsserver-cert-public.crt'), mpsCertificate);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('mpsserver-cert-private.key'), mpsPrivateKey);
|
||||
} else {
|
||||
|
|
@ -1093,7 +1221,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
// Fetch the certificates names for the main certificate
|
||||
var webCertificate = obj.pki.certificateFromPem(r.web.cert);
|
||||
r.WebIssuer = webCertificate.issuer.getField('CN').value;
|
||||
if (webCertificate.issuer.getField('CN') != null) { r.WebIssuer = webCertificate.issuer.getField('CN').value; } else { r.WebIssuer = null; }
|
||||
r.CommonName = webCertificate.subject.getField('CN').value;
|
||||
if (r.CommonName.startsWith('*.')) {
|
||||
if (commonName.indexOf('.') == -1) { console.log("ERROR: Must specify a server full domain name in Config.json->Settings->Cert when using a wildcard certificate."); process.exit(0); return; }
|
||||
|
|
@ -1115,7 +1243,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
// Look for domains with DNS names that have no certificates and generated them.
|
||||
for (i in config.domains) {
|
||||
if ((i != "") && (config.domains[i] != null) && (config.domains[i].dns != null)) {
|
||||
if ((i != '') && (config.domains[i] != null) && (config.domains[i].dns != null)) {
|
||||
dnsname = config.domains[i].dns;
|
||||
// Check if this domain matches a parent wildcard cert, if so, use the parent cert.
|
||||
if (obj.compareCertificateNames(r.CommonNames, dnsname) == true) {
|
||||
|
|
@ -1128,6 +1256,7 @@ module.exports.CertificateOperations = function (parent) {
|
|||
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
|
||||
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
|
||||
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
|
||||
parent.common.moveOldFiles([ parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'), parent.getConfigFilePath('webserver-' + i + '-cert-private.key') ]);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-public.crt'), xwebCertificate);
|
||||
obj.fs.writeFileSync(parent.getConfigFilePath('webserver-' + i + '-cert-private.key'), xwebPrivateKey);
|
||||
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
|
||||
|
|
@ -1279,20 +1408,15 @@ module.exports.CertificateOperations = function (parent) {
|
|||
|
||||
// Perform any general operation
|
||||
obj.acceleratorPerformOperation = function (operation, data, tag, func) {
|
||||
if (acceleratorTotalCount <= 1) {
|
||||
// No accelerators available
|
||||
require(program).processMessage({ action: operation, data: data, tag: tag, func: func });
|
||||
var acc = obj.getAccelerator();
|
||||
if (acc == null) {
|
||||
// Add to pending accelerator workload
|
||||
acceleratorPerformSignaturePushFuncCall++;
|
||||
pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func });
|
||||
} else {
|
||||
var acc = obj.getAccelerator();
|
||||
if (acc == null) {
|
||||
// Add to pending accelerator workload
|
||||
acceleratorPerformSignaturePushFuncCall++;
|
||||
pendingAccelerator.push({ action: operation, data: data, tag: tag, func: func });
|
||||
} else {
|
||||
// Send to accelerator now
|
||||
acceleratorPerformSignatureRunFuncCall++;
|
||||
acc.send(acc.x = { action: operation, data: data, tag: tag, func: func });
|
||||
}
|
||||
// Send to accelerator now
|
||||
acceleratorPerformSignatureRunFuncCall++;
|
||||
acc.send(acc.x = { action: operation, data: data, tag: tag, func: func });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
101
common.js
101
common.js
|
|
@ -106,7 +106,7 @@ module.exports.random = function (max) {
|
|||
return r;
|
||||
};
|
||||
|
||||
// Split a comma seperated string, ignoring commas in quotes.
|
||||
// Split a comma separated string, ignoring commas in quotes.
|
||||
module.exports.quoteSplit = function (str) {
|
||||
var tmp = '', quote = 0, result = [];
|
||||
for (var i in str) { if (str[i] == '"') { quote = (quote + 1) % 2; } if ((str[i] == ',') && (quote == 0)) { tmp = tmp.trim(); result.push(tmp); tmp = ''; } else { tmp += str[i]; } }
|
||||
|
|
@ -142,25 +142,48 @@ module.exports.zeroPad = function(num, c) { if (c == null) { c = 2; } var s = '0
|
|||
|
||||
// Lowercase all the names in a object recursively
|
||||
// Allow for exception keys, child of exceptions will not get lower-cased.
|
||||
module.exports.objKeysToLower = function (obj, exceptions) {
|
||||
// Exceptions is an array of "keyname" or "parent\keyname"
|
||||
module.exports.objKeysToLower = function (obj, exceptions, parent) {
|
||||
for (var i in obj) {
|
||||
if ((typeof obj[i] == 'object') && ((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1))) { module.exports.objKeysToLower(obj[i], exceptions); } // LowerCase all key names in the child object
|
||||
if ((typeof obj[i] == 'object') &&
|
||||
((exceptions == null) || (exceptions.indexOf(i.toLowerCase()) == -1) && ((parent == null) || (exceptions.indexOf(parent.toLowerCase() + '/' + i.toLowerCase()) == -1)))
|
||||
) {
|
||||
module.exports.objKeysToLower(obj[i], exceptions, i); // LowerCase all key names in the child object
|
||||
}
|
||||
if (i.toLowerCase() !== i) { obj[i.toLowerCase()] = obj[i]; delete obj[i]; } // LowerCase all key names
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
// Escape and unexcape feild names so there are no invalid characters for MongoDB
|
||||
module.exports.escapeFieldName = function (name) { if ((name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24'); };
|
||||
module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
|
||||
// Escape and unescape field names so there are no invalid characters for MongoDB/NeDB ("$", ",", ".", see https://github.com/seald/nedb/tree/master?tab=readme-ov-file#inserting-documents)
|
||||
module.exports.escapeFieldName = function (name) { if ((name.indexOf(',') == -1) && (name.indexOf('%') == -1) && (name.indexOf('.') == -1) && (name.indexOf('$') == -1)) return name; return name.split('%').join('%25').split('.').join('%2E').split('$').join('%24').split(',').join('%2C'); };
|
||||
module.exports.unEscapeFieldName = function (name) { if (name.indexOf('%') == -1) return name; return name.split('%2C').join(',').split('%2E').join('.').split('%24').join('$').split('%25').join('%'); };
|
||||
|
||||
// Escape all links
|
||||
module.exports.escapeLinksFieldNameEx = function (docx) { if (docx.links == null) { return docx; } var doc = Object.assign({}, docx); doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } return doc; };
|
||||
module.exports.escapeLinksFieldName = function (docx) { var doc = Object.assign({}, docx); if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } } return doc; };
|
||||
module.exports.unEscapeLinksFieldName = function (doc) { if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } } return doc; };
|
||||
// Escape all links, SSH and RDP usernames
|
||||
// This is required for databases like NeDB that don't accept "." or "," as part of a field name.
|
||||
module.exports.escapeLinksFieldNameEx = function (docx) { if ((docx.links == null) && (docx.ssh == null) && (docx.rdp == null)) { return docx; } return module.exports.escapeLinksFieldName(docx); };
|
||||
module.exports.escapeLinksFieldName = function (docx) {
|
||||
var doc = Object.assign({}, docx);
|
||||
if (doc.links != null) { doc.links = Object.assign({}, doc.links); for (var i in doc.links) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.links[ue] = doc.links[i]; delete doc.links[i]; } } }
|
||||
if (doc.ssh != null) { doc.ssh = Object.assign({}, doc.ssh); for (var i in doc.ssh) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.ssh[ue] = doc.ssh[i]; delete doc.ssh[i]; } } }
|
||||
if (doc.rdp != null) { doc.rdp = Object.assign({}, doc.rdp); for (var i in doc.rdp) { var ue = module.exports.escapeFieldName(i); if (ue !== i) { doc.rdp[ue] = doc.rdp[i]; delete doc.rdp[i]; } } }
|
||||
return doc;
|
||||
};
|
||||
module.exports.unEscapeLinksFieldName = function (doc) {
|
||||
if (doc.links != null) { for (var j in doc.links) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.links[ue] = doc.links[j]; delete doc.links[j]; } } }
|
||||
if (doc.ssh != null) { for (var j in doc.ssh) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.ssh[ue] = doc.ssh[j]; delete doc.ssh[j]; } } }
|
||||
if (doc.rdp != null) { for (var j in doc.rdp) { var ue = module.exports.unEscapeFieldName(j); if (ue !== j) { doc.rdp[ue] = doc.rdp[j]; delete doc.rdp[j]; } } }
|
||||
return doc;
|
||||
};
|
||||
//module.exports.escapeAllLinksFieldName = function (docs) { for (var i in docs) { module.exports.escapeLinksFieldName(docs[i]); } return docs; };
|
||||
module.exports.unEscapeAllLinksFieldName = function (docs) { for (var i in docs) { docs[i] = module.exports.unEscapeLinksFieldName(docs[i]); } return docs; };
|
||||
|
||||
// Escape field names for aceBase
|
||||
var aceEscFields = ['links', 'ssh', 'rdp', 'notify'];
|
||||
module.exports.aceEscapeFieldNames = function (docx) { var doc = Object.assign({}, docx); for (var k in aceEscFields) { if (typeof doc[aceEscFields[k]] == 'object') { doc[aceEscFields[k]] = Object.assign({}, doc[aceEscFields[k]]); for (var i in doc[aceEscFields[k]]) { var ue = encodeURIComponent(i); if (ue !== i) { doc[aceEscFields[k]][ue] = doc[aceEscFields[k]][i]; delete doc[aceEscFields[k]][i]; } } } } return doc; };
|
||||
module.exports.aceUnEscapeFieldNames = function (doc) { for (var k in aceEscFields) { if (typeof doc[aceEscFields[k]] == 'object') { for (var j in doc[aceEscFields[k]]) { var ue = decodeURIComponent(j); if (ue !== j) { doc[aceEscFields[k]][ue] = doc[aceEscFields[k]][j]; delete doc[aceEscFields[k]][j]; } } } } return doc; };
|
||||
module.exports.aceUnEscapeAllFieldNames = function (docs) { for (var i in docs) { docs[i] = module.exports.aceUnEscapeFieldNames(docs[i]); } return docs; };
|
||||
|
||||
// Validation methods
|
||||
module.exports.validateString = function (str, minlen, maxlen) { return ((str != null) && (typeof str == 'string') && ((minlen == null) || (str.length >= minlen)) && ((maxlen == null) || (str.length <= maxlen))); };
|
||||
module.exports.validateInt = function (int, minval, maxval) { return ((int != null) && (typeof int == 'number') && ((minval == null) || (int >= minval)) && ((maxval == null) || (int <= maxval))); };
|
||||
|
|
@ -311,6 +334,11 @@ module.exports.meshServerRightsArrayToNumber = function (val) {
|
|||
if (r == 'locked') { newAccRights |= 32; }
|
||||
if (r == 'nonewgroups') { newAccRights |= 64; }
|
||||
if (r == 'notools') { newAccRights |= 128; }
|
||||
if (r == 'usergroups') { newAccRights |= 256; }
|
||||
if (r == 'recordings') { newAccRights |= 512; }
|
||||
if (r == 'locksettings') { newAccRights |= 1024; }
|
||||
if (r == 'allevents') { newAccRights |= 2048; }
|
||||
if (r == 'nonewdevices') { newAccRights |= 4096; }
|
||||
}
|
||||
return newAccRights;
|
||||
}
|
||||
|
|
@ -339,3 +367,56 @@ function validateObjectForMongoRec(obj, maxStrLen) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse a version string of the type n.n.n.n
|
||||
module.exports.parseVersion = function (verstr) {
|
||||
if (typeof verstr != 'string') return null;
|
||||
const r = [], verstrsplit = verstr.split('.');
|
||||
if (verstrsplit.length != 4) return null;
|
||||
for (var i in verstrsplit) {
|
||||
var n = parseInt(verstrsplit[i]);
|
||||
if (isNaN(n) || (n < 0) || (n > 65535)) return null;
|
||||
r.push(n);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Move old files. If we are about to overwrite a file, we can move if first just in case the change needs to be reverted
|
||||
module.exports.moveOldFiles = function (filelist) {
|
||||
// Fine an old extension that works for all files in the file list
|
||||
var oldFileExt, oldFileExtCount = 0, extOk;
|
||||
do {
|
||||
extOk = true;
|
||||
if (++oldFileExtCount == 1) { oldFileExt = '-old'; } else { oldFileExt = '-old' + oldFileExtCount; }
|
||||
for (var i in filelist) { if (fs.existsSync(filelist[i] + oldFileExt) == true) { extOk = false; } }
|
||||
} while (extOk == false);
|
||||
for (var i in filelist) { try { fs.renameSync(filelist[i], filelist[i] + oldFileExt); } catch (ex) { } }
|
||||
}
|
||||
|
||||
// Convert strArray to Array, returns array if strArray or null if any other type
|
||||
module.exports.convertStrArray = function (object, split) {
|
||||
if (split && typeof object === 'string') {
|
||||
return object.split(split)
|
||||
} else if (typeof object === 'string') {
|
||||
return Array(object);
|
||||
} else if (Array.isArray(object)) {
|
||||
return object
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.uniqueArray = function (a) {
|
||||
var seen = {};
|
||||
var out = [];
|
||||
var len = a.length;
|
||||
var j = 0;
|
||||
for(var i = 0; i < len; i++) {
|
||||
var item = a[i];
|
||||
if(seen[item] !== 1) {
|
||||
seen[item] = 1;
|
||||
out[j++] = item;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
141
crowdsec.js
Normal file
141
crowdsec.js
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
module.exports.CreateCrowdSecBouncer = function (parent, config) {
|
||||
const obj = {};
|
||||
|
||||
// Setup constants
|
||||
const { getLogger } = require('@crowdsec/express-bouncer/src/nodejs-bouncer/lib/logger');
|
||||
const { configure, renderBanWall, testConnectionToCrowdSec, getRemediationForIp } = require('@crowdsec/express-bouncer/src/nodejs-bouncer');
|
||||
const applyCaptcha = require('@crowdsec/express-bouncer/src/express-crowdsec-middleware/lib/captcha');
|
||||
const { BYPASS_REMEDIATION, CAPTCHA_REMEDIATION, BAN_REMEDIATION } = require('@crowdsec/express-bouncer/src/nodejs-bouncer/lib/constants'); // "bypass", "captcha", "ban";
|
||||
const svgCaptcha = require('svg-captcha');
|
||||
const { renderCaptchaWall } = require('@crowdsec/express-bouncer/src/nodejs-bouncer');
|
||||
|
||||
// Current captcha state
|
||||
const currentCaptchaIpList = {};
|
||||
|
||||
// Set the default values. "config" will come in with lowercase names with everything, so we need to correct some value names.
|
||||
if (typeof config.useragent != 'string') { config.useragent = 'CrowdSec Express-NodeJS bouncer/v0.0.1'; }
|
||||
if (typeof config.timeout != 'number') { config.timeout = 2000; }
|
||||
if ((typeof config.fallbackremediation != 'string') || (['bypass', 'captcha', 'ban'].indexOf(config.fallbackremediation) == -1)) { config.fallbackremediation = BAN_REMEDIATION; }
|
||||
if (typeof config.maxremediation != 'number') { config.maxremediation = BAN_REMEDIATION; }
|
||||
if (typeof config.captchagenerationcacheduration != 'number') { config.captchagenerationcacheduration = 60 * 1000; } // 60 seconds
|
||||
if (typeof config.captcharesolutioncacheduration != 'number') { config.captcharesolutioncacheduration = 30 * 60 * 1000; } // 30 minutes
|
||||
if (typeof config.captchatexts != 'object') { config.captchatexts = {}; } else {
|
||||
if (typeof config.captchatexts.tabtitle == 'string') { config.captchatexts.tabTitle = config.captchatexts.tabtitle; delete config.captchatexts.tabtitle; } // Fix "tabTitle" capitalization
|
||||
}
|
||||
if (typeof config.bantexts != 'object') { config.bantexts = {}; } else {
|
||||
if (typeof config.bantexts.tabtitle == 'string') { config.bantexts.tabTitle = config.bantexts.tabtitle; delete config.bantexts.tabtitle; } // Fix "tabTitle" capitalization
|
||||
}
|
||||
if (typeof config.colors != 'object') { config.colors = {}; } else {
|
||||
var colors = {};
|
||||
// All of the values in "text" and "background" sections happen to be lowercase, so, we can use the values as-is.
|
||||
if (typeof config.colors.text == 'object') { colors.text = config.colors.text; }
|
||||
if (typeof config.colors.background == 'object') { colors.background = config.colors.background; }
|
||||
config.colors = colors;
|
||||
}
|
||||
if (typeof config.hidecrowdsecmentions != 'boolean') { config.hidecrowdsecmentions = false; }
|
||||
if (typeof config.customcss != 'string') { delete config.customcss; }
|
||||
if (typeof config.bypass != 'boolean') { config.bypass = false; }
|
||||
if (typeof config.customlogger != 'object') { delete config.customlogger; }
|
||||
if (typeof config.bypassconnectiontest != 'boolean') { config.bypassconnectiontest = false; }
|
||||
|
||||
// Setup the logger
|
||||
var logger = config.customLogger ? config.customLogger : getLogger();
|
||||
|
||||
// Configure the bouncer
|
||||
configure({
|
||||
url: config.url,
|
||||
apiKey: config.apikey,
|
||||
userAgent: config.useragent,
|
||||
timeout: config.timeout,
|
||||
fallbackRemediation: config.fallbackremediation,
|
||||
maxRemediation: config.maxremediation,
|
||||
captchaTexts: config.captchatexts,
|
||||
banTexts: config.bantexts,
|
||||
colors: config.colors,
|
||||
hideCrowdsecMentions: config.hidecrowdsecmentions,
|
||||
customCss: config.customcss
|
||||
});
|
||||
|
||||
// Test connectivity
|
||||
obj.testConnectivity = async function() { return (await testConnectionToCrowdSec())['success']; }
|
||||
|
||||
// Process a web request
|
||||
obj.process = async function (domain, req, res, next) {
|
||||
try {
|
||||
var remediation = config.fallbackremediation;
|
||||
try { remediation = await getRemediationForIp(req.clientIp); } catch (ex) { }
|
||||
//console.log('CrowdSec', req.clientIp, remediation, req.url);
|
||||
switch (remediation) {
|
||||
case BAN_REMEDIATION:
|
||||
const banWallTemplate = await renderBanWall();
|
||||
res.status(403);
|
||||
res.send(banWallTemplate);
|
||||
return true;
|
||||
case CAPTCHA_REMEDIATION:
|
||||
if ((currentCaptchaIpList[req.clientIp] == null) || (currentCaptchaIpList[req.clientIp].resolved !== true)) {
|
||||
var domainCaptchaUrl = ((domain != null) && (domain.id != '') && (domain.dns == null)) ? ('/' + domain.id + '/captcha.ashx') : '/captcha.ashx';
|
||||
if (req.url != domainCaptchaUrl) { res.redirect(domainCaptchaUrl); return true; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (ex) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
// Process a captcha request
|
||||
obj.applyCaptcha = async function (req, res, next) {
|
||||
await applyCaptchaEx(req.clientIp, req, res, next, config.captchagenerationcacheduration, config.captcharesolutioncacheduration, logger);
|
||||
}
|
||||
|
||||
// Process a captcha request
|
||||
async function applyCaptchaEx(ip, req, res, next, captchaGenerationCacheDuration, captchaResolutionCacheDuration, loggerInstance) {
|
||||
logger = loggerInstance;
|
||||
let error = false;
|
||||
|
||||
if (currentCaptchaIpList[ip] == null) {
|
||||
generateCaptcha(ip, captchaGenerationCacheDuration);
|
||||
} else {
|
||||
if (currentCaptchaIpList[ip] && currentCaptchaIpList[ip].resolved) {
|
||||
logger.debug({ type: 'CAPTCHA_ALREADY_SOLVED', ip });
|
||||
next();
|
||||
return;
|
||||
} else {
|
||||
if (req.body && req.body.crowdsec_captcha) {
|
||||
if (req.body.refresh === '1') { generateCaptcha(ip, captchaGenerationCacheDuration); }
|
||||
if (req.body.phrase !== '') {
|
||||
if (currentCaptchaIpList[ip].text === req.body.phrase) {
|
||||
currentCaptchaIpList[ip].resolved = true;
|
||||
setTimeout(function() { if (currentCaptchaIpList[ip]) { delete currentCaptchaIpList[ip]; } }, captchaResolutionCacheDuration);
|
||||
res.redirect(req.originalUrl);
|
||||
logger.info({ type: 'CAPTCHA_RESOLUTION', ip, result: true });
|
||||
return;
|
||||
} else {
|
||||
logger.info({ type: 'CAPTCHA_RESOLUTION', ip, result: false });
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const captchaWallTemplate = await renderCaptchaWall({ captchaImageTag: currentCaptchaIpList[ip].data, captchaResolutionFormUrl: '', error });
|
||||
res.status(401);
|
||||
res.send(captchaWallTemplate);
|
||||
};
|
||||
|
||||
// Generate a CAPTCHA
|
||||
function generateCaptcha(ip, captchaGenerationCacheDuration) {
|
||||
const captcha = svgCaptcha.create();
|
||||
currentCaptchaIpList[ip] = {
|
||||
data: captcha.data,
|
||||
text: captcha.text,
|
||||
resolved: false,
|
||||
};
|
||||
setTimeout(() => {
|
||||
if (currentCaptchaIpList[ip]) { delete currentCaptchaIpList[ip]; }
|
||||
}, captchaGenerationCacheDuration);
|
||||
logger.debug({ type: "GENERATE_CAPTCHA", ip });
|
||||
};
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
"archiver": "^5.3.1",
|
||||
"body-parser": "^1.19.0",
|
||||
"cbor": "~5.2.0",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-session": "^1.4.0",
|
||||
"express": "^4.17.0",
|
||||
"express-handlebars": "^5.3.5",
|
||||
"express-ws": "^4.0.0",
|
||||
"ipcheck": "^0.1.0",
|
||||
"minimist": "^1.2.5",
|
||||
"multiparty": "^4.2.1",
|
||||
"@yetzt/nedb": "^1.8.0",
|
||||
"node-forge": "^1.0.0",
|
||||
"ws": "^5.2.3",
|
||||
"yauzl": "^2.10.0"
|
||||
"@seald-io/nedb": "4.0.4",
|
||||
"archiver": "7.0.1",
|
||||
"body-parser": "1.20.3",
|
||||
"cbor": "5.2.0",
|
||||
"compression": "1.7.5",
|
||||
"cookie-session": "2.1.0",
|
||||
"express": "4.21.2",
|
||||
"express-handlebars": "7.1.3",
|
||||
"express-ws": "5.0.2",
|
||||
"ipcheck": "0.1.0",
|
||||
"minimist": "1.2.8",
|
||||
"multiparty": "4.2.3",
|
||||
"node-forge": "1.3.1",
|
||||
"ua-parser-js": "1.0.39",
|
||||
"ws": "8.18.0",
|
||||
"yauzl": "2.10.0"
|
||||
29
docker/BUILD.md
Normal file
29
docker/BUILD.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# How to create a docker image for meshcentral
|
||||
|
||||
```
|
||||
> git clone https://github.com/Ylianst/MeshCentral.git
|
||||
> cd MeshCentral
|
||||
|
||||
> docker build -f docker/Dockerfile --force-rm -t meshcentral .
|
||||
|
||||
# alternative, if you want to include the mongodb-tools (mongodump, ...), you can add the 'INCLUDE_MONGODBTOOLS=yes' build argument
|
||||
> docker build -f docker/Dockerfile --force-rm --build-arg INCLUDE_MONGODBTOOLS=yes -t meshcentral .
|
||||
|
||||
# (optional) cleanup after docker build:
|
||||
> cd ..
|
||||
> rm -rf MeshCentral/
|
||||
```
|
||||
|
||||
> | Argument | Description |
|
||||
> | :--- | :--- |
|
||||
> | -f docker/Dockerfile | Path/Name of the Dockerfile |
|
||||
> | --force-rm | Always remove intermediate containers |
|
||||
> | -t meshcentral | Name and optionally a tag in the 'name:tag' format |
|
||||
|
||||
### Optional build arguments
|
||||
> | Argument | Description |
|
||||
> | :--- | :--- |
|
||||
> | INCLUDE_MONGODBTOOLS=yes | Includes mongodb-tools (mongodump, ...) in the image |
|
||||
> | DISABLE_MINIFY=yes | Disables the minification of files |
|
||||
> | DISABLE_TRANSLATE=yes | Disables the translation of files |
|
||||
|
||||
|
|
@ -1,66 +1,94 @@
|
|||
FROM node:current-alpine AS base
|
||||
FROM --platform=$BUILDPLATFORM node:22-alpine AS builder
|
||||
|
||||
#Add non-root user, add installation directories and assign proper permissions
|
||||
RUN mkdir -p /opt/meshcentral
|
||||
|
||||
# meshcentral installation
|
||||
RUN mkdir -p /opt/meshcentral/meshcentral
|
||||
COPY ./ /opt/meshcentral/meshcentral/
|
||||
WORKDIR /opt/meshcentral
|
||||
|
||||
RUN apk add --no-cache bash
|
||||
|
||||
|
||||
FROM base AS builder
|
||||
|
||||
ARG DISABLE_MINIFY=""
|
||||
ARG DISABLE_TRANSLATE=""
|
||||
|
||||
RUN mkdir /opt/meshcentral/meshcentral
|
||||
COPY ./ /opt/meshcentral/meshcentral/
|
||||
|
||||
RUN if ! [ -z "$DISABLE_MINIFY" ] && [ "$DISABLE_MINIFY" != "yes" ] && [ "$DISABLE_MINIFY" != "YES" ] \
|
||||
&& [ "$DISABLE_MINIFY" != "true" ] && [ "$DISABLE_MINIFY" != "TRUE" ]; then \
|
||||
echo -e "\e[0;31;49mInvalid value for build argument DISABLE_MINIFY, possible values: yes/true\e[;0m"; exit 1; \
|
||||
echo -e "\e[0;31;49mInvalid value for build argument DISABLE_MINIFY, possible values: yes/true\e[;0m"; exit 1; \
|
||||
fi
|
||||
RUN if ! [ -z "$DISABLE_TRANSLATE" ] && [ "$DISABLE_TRANSLATE" != "yes" ] && [ "$DISABLE_TRANSLATE" != "YES" ] \
|
||||
&& [ "$DISABLE_TRANSLATE" != "true" ] && [ "$DISABLE_TRANSLATE" != "TRUE" ]; then \
|
||||
echo -e "\e[0;31;49mInvalid value for build argument DISABLE_TRANSLATE, possible values: yes/true\e[;0m"; exit 1; \
|
||||
echo -e "\e[0;31;49mInvalid value for build argument DISABLE_TRANSLATE, possible values: yes/true\e[;0m"; exit 1; \
|
||||
fi
|
||||
|
||||
# first try throws Error: Cannot find module 'jsdom'
|
||||
RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js extractall; exit 0; fi
|
||||
# install translate/minify modules if need too
|
||||
RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral && npm install html-minifier@4.0.0 jsdom@22.1.0 esprima@4.0.1; fi
|
||||
|
||||
# first extractall if need too
|
||||
RUN if [ -z "$DISABLE_MINIFY" ] || [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js extractall; fi
|
||||
|
||||
# minify files
|
||||
RUN if [ -z "$DISABLE_MINIFY" ]; then cd meshcentral/translate && node translate.js minifyall; fi
|
||||
|
||||
# translate
|
||||
RUN if [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js extractall; fi
|
||||
RUN if [ -z "$DISABLE_TRANSLATE" ]; then cd meshcentral/translate && node translate.js translateall; fi
|
||||
|
||||
# cleanup
|
||||
RUN rm -rf /opt/meshcentral/meshcentral/docker
|
||||
RUN rm -rf /opt/meshcentral/meshcentral/node_modules
|
||||
|
||||
FROM base
|
||||
|
||||
FROM --platform=$TARGETPLATFORM alpine:3.21
|
||||
|
||||
#Add non-root user, add installation directories and assign proper permissions
|
||||
RUN mkdir -p /opt/meshcentral/meshcentral
|
||||
|
||||
# meshcentral installation
|
||||
WORKDIR /opt/meshcentral
|
||||
|
||||
RUN apk update \
|
||||
&& apk add --no-cache --update tzdata nodejs npm bash python3 make gcc g++ \
|
||||
&& rm -rf /var/cache/apk/*
|
||||
RUN npm install -g npm@latest
|
||||
|
||||
ARG INCLUDE_MONGODBTOOLS=""
|
||||
ARG PREINSTALL_LIBS="false"
|
||||
|
||||
# environment variables
|
||||
ENV NODE_ENV="production"
|
||||
ENV CONFIG_FILE="config.json"
|
||||
|
||||
# environment variables for initial configuration file
|
||||
ENV USE_MONGODB="false"
|
||||
ENV MONGO_INITDB_ROOT_USERNAME="root"
|
||||
ENV MONGO_INITDB_ROOT_PASSWORD="pass"
|
||||
ENV MONGO_URL=""
|
||||
ENV HOSTNAME="localhost"
|
||||
ENV ALLOW_NEW_ACCOUNTS="true"
|
||||
ENV ALLOWPLUGINS="false"
|
||||
ENV LOCALSESSIONRECORDING="true"
|
||||
ENV MINIFY="false"
|
||||
ENV WEBRTC="false"
|
||||
ENV IFRAME="false"
|
||||
ENV SESSION_KEY=""
|
||||
ENV REVERSE_PROXY="false"
|
||||
ENV REVERSE_PROXY_TLS_PORT=""
|
||||
ENV ARGS=""
|
||||
|
||||
RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ] && [ "$INCLUDE_MONGODBTOOLS" != "yes" ] && [ "$INCLUDE_MONGODBTOOLS" != "YES" ] \
|
||||
&& [ "$INCLUDE_MONGODBTOOLS" != "true" ] && [ "$INCLUDE_MONGODBTOOLS" != "TRUE" ]; then \
|
||||
echo -e "\e[0;31;49mInvalid value for build argument INCLUDE_MONGODBTOOLS, possible values: yes/true\e[;0m"; exit 1; \
|
||||
echo -e "\e[0;31;49mInvalid value for build argument INCLUDE_MONGODBTOOLS, possible values: yes/true\e[;0m"; exit 1; \
|
||||
fi
|
||||
|
||||
RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then apk add --no-cache mongodb-tools; fi
|
||||
|
||||
# copy files from builder-image
|
||||
COPY --from=builder /opt/meshcentral/meshcentral /opt/meshcentral/meshcentral
|
||||
COPY --from=builder /opt/meshcentral/meshcentral/docker/startup.sh ./startup.sh
|
||||
COPY --from=builder /opt/meshcentral/meshcentral/docker/config.json.template /opt/meshcentral/config.json.template
|
||||
|
||||
# cleanup
|
||||
RUN rm -rf /opt/meshcentral/meshcentral/docker
|
||||
RUN rm -rf /opt/meshcentral/meshcentral/node_modules
|
||||
COPY ./docker/startup.sh ./startup.sh
|
||||
COPY ./docker/config.json.template /opt/meshcentral/config.json.template
|
||||
|
||||
# install dependencies from package.json
|
||||
RUN cd meshcentral && npm install
|
||||
|
||||
# install dependencies for plugins
|
||||
RUN cd meshcentral && npm install nedb
|
||||
# NOTE: ALL MODULES MUST HAVE A VERSION NUMBER AND THE VERSION MUST MATCH THAT USED IN meshcentral.js mainStart()
|
||||
RUN if ! [ -z "$INCLUDE_MONGODBTOOLS" ]; then cd meshcentral && npm install mongodb@4.13.0 saslprep@1.0.3; fi
|
||||
RUN if ! [ -z "$PREINSTALL_LIBS" ] && [ "$PREINSTALL_LIBS" == "true" ]; then cd meshcentral && npm install ssh2@1.16.0 semver@7.5.4 nodemailer@6.9.15 image-size@1.1.1 wildleek@2.0.0 otplib@10.2.3 yubikeyotp@0.2.0; fi
|
||||
|
||||
EXPOSE 80 443 4433
|
||||
|
||||
|
|
@ -68,6 +96,6 @@ EXPOSE 80 443 4433
|
|||
VOLUME /opt/meshcentral/meshcentral-data
|
||||
VOLUME /opt/meshcentral/meshcentral-files
|
||||
VOLUME /opt/meshcentral/meshcentral-web
|
||||
VOLUME /opt/meshcentral/meshcentral-backup
|
||||
VOLUME /opt/meshcentral/meshcentral-backups
|
||||
|
||||
CMD ["bash", "/opt/meshcentral/startup.sh"]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"$schema": "http://info.meshcentral.com/downloads/meshcentral-config-schema.json",
|
||||
"$schema": "https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json",
|
||||
"settings": {
|
||||
"plugins":{"enabled": false},
|
||||
"_mongoDb": null,
|
||||
|
|
@ -21,9 +21,9 @@
|
|||
"": {
|
||||
"_title": "MyServer",
|
||||
"_title2": "Servername",
|
||||
"minify": true,
|
||||
"minify": false,
|
||||
"NewAccounts": true,
|
||||
"localSessionRecording": false,
|
||||
"localSessionRecording": true,
|
||||
"_userNameIsEmail": true,
|
||||
"_certUrl": "my.reverse.proxy"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
MSG="";
|
||||
PRUNE="false";
|
||||
|
||||
LOG_FILE=""
|
||||
#LOG_FILE="$(dirname -- "$( readlink -f -- "$0"; )")/build.log";
|
||||
OVERRIDE_TAGS="false";
|
||||
ENABLE_LOG="false";
|
||||
LOG_FILE="$(dirname -- "$( readlink -f -- "$0"; )")/build.log";
|
||||
|
||||
function appendOutput()
|
||||
{
|
||||
|
|
@ -12,23 +12,35 @@ function appendOutput()
|
|||
|
||||
ARGS=$@;
|
||||
LINE="${ARGS}\n";
|
||||
if [ -z "${LOG_FILE}" ]; then echo -e "${LINE}" > /dev/tty; else echo -e "${LINE}" &>> "${LOG_FILE}"; fi
|
||||
if [ -z "${ENABLE_LOG}" ] || [ "${ENABLE_LOG}" != "true" ]; then echo -e "${LINE}" > /dev/tty; else echo -e "${LINE}" 2>&1 | tee -a ${LOG_FILE}; fi
|
||||
|
||||
MSG="${MSG}${LINE}";
|
||||
}
|
||||
|
||||
function runDockerBuild()
|
||||
{
|
||||
if [ "${PRUNE}" == "true" ]; then docker system prune -a -f; fi
|
||||
if [ "${PRUNE}" == "true" ]; then
|
||||
if [ -z "${ENABLE_LOG}" ] || [ "${ENABLE_LOG}" != "true" ]; then docker system prune -a -f;
|
||||
else docker system prune -a -f | tee -a ${LOG_FILE}; fi
|
||||
fi
|
||||
|
||||
STARTTS=$(date +%s);
|
||||
ARGS=$@;
|
||||
|
||||
BUILD_CMD="docker build -f docker/Dockerfile --force-rm --no-cache ${ARGS} -t meshcentral .";
|
||||
APP_VERSION=$(grep -o '"version":\s*"[^"]*"' ./package.json | cut -f4- -d\" | tr -d '"');
|
||||
BASE_TAGS="";
|
||||
if [ -z "${OVERRIDE_TAGS}" ] || [ "${OVERRIDE_TAGS}" != "true" ]; then
|
||||
BASE_TAGS="-t meshcentral:latest -t meshcentral:${APP_VERSION}";
|
||||
fi
|
||||
|
||||
BUILD_CMD="docker build -f docker/Dockerfile --force-rm --no-cache ${ARGS} ${BASE_TAGS} .";
|
||||
appendOutput "Current build: ${BUILD_CMD}";
|
||||
|
||||
if [ -z "${LOG_FILE}" ]; then ${BUILD_CMD}; else ${BUILD_CMD} &>> "${LOG_FILE}"; fi
|
||||
if [ -z "${ENABLE_LOG}" ] || [ "${ENABLE_LOG}" != "true" ]; then ${BUILD_CMD}; else ${BUILD_CMD} | tee -a ${LOG_FILE}; fi
|
||||
if [ $? -ne 0 ]; then exit $?; fi
|
||||
|
||||
IMAGEID=$(docker images --format "{{.ID}} {{.CreatedAt}}" | sort -rk 2 | awk 'NR==1{print $1}');
|
||||
appendOutput "\tImageId: ${IMAGEID}";
|
||||
|
||||
ENDTS=$(date +%s);
|
||||
DIFSEC=$((${ENDTS}-${STARTTS}));
|
||||
|
|
@ -44,7 +56,7 @@ function runDockerBuild()
|
|||
else appendOutput "\tBuild time: ${TMPMIN} min ${TMPSEC} sec"; fi
|
||||
else appendOutput "\tBuild time: ${DIFSEC} sec"; fi
|
||||
|
||||
IMG_SIZE=$(docker image inspect meshcentral | grep -e "\"Size\"" | tr -d '",' | sed -E "s/\s*Size:\s*//");
|
||||
IMG_SIZE=$(docker image inspect ${IMAGEID} | grep -o '"Size":\s*[^,]*' | cut -f2- -d ':' | tr -d ' ');
|
||||
expr $IMG_SIZE + 0 > /dev/null;
|
||||
appendOutput "\tImage size: ${IMG_SIZE} ($((${IMG_SIZE}/1024/1024))M)\n";
|
||||
|
||||
|
|
@ -57,19 +69,64 @@ if [ "${parent_path}" != "$(pwd -P)" ]; then
|
|||
cd "${parent_path}";
|
||||
fi
|
||||
|
||||
if ! [ -z $1 ] && [ "${1}" == "prune" ]; then PRUNE="true"; fi
|
||||
if ! [ -z $1 ]; then
|
||||
for arg in "$@"
|
||||
do
|
||||
case "${arg}" in
|
||||
--prune)
|
||||
PRUNE="true";
|
||||
shift 1;
|
||||
;;
|
||||
--log)
|
||||
ENABLE_LOG="true";
|
||||
shift 1;
|
||||
;;
|
||||
--no-tags)
|
||||
OVERRIDE_TAGS="true";
|
||||
shift 1;
|
||||
;;
|
||||
--help)
|
||||
__usage="\n
|
||||
Usage: ./$(basename ${0}) [OPTIONS] [BUILD ARGUMENTS]\n
|
||||
\n
|
||||
Options:\n
|
||||
\t--log \t\twrite output to build.log file\n
|
||||
\t--no-tags \tdo not use default tags (meshcentral:latest and meshcentral:%VERSION%)\n
|
||||
\t--prune \tWARNING: This will remove:\n
|
||||
\t\t\t - all stopped docker containers\n
|
||||
\t\t\t - all docker networks not used by at least one container\n
|
||||
\t\t\t - all docker images without at least one container associated to them\n
|
||||
\t\t\t - all docker build cache\n
|
||||
\n
|
||||
Build arguments: \tAll build arguments are forwarded to the docker build command, so you can use any option accepted by 'docker build'\n
|
||||
\t\t\t(https://docs.docker.com/engine/reference/commandline/build/#options)\n\n
|
||||
\t--build-arg INCLUDE_MONGODBTOOLS=yes \tIncludes mongodb-tools (mongodump, ...) in the image\n
|
||||
\t--build-arg DISABLE_MINIFY=yes \t\tDisables minification of files\n
|
||||
\t--build-arg DISABLE_TRANSLATE=yes \tDisables translation of files\n
|
||||
";
|
||||
echo -e $__usage;
|
||||
exit 0;
|
||||
;;
|
||||
*)
|
||||
break;
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
#runDockerBuild --build-arg DISABLE_MINIFY=yes --build-arg DISABLE_TRANSLATE=yes;
|
||||
#runDockerBuild --build-arg DISABLE_TRANSLATE=yes;
|
||||
#runDockerBuild --build-arg DISABLE_MINIFY=yes;
|
||||
runDockerBuild;
|
||||
MAINARGS=$@;
|
||||
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes --build-arg DISABLE_MINIFY=yes --build-arg DISABLE_TRANSLATE=yes;
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes --build-arg DISABLE_TRANSLATE=yes;
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes --build-arg DISABLE_MINIFY=yes;
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes;
|
||||
#runDockerBuild --build-arg DISABLE_MINIFY=yes --build-arg DISABLE_TRANSLATE=yes ${MAINARGS};
|
||||
#runDockerBuild --build-arg DISABLE_TRANSLATE=yes ${MAINARGS};
|
||||
#runDockerBuild --build-arg DISABLE_MINIFY=yes ${MAINARGS};
|
||||
runDockerBuild ${MAINARGS};
|
||||
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes --build-arg DISABLE_MINIFY=yes --build-arg DISABLE_TRANSLATE=yes ${MAINARGS};
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes --build-arg DISABLE_TRANSLATE=yes ${MAINARGS};
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes --build-arg DISABLE_MINIFY=yes ${MAINARGS};
|
||||
#runDockerBuild --build-arg INCLUDE_MONGODBTOOLS=yes ${MAINARGS};
|
||||
|
||||
echo "";
|
||||
echo -e "${MSG}";
|
||||
if [ -z "${ENABLE_LOG}" ] || [ "${ENABLE_LOG}" != "true" ]; then echo -e "${MSG}"; else echo -e "${MSG}" 2>&1 | tee -a ${LOG_FILE}; fi
|
||||
|
||||
exit 0;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,3 @@
|
|||
|
||||
# How to create a docker image for meshcentral
|
||||
|
||||
```
|
||||
> git clone https://github.com/Ylianst/MeshCentral.git
|
||||
> cd MeshCentral
|
||||
|
||||
> docker build -f docker/Dockerfile --force-rm -t meshcentral .
|
||||
|
||||
# alternative, if you want to include the mongodb-tools (mongodump, ...), you can add the 'INCLUDE_MONGODBTOOLS=yes' build argument
|
||||
> docker build -f docker/Dockerfile --force-rm --build-arg INCLUDE_MONGODBTOOLS=yes -t meshcentral .
|
||||
|
||||
# (optional) cleanup after docker build:
|
||||
> cd ..
|
||||
> rm -rf MeshCentral/
|
||||
```
|
||||
|
||||
> | Argument | Description |
|
||||
> | :--- | :--- |
|
||||
> | -f docker/Dockerfile | Path/Name of the Dockerfile |
|
||||
> | --force-rm | Always remove intermediate containers |
|
||||
> | -t meshcentral | Name and optionally a tag in the 'name:tag' format |
|
||||
|
||||
### Optional build arguments
|
||||
> | Argument | Description |
|
||||
> | :--- | :--- |
|
||||
> | INCLUDE_MONGODBTOOLS=yes | Includes mongodb-tools (mongodump, ...) in the image |
|
||||
> | DISABLE_MINIFY=yes | Disables the minification of files |
|
||||
> | DISABLE_TRANSLATE=yes | Disables the translation of files |
|
||||
|
||||
# Create folder-structure and files
|
||||
|
||||
```
|
||||
|
|
@ -40,12 +10,18 @@
|
|||
| - docker-compose.yml
|
||||
```
|
||||
|
||||
# Templates:
|
||||
## .env:
|
||||
# Templates
|
||||
|
||||
## .env
|
||||
You can place the `config.json` file directly under `./meshcentral/data/`, or use the following `.env` file instead.
|
||||
|
||||
```ini
|
||||
NODE_ENV=production
|
||||
|
||||
# initial mongodb-variables
|
||||
USE_MONGODB=false
|
||||
# set already exist mongo connection string url here
|
||||
MONGO_URL=
|
||||
# or set following init params for new mongodb, use it with docker-compose file with mongodb version
|
||||
MONGO_INITDB_ROOT_USERNAME=mongodbadmin
|
||||
MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd
|
||||
|
||||
|
|
@ -54,15 +30,14 @@ MONGO_INITDB_ROOT_PASSWORD=mongodbpasswd
|
|||
|
||||
# your hostname
|
||||
HOSTNAME=my.domain.com
|
||||
USE_MONGODB=false
|
||||
# set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy
|
||||
# set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy
|
||||
REVERSE_PROXY=false
|
||||
REVERSE_PROXY_TLS_PORT=
|
||||
# set to true if you wish to enable iframe support
|
||||
IFRAME=false
|
||||
# set to false if you want disable self-service creation of new accounts besides the first (admin)
|
||||
ALLOW_NEW_ACCOUNTS=true
|
||||
# set to true to enable WebRTC - per documentation it is not officially released with meshcentral, but is solid enough to work with. Use with caution
|
||||
# set to true to enable WebRTC - per documentation it is not officially released with meshcentral and currently experimental. Use with caution
|
||||
WEBRTC=false
|
||||
# set to true to allow plugins
|
||||
ALLOWPLUGINS=false
|
||||
|
|
@ -70,9 +45,12 @@ ALLOWPLUGINS=false
|
|||
LOCALSESSIONRECORDING=false
|
||||
# set to enable or disable minification of json, reduces traffic
|
||||
MINIFY=true
|
||||
# set this value to add extra arguments to meshcentral on startup (e.g --debug ldap)
|
||||
ARGS=
|
||||
```
|
||||
|
||||
## docker-compose.yml:
|
||||
## docker-compose.yml
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
|
|
@ -80,7 +58,8 @@ services:
|
|||
meshcentral:
|
||||
restart: always
|
||||
container_name: meshcentral
|
||||
image: meshcentral
|
||||
# use the official meshcentral container
|
||||
image: ghcr.io/ylianst/meshcentral:latest
|
||||
ports:
|
||||
# MeshCentral will moan and try everything not to use port 80, but you can also use it if you so desire, just change the config.json according to your needs
|
||||
- 8086:443
|
||||
|
|
@ -92,12 +71,13 @@ services:
|
|||
# where file uploads for users live
|
||||
- ./meshcentral/user_files:/opt/meshcentral/meshcentral-files
|
||||
# location for the meshcentral-backups - this should be mounted to an external storage
|
||||
- ./meshcentral/backup:/opt/meshcentral/meshcentral-backup
|
||||
- ./meshcentral/backup:/opt/meshcentral/meshcentral-backups
|
||||
# location for site customization files
|
||||
- ./meshcentral/web:/opt/meshcentral/meshcentral-web
|
||||
```
|
||||
|
||||
## docker-compose.yml mongodb:
|
||||
## docker-compose.yml mongodb
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
|
||||
|
|
@ -121,7 +101,8 @@ services:
|
|||
meshcentral:
|
||||
restart: always
|
||||
container_name: meshcentral
|
||||
image: meshcentral
|
||||
# use the official meshcentral container
|
||||
image: ghcr.io/ylianst/meshcentral:latest
|
||||
depends_on:
|
||||
- mongodb
|
||||
ports:
|
||||
|
|
@ -135,7 +116,7 @@ services:
|
|||
# where file uploads for users live
|
||||
- ./meshcentral/user_files:/opt/meshcentral/meshcentral-files
|
||||
# location for the meshcentral-backups - this should be mounted to an external storage
|
||||
- ./meshcentral/backup:/opt/meshcentral/meshcentral-backup
|
||||
- ./meshcentral/backup:/opt/meshcentral/meshcentral-backups
|
||||
# location for site customization files
|
||||
- ./meshcentral/web:/opt/meshcentral/meshcentral-web
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -1,36 +1,34 @@
|
|||
#!/bin/bash
|
||||
|
||||
export NODE_ENV=production
|
||||
|
||||
export HOSTNAME
|
||||
export REVERSE_PROXY
|
||||
export REVERSE_PROXY_TLS_PORT
|
||||
export IFRAME
|
||||
export ALLOW_NEW_ACCOUNTS
|
||||
export WEBRTC
|
||||
export MONGO_INITDB_ROOT_USERNAME
|
||||
export MONGO_INITDB_ROOT_PASSWORD
|
||||
export USE_MONGODB
|
||||
|
||||
if [ -f "meshcentral-data/config.json" ]
|
||||
then
|
||||
node meshcentral/meshcentral
|
||||
else
|
||||
cp config.json.template meshcentral-data/config.json
|
||||
if ! [ -z "$USE_MONGODB" ] && [ "$USE_MONGODB" == "true" ]; then
|
||||
sed -i "s/\"_mongoDb\": null/\"mongoDb\": \"mongodb:\/\/$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@mongodb:27017\"/" meshcentral-data/config.json
|
||||
if [ -f "meshcentral-data/${CONFIG_FILE}" ]; then
|
||||
node meshcentral/meshcentral --configfile "${CONFIG_FILE}" ${ARGS}
|
||||
else
|
||||
cp config.json.template meshcentral-data/"${CONFIG_FILE}"
|
||||
if [ -n "$USE_MONGODB" ] && [ "$USE_MONGODB" == "true" ]; then
|
||||
if [ -z "$MONGO_URL" ]; then
|
||||
prefix=""
|
||||
if [ -n "$MONGO_INITDB_ROOT_USERNAME" ] && [ -n "$MONGO_INITDB_ROOT_PASSWORD" ]; then
|
||||
prefix="$MONGO_INITDB_ROOT_USERNAME:$MONGO_INITDB_ROOT_PASSWORD@"
|
||||
fi
|
||||
MONGO_URL="${prefix}mongodb:27017"
|
||||
fi
|
||||
sed -i "s/\"cert\": \"myserver.mydomain.com\"/\"cert\": \"$HOSTNAME\"/" meshcentral-data/config.json
|
||||
sed -i "s/\"NewAccounts\": true/\"NewAccounts\": \"$ALLOW_NEW_ACCOUNTS\"/" meshcentral-data/config.json
|
||||
sed -i "s/\"enabled\": false/\"enabled\": \"$ALLOWPLUGINS\"/" meshcentral-data/config.json
|
||||
sed -i "s/\"localSessionRecording\": false/\"localSessionRecording\": \"$LOCALSESSIONRECORDING\"/" meshcentral-data/config.json
|
||||
sed -i "s/\"minify\": true/\"minify\": \"$MINIFY\"/" meshcentral-data/config.json
|
||||
sed -i "s/\"WebRTC\": false/\"WebRTC\": \"$WEBRTC\"/" meshcentral-data/config.json
|
||||
sed -i "s/\"AllowFraming\": false/\"AllowFraming\": \"$IFRAME\"/" meshcentral-data/config.json
|
||||
if [ "$REVERSE_PROXY" != "false" ]; then
|
||||
sed -i "s/\"_certUrl\": \"my\.reverse\.proxy\"/\"certUrl\": \"https:\/\/$REVERSE_PROXY:$REVERSE_PROXY_TLS_PORT\"/" meshcentral-data/config.json
|
||||
node meshcentral/meshcentral
|
||||
exit
|
||||
fi
|
||||
node meshcentral/meshcentral --cert "$HOSTNAME"
|
||||
fi
|
||||
sed -i "s/\"_mongoDb\": null/\"mongoDb\": \"mongodb:\/\/$MONGO_URL\"/" meshcentral-data/"${CONFIG_FILE}"
|
||||
fi
|
||||
sed -i "s/\"cert\": \"myserver.mydomain.com\"/\"cert\": \"$HOSTNAME\"/" meshcentral-data/"${CONFIG_FILE}"
|
||||
sed -i "s/\"NewAccounts\": true/\"NewAccounts\": $ALLOW_NEW_ACCOUNTS/" meshcentral-data/"${CONFIG_FILE}"
|
||||
sed -i "s/\"enabled\": false/\"enabled\": $ALLOWPLUGINS/" meshcentral-data/"${CONFIG_FILE}"
|
||||
sed -i "s/\"localSessionRecording\": false/\"localSessionRecording\": $LOCALSESSIONRECORDING/" meshcentral-data/"${CONFIG_FILE}"
|
||||
sed -i "s/\"minify\": false/\"minify\": $MINIFY/" meshcentral-data/"${CONFIG_FILE}"
|
||||
sed -i "s/\"WebRTC\": false/\"WebRTC\": $WEBRTC/" meshcentral-data/"${CONFIG_FILE}"
|
||||
sed -i "s/\"AllowFraming\": false/\"AllowFraming\": $IFRAME/" meshcentral-data/"${CONFIG_FILE}"
|
||||
if [ -z "$SESSION_KEY" ]; then
|
||||
SESSION_KEY="$(cat /dev/urandom | tr -dc 'A-Z0-9' | fold -w 48 | head -n 1)"
|
||||
fi
|
||||
sed -i "s/\"_sessionKey\": \"MyReallySecretPassword1\"/\"sessionKey\": \"$SESSION_KEY\"/" meshcentral-data/"${CONFIG_FILE}"
|
||||
if [ "$REVERSE_PROXY" != "false" ]; then
|
||||
sed -i "s/\"_certUrl\": \"my\.reverse\.proxy\"/\"certUrl\": \"https:\/\/$REVERSE_PROXY:$REVERSE_PROXY_TLS_PORT\"/" meshcentral-data/"${CONFIG_FILE}"
|
||||
node meshcentral/meshcentral --configfile "${CONFIG_FILE}" ${ARGS}
|
||||
exit
|
||||
fi
|
||||
node meshcentral/meshcentral --configfile "${CONFIG_FILE}" --cert "$HOSTNAME" ${ARGS}
|
||||
fi
|
||||
|
|
|
|||
55
docs/Example configs/haproxy-with-sni-sample.cfg
Normal file
55
docs/Example configs/haproxy-with-sni-sample.cfg
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Uses proxy protocol in HAProxy in combination with SNI to preserve the original host address
|
||||
# Update the config.json to work with HAProxy
|
||||
# Specify the IP addrehostname that the traffic will come from HAProxy (this might not be the address that is bound to the listener)
|
||||
# "tlsOffload": "10.1.1.10",
|
||||
#
|
||||
# Specify the HAPRoxy URL with the hostname to get the certificate
|
||||
# "certUrl": "https://mc.publicdomain.com:443/"
|
||||
|
||||
frontend sni-front
|
||||
bind 10.1.1.10:443
|
||||
mode tcp
|
||||
tcp-request inspect-delay 5s
|
||||
tcp-request content accept if { req_ssl_hello_type 1 }
|
||||
default_backend sni-back
|
||||
|
||||
backend sni-back
|
||||
mode tcp
|
||||
acl gitlab-sni req_ssl_sni -i gitlab.publicdomain.com
|
||||
acl mc-sni req_ssl_sni -i mc.publicdomain.com
|
||||
use-server gitlabSNI if gitlab-sni
|
||||
use-server mc-SNI if mc-sni
|
||||
server mc-SNI 10.1.1.10:1443 send-proxy-v2-ssl-cn
|
||||
|
||||
frontend cira-tcp-front
|
||||
bind 10.1.1.10:4433
|
||||
mode tcp
|
||||
option tcplog
|
||||
tcp-request inspect-delay 5s
|
||||
default_backend mc-cira-back
|
||||
|
||||
backend cira-tcp-back
|
||||
mode tcp
|
||||
server mc-cira 10.1.1.30:4433
|
||||
|
||||
frontend mc-front-HTTPS
|
||||
mode http
|
||||
option forwardfor
|
||||
bind 10.1.1.10:1443 ssl crt /etc/haproxy/vm.publicdomain.net.pem accept-proxy
|
||||
http-request set-header X-Forwarded-Proto https
|
||||
option tcpka
|
||||
default_backend mc-back-HTTP
|
||||
|
||||
backend mc-back-HTTPS
|
||||
mode http
|
||||
option forwardfor
|
||||
http-request add-header X-Forwarded-Host %[req.hdr(Host)]
|
||||
option http-server-close
|
||||
server mc-01 10.1.1.30:443 check port 443 verify none
|
||||
|
||||
# In the event that it is required to have TLS between HAProxy and Meshcentral,
|
||||
# Remove the tls_Offload line and replace with trustedProxy
|
||||
# Specify the IP addrehostname that the traffic will come from HAProxy (this might not be the address that is bound to the listener)
|
||||
# "trustedProxy": "10.1.1.10",
|
||||
# and change the last line of backend mc-back-HTTPS to use HTTPS by adding the ssl keyword
|
||||
# server mc-01 10.1.1.30:443 check ssl port 443 verify none
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||

|
||||
|
||||
Design and Architecture Guide [as .pdf](https://meshcentral.com/info/docs/MeshCentral2DesignArchitecture.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral Design & Architecture v0.0.4.odt?raw=true)
|
||||
Design and Architecture Guide [as .pdf](https://meshcentral.com/docs/MeshCentral2DesignArchitecture.pdf) [as .odt](https://github.com/Ylianst/MeshCentral/blob/master/docs/MeshCentral Design & Architecture v0.0.4.odt?raw=true)
|
||||
## Video Walkthru
|
||||
|
||||
<div class="video-wrapper">
|
||||
|
|
@ -108,29 +108,46 @@ Someone would think the server is rather simple when taking a look at the MeshCe
|
|||
### Code files
|
||||
|
||||
```
|
||||
amtevents.js | Used to scan a local network for Intel AMT machines.
|
||||
amtscanner.js | Used to run Intel AMT scripts from MeshCommander.
|
||||
amtscript.js | Used to generate and perform certificate operations.
|
||||
certoperations.js | Various commonly used methods.
|
||||
common.js | Used to access the MongoDB or NeDB database.
|
||||
db.js | Used to modify windows executables.
|
||||
exeHandler.js | Used to insert credentials in an HTTP stream.
|
||||
interceptor.js | Used to obtain and use a Let’s Encrypt certificate.
|
||||
letsencrypt.js | Used to offload RSA sign to other CPU cores.
|
||||
meshaccelerator.js | Used to communicate to agents.
|
||||
meshagent.js | The is the main module, gets the server started.
|
||||
meshcentral.js | Used to send SMTP mails.
|
||||
meshmail.js | Used to relay agent and browser web socket connections.
|
||||
meshrelay.js | MeshCentral server discovery when in LAN mode.
|
||||
meshscanner.js | Used to communicate with browsers.
|
||||
meshuser.js | Used to communicate to Intel® AMT CIRA.
|
||||
mpsserver.js | Used for server-to-server communication.
|
||||
multiserver.js | Performs password hash + salt.
|
||||
pass.js | Used to handle HTTP traffic.
|
||||
redirserver.js | Used to upgrade legacy MeshCentralv1 agents.
|
||||
swarmserver.js | Handles HTTPS traffic.
|
||||
webserver.js | Server background install on Windows.
|
||||
winservice.js | Server background install on Windows.
|
||||
amtevents.js | Used to decode Intel AMT WSMAN events.
|
||||
amtmanager.js | Used to handle Intel AMT/CIRA things.
|
||||
amtprovisioningserver.js | Used to Provision Intel AMT on a Local Network.
|
||||
amtscanner.js | Used to scan a local network for Intel AMT machines.
|
||||
amtscript.js | Used to run Intel AMT scripts from MeshCommander.
|
||||
certoperations.js | Used to generate and perform certificate operations.
|
||||
common.js | Various commonly used methods.
|
||||
crowdsec.js | Used to handle all crowdsec security features
|
||||
db.js | Used to access the MongoDB or NeDB database.
|
||||
exeHandler.js | Used to modify windows executables.
|
||||
firebase.js | Used to handle Google Firebase things.
|
||||
interceptor.js | Used to insert credentials in an HTTP stream.
|
||||
letsencrypt.js | Used to obtain and use a Let’s Encrypt certificate.
|
||||
mcrec.js | Standalone Session Recording Indexer.
|
||||
meshaccelerator.js | Used to offload RSA sign to other CPU cores.
|
||||
meshagent.js | Used to communicate to agents.
|
||||
meshbot.js | Sample bot to connect to meshcentral and preform various tasks
|
||||
meshcentral.js | The is the main module, gets the server started.
|
||||
meshctrl.js | MeshCtrl performs command line actions on a MeshCentral server.
|
||||
meshcore.js | Main Agent Code that runs on your remote devices.
|
||||
meshdesktopmultiplex.js | Used to handle remote desktop multiplexing.
|
||||
meshdevicefile.js | Used to handle file download requests.
|
||||
meshipkvm.js | Used to handle IP KVM integration
|
||||
meshmail.js | Used to send SMTP mails.
|
||||
meshmessaging.js | Used to handle all users messaging methods like 2FA.
|
||||
meshrelay.js | Used to relay agent and browser web socket connections.
|
||||
meshscanner.js | MeshCentral server discovery when in LAN mode.
|
||||
meshsms.js | Used to handle all users sms methods.
|
||||
meshuser.js | Used to communicate with browsers.
|
||||
mpsserver.js | Used to communicate to Intel® AMT CIRA.
|
||||
mqttbroker.js | Used to create/handle an MQTT broker (beta)
|
||||
multiserver.js | Used for server-to-server communication.
|
||||
pass.js | Performs password hash + salt.
|
||||
redirserver.js | Used to handle HTTP traffic.
|
||||
swarmserver.js | Used to upgrade legacy MeshCentralv1 agents.
|
||||
webauthn.js | Handles all WebAuthN things.
|
||||
webrelayserver.js | Used for all HTTP/HTTPS web relaying from agents.
|
||||
webserver.js | Handles HTTPS traffic.
|
||||
winservice.js | Server background install on Windows.
|
||||
|
||||
```
|
||||
|
||||
At a high level, the MeshCentral.js file will get the server started. By default, it will start the webserver.js on port 443, redirectserver.js on port 80 and mpssrver.js on port 4433. The webserver.js file will create a meshuser.js or meshagent.js instance each time a user or agent connects. The other files support various usages, but this is the basic working on the server.
|
||||
|
|
|
|||
BIN
docs/docs/how-to-contribute/images/translation-msg-output.png
Normal file
BIN
docs/docs/how-to-contribute/images/translation-msg-output.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
56
docs/docs/how-to-contribute/index.md
Normal file
56
docs/docs/how-to-contribute/index.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Contribute to MeshCentral
|
||||
|
||||
## Contributing to MeshCentral via GitHub Pull Request
|
||||
|
||||
If you're looking to contribute beyond translations, such as updating documentation or enhancing the software by adding features or fixing bugs, the process involves several key steps:
|
||||
|
||||
1. **Fork the Repository:** Start by forking the [MeshCentral](https://github.com/Ylianst/MeshCentral) repository on GitHub. This creates a copy of the repository under your own GitHub account, allowing you to make changes without affecting the original project.
|
||||
|
||||
2. **Make Your Changes**
|
||||
- In your forked repository, create a new branch to keep your changes organized. This helps in managing different contributions separately.
|
||||
- Make the necessary changes in your repository. This could involve updating documentation files or modifying code to add new features or fix bugs.
|
||||
|
||||
3. **Review Your Changes:** Before submitting your work, carefully review the changes you’ve made. Check the "Files Changed" section on GitHub to ensure that all modifications are intended and correctly implemented.
|
||||
|
||||
4. **Submit a Pull Request**
|
||||
- Once your changes are ready and reviewed, submit a pull request (PR) from your branch to the `master` branch of the main MeshCentral repository.
|
||||
- When creating the pull request, provide a clear and detailed description of what changes have been made and why. This helps maintainers understand the purpose of your contributions.
|
||||
|
||||
5. **Wait for Review:** After submitting your pull request, wait for a project maintainer to review your contribution. Review time can vary depending on the complexity of the changes and the availability of the maintainers.
|
||||
|
||||
6. **Respond to Feedback:** The maintainer may request further modifications or provide feedback on your pull request. Be prepared to make additional changes based on their suggestions to ensure that your contribution meets the project’s standards and requirements.
|
||||
|
||||
7. **Final Steps:** Once your pull request is approved and merged by a maintainer, your contributions will be incorporated into the MeshCentral project. Congratulations, and thank you for helping improve MeshCentral!
|
||||
|
||||
---
|
||||
|
||||
## Contribute to MeshCentral's Multilingual Support
|
||||
|
||||
To make MeshCentral multilingual, your contributions are crucial. Follow these steps to translate the interface into various languages.
|
||||
|
||||
1. **Remove Local Translations:** Delete `translate.json` from your `meshcentral-data` folder. This file contains your local copy of translations, which may become outdated as new features and texts are added.
|
||||
|
||||
2. **Access MeshCentral:** Ensure you are logged into MeshCentral.
|
||||
3. **Open Translation Tool:** Visit `https://YOURMESHCENTRALSERVER.COM/translator.htm` to access the translation interface.
|
||||
4. **Choose a Language:** Select the language you wish to translate from the list provided.
|
||||
|
||||
5. **Translate Text:** Use the search function or scroll through the list to find text segments you want to translate. Utilize the "show no translations only" checkbox to filter untranslated texts.
|
||||
6. **Enter Translations:** For each text segment, enter your translation in the bottom box (not the top one) and click `SET (F1)`.
|
||||
7. **Repeat Translation:** Continue translating by repeating steps 5 and 6 for other texts as desired.
|
||||
|
||||
8. **Save and Apply Translations**
|
||||
- Click `SAVE TO SERVER (F3)` to save your translations to `meshcentral-data/translate.json` locally in your MeshCentral server.
|
||||
- Optionally, click `SAVE TO FILE (F4)` to download the `translate.json` file for offline review or sharing.
|
||||
|
||||
9. **Deploy Translations:** Click `TRANSLATE SERVER` and allow some time for the process to complete (approximately 5-15 minutes depending on server specifications). This command line output will indicate when the translation is complete.
|
||||

|
||||
|
||||
10. **Finalize Changes:** It’s crucial to restart MeshCentral to ensure that the translated files are picked up correctly.
|
||||
11. **Share your translations:** Once a language translation is complete, take the latest `translation.json` and share it by emailing it to the maintainer (Ylianst, `ylianst@gmail.com`) or by submitting it to the MeshCentral GitHub repository via a pull request.
|
||||
|
||||
---
|
||||
|
||||
#### Additional Information:
|
||||
- If you make any changes to `default.handlebars`, run the translate server to propagate these modifications to the language-specific handlebar files located in `node_modules/meshcentral/views/translations`.
|
||||
|
||||
By following these steps, you help MeshCentral support any language you choose, making it more accessible worldwide. By sharing your translations with us, you also help make these languages available to other users, improving the community and extending the software's reach.
|
||||
BIN
docs/docs/images/2022-08-04-18-19-19.png
Normal file
BIN
docs/docs/images/2022-08-04-18-19-19.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
MeshCentral is a full computer management web site. With MeshCentral, you can run your own web server to remotely manage and control computers on a local network or anywhere on the internet. Once you get the server started, create device group and download and install an agent on each computer you want to manage. A minute later, the new computer will show up on the web site and you can take control of it. MeshCentral includes full web-based remote desktop, terminal and file management capability.
|
||||
|
||||
To try out this software on the public server, please visit [MeshCentral.com/login](https://meshcentral.com/login). Be mindful that the public MeshCentral server comes with no guaranties, most should setup their own server.
|
||||
|
||||
For more information, [visit MeshCentral.com](https://www.meshcentral.com/).
|
||||
|
||||
## Social Media
|
||||
|
|
@ -14,17 +12,17 @@ For more information, [visit MeshCentral.com](https://www.meshcentral.com/).
|
|||
|
||||
[Reddit](https://www.reddit.com/r/MeshCentral/)
|
||||
|
||||
[Twitter](https://twitter.com/MeshCentral)
|
||||
[BlueSky](https://bsky.app/profile/meshcentral.bsky.social)
|
||||
|
||||
[BlogSpot](https://meshcentral2.blogspot.com/)
|
||||
|
||||
## Documentation
|
||||
|
||||
The [User's Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2UserGuide.pdf) contains information every adminstrator should know including usage, the server configuration file, databases, TLS offloading, Lets Encrypt, IP Filtering, Email setup, embedding, server port aliasing, reverse proxy setup, multi factor authentication, branding & terms of use, HashiCorp Vault support, and SSO.
|
||||
The [User's Guide](meshcentral) contains information every administrator should know including usage, the server configuration file, databases, TLS offloading, Lets Encrypt, IP Filtering, Email setup, embedding, server port aliasing, reverse proxy setup, multi factor authentication, branding & terms of use, HashiCorp Vault support, and SSO.
|
||||
|
||||
The [Installation Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2InstallGuide.pdf) has detailed instructions for installing the MeshCentral Server on Windows 8.1, Windows 10, Windows 2012 R2, Amazon Linux 2, Raspberry Pi, Microsoft Azure, Google Cloud, Ubuntu 18, Ubuntu 16 and OpenBSD.
|
||||
The [Installation Guide](install/install2.md) has detailed instructions for installing the MeshCentral Server on Windows 8.1, Windows 10, Windows 2012 R2, Amazon Linux 2, Raspberry Pi, Microsoft Azure, Google Cloud, Ubuntu 18, Ubuntu 16 and OpenBSD.
|
||||
|
||||
The [Design and Architecture Guide](https://info.meshcentral.com/downloads/MeshCentral2/MeshCentral2DesignArchitecture.pdf) is a short document that includes information on the design overview, dependencies, source code descriptions of each file, certificates, TLS security, the agent to server handshake, browser to agent relay and WebRTC and the messenger service.
|
||||
The [Design and Architecture Guide](design) is a short document that includes information on the design overview, dependencies, source code descriptions of each file, certificates, TLS security, the agent to server handshake, browser to agent relay and WebRTC and the messenger service.
|
||||
|
||||
## Video Tutorials
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ npm install meshcentral
|
|||
node node_modules/meshcentral
|
||||
```
|
||||
|
||||
That's it. MeshCentral will set itself up and start managing computers on your local network. By default it will be setup in LAN mode and agents you install will multicast on the local network to find the server. To setup the server so that agents use a well known DNS name and to start customizing your server, go in the "meshcentral-data" folder and edit the config.json file. The configuration file must be valid JSON, you can use this link to validate the file format.
|
||||
That's it. MeshCentral will set itself up and start managing computers on your local network. By default it will be setup in LAN mode and agents you install will multicast on the local network to find the server. To setup the server so that agents use a well known DNS name and to start customizing your server, go in the "meshcentral-data" folder and edit the config.json file. The configuration file must be valid JSON, you can use this [link](https://duckduckgo.com/?va=j&t=hc&q=json+lint&ia=answer) to validate the file format.
|
||||
|
||||
For Windows users, you can download the MeshCentral Installer that will automate installation of NodeJS and provide basic configuration of the server. This option is not recommended for advanced users.
|
||||
|
||||
[Win32 MeshCentral Installer](https://meshcentral.com/info/tools/MeshCentralInstaller.exe)
|
||||
[Win32 MeshCentral Installer](https://meshcentral.com/tools/MeshCentralInstaller.exe)
|
||||
|
||||
By default, MeshCentral will use NeDB as this is the built-in database. For more advanced users, it's recommended to switch to using MongoDB. MeshCentral can be installed on a very small server. A [Raspberry Pi](https://www.raspberrypi.org/) or [AWS t3.nano running Amazon Linux 2 instance](https://aws.amazon.com/ec2/pricing/on-demand/) for 5$ a month will do just fine for managing up to a few hundred devices.
|
||||
|
||||
|
|
@ -23,10 +23,10 @@ You can run the MeshCentral Server with --help to get options for background ins
|
|||
|
||||
Once you get MeshCentral installed, the first user account that is created will be the server administrator. So, don't delay and navigate to the login page and create a new account. You can then start using your server right away. A lot of the fun with MeshCentral is the 100's of configuration options that are available in the config.json file. You can put your own branding on the web pages, setup a SMTP email server, SMS services and much more.
|
||||
|
||||
You can look [here for simple config.json](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config.json), [here for a more advanced configuration](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config-advanced.json) and [here for all possible configuration options](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json). You can also take a look at the [MeshCentral User's Guide](https://meshcentral.com/info/docs/MeshCentral2InstallGuide.pdf) and [tutorial videos](https://meshcentral.com/info/tutorials.html) for additional help.
|
||||
You can look [here for simple config.json](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config.json), [here for a more advanced configuration](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/sample-config-advanced.json) and [here for all possible configuration options](https://raw.githubusercontent.com/Ylianst/MeshCentral/master/meshcentral-config-schema.json). You can also take a look at the [tutorial videos](https://www.youtube.com/@MeshCentral/videos) for additional help.
|
||||
|
||||
## Video Walkthru
|
||||
|
||||
<div class="video-wrapper">
|
||||
<iframe width="320" height="180" src="https://www.youtube.com/embed/LSiWuu71k_U" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,45 @@
|
|||
|
||||
This guide is specifically intended to help users install MeshCentral from start to finish. Once installed, you can take a look at the MeshCentral user’s guide for information on how to configure MeshCentral for your specific use. In this document, we will look at installing MeshCentral on AWS Linux, Raspberry Pi and Ubuntu.
|
||||
|
||||
## Docker
|
||||
|
||||
<https://github.com/Ylianst/MeshCentral/pkgs/container/meshcentral>
|
||||
|
||||
```
|
||||
docker pull ghcr.io/ylianst/meshcentral:master
|
||||
```
|
||||
|
||||
!!!warning
|
||||
Do not use the built in mesh update function. Update docker the docker way.
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```
|
||||
version: '3'
|
||||
services:
|
||||
meshcentral:
|
||||
restart: unless-stopped # always restart the container unless you stop it
|
||||
image: ghcr.io/ylianst/meshcentral:1.1.27 # 1.1.27 is a version number OR use master for the master branch of bug fixes
|
||||
ports:
|
||||
- 80:80 # HTTP
|
||||
- 443:443 # HTTPS
|
||||
- 4433:4433 # AMT (Optional)
|
||||
volumes:
|
||||
- data:/opt/meshcentral/meshcentral-data # config.json and other important files live here
|
||||
- user_files:/opt/meshcentral/meshcentral-files # where file uploads for users live
|
||||
- backup:/opt/meshcentral/meshcentral-backups # location for the meshcentral backups - this should be mounted to an external storage
|
||||
- web:/opt/meshcentral/meshcentral-web # location for site customization files
|
||||
volumes:
|
||||
data:
|
||||
driver: local
|
||||
user_files:
|
||||
driver: local
|
||||
backup:
|
||||
driver: local
|
||||
web:
|
||||
driver: local
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
For some who want to skip this document entirely, there are quick install scripts that will get a MeshCentral2 instance up and running on Linux in a few minutes. These scripts will pretty much do what this document explains very rapidly. Right now, there are two such scripts available:
|
||||
|
|
@ -13,7 +52,7 @@ For some who want to skip this document entirely, there are quick install script
|
|||
For Amazon EC2 users, that want to manage 100 devices or less. Launch a t3.nano or t3.micro EC2 instance with Amazon Linux 2 with TCP ports 22 (SSH), 80 (HTTP), 443 (HTTPS) and 4433 (CIRA) open. Then login as `ec2-user` and enter the following commands:
|
||||
|
||||
```
|
||||
wget http://info.meshcentral.com/scripts/mc-aws-linux2.sh
|
||||
wget https://meshcentral.com/scripts/mc-aws-linux2.sh
|
||||
chmod 755 mc-aws-linux2.sh
|
||||
./mc-aws-linux2.sh
|
||||
```
|
||||
|
|
@ -21,7 +60,7 @@ chmod 755 mc-aws-linux2.sh
|
|||
This will download the fast install script and once run, will install nodejs, meshcentral, setup systemd and start the server. For a larger instance like a t3.small, t3.medium or larger you can run the following that does the same but also installs MongoDB.
|
||||
|
||||
```
|
||||
wget http://info.meshcentral.com/scripts/mc-aws-linux2-mongo.sh
|
||||
wget https://meshcentral.com/scripts/mc-aws-linux2-mongo.sh
|
||||
chmod 755 mc-aws-linux2-mongo.sh
|
||||
./mc-aws-linux2-mongo.sh
|
||||
```
|
||||
|
|
@ -33,13 +72,29 @@ After these scripts are run, try accessing the server using a browser. MeshCentr
|
|||
For 100 devices or less, launch an instance of Ubuntu 18.04 using a small B1s instance. Set the username to `default` in all lower case and open ports 22, 80, 443 and 3389 using the basic network profile. Then start the instance and run the following lines.
|
||||
|
||||
```
|
||||
wget http://info.meshcentral.com/scripts/mc-azure-ubuntu1804.sh
|
||||
wget https://meshcentral.com/scripts/mc-azure-ubuntu1804.sh
|
||||
chmod 755 mc-azure-ubuntu1804.sh
|
||||
./mc-azure-ubuntu1804.sh
|
||||
```
|
||||
|
||||
In this situation, port 3389 will be used to receive Intel AMT CIRA connections instead of port 4433. After these scripts are run, try accessing the server using a browser. MeshCentral will take a minute or two to create certificates after that, the server will be up. The first account to be created will be the site administrator – so don’t delay and create an account right away. Once running, move on to the MeshCentral’s user’s guide to configure your new server.
|
||||
|
||||
### Elestio
|
||||
|
||||
You can deploy MeshCentral on Elestio using one-click deployment. Elestio handles version updates, maintenance, securtiy, backups, etc. Additionally, Elestio supports MeshCentral by providing revenue share so go ahead and click below to deploy and start using.
|
||||
|
||||
[](https://elest.io/open-source/meshcentral)
|
||||
|
||||
## Server Security - Adding Crowdsec
|
||||
|
||||
MeshCentral has built-in support for a CrowdSec bouncer. This allows MeshCentral to get threat signals from the community and block or CAPTCHA requests coming from known bad IP addresses.
|
||||
|
||||
## Video Walkthru
|
||||
|
||||
<div class="video-wrapper">
|
||||
<iframe width="320" height="180" src="https://www.youtube.com/embed/TVKF9gBJFCE" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
## Windows Installation
|
||||
MeshCentral is constructed entirely with NodeJS, an asynchronous event driven JavaScript runtime (https://nodejs.org/). A basic understanding on NodeJS may be preferable but not compulsory. MeshCentral server which heavily relies on NodeJS runtime will be able run on almost any computing platform with contemporary operating systems including Windows*, Linux* and macOS*.
|
||||
|
||||
|
|
@ -874,7 +929,7 @@ The last line will run MeshCentral manually and allow it to install any missing
|
|||
|
||||
```
|
||||
sudo chown -R meshcentral:meshcentral /opt/meshcentral
|
||||
sudo chmod 755 –R /opt/meshcentral/meshcentral-*
|
||||
sudo chmod -R 755 /opt/meshcentral/meshcentral-*
|
||||
```
|
||||
|
||||
To make this work, you will need to make MeshCentral work with MongoDB because the /meshcentral-data folder will be read-only. In addition, MeshCentral will not be able to update itself since the account does not have write access to the /node_modules files, so the update will have to be manual. First used systemctl to stop the MeshCentral server process, than use this:
|
||||
|
|
@ -891,7 +946,7 @@ This will perform the update to the latest server on NPM and re-set the permissi
|
|||
MeshCentral allows users to upload and download files stores in the server’s `meshcentral-files` folder. In an increased security setup, we still want the server to be able to read and write files to this folder and we can allow this with:
|
||||
|
||||
```
|
||||
sudo chmod 755 –R /opt/meshcentral/meshcentral-files
|
||||
sudo chmod -R 755 /opt/meshcentral/meshcentral-files
|
||||
```
|
||||
|
||||
If you plan on using the increased security installation along with MeshCentral built-in Let’s Encrypt support you will need to type the following commands to make the `letsencrypt` folder in `meshcentral-data` writable.
|
||||
|
|
@ -899,11 +954,19 @@ If you plan on using the increased security installation along with MeshCentral
|
|||
```
|
||||
sudo mkdir /opt/meshcentral/meshcentral-data
|
||||
sudo mkdir /opt/meshcentral/meshcentral-data/letsencrypt
|
||||
sudo chmod 755 –R /opt/meshcentral/meshcentral-data/letsencrypt
|
||||
sudo chmod -R 755 /opt/meshcentral/meshcentral-data/letsencrypt
|
||||
```
|
||||
|
||||
This will allow the server to get and periodically update its Let’s Encrypt certificate. If this is not done, the server will generate an `ACCES: permission denied` exception.
|
||||
|
||||
### Restore backup in Ubuntu
|
||||
|
||||
- Stop Meshcentral service `sudo systemctl stop meshcentral.service`
|
||||
- In your old server, get your backup : meshcentral-data folder, and mongodump-xxxx.archive
|
||||
- In the new server, replace the actual meshcentral-data with your backup (it will handle your LestEncrypt cert also)
|
||||
- Restore mongodb : mongorestore --archive=mongodump-xxxx.archive
|
||||
- Restart meshcentral.service `sudo systemctl start meshcentral.service`
|
||||
|
||||
## Microsoft Azure
|
||||
|
||||
In this section, we will look installing MeshCentral on Microsoft Azure. Microsoft Azure offers many operating system options and we will be selecting `Ubuntu Server` as our choice. From the Azure portal, we select `Virtual machines` on the left and `Add`.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue