mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Compare commits
904 Commits
v1.77.2-nb
...
v1.77.3-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5c156e0b1 | ||
|
|
a7e8d8523a | ||
|
|
2ead94a740 | ||
|
|
737df595df | ||
|
|
e1023a6aed | ||
|
|
0eedfab5b1 | ||
|
|
c682b603e7 | ||
|
|
fe063a98cd | ||
|
|
c90beb66a0 | ||
|
|
f38dc86551 | ||
|
|
389776ae64 | ||
|
|
ebe782e5a4 | ||
|
|
d3f497bfbc | ||
|
|
e89b1f4139 | ||
|
|
b5c431b8e7 | ||
|
|
3746ba1819 | ||
|
|
945bff3c17 | ||
|
|
d7e318b1f8 | ||
|
|
eb3db198a1 | ||
|
|
a908a783be | ||
|
|
1ae9960e82 | ||
|
|
5aa8425209 | ||
|
|
b794aa8089 | ||
|
|
e8bb0bffaa | ||
|
|
e1e0661f25 | ||
|
|
7848c83c72 | ||
|
|
2de37ed9c7 | ||
|
|
425b433cd2 | ||
|
|
44e07e3cdb | ||
|
|
689f882104 | ||
|
|
207beaee12 | ||
|
|
bd21b85de7 | ||
|
|
2e7579cac5 | ||
|
|
ec63812af0 | ||
|
|
8dfe1a22c9 | ||
|
|
c0e3f547ec | ||
|
|
dafb1b364c | ||
|
|
7d1b9d8635 | ||
|
|
8041f58ffd | ||
|
|
d018fdbace | ||
|
|
489602ffb3 | ||
|
|
600ba73f5f | ||
|
|
88600ae6df | ||
|
|
5e3bce9a92 | ||
|
|
9b28b7057d | ||
|
|
0a17220446 | ||
|
|
7684b19d13 | ||
|
|
47baf3b662 | ||
|
|
bc5e2b9437 | ||
|
|
cf0ef6d9d0 | ||
|
|
b6f3047f82 | ||
|
|
0a418561d7 | ||
|
|
6da79a41df | ||
|
|
3ddeac6c74 | ||
|
|
98f97c442d | ||
|
|
472d33ba12 | ||
|
|
d906cfcc1e | ||
|
|
0f0d8bdcdb | ||
|
|
005b2485f6 | ||
|
|
ffd90bed70 | ||
|
|
70264a24ab | ||
|
|
ad3a37fde3 | ||
|
|
9dac0eeaac | ||
|
|
8dac393bb4 | ||
|
|
287d1a5575 | ||
|
|
20278e0e53 | ||
|
|
a3c3ec8c5c | ||
|
|
3039b25a66 | ||
|
|
0b7ce92af8 | ||
|
|
e3ec521a1d | ||
|
|
88999263a7 | ||
|
|
9687ccd01d | ||
|
|
ca62502499 | ||
|
|
8b3a68f58e | ||
|
|
08eb35a360 | ||
|
|
dec82b41f2 | ||
|
|
b9ab5c76f7 | ||
|
|
6de0c536e8 | ||
|
|
3f0aca97bf | ||
|
|
ccb51a2603 | ||
|
|
99d9e70921 | ||
|
|
b8b54271dd | ||
|
|
49a1549e5a | ||
|
|
b3f936c194 | ||
|
|
f3b10d4c20 | ||
|
|
94b17037d0 | ||
|
|
83f3846ce6 | ||
|
|
711a751117 | ||
|
|
e013e32792 | ||
|
|
6e64b09256 | ||
|
|
e32d268587 | ||
|
|
05635dec93 | ||
|
|
e694923d33 | ||
|
|
7322683465 | ||
|
|
64688f3512 | ||
|
|
762760af2f | ||
|
|
48e6881401 | ||
|
|
95c958136f | ||
|
|
53a6be0f82 | ||
|
|
0b4d95be1c | ||
|
|
aad3948475 | ||
|
|
093370081e | ||
|
|
33426ceee9 | ||
|
|
5f5700b948 | ||
|
|
802e9abfef | ||
|
|
45149d6547 | ||
|
|
595681a982 | ||
|
|
e1cac723d6 | ||
|
|
683f84f053 | ||
|
|
b6d882a06f | ||
|
|
9d4bfbcb1c | ||
|
|
b563747046 | ||
|
|
1ebd0a430f | ||
|
|
ef4366be4d | ||
|
|
484283fef8 | ||
|
|
b546a48a5f | ||
|
|
51bd64d005 | ||
|
|
2c65d12b92 | ||
|
|
c43a3b5115 | ||
|
|
515778b13d | ||
|
|
bb4b9ce9e7 | ||
|
|
1d6707fecd | ||
|
|
5b2a46ed91 | ||
|
|
24fa97da4c | ||
|
|
b0109c2581 | ||
|
|
20f237ec4c | ||
|
|
6ea535ae29 | ||
|
|
57ca8a3eee | ||
|
|
307ea42a0f | ||
|
|
ac41c04f67 | ||
|
|
b3496e79de | ||
|
|
4f7aa755e3 | ||
|
|
d3af50f009 | ||
|
|
ba77a7b7c0 | ||
|
|
666a0e1537 | ||
|
|
96f4307910 | ||
|
|
81e997eb60 | ||
|
|
7132c6e7c2 | ||
|
|
cb01e92fe2 | ||
|
|
2c9c512d74 | ||
|
|
8d05c9040b | ||
|
|
4e994fb202 | ||
|
|
ab2a778694 | ||
|
|
115375820d | ||
|
|
8cb753916b | ||
|
|
ec3a0cee9b | ||
|
|
13f8f82537 | ||
|
|
54544dd2aa | ||
|
|
ac99115424 | ||
|
|
d6c6038193 | ||
|
|
c97b84e4a2 | ||
|
|
6698ec0b06 | ||
|
|
290b1c4de5 | ||
|
|
d497a50727 | ||
|
|
2837c91f5e | ||
|
|
9a717f28c6 | ||
|
|
e416c2c9c9 | ||
|
|
331cdaa6ce | ||
|
|
aa329b1a9a | ||
|
|
16c080942d | ||
|
|
4acc111b3d | ||
|
|
afe453d371 | ||
|
|
e93c120dac | ||
|
|
2f701458f4 | ||
|
|
6a35961dfb | ||
|
|
1a90095ba3 | ||
|
|
5dc87213b5 | ||
|
|
ff8044b09b | ||
|
|
f1fa40f6fd | ||
|
|
9bc5b62828 | ||
|
|
5aae586812 | ||
|
|
bc5e5be42e | ||
|
|
be68573378 | ||
|
|
cf0bc3d270 | ||
|
|
d5773eb2e9 | ||
|
|
50523e5b67 | ||
|
|
feeca86c6a | ||
|
|
a2e2671483 | ||
|
|
0b4d6ef8ef | ||
|
|
bdf0e532a5 | ||
|
|
d8cf72d09b | ||
|
|
6c3ec8f058 | ||
|
|
fbd9b76a09 | ||
|
|
bee216220a | ||
|
|
4ca7f34989 | ||
|
|
51015e6b51 | ||
|
|
46100d6d94 | ||
|
|
c94eac3863 | ||
|
|
965b0e5b6d | ||
|
|
000cea1dda | ||
|
|
6d4d60e3b1 | ||
|
|
9957282bfa | ||
|
|
9b603dd956 | ||
|
|
759ee55780 | ||
|
|
93b2edb5a5 | ||
|
|
4d49c14bb9 | ||
|
|
6398808a0a | ||
|
|
64e20f3665 | ||
|
|
3b542d8868 | ||
|
|
d5af0e43a5 | ||
|
|
7a8ef87dc7 | ||
|
|
7a5293cde3 | ||
|
|
26400631a0 | ||
|
|
97a5c584be | ||
|
|
0700b6573c | ||
|
|
d8f66a4188 | ||
|
|
c22971cf54 | ||
|
|
9d2dd5dd93 | ||
|
|
c19d512631 | ||
|
|
9efda5fef3 | ||
|
|
a27cdcfdb5 | ||
|
|
5667a07b25 | ||
|
|
7d0bd85466 | ||
|
|
4f269442a6 | ||
|
|
16d182fca2 | ||
|
|
6d1a206cc9 | ||
|
|
d8a7fdbf4f | ||
|
|
516b365ebc | ||
|
|
6da6a5ede9 | ||
|
|
67244f1957 | ||
|
|
0a304e9a03 | ||
|
|
05154af606 | ||
|
|
7454b15ec9 | ||
|
|
38f435f639 | ||
|
|
5f38ec7210 | ||
|
|
ca143bf969 | ||
|
|
402e5c3665 | ||
|
|
290dbcc3ed | ||
|
|
a7749c70e7 | ||
|
|
9f0cfd5f22 | ||
|
|
f47434c09e | ||
|
|
795a4b571e | ||
|
|
f71727e05e | ||
|
|
d2fa8e86b1 | ||
|
|
23dcd9d30f | ||
|
|
d6890c6ecd | ||
|
|
b1a6ba78d4 | ||
|
|
e6abe3f3a1 | ||
|
|
6c32540ecb | ||
|
|
951ad5cd0a | ||
|
|
5f56477123 | ||
|
|
3180f38a1d | ||
|
|
07f15993e5 | ||
|
|
fc8e9c7689 | ||
|
|
7cb20b9e28 | ||
|
|
ffc2351d64 | ||
|
|
f10fec61ac | ||
|
|
e41200067c | ||
|
|
30f6d3dde7 | ||
|
|
7f9dcb11f0 | ||
|
|
d5fa2f62c0 | ||
|
|
fa7967190d | ||
|
|
20e04c0d75 | ||
|
|
d5eea9db20 | ||
|
|
8cb598ce25 | ||
|
|
f3a57d7f23 | ||
|
|
14e47def9d | ||
|
|
7573081d7a | ||
|
|
aaca581324 | ||
|
|
43c2797a51 | ||
|
|
da6bbf65f0 | ||
|
|
7d0cbf423e | ||
|
|
d94eab71da | ||
|
|
b0a8ccc5b6 | ||
|
|
5cbf1f1568 | ||
|
|
22cde74db2 | ||
|
|
cdc3759c04 | ||
|
|
38abc8a167 | ||
|
|
7c7c7086ce | ||
|
|
50daf64025 | ||
|
|
dc38df5389 | ||
|
|
a46b2c9d98 | ||
|
|
200756361c | ||
|
|
877a1e4cd0 | ||
|
|
a382206f5a | ||
|
|
1af7a622a6 | ||
|
|
3f95b2aa7e | ||
|
|
b7871e2e04 | ||
|
|
6b6ceda497 | ||
|
|
b01b8e4bc8 | ||
|
|
20f7cb1cd0 | ||
|
|
3e1ee0056d | ||
|
|
a3a851e57f | ||
|
|
cf650d4318 | ||
|
|
58e7420f04 | ||
|
|
aedaf084d9 | ||
|
|
c18f638989 | ||
|
|
fb50cdc058 | ||
|
|
68e702c344 | ||
|
|
651b18a8b3 | ||
|
|
2174e56407 | ||
|
|
ea27a4da02 | ||
|
|
321fd1162b | ||
|
|
c51f38ddc7 | ||
|
|
b34cd1acc5 | ||
|
|
43f20bb83a | ||
|
|
79b8ddef15 | ||
|
|
2642ea0601 | ||
|
|
7a2f934f6a | ||
|
|
f299fefcdc | ||
|
|
209319f460 | ||
|
|
5ec4f4dcea | ||
|
|
16f67d58d1 | ||
|
|
542d794ab4 | ||
|
|
ede1573b56 | ||
|
|
bc8eec8887 | ||
|
|
59b0654b95 | ||
|
|
cae3477591 | ||
|
|
6a3115b80a | ||
|
|
1232d7c288 | ||
|
|
8e1b4c9271 | ||
|
|
0f8810e22a | ||
|
|
7bbff38b6b | ||
|
|
4a7b8fa250 | ||
|
|
53acc94976 | ||
|
|
ab8d83b12d | ||
|
|
713a0a6174 | ||
|
|
a3b9695b81 | ||
|
|
85dd381bd9 | ||
|
|
05b418e9b6 | ||
|
|
40af584afe | ||
|
|
93fe32491b | ||
|
|
4b67fcb0d4 | ||
|
|
0b0c92717d | ||
|
|
4564cafa85 | ||
|
|
2e21f8d03a | ||
|
|
4336254d56 | ||
|
|
bc5e9279a5 | ||
|
|
1bfbb956c2 | ||
|
|
b336db773c | ||
|
|
30e7d2424c | ||
|
|
cbb8c0234d | ||
|
|
95469107fd | ||
|
|
ba0058c0b9 | ||
|
|
8f35afe353 | ||
|
|
aaf219eb90 | ||
|
|
1167794d58 | ||
|
|
929babd69a | ||
|
|
870b7c1ffd | ||
|
|
9ed9d835b9 | ||
|
|
985feb4b91 | ||
|
|
c43c85bb21 | ||
|
|
038074131c | ||
|
|
ab9156a7d3 | ||
|
|
f4b76818e8 | ||
|
|
12a399a354 | ||
|
|
dfdbbea85c | ||
|
|
5fad5ec4c7 | ||
|
|
fe94da4727 | ||
|
|
361ae3af50 | ||
|
|
a2e302ebfa | ||
|
|
186ab9c00e | ||
|
|
9a2453524a | ||
|
|
3a2e128e98 | ||
|
|
1bd2dbf9f0 | ||
|
|
b7f880e7f8 | ||
|
|
13cd926b4f | ||
|
|
6fb7b1c6e4 | ||
|
|
8f35015a6c | ||
|
|
a926bccb97 | ||
|
|
b9f2abf5eb | ||
|
|
8dc5bda171 | ||
|
|
d24bdb543b | ||
|
|
dc921161e4 | ||
|
|
8e248cb545 | ||
|
|
ae93be4cfb | ||
|
|
42949fbe91 | ||
|
|
21dd175456 | ||
|
|
a3df0da26b | ||
|
|
6b9d4fd107 | ||
|
|
fac2ae6399 | ||
|
|
46732803c3 | ||
|
|
39d205bd4d | ||
|
|
8e2bd7997e | ||
|
|
76db9a6c62 | ||
|
|
c03d5e891d | ||
|
|
b21f6e8ce7 | ||
|
|
4b916f1888 | ||
|
|
1f80e5339b | ||
|
|
dc616f8ea1 | ||
|
|
dc6588243f | ||
|
|
690d3b0d4e | ||
|
|
4bc5dffabb | ||
|
|
55a1e4a544 | ||
|
|
5cb32dd75a | ||
|
|
f858c9fe48 | ||
|
|
0ac39af404 | ||
|
|
fc757b236f | ||
|
|
a921e6e3d4 | ||
|
|
8cf0f50565 | ||
|
|
575ad7664f | ||
|
|
be17488070 | ||
|
|
f504107928 | ||
|
|
0113f549c5 | ||
|
|
9ff831faab | ||
|
|
a9ca243c0b | ||
|
|
553bbef45f | ||
|
|
8f713f861b | ||
|
|
324054b9d7 | ||
|
|
d3fc9404ee | ||
|
|
5bb780439b | ||
|
|
f0e6008441 | ||
|
|
39dd69f15e | ||
|
|
7b2e89df26 | ||
|
|
aa853f8481 | ||
|
|
83bba75af6 | ||
|
|
23889aa5b1 | ||
|
|
5e6094fc42 | ||
|
|
a4181cb6d6 | ||
|
|
88c49f0722 | ||
|
|
513d9e199c | ||
|
|
e80975c56e | ||
|
|
9051ac102c | ||
|
|
39a9b2e619 | ||
|
|
dbc55d248f | ||
|
|
2b46180bfb | ||
|
|
5abe6c7e27 | ||
|
|
4595ebeb9a | ||
|
|
815c08e6d4 | ||
|
|
a72ad218a0 | ||
|
|
944ad1f769 | ||
|
|
e17a68f61c | ||
|
|
0b8196be68 | ||
|
|
d9c01148b7 | ||
|
|
2b3cfd992f | ||
|
|
7e4bd7a6f3 | ||
|
|
161e0ed637 | ||
|
|
1ee03e863c | ||
|
|
2411481d8b | ||
|
|
0314a627ed | ||
|
|
4d339a0b09 | ||
|
|
c171e7f94b | ||
|
|
eac4d966d9 | ||
|
|
c20868c20c | ||
|
|
bb74d46f1f | ||
|
|
152d48c583 | ||
|
|
b7a0155ba4 | ||
|
|
0414724b21 | ||
|
|
469f21db8d | ||
|
|
b6c9d30195 | ||
|
|
7b89430317 | ||
|
|
5bd854116a | ||
|
|
3fb7575529 | ||
|
|
a3a868c2ce | ||
|
|
1eb6fc2235 | ||
|
|
5ff4502f0a | ||
|
|
3126b8d4b0 | ||
|
|
dfb1d34b8a | ||
|
|
ace62c07be | ||
|
|
ec2f3024b6 | ||
|
|
25543f6561 | ||
|
|
3278657da7 | ||
|
|
90c4d12688 | ||
|
|
4ceaea99f7 | ||
|
|
585de34ef1 | ||
|
|
60e1a3ce93 | ||
|
|
413d77ff1a | ||
|
|
d8bb561063 | ||
|
|
5dff2c20b2 | ||
|
|
27803e7787 | ||
|
|
58f9c1575f | ||
|
|
7b909665b9 | ||
|
|
11eee991a1 | ||
|
|
7056a859ef | ||
|
|
2455f0d73e | ||
|
|
943d36e23e | ||
|
|
b563ac6e0c | ||
|
|
ed37a8ca2a | ||
|
|
55bee8b0d8 | ||
|
|
6bd18c29e3 | ||
|
|
37fc611767 | ||
|
|
f95fe351e2 | ||
|
|
2fb0ab1d91 | ||
|
|
85f7be1d79 | ||
|
|
b3e5c1abc2 | ||
|
|
9e216c0020 | ||
|
|
a9f00b6a8c | ||
|
|
46e7b02da2 | ||
|
|
8db0bc6e6f | ||
|
|
1702b5867a | ||
|
|
c03a6452ef | ||
|
|
69b840fb12 | ||
|
|
9385ab287f | ||
|
|
d2b2c39b97 | ||
|
|
f8ff978738 | ||
|
|
d50b32236c | ||
|
|
88d1db2840 | ||
|
|
b1dbe562d6 | ||
|
|
e95b6f1b5d | ||
|
|
1cbb7bb5dd | ||
|
|
34f3ffa129 | ||
|
|
ecd25a673e | ||
|
|
58d0778c3d | ||
|
|
81a5422974 | ||
|
|
eb859e5ede | ||
|
|
c8035b5071 | ||
|
|
a98a336e52 | ||
|
|
d7f6535b85 | ||
|
|
f9d4e3152b | ||
|
|
69bd816aeb | ||
|
|
783810749c | ||
|
|
92c3c967ba | ||
|
|
c632ba4306 | ||
|
|
e29d2c25ba | ||
|
|
5cfdc96cd2 | ||
|
|
a20e10b342 | ||
|
|
39b7414553 | ||
|
|
0eef20caf6 | ||
|
|
859d12b450 | ||
|
|
cd7c594b76 | ||
|
|
39862e15f6 | ||
|
|
87b0cf5c3f | ||
|
|
a14219e1e2 | ||
|
|
ee4660707c | ||
|
|
ccdf15c79c | ||
|
|
b31362afab | ||
|
|
74d6c88565 | ||
|
|
638f64b888 | ||
|
|
ffff9c1529 | ||
|
|
39968c7c6e | ||
|
|
2c3edf0ff2 | ||
|
|
2c4445a2d9 | ||
|
|
09114a5ed3 | ||
|
|
22e7825d65 | ||
|
|
62862141a8 | ||
|
|
920461920c | ||
|
|
f5d0e93ecd | ||
|
|
952a2f536b | ||
|
|
fbb9d849b4 | ||
|
|
65a13dee68 | ||
|
|
09d26b37c7 | ||
|
|
47de6905df | ||
|
|
c0cf316c16 | ||
|
|
c055f8069d | ||
|
|
575356214f | ||
|
|
4b5dc4152a | ||
|
|
a023409fe9 | ||
|
|
d36c59658d | ||
|
|
4f832ee70b | ||
|
|
7b97097515 | ||
|
|
86b3cb8d5d | ||
|
|
33e007ad48 | ||
|
|
efea9f0857 | ||
|
|
aa755a0093 | ||
|
|
807e80acbe | ||
|
|
4096247ee8 | ||
|
|
782d09ddbc | ||
|
|
4c304e11f3 | ||
|
|
aee497de03 | ||
|
|
823f8614e5 | ||
|
|
b54afb8823 | ||
|
|
22e611c63b | ||
|
|
3deb01a65d | ||
|
|
6f24b0bb71 | ||
|
|
9d7921f538 | ||
|
|
a4e66b3d11 | ||
|
|
3866ff76f9 | ||
|
|
82f947abdd | ||
|
|
47c6f53b43 | ||
|
|
606657524e | ||
|
|
168285944c | ||
|
|
1746af927b | ||
|
|
2eca8ffba2 | ||
|
|
6ef0c06a19 | ||
|
|
af68f1a16e | ||
|
|
f429839a17 | ||
|
|
66770e602a | ||
|
|
f760131cf5 | ||
|
|
cdc1d5064f | ||
|
|
3b707d29b9 | ||
|
|
df632bb1f0 | ||
|
|
74cb453995 | ||
|
|
f8eec94b04 | ||
|
|
697efacc58 | ||
|
|
ff9cff8f44 | ||
|
|
d78388646d | ||
|
|
05ffcdeef7 | ||
|
|
3b8e347a9e | ||
|
|
37f160f698 | ||
|
|
6f1446339c | ||
|
|
fed44dc366 | ||
|
|
c71ec34998 | ||
|
|
157bda8f51 | ||
|
|
d80e5bc792 | ||
|
|
f9669e8158 | ||
|
|
04c83c608b | ||
|
|
9f50037e11 | ||
|
|
33fd741ba7 | ||
|
|
035c3f9319 | ||
|
|
3df922340d | ||
|
|
72b9190e2f | ||
|
|
8fe1bdf39a | ||
|
|
f78bf2bc8a | ||
|
|
a1f0a69874 | ||
|
|
8a26b2f433 | ||
|
|
a18784d2c7 | ||
|
|
3c25a987fd | ||
|
|
7cebc4ef42 | ||
|
|
a8ab46d5c8 | ||
|
|
8bac5a8c54 | ||
|
|
801a41ae10 | ||
|
|
47e37afe12 | ||
|
|
942bf7d8cb | ||
|
|
0e8d573819 | ||
|
|
2bdfd7401e | ||
|
|
68dd6b1e23 | ||
|
|
2fe85ae0e5 | ||
|
|
e9fa1c3b5e | ||
|
|
f543b83cfc | ||
|
|
2d917ca11a | ||
|
|
2c830627ef | ||
|
|
46003a3509 | ||
|
|
6b0412586e | ||
|
|
36ca7ffbdb | ||
|
|
e5244f1fec | ||
|
|
359a7272e8 | ||
|
|
82cd3a7e56 | ||
|
|
a2e78fd08a | ||
|
|
a48b5e9d65 | ||
|
|
f4c4d9ea8c | ||
|
|
02ed45fa61 | ||
|
|
ad227ea2ee | ||
|
|
d7e2358d3e | ||
|
|
196e98e4a7 | ||
|
|
00bc45fba1 | ||
|
|
62c0d3f07f | ||
|
|
d42574a16c | ||
|
|
a854b04293 | ||
|
|
96632da4d7 | ||
|
|
cf18d6b1e9 | ||
|
|
262e2e1b85 | ||
|
|
743c46de70 | ||
|
|
9624bc96c9 | ||
|
|
1643bb7d59 | ||
|
|
edad5a838f | ||
|
|
fb35226e20 | ||
|
|
40605737b1 | ||
|
|
01a62e099e | ||
|
|
80748bb66b | ||
|
|
c6c77e9bc4 | ||
|
|
1f462648c4 | ||
|
|
099256e5d4 | ||
|
|
8735d24122 | ||
|
|
b2fc3967d3 | ||
|
|
0ec02cfa56 | ||
|
|
ade36d6876 | ||
|
|
73313d7dae | ||
|
|
7db9865ffa | ||
|
|
40656cb70b | ||
|
|
b5a07f3e79 | ||
|
|
66877ce9b1 | ||
|
|
57b067b4e2 | ||
|
|
74999e9394 | ||
|
|
f4d6f1e5ee | ||
|
|
096f670eb3 | ||
|
|
bceaca49bf | ||
|
|
5e94c84516 | ||
|
|
28dc14e739 | ||
|
|
d5d28e80cb | ||
|
|
f1eea76249 | ||
|
|
0976404eda | ||
|
|
8074c9a7c6 | ||
|
|
513af43fca | ||
|
|
afd5d76992 | ||
|
|
a31da5f880 | ||
|
|
be470f50ec | ||
|
|
a04494346e | ||
|
|
797533459e | ||
|
|
22e879ef18 | ||
|
|
dc6bc5b4d6 | ||
|
|
a6c7457c59 | ||
|
|
b609cfba2a | ||
|
|
345980f457 | ||
|
|
5a86a0a8cb | ||
|
|
24c1ce3f4a | ||
|
|
fc65c2583e | ||
|
|
1df3c33f69 | ||
|
|
98a9cc7436 | ||
|
|
ff88d4649c | ||
|
|
8c61306a8d | ||
|
|
6496e34868 | ||
|
|
7d6c9d517c | ||
|
|
d918d8ffd1 | ||
|
|
ca61ea09d0 | ||
|
|
faff230d42 | ||
|
|
c288c3d071 | ||
|
|
500a22b0b6 | ||
|
|
ba1317d245 | ||
|
|
5cfbfc5071 | ||
|
|
bf4b9d5355 | ||
|
|
904f0bc202 | ||
|
|
94c546bd0f | ||
|
|
64f1e10a5e | ||
|
|
8b20da78ff | ||
|
|
1be4ef437d | ||
|
|
76da9c3247 | ||
|
|
1e4dcc23d7 | ||
|
|
9c95e7fd96 | ||
|
|
cea5f57c60 | ||
|
|
19e6d37b62 | ||
|
|
018979d17f | ||
|
|
8bd398cbd6 | ||
|
|
59872b14cf | ||
|
|
c5240d72e1 | ||
|
|
77b54f9a10 | ||
|
|
b5bcb5b3bb | ||
|
|
87c500138b | ||
|
|
f3f384ebcc | ||
|
|
08de2eacd6 | ||
|
|
b763d968fe | ||
|
|
3b05eba2e2 | ||
|
|
b6d2c72a40 | ||
|
|
e6d2c9791d | ||
|
|
91a0eeb29a | ||
|
|
8c9c4865f2 | ||
|
|
6fbd4a7c88 | ||
|
|
239adaa129 | ||
|
|
9f8c82b649 | ||
|
|
7875bb6ebd | ||
|
|
a33abf3f56 | ||
|
|
1fadadcdb5 | ||
|
|
a294dec0dc | ||
|
|
5de75e6a8a | ||
|
|
4b44be2e54 | ||
|
|
b5f1d63175 | ||
|
|
1c5695df7e | ||
|
|
1808ad9ad7 | ||
|
|
8dc5e81374 | ||
|
|
b899056a8e | ||
|
|
f884c47ad8 | ||
|
|
07eae639b6 | ||
|
|
d2349bd713 | ||
|
|
28ee3c6e8f | ||
|
|
4430f269f7 | ||
|
|
a72f7d63f6 | ||
|
|
859b6f8ac5 | ||
|
|
a7f238aba3 | ||
|
|
e0cff27aae | ||
|
|
d9c4a6ec76 | ||
|
|
4d95bc4255 | ||
|
|
fdea0144b0 | ||
|
|
7398a373c2 | ||
|
|
c88e45cde8 | ||
|
|
f77848e3d9 | ||
|
|
5ed78cc3b6 | ||
|
|
1b4593bb62 | ||
|
|
c620e26644 | ||
|
|
74af24c3db | ||
|
|
ac1f32f773 | ||
|
|
99c7dbb332 | ||
|
|
b0632b8910 | ||
|
|
d26a9615c0 | ||
|
|
f609d6e0b2 | ||
|
|
e5042712b6 | ||
|
|
bf93d3af04 | ||
|
|
ea43abe392 | ||
|
|
0e74314ddc | ||
|
|
54eabd6a74 | ||
|
|
2f52473566 | ||
|
|
98e7250b3c | ||
|
|
882438f5e0 | ||
|
|
bb93dddd39 | ||
|
|
59f6a8a933 | ||
|
|
8ce83f3cd0 | ||
|
|
745e402da9 | ||
|
|
6cbe1c92d5 | ||
|
|
54fc2fb4c6 | ||
|
|
adc2815ab5 | ||
|
|
75f9f647ee | ||
|
|
f14f7dbb72 | ||
|
|
4978618e9a | ||
|
|
59b9f4f15b | ||
|
|
7ff0ce5369 | ||
|
|
93bd278819 | ||
|
|
b97b1f3690 | ||
|
|
307f374be1 | ||
|
|
17f701824e | ||
|
|
c7b89dcf71 | ||
|
|
fc527a947f | ||
|
|
d0520690a2 | ||
|
|
315d020b6f | ||
|
|
8a4bcdef52 | ||
|
|
727ef34c6d | ||
|
|
d8bc06d05d | ||
|
|
def214dde2 | ||
|
|
219f948c4a | ||
|
|
72193eccf0 | ||
|
|
7eb85c6a3d | ||
|
|
954c667173 | ||
|
|
33c738df5f | ||
|
|
2141fe298f | ||
|
|
8e73f512b4 | ||
|
|
92dddb8fd8 | ||
|
|
e9869f4c88 | ||
|
|
52597d4dcb | ||
|
|
dc7ce27b81 | ||
|
|
4242595a66 | ||
|
|
50b9a11503 | ||
|
|
621a723602 | ||
|
|
6260cc3655 | ||
|
|
300e668327 | ||
|
|
3cf274c37a | ||
|
|
2ca356ee5c | ||
|
|
ca8751c40c | ||
|
|
3c7e97d2d9 | ||
|
|
dbe2d690da | ||
|
|
949410e2cc | ||
|
|
100f856b5f | ||
|
|
d7bee01454 | ||
|
|
5566081986 | ||
|
|
29f7dd93f3 | ||
|
|
3dd8db5728 | ||
|
|
17e70d11f5 | ||
|
|
f8afd439b2 | ||
|
|
0dc61b1c26 | ||
|
|
de6c4fcb17 | ||
|
|
57f5c854ff | ||
|
|
4f4523ab77 | ||
|
|
e34e632519 | ||
|
|
f810b902a6 | ||
|
|
fd5bdc1484 | ||
|
|
e3a12ae6c5 | ||
|
|
c9c5664ec6 | ||
|
|
75cff549ce | ||
|
|
885cb6915d | ||
|
|
f9396a4ecf | ||
|
|
f1a03329e5 | ||
|
|
f65be671a3 | ||
|
|
fa9e8f6cba | ||
|
|
67a3e76cfe | ||
|
|
e4569c0bb8 | ||
|
|
6f1a62e917 | ||
|
|
3f6e21f15a | ||
|
|
46c4287c67 | ||
|
|
1ea1826a27 | ||
|
|
151457daf0 | ||
|
|
38cc21fa3a | ||
|
|
77f759f258 | ||
|
|
07c04061c2 | ||
|
|
d4bf6ed0c8 | ||
|
|
ebd46efe81 | ||
|
|
24d193efb0 | ||
|
|
3b2a63178f | ||
|
|
78f60afb85 | ||
|
|
52a7957789 | ||
|
|
6870583b1c | ||
|
|
9ffe514350 | ||
|
|
fc6e04497a | ||
|
|
cfb3f9a3ca | ||
|
|
d47fac791e | ||
|
|
490b70c2d3 | ||
|
|
3eecdd9ada | ||
|
|
7bdbc5417c | ||
|
|
2cd07dcb72 | ||
|
|
adb83ade67 | ||
|
|
a90f5da8b0 | ||
|
|
38937a4f83 | ||
|
|
31f35a23ee | ||
|
|
74de010d3c | ||
|
|
a9e4c880df | ||
|
|
b7fe265604 | ||
|
|
25c4af5a9f | ||
|
|
b3ecf702e1 | ||
|
|
c34a3cc7e7 | ||
|
|
158783f2d1 | ||
|
|
624192d301 | ||
|
|
e9be139ed0 | ||
|
|
2b9195ed9c | ||
|
|
dfdfecba57 | ||
|
|
2d6fec13fb | ||
|
|
216f340468 | ||
|
|
a4211a7e55 | ||
|
|
d6a2488fde | ||
|
|
d4d60439b6 | ||
|
|
75edd0d8ef | ||
|
|
b4e6e21094 | ||
|
|
8c48bc926e | ||
|
|
031b6fb30d | ||
|
|
647542e462 | ||
|
|
dbf28d83f3 | ||
|
|
142acdd42f | ||
|
|
ce103d30d3 | ||
|
|
556d65e8b4 | ||
|
|
e0cf070bd0 | ||
|
|
70c5a336c2 | ||
|
|
f82d5fbd2d | ||
|
|
67dfd6b036 | ||
|
|
162eb0c958 | ||
|
|
a2dcc42f68 | ||
|
|
6b7f6dcb19 | ||
|
|
066e783a37 | ||
|
|
3e1bf001c7 | ||
|
|
722e18c07d | ||
|
|
a66ec00587 | ||
|
|
2b5100c019 | ||
|
|
74da05e6e8 | ||
|
|
af24e3b284 | ||
|
|
fb68d0bff3 | ||
|
|
d3a2ba26ba | ||
|
|
2f70ec5cb6 | ||
|
|
9173e9e56a | ||
|
|
11ad8a8398 | ||
|
|
0d518e44c7 | ||
|
|
7d8a5a2bdf |
130
.github/workflows/build-x86_64.yml
vendored
Normal file
130
.github/workflows/build-x86_64.yml
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
name: Build x86_64
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v1.77.3-dev
|
||||
|
||||
jobs:
|
||||
Build-Debug-MSI:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
with:
|
||||
vs-version: '17.12.4'
|
||||
|
||||
- name: 03. Restore nuget packages for solution
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: 04. Compile mRemoteNG
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Debug Installer" -p:Platform=x64 /verbosity:normal
|
||||
|
||||
- name: 05. Publish MSI as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debug-msi-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNGInstaller\Installer\bin\x64\Debug\en-US\
|
||||
if-no-files-found: error
|
||||
|
||||
Build-Debug-Portable:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
with:
|
||||
vs-version: '17.8.3'
|
||||
|
||||
- name: 03. Restore nuget packages for solution
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: 04. Compile mRemoteNG
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Debug Portable" -p:Platform=x64 /verbosity:normal
|
||||
|
||||
- name: 05. Publish Portable Binary as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debug-portable-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNG\bin\x64\Debug Portable\
|
||||
if-no-files-found: error
|
||||
|
||||
Build-Release:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
with:
|
||||
vs-version: '17.12.4'
|
||||
|
||||
- name: 03. Restore nuget packages for solution
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: 04. Compile mRemoteNG
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Release Installer and Portable" -p:Platform=x64 /verbosity:normal
|
||||
|
||||
- name: 05. Publish MSI Binary as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-msi-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNGInstaller\Installer\bin\x64\Release\en-US\
|
||||
if-no-files-found: error
|
||||
|
||||
- name: 06. Publish Portable Binary as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-portable-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNG\bin\x64\Release
|
||||
if-no-files-found: error
|
||||
|
||||
Create-Release:
|
||||
needs: [Build-Debug-MSI, Build-Debug-Portable, Build-Release]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: 03. Create compressed archives # Needs to be done because "actions/download-artifact@v4" is extracting the zipped Artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
zip -r debug-msi-x86_64.zip debug-msi-x86_64/
|
||||
zip -r debug-portable-x86_64.zip debug-portable-x86_64/
|
||||
zip -r release-msi-x86_64.zip release-msi-x86_64/
|
||||
zip -r release-portable-x86_64.zip release-portable-x86_64/
|
||||
|
||||
- name: 04. Create Release
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release create "v1.77.3-dev-${GITHUB_RUN_NUMBER}" \
|
||||
--title "v1.77.3-dev-${GITHUB_RUN_NUMBER}" \
|
||||
--prerelease \
|
||||
--generate-notes \
|
||||
$GITHUB_WORKSPACE/debug-msi-x86_64.zip \
|
||||
$GITHUB_WORKSPACE/debug-portable-x86_64.zip \
|
||||
$GITHUB_WORKSPACE/release-msi-x86_64.zip \
|
||||
$GITHUB_WORKSPACE/release-portable-x86_64.zip
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -283,6 +283,6 @@ Installer Projects/Installer/Fragments/HelpFilesFragment.wxs
|
||||
InstallerProjects/Installer/Fragments/FilesFragment.wxs
|
||||
InstallerProjects/Installer/Resources/License.rtf
|
||||
|
||||
# gh-pages info
|
||||
runlocal.bat
|
||||
/_site
|
||||
# mRemoteNG
|
||||
**/mRemoteNG/Properties/AssemblyInfo.tt
|
||||
**/mRemoteNG/Properties/AssemblyInfo.cs
|
||||
14
.readthedocs.yaml
Normal file
14
.readthedocs.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: mRemoteNGDocumentation/conf.py
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF
|
||||
formats:
|
||||
- pdf
|
||||
11
Add-ons/README.md
Normal file
11
Add-ons/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## Add-ons library by 3rd party
|
||||
This is a list of add-ons, plugins and extentions what could be used with mRemoteNG, if you wish to add yours to this list - just drop me a line: <a href="mailto:support@mremoteng.org">support@mremoteng.org</a>
|
||||
<br>
|
||||
|
||||
| <b>Date added</b> | <b>Author</b> | <b>Type</b> | <b>Name</b> | <b>Description</b> | <b>Repository</b> |
|
||||
| :---------------------------------------------------------:|:-------------------------------------------------:| :---------: |-------------|--------------------|:-----------------:|
|
||||
| 02-08-2022 | <a href="https://github.com/JustBeta"><img align="left" src="https://avatars.githubusercontent.com/u/25150896?v=4" alt="JustBeta" width="30px"/>JustBeta</a> | script | Export-MobaXterm2mRemoteNG | Conversion of MobaXterm's ini file to mRemoteNG format. | [GITHUB Repository](https://github.com/JustBeta/Export-MobaXtern2mRemoteNG/tree/main) |
|
||||
|
||||
<br>
|
||||
|
||||
For a detailed usage examples and documentation please reach out authors.
|
||||
67
CHANGELOG.md
67
CHANGELOG.md
@@ -2,36 +2,91 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
## [1.77.3.1784]
|
||||
### Fixed
|
||||
- #2362: Fix use of sql database
|
||||
- #2356: Improve speed for the display of the options page
|
||||
- #2352: SSH.NET Update
|
||||
- #2346: Modify "auto reconnect" to have the ability to really auto-reconnect
|
||||
- #2340: Set the default theme setting
|
||||
- #2339: Add 2 missing settings
|
||||
- #2261: Implement Show/Hide file menu in view menu
|
||||
- #2244: Save RCG and RestrictedAdmin fields correctly in connections file
|
||||
- #2195: Fix crafted XML File Code Execution vulnerability
|
||||
- #304: use pwfile instead of cleartext password for puttyng
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- #1427: Fix RDP local desktop scale not taking effect on remote
|
||||
- #2285: Support extraction of SSH private keys from external cred prov
|
||||
- #2268: Postregsql database support
|
||||
|
||||
### Updated
|
||||
- #2295: Updates hyperlink style to make links more visible to end users
|
||||
- #2337: Set language.resx to auto generate the designer class
|
||||
|
||||
## [1.77.3]
|
||||
### Added
|
||||
- #1736: Update of SSH.NET to 2020.0.2 to allow File Transfer again
|
||||
- #2138: Improve compatibility with Remote Desktop Connection Manager v2.83
|
||||
- #2123: Thycotic Secret Server - Added 2FA OTP support
|
||||
### Changed
|
||||
- #1546: Enable resize without reconnect for RDP Version Rdc9 or higher
|
||||
|
||||
## [1.77.2]
|
||||
### Added
|
||||
- #2086: Replace WebClient with async HttpClient for updater.
|
||||
- #1850: Minify config xml
|
||||
- #1770: Added missing RDP performance settings
|
||||
- #1516: added API to access credential vault (Thycotic Secret Server) by specifying SSAPI:ID as username
|
||||
- #1476: Configurable backups. Can now edit/set backup frequency, backup path, and max number of backup files.
|
||||
- #1427: Fix RDP local desktop scale not taking effect on remote
|
||||
- #1332: Added option to hide menu strip container
|
||||
- #870: Added option to push inheritance settings to child nodes recursively
|
||||
- #545: Option to minimize to system tray on closing
|
||||
- #503: SSH Execute a single command after login
|
||||
- #420: SSH tunneling implemented
|
||||
- #327: Added Alternative Shell for RDP settings
|
||||
- #319: Override quick connect username when using user@domain
|
||||
- #283: Support for native PowerShell remoting as new protocol
|
||||
- #1850: Minify config xml
|
||||
- #xxx: Add external connector to retrieve ip address from Amazon EC2 Instance IDs
|
||||
### Changed
|
||||
- #2102: Extended the field RenderingEngine from 10 chars to 16
|
||||
- #2022: Replaced CefSharp with WebView2
|
||||
- #2014: Revised icons
|
||||
- #2013: Removed components check
|
||||
- #2011: Removed screenshot manager
|
||||
- #2010: Redesigned menus
|
||||
- #2005: Removed in-app documentation
|
||||
- #1777: Cleaned up VisualStudio project structure
|
||||
- #1767: Turned about window into a simple popup form
|
||||
- #1766: Converted components check page into options page
|
||||
- #1690: Replaced GeckoFX (Firefox) with CefSharp (Chromium)
|
||||
- #1325: Language resource files cleanup
|
||||
- #xxxx: Secret Server connector via new field "API User ID" instead of SSAPI: prefix
|
||||
### Fixed
|
||||
- #2125: Fixed string parsing logic for Quick Connect toolbar.
|
||||
- #2122: Fix to avoid throwing exception incase if not able decrypt connections and ask to open another one or create a new.
|
||||
- #2117: Fix of broken Links due migration to .NET 6 and branch renaming
|
||||
- #2098: Fix failed BinaryFileTest
|
||||
- #2097: Fix failed tests related to mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
- #2096: Corrected encryption code of LegacyRijndaelCryptographyProvider
|
||||
- #2089: Fixed the exception thrown by menu buttons "Documentation" and "Website"
|
||||
- #2087: Fixed application crash, when the update file is launched from the application
|
||||
- #2079: Fixed theme files not being copied to output directory
|
||||
- #2012: Updated PuTTYNG to v0.76
|
||||
- #1884: Allow setting Port when using MSSQL
|
||||
- #1783: Added missing inheritance properties to SQL scripts
|
||||
- #1773: Connection issue with mysql - Missing fields in
|
||||
- #1773: Connection issue with MySql - Missing fields in
|
||||
- #1756: Cannot type any character on MultiSSH toolbar
|
||||
- #1720: Show configuration file name in title of password prompt form
|
||||
- #1713: Sound redirection does not work if Clipboard redirection is set to No
|
||||
- #1632: 1.77.1 breaks RDP drive and sound redirection
|
||||
- #1610: Menu bar changes to english when cancelling options form
|
||||
- #1610: Menu bar changes to English when canceling options form
|
||||
- #1595: Unhandled exception when trying to browse through non existent multi ssh history with keyboard key strokes
|
||||
- #1589: Update SQL tables instead of rewriting them
|
||||
- #1465: REGRESSION: Smart Cards redirection to Remote Desktop not working
|
||||
- #1363: Don't show "Disk Usage" button in installer
|
||||
- #1337: Unhandled exception after closing mRemoteNG
|
||||
- #359: Making a VNC connection to an unreachable host causes the application to not respond for 20-30 seconds
|
||||
- #618: Do not break the Windows Clipboard Chain when exiting.
|
||||
|
||||
## [1.77.1] - 2019-09-02
|
||||
### Added
|
||||
|
||||
@@ -278,62 +278,3 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
180
ExternalConnectors/AWS/AWSConnectionForm.Designer.cs
generated
Normal file
180
ExternalConnectors/AWS/AWSConnectionForm.Designer.cs
generated
Normal file
@@ -0,0 +1,180 @@
|
||||
namespace ExternalConnectors.AWS
|
||||
{
|
||||
partial class AWSConnectionForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.tbAccesKeyID = new System.Windows.Forms.TextBox();
|
||||
this.tbAccesKey = new System.Windows.Forms.TextBox();
|
||||
this.btnOK = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tbAccesKeyID
|
||||
//
|
||||
this.tbAccesKeyID.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tbAccesKeyID.Location = new System.Drawing.Point(152, 4);
|
||||
this.tbAccesKeyID.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.tbAccesKeyID.Name = "tbAccesKeyID";
|
||||
this.tbAccesKeyID.Size = new System.Drawing.Size(490, 23);
|
||||
this.tbAccesKeyID.TabIndex = 0;
|
||||
//
|
||||
// tbAccesKey
|
||||
//
|
||||
this.tbAccesKey.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tbAccesKey.Location = new System.Drawing.Point(152, 43);
|
||||
this.tbAccesKey.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.tbAccesKey.Name = "tbAccesKey";
|
||||
this.tbAccesKey.Size = new System.Drawing.Size(490, 23);
|
||||
this.tbAccesKey.TabIndex = 2;
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
this.btnOK.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnOK.Location = new System.Drawing.Point(219, 12);
|
||||
this.btnOK.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.btnOK.Name = "btnOK";
|
||||
this.btnOK.Size = new System.Drawing.Size(88, 26);
|
||||
this.btnOK.TabIndex = 10;
|
||||
this.btnOK.Text = "OK";
|
||||
this.btnOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(338, 12);
|
||||
this.btnCancel.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(88, 26);
|
||||
this.btnCancel.TabIndex = 11;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 22.92994F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 77.07006F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label2, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tbAccesKeyID, 1, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tbAccesKey, 1, 1);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 3;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(646, 102);
|
||||
this.tableLayoutPanel1.TabIndex = 12;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label1.Location = new System.Drawing.Point(4, 0);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(140, 39);
|
||||
this.label1.TabIndex = 2;
|
||||
this.label1.Text = "Access Key ID";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label2.Location = new System.Drawing.Point(4, 39);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(140, 39);
|
||||
this.label2.TabIndex = 4;
|
||||
this.label2.Text = "Access Key";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 5;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 93F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 23F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 93F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.btnOK, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.btnCancel, 3, 0);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 112);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 1;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(646, 50);
|
||||
this.tableLayoutPanel2.TabIndex = 13;
|
||||
//
|
||||
// AWSConnectionForm
|
||||
//
|
||||
this.AcceptButton = this.btnOK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(646, 162);
|
||||
this.Controls.Add(this.tableLayoutPanel2);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
|
||||
this.Name = "AWSConnectionForm";
|
||||
this.Text = "AWS EC2 API Login Data";
|
||||
this.Activated += new System.EventHandler(this.AWSConnectionForm_Activated);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public System.Windows.Forms.TextBox tbAccesKeyID;
|
||||
public System.Windows.Forms.TextBox tbAccesKey;
|
||||
private System.Windows.Forms.Button btnOK;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
}
|
||||
}
|
||||
16
ExternalConnectors/AWS/AWSConnectionForm.cs
Normal file
16
ExternalConnectors/AWS/AWSConnectionForm.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace ExternalConnectors.AWS
|
||||
{
|
||||
public partial class AWSConnectionForm : Form
|
||||
{
|
||||
public AWSConnectionForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
}
|
||||
|
||||
private void AWSConnectionForm_Activated(object sender, EventArgs e)
|
||||
{
|
||||
tbAccesKeyID.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
ExternalConnectors/AWS/AWSConnectionForm.resx
Normal file
60
ExternalConnectors/AWS/AWSConnectionForm.resx
Normal file
@@ -0,0 +1,60 @@
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
119
ExternalConnectors/AWS/EC2FetchDataService.cs
Normal file
119
ExternalConnectors/AWS/EC2FetchDataService.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using Amazon;
|
||||
using Amazon.EC2;
|
||||
using Amazon.EC2.Model;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace ExternalConnectors.AWS
|
||||
{
|
||||
public class EC2FetchDataService
|
||||
{
|
||||
private static DateTime lastFetch;
|
||||
private static List<InstanceInfo>? lastData;
|
||||
|
||||
// input must be in format "AWSAPI:instanceid" where instanceid is the ec2 instance id, e.g. i-066f750a76c97583d
|
||||
public static async Task<string> GetEC2InstanceDataAsync(string input, string region)
|
||||
{
|
||||
// get secret id
|
||||
if (!input.StartsWith("AWSAPI:"))
|
||||
throw new Exception("calling this function requires AWSAPI: input");
|
||||
string InstanceID = input[7..];
|
||||
|
||||
// init connection credentials, display popup if necessary
|
||||
AWSConnectionData.Init();
|
||||
var alldata = await GetEC2IPDataAsync(region);
|
||||
var found = alldata.Where(x => x.InstanceId == InstanceID).SingleOrDefault();
|
||||
return (found == null) ? "" : found.PublicIP;
|
||||
}
|
||||
|
||||
private static async Task<List<InstanceInfo>> GetEC2IPDataAsync(string region)
|
||||
{
|
||||
// caching
|
||||
TimeSpan timeSpan = DateTime.Now - lastFetch;
|
||||
if (timeSpan.TotalMinutes < 1 && lastData != null)
|
||||
return lastData;
|
||||
|
||||
//AWSConfigs.AWSRegion = AWSConnectionData.region;
|
||||
AWSConfigs.AWSRegion = region;
|
||||
string awsAccessKeyId = AWSConnectionData.awsKeyID;
|
||||
string awsSecretAccessKey = AWSConnectionData.awsKey;
|
||||
|
||||
var _client = new AmazonEC2Client(awsAccessKeyId, awsSecretAccessKey, RegionEndpoint.EUCentral1);
|
||||
bool done = false;
|
||||
|
||||
List<InstanceInfo> instanceList = new();
|
||||
var request = new DescribeInstancesRequest();
|
||||
while (!done)
|
||||
{
|
||||
DescribeInstancesResponse response = await _client.DescribeInstancesAsync(request);
|
||||
|
||||
foreach (var reservation in response.Reservations)
|
||||
{
|
||||
foreach (var instance in reservation.Instances)
|
||||
{
|
||||
string vmname = "";
|
||||
foreach (var tag in instance.Tags)
|
||||
{
|
||||
if (tag.Key == "Name")
|
||||
{
|
||||
vmname = tag.Value;
|
||||
}
|
||||
}
|
||||
InstanceInfo inf = new(instance, vmname);
|
||||
instanceList.Add(inf);
|
||||
}
|
||||
}
|
||||
|
||||
request.NextToken = response.NextToken;
|
||||
|
||||
if (response.NextToken == null)
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
lastData = instanceList.OrderBy(x => x.Name).ToList();
|
||||
lastFetch = DateTime.Now;
|
||||
return lastData;
|
||||
}
|
||||
|
||||
|
||||
public static class AWSConnectionData
|
||||
{
|
||||
private static readonly RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteAWSInterface");
|
||||
|
||||
public static string awsKeyID = "";
|
||||
public static string awsKey = "";
|
||||
//public static string _region = "eu-central-1";
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if (awsKey != "")
|
||||
return;
|
||||
// display gui and ask for data
|
||||
AWSConnectionForm f = new();
|
||||
f.tbAccesKeyID.Text = "" + key.GetValue("KeyID");
|
||||
f.tbAccesKey.Text = "" + key.GetValue("Key");
|
||||
//f.tbRegion.Text = "" + key.GetValue("Region");
|
||||
//if (f.tbRegion.Text == null || f.tbRegion.Text.Length < 2)
|
||||
// f.tbRegion.Text = region;
|
||||
_ = f.ShowDialog();
|
||||
|
||||
if (f.DialogResult != DialogResult.OK)
|
||||
return;
|
||||
|
||||
// store values to memory
|
||||
awsKeyID = f.tbAccesKeyID.Text;
|
||||
awsKey = f.tbAccesKey.Text;
|
||||
//region = f.tbRegion.Text;
|
||||
|
||||
|
||||
// write values to registry
|
||||
key.SetValue("KeyID", awsKeyID);
|
||||
key.SetValue("Key", awsKey);
|
||||
//key.SetValue("Region", region);
|
||||
key.Close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
34
ExternalConnectors/AWS/InstanceInfo.cs
Normal file
34
ExternalConnectors/AWS/InstanceInfo.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Amazon.EC2.Model;
|
||||
using System;
|
||||
|
||||
namespace ExternalConnectors.AWS
|
||||
{
|
||||
public class InstanceInfo
|
||||
{
|
||||
public string InstanceId { get; }
|
||||
public string Name { get; }
|
||||
public string Status { get; }
|
||||
public string PublicIP { get; }
|
||||
public string PrivateIP { get; }
|
||||
public InstanceInfo(Instance instance, string name)
|
||||
{
|
||||
InstanceId = instance.InstanceId;
|
||||
Name = name;
|
||||
|
||||
switch(instance.State.Code)
|
||||
{
|
||||
case 0: Status = "Pending"; break;
|
||||
case 16: Status = "Running"; break;
|
||||
case 32: Status = "Shutdown"; break;
|
||||
case 48: Status = "Terminated"; break;
|
||||
case 64: Status = "Stopping"; break;
|
||||
case 80: Status = "Stopped"; break;
|
||||
default: Status = "Unknown"; break;
|
||||
};
|
||||
|
||||
PublicIP = instance.PublicIpAddress ?? "";
|
||||
PrivateIP = instance.PrivateIpAddress ?? "";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
ExternalConnectors/CPS/CPS.ico
Normal file
BIN
ExternalConnectors/CPS/CPS.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
241
ExternalConnectors/CPS/CPSConnectionForm.Designer.cs
generated
Normal file
241
ExternalConnectors/CPS/CPSConnectionForm.Designer.cs
generated
Normal file
@@ -0,0 +1,241 @@
|
||||
namespace ExternalConnectors.CPS
|
||||
{
|
||||
partial class CPSConnectionForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CPSConnectionForm));
|
||||
tbServerURL = new TextBox();
|
||||
label3 = new Label();
|
||||
tbAPIKey = new TextBox();
|
||||
btnOK = new Button();
|
||||
btnCancel = new Button();
|
||||
tableLayoutPanel1 = new TableLayoutPanel();
|
||||
label1 = new Label();
|
||||
label6 = new Label();
|
||||
tbOTP = new TextBox();
|
||||
cbUseSSO = new CheckBox();
|
||||
tableLayoutPanel2 = new TableLayoutPanel();
|
||||
label4 = new Label();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
tableLayoutPanel2.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tbServerURL
|
||||
//
|
||||
tbServerURL.Dock = DockStyle.Fill;
|
||||
tbServerURL.Location = new Point(298, 5);
|
||||
tbServerURL.Margin = new Padding(5);
|
||||
tbServerURL.Name = "tbServerURL";
|
||||
tbServerURL.Size = new Size(611, 27);
|
||||
tbServerURL.TabIndex = 0;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
label3.AutoSize = true;
|
||||
label3.Dock = DockStyle.Fill;
|
||||
label3.Location = new Point(5, 84);
|
||||
label3.Margin = new Padding(5, 0, 5, 0);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(283, 42);
|
||||
label3.TabIndex = 5;
|
||||
label3.Text = "API Key";
|
||||
label3.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// tbAPIKey
|
||||
//
|
||||
tbAPIKey.Dock = DockStyle.Fill;
|
||||
tbAPIKey.Location = new Point(298, 89);
|
||||
tbAPIKey.Margin = new Padding(5);
|
||||
tbAPIKey.Name = "tbAPIKey";
|
||||
tbAPIKey.Size = new Size(611, 27);
|
||||
tbAPIKey.TabIndex = 4;
|
||||
tbAPIKey.UseSystemPasswordChar = true;
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
btnOK.Anchor = AnchorStyles.Right;
|
||||
btnOK.DialogResult = DialogResult.OK;
|
||||
btnOK.Location = new Point(337, 16);
|
||||
btnOK.Margin = new Padding(5);
|
||||
btnOK.Name = "btnOK";
|
||||
btnOK.Size = new Size(101, 35);
|
||||
btnOK.TabIndex = 6;
|
||||
btnOK.Text = "OK";
|
||||
btnOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
btnCancel.Anchor = AnchorStyles.Left;
|
||||
btnCancel.DialogResult = DialogResult.Cancel;
|
||||
btnCancel.Location = new Point(474, 16);
|
||||
btnCancel.Margin = new Padding(5);
|
||||
btnCancel.Name = "btnCancel";
|
||||
btnCancel.Size = new Size(101, 35);
|
||||
btnCancel.TabIndex = 11;
|
||||
btnCancel.Text = "Cancel";
|
||||
btnCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
tableLayoutPanel1.ColumnCount = 2;
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 32.06997F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 67.93003F));
|
||||
tableLayoutPanel1.Controls.Add(label1, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(label3, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(tbServerURL, 1, 0);
|
||||
tableLayoutPanel1.Controls.Add(tbAPIKey, 1, 2);
|
||||
tableLayoutPanel1.Controls.Add(label6, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(tbOTP, 1, 3);
|
||||
tableLayoutPanel1.Controls.Add(cbUseSSO, 0, 1);
|
||||
tableLayoutPanel1.Dock = DockStyle.Top;
|
||||
tableLayoutPanel1.Location = new Point(0, 0);
|
||||
tableLayoutPanel1.Margin = new Padding(5);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 5;
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
|
||||
tableLayoutPanel1.Size = new Size(914, 212);
|
||||
tableLayoutPanel1.TabIndex = 12;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
label1.AutoSize = true;
|
||||
label1.Dock = DockStyle.Fill;
|
||||
label1.Location = new Point(5, 0);
|
||||
label1.Margin = new Padding(5, 0, 5, 0);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new Size(283, 42);
|
||||
label1.TabIndex = 2;
|
||||
label1.Text = "Passwordstate URL";
|
||||
label1.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// label6
|
||||
//
|
||||
label6.AutoSize = true;
|
||||
label6.Dock = DockStyle.Fill;
|
||||
label6.Location = new Point(3, 126);
|
||||
label6.Name = "label6";
|
||||
label6.Size = new Size(287, 42);
|
||||
label6.TabIndex = 15;
|
||||
label6.Text = "2FA OTP (Optional)";
|
||||
//
|
||||
// tbOTP
|
||||
//
|
||||
tbOTP.Dock = DockStyle.Fill;
|
||||
tbOTP.Location = new Point(298, 131);
|
||||
tbOTP.Margin = new Padding(5);
|
||||
tbOTP.Name = "tbOTP";
|
||||
tbOTP.Size = new Size(611, 27);
|
||||
tbOTP.TabIndex = 5;
|
||||
//
|
||||
// cbUseSSO
|
||||
//
|
||||
cbUseSSO.Anchor = AnchorStyles.Left;
|
||||
cbUseSSO.AutoSize = true;
|
||||
cbUseSSO.Location = new Point(5, 53);
|
||||
cbUseSSO.Margin = new Padding(5, 5, 5, 0);
|
||||
cbUseSSO.Name = "cbUseSSO";
|
||||
cbUseSSO.Size = new Size(157, 24);
|
||||
cbUseSSO.TabIndex = 14;
|
||||
cbUseSSO.Text = "Use SSO / WinAuth";
|
||||
cbUseSSO.UseVisualStyleBackColor = true;
|
||||
cbUseSSO.CheckedChanged += cbUseSSO_CheckedChanged;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
tableLayoutPanel2.ColumnCount = 5;
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 106F));
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 26F));
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 107F));
|
||||
tableLayoutPanel2.Controls.Add(btnOK, 1, 0);
|
||||
tableLayoutPanel2.Controls.Add(btnCancel, 3, 0);
|
||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
||||
tableLayoutPanel2.Location = new Point(0, 300);
|
||||
tableLayoutPanel2.Margin = new Padding(5);
|
||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
tableLayoutPanel2.RowCount = 1;
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel2.Size = new Size(914, 67);
|
||||
tableLayoutPanel2.TabIndex = 13;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
label4.AutoSize = true;
|
||||
label4.Dock = DockStyle.Fill;
|
||||
label4.Location = new Point(0, 212);
|
||||
label4.Margin = new Padding(5, 0, 5, 0);
|
||||
label4.Name = "label4";
|
||||
label4.Size = new Size(345, 20);
|
||||
label4.TabIndex = 14;
|
||||
label4.Text = "URL is the base URL, like https://pass.domain.local/";
|
||||
label4.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// CPSConnectionForm
|
||||
//
|
||||
AcceptButton = btnOK;
|
||||
AutoScaleDimensions = new SizeF(8F, 20F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(914, 367);
|
||||
Controls.Add(label4);
|
||||
Controls.Add(tableLayoutPanel2);
|
||||
Controls.Add(tableLayoutPanel1);
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
Margin = new Padding(5);
|
||||
Name = "CPSConnectionForm";
|
||||
Text = "Passwordstate API Login Data";
|
||||
Activated += CPSConnectionForm_Activated;
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
tableLayoutPanel2.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.Label label3;
|
||||
|
||||
public System.Windows.Forms.TextBox tbServerURL;
|
||||
//public System.Windows.Forms.TextBox tbUsername;
|
||||
public System.Windows.Forms.TextBox tbAPIKey;
|
||||
private System.Windows.Forms.Button btnOK;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
public System.Windows.Forms.CheckBox cbUseSSO;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private Label label6;
|
||||
public TextBox tbOTP;
|
||||
}
|
||||
}
|
||||
41
ExternalConnectors/CPS/CPSConnectionForm.cs
Normal file
41
ExternalConnectors/CPS/CPSConnectionForm.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace ExternalConnectors.CPS
|
||||
{
|
||||
public partial class CPSConnectionForm : Form
|
||||
{
|
||||
public CPSConnectionForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void CPSConnectionForm_Activated(object sender, EventArgs e)
|
||||
{
|
||||
SetVisibility();
|
||||
if (cbUseSSO.Checked)
|
||||
btnOK.Focus();
|
||||
else
|
||||
{
|
||||
if (tbAPIKey.Text.Length == 0)
|
||||
tbAPIKey.Focus();
|
||||
else
|
||||
tbOTP.Focus();
|
||||
}
|
||||
|
||||
tbAPIKey.Focus();
|
||||
if (!string.IsNullOrEmpty(tbAPIKey.Text) || cbUseSSO.Checked == true)
|
||||
tbOTP.Focus();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void cbUseSSO_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetVisibility();
|
||||
}
|
||||
private void SetVisibility()
|
||||
{
|
||||
bool ch = cbUseSSO.Checked;
|
||||
tbAPIKey.Enabled = !ch;
|
||||
//tbUsername.Enabled = !ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -117,35 +117,33 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="resultsMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="portScanToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>161, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAGxsbP9sbGz/EVuT/xRclP8XX5f/GmGZ/x1jm/8hZp7/JGig/yhro/8sbqb/MHGp/66u
|
||||
rv+3t7f/AAAAAAAAAAAAAAAAAAAAABVdlf90qNH/dqrS/3mr0/97rdT/fa/V/4Gy1v+Ds9f/hrbY/zZ1
|
||||
rf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZYJj/d6vT/1SVx/9Yl8j/W5rJ/1+dy/9ioM3/ZqLO/4u5
|
||||
2v88ebH/IGqqAiZqoJMbYpl3AAAAAAAAAAAAAAAAHmSc/3ut1P9Zmcn/XJvK/2CezP9koc3/Z6TP/3an
|
||||
yf+buMv/Tn+u/0OEv5t6qNL/MnKotwAAAAAAAAAAAAAAACNnn/9/sNX/XpzL/2KfzP9mos7/aaXP/4+u
|
||||
wP/bxK//682z/9y9o/+sr7b/UYzCvSJopBgAAAAAAAAAAAAAAAAoa6P/gbTX/1TC7f9bt+P/a6fQ/2+p
|
||||
0v/ezrz/9+PQ//Xcw//64cf/4cGm/WGCpCoAAAAAAAAAAAAAAAAAAAAALm+n/3y74P9L1P//X7rk/3Gr
|
||||
0v91rdT/8d3J//bizv/03MP/9t3E/+3Qtv/TpH4qAAAAAAAAAAAAAAAAAAAAADNzq/+Mutr/bavU/3Os
|
||||
0/93r9X/erLW/+LYy//46dr/9uPQ//jl0//qzLLr3bGNGQAAAAAAAAAAAAAAAAAAAAA5d6//j73c/3St
|
||||
1P95sNX/fLPX/4C22P+bwNX/49nN//Phzv/czcH/58KhSgAAAAAAAAAAAAAAAAAAAAAAAAAAP3y0/5TB
|
||||
3f96stb/frTX/4G32f+Futv/iL3c/4y/3f+oz+X/Y5XN/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEWA
|
||||
uP+ZxOD/gLbY/4O42v+Hu9v/ir7c/43A3v+Qwt//q9Hn/2eY0P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AABLhLz/ncfh/6DJ4v+iy+T/pc3k/6jP5f+q0ef/q9Po/67U6P9rm9P/AAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAUYjA/1WLw/9Zjsb/XJDI/2CTy/9jlc3/ZpfP/2ma0v9sm9P/bp3V/wAAAAAAAAAAAAAAAAAA
|
||||
AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAA
|
||||
AAAtLDAA+PDaAP///wD79ugA/PrzAPf39wBGRUkA7NacAM2WAAA3z6kA+Pz/AIKBgwD+//4A4sNtAHXe
|
||||
xAD8+vIAjuTOANOjHgDV6/4AJZf3APn5+QDw37IAIB8jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAA//+cQYABnEHgB5xB4ACcQeAAnEHgAJxB4AGcQeABnEHgAZxB4AOcQeAHnEHgB5xB4AecQeAH
|
||||
nEH//5xB//+cQQ==
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAgICAgICCQ4CAgIWAgIUAgICAgICAgkJAgICFhYWAAIIDwICAgICCQwCAhYWFgYCCAgIBwIC
|
||||
AgkJAgsWFhYWBQICCAgIAwIJCQIWFhYWAgICAgINCAgCAgICFhYCAgICAgICAgIRAgICAgICAgICAgIC
|
||||
AgICEwICAgICEhMTExMCAgITExMCAgICAgITExMTAhMTExMCAgICAgICAgICAhMTEwICAgIICAIJCQIC
|
||||
AgIKAgICAgIICAQCAgkJAgICAgICAgICCAgCAgICCQkCAgICAgICFQgBAgICAgwJAgICAgICAggIAgIC
|
||||
AgICEAkCAgICAgIIAgICAgICAgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
301
ExternalConnectors/CPS/PasswordstateInterface.cs
Normal file
301
ExternalConnectors/CPS/PasswordstateInterface.cs
Normal file
@@ -0,0 +1,301 @@
|
||||
using Microsoft.Win32;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.OpenSsl;
|
||||
using Org.BouncyCastle.Security;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace ExternalConnectors.CPS;
|
||||
|
||||
public class PasswordstateInterface
|
||||
{
|
||||
private static class CPSConnectionData
|
||||
{
|
||||
public static string ssUsername = "";
|
||||
public static string ssPassword = "";
|
||||
public static string ssUrl = "";
|
||||
public static string ssOTP = "";
|
||||
public static DateTime ssOTPTimeStampExpiration;
|
||||
|
||||
public static bool ssSSO = false;
|
||||
public static bool initdone = false;
|
||||
|
||||
//token
|
||||
//public static string ssTokenBearer = "";
|
||||
//public static DateTime ssTokenExpiresOn = DateTime.UtcNow;
|
||||
//public static string ssTokenRefresh = "";
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
// 2024-05-04 passwordstate currently does not support auth tokens, so we need to re-enter otp codes frequently
|
||||
if (!string.IsNullOrEmpty(ssOTP) && DateTime.Now > ssOTPTimeStampExpiration)
|
||||
{
|
||||
ssOTP = "";
|
||||
initdone = false;
|
||||
}
|
||||
|
||||
if (initdone == true)
|
||||
return;
|
||||
|
||||
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteCPSInterface");
|
||||
try
|
||||
{
|
||||
// display gui and ask for data
|
||||
CPSConnectionForm f = new CPSConnectionForm();
|
||||
//string? un = key.GetValue("Username") as string;
|
||||
//f.tbUsername.Text = un ?? "";
|
||||
f.tbAPIKey.Text = CPSConnectionData.ssPassword; // in OTP refresh cases, this value might already be filled
|
||||
|
||||
string? url = key.GetValue("URL") as string;
|
||||
if (url == null || !url.Contains("://"))
|
||||
url = "https://cred.domain.local/SecretServer";
|
||||
f.tbServerURL.Text = url;
|
||||
|
||||
var b = key.GetValue("SSO");
|
||||
if (b == null || (string)b != "True")
|
||||
ssSSO = false;
|
||||
else
|
||||
ssSSO = true;
|
||||
f.cbUseSSO.Checked = ssSSO;
|
||||
|
||||
// show dialog
|
||||
while (true)
|
||||
{
|
||||
_ = f.ShowDialog();
|
||||
|
||||
if (f.DialogResult != DialogResult.OK)
|
||||
return;
|
||||
|
||||
// store values to memory
|
||||
//ssUsername = f.tbUsername.Text;
|
||||
ssPassword = f.tbAPIKey.Text;
|
||||
ssUrl = f.tbServerURL.Text;
|
||||
ssSSO = f.cbUseSSO.Checked;
|
||||
ssOTP = f.tbOTP.Text;
|
||||
ssOTPTimeStampExpiration = DateTime.Now.AddSeconds(30);
|
||||
// check connection first
|
||||
try
|
||||
{
|
||||
if (TestCredentials() == true)
|
||||
{
|
||||
initdone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageBox.Show("Test Credentials failed - please check your credentials");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// write values to registry
|
||||
//key.SetValue("Username", ssUsername);
|
||||
key.SetValue("URL", ssUrl);
|
||||
key.SetValue("SSO", ssSSO);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
key.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TestCredentials()
|
||||
{
|
||||
return ConnectionTest();
|
||||
}
|
||||
private static bool ConnectionTest()
|
||||
{
|
||||
if (CPSConnectionData.ssSSO)
|
||||
{
|
||||
string url = $"{CPSConnectionData.ssUrl}/winapi/passwordlists/";
|
||||
|
||||
using HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
|
||||
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
|
||||
|
||||
var json = client.GetStringAsync(url).Result;
|
||||
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
|
||||
if (data == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
string url = $"{CPSConnectionData.ssUrl}/api/passwordlists/";
|
||||
using HttpClient client = new HttpClient();
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
|
||||
client.DefaultRequestHeaders.Add("APIKey", CPSConnectionData.ssPassword);
|
||||
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
|
||||
|
||||
var json = client.GetStringAsync(url).Result;
|
||||
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
|
||||
if (data == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonNode? FetchDataWinAuth(int secretID)
|
||||
{
|
||||
string url = $"{CPSConnectionData.ssUrl}/winapi/passwords/{secretID}";
|
||||
|
||||
using HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
|
||||
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
|
||||
|
||||
var json = client.GetStringAsync(url).Result;
|
||||
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
|
||||
if (data == null)
|
||||
return null;
|
||||
JsonNode? element = data[0];
|
||||
return element;
|
||||
}
|
||||
private static JsonNode? FetchDataAPIKeyAuth(int secretID)
|
||||
{
|
||||
string url = $"{CPSConnectionData.ssUrl}/api/passwords/{secretID}";
|
||||
|
||||
using HttpClient client = new HttpClient();
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
|
||||
client.DefaultRequestHeaders.Add("APIKey", CPSConnectionData.ssPassword);
|
||||
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
|
||||
|
||||
var json = client.GetStringAsync(url).Result;
|
||||
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
|
||||
if (data == null)
|
||||
return null;
|
||||
JsonNode? element = data[0];
|
||||
return element;
|
||||
}
|
||||
|
||||
private static void FetchSecret(int secretID, out string secretUsername, out string secretPassword, out string secretDomain, out string privatekey)
|
||||
{
|
||||
// clear return variables
|
||||
secretDomain = "";
|
||||
secretUsername = "";
|
||||
secretPassword = "";
|
||||
privatekey = "";
|
||||
string privatekeypassphrase = "";
|
||||
JsonNode? element = null;
|
||||
|
||||
if (CPSConnectionData.ssSSO)
|
||||
element = FetchDataWinAuth(secretID);
|
||||
else
|
||||
element = FetchDataAPIKeyAuth(secretID);
|
||||
|
||||
if (element == null)
|
||||
return;
|
||||
|
||||
var dom = element["Domain"];
|
||||
if (dom != null) secretDomain = dom.ToString();
|
||||
|
||||
var user = element["UserName"];
|
||||
if (user != null) secretUsername = user.ToString();
|
||||
|
||||
var pw = element["Password"];
|
||||
if (pw != null) secretPassword = pw.ToString();
|
||||
|
||||
var privkey = element["GenericField1"];
|
||||
if (privkey != null) privatekey = privkey.ToString();
|
||||
|
||||
var phrase = element["GenericField3"];
|
||||
if (phrase != null) privatekeypassphrase = phrase.ToString();
|
||||
|
||||
// need to decode the private key?
|
||||
if (!string.IsNullOrEmpty(privatekeypassphrase))
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = DecodePrivateKey(privatekey, privatekeypassphrase);
|
||||
privatekey = key;
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// conversion to putty format necessary?
|
||||
if (!string.IsNullOrEmpty(privatekey) && !privatekey.StartsWith("PuTTY-User-Key-File-2"))
|
||||
{
|
||||
try
|
||||
{
|
||||
RSACryptoServiceProvider key = ImportPrivateKey(privatekey);
|
||||
privatekey = PuttyKeyFileGenerator.ToPuttyPrivateKey(key);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region PUTTY KEY HANDLING
|
||||
// decode rsa private key with encryption password
|
||||
private static string DecodePrivateKey(string encryptedPrivateKey, string password)
|
||||
{
|
||||
TextReader textReader = new StringReader(encryptedPrivateKey);
|
||||
PemReader pemReader = new PemReader(textReader, new PasswordFinder(password));
|
||||
|
||||
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
|
||||
|
||||
TextWriter textWriter = new StringWriter();
|
||||
var pemWriter = new PemWriter(textWriter);
|
||||
pemWriter.WriteObject(keyPair.Private);
|
||||
pemWriter.Writer.Flush();
|
||||
|
||||
return ""+textWriter.ToString();
|
||||
}
|
||||
private class PasswordFinder : IPasswordFinder
|
||||
{
|
||||
private string password;
|
||||
|
||||
public PasswordFinder(string password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
public char[] GetPassword()
|
||||
{
|
||||
return password.ToCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
// read private key pem string to rsacryptoserviceprovider
|
||||
public static RSACryptoServiceProvider ImportPrivateKey(string pem)
|
||||
{
|
||||
PemReader pr = new PemReader(new StringReader(pem));
|
||||
AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
|
||||
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private);
|
||||
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
|
||||
rsa.ImportParameters(rsaParams);
|
||||
return rsa;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
// input: must be the secret id to fetch
|
||||
public static void FetchSecretFromServer(string secretID, out string username, out string password, out string domain, out string privatekey)
|
||||
{
|
||||
// get secret id
|
||||
int sid = Int32.Parse(secretID);
|
||||
|
||||
// init connection credentials, display popup if necessary
|
||||
CPSConnectionData.Init();
|
||||
|
||||
// get the secret
|
||||
FetchSecret(sid, out username, out password, out domain, out privatekey);
|
||||
}
|
||||
}
|
||||
BIN
ExternalConnectors/DSS/DSS.ico
Normal file
BIN
ExternalConnectors/DSS/DSS.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
281
ExternalConnectors/DSS/SSConnectionForm.Designer.cs
generated
Normal file
281
ExternalConnectors/DSS/SSConnectionForm.Designer.cs
generated
Normal file
@@ -0,0 +1,281 @@
|
||||
namespace ExternalConnectors.DSS
|
||||
{
|
||||
partial class SSConnectionForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SSConnectionForm));
|
||||
this.tbSSURL = new System.Windows.Forms.TextBox();
|
||||
this.tbUsername = new System.Windows.Forms.TextBox();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.tbPassword = new System.Windows.Forms.TextBox();
|
||||
this.btnOK = new System.Windows.Forms.Button();
|
||||
this.btnCancel = new System.Windows.Forms.Button();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.cbUseSSO = new System.Windows.Forms.CheckBox();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.tbOTP = new System.Windows.Forms.TextBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// tbSSURL
|
||||
//
|
||||
this.tbSSURL.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tbSSURL.Location = new System.Drawing.Point(298, 5);
|
||||
this.tbSSURL.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.tbSSURL.Name = "tbSSURL";
|
||||
this.tbSSURL.Size = new System.Drawing.Size(611, 27);
|
||||
this.tbSSURL.TabIndex = 0;
|
||||
//
|
||||
// tbUsername
|
||||
//
|
||||
this.tbUsername.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tbUsername.Location = new System.Drawing.Point(298, 47);
|
||||
this.tbUsername.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.tbUsername.Name = "tbUsername";
|
||||
this.tbUsername.Size = new System.Drawing.Size(611, 27);
|
||||
this.tbUsername.TabIndex = 2;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label3.Location = new System.Drawing.Point(5, 84);
|
||||
this.label3.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(283, 42);
|
||||
this.label3.TabIndex = 5;
|
||||
this.label3.Text = "Password";
|
||||
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// tbPassword
|
||||
//
|
||||
this.tbPassword.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tbPassword.Location = new System.Drawing.Point(298, 89);
|
||||
this.tbPassword.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.tbPassword.Name = "tbPassword";
|
||||
this.tbPassword.Size = new System.Drawing.Size(611, 27);
|
||||
this.tbPassword.TabIndex = 4;
|
||||
this.tbPassword.UseSystemPasswordChar = true;
|
||||
//
|
||||
// btnOK
|
||||
//
|
||||
this.btnOK.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
this.btnOK.Location = new System.Drawing.Point(337, 16);
|
||||
this.btnOK.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.btnOK.Name = "btnOK";
|
||||
this.btnOK.Size = new System.Drawing.Size(101, 35);
|
||||
this.btnOK.TabIndex = 6;
|
||||
this.btnOK.Text = "OK";
|
||||
this.btnOK.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnCancel
|
||||
//
|
||||
this.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
this.btnCancel.Location = new System.Drawing.Point(474, 16);
|
||||
this.btnCancel.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.btnCancel.Name = "btnCancel";
|
||||
this.btnCancel.Size = new System.Drawing.Size(101, 35);
|
||||
this.btnCancel.TabIndex = 11;
|
||||
this.btnCancel.Text = "Cancel";
|
||||
this.btnCancel.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 2;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 32.06997F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 67.93003F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.label5, 1, 4);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label2, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label3, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tbSSURL, 1, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.cbUseSSO, 0, 4);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tbUsername, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tbPassword, 1, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.label6, 0, 3);
|
||||
this.tableLayoutPanel1.Controls.Add(this.tbOTP, 1, 3);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 5;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(914, 212);
|
||||
this.tableLayoutPanel1.TabIndex = 12;
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label5.Location = new System.Drawing.Point(298, 168);
|
||||
this.label5.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(611, 44);
|
||||
this.label5.TabIndex = 15;
|
||||
this.label5.Text = "For SSO to work, additional IIS configuration is required!";
|
||||
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label1.Location = new System.Drawing.Point(5, 0);
|
||||
this.label1.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(283, 42);
|
||||
this.label1.TabIndex = 2;
|
||||
this.label1.Text = "Secret Server URL";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label2.Location = new System.Drawing.Point(5, 42);
|
||||
this.label2.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(283, 42);
|
||||
this.label2.TabIndex = 4;
|
||||
this.label2.Text = "DOMAIN\\Username";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// cbUseSSO
|
||||
//
|
||||
this.cbUseSSO.AutoSize = true;
|
||||
this.cbUseSSO.Location = new System.Drawing.Point(5, 173);
|
||||
this.cbUseSSO.Margin = new System.Windows.Forms.Padding(5, 5, 5, 0);
|
||||
this.cbUseSSO.Name = "cbUseSSO";
|
||||
this.cbUseSSO.Size = new System.Drawing.Size(86, 24);
|
||||
this.cbUseSSO.TabIndex = 14;
|
||||
this.cbUseSSO.Text = "Use SSO";
|
||||
this.cbUseSSO.UseVisualStyleBackColor = true;
|
||||
this.cbUseSSO.CheckedChanged += new System.EventHandler(this.cbUseSSO_CheckedChanged);
|
||||
//
|
||||
// label6
|
||||
//
|
||||
this.label6.AutoSize = true;
|
||||
this.label6.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label6.Location = new System.Drawing.Point(3, 126);
|
||||
this.label6.Name = "label6";
|
||||
this.label6.Size = new System.Drawing.Size(287, 42);
|
||||
this.label6.TabIndex = 15;
|
||||
this.label6.Text = "2FA OTP (Optional)";
|
||||
//
|
||||
// tbOTP
|
||||
//
|
||||
this.tbOTP.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tbOTP.Location = new System.Drawing.Point(296, 130);
|
||||
this.tbOTP.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
this.tbOTP.Name = "tbOTP";
|
||||
this.tbOTP.Size = new System.Drawing.Size(615, 27);
|
||||
this.tbOTP.TabIndex = 5;
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 5;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 106F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 26F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 107F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.btnOK, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.btnCancel, 3, 0);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Bottom;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 300);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 1;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(914, 67);
|
||||
this.tableLayoutPanel2.TabIndex = 13;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.label4.Location = new System.Drawing.Point(0, 212);
|
||||
this.label4.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(427, 20);
|
||||
this.label4.TabIndex = 14;
|
||||
this.label4.Text = "URL is the base URL, like https://cred.domain.local/SecretServer";
|
||||
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// SSConnectionForm
|
||||
//
|
||||
this.AcceptButton = this.btnOK;
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(914, 367);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.tableLayoutPanel2);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
|
||||
this.Name = "SSConnectionForm";
|
||||
this.Text = "Secret Server API Login Data";
|
||||
this.Activated += new System.EventHandler(this.SSConnectionForm_Activated);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
private System.Windows.Forms.Label label3;
|
||||
|
||||
public System.Windows.Forms.TextBox tbSSURL;
|
||||
public System.Windows.Forms.TextBox tbUsername;
|
||||
public System.Windows.Forms.TextBox tbPassword;
|
||||
private System.Windows.Forms.Button btnOK;
|
||||
private System.Windows.Forms.Button btnCancel;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
public System.Windows.Forms.CheckBox cbUseSSO;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private Label label5;
|
||||
private Label label6;
|
||||
public TextBox tbOTP;
|
||||
}
|
||||
}
|
||||
35
ExternalConnectors/DSS/SSConnectionForm.cs
Normal file
35
ExternalConnectors/DSS/SSConnectionForm.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace ExternalConnectors.DSS
|
||||
{
|
||||
public partial class SSConnectionForm : Form
|
||||
{
|
||||
public SSConnectionForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void SSConnectionForm_Activated(object sender, EventArgs e)
|
||||
{
|
||||
SetVisibility();
|
||||
if (cbUseSSO.Checked)
|
||||
btnOK.Focus();
|
||||
else
|
||||
{
|
||||
if (tbPassword.Text.Length == 0)
|
||||
tbPassword.Focus();
|
||||
else
|
||||
tbOTP.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void cbUseSSO_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
SetVisibility();
|
||||
}
|
||||
private void SetVisibility()
|
||||
{
|
||||
bool ch = cbUseSSO.Checked;
|
||||
tbPassword.Enabled = !ch;
|
||||
tbUsername.Enabled = !ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
615
ExternalConnectors/DSS/SSConnectionForm.resx
Normal file
615
ExternalConnectors/DSS/SSConnectionForm.resx
Normal file
@@ -0,0 +1,615 @@
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
AAABAAQAQEAAAAEAIAAoQAAARgAAACAgAAABACAAKBAAAG5AAAAYGAAAAQAgACgJAACWUAAAEBAAAAEA
|
||||
IAAoBAAAvlkAACgAAABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9/f3e/f397vz9
|
||||
/e79/f3u7ezr7p6Xju5XTEHuNScV7i8hCe4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isf
|
||||
CO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isf
|
||||
CO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isf
|
||||
CO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHAjuKx8I7jYoFu5XTUHumJGO7u3r6+79/f3u/f397v39
|
||||
/e79/f3e/f399P//////////u7Wy/0M1KP8jEwD/KRgA/ywdBv8tHwj/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8sHAT/KRcA/yAR
|
||||
AP9DNSX/ubOt/////////////f399Pv8/e7/////m5aK/xoMAP8lFAD/LSAI/y0gCv8uIAr/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cv8uIAr/LB4J/ysfCf8uIQj/JBYA/xoLAP+elYz///////z9/O79/f3uvLWw/xsNAP8rHAX/LiAK/y0f
|
||||
Cf8tHwj/LR8I/y0fCf8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCf8tHwn/LR8J/y4gCv8pGgP/GgsA/7y3sP/9/f3u6unp7kM0
|
||||
I/8nFwH/LiEL/yweCP8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAr/LR8J/yIU
|
||||
AP9DNSL/6+nq7pqUju4fEQD/LiAI/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8uIAf/HxAA/5qTju5YTT7uJRYA/ywgCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/Kx8I/ygXAP9YTkDuOCkV7iweBv8sHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sHQX/NykW7ioc
|
||||
CO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8uIAn/Lh8I/yocCO4qHAjuLyEK/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8K/y4gCf8rHAjuKx8I7i4gCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8J/y0fCP8tHwn/LR8J/y0f
|
||||
CP8tHwn/LR8J/y0fCP8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
CP8tHwj/LR8J/y0fCf8tHwj/LR8J/y0fCf8tHwn/LR8J/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8uIAj/Kx8I7isfCO4uIAn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8I/y8fCP8uHwj/LR8G/yweCP8uHgn/LR4H/yweB/8rHgf/Kx4H/yweCP8sHgj/Kx4I/yse
|
||||
CP8sHgj/LB4I/yweCP8sHgn/LB4J/yoeCP8qHgj/LB4I/y4fCP8sIQj/LB8H/y0eCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysf
|
||||
CO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tIAn/LiAK/y0WAf8sFgH/LRsG/ywbBv8uGwX/MR0B/y8cAv8uGwX/LRkG/ysZ
|
||||
Bf8qGQX/KhkF/ygaBP8oGgX/JxoF/ycaBf8pGgX/KRkG/ykZBv8nGQT/JxkF/ygZCv8jFAb/IBUG/ywe
|
||||
Cf8tHwf/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/Lh0I/y0XA/84Qyf/P31P/0aSXP9KkVv/UpJT/2OV
|
||||
Sv93mUf/jJ9A/6CjPP+vpjv/rac4/6ilN/+ppDn/qaQ4/62jOP+uozj/sKI2/7KiNv+yojX/s6Az/7Wi
|
||||
NP+0oDP/mIUs/1pIFv8lFQb/Kh4I/y4gCf8sHgn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR4I/ygWA/83b0X/SsOE/0zC
|
||||
f/9QvHf/Ubp0/1e4b/9YtGz/WrJl/2KwZP96tWD/lL9X/7fNUf/b2E//3NhP/9nWTP/X00v/29NL/9vS
|
||||
Sv/d0Ur/39FJ/9/RSP/j0Ej/5tBD/+3VRP/r0EX/jHYl/yMUBv8sHwb/LB4I/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/ysV
|
||||
AP8zWTb/ScmH/0e8ef9Ltnb/TrRx/1Cyb/9VsGr/Wa1m/1mrYf9dqV3/XqRc/1yfWf9ooVL/g6tQ/7XD
|
||||
Tf/R0Ur/ys1H/87LR//Oykb/0MlG/9PKRf/Uy0X/18pF/9jJQf/byEH/4MtD/+7VRv9rWxz/HxMC/y8h
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/Kx8I/y0cBv8vHQj/QKFs/0fEgP9IuHX/TLZ0/0+0cP9UsW3/Vq9o/1isZP9cqWD/X6hc/2Ok
|
||||
Wf9loVX/aKBT/2iZUP9um0j/obZJ/87RTP/SzUz/yspI/8zLSP/Qykj/0stH/9XJR//VyUT/2clE/9fH
|
||||
RP/izkn/vao2/ywdBv8rHAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tGwX/MCoV/0azfP9Fvnv/Sbh2/0y2c/9PtG//VbFs/1av
|
||||
Z/9YrGT/XKlg/2KnXP9kpVr/ZaJX/2mhU/9unkz/bZtK/2qVR/+asUj/zdJM/8nOSf/JzUv/zcxJ/8/L
|
||||
R//Rykf/0cpE/9XKRP/WykX/3c5G/9DBQv86Kw//KRoH/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LiAI/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwr/LRoE/ywsGP9Dt3//R7x6/0q3
|
||||
dv9OtHL/ULNu/1Wwa/9Xrmb/Watj/12pXv9hplv/ZaRY/2eiVP9qoFH/bp5M/3OcSf9ymUb/b5BC/6m5
|
||||
SP/L0k7/yM5M/8vNS//LzEn/z8xJ/87LR//Rykf/08tH/9nNSP/RxkT/PS8R/ygZBv8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4g
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LB8K/y4a
|
||||
A/8uLRj/RLZ9/0e8ev9LtnX/ULNy/1Gybf9VsGr/Wa5l/1mrYv9dqVz/YKZa/2WkVv9oolL/aqBQ/2+e
|
||||
S/9zm0n/dJpE/3SUQ/+Dmj7/wMxM/8fPTP/IzUz/yc5L/8zNS//LzEr/z8tK/8/LSP/UzUj/0MZG/z0u
|
||||
EP8oGgX/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8uIAj/Kx8I7isfCO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/ywfCv8uGgP/Li0Y/0W2fP9Iu3n/TLZ0/1Czcf9Rsm3/VbBq/1muZf9aq2L/Xqlc/2Gm
|
||||
Wv9lpFb/aKJS/2ugUP9wnkv/c5tI/3WaQ/95l0H/do07/6m6Rf/F007/xM5N/8XOTP/IzUz/yM5L/8zN
|
||||
S//MzEn/0c9J/83HR/89LhD/KBoG/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwr/LRsE/zAsGP9HtHr/S7p3/061cv9Qs2//U7Fr/1Wv
|
||||
af9arGP/XKlh/2GnW/9lpFn/ZaNV/2igUf9unk7/cpxK/3WbRv91mEH/e5Y//3mPOP+YrEH/wtVT/7/O
|
||||
Uf/CzlD/xc1Q/8TOTP/IzUz/yc5L/87QTP/HyEn/PS8P/ykZBv8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8K/y0bBP8wLBj/R7R6/0u6
|
||||
d/9OtXL/ULNv/1Oxa/9Vr2n/Wqxj/1ypYf9hp1v/ZaRZ/2WjVf9ooFH/bp5O/3KcSv91m0b/dZhB/3yW
|
||||
P/97kDj/j6I9/7/VV/+90VH/wNBR/8PPUf/Bz0z/xM5M/8XOS//K0Uz/xclJ/z0vD/8pGQb/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isf
|
||||
CO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tGwT/MCwa/0qzef9MuXb/TrRx/1Kybv9Tr2n/V61k/12qYP9fqF3/YKZZ/2SkVv9qoVL/bKBP/26d
|
||||
TP9ym0b/dJpE/3iWQf98lD7/fY43/42gPf+111v/t9RU/7nSU/+/z1L/vtBQ/8HPUP/Cz03/xtFN/8HJ
|
||||
TP88MA//KhsF/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LRsE/zAsGv9Ks3n/TLl2/060cf9Ssm7/U69p/1etZP9dqmD/X6hd/2Cm
|
||||
Wf9kpFb/aqFS/2ygT/9unUz/cptG/3SaRP94lkH/fJQ+/36NNv+LpkP/qNxh/6zYWv+v1Ff/ttFV/7zS
|
||||
Uf/A0VL/wNFP/8TUT//Ayk3/PDAP/yobBP8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4cA/8wLBn/SrN2/024dP9Ps3D/VLFs/1eu
|
||||
Z/9Zq2T/XKlf/2KnXf9jpVj/ZaNV/2qgUf9unk7/cJ1K/3KbRf92mUP/e5U+/3mUPP9/jDP/ibRM/5zi
|
||||
aP+g2mD/pdhe/6zVW/+01Ff/utNU/7vSUv/D1VH/vctN/zswEf8pGgb/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8uHQL/MCwY/0qz
|
||||
df9NuHP/T7Nv/1Wwa/9arWb/Wqtj/1qpX/9jplz/ZKRY/2WiVf9qoFH/b55N/3CdSf9ym0T/d5hC/3yW
|
||||
Pf98kjn/g441/4nRZP+N4mv/ld5n/5rcZf+g22D/p9hd/63XWf+y1Fb/utZU/7jMTv86MBH/KBoG/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LiAI/ysf
|
||||
CO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/Lh0D/zAsF/9LsnT/Trdz/1Gybv9WsGr/WK1l/1uqYv9dqV3/YqZb/2WkVv9nolT/aqBQ/2+e
|
||||
TP9ynEn/c5pD/3aXQf97lT3/gokz/3uvT/986nr/g+Rw/4nibf+O32v/lN5n/5rcY/+h22D/ptdd/6/Y
|
||||
Wv+xzlX/Oi8R/ygZBv8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4cBf8wLRb/TbFz/1C2cv9TsWz/V7Bo/1etZP9cqmH/Yahb/2Gl
|
||||
Wv9mo1T/aKFS/2ugTv9wnUr/dJpI/3WZQ/98kz3/gYo3/3WsUP9s7ID/but8/3fneP995XT/geJy/4fh
|
||||
bf+O32r/lN5m/5rbZP+j3GL/pdJd/zkvEv8pFwX/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHAX/MC0W/02xc/9QtnL/U7Fs/1ev
|
||||
aP9YrWT/XKpg/1+oW/9hpVr/ZqNV/2mhUv9sn03/cJxJ/3WVRP95kT3/eJZA/2TAYf9Y8Yj/XPOI/2fs
|
||||
gv9r637/cel7/3bneP995XT/g+Nw/4nibP+P32r/l+Bo/5jXYf85MBL/KhgG/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/KhsE/zAs
|
||||
FP9NsXH/UbVv/1awav9arWf/Wqxi/12oXv9jo1v/Y6FU/2mcUP9tm0r/bptI/2+cSv9rp1P/YMNo/1Do
|
||||
hf9G/ZX/SfaO/1PyjP9b8Ir/X+6F/2btgv9s637/cul6/3fmeP995XT/g+Nw/4vlbv+O22n/NjAU/yca
|
||||
BP8uHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/yobBP8wLBT/TbJy/1G1b/9WsGr/Wq1n/1uoX/9dp13/YKlf/2CvXv9gt2X/XcBq/1XQ
|
||||
dv9P4YP/SPCO/0T3lP9J85L/R/SR/0n1kf9L9ZD/TfSP/1Tzi/9b8Yj/Yu+E/2ftgP9r637/cel6/3jn
|
||||
dv+A6XT/geBs/zgxFf8pGwX/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y8fCf8rHAL/LisU/02ucv9Vs23/VLBp/1ipYP9XuGr/TtOA/0fg
|
||||
if9H5Ir/RuqO/0Xukf9G7pL/Ru2Q/0Ttjf9J7I7/R+6N/0nwj/9L8ZD/S/KR/0nzkP9I85D/TPSN/1X0
|
||||
if9d8If/Ye6D/2fsf/9s6nz/cux7/3Xic/81MRb/KxkE/ywfCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sHwn/Lh0D/y4gCP9PnWP/Vbdx/1eq
|
||||
ZP9TwXP/RuSM/0fmjv9F4ov/Q+SJ/0bliv9F5or/RuaM/0bojP9G6or/R+uM/0jtjP9J7o3/SO+O/0nw
|
||||
j/9I8o//RvKP/0f0j/9K947/S/WN/1Tyif9b8YT/YO6D/2n2hP9kz27/KyEM/y4dBv8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LB8J/y4e
|
||||
B/8sFgH/PGU2/1i9dP9Utm3/RN6J/0Leif9J3on/SN+K/0Xgif9H4ov/R+KL/0fjjP9I5Yz/R+eL/0jo
|
||||
jP9I6o3/SeuO/0jsjf9J7Y7/SO+O/0jwjv9J8Y//S/OQ/0r0kf9M9ZD/T/SO/1Pziv9h/5X/SIJE/yoP
|
||||
Af8sHwf/LR8K/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8uIAn/Kx8I7isfCO4uIAj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwn/LBwH/ywdCf9IfEf/Tsx8/0Ddif9F14X/RduH/0bdiP9E3on/Rd+K/0fl
|
||||
jf9I6JD/SOqQ/0jsj/9J7ZD/SO6R/0nvkv9H8JD/SPKR/0n0kf9K84//SPCP/0fxkP9J8pH/SvWS/0r3
|
||||
lP9M/pn/RKxh/y0YBv8sHAf/LR8J/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LiAI/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sGgX/KhUE/0GsbP9E4Y7/QteG/0TZ
|
||||
h/9F2oj/RdyI/0Teiv9Ez3//RMp7/0XNe/9Eznr/RM97/0TQff9F0H3/Q9J7/0PTfP9E0n3/SNyC/0zq
|
||||
iv9M6Yr/TeqL/0zsiv9P8Iz/S7Vp/ywWB/8sGgT/LiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sHwn/Lh8G/ywR
|
||||
BP87m2b/ReCR/0PUiP9E1oj/RtiJ/0bZh/9D5o//Nlk1/ywZB/8vJg3/LyYM/y8mDP8vJQ3/LyUN/ywm
|
||||
DP8sJgz/KhgH/z9sO/9c2Hr/Vslx/1fJcf9YyXL/XdF3/0yRUv8pEwT/LyEJ/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isf
|
||||
CO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LB8J/y0eBv8sEwX/PJ1n/0Tej/9D0of/Q9SG/0TWiP9F2Ib/QuWO/zVPLv8sDgD/MBsI/y8b
|
||||
B/8vGwb/LhsE/y4bBP8sGgb/KxoG/ywKAP87Zjr/U+CD/1HQe/9R0Hv/UtB7/1Pcg/9En17/KxMD/y4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4fCf8sHwj/LhUD/0CbZP9F2o7/RM+H/0TQhv9F0of/Q9WG/0bk
|
||||
kf8yVzL/KxEA/y4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tDgD/O3ZF/0zslP9I2ob/SdqG/0na
|
||||
hv9L5o7/QaNm/ywVAv8uHgf/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sHwj/LiAJ/ywUAf89jlf/Q9qO/0LN
|
||||
hf9Dz4T/RNCG/0LRg/9H4I//O4dQ/yoOAP8tIAj/LR8J/y0fCf8tHwn/LR8J/y0fCP8tHgj/LBMC/z+n
|
||||
ZP9H6pH/RN+K/0Tfiv9E34r/RuyT/z2bXv8uEwH/LR8H/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LB8J/y0f
|
||||
Cf8rDwD/NXNF/0PZjP9DyYX/RcuF/0XNhv9EzYT/RdSJ/0TFfv8uKRH/LBYC/ywfCP8tHwn/LR8J/ywf
|
||||
Cf8sHwj/KBAA/zZAIf9H34n/R+GL/0Xdif9F3Yn/Rd2I/0nvlv86gU3/Kg4A/y0eCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysf
|
||||
CO4rHwjuLiAI/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCf8rHwj/LRMB/zZRLv9H0ov/QsmE/0LKhP9Ey4X/Q8uE/0XMhP9H3I7/Pppj/ysa
|
||||
Bv8sEQD/Lh0I/y0fB/8tGgX/Kg4A/y0lD/9AuXH/R+qQ/0Lci/9D34n/Rd6J/0PdiP9C65H/M1wx/y8U
|
||||
Av8uIAf/LR8J/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y4gCP8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LB4I/y4bBv8uJQ//QLV4/0LNh/9Bx4P/Q8iE/0PJ
|
||||
g/9Ey4P/RMuG/0Xajv9EpGn/MEoo/ysfC/8uFgr/LiUN/zNULf8+vHf/SOWQ/0TYh/9F3Ij/Rt6J/0fe
|
||||
i/9E44z/Rc9//y0qDv8vGQX/LSAH/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCf8tHwn/KxEA/zt2
|
||||
Sv9F047/QcOC/0PFg/9Cx4L/RMmD/0PKgv9EzIP/RdaL/0fUif8/t3P/Pqpv/0C+dv9H3I//Rt6O/0HW
|
||||
hv9E1oj/RdiI/0Tah/9G3In/R+6U/zuET/8sDwD/LR8J/y0fCf8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LiAI/ysfCO4rHwjuLiAJ/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0aBP8wKhH/QLV4/0HKhv9BxIP/QsWB/0LHgv9CyIL/QsmD/0XKg/9FzoT/Q9KH/0LY
|
||||
iP9G14r/Q9CH/0XRhf9F0oX/RNSI/0LXiP9C14X/ReGM/0XOgv8uKxT/KxgF/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8rHwjuKx8I7i4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwf/LRYA/zRTL/9Dy4v/QcWG/0HCgf9CxIL/QsSC/0PE
|
||||
g/9CxoP/Q8iC/0TKhP9Dy4T/RsyF/0PNhf9Cz4b/RNCH/0XSiP9H0oj/QtiJ/0jikP8yWjX/KxAA/ywg
|
||||
B/8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isfCO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LSAH/y8gBv8vEgD/OWlC/0PL
|
||||
if8+xYP/P8KA/0DCgf9Bw4L/QsaC/0LHgf9DyIL/QsqC/0PLg/9CzIT/Q82F/0TOhf9Fz4X/RdaK/0fg
|
||||
lf85dkf/KhEA/yseB/8uHwj/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysfCO4rHwjuLiAJ/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8vHwn/Kh4I/y8WAP82Yzj/P7+C/0LLiP9CwoL/QMGC/0HFhP9BxIH/Q8WD/0PGhP9Ex4X/RMmE/0bK
|
||||
hf9DzYT/QtyN/0nTiP86aj3/LRIA/y4eCP8sIAr/Lh8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuKx8I7i4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8rIAj/KhQA/zU/IP9Bl2X/RseI/0LLiv8/x4b/QMaD/0DF
|
||||
g/9CxoT/Q8mG/0LOh/9G1o3/RtSK/0WjaP8yQiD/LBEA/y8eCP8sIAn/LR8I/y0fCP8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8uIAn/Kx8I7isfCO4uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sHwn/LR4I/y4gCv8sFQD/KxoE/zRJ
|
||||
Kf9Cg1P/Q6tv/0O6ev9EwoL/QsOC/0a+fv9FsHD/QoZS/zZJJ/8sGgT/KxMB/y4fCf8wIAj/Lh8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LiAJ/ysfCO4rHwjuLiAI/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8J/y0f
|
||||
Cf8tHwj/LR8J/y0dCP8rEwL/LBQA/zEjCf8yLxP/Njce/zQ3H/8yMBT/MiMJ/y8UAP8rEgD/LB0H/y4g
|
||||
Cf8tHwn/LB8J/y0fCf8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y4gCP8rHwjuKx8I7i4gCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAI/yseB/8rHQj/LBoF/ysXAv8sGAP/KxsF/ygb
|
||||
Bv8wHgf/LR8J/y4fCv8uIAr/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/Kx8I7isf
|
||||
CO4uIAj/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8I/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LB8J/y0fCf8tHwj/LR8I/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LiAJ/ysfCO4rHwjuLyEJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHwjuLh8J7i8hCP8tIAj/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwj/LyEJ7jgqFu4sHgX/LR8H/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/LB4G/zUn
|
||||
FO5YTT7uJhUA/y4gCv8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LSAL/yoZAP9XTD7um5SO7iMRAP8vIAn/LR8J/y0fCf8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwn/LR8I/ywfBv8iEgD/npeO7urq6e5ENSX/JBQA/y0hCP8tIAf/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/Kx0H/y4gCv8lFQD/QzYm/+vr6e79/f3uvLax/xoM
|
||||
AP8pGwL/LiEI/y0fCf8tHwj/LR8J/y0fCf8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0f
|
||||
CP8tHwj/LR8I/y0fCP8tHwj/LR8I/y0fCP8tHwj/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHQX/Gw0A/723
|
||||
tP/9/f3u+vv87v////+ak4n/GQsA/yQUAP8uHwn/LR8J/y0fCP8uIAn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0eCf8sHgj/LB8J/y4g
|
||||
B/8mFwD/Gw0A/5qViv//////+/z87v39/fT//////////7q1sP9DNCb/IxEA/ycWAP8rHgX/LiAH/y8h
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/zAh
|
||||
Cv8uHwj/LB0G/yQWAP8fEQD/QzQm/7q0r/////////////39/fT9/f3e/f397vz9/e79/f3u6+rp7puU
|
||||
ju5YTj/uOCkW7i4fCu4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isf
|
||||
CO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isf
|
||||
CO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isfCO4rHwjuKx8I7isf
|
||||
CO4rHwjuKx8I7isfCO4rHwjuKyAI7jcpFu5YTj7umpOO7uvr6u79/f3u/Pz97v39/e79/f3eKAAAACAA
|
||||
AABAAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP39/dzt6+vtdGte7TQmFu0rHQjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7SsdBu00Jhbtc2le7e3r6e39/f3c6ubl81ZKOP8dDgD/LB4G/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LyAK/ywdBf8dDgD/VUk4/+rn5vN0a13tHg4A/y4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8dDQD/dWtd7TQm
|
||||
Eu0rHQb/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/ywd
|
||||
Bf80JhLtKx0G7S8gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LiAJ/ysdBu0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwj/LBcC/ysT
|
||||
AP8pFAH/JhMC/yISA/8hEQP/IBID/yASA/8gEgT/HxIE/x8RBP8jFgb/LB4I/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR4I/ywY
|
||||
BP81QiP/Olw1/0RbLP9WXSb/bGMj/3RnIP9vZCD/bmIg/3FiIP9yYh7/dWMf/1ZFFv8lFwb/LB4I/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8rFgL/N2c//0vDgf9SwHr/W7pv/2a2Zf9+t13/p8RT/9bYT//g20z/3tZL/+LWSv/p10f/69RF/39r
|
||||
Iv8iFQT/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LBwG/y4lD/9Esnb/Sr55/1Kybv9XrWf/Xahe/1+iWP9imlH/faJJ/8DHSv/Pz0r/z8tI/9PK
|
||||
Rf/f0Uf/z75A/zQmC/8pGwj/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8sGgX/Ly0W/0S0ef9NuHb/U7Fs/1itZP9ep1z/ZqNW/2yfTv9slUb/hqFE/8fP
|
||||
TP/Lzkv/zcxJ/9TOSf/Ow0T/PS4P/ygaB/8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/ywbBf8wLBX/RrF1/0+4dP9UsGv/Wqxj/2CmWv9molT/b55N/3WZ
|
||||
RP93kTz/r8BI/8fST//Hzkz/zdFM/8bERv87LQ7/KRoH/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/y0f
|
||||
CO0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LBsF/zAsFf9Jr3T/ULdz/1WvaP9dqmD/YqVZ/2mg
|
||||
Uv9wnEv/dplD/3mOOf+iuEn/wNZV/8HPT//H0k7/v8ZJ/zstDv8pGgf/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8sGwX/MCwV/0mvc/9RtnH/Vq1m/16p
|
||||
Xv9jpFf/bKBQ/3CcSP93mEH/fIw2/5bCU/+q3F//tdNW/8HWUv+7yEv/Oi4O/ykaB/8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/ywbBf8wLRT/S65w/1O1
|
||||
bv9ZrGT/YKdc/2ajVv9sn0//cpxG/3uPOf+AmT7/hd5t/5Hhav+e22L/rdtc/6/KUf85LQ//KRoH/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LBsG/zAs
|
||||
E/9NrW7/VrRt/1qrYf9ipFj/aZ5R/3GXR/94kj//dKFI/2bddv9t74H/eeZ2/4Xib/+U4mr/mdFe/zgt
|
||||
EP8qGQb/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8sGwb/LiwU/06ubf9ZsGn/Xahf/2CqXv9jr13/YLtj/1jRdP9K8o7/SvqT/1byi/9j7oP/b+p8/3zq
|
||||
d/+D22r/NjAS/yoaBv8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/ywcBv8vJw7/Ualp/1e3bP9N0n//R+GJ/0bojf9E75H/RPKR/0jwj/9J8ZD/R/OR/0z1
|
||||
jv9W8on/ZfWF/2vhd/8yKg//KxoG/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8I/ysXAv9CaTr/TNSC/0PijP9F34n/RueP/0n0lv9J95b/SvqY/0n9
|
||||
mP9J+5b/R/OR/0j4lP9Q/pb/RI5N/ysTAv8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/LR8I7S0f
|
||||
CO0uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LRwG/ywbB/9Aunf/RN6M/0bijf9At3D/OXJC/zp7
|
||||
Rf86fEb/NnhD/z+SUv9S3H//U+KD/068bf8sGgj/LRsH/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHQf/LRwI/0CydP9E2oz/RuWR/zqO
|
||||
Vv8qAAD/LA8A/ywOAP8pAgD/Mzkb/0/bhP9Q24T/SLRs/y0dCP8tHQf/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0eCP8tGQT/PqZp/0TW
|
||||
jP9F1or/Qbh0/ywbBv8sFQL/LBwG/ykGAP86eEX/Ru6U/0Xpkf9At3H/LRkE/y0eB/8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/ysR
|
||||
AP86fk//RNeP/0TJg/9G14z/PI1Y/y4pEP8tHQn/M1ky/0TWhv9F4Yz/R/CV/zqOU/8sEAD/LR8I/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LBcD/zE5HP9CxoX/QsqF/0PIgv9F1ov/QsR+/0C7d/9F2oz/RNmK/0Xdiv9G34z/MT0d/ywW
|
||||
A/8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LBQA/zdmPf9C0Iz/QcmG/0LFgv9DzIX/RNGI/0POhv9F14v/R+WU/zdv
|
||||
Qv8qEQD/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHgj/LBUB/zVeNv9Ct3v/Q8+M/0LRjP9E1I7/RteO/0TE
|
||||
fv84ZDr/LRQB/y0eCP8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHgj/LBMA/y8qEf84Xjb/O3lM/zt6
|
||||
Tf86YDf/MCoR/ysSAP8tHgj/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LiAJ/y0f
|
||||
CO0tHwjtLiAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LBoF/ysT
|
||||
AP8sEQD/KxEA/ysSAP8sGgX/LSAJ/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8uIAn/LR8I7SweBu0vIAn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8rHQbtNCYT7SwdBv8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LB4G/zQmEu11a17tHQ4A/y4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0gCf8dDgD/dmxe7ern5vNVSTf/Hg4A/ywdBv8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8rHQX/Hg4A/1ZKOP/q5+fz/f393Ozr6e10aV7tNSYU7Swe
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLB4I7TQmFO1zaV7t7evp7f39/dwoAAAAGAAAADAA
|
||||
AAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/f393JSPhO00JhbtKx0G7S0fCO0tHwjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0rHQbtMyUW7ZSO
|
||||
g+39/f3ckouC8yESAP8qHAT/LyAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8vIAn/KhwE/yERAP+Si4LzMyUR7SocBP8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/yocBP8zJRLtKx0F7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0eCP8sGgX/KxoG/yka
|
||||
B/8oGgf/KBoH/ygaB/8nGgf/KBoH/yweCP8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8rHQXtLR8I7S4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LRwH/y0aBf8wLRP/Ni8Q/0ExDv9FMw3/PjAN/z4vDv8/MA3/PS4N/ycZ
|
||||
B/8qHAj/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHQf/LB8K/z6E
|
||||
VP9NsnL/Wapi/3GoVv+bskv/x8VG/87FRP/PwkL/2cZB/6GMLf8tHwj/Kx0I/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8sFgH/MkYn/0nIhP9Rt3L/WK9m/16nXf9jnlP/iKlK/8nO
|
||||
S//T0Er/2M9H/+jYSv9XSRf/IxUF/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0f
|
||||
Cf8sFQH/M0os/0vBfv9Tsm3/Wqxi/2OlWP9sn07/bJJD/5uuRP/M0k3/y81L/9nWTP9cTxv/IhQF/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8rFQH/NEkq/02+e/9UsGr/Xalg/2Wj
|
||||
Vv9unkz/dJRB/4ufPv+/01P/xM9O/8/XT/9YThr/IxQE/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4g
|
||||
Cf8tHwn/LR8J/y0fCf8rFgH/NUkp/068ef9Xrmf/X6dc/2iiVP9wnUn/eI86/4ilRP+k3mL/tNVX/8ba
|
||||
U/9WTxv/JBQE/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8rFgH/Nkgo/1K7
|
||||
dv9ZrWT/YqRZ/2ycTf93kj//epU+/3bVa/+D53T/lN5n/63hYv9RTx//JRMD/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8qFQL/NUop/1a6c/9cqWH/Yatd/2SwW/9gv2b/UeeE/1L4
|
||||
kP9k7oL/dOh5/4vvdf9JViX/JxIC/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0f
|
||||
Cf8rFwP/NT4e/1a5cP9N0H3/R+GI/0fwkv9F+5n/SPuY/0j7lv9J95H/VfaM/2f6iP88SyH/KhQC/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHgj/LBUC/z6ETv9E6JL/Rd+L/0LG
|
||||
ef9DwHP/QsR1/0LHdP9L4oX/T/aS/0KaV/8rFgT/LR4I/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/Kw8A/zVgOv9F4pL/Rd+N/zJGJP8tEAD/LRoF/ywaBv9Lum3/VOeL/zle
|
||||
M/8qDwD/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/KxMA/zVX
|
||||
Mf9F2I7/RtuO/zl3R/8qBQD/KQQA/zJDIv9F4Iv/RvCW/zVfNf8rEQD/LR8J/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/LBoF/zAtE/9Cv3//RNCJ/0TNhf86g1D/N29C/0LF
|
||||
fP9G6JH/RNeF/y8wFP8sGQT/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/ywTAP82Yzv/QtKN/0PPif9F2I3/Rd2Q/0XekP9H5ZP/N2w//ysRAP8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0eCP8sFQH/NVs1/0Cu
|
||||
dP9CxoT/RMqG/0O3dv83YTj/LBQB/y0eCP8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtLR8I7S4g
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHgj/LBMA/y4iC/8zPB7/Mj0e/y8hCv8rEgD/LR4I/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4gCf8tHwjtKx0F7S4gCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/ywcB/8sFwP/LBcD/ywcB/8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y4g
|
||||
Cf8rHQbtNCUS7SocBP8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0f
|
||||
Cf8tHwn/LR8J/y0fCf8tHwn/LR8J/y0fCf8tHwn/LR8J/yocBP80JhLtkouD8yERAP8qHAT/LyAJ/y4g
|
||||
Cf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4gCf8uIAn/LiAJ/y4g
|
||||
Cf8vIAn/KhwE/yERAP+VjITz/f393JSOhO00JhbtKx0G7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0rHQbtMyUW7ZSOg+39/f3cKAAAABAA
|
||||
AAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL65stw/MR/tKBkF7S0fCO0tHwjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0oGQXtPzEf7b65stw8MR3zJxgA/y8gCf8uIAn/LiAJ/y4g
|
||||
Cf8uHwn/Lh8J/y4fCf8uHwn/LiAJ/y4gCf8uIAn/LyAJ/ycYAP88MR3zKBoE7S8gCf8tHwn/LSAJ/ywa
|
||||
Bf8rFAH/LBcD/ysXBP8kFQT/IxUF/yATBP8oGgf/LiAJ/y0fCf8vIQn/KBkE7S0fCO0uIAn/LR8J/ywa
|
||||
Bf8wMxj/QYNR/1OFSP94iTr/npg0/6aYM/+hji7/RDQP/ycaB/8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0f
|
||||
Cf8rEQD/OW9F/1LNhP9dtGj/aahY/5u2TP/Z2U3/7+ZP/4V2KP8eEAT/LR8J/y4gCf8tHwjtLR8I7S4g
|
||||
Cf8tHwn/KxIA/ztvRf9Tv3f/Xqhd/2ufT/91kj7/tMNK/9fgU/+AeSr/IBAD/y0fCf8uIAn/LR8I7S0f
|
||||
CO0uIAn/LR8J/ysTAP89bUL/Vrxz/2OjWP9ylkX/fZQ7/5XTX/+952D/d3ot/yEQA/8tHwn/LiAJ/y0f
|
||||
CO0tHwjtLiAJ/y0fCf8qEwD/P29C/1y6bv9iqlv/Z7Fa/1zad/9l8oX/ifZ6/2OGPP8lDgH/LR8J/y4g
|
||||
Cf8tHwjtLR8I7S4gCf8tHwn/KhQB/zxULf9P0oD/SOSL/0b1lf9F/Jn/SPaS/1j7kP9DbTb/KRAB/y0f
|
||||
Cf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0cB/8uIwz/QcuC/0HCef8zRSL/MD0e/0SmYP9M0n7/LSMN/ywc
|
||||
Bv8tHwn/LiAJ/y0fCO0tHwjtLiAJ/y0fCf8tHQj/LRsG/0Cxc/9Ez4b/MDca/yweCf9Cxnr/Qsd6/y0b
|
||||
Bv8tHQj/LR8J/y4gCf8tHwjtLR8I7S4gCf8tHwn/LR8J/ywUAf81XTf/RNiR/0TTiv9E1In/R+2Y/zZn
|
||||
Ov8rEgH/LR8J/y0fCf8uIAn/LR8I7S0fCO0uIAn/LR8J/y0fCf8tHgj/LBcC/zRWMv8+nWb/P6Jo/zZb
|
||||
NP8sFgL/LR4I/y0fCf8tHwn/LiAJ/y0fCO0oGgTtLyEJ/y0fCf8tHwn/LR8J/y0fCP8sFAH/LBYC/ywW
|
||||
Av8rEwD/LR4I/y0fCf8tHwn/LR8J/y8hCf8oGQTtPTEd8ycYAP8vIAn/LiAJ/y4gCf8uIAn/LiAJ/y4f
|
||||
CP8uHwn/LiAJ/y4gCf8uIAn/LiAJ/y8gCf8nGAD/PTEd87u5stw/MR/tKBkF7S0fCO0tHwjtLR8I7S0f
|
||||
CO0tHwjtLR8I7S0fCO0tHwjtLR8I7S0fCO0oGQXtPzEf7b65stwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
383
ExternalConnectors/DSS/SecretServerAuthentication.cs
Normal file
383
ExternalConnectors/DSS/SecretServerAuthentication.cs
Normal file
@@ -0,0 +1,383 @@
|
||||
//----------------------
|
||||
// <auto-generated>
|
||||
// Generated using the NSwag toolchain v13.14.8.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0)) (http://NSwag.org)
|
||||
// </auto-generated>
|
||||
//----------------------
|
||||
|
||||
#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
|
||||
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
|
||||
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
|
||||
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
|
||||
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
|
||||
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
|
||||
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
|
||||
|
||||
namespace SecretServerAuthentication.DSS
|
||||
{
|
||||
using System = global::System;
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.14.8.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class OAuth2ServiceClient
|
||||
{
|
||||
private string _baseUrl = "";
|
||||
private System.Net.Http.HttpClient _httpClient;
|
||||
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;
|
||||
|
||||
public OAuth2ServiceClient(string baseUrl, System.Net.Http.HttpClient httpClient)
|
||||
{
|
||||
BaseUrl = baseUrl;
|
||||
_httpClient = httpClient;
|
||||
_settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
|
||||
}
|
||||
|
||||
private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
|
||||
{
|
||||
var settings = new Newtonsoft.Json.JsonSerializerSettings();
|
||||
UpdateJsonSerializerSettings(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
public string BaseUrl
|
||||
{
|
||||
get { return _baseUrl; }
|
||||
set { _baseUrl = value; }
|
||||
}
|
||||
|
||||
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } }
|
||||
|
||||
partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings);
|
||||
|
||||
|
||||
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url);
|
||||
partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
|
||||
partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response);
|
||||
/// <summary>Retrieve or Refresh Access Token</summary>
|
||||
/// <param name="grant_type">Authentication grant type. Use 'password' when authenticating, and 'refresh_token' when refreshing a token.</param>
|
||||
/// <param name="username">Secret Server authentication username. Required when authenticating.</param>
|
||||
/// <param name="password">Secret Server authentication password. Required when authenticating.</param>
|
||||
/// <param name="refresh_token">The refresh token. Required when refreshing a token.</param>
|
||||
/// <returns>Successful retrieval of an access token</returns>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public System.Threading.Tasks.Task<TokenResponse> AuthorizeAsync(Grant_type grant_type, string username, string password, string refresh_token, string OTP)
|
||||
{
|
||||
return AuthorizeAsync(grant_type, username, password, refresh_token, System.Threading.CancellationToken.None, OTP);
|
||||
}
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <summary>Retrieve or Refresh Access Token</summary>
|
||||
/// <param name="grant_type">Authentication grant type. Use 'password' when authenticating, and 'refresh_token' when refreshing a token.</param>
|
||||
/// <param name="username">Secret Server authentication username. Required when authenticating.</param>
|
||||
/// <param name="password">Secret Server authentication password. Required when authenticating.</param>
|
||||
/// <param name="refresh_token">The refresh token. Required when refreshing a token.</param>
|
||||
/// <returns>Successful retrieval of an access token</returns>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public async System.Threading.Tasks.Task<TokenResponse> AuthorizeAsync(Grant_type grant_type, string username, string password, string refresh_token, System.Threading.CancellationToken cancellationToken, string OTP)
|
||||
{
|
||||
var urlBuilder_ = new System.Text.StringBuilder();
|
||||
urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/oauth2/token");
|
||||
|
||||
var client_ = _httpClient;
|
||||
var disposeClient_ = false;
|
||||
try
|
||||
{
|
||||
using (var request_ = new System.Net.Http.HttpRequestMessage())
|
||||
{
|
||||
var keyValues_ = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>>();
|
||||
if (grant_type == null)
|
||||
throw new System.ArgumentNullException("grant_type");
|
||||
else
|
||||
keyValues_.Add(new System.Collections.Generic.KeyValuePair<string, string>("grant_type", ConvertToString(grant_type, System.Globalization.CultureInfo.InvariantCulture)));
|
||||
if (username != null)
|
||||
keyValues_.Add(new System.Collections.Generic.KeyValuePair<string, string>("username", ConvertToString(username, System.Globalization.CultureInfo.InvariantCulture)));
|
||||
if (password != null)
|
||||
keyValues_.Add(new System.Collections.Generic.KeyValuePair<string, string>("password", ConvertToString(password, System.Globalization.CultureInfo.InvariantCulture)));
|
||||
if (refresh_token != null)
|
||||
keyValues_.Add(new System.Collections.Generic.KeyValuePair<string, string>("refresh_token", ConvertToString(refresh_token, System.Globalization.CultureInfo.InvariantCulture)));
|
||||
if (OTP != null)
|
||||
request_.Headers.Add("OTP", ConvertToString(OTP, System.Globalization.CultureInfo.InvariantCulture));
|
||||
|
||||
request_.Content = new System.Net.Http.FormUrlEncodedContent(keyValues_);
|
||||
request_.Method = new System.Net.Http.HttpMethod("POST");
|
||||
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||
|
||||
PrepareRequest(client_, request_, urlBuilder_);
|
||||
|
||||
var url_ = urlBuilder_.ToString();
|
||||
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
|
||||
|
||||
PrepareRequest(client_, request_, url_);
|
||||
|
||||
var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
|
||||
var disposeResponse_ = true;
|
||||
try
|
||||
{
|
||||
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value);
|
||||
if (response_.Content != null && response_.Content.Headers != null)
|
||||
{
|
||||
foreach (var item_ in response_.Content.Headers)
|
||||
headers_[item_.Key] = item_.Value;
|
||||
}
|
||||
|
||||
ProcessResponse(client_, response_);
|
||||
|
||||
var status_ = (int)response_.StatusCode;
|
||||
if (status_ == 200)
|
||||
{
|
||||
var objectResponse_ = await ReadObjectResponseAsync<TokenResponse>(response_, headers_, cancellationToken).ConfigureAwait(false);
|
||||
if (objectResponse_.Object == null)
|
||||
{
|
||||
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
|
||||
}
|
||||
|
||||
return objectResponse_.Object;
|
||||
}
|
||||
else
|
||||
if (status_ == 400)
|
||||
{
|
||||
var objectResponse_ = await ReadObjectResponseAsync<TokenErrorResponse>(response_, headers_, cancellationToken).ConfigureAwait(false);
|
||||
if (objectResponse_.Object == null)
|
||||
{
|
||||
throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null);
|
||||
}
|
||||
throw new ApiException<TokenErrorResponse>("An error occurred", status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeResponse_)
|
||||
response_.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeClient_)
|
||||
client_.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected struct ObjectResponseResult<T>
|
||||
{
|
||||
public ObjectResponseResult(T responseObject, string responseText)
|
||||
{
|
||||
this.Object = responseObject;
|
||||
this.Text = responseText;
|
||||
}
|
||||
|
||||
public T Object { get; }
|
||||
|
||||
public string Text { get; }
|
||||
}
|
||||
|
||||
public bool ReadResponseAsString { get; set; }
|
||||
|
||||
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
if (response == null || response.Content == null)
|
||||
{
|
||||
return new ObjectResponseResult<T>(default(T), string.Empty);
|
||||
}
|
||||
|
||||
if (ReadResponseAsString)
|
||||
{
|
||||
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
|
||||
return new ObjectResponseResult<T>(typedBody, responseText);
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonException exception)
|
||||
{
|
||||
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
|
||||
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
using (var streamReader = new System.IO.StreamReader(responseStream))
|
||||
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
|
||||
{
|
||||
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
|
||||
var typedBody = serializer.Deserialize<T>(jsonTextReader);
|
||||
return new ObjectResponseResult<T>(typedBody, string.Empty);
|
||||
}
|
||||
}
|
||||
catch (Newtonsoft.Json.JsonException exception)
|
||||
{
|
||||
var message = "Could not deserialize the response body stream as " + typeof(T).FullName + ".";
|
||||
throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (value is System.Enum)
|
||||
{
|
||||
var name = System.Enum.GetName(value.GetType(), value);
|
||||
if (name != null)
|
||||
{
|
||||
var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name);
|
||||
if (field != null)
|
||||
{
|
||||
var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute))
|
||||
as System.Runtime.Serialization.EnumMemberAttribute;
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute.Value != null ? attribute.Value : name;
|
||||
}
|
||||
}
|
||||
|
||||
var converted = System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
|
||||
return converted == null ? string.Empty : converted;
|
||||
}
|
||||
}
|
||||
else if (value is bool)
|
||||
{
|
||||
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
|
||||
}
|
||||
else if (value is byte[])
|
||||
{
|
||||
return System.Convert.ToBase64String((byte[])value);
|
||||
}
|
||||
else if (value.GetType().IsArray)
|
||||
{
|
||||
var array = System.Linq.Enumerable.OfType<object>((System.Array)value);
|
||||
return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo)));
|
||||
}
|
||||
|
||||
var result = System.Convert.ToString(value, cultureInfo);
|
||||
return result == null ? "" : result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>API access token response</summary>
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")]
|
||||
public partial class TokenResponse
|
||||
{
|
||||
/// <summary>Authentication token</summary>
|
||||
[Newtonsoft.Json.JsonProperty("access_token", Required = Newtonsoft.Json.Required.Always)]
|
||||
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
|
||||
public string Access_token { get; set; }
|
||||
|
||||
/// <summary>Authentication token type</summary>
|
||||
[Newtonsoft.Json.JsonProperty("token_type", Required = Newtonsoft.Json.Required.Always)]
|
||||
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
|
||||
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||
public TokenResponseToken_type Token_type { get; set; }
|
||||
|
||||
|
||||
private string _Expires_in;
|
||||
/// <summary>Authentication token expiration time, in seconds</summary>
|
||||
[Newtonsoft.Json.JsonProperty("expires_in", Required = Newtonsoft.Json.Required.Always)]
|
||||
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
|
||||
// public string Expires_in { get; set; }
|
||||
|
||||
public string Expires_in
|
||||
{
|
||||
get { return _Expires_in; }
|
||||
set
|
||||
{
|
||||
_Expires_in = value;
|
||||
Expires_on = DateTime.UtcNow.AddSeconds(Double.Parse(value) - 60);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Authentication token expiration time in UTC</summary>
|
||||
public DateTime Expires_on { get; set; }
|
||||
|
||||
/// <summary>Refresh token. This is only provided when the server is set to allow refresh tokens for web services and when the session timeout duration is not set to Unlimited.</summary>
|
||||
[Newtonsoft.Json.JsonProperty("refresh_token", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
|
||||
public string Refresh_token { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>API access token error response</summary>
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")]
|
||||
public partial class TokenErrorResponse
|
||||
{
|
||||
/// <summary>Authentication token</summary>
|
||||
[Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)]
|
||||
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
|
||||
public string Message { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Authentication grant type. Use 'password' when authenticating, and 'refresh_token' when refreshing a token.</summary>
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")]
|
||||
public enum Grant_type
|
||||
{
|
||||
[System.Runtime.Serialization.EnumMember(Value = @"password")]
|
||||
Password = 0,
|
||||
|
||||
[System.Runtime.Serialization.EnumMember(Value = @"refresh_token")]
|
||||
Refresh_token = 1,
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v11.0.0.0)")]
|
||||
public enum TokenResponseToken_type
|
||||
{
|
||||
[System.Runtime.Serialization.EnumMember(Value = @"bearer")]
|
||||
Bearer = 0,
|
||||
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.14.8.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class ApiException : System.Exception
|
||||
{
|
||||
public int StatusCode { get; private set; }
|
||||
|
||||
public string Response { get; private set; }
|
||||
|
||||
public System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }
|
||||
|
||||
public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Exception innerException)
|
||||
: base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null) ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Response = response;
|
||||
Headers = headers;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.14.8.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
public partial class ApiException<TResult> : ApiException
|
||||
{
|
||||
public TResult Result { get; private set; }
|
||||
|
||||
public ApiException(string message, int statusCode, string response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, TResult result, System.Exception innerException)
|
||||
: base(message, statusCode, response, headers, innerException)
|
||||
{
|
||||
Result = result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma warning restore 1591
|
||||
#pragma warning restore 1573
|
||||
#pragma warning restore 472
|
||||
#pragma warning restore 114
|
||||
#pragma warning restore 108
|
||||
#pragma warning restore 3016
|
||||
341
ExternalConnectors/DSS/SecretServerInterface.cs
Normal file
341
ExternalConnectors/DSS/SecretServerInterface.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
using Microsoft.Win32;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.OpenSsl;
|
||||
using Org.BouncyCastle.Security;
|
||||
using SecretServerAuthentication.DSS;
|
||||
using SecretServerRestClient.DSS;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace ExternalConnectors.DSS;
|
||||
|
||||
public class SecretServerInterface
|
||||
{
|
||||
private static class SSConnectionData
|
||||
{
|
||||
public static string ssUsername = "";
|
||||
public static string ssPassword = "";
|
||||
public static string ssUrl = "";
|
||||
public static string ssOTP = "";
|
||||
public static bool ssSSO = false;
|
||||
public static bool initdone = false;
|
||||
|
||||
//token
|
||||
public static string ssTokenBearer = "";
|
||||
public static DateTime ssTokenExpiresOn = DateTime.UtcNow;
|
||||
public static string ssTokenRefresh = "";
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if (initdone == true)
|
||||
return;
|
||||
|
||||
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteSSInterface");
|
||||
try
|
||||
{
|
||||
// display gui and ask for data
|
||||
SSConnectionForm f = new();
|
||||
string? un = key.GetValue("Username") as string;
|
||||
f.tbUsername.Text = un ?? "";
|
||||
f.tbPassword.Text = SSConnectionData.ssPassword; // in OTP refresh cases, this value might already be filled
|
||||
|
||||
string? url = key.GetValue("URL") as string;
|
||||
if (url == null || !url.Contains("://"))
|
||||
url = "https://cred.domain.local/SecretServer";
|
||||
f.tbSSURL.Text = url;
|
||||
|
||||
var b = key.GetValue("SSO");
|
||||
if (b == null || (string)b != "True")
|
||||
ssSSO = false;
|
||||
else
|
||||
ssSSO = true;
|
||||
f.cbUseSSO.Checked = ssSSO;
|
||||
|
||||
// show dialog
|
||||
while (true)
|
||||
{
|
||||
_ = f.ShowDialog();
|
||||
|
||||
if (f.DialogResult != DialogResult.OK)
|
||||
return;
|
||||
|
||||
// store values to memory
|
||||
ssUsername = f.tbUsername.Text;
|
||||
ssPassword = f.tbPassword.Text;
|
||||
ssUrl = f.tbSSURL.Text;
|
||||
ssSSO = f.cbUseSSO.Checked;
|
||||
ssOTP = f.tbOTP.Text;
|
||||
// check connection first
|
||||
try
|
||||
{
|
||||
if (TestCredentials() == true)
|
||||
{
|
||||
initdone = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageBox.Show("Test Credentials failed - please check your credentials");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// write values to registry
|
||||
key.SetValue("Username", ssUsername);
|
||||
key.SetValue("URL", ssUrl);
|
||||
key.SetValue("SSO", ssSSO);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
key.Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TestCredentials()
|
||||
{
|
||||
if (SSConnectionData.ssSSO)
|
||||
{
|
||||
// checking creds doesn't really make sense here, as we can't modify them anyway if something is wrong
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (!String.IsNullOrEmpty(GetToken()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SecretsServiceClient ConstructSecretsServiceClient()
|
||||
{
|
||||
string baseURL = SSConnectionData.ssUrl;
|
||||
if (SSConnectionData.ssSSO)
|
||||
{
|
||||
// REQUIRES IIS CONFIG! https://docs.thycotic.com/ss/11.0.0/api-scripting/webservice-iwa-powershell
|
||||
var handler = new HttpClientHandler() { UseDefaultCredentials = true };
|
||||
var httpClient = new HttpClient(handler);
|
||||
{
|
||||
// Call REST API:
|
||||
return new SecretsServiceClient($"{baseURL}/winauthwebservices/api", httpClient);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var httpClient = new HttpClient();
|
||||
{
|
||||
|
||||
var token = GetToken();
|
||||
// Set credentials (token):
|
||||
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
|
||||
// Call REST API:
|
||||
return new SecretsServiceClient($"{baseURL}/api", httpClient);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private static void FetchSecret(int secretID, out string secretUsername, out string secretPassword, out string secretDomain, out string privatekey)
|
||||
{
|
||||
var client = ConstructSecretsServiceClient();
|
||||
SecretModel secret = client.GetSecretAsync(false, true, secretID, null).Result;
|
||||
|
||||
// clear return variables
|
||||
secretDomain = "";
|
||||
secretUsername = "";
|
||||
secretPassword = "";
|
||||
privatekey = "";
|
||||
string privatekeypassphrase = "";
|
||||
|
||||
// parse data and extract what we need
|
||||
foreach (var item in secret.Items)
|
||||
{
|
||||
if (item.FieldName.ToLower().Equals("domain"))
|
||||
secretDomain = item.ItemValue;
|
||||
else if (item.FieldName.ToLower().Equals("username"))
|
||||
secretUsername = item.ItemValue;
|
||||
else if (item.FieldName.ToLower().Equals("password"))
|
||||
secretPassword = item.ItemValue;
|
||||
else if (item.FieldName.ToLower().Equals("private key"))
|
||||
{
|
||||
client.ReadResponseNoJSONConvert = true;
|
||||
privatekey = client.GetFieldAsync(false, false, secretID, "private-key").Result;
|
||||
client.ReadResponseNoJSONConvert = false;
|
||||
}
|
||||
else if (item.FieldName.ToLower().Equals("private key passphrase"))
|
||||
privatekeypassphrase = item.ItemValue;
|
||||
}
|
||||
|
||||
// need to decode the private key?
|
||||
if (!string.IsNullOrEmpty(privatekeypassphrase))
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = DecodePrivateKey(privatekey, privatekeypassphrase);
|
||||
privatekey = key;
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// conversion to putty format necessary?
|
||||
if (!string.IsNullOrEmpty(privatekey) && !privatekey.StartsWith("PuTTY-User-Key-File-2"))
|
||||
{
|
||||
try
|
||||
{
|
||||
RSACryptoServiceProvider key = ImportPrivateKey(privatekey);
|
||||
privatekey = PuttyKeyFileGenerator.ToPuttyPrivateKey(key);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region PUTTY KEY HANDLING
|
||||
// decode rsa private key with encryption password
|
||||
private static string DecodePrivateKey(string encryptedPrivateKey, string password)
|
||||
{
|
||||
TextReader textReader = new StringReader(encryptedPrivateKey);
|
||||
PemReader pemReader = new(textReader, new PasswordFinder(password));
|
||||
|
||||
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
|
||||
|
||||
TextWriter textWriter = new StringWriter();
|
||||
var pemWriter = new PemWriter(textWriter);
|
||||
pemWriter.WriteObject(keyPair.Private);
|
||||
pemWriter.Writer.Flush();
|
||||
|
||||
return ""+textWriter.ToString();
|
||||
}
|
||||
private class PasswordFinder : IPasswordFinder
|
||||
{
|
||||
private string password;
|
||||
|
||||
public PasswordFinder(string password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
|
||||
public char[] GetPassword()
|
||||
{
|
||||
return password.ToCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
// read private key pem string to rsacryptoserviceprovider
|
||||
public static RSACryptoServiceProvider ImportPrivateKey(string pem)
|
||||
{
|
||||
PemReader pr = new(new StringReader(pem));
|
||||
AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
|
||||
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private);
|
||||
RSACryptoServiceProvider rsa = new();
|
||||
rsa.ImportParameters(rsaParams);
|
||||
return rsa;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region TOKEN
|
||||
private static string GetToken()
|
||||
{
|
||||
// if there is no token, fetch a fresh one
|
||||
if (String.IsNullOrEmpty(SSConnectionData.ssTokenBearer))
|
||||
{
|
||||
return GetTokenFresh();
|
||||
}
|
||||
// if there is a token, check if it is valid
|
||||
if (SSConnectionData.ssTokenExpiresOn >= DateTime.UtcNow)
|
||||
{
|
||||
return SSConnectionData.ssTokenBearer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// try using refresh token
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
var tokenClient = new OAuth2ServiceClient(SSConnectionData.ssUrl, httpClient);
|
||||
TokenResponse token = new();
|
||||
try
|
||||
{
|
||||
token = tokenClient.AuthorizeAsync(Grant_type.Refresh_token, null, null, SSConnectionData.ssTokenRefresh, null).Result;
|
||||
var tokenResult = token.Access_token;
|
||||
|
||||
SSConnectionData.ssTokenBearer = tokenResult;
|
||||
SSConnectionData.ssTokenRefresh = token.Refresh_token;
|
||||
SSConnectionData.ssTokenExpiresOn = token.Expires_on;
|
||||
return tokenResult;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// refresh token failed. clean memory and start fresh
|
||||
SSConnectionData.ssTokenBearer = "";
|
||||
SSConnectionData.ssTokenRefresh = "";
|
||||
SSConnectionData.ssTokenExpiresOn = DateTime.Now;
|
||||
// if OTP is required we need to ask user for a new OTP
|
||||
if (!String.IsNullOrEmpty(SSConnectionData.ssOTP))
|
||||
{
|
||||
SSConnectionData.initdone = false;
|
||||
// the call below executes a connection test, which fetches a valid token
|
||||
SSConnectionData.Init();
|
||||
// we now have a fresh token in memory. return it to caller
|
||||
return SSConnectionData.ssTokenBearer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no user interaction required. get a fresh token and return it to caller
|
||||
return GetTokenFresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static string GetTokenFresh()
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
// Authenticate:
|
||||
var tokenClient = new OAuth2ServiceClient(SSConnectionData.ssUrl, httpClient);
|
||||
// call below will throw an exception if the creds are invalid
|
||||
var token = tokenClient.AuthorizeAsync(Grant_type.Password, SSConnectionData.ssUsername, SSConnectionData.ssPassword, null, SSConnectionData.ssOTP).Result;
|
||||
// here we can be sure the creds are ok - return success state
|
||||
var tokenResult = token.Access_token;
|
||||
|
||||
SSConnectionData.ssTokenBearer = tokenResult;
|
||||
SSConnectionData.ssTokenRefresh = token.Refresh_token;
|
||||
SSConnectionData.ssTokenExpiresOn = token.Expires_on;
|
||||
return tokenResult;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
// input must be the secret id to fetch
|
||||
public static void FetchSecretFromServer(string input, out string username, out string password, out string domain, out string privatekey)
|
||||
{
|
||||
// get secret id
|
||||
int secretID = Int32.Parse(input);
|
||||
|
||||
// init connection credentials, display popup if necessary
|
||||
SSConnectionData.Init();
|
||||
|
||||
// get the secret
|
||||
FetchSecret(secretID, out username, out password, out domain, out privatekey);
|
||||
}
|
||||
}
|
||||
130353
ExternalConnectors/DSS/SecretServerRestClient.cs
Normal file
130353
ExternalConnectors/DSS/SecretServerRestClient.cs
Normal file
File diff suppressed because it is too large
Load Diff
30
ExternalConnectors/ExternalConnectors.csproj
Normal file
30
ExternalConnectors/ExternalConnectors.csproj
Normal file
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Library</OutputType>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<Platforms>x64</Platforms>
|
||||
<Configurations>Debug;Release;Debug Portable;Release Portable;Deploy to github</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Portable|x64'">
|
||||
<Optimize>True</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AWSSDK.Core" Version="3.7.401.6" />
|
||||
<PackageReference Include="AWSSDK.EC2" Version="3.7.429.1" />
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="AWS\AWSConnectionForm.cs" />
|
||||
<Compile Update="CPS\CPSConnectionForm.cs" />
|
||||
<Compile Update="DSS\SSConnectionForm.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
111
ExternalConnectors/PuttyKeyFileGenerator.cs
Normal file
111
ExternalConnectors/PuttyKeyFileGenerator.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace ExternalConnectors;
|
||||
|
||||
public class PuttyKeyFileGenerator
|
||||
{
|
||||
private const int prefixSize = 4;
|
||||
private const int paddedPrefixSize = prefixSize + 1;
|
||||
private const int lineLength = 64;
|
||||
private const string keyType = "ssh-rsa";
|
||||
private const string encryptionType = "none";
|
||||
|
||||
public static string ToPuttyPrivateKey(RSACryptoServiceProvider cryptoServiceProvider, string Comment = "imported-openssh-key")
|
||||
{
|
||||
var publicParameters = cryptoServiceProvider.ExportParameters(false);
|
||||
byte[] publicBuffer = new byte[3 + keyType.Length + GetPrefixSize(publicParameters.Exponent) + publicParameters.Exponent!.Length + GetPrefixSize(publicParameters.Modulus) + publicParameters.Modulus!.Length + 1];
|
||||
|
||||
using (var bw = new BinaryWriter(new MemoryStream(publicBuffer)))
|
||||
{
|
||||
bw.Write(new byte[] { 0x00, 0x00, 0x00 });
|
||||
bw.Write(Encoding.ASCII.GetBytes(keyType));
|
||||
PutPrefixed(bw, publicParameters.Exponent, CheckIsNeddPadding(publicParameters.Exponent));
|
||||
PutPrefixed(bw, publicParameters.Modulus, CheckIsNeddPadding(publicParameters.Modulus));
|
||||
}
|
||||
var publicBlob = System.Convert.ToBase64String(publicBuffer);
|
||||
|
||||
var privateParameters = cryptoServiceProvider.ExportParameters(true);
|
||||
|
||||
byte[] privateBuffer = new byte[paddedPrefixSize + privateParameters.D!.Length + paddedPrefixSize + privateParameters.P!.Length + paddedPrefixSize + privateParameters.Q!.Length + paddedPrefixSize + privateParameters.InverseQ!.Length];
|
||||
|
||||
using (var bw = new BinaryWriter(new MemoryStream(privateBuffer)))
|
||||
{
|
||||
PutPrefixed(bw, privateParameters.D, true);
|
||||
PutPrefixed(bw, privateParameters.P, true);
|
||||
PutPrefixed(bw, privateParameters.Q, true);
|
||||
PutPrefixed(bw, privateParameters.InverseQ, true);
|
||||
}
|
||||
var privateBlob = System.Convert.ToBase64String(privateBuffer);
|
||||
|
||||
HMACSHA1 hmacSha1 = new(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes("putty-private-key-file-mac-key")));
|
||||
byte[] bytesToHash = new byte[prefixSize + keyType.Length + prefixSize + encryptionType.Length + prefixSize + Comment.Length + prefixSize + publicBuffer.Length + prefixSize + privateBuffer.Length];
|
||||
|
||||
using (var bw = new BinaryWriter(new MemoryStream(bytesToHash)))
|
||||
{
|
||||
PutPrefixed(bw, Encoding.ASCII.GetBytes(keyType));
|
||||
PutPrefixed(bw, Encoding.ASCII.GetBytes(encryptionType));
|
||||
PutPrefixed(bw, Encoding.ASCII.GetBytes(Comment));
|
||||
PutPrefixed(bw, publicBuffer);
|
||||
PutPrefixed(bw, privateBuffer);
|
||||
}
|
||||
|
||||
var hash = string.Join("", hmacSha1.ComputeHash(bytesToHash).Select(x => $"{x:x2}"));
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("PuTTY-User-Key-File-2: " + keyType);
|
||||
sb.AppendLine("Encryption: " + encryptionType);
|
||||
sb.AppendLine("Comment: " + Comment);
|
||||
|
||||
var publicLines = SpliceText(publicBlob, lineLength);
|
||||
sb.AppendLine("Public-Lines: " + publicLines.Length);
|
||||
foreach (var line in publicLines)
|
||||
{
|
||||
sb.AppendLine(line);
|
||||
}
|
||||
|
||||
var privateLines = SpliceText(privateBlob, lineLength);
|
||||
sb.AppendLine("Private-Lines: " + privateLines.Length);
|
||||
foreach (var line in privateLines)
|
||||
{
|
||||
sb.AppendLine(line);
|
||||
}
|
||||
|
||||
sb.AppendLine("Private-MAC: " + hash);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void PutPrefixed(BinaryWriter bw, byte[] bytes, bool addLeadingNull = false)
|
||||
{
|
||||
bw.Write(BitConverter.GetBytes(bytes.Length + (addLeadingNull ? 1 : 0)).Reverse().ToArray());
|
||||
if (addLeadingNull)
|
||||
bw.Write(new byte[] { 0x00 });
|
||||
bw.Write(bytes);
|
||||
}
|
||||
|
||||
private static string[] SpliceText(string text, int lineLength)
|
||||
{
|
||||
return Regex.Matches(text, ".{1," + lineLength + "}").Cast<Match>().Select(m => m.Value).ToArray();
|
||||
}
|
||||
|
||||
private static int GetPrefixSize(byte[]? bytes)
|
||||
{
|
||||
if (bytes is null)
|
||||
return 0;
|
||||
|
||||
return CheckIsNeddPadding(bytes) ? paddedPrefixSize : prefixSize;
|
||||
}
|
||||
|
||||
private static bool CheckIsNeddPadding(byte[] bytes)
|
||||
{
|
||||
if (bytes is null || bytes.Length == 0)
|
||||
return false;
|
||||
|
||||
// 128 == 10000000
|
||||
// This means that the number of bits can be divided by 8.
|
||||
// According to the algorithm in putty, you need to add a padding.
|
||||
return bytes[0] >= 128;
|
||||
}
|
||||
}
|
||||
63
Jenkinsfile
vendored
63
Jenkinsfile
vendored
@@ -1,63 +0,0 @@
|
||||
#!groovy
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def reportGeneratorPath = "${jobDir}\\packages\\ReportGenerator.3.0.2\\tools\\ReportGenerator.exe"
|
||||
def testResultFilePrefix = "TestResult"
|
||||
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"
|
||||
def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml"
|
||||
def testResultFileAcceptance = "${testResultFilePrefix}_AcceptanceTests.xml"
|
||||
def coverageReport = "code_coverage_report.xml"
|
||||
def codeCoverageHtml = "CodeCoverageReport.html"
|
||||
|
||||
stage ('Checkout Branch') {
|
||||
checkout scm
|
||||
bat "del /Q \"${jobDir}\\${testResultFilePrefix}*.xml\""
|
||||
}
|
||||
|
||||
stage ('Restore NuGet Packages') {
|
||||
def nugetPath = "C:\\nuget.exe"
|
||||
bat "${nugetPath} restore ${solutionFilePath}"
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Normal)') {
|
||||
bat "\"${msBuild}\" /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${msBuild}\" /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Normal, w/coverage)') {
|
||||
try {
|
||||
bat "\"${openCoverPath}\" -register:user -target:\"${nunitConsolePath}\" -targetargs:\"\"${jobDir}\\mRemoteNGTests\\bin\\debug\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86\" -output:\"${coverageReport}\""
|
||||
}
|
||||
catch (ex) {
|
||||
nunit testResultsPattern: "${testResultFilePrefix}*.xml"
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
try {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\debug portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86"
|
||||
}
|
||||
catch (ex) {
|
||||
nunit testResultsPattern: "${testResultFilePrefix}*.xml"
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run Acceptance Tests') {
|
||||
try {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNG.Specs\\bin\\debug\\mRemoteNG.Specs.dll\" --result=${testResultFileAcceptance} --x86"
|
||||
}
|
||||
catch (ex) {
|
||||
nunit testResultsPattern: "${testResultFilePrefix}*.xml"
|
||||
throw ex
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.10.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def testResultFilePrefix = "TestResult"
|
||||
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"
|
||||
def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml"
|
||||
def coverageReport = "code_coverage_report.xml"
|
||||
|
||||
|
||||
stage ('Clean output dir') {
|
||||
bat script: "rmdir /S /Q \"${jobDir}\\Release\" 2>nul", returnStatus: true
|
||||
}
|
||||
|
||||
stage ('Checkout Branch') {
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: [[name: '*/${TargetBranch}']],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[
|
||||
credentialsId: '9c3fbff4-5b90-402f-a298-00e607fcec87',
|
||||
url: 'https://github.com/mRemoteNG/mRemoteNG.git'
|
||||
]]
|
||||
])
|
||||
}
|
||||
|
||||
stage ('Restore NuGet Packages') {
|
||||
def nugetPath = "C:\\nuget.exe"
|
||||
bat "${nugetPath} restore ${solutionFilePath}"
|
||||
}
|
||||
|
||||
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
|
||||
stage ('Build mRemoteNG (Normal - MSI)') {
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Normal - MSI)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86"
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86"
|
||||
}
|
||||
|
||||
stage ('Generate UpdateCheck Files') {
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\""
|
||||
archiveArtifacts artifacts: "Release\\*.txt", caseSensitive: false, onlyIfSuccessful: true
|
||||
}
|
||||
|
||||
stage ('Publish to GitHub') {
|
||||
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
|
||||
def releaseFolder = "${jobDir}\\Release"
|
||||
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell
|
||||
def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString()
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ReleaseFolderPath \"${releaseFolder}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
**NOTICE: This project is currently stalled and we are transitioning to a new maintainer. Please see [this stickied issue](https://github.com/mRemoteNG/mRemoteNG/issues/1949) for more details. Development help would be greatly appreciated.**
|
||||
**NOTICE: This project currently transited to a new maintainer. Development help would be greatly appreciated.**
|
||||
|
||||
<br/><br/>
|
||||
<p align="center">
|
||||
<img width="500" src="https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/Tools/img/logo.png">
|
||||
<img width="450" src="https://github.com/mRemoteNG/mRemoteNG/blob/mRemoteNGProjectFiles/Header_dark.png">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -20,10 +20,12 @@
|
||||
<a href="https://twitter.com/mremoteng">
|
||||
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/mremoteng?color=%231DA1F2&label=Twitter&logo=Twitter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://gitter.im/mRemoteNG/PublicChat">
|
||||
<img alt="Gitter" src="https://img.shields.io/gitter/room/mRemoteNG/PublicChat?label=Join%20the%20Chat&logo=Gitter&style=flat-square">
|
||||
<a href="https://app.element.io/#/room/#mremoteng:matrix.org">
|
||||
<img alt="Element" src="https://img.shields.io/matrix/mremoteng:matrix.org?label=Join%20to%20chat%20about%20mRemoteNG&logo=element&style=social&link=https://app.element.io/#/room/#mremoteng:matrix.org">
|
||||
</a>
|
||||
<a href="https://www.paypal.me/DavidSparer">
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://www.paypal.com/paypalme/mremoteng">
|
||||
<img alt="PayPal" src="https://img.shields.io/badge/%24-PayPal-blue.svg?label=Donate&logo=PayPal&style=flat-square">
|
||||
</a>
|
||||
<a href="bitcoin:16fUnHUM3k7W9Fvpc6dug7TAdfeGEcLbSg">
|
||||
@@ -41,15 +43,18 @@
|
||||
<a href='https://mremoteng.readthedocs.io/en/latest/?badge=latest'>
|
||||
<img src='https://readthedocs.org/projects/mremoteng/badge/?version=latest' alt='Documentation Status' />
|
||||
</a>
|
||||
<a href="https://gurubase.io/g/mremoteng">
|
||||
<img alt="Gurubase" src="https://img.shields.io/badge/Gurubase-Ask%20mRemoteNG%20Guru-006BFF?style=flat-square">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
| Update Channel | Build Status | Downloads |
|
||||
| Channel | Build Status | Downloads |
|
||||
| ---------------|--------------|-----------|
|
||||
| Stable | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/master) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76.20) |
|
||||
| Prerelease | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.77.1) |
|
||||
| Nightly build | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.77.2) |
|
||||
| Stable |  | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76.20) |
|
||||
| Preview |  | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.77.1) |
|
||||
| Nightly |  | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/2023.03.03-v1.77.3-nb) |
|
||||
|
||||
## Features
|
||||
|
||||
@@ -70,26 +75,14 @@ For a detailed feature list and general usage support, refer to the [Documentati
|
||||
|
||||
### Supported Operating Systems
|
||||
|
||||
- [Windows 11](https://en.wikipedia.org/wiki/Windows_11)
|
||||
- [Windows 10](https://en.wikipedia.org/wiki/Windows_10)
|
||||
- [Windows 8.1](https://en.wikipedia.org/wiki/Windows_8.1)
|
||||
- [Windows Server 2022](https://en.wikipedia.org/wiki/Windows_Server_2022)
|
||||
- [Windows Server 2019](https://en.wikipedia.org/wiki/Windows_Server_2019)
|
||||
- [Windows Server 2016](https://en.wikipedia.org/wiki/Windows_Server_2016)
|
||||
- [Windows Server 2012 R2](https://en.wikipedia.org/wiki/Windows_Server_2012_R2)
|
||||
|
||||
### Packaging
|
||||
|
||||
Downloads are provided in three different packages.
|
||||
|
||||
#### Binary package
|
||||
|
||||
The binary package of mRemoteNG is a compiled version of mRemoteNG which comes in an MSI installer.
|
||||
This is the most common way to install mRemoteNG and get up and running.
|
||||
|
||||
#### Portable package
|
||||
|
||||
The portable package contains a modified version of the executable which stores and loads all your settings from files in the application's directory.
|
||||
This package can be used to run mRemoteNG from a USB stick and preserve your configuration wherever you go.
|
||||
|
||||
#### Source package
|
||||
|
||||
This contains the source code from which mRemoteNG is build.
|
||||
@@ -97,15 +90,15 @@ You will need to compile it yourself using Visual Studio.
|
||||
|
||||
### Minimum Requirements
|
||||
|
||||
* [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads)
|
||||
* [Microsoft .NET Framework 4.0](https://www.microsoft.com/en-us/download/details.aspx?id=17851)
|
||||
* [Microsoft Visual C++ Redistributable for Visual Studio 2015 - 2022](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads)
|
||||
* [Microsoft .NET 6.0 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/6.0)
|
||||
* Microsoft Terminal Service Client 6.0 or later
|
||||
* Needed if you use RDP. mstscax.dll and/or msrdp.ocx be registered.
|
||||
* [Citrix ICA Client](https://www.citrix.com/downloads/citrix-receiver.html)
|
||||
* Needed if you use ICA. wfica.ocx must be registered
|
||||
|
||||
### Download
|
||||
|
||||
> :star: Starting Windows 11 you can use winget to install mRemoteNG. Just run `winget install -e --id mRemoteNG.mRemoteNG`
|
||||
|
||||
mRemoteNG is available as a redistributable MSI package or as a portable ZIP package and can be downloaded from the following locations:
|
||||
* [GitHub](https://github.com/mRemoteNG/mRemoteNG/releases)
|
||||
* [Project Website](https://mremoteng.org/download)
|
||||
@@ -114,56 +107,36 @@ mRemoteNG is available as a redistributable MSI package or as a portable ZIP pac
|
||||
|
||||
The MSI package of mRemoteNG can be installed using the command line:
|
||||
|
||||
`msiexec /i C:\Path\To\mRemoteNG-Installer.exe [INSTALLDIR=value] [IGNOREPREREQUISITES=value]`
|
||||
`msiexec /i [/qn] C:\Path\To\mRemoteNG-Installer.exe [INSTALLDIR=value] [IGNOREPREREQUISITES=value] [/lv* <log path>]`
|
||||
|
||||
| Property | Value | Description |
|
||||
| Argument/Property | Value | Description |
|
||||
|-|-|-|
|
||||
| INSTALLDIR | `folder path` | This allows you to set the installation directory from the command line. For paths that contain spaces, enclose the path in double quotes (""). This overrides any value found in the registry. |
|
||||
| /qn | `Silent Installation` | Will run the installer silently in the background. |
|
||||
| /lv* | `Silent Installation` | Will write a logfile to the specified location. (For paths that contain spaces, enclose the path in double quotes) |
|
||||
| INSTALLDIR | `folder path` | Allows you to set the installation directory from the command line. (For paths that contain spaces, enclose the path in double quotes) |
|
||||
| IGNOREPREREQUISITES | `0` or `1` | When set to `1`, the installer will not be halted if any prerequisite check is not met. You must still run the installer as administrator. |
|
||||
|
||||
#### Examples
|
||||
|
||||
**Install to a custom folder**
|
||||
|
||||
`msiexec /i C:\Path\To\mRemoteNG-Installer.msi INSTALLDIR="D:\Work Apps\mRemoteNG"`
|
||||
|
||||
**Ignore prerequisites during a normal install**
|
||||
|
||||
`msiexec /i C:\Path\To\mRemoteNG-Installer.msi IGNOREPREREQUISITES=1`
|
||||
|
||||
**Ignore prerequisites during a silent install**
|
||||
|
||||
`msiexec /i C:\Path\To\mRemoteNG-Installer.msi /qn IGNOREPREREQUISITES=1`
|
||||
|
||||
### Troubleshooting installation
|
||||
|
||||
Turn on verbose logging by using the `/lv* <log path>` argument at the command line.
|
||||
|
||||
`msiexec /i C:\Path\To\mRemoteNG-Installer.msi /l*v C:\mremoteng_install.log`
|
||||
|
||||
## Uninstall
|
||||
|
||||
### Standard Uninstall
|
||||
|
||||
mRemoteNG basic binary package can be uninstalled with Windows Control Panel. If for some reason it does not work please
|
||||
follow information provided below for Manual Uninstall.
|
||||
|
||||
### Manual Uninstall
|
||||
## Manual Uninstall
|
||||
|
||||
_If you are using the Portable version, simply deleting the folder that contains mRemoteNG should be sufficient. These uninstall instructions are only necessary for the normal binary .MSI installed version of mRemoteNG_
|
||||
|
||||
* Delete the folder where mRemoteNG was installed. By default, this is:
|
||||
`%PROGRAMFILES%\mRemoteNG`
|
||||
`%PROGRAMFILES%\mRemoteNG` (for versions before 1.77 on a x64 Windows its `%programfiles(x86)%\mRemoteNG`)
|
||||
|
||||
* Delete the mRemoteNG install entry from one of the following locations. Search for "mRemoteNG" in the DisplayName field:
|
||||
* x86: ``HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\``
|
||||
* x64: ``HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\``
|
||||
* Delete the mRemoteNG install entry from the following location. You may search for "mRemoteNG" in the DisplayName field:
|
||||
* x86 Windows or mRemoteNG starting with v1.77: `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\`
|
||||
* x64 Windows and mRemoteNG before 1.77: `HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\`
|
||||
* Remove the following registry key: `HKLM\SOFTWARE\mRemoteNG` (on x64 Windows with mRemoteNG before 1.77 it's `HKLM\SOFTWARE\WOW6432Node\mRemoteNG`)
|
||||
|
||||
* (Optional) If you would also like to delete user data remove `%LOCALAPPDATA%\mRemoteNG`
|
||||
* (Optional) If you would also like to remove the connection configuration, delete `%APPDATA%\mRemoteNG`
|
||||
|
||||
* (Optional) If no other software uses it, the "Microsoft Windows Desktop Runtime" may be uninstalled too.
|
||||
|
||||
## Featured Projects
|
||||
|
||||
* [PSmRemoteNG](https://github.com/realslacker/PSmRemoteNG) A module to create mRemoteNG connection files from PowerShell.
|
||||
* [mRemoteNGOpenVPN](https://github.com/T3los/mRemoteNGOpenVPN) A script that can be embedded as an external tool to control OpenVPN.
|
||||
|
||||
## Contribute
|
||||
|
||||
@@ -177,5 +150,5 @@ Check out the [Wiki page](https://github.com/mRemoteNG/mRemoteNG/wiki) on how to
|
||||
|
||||
</br>
|
||||
<p align="center">
|
||||
<img alt="Developed with ReSharper" src="https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/Tools/img/icon_ReSharper.png">
|
||||
<img alt="Developed with ReSharper" src="https://github.com/mRemoteNG/mRemoteNG/blob/mRemoteNGProjectFiles/icon_ReSharper.png">
|
||||
</p>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,31 +0,0 @@
|
||||
7-Zip Extra
|
||||
~~~~~~~~~~~
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (C) 1999-2019 Igor Pavlov.
|
||||
|
||||
7-Zip Extra files are under the GNU LGPL license.
|
||||
|
||||
|
||||
Notes:
|
||||
You can use 7-Zip Extra on any computer, including a computer in a commercial
|
||||
organization. You don't need to register or pay for 7-Zip.
|
||||
|
||||
|
||||
GNU LGPL information
|
||||
--------------------
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You can receive a copy of the GNU Lesser General Public License from
|
||||
http://www.gnu.org/
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
7-Zip Extra history
|
||||
-------------------
|
||||
|
||||
This file contains only information about changes related to that package exclusively.
|
||||
The full history of changes is listed in history.txt in main 7-Zip program.
|
||||
|
||||
|
||||
19.00 2019-02-21
|
||||
-------------------------
|
||||
- Encryption strength for 7z archives was increased:
|
||||
the size of random initialization vector was increased from 64-bit to 128-bit,
|
||||
and the pseudo-random number generator was improved.
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
18.06 2018-12-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
|
||||
and there are minor changes in compression ratio.
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
18.05 2018-04-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased
|
||||
by 8% for fastest/fast compression levels and
|
||||
by 3% for normal/maximum compression levels.
|
||||
|
||||
|
||||
18.03 beta 2018-03-04
|
||||
-------------------------
|
||||
- The speed for single-thread LZMA/LZMA2 decoding
|
||||
was increased by 30% in x64 version and by 3% in x86 version.
|
||||
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
|
||||
if there are multiple independent data chunks in LZMA2 stream.
|
||||
|
||||
|
||||
9.35 beta 2014-12-07
|
||||
------------------------------
|
||||
- SFX modules were moved to LZMA SDK package.
|
||||
|
||||
|
||||
9.34 alpha 2014-06-22
|
||||
------------------------------
|
||||
- Minimum supported system now is Windows 2000 for EXE and DLL files.
|
||||
- all EXE and DLL files use msvcrt.dll.
|
||||
- 7zr.exe now support AES encryption.
|
||||
|
||||
|
||||
9.18 2010-11-02
|
||||
------------------------------
|
||||
- New small SFX module for installers.
|
||||
|
||||
|
||||
9.17 2010-10-04
|
||||
------------------------------
|
||||
- New 7-Zip plugin for FAR Manager x64.
|
||||
|
||||
|
||||
9.10 2009-12-30
|
||||
------------------------------
|
||||
- 7-Zip for installers now supports LZMA2.
|
||||
|
||||
|
||||
9.09 2009-12-12
|
||||
------------------------------
|
||||
- LZMA2 compression method support.
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
4.65 2009-02-03
|
||||
------------------------------
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
4.38 beta 2006-04-13
|
||||
------------------------------
|
||||
- SFX for installers now supports new properties in config file:
|
||||
Progress, Directory, ExecuteFile, ExecuteParameters.
|
||||
|
||||
|
||||
4.34 beta 2006-02-27
|
||||
------------------------------
|
||||
- ISetProperties::SetProperties:
|
||||
it's possible to specify desirable number of CPU threads:
|
||||
PROPVARIANT: name=L"mt", vt = VT_UI4, ulVal = NumberOfThreads
|
||||
If "mt" is not defined, 7za.dll will check number of processors in system to set
|
||||
number of desirable threads.
|
||||
Now 7za.dll can use:
|
||||
2 threads for LZMA compressing
|
||||
N threads for BZip2 compressing
|
||||
4 threads for BZip2 decompressing
|
||||
Other codecs use only one thread.
|
||||
Note: 7za.dll can use additional "small" threads with low CPU load.
|
||||
- It's possible to call ISetProperties::SetProperties to specify "mt" property for decoder.
|
||||
|
||||
|
||||
4.33 beta 2006-02-05
|
||||
------------------------------
|
||||
- Compressing speed and Memory requirements were increased.
|
||||
Default dictionary size was increased: Fastest: 64 KB, Fast: 1 MB,
|
||||
Normal: 4 MB, Max: 16 MB, Ultra: 64 MB.
|
||||
- 7z/LZMA now can use only these match finders: HC4, BT2, BT3, BT4
|
||||
|
||||
|
||||
4.27 2005-09-21
|
||||
------------------------------
|
||||
- Some GUIDs/interfaces were changed.
|
||||
IStream.h:
|
||||
ISequentialInStream::Read now works as old ReadPart
|
||||
ISequentialOutStream::Write now works as old WritePart
|
||||
@@ -1,124 +0,0 @@
|
||||
7-Zip Extra 19.00
|
||||
-----------------
|
||||
|
||||
7-Zip Extra is package of extra modules of 7-Zip.
|
||||
|
||||
7-Zip Copyright (C) 1999-2019 Igor Pavlov.
|
||||
|
||||
7-Zip is free software. Read License.txt for more information about license.
|
||||
|
||||
Source code of binaries can be found at:
|
||||
http://www.7-zip.org/
|
||||
|
||||
This package contains the following files:
|
||||
|
||||
7za.exe - standalone console version of 7-Zip with reduced formats support.
|
||||
7za.dll - library for working with 7z archives
|
||||
7zxa.dll - library for extracting from 7z archives
|
||||
License.txt - license information
|
||||
readme.txt - this file
|
||||
|
||||
Far\ - plugin for Far Manager
|
||||
x64\ - binaries for x64
|
||||
|
||||
|
||||
All 32-bit binaries can work in:
|
||||
Windows 2000 / 2003 / 2008 / XP / Vista / 7 / 8 / 10
|
||||
and in any Windows x64 version with WoW64 support.
|
||||
All x64 binaries can work in any Windows x64 version.
|
||||
|
||||
All binaries use msvcrt.dll.
|
||||
|
||||
7za.exe
|
||||
-------
|
||||
|
||||
7za.exe - is a standalone console version of 7-Zip with reduced formats support.
|
||||
|
||||
Extra: 7za.exe : support for only some formats of 7-Zip.
|
||||
7-Zip: 7z.exe with 7z.dll : support for all formats of 7-Zip.
|
||||
|
||||
7za.exe and 7z.exe from 7-Zip have same command line interface.
|
||||
7za.exe doesn't use external DLL files.
|
||||
|
||||
You can read Help File (7-zip.chm) from 7-Zip package for description
|
||||
of all commands and switches for 7za.exe and 7z.exe.
|
||||
|
||||
7za.exe features:
|
||||
|
||||
- High compression ratio in 7z format
|
||||
- Supported formats:
|
||||
- Packing / unpacking: 7z, xz, ZIP, GZIP, BZIP2 and TAR
|
||||
- Unpacking only: Z, lzma, CAB.
|
||||
- Highest compression ratio for ZIP and GZIP formats.
|
||||
- Fast compression and decompression
|
||||
- Strong AES-256 encryption in 7z and ZIP formats.
|
||||
|
||||
Note: LZMA SDK contains 7zr.exe - more reduced version of 7za.exe.
|
||||
But you can use 7zr.exe as "public domain" code.
|
||||
|
||||
|
||||
|
||||
DLL files
|
||||
---------
|
||||
|
||||
7za.dll and 7zxa.dll are reduced versions of 7z.dll from 7-Zip.
|
||||
7za.dll and 7zxa.dll support only 7z format.
|
||||
Note: 7z.dll is main DLL file that works with all archive types in 7-Zip.
|
||||
|
||||
7za.dll and 7zxa.dll support the following decoding methods:
|
||||
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES, BZip2, Deflate.
|
||||
|
||||
7za.dll also supports 7z encoding with the following encoding methods:
|
||||
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES.
|
||||
|
||||
7za.dll and 7zxa.dll work via COM interfaces.
|
||||
But these DLLs don't use standard COM interfaces for objects creating.
|
||||
|
||||
Look also example code that calls DLL functions (in source code of 7-Zip):
|
||||
|
||||
7zip\UI\Client7z
|
||||
|
||||
Another example of binary that uses these interface is 7-Zip itself.
|
||||
The following binaries from 7-Zip use 7z.dll:
|
||||
- 7z.exe (console version)
|
||||
- 7zG.exe (GUI version)
|
||||
- 7zFM.exe (7-Zip File Manager)
|
||||
|
||||
Note: The source code of LZMA SDK also contains the code for similar DLLs
|
||||
(DLLs without BZip2, Deflate support). And these files from LZMA SDK can be
|
||||
used as "public domain" code. If you use LZMA SDK files, you don't need to
|
||||
follow GNU LGPL rules, if you want to change the code.
|
||||
|
||||
|
||||
|
||||
|
||||
License FAQ
|
||||
-----------
|
||||
|
||||
Can I use the EXE or DLL files from 7-Zip in a commercial application?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Yes, but you are required to specify in documentation for your application:
|
||||
(1) that you used parts of the 7-Zip program,
|
||||
(2) that 7-Zip is licensed under the GNU LGPL license and
|
||||
(3) you must give a link to www.7-zip.org, where the source code can be found.
|
||||
|
||||
|
||||
Can I use the source code of 7-Zip in a commercial application?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Since 7-Zip is licensed under the GNU LGPL you must follow the rules of that license.
|
||||
In brief, it means that any LGPL'ed code must remain licensed under the LGPL.
|
||||
For instance, you can change the code from 7-Zip or write a wrapper for some
|
||||
code from 7-Zip and compile it into a DLL; but, the source code of that DLL
|
||||
(including your modifications / additions / wrapper) must be licensed under
|
||||
the LGPL or GPL.
|
||||
Any other code in your application can be licensed as you wish. This scheme allows
|
||||
users and developers to change LGPL'ed code and recompile that DLL. That is the
|
||||
idea of free software. Read more here: http://www.gnu.org/.
|
||||
|
||||
|
||||
|
||||
Note: You can look also LZMA SDK, which is available under a more liberal license.
|
||||
|
||||
|
||||
---
|
||||
End of document
|
||||
38
Tools/cert/CodeSigning_Cert_mRemoteNG_Certum.enc
Normal file
38
Tools/cert/CodeSigning_Cert_mRemoteNG_Certum.enc
Normal file
@@ -0,0 +1,38 @@
|
||||
U2FsdGVkX1/uEeToOEIrunpoPNl7NUYNQfI+ixMzGgKX0DlHZxa/PonAVd9NoAE+
|
||||
dqWegkN8fa/M2HcW8moN5sN0yS88amG8cfwRZNRSgRB4IxDdYPjM/iX7y8FjUh9R
|
||||
OZnGhq1rAkqcf7ASAdZfQDSFOAEDPQgByN4IB2j/G3ueqV3jf5sWWiM0ielcorWX
|
||||
jXuEL7uIk9diI3Qh3BVqmrotzErzqTTLB4DWoL1aWqRRYH+exKahfcMT3C9r+tul
|
||||
ETH6o1im3kdYzFgHl58FmihbHa+h1+c+DWVGGXRxJPw1DZfg8/+ldIy8J75aWimz
|
||||
2MX+PiBVQj+wYlSSkQLj2EdbpSERlinE1O55ldwpbnMPAlYCgFRdO3/hiB6LiLLt
|
||||
n9s8f32HLNG20Mk1oxXdN9VPOw+RwQpUf6Zfcyps6e/9EFKBLnwq4cYwM/dHRuez
|
||||
w48EJX5wKzpukHn2UFg5aCRGYU/4NyUn+AlIjjCMBWY1R0uBhC340cl6YqoPFN12
|
||||
clzbS6JdQS+ktusCeaKcsj2iknVqQrGY81LKrTaQZdfehGwAn9pMWE3iWRX80yzO
|
||||
s08lpmHfPK4uhtlyIbdReLn4n7hvB8KRVa7Foms+4wpEwKrL8KF/8CYc89Tm3PSD
|
||||
LCrLr7rzCHh51ncJXHAwZqY2ZRLnQBVwhIRsFYyZ595b89tuDY00sYpWnTKzWubK
|
||||
UD993CmYKg1cA+mj6NR6iSmecawsUz68nI/nmHM2APE5cCCHSK3lz40e9Z9Hmy5Y
|
||||
kVS6c86a+gwNyn4F9t3iISdj2vIOwGMVWQLeY+nwpiKnnOuI0XPtIMjNbhoaDToT
|
||||
kph2ZVjqbpmYHgTSX71v8Y16Stl+p/dZn0dE2d4JhxOJxDN//H6y7mOwg8DYX9GP
|
||||
rFBMIEWyEQyEFYTmWgztQ5KU89w0lV1qiWpaiWR/IDkGbUzHR8ELp4NHYPbZnuYa
|
||||
FFXooJGPsQ02ioXPm18Lkhloo63lANgyBE0jc1x9hPrI0oVn1wTkKdeW13IbHzrn
|
||||
VsGXeZz06bB46QChXUPmQ49sNkAXcMDnfNFM9ayUa8eVmNx9fWabtBy8qs7rpdv0
|
||||
1y/2ud4Da9t7SAUvxwI65+b2Ytk05pLFLmQYb01g4BpBDxbJW3yw3CqKgMnLoZ3t
|
||||
s2kiUpn7FEQU8jbpbFV+UB4DdJgm8S7o1gbTEWYTscZ7l+oLCmQgMYoi/EJDDIa2
|
||||
cCSdGy4p7kLlLUoO438Mz36+FDf6qX2B86ezVdNnXQb3UPljjDxiOFM6NkI3HTpl
|
||||
RqxjBg8JdrwoQ1UMha6ucDKhPXq1xkg0dpO9QyjxywssG3krgQ5Py64s5Xu7IgQm
|
||||
AzmwGTZ6gFZlDTr9SpJkiucF9vexCo6JHHkF8OjhS49FanqB8otJvg5JclVugP51
|
||||
LcqqvuMkAsFago261SNcOhgtR6nV5B9QgHyr66c6YnTlwt07T1Qq3S1lw2x0Eccs
|
||||
PKbJDVU5rAHiM71QYmwsuoC8qkYPTtVPIoUTs+5u5aLywVoLejr1dE5twNXy5PYY
|
||||
fDwubg0YG3kchvv85N3epZ1h50ADq3W3msU9bWDKWwdwIbpGq+dwjkLssBQmjVtI
|
||||
R8rGbt1DgL7xtRNF9ESnWVkfHJvJu/5oD6wGAU/oIfBxVON0VYb1evc8wRdQTbDH
|
||||
Dnt+aKwcSPYdyGVRKfRtBGvEZ8rB5hzCXQnS795L0imdfXjBSJn7Pnl9VwpcB3Pr
|
||||
aZ6s0GcB8kYDEXzjv+o7JF6k5i2I+sVGwvFVGIoVd/Igq2ysrk/GfWVov0SUu78A
|
||||
JeHYdtRuKwXOdZw2cjZQ72bvFaHOuoXrQnyKyZDWRyu0NB5HLW75v/YEbr4msIm9
|
||||
E+3HFwRvKSTfUx/M4NgVKrgsHDeBRD4tLNx/SerQvqaplunM7OfAtULucveUhwSo
|
||||
vT6uNK3URe1qDgX554cz8c6+KrkglTLFMuKfNWj3q/uSM0BxTTD9QgorNdlMmErH
|
||||
TfV/ZpZACpuMFRbC5xQRkCG1x4U12pdPbtIkGtVBJROEXhP1aw3BDWwrIN7zSgfj
|
||||
8I4OF4fbj/rSuvI4klzi1zlUMQQnenlRURE+7DKRxtWipJhW9vtDI0LXN7gGfmbR
|
||||
73uR3YUny6zUJ0svqaWj4Eo6t3g99nmk4D2hm/622dRksv2HqEQiq29jJxlcbdZB
|
||||
PU96wOp54s/BzgodyI5dh+xL06Obr9AltLV9vw3iK0VBZqquj9FuhvWC1tYlZQJF
|
||||
AOgVDOGUZzmAJXftI7gaohFBwsT5tAHQtBuY7tB3b1hrnfrFb9FTNxGZJKcIH3p4
|
||||
dOAvedsfuq+2/lU9iM4tX9fjSzfnGRZRuKCGDSdhE6EDik9/f2kSCoY9z0zJwdZH
|
||||
324TpGbZNbgcwgHDL9i5Nsnaua5yxtr0/Fr1We1tvn0=
|
||||
Binary file not shown.
@@ -1,15 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying PUTTYNG to correct directory"
|
||||
Copy-Item -Path (Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\Resources\PuTTYNG.exe") -Destination $TargetDir -Force
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,21 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
$SourcePath,
|
||||
|
||||
[string]
|
||||
$DestinationDir
|
||||
)
|
||||
|
||||
Write-Host $SourcePath
|
||||
Write-Host $DestinationDir
|
||||
|
||||
if (!(Test-Path -Path $DestinationDir))
|
||||
{
|
||||
New-Item -Path $DestinationDir -ItemType "directory"
|
||||
}
|
||||
|
||||
$sourceFiles = Get-ChildItem -Path $SourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
|
||||
foreach ($item in $sourceFiles)
|
||||
{
|
||||
Copy-Item -Path $item.FullName -Destination $DestinationDir -Force
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying THEMES folder to output"
|
||||
|
||||
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteNG\Resources\Themes' )
|
||||
$DestinationDir = [io.path]::combine($TargetDir , 'Themes')
|
||||
|
||||
robocopy $sourceFiles $DestinationDir *.vstheme /s
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,17 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying TILES folder to output"
|
||||
|
||||
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteNG\Resources\Tiles' )
|
||||
robocopy $sourceFiles $TargetDir *.*
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,17 +1,27 @@
|
||||
#Requires -Version 4.0
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$WebsiteTargetOwner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$WebsiteTargetRepository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$false)]
|
||||
$PreTagName = "",
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("Stable","Beta","Development")]
|
||||
$UpdateChannel
|
||||
$ProjectName
|
||||
)
|
||||
|
||||
|
||||
|
||||
function New-MsiUpdateFileContent {
|
||||
param (
|
||||
[System.IO.FileInfo]
|
||||
@@ -25,7 +35,7 @@ function New-MsiUpdateFileContent {
|
||||
|
||||
$version = $MsiFile.BaseName -replace "[a-zA-Z-]*"
|
||||
$certThumbprint = (Get-AuthenticodeSignature -FilePath $MsiFile).SignerCertificate.Thumbprint
|
||||
$hash = Get-FileHash -Algorithm SHA512 $MsiFile | % { $_.Hash }
|
||||
$hash = Get-FileHash -Algorithm SHA512 $MsiFile | ForEach-Object { $_.Hash }
|
||||
|
||||
$fileContents = `
|
||||
"Version: $version
|
||||
@@ -49,7 +59,7 @@ function New-ZipUpdateFileContent {
|
||||
)
|
||||
|
||||
$version = $ZipFile.BaseName -replace "[a-zA-Z-]*"
|
||||
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | % { $_.Hash }
|
||||
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | ForEach-Object { $_.Hash }
|
||||
|
||||
$fileContents = `
|
||||
"Version: $version
|
||||
@@ -64,7 +74,7 @@ function Resolve-UpdateCheckFileName {
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("Stable","Beta","Development")]
|
||||
[ValidateSet("Stable","Preview","Nightly")]
|
||||
$UpdateChannel,
|
||||
|
||||
[string]
|
||||
@@ -75,8 +85,8 @@ function Resolve-UpdateCheckFileName {
|
||||
|
||||
$fileName = ""
|
||||
|
||||
if ($UpdateChannel -eq "Beta") { $fileName += "beta-" }
|
||||
elseif ($UpdateChannel -eq "Development") { $fileName += "dev-" }
|
||||
if ($UpdateChannel -eq "Preview") { $fileName += "preview-" }
|
||||
elseif ($UpdateChannel -eq "Nightly") { $fileName += "nightly-" }
|
||||
|
||||
$fileName += "update"
|
||||
|
||||
@@ -87,23 +97,72 @@ function Resolve-UpdateCheckFileName {
|
||||
Write-Output $fileName
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# determine update channel
|
||||
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
|
||||
Write-Output "UpdateChannel = Nightly"
|
||||
$UpdateChannel = "Nightly"
|
||||
$ModifiedTagName = "$PreTagName-$TagName-NB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
|
||||
Write-Output "UpdateChannel = Preview"
|
||||
$UpdateChannel = "Preview"
|
||||
$ModifiedTagName = "v$TagName-PB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
|
||||
Write-Output "UpdateChannel = Stable"
|
||||
$UpdateChannel = "Stable"
|
||||
$ModifiedTagName = "v" + $TagName.Split("-")[0]
|
||||
} else {
|
||||
$UpdateChannel = ""
|
||||
}
|
||||
|
||||
#$buildFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\mRemoteNG\bin\x64\Release" -Resolve -ErrorAction Ignore
|
||||
$ReleaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
|
||||
|
||||
if ($UpdateChannel -ne "" -and $ReleaseFolder -ne "" -and $WebsiteTargetOwner -and $WebsiteTargetRepository) {
|
||||
|
||||
$releaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
|
||||
$msiFile = Get-ChildItem -Path "$ReleaseFolder\*.msi" -Exclude "*-symbols-*.zip" | Sort-Object LastWriteTime | Select-Object -last 1
|
||||
if (![string]::IsNullOrEmpty($msiFile)) {
|
||||
$msiUpdateContents = New-MsiUpdateFileContent -MsiFile $msiFile -TagName $ModifiedTagName
|
||||
$msiUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Normal
|
||||
Write-Output "`n`nMSI Update Check File Contents ($msiUpdateFileName)`n------------------------------"
|
||||
Tee-Object -InputObject $msiUpdateContents -FilePath "$ReleaseFolder\$msiUpdateFileName"
|
||||
|
||||
# commit msi update txt file
|
||||
if ($env:WEBSITE_UPDATE_ENABLED.ToLower() -eq "true") {
|
||||
if ((Test-Path -Path "$ReleaseFolder\$msiUpdateFileName") -and (-not [string]::IsNullOrEmpty($WebsiteTargetRepository))) {
|
||||
Write-Output "Publish Update File $msiUpdateFileName to $WebsiteTargetRepository"
|
||||
$update_file_content_string = Get-Content "$ReleaseFolder\$msiUpdateFileName" | Out-String
|
||||
Set-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path $msiUpdateFileName -CommitMessage "Build $ModifiedTagName" -Content $update_file_content_string -BranchName main
|
||||
} else {
|
||||
Write-Warning "WARNING: Update file does not exist: $ReleaseFolder\$msiUpdateFileName"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# build msi update file
|
||||
$msiFile = Get-ChildItem -Path "$releaseFolder\*.msi" | sort LastWriteTime | select -last 1
|
||||
$msiUpdateContents = New-MsiUpdateFileContent -MsiFile $msiFile -TagName $TagName
|
||||
$msiUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Normal
|
||||
Write-Output "`n`nMSI Update Check File Contents ($msiUpdateFileName)`n------------------------------"
|
||||
Tee-Object -InputObject $msiUpdateContents -FilePath "$releaseFolder\$msiUpdateFileName"
|
||||
# build zip update file
|
||||
$zipFile = Get-ChildItem -Path "$ReleaseFolder\*.zip" -Exclude "*-symbols-*.zip" | Sort-Object LastWriteTime | Select-Object -last 1
|
||||
if (![string]::IsNullOrEmpty($zipFile)) {
|
||||
$zipUpdateContents = New-ZipUpdateFileContent -ZipFile $zipFile -TagName $ModifiedTagName
|
||||
$zipUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Portable
|
||||
Write-Output "`n`nZip Update Check File Contents ($zipUpdateFileName)`n------------------------------"
|
||||
Tee-Object -InputObject $zipUpdateContents -FilePath "$ReleaseFolder\$zipUpdateFileName"
|
||||
|
||||
# commit zip update txt file
|
||||
if ($env:WEBSITE_UPDATE_ENABLED.ToLower() -eq "true") {
|
||||
if ((Test-Path -Path "$ReleaseFolder\$zipUpdateFileName") -and (-not [string]::IsNullOrEmpty($WebsiteTargetRepository))) {
|
||||
Write-Output "Publish Update File $zipUpdateFileName to $WebsiteTargetRepository"
|
||||
$update_file_content_string = Get-Content "$ReleaseFolder\$zipUpdateFileName" | Out-String
|
||||
Set-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path $zipUpdateFileName -CommitMessage "Build $ModifiedTagName" -Content $update_file_content_string -BranchName main
|
||||
} else {
|
||||
Write-Warning "WARNING: Update file does not exist: $ReleaseFolder\$zipUpdateFileName"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Output "ReleaseFolder not found"
|
||||
}
|
||||
|
||||
|
||||
# build zip update file
|
||||
$zipFile = Get-ChildItem -Path "$releaseFolder\*.zip" | sort LastWriteTime | select -last 1
|
||||
$zipUpdateContents = New-ZipUpdateFileContent -ZipFile $zipFile -TagName $TagName
|
||||
$zipUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Portable
|
||||
Write-Output "`n`nZip Update Check File Contents ($zipUpdateFileName)`n------------------------------"
|
||||
Tee-Object -InputObject $zipUpdateContents -FilePath "$releaseFolder\$zipUpdateFileName"
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
|
||||
2
Tools/decrypt.bat
Normal file
2
Tools/decrypt.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
openssl enc -base64 -aes-256-cbc -md sha512 -pbkdf2 -iter 100000 -d -in cert/CodeSigning_Cert_mRemoteNG_Certum.enc -out cert/CodeSigning_Cert_mRemoteNG_Certum.cer
|
||||
pause
|
||||
2
Tools/encrypt.bat
Normal file
2
Tools/encrypt.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
openssl enc -base64 -aes-256-cbc -md sha512 -pbkdf2 -iter 100000 -e -in cert/CodeSigning_Cert_mRemoteNG_Certum.cer -out cert/CodeSigning_Cert_mRemoteNG_Certum.enc
|
||||
pause
|
||||
@@ -19,27 +19,28 @@ function EditBinCertificateIsValid() {
|
||||
"3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC",
|
||||
"98ED99A67886D020C564923B7DF25E9AC019DF26",
|
||||
"108E2BA23632620C427C570B6D9DB51AC31387FE",
|
||||
"5EAD300DC7E4D637948ECB0ED829A072BD152E17"
|
||||
"5EAD300DC7E4D637948ECB0ED829A072BD152E17",
|
||||
"97221B97098F37A135DCC212E2B41E452BCE51F2"
|
||||
)
|
||||
$file_signature = Get-AuthenticodeSignature -FilePath $Path
|
||||
if (($file_signature.Status -ne "Valid") -or ($valid_microsoft_cert_thumbprints -notcontains $file_signature.SignerCertificate.Thumbprint)) {
|
||||
Write-Warning "Could not validate the signature of $Path"
|
||||
Write-Warning "Could not validate the signature of $Path $($file_signature.SignerCertificate.Thumbprint)"
|
||||
Write-Output "file_signature.SignerCertificate.Thumbprint: $($file_signature.SignerCertificate.Thumbprint)"
|
||||
return $false
|
||||
} else {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ToolCanBeExecuted {
|
||||
param (
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
$null = & $Path
|
||||
Write-Output ($LASTEXITCODE -gt 0)
|
||||
$env:PATHEXT.Contains((Get-Item $Path).Extension.ToUpper())
|
||||
}
|
||||
|
||||
|
||||
$rootSearchPaths = @(
|
||||
[System.IO.Directory]::EnumerateFileSystemEntries("C:\Program Files", "*Visual Studio*", [System.IO.SearchOption]::TopDirectoryOnly),
|
||||
[System.IO.Directory]::EnumerateFileSystemEntries("C:\Program Files (x86)", "*Visual Studio*", [System.IO.SearchOption]::TopDirectoryOnly)
|
||||
@@ -51,7 +52,8 @@ foreach ($searchPath in $rootSearchPaths) {
|
||||
Write-Verbose "Searching in folder '$visualStudioFolder'"
|
||||
$matchingExes = [System.IO.Directory]::EnumerateFileSystemEntries($visualStudioFolder, $FileName, [System.IO.SearchOption]::AllDirectories)
|
||||
foreach ($matchingExe in $matchingExes) {
|
||||
if ((EditBinCertificateIsValid -Path $matchingExe) -and (ToolCanBeExecuted -Path $matchingExe)) {
|
||||
#if ((EditBinCertificateIsValid -Path $matchingExe) -and (ToolCanBeExecuted -Path $matchingExe)) {
|
||||
if (ToolCanBeExecuted -Path $matchingExe) {
|
||||
return $matchingExe
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,32 @@ $githubUrl = 'https://api.github.com'
|
||||
# GitHub doesn't support the default powershell protocol (TLS 1.0)
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
if ($IsAppVeyor) {
|
||||
#$CURRENT_GITHUB_USER = $env:APPVEYOR_REPO_NAME.Split("/")[0]
|
||||
Install-Module -Name PowerShellForGitHub -Scope CurrentUser
|
||||
Set-GitHubConfiguration -DisableTelemetry
|
||||
$PSDefaultParameterValues["*-GitHub*:AccessToken"] = "$env:ACCESS_TOKEN"
|
||||
#New-Item -Path "$Env:APPVEYOR_BUILD_FOLDER\Release" -ItemType Directory -Force
|
||||
}
|
||||
|
||||
function New-TemporaryDirectory {
|
||||
$parent = [System.IO.Path]::GetTempPath()
|
||||
[string] $name = [System.Guid]::NewGuid()
|
||||
$fullTempPath = (Join-Path $parent $name)
|
||||
New-Item -ItemType Directory -Path $fullTempPath
|
||||
return $fullTempPath
|
||||
}
|
||||
|
||||
Function ConvertFrom-Base64($base64) {
|
||||
return [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64))
|
||||
}
|
||||
|
||||
Function ConvertTo-Base64($plain) {
|
||||
return [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($plain))
|
||||
}
|
||||
|
||||
function Publish-GitHubRelease {
|
||||
param (
|
||||
[string]
|
||||
@@ -232,4 +258,4 @@ function New-GitHubReleaseRequestBody {
|
||||
|
||||
$json_body = ConvertTo-Json -InputObject $body_params -Compress
|
||||
Write-Output $json_body
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB |
76
Tools/postbuild.ps1
Normal file
76
Tools/postbuild.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
$CertificatePassword,
|
||||
|
||||
[string[]]
|
||||
$ExcludeFromSigning
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "+============================================================+"
|
||||
Write-Output "| Beginning mRemoteNG Post Build |"
|
||||
Write-Output "+============================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"CertificatePath" = $CertificatePath
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
if ( $ConfigurationName -match "Debug" -and ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) { return; } #skip when Debug local developer build
|
||||
if ( $env:APPVEYOR_PROJECT_NAME -match "(CI)" -and -not ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) { return; } #skip when AppVeyor (CI) build
|
||||
|
||||
$dstPath = "$($SolutionDir)Release"
|
||||
New-Item -Path $dstPath -ItemType Directory -Force
|
||||
|
||||
# $RunInstaller = $TargetDir -match "\\mRemoteNGInstaller\\Installer\\bin\\"
|
||||
# $RunPortable = ( ($Targetdir -match "\\mRemoteNG\\bin\\") -and -not ($TargetDir -match "\\mRemoteNGInstaller\\Installer\\bin\\") )
|
||||
|
||||
if ( ($ConfigurationName -match "Release") -and ($env:APPVEYOR_PROJECT_NAME -notmatch "(CI)") -and -not ([string]::IsNullOrEmpty($env:WEBSITE_TARGET_OWNER)) -and -not ([string]::IsNullOrEmpty($env:WEBSITE_TARGET_REPOSITORY)) ) {
|
||||
|
||||
Write-Output "-Begin Release Portable"
|
||||
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
|
||||
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
|
||||
|
||||
& "$PSScriptRoot\zip_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
|
||||
& "$PSScriptRoot\create_upg_chk_files.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
|
||||
|
||||
& "$PSScriptRoot\update_and_upload_website_release_json_file.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
|
||||
|
||||
Write-Output "-End Release Portable"
|
||||
|
||||
}
|
||||
|
||||
|
||||
Write-Output "End mRemoteNG Post Build"
|
||||
Write-Output ""
|
||||
|
||||
@@ -25,9 +25,12 @@ param (
|
||||
$ExcludeFromSigning
|
||||
)
|
||||
|
||||
Write-Output "+=================================================================+"
|
||||
Write-Output "| Beginning mRemoteNG Installer Post Build |"
|
||||
Write-Output "+=================================================================+"
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "+===========================================================================================+"
|
||||
Write-Output "| Beginning mRemoteNG Installer Post Build |"
|
||||
Write-Output "+===========================================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
@@ -37,8 +40,24 @@ Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\rename_installer_with_version.ps1" -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\copy_release_installer.ps1" -SourcePath $TargetDir -DestinationDir (Join-Path -Path $SolutionDir -ChildPath "Release")
|
||||
if ( $IsAppVeyor -and ($ConfigurationName.ToUpper() -match "RELEASE") -and (($env:APPVEYOR_PROJECT_NAME).ToUpper() -notmatch "(CI)") ) {
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
|
||||
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
|
||||
|
||||
& "$PSScriptRoot\rename_and_copy_installer.ps1" -SolutionDir $SolutionDir -BuildConfiguration $ConfigurationName.Trim()
|
||||
|
||||
& "$PSScriptRoot\create_upg_chk_files.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
|
||||
|
||||
& "$PSScriptRoot\update_and_upload_website_release_json_file.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
|
||||
|
||||
& "$PSScriptRoot\update_and_upload_assemblyinfocs.ps1"
|
||||
|
||||
}
|
||||
|
||||
|
||||
Write-Output "End mRemoteNG Installer Post Build"
|
||||
Write-Output ""
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
$CertificatePassword,
|
||||
|
||||
[string[]]
|
||||
$ExcludeFromSigning
|
||||
)
|
||||
|
||||
Write-Output "+=================================================================+"
|
||||
Write-Output "| Beginning mRemoteNG Post Build |"
|
||||
Write-Output "+=================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"CertificatePath" = $CertificatePath
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
|
||||
& "$PSScriptRoot\copy_puttyng.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\copy_themes.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\copy_tiles.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\sphinx_docs.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
& "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
91
Tools/postbuild_portable.ps1
Normal file
91
Tools/postbuild_portable.ps1
Normal file
@@ -0,0 +1,91 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
$CertificatePassword,
|
||||
|
||||
[string[]]
|
||||
$ExcludeFromSigning
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "+===========================================================================================+"
|
||||
Write-Output "| Beginning mRemoteNG Portable Post Build |"
|
||||
Write-Output "+===========================================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"CertificatePath" = $CertificatePath
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
# Move dlls resurses into folder
|
||||
#Remove-Item -Path "$TargetDir\libs" -Recurse -ErrorAction Ignore
|
||||
#New-Item -ItemType "directory" -Force -Path $TargetDir -Name "libs"
|
||||
#Move-Item -Path "$TargetDir\*.dll" -Destination "$TargetDir\libs" -force
|
||||
|
||||
|
||||
###
|
||||
|
||||
# Move lang resurses into folder
|
||||
#Remove-Item -Path "$TargetDir\languages" -Recurse -ErrorAction Ignore
|
||||
#New-Item -ItemType "directory" -Force -Path $TargetDir -Name "languages"
|
||||
#"cs-CZ,de,el,en-US,es-AR,es,fr,hu,it,lt,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW,fi-FI".Split(",") | ForEach {
|
||||
# Move-Item -Path "$TargetDir\$_" -Destination "$TargetDir\languages" -force
|
||||
# }
|
||||
###
|
||||
|
||||
# Currently targeting x64, shouldn't need to manually set LargeAddressAware...
|
||||
#& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
#& "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
|
||||
if (!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
|
||||
$postbuild_installer_executed = Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\AppVeyor_mRemoteNG' -Name postbuild_installer_executed
|
||||
} else {
|
||||
$postbuild_installer_executed = ""
|
||||
}
|
||||
|
||||
write-host "-SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName "
|
||||
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
|
||||
if ($postbuild_installer_executed -ne "true" -or $env:postbuild_installer_executed -ne "true") {
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
|
||||
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
|
||||
}
|
||||
|
||||
& "$PSScriptRoot\zip_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
|
||||
if ( ![string]::IsNullOrEmpty($env:WEBSITE_TARGET_OWNER) -and ![string]::IsNullOrEmpty($env:WEBSITE_TARGET_REPOSITORY) ) {
|
||||
|
||||
& "$PSScriptRoot\create_upg_chk_files.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
|
||||
|
||||
& "$PSScriptRoot\update_and_upload_website_release_json_file.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
|
||||
|
||||
}
|
||||
|
||||
Write-Output "End mRemoteNG Portable Post Build"
|
||||
Write-Output ""
|
||||
61
Tools/rename_and_copy_installer.ps1
Normal file
61
Tools/rename_and_copy_installer.ps1
Normal file
@@ -0,0 +1,61 @@
|
||||
param (
|
||||
[string]
|
||||
$SolutionDir,
|
||||
[string]
|
||||
$BuildConfiguration
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Output ""
|
||||
Write-Output " /===== Begin rename_and_copy_installer =====/"
|
||||
|
||||
$targetVersionedFile = "$SolutionDir\mRemoteNG\bin\x64\$BuildConfiguration\mRemoteNG.exe"
|
||||
#$fileversion = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
#$prodversion = ((Get-Item -Path $targetVersionedFile).VersionInfo | Select-Object -Property ProductVersion)."ProductVersion"
|
||||
$fileversion = ((Get-Item -Path $targetVersionedFile).VersionInfo | Select-Object -Property FileVersion)."FileVersion"
|
||||
|
||||
Write-Output "fileversion: $fileversion"
|
||||
$msiversion = $fileversion
|
||||
|
||||
# determine update channel
|
||||
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
|
||||
Write-Output " UpdateChannel = Nightly"
|
||||
$msiversion = "$msiversion-NB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
|
||||
Write-Output " UpdateChannel = Preview"
|
||||
$msiversion = "$msiversion-PB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
|
||||
Write-Output " UpdateChannel = Stable"
|
||||
} else {
|
||||
}
|
||||
|
||||
$dstPath = "$($SolutionDir)Release"
|
||||
New-Item -Path $dstPath -ItemType Directory -Force
|
||||
$srcMsi = $SolutionDir + "mRemoteNGInstaller\Installer\bin\x64\$BuildConfiguration\en-US\mRemoteNG-Installer.msi"
|
||||
$dstMsi = $dstPath + "\mRemoteNG-Installer-" + $msiversion + ".msi"
|
||||
#$srcSymbols = $SolutionDir + "mRemoteNGInstaller\Installer\bin\x64\$BuildConfiguration\en-US\mRemoteNG-Installer-Symbols*.zip"
|
||||
#$dstSymbols = $SolutionDir + "Release\mRemoteNG-Installer-Symbols-" + $msiversion + ".zip"
|
||||
|
||||
Write-Output " Copy Installer file:"
|
||||
Write-Output " From: $srcMsi"
|
||||
Write-Output " To: $dstMsi"
|
||||
Write-Output ""
|
||||
# Copy file
|
||||
try
|
||||
{
|
||||
Copy-Item $srcMsi -Destination $dstMsi -Force -ErrorAction Stop
|
||||
#Copy-Item $srcSymbols -Destination $dstSymbols -Force -ErrorAction Stop
|
||||
Write-Host " [Success!]" -ForegroundColor green
|
||||
}
|
||||
catch
|
||||
{
|
||||
Write-Host " [Failure!]" -ForegroundColor red
|
||||
Write-Output $Error[0]
|
||||
$PSCmdlet.ThrowTerminatingError()
|
||||
}
|
||||
|
||||
|
||||
Write-Output ""
|
||||
Write-Output " /===== End rename_and_copy_installer.ps1 =====/"
|
||||
Write-Output ""
|
||||
@@ -1,29 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
$SolutionDir
|
||||
)
|
||||
|
||||
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
|
||||
Write-Host $SolutionDir
|
||||
Write-Host $renameTarget
|
||||
|
||||
$targetVersionedFile = "$SolutionDir\mRemoteNG\bin\Release\mRemoteNG.exe"
|
||||
$version = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
|
||||
|
||||
$renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue
|
||||
if ($renameTargetFileObject)
|
||||
{
|
||||
# Build the new file name
|
||||
$oldFileName = $renameTargetFileObject.Name
|
||||
$newFileName = $oldFileName -replace "$("\"+$renameTargetFileObject.Extension)",$("-"+$version+$renameTargetFileObject.Extension)
|
||||
Write-Host $oldFileName
|
||||
Write-Host $newFileName
|
||||
|
||||
# Delete any items that already exist with the new name (effectively an overwrite)
|
||||
Remove-Item -Path "$($renameTargetFileObject.Directory.FullName)\$newFileName" -ErrorAction SilentlyContinue
|
||||
|
||||
# Rename file
|
||||
Rename-Item -Path $renameTarget -NewName $newFileName -ErrorAction SilentlyContinue
|
||||
}
|
||||
@@ -24,65 +24,80 @@ param (
|
||||
$SolutionDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
# validate release versions and if the certificate value was passed
|
||||
if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
|
||||
try {
|
||||
# validate release versions and if the certificate value was passed
|
||||
if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
|
||||
|
||||
if(-Not ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) {
|
||||
$CertificatePath = Join-Path -Path $SolutionDir -ChildPath $CertificatePath
|
||||
if($IsAppVeyor) {
|
||||
$CertificatePath = Join-Path -Path $SolutionDir -ChildPath $CertificatePath
|
||||
Write-Output "Decrypt Cert"
|
||||
& appveyor-tools\secure-file -decrypt "$($Env:cert_path).enc" -secret "$Env:cert_decrypt_pwd"
|
||||
if(-Not (Test-Path $Env:cert_path)) {
|
||||
Write-Output "decrypt cert does not exist..."
|
||||
Throw "Could not decrypt cert"
|
||||
}
|
||||
Write-Output "Restoring NuGets"
|
||||
}
|
||||
|
||||
# make sure the cert is actually available
|
||||
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
|
||||
{
|
||||
Write-Output "Certificate is not present - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
if ($CertificatePassword -eq "") {
|
||||
Write-Output "No certificate password was provided - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$certKeyStore = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword, $certKeyStore) -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Output "Error loading certificate file - we won't sign files."
|
||||
Write-Output $Error[0]
|
||||
return
|
||||
}
|
||||
|
||||
# Sign MSI if we are building a release version and the certificate is available
|
||||
Write-Output "Signing Binaries"
|
||||
Write-Output "Getting files from path: $TargetDir"
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
|
||||
|
||||
$excluded_files = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -contains $_.Name}
|
||||
$excluded_files | ForEach-Object `
|
||||
-Begin { Write-Output "The following files were excluded from signing due to being on the exclusion list:" } `
|
||||
-Process { Write-Output "-- $($_.FullName)" }
|
||||
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
|
||||
}
|
||||
|
||||
|
||||
# Release certificate
|
||||
if ($null -ne $cert) {
|
||||
$cert.Dispose()
|
||||
}
|
||||
} else {
|
||||
Write-Output "This is not a release build or CertificatePath wasn't provided - we won't sign files."
|
||||
Write-Output "Config: $($ConfigurationName)`tCertPath: $($CertificatePath)"
|
||||
}
|
||||
|
||||
# make sure the cert is actually available
|
||||
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
|
||||
{
|
||||
Write-Output "Certificate is not present - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
if ($CertificatePassword -eq "") {
|
||||
Write-Output "No certificate password was provided - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$certKeyStore = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword, $certKeyStore) -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Output "Error loading certificate file - we won't sign files."
|
||||
Write-Output $Error[0]
|
||||
return
|
||||
}
|
||||
|
||||
# Sign MSI if we are building a release version and the certificate is available
|
||||
Write-Output "Signing Binaries"
|
||||
Write-Output "Getting files from path: $TargetDir"
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
|
||||
|
||||
$excluded_files = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -contains $_.Name}
|
||||
$excluded_files | ForEach-Object `
|
||||
-Begin { Write-Output "The following files were excluded from signing due to being on the exclusion list:" } `
|
||||
-Process { Write-Output "-- $($_.FullName)" }
|
||||
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
|
||||
}
|
||||
|
||||
|
||||
# Release certificate
|
||||
if ($cert -ne $null) {
|
||||
$cert.Dispose()
|
||||
}
|
||||
} else {
|
||||
Write-Output "This is not a release build or CertificatePath wasn't provided - we won't sign files."
|
||||
Write-Output "Config: $($ConfigurationName)`tCertPath: $($CertificatePath)"
|
||||
|
||||
}
|
||||
catch {
|
||||
Write-Output $Error[0]
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
|
||||
@@ -28,4 +28,6 @@ Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
Write-Output "Building HTML-Documentation with Sphinx"
|
||||
|
||||
$path_HelpFilesDir = Join-Path -Path $TargetDir -ChildPath "Help"
|
||||
$path_SphinxSourceDir = Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\Documentation"
|
||||
|
||||
# Remove stale Help files, if they exist
|
||||
if (Test-Path -Path $path_HelpFilesDir) {
|
||||
Remove-Item -Path $path_HelpFilesDir -Recurse -Force
|
||||
}
|
||||
|
||||
# Build docs
|
||||
sphinx-build $path_SphinxSourceDir $path_HelpFilesDir
|
||||
|
||||
# Place dummy html file if build failed
|
||||
if (-Not (Test-Path $path_HelpFilesDir\index.html -PathType Leaf)) {
|
||||
New-Item -Path $path_HelpFilesDir -ItemType "directory"
|
||||
New-Item $path_HelpFilesDir\index.html
|
||||
Set-Content $path_HelpFilesDir\index.html 'Welcome to mRemoteNG!'
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -8,14 +8,14 @@ param (
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# Remove unnecessary files from Release versions
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Removing unnecessary files from Release versions"
|
||||
|
||||
$test = Join-Path -Path $TargetDir -ChildPath "app.publish"
|
||||
if (Test-Path $test -PathType Container) {
|
||||
if (Test-Path $test -PathType Container)
|
||||
{
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
|
||||
}
|
||||
|
||||
@@ -29,11 +29,18 @@ if ($ConfigurationName -match "Release") {
|
||||
) -Exclude @(
|
||||
"mRemoteNG.VisualElementsManifest.xml"
|
||||
)
|
||||
Remove-Item -Path $filesToDelete.FullName
|
||||
Write-Output $filesToDelete.FullName
|
||||
}
|
||||
else {
|
||||
|
||||
if ($filesToDelete)
|
||||
{
|
||||
Write-Output "Unnecessary files are detected and will be removed"
|
||||
Remove-Item -Path $filesToDelete.FullName
|
||||
Write-Output $filesToDelete.FullName
|
||||
} else {
|
||||
Write-Output " No unnecessary files are detected"
|
||||
}
|
||||
} else {
|
||||
Write-Output "We will not remove anything - this is not a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
|
||||
53
Tools/update_and_upload_assemblyinfocs.ps1
Normal file
53
Tools/update_and_upload_assemblyinfocs.ps1
Normal file
@@ -0,0 +1,53 @@
|
||||
#Requires -Version 4.0
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$MainRepository = $Env:APPVEYOR_REPO_NAME.Split("/\")[1]
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
Write-Output "MainRepository: $MainRepository"
|
||||
|
||||
if ($IsAppVeyor) {
|
||||
|
||||
# determine update channel
|
||||
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
|
||||
Write-Output "UpdateChannel = Nightly"
|
||||
$UpdateChannel = "Nightly"
|
||||
$ModifiedTagName = "$PreTagName-$TagName-NB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
|
||||
Write-Output "UpdateChannel = Preview"
|
||||
$UpdateChannel = "Preview"
|
||||
$ModifiedTagName = "v$TagName-PB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
|
||||
Write-Output "UpdateChannel = Stable"
|
||||
$UpdateChannel = "Stable"
|
||||
$ModifiedTagName = "v" + $TagName.Split("-")[0]
|
||||
} else {
|
||||
$UpdateChannel = ""
|
||||
}
|
||||
|
||||
if ($UpdateChannel -ne "" -and $MainRepository -ne "" ) {
|
||||
|
||||
# commit AssemblyInfo.cs change
|
||||
Write-Output "publish AssemblyInfo.cs"
|
||||
|
||||
$buildFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\" -Resolve -ErrorAction Ignore
|
||||
|
||||
if (Test-Path -Path "$buildFolder\mRemoteNG\Properties\AssemblyInfo.cs") {
|
||||
|
||||
$assemblyinfocs_content = [System.String]::Join("`r`n", (Get-Content "$buildFolder\mRemoteNG\Properties\AssemblyInfo.cs"))
|
||||
|
||||
Set-GitHubContent -OwnerName $MainRepository -RepositoryName $MainRepository -Path "mRemoteNG\Properties\AssemblyInfo.cs" -CommitMessage "AssemblyInfo.cs updated for $UpdateChannel $ModifiedTagName" -Content $assemblyinfocs_content -BranchName main
|
||||
|
||||
Write-Output "publish completed"
|
||||
|
||||
}
|
||||
} else {
|
||||
Write-Output "Source folder not found"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
178
Tools/update_and_upload_website_release_json_file.ps1
Normal file
178
Tools/update_and_upload_website_release_json_file.ps1
Normal file
@@ -0,0 +1,178 @@
|
||||
#Requires -Version 4.0
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$WebsiteTargetOwner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$WebsiteTargetRepository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$false)]
|
||||
$PreTagName = "",
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ProjectName
|
||||
)
|
||||
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$MainRepository = $Env:APPVEYOR_REPO_NAME.Split("/\")[1]
|
||||
|
||||
# determine update channel
|
||||
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
|
||||
Write-Output "UpdateChannel = Nightly"
|
||||
$UpdateChannel = "Nightly"
|
||||
$ModifiedTagName = "$PreTagName-$TagName-NB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
|
||||
Write-Output "UpdateChannel = Preview"
|
||||
$UpdateChannel = "Preview"
|
||||
$ModifiedTagName = "v$TagName-PB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
|
||||
Write-Output "UpdateChannel = Stable"
|
||||
$UpdateChannel = "Stable"
|
||||
$ModifiedTagName = "v" + $TagName.Split("-")[0]
|
||||
} else {
|
||||
$UpdateChannel = ""
|
||||
}
|
||||
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
if ($IsAppVeyor) {
|
||||
|
||||
#$buildFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\mRemoteNG\bin\x64\Release" -Resolve -ErrorAction Ignore
|
||||
$ReleaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
|
||||
|
||||
if ($UpdateChannel -ne "" -and $ReleaseFolder -ne "" -and $MainRepository -ne "" -and $WebsiteTargetOwner -ne "" -and $WebsiteTargetRepository -ne "" ) {
|
||||
|
||||
$published_at = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
|
||||
# get releases.json from github
|
||||
$releases_json = Get-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path _data\releases.json
|
||||
ConvertFrom-Base64($releases_json.content) | Out-File -FilePath "$ReleaseFolder\releases.json"
|
||||
$websiteJsonReleaseFile = Get-ChildItem -Path "$ReleaseFolder\releases.json"
|
||||
|
||||
# installer
|
||||
$msiFile = Get-ChildItem -Path "$ReleaseFolder\*.msi" | Sort-Object LastWriteTime | Select-Object -last 1
|
||||
if (![string]::IsNullOrEmpty($msiFile)) {
|
||||
Write-Output "UpdateChannel: $UpdateChannel"
|
||||
Write-Output "msiFile: $msiFile"
|
||||
$checksum = (Get-FileHash $msiFile -Algorithm SHA512).Hash
|
||||
$file_size = (Get-ChildItem $msiFile).Length
|
||||
$a = Get-Content $websiteJsonReleaseFile | ConvertFrom-Json
|
||||
switch ($UpdateChannel) {
|
||||
"Nightly" {
|
||||
$GithubTag = "$((Get-Date).ToUniversalTime().ToString("yyyyMMdd"))-$TagName-NB"
|
||||
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
|
||||
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($msiFile.Name)"
|
||||
$a.nightlybuild.name = "v$TagName-NB"
|
||||
$a.nightlybuild.published_at = $published_at
|
||||
$a.nightlybuild.html_url = $html_url
|
||||
$a.nightlybuild.assets.installer.browser_download_url = $browser_download_url
|
||||
$a.nightlybuild.assets.installer.checksum = $checksum
|
||||
$a.nightlybuild.assets.installer.size = $file_size
|
||||
break
|
||||
}
|
||||
"Preview" {
|
||||
$GithubTag = "$TagName-PB"
|
||||
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
|
||||
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($msiFile.Name)"
|
||||
$a.prerelease.name = "v$TagName-PB"
|
||||
$a.prerelease.published_at = $published_at
|
||||
$a.prerelease.html_url = $html_url
|
||||
$a.prerelease.assets.installer.browser_download_url = $browser_download_url
|
||||
$a.prerelease.assets.installer.checksum = $checksum
|
||||
$a.prerelease.assets.installer.size = $file_size
|
||||
break
|
||||
}
|
||||
"Stable" {
|
||||
$GithubTag = "$TagName"
|
||||
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
|
||||
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($msiFile.Name)"
|
||||
$a.stable.name = "v$TagName"
|
||||
$a.stable.published_at = $published_at
|
||||
$a.stable.html_url = $html_url
|
||||
$a.stable.assets.installer.browser_download_url = $browser_download_url
|
||||
$a.stable.assets.installer.checksum = $checksum
|
||||
$a.stable.assets.installer.size = $file_size
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# portable
|
||||
$zipFile = Get-ChildItem -Path "$ReleaseFolder\*.zip" -Exclude "*-symbols-*.zip" | Sort-Object LastWriteTime | Select-Object -last 1
|
||||
if (![string]::IsNullOrEmpty($zipFile)) {
|
||||
Write-Output "UpdateChannel: $UpdateChannel"
|
||||
Write-Output "zipFile: $zipFile"
|
||||
$checksum = (Get-FileHash $zipFile -Algorithm SHA512).Hash
|
||||
$file_size = (Get-ChildItem $zipFile).Length
|
||||
$a = Get-Content $websiteJsonReleaseFile | ConvertFrom-Json
|
||||
switch ($UpdateChannel) {
|
||||
"Nightly" {
|
||||
$GithubTag = "$((Get-Date).ToUniversalTime().ToString("yyyyMMdd"))-$TagName-NB"
|
||||
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
|
||||
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($zipFile.Name)"
|
||||
$a.nightlybuild.name = "v$TagName-NB"
|
||||
$a.nightlybuild.published_at = $published_at
|
||||
$a.nightlybuild.html_url = $html_url
|
||||
$a.nightlybuild.assets.portable.browser_download_url = $browser_download_url
|
||||
$a.nightlybuild.assets.portable.checksum = $checksum
|
||||
$a.nightlybuild.assets.portable.size = $file_size
|
||||
break
|
||||
}
|
||||
"Preview" {
|
||||
$GithubTag = "$TagName-PB"
|
||||
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
|
||||
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($zipFile.Name)"
|
||||
$a.prerelease.name = "v$TagName-PB"
|
||||
$a.prerelease.published_at = $published_at
|
||||
$a.prerelease.html_url = $html_url
|
||||
$a.prerelease.assets.portable.browser_download_url = $browser_download_url
|
||||
$a.prerelease.assets.portable.checksum = $checksum
|
||||
$a.prerelease.assets.portable.size = $file_size
|
||||
break
|
||||
}
|
||||
"Stable" {
|
||||
$GithubTag = "$TagName"
|
||||
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
|
||||
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($zipFile.Name)"
|
||||
$a.stable.name = "v$TagName"
|
||||
$a.stable.published_at = $published_at
|
||||
$a.stable.html_url = $html_url
|
||||
$a.stable.assets.portable.browser_download_url = $browser_download_url
|
||||
$a.stable.assets.portable.checksum = $checksum
|
||||
$a.stable.assets.portable.size = $file_size
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$a | ConvertTo-Json -Depth 10 | Set-Content $websiteJsonReleaseFile
|
||||
|
||||
# commit releases.json change
|
||||
if ($env:WEBSITE_UPDATE_ENABLED.ToLower() -eq "true") {
|
||||
Write-Output "publish releases.json"
|
||||
if (Test-Path -Path "$ReleaseFolder\releases.json") {
|
||||
$releases_json_string = Get-Content "$ReleaseFolder\releases.json" | Out-String
|
||||
Set-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path _data\releases.json -CommitMessage "Updated for $UpdateChannel $ModifiedTagName" -Content $releases_json_string -BranchName main
|
||||
Write-Output "publish completed"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Output "ReleaseFolder not found"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
@@ -5,7 +5,13 @@ param (
|
||||
$FullPath
|
||||
)
|
||||
|
||||
$validMSCertThumbprints = @("3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC", "108E2BA23632620C427C570B6D9DB51AC31387FE", "98ED99A67886D020C564923B7DF25E9AC019DF26", "5EAD300DC7E4D637948ECB0ED829A072BD152E17")
|
||||
$validMSCertThumbprints = @(
|
||||
"3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC",
|
||||
"108E2BA23632620C427C570B6D9DB51AC31387FE",
|
||||
"98ED99A67886D020C564923B7DF25E9AC019DF26",
|
||||
"5EAD300DC7E4D637948ECB0ED829A072BD152E17",
|
||||
"97221B97098F37A135DCC212E2B41E452BCE51F2"
|
||||
)
|
||||
$exeSignature = Get-AuthenticodeSignature -FilePath $FullPath
|
||||
$baseErrorMsg = "Could not validate the certificate of $FullPath. "
|
||||
|
||||
@@ -14,4 +20,4 @@ if ($exeSignature.Status -ne "Valid") {
|
||||
}
|
||||
elseif ($validMSCertThumbprints -notcontains $exeSignature.SignerCertificate.Thumbprint) {
|
||||
Write-Error -Message ($baseErrorMsg+"The certificate thumbprint ($($exeSignature.SignerCertificate.Thumbprint)) is not trusted.") -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ param (
|
||||
$TargetFileName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_dumpBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\dumpbin.exe"
|
||||
$path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
@@ -18,7 +19,7 @@ $path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
# Dump exe header
|
||||
$output = & "$path_dumpBin" /NOLOGO /HEADERS "$path_outputExe" | Select-String large
|
||||
|
||||
if ($output -eq $null)
|
||||
if ($null -eq $output)
|
||||
{
|
||||
Write-Warning "Could not validate LargeAddressAware"
|
||||
}
|
||||
@@ -27,4 +28,5 @@ else
|
||||
Write-Output $output.ToString().TrimStart(" ")
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
|
||||
@@ -18,12 +18,15 @@ param (
|
||||
$SolutionDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
# validate release versions and if the certificate value was passed
|
||||
if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
|
||||
|
||||
if(-Not ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) {
|
||||
if($IsAppVeyor) {
|
||||
$CertificatePath = Join-Path -Path $SolutionDir -ChildPath $CertificatePath
|
||||
}
|
||||
|
||||
@@ -36,9 +39,10 @@ if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
|
||||
|
||||
Write-Output "Verifying signature of binaries"
|
||||
Write-Output "Getting files from path: $TargetDir"
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"}
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | Where-Object {$_.Extension -match "dll|exe|msi"}
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
$badSignatureFound = $false
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
$signature = Get-AuthenticodeSignature -FilePath $file.FullName
|
||||
if ($signature.Status -ne "Valid") {
|
||||
@@ -46,6 +50,7 @@ if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
|
||||
$badSignatureFound = $true
|
||||
}
|
||||
}
|
||||
|
||||
if ($badSignatureFound) {
|
||||
Write-Output "One or more files were improperly signed."
|
||||
} else {
|
||||
@@ -56,4 +61,5 @@ if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
|
||||
Write-Output "Config: $($ConfigurationName)`tCertPath: $($CertificatePath)"
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
|
||||
93
Tools/zip_files.ps1
Normal file
93
Tools/zip_files.ps1
Normal file
@@ -0,0 +1,93 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
|
||||
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
$exe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
#$version = ((Get-Item -Path $exe).VersionInfo | Select-Object -Property ProductVersion)."ProductVersion"
|
||||
$version = $(Get-Item -Path $exe).VersionInfo.FileVersion
|
||||
Write-Output "FileVersion: $version"
|
||||
|
||||
|
||||
# determine update channel
|
||||
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
|
||||
Write-Output "UpdateChannel = Nightly"
|
||||
$ModifiedVersion = "$version-NB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
|
||||
Write-Output "UpdateChannel = Preview"
|
||||
$ModifiedVersion = "$version-PB"
|
||||
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
|
||||
Write-Output "UpdateChannel = Stable"
|
||||
$ModifiedVersion = $version
|
||||
} else {
|
||||
}
|
||||
|
||||
# Fix for AppVeyor
|
||||
if($IsAppVeyor) {
|
||||
if(!(Test-Path "Release")) {
|
||||
New-Item -ItemType Directory -Force -Path "Release" | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Package debug symbols zip file
|
||||
Write-Output "Packaging debug symbols"
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
$pdbFiles = Get-ChildItem -Path $SolutionDir -Filter *.pdb -Recurse
|
||||
$tempPdbPath = (New-TemporaryDirectory)[0]
|
||||
foreach ($pdbFile in $pdbFiles) {
|
||||
if (($pdbFile.FullName).Contains("\$ConfigurationName\")) {
|
||||
Copy-Item $pdbFile.FullName -Destination $tempPdbPath -Force
|
||||
}
|
||||
}
|
||||
|
||||
if ($IsAppVeyor) {
|
||||
# AppVeyor build
|
||||
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\$zipFilePrefix-$($ModifiedVersion).zip"
|
||||
Write-Output "outputZipPath: $outputZipPath"
|
||||
7z a $outputZipPath "$tempPdbPath\*.pdb"
|
||||
}
|
||||
# else {
|
||||
# # Local build
|
||||
# $outputZipPath = "$($SolutionDir)Release\$zipFilePrefix-$($ModifiedVersion).zip"
|
||||
# Write-Output "outputZipPath: $outputZipPath"
|
||||
# Compress-Archive -Path $tempPdbPath -DestinationPath $outputZipPath -Force
|
||||
# }
|
||||
|
||||
|
||||
# Package portable release zip file
|
||||
Write-Output "Packaging portable ZIP file"
|
||||
# AppVeyor build
|
||||
if ($IsAppVeyor) {
|
||||
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\mRemoteNG-Portable-$($ModifiedVersion).zip"
|
||||
7z a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath $TargetDir\*
|
||||
Write-Output "Portable ZIP: $outputZipPath"
|
||||
}
|
||||
# Local build
|
||||
else {
|
||||
if ($Source)
|
||||
{
|
||||
$outputZipPath="$($SolutionDir)\Release\mRemoteNG-Portable-$($ModifiedVersion).zip"
|
||||
Compress-Archive $Source $outputZipPath -Force
|
||||
} else {
|
||||
Write-Output "Files do not exist:" $Source", nothing to compress"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
|
||||
Write-Output ""
|
||||
@@ -1,64 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteNG\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
$tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\bin\package"
|
||||
Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item $tempFolderPath -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteNG\Resources\PuTTYNG.exe" -Destination $tempFolderPath
|
||||
|
||||
#Write-Output "$($SolutionDir)mRemoteNG\bin\$ConfigurationName"
|
||||
#Write-Output "$($SolutionDir)mRemoteNG\bin\package"
|
||||
Copy-Item "$($SolutionDir)mRemoteNG\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force
|
||||
# Delete any PDB files that accidentally get copied into the temp folder
|
||||
Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*")
|
||||
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,56 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Packaging debug symbols"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteNG\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
if ($ConfigurationName -match "Portable") {
|
||||
$zipFilePrefix = "mRemoteNG-Portable-symbols"
|
||||
} else {
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
}
|
||||
|
||||
$outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
|
||||
|
||||
Write-Output "Creating debug symbols ZIP file $($outputZipPath)"
|
||||
Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb")
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not package debug symbols - this isnt a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
6
mRemoteNG.lutconfig
Normal file
6
mRemoteNG.lutconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
<LUTConfig Version="1.0">
|
||||
<Repository />
|
||||
<ParallelBuilds>true</ParallelBuilds>
|
||||
<ParallelTestRuns>true</ParallelTestRuns>
|
||||
<TestCaseTimeout>180000</TestCaseTimeout>
|
||||
</LUTConfig>
|
||||
143
mRemoteNG.sln
143
mRemoteNG.sln
@@ -1,11 +1,11 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28803.352
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31912.275
|
||||
MinimumVisualStudioVersion = 14.0.25420.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNG", "mRemoteNG\mRemoteNG.csproj", "{4934A491-40BC-4E5B-9166-EA1169A220F6}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNG", "mRemoteNG\mRemoteNG.csproj", "{4934A491-40BC-4E5B-9166-EA1169A220F6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNGTests", "mRemoteNGTests\mRemoteNGTests.csproj", "{1453B37F-8621-499E-B0B2-6091F76DC0BB}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNGTests", "mRemoteNGTests\mRemoteNGTests.csproj", "{1453B37F-8621-499E-B0B2-6091F76DC0BB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mRemoteNGInstaller", "mRemoteNGInstaller", "{4FE795BE-646E-4F1B-BAD0-A68EA26394DD}"
|
||||
EndProject
|
||||
@@ -13,111 +13,52 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomActions", "mRemoteNGI
|
||||
EndProject
|
||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "mRemoteNGInstaller\Installer\Installer.wixproj", "{F0168B9F-6815-40DF-BA53-46CEE7683B68}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6} = {4934A491-40BC-4E5B-9166-EA1169A220F6}
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04} = {5423D985-CB48-4344-B47F-E8C6D60C8B04}
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD} = {A56A2029-79B8-492A-ABE5-D2BFE05801BD}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalConnectors", "ExternalConnectors\ExternalConnectors.csproj", "{A56A2029-79B8-492A-ABE5-D2BFE05801BD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug Portable|Any CPU = Debug Portable|Any CPU
|
||||
Debug Portable|x86 = Debug Portable|x86
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x86 = Debug|x86
|
||||
Release Installer|Any CPU = Release Installer|Any CPU
|
||||
Release Installer|x86 = Release Installer|x86
|
||||
Release Portable|Any CPU = Release Portable|Any CPU
|
||||
Release Portable|x86 = Release Portable|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x86 = Release|x86
|
||||
Debug|x64 = Debug|x64
|
||||
Release Installer and Portable|x64 = Release Installer and Portable|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|Any CPU.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.Build.0 = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.Build.0 = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x86.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x86.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|x86.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug Portable|Any CPU.Build.0 = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug Portable|x86.ActiveCfg = Debug|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug Portable|x86.Build.0 = Debug|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x86.Build.0 = Debug|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|x86.Build.0 = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Portable|Any CPU.Build.0 = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Portable|x86.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Portable|x86.Build.0 = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x64.Build.0 = Debug|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|x64.Build.0 = Release|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x64.ActiveCfg = Release|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x64.Build.0 = Release|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x64.Build.0 = Debug|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer and Portable|x64.Build.0 = Release|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x64.ActiveCfg = Release|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x64.Build.0 = Debug|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer and Portable|x64.Build.0 = Release|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|x64.ActiveCfg = Release|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x64.Build.0 = Debug|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x64.ActiveCfg = Release Installer|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|x64.Build.0 = Debug|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|x64.Build.0 = Release|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|x64.ActiveCfg = Release|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
11
mRemoteNG/App.config
Normal file
11
mRemoteNG/App.config
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="LanguageFolder" value="Language"/>
|
||||
</appSettings>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<probing privatePath="Languages"/>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -5,12 +5,14 @@ using Microsoft.Win32;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.TaskDialog;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class CompatibilityChecker
|
||||
{
|
||||
public static void CheckCompatibility(MessageCollector messageCollector)
|
||||
@@ -33,18 +35,13 @@ namespace mRemoteNG.App
|
||||
|
||||
if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return;
|
||||
|
||||
var errorText = string.Format(Language.ErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName);
|
||||
string errorText = string.Format(Language.ErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName);
|
||||
messageCollector.AddMessage(MessageClass.ErrorMsg, errorText, true);
|
||||
|
||||
//About to pop up a message, let's not block it...
|
||||
FrmSplashScreen.getInstance().Close();
|
||||
FrmSplashScreenNew.GetInstance().Close();
|
||||
|
||||
var ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName,
|
||||
Language.CompatibilityProblemDetected, errorText, "",
|
||||
"",
|
||||
Language.CheckboxDoNotShowThisMessageAgain,
|
||||
ETaskDialogButtons.OkCancel, ESysIcons.Warning,
|
||||
ESysIcons.Warning);
|
||||
DialogResult ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, Language.CompatibilityProblemDetected, errorText, "", "", Language.CheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.OkCancel, ESysIcons.Warning, ESysIcons.Warning);
|
||||
if (CTaskDialog.VerificationChecked && ShouldIStayOrShouldIGo == DialogResult.OK)
|
||||
{
|
||||
messageCollector.AddMessage(MessageClass.ErrorMsg, "User requests that FIPS check be overridden", true);
|
||||
@@ -59,7 +56,7 @@ namespace mRemoteNG.App
|
||||
|
||||
private static bool FipsPolicyEnabledForServer2003()
|
||||
{
|
||||
var regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa");
|
||||
RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa");
|
||||
if (!(regKey?.GetValue("FIPSAlgorithmPolicy") is int fipsPolicy))
|
||||
return false;
|
||||
return fipsPolicy != 0;
|
||||
@@ -67,7 +64,7 @@ namespace mRemoteNG.App
|
||||
|
||||
private static bool FipsPolicyEnabledForServer2008AndNewer()
|
||||
{
|
||||
var regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy");
|
||||
RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy");
|
||||
if (!(regKey?.GetValue("Enabled") is int fipsPolicy))
|
||||
return false;
|
||||
return fipsPolicy != 0;
|
||||
@@ -80,7 +77,7 @@ namespace mRemoteNG.App
|
||||
if (!Settings.Default.CompatibilityWarnLenovoAutoScrollUtility)
|
||||
return;
|
||||
|
||||
var proccesses = new Process[] { };
|
||||
Process[] proccesses = new Process[] { };
|
||||
try
|
||||
{
|
||||
proccesses = Process.GetProcessesByName("virtscrl");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
@@ -17,15 +18,16 @@ using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class Export
|
||||
{
|
||||
public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var saveFilter = new SaveFilter();
|
||||
SaveFilter saveFilter = new();
|
||||
|
||||
using (var exportForm = new FrmExport())
|
||||
using (FrmExport exportForm = new())
|
||||
{
|
||||
if (selectedNode?.GetTreeNodeType() == TreeNodeType.Container)
|
||||
exportForm.SelectedFolder = selectedNode as ContainerInfo;
|
||||
@@ -79,9 +81,9 @@ namespace mRemoteNG.App
|
||||
switch (saveFormat)
|
||||
{
|
||||
case SaveFormat.mRXML:
|
||||
var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
|
||||
var rootNode = exportTarget.GetRootParent() as RootNodeInfo;
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer27(
|
||||
ICryptographyProvider cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
|
||||
RootNodeInfo rootNode = exportTarget.GetRootParent() as RootNodeInfo;
|
||||
XmlConnectionNodeSerializer28 connectionNodeSerializer = new(
|
||||
cryptographyProvider,
|
||||
rootNode?.PasswordString
|
||||
.ConvertToSecureString() ??
|
||||
@@ -100,8 +102,8 @@ namespace mRemoteNG.App
|
||||
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);
|
||||
}
|
||||
|
||||
var serializedData = serializer.Serialize(exportTarget);
|
||||
var fileDataProvider = new FileDataProvider(fileName);
|
||||
string serializedData = serializer.Serialize(exportTarget);
|
||||
FileDataProvider fileDataProvider = new(fileName);
|
||||
fileDataProvider.Save(serializedData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -6,24 +6,26 @@ using mRemoteNG.Config.Import;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
public static class Import
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class Import
|
||||
{
|
||||
public static void ImportFromFile(ContainerInfo importDestinationContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var openFileDialog = new OpenFileDialog())
|
||||
using (OpenFileDialog openFileDialog = new())
|
||||
{
|
||||
openFileDialog.CheckFileExists = true;
|
||||
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
|
||||
openFileDialog.Multiselect = true;
|
||||
|
||||
var fileTypes = new List<string>();
|
||||
List<string> fileTypes = new();
|
||||
fileTypes.AddRange(new[] {Language.FilterAllImportable, "*.xml;*.rdp;*.rdg;*.dat;*.csv"});
|
||||
fileTypes.AddRange(new[] {Language.FiltermRemoteXML, "*.xml"});
|
||||
fileTypes.AddRange(new[] {Language.FiltermRemoteCSV, "*.csv"});
|
||||
@@ -31,6 +33,7 @@ namespace mRemoteNG.App
|
||||
fileTypes.AddRange(new[] {Language.FilterRdgFiles, "*.rdg"});
|
||||
fileTypes.AddRange(new[] {Language.FilterPuttyConnectionManager, "*.dat"});
|
||||
fileTypes.AddRange(new[] {Language.FilterAll, "*.*"});
|
||||
fileTypes.AddRange(new[] { Language.FilterSecureCRT, "*.crt" });
|
||||
|
||||
openFileDialog.Filter = string.Join("|", fileTypes.ToArray());
|
||||
|
||||
@@ -38,8 +41,8 @@ namespace mRemoteNG.App
|
||||
return;
|
||||
|
||||
HeadlessFileImport(
|
||||
openFileDialog.FileNames,
|
||||
importDestinationContainer,
|
||||
openFileDialog.FileNames,
|
||||
importDestinationContainer,
|
||||
Runtime.ConnectionsService,
|
||||
fileName => MessageBox.Show(string.Format(Language.ImportFileFailedContent, fileName), Language.AskUpdatesMainInstruction,
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1));
|
||||
@@ -51,19 +54,50 @@ namespace mRemoteNG.App
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportFromRemoteDesktopManagerCsv(ContainerInfo importDestinationContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Runtime.ConnectionsService.BatchedSavingContext())
|
||||
{
|
||||
using (OpenFileDialog openFileDialog = new())
|
||||
{
|
||||
openFileDialog.CheckFileExists = true;
|
||||
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
|
||||
openFileDialog.Multiselect = false;
|
||||
|
||||
List<string> fileTypes = new();
|
||||
fileTypes.AddRange(new[] {Language.FiltermRemoteRemoteDesktopManagerCSV, "*.csv"});
|
||||
|
||||
openFileDialog.Filter = string.Join("|", fileTypes.ToArray());
|
||||
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
RemoteDesktopManagerImporter importer = new();
|
||||
importer.Import(openFileDialog.FileName, importDestinationContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage("App.Import.ImportFromRemoteDesktopManagerCsv() failed.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void HeadlessFileImport(
|
||||
IEnumerable<string> filePaths,
|
||||
ContainerInfo importDestinationContainer,
|
||||
IEnumerable<string> filePaths,
|
||||
ContainerInfo importDestinationContainer,
|
||||
ConnectionsService connectionsService,
|
||||
Action<string> exceptionAction = null)
|
||||
{
|
||||
using (connectionsService.BatchedSavingContext())
|
||||
{
|
||||
foreach (var fileName in filePaths)
|
||||
foreach (string fileName in filePaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
var importer = BuildConnectionImporterFromFileExtension(fileName);
|
||||
IConnectionImporter<string> importer = BuildConnectionImporterFromFileExtension(fileName);
|
||||
importer.Import(fileName, importDestinationContainer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -100,7 +134,7 @@ namespace mRemoteNG.App
|
||||
{
|
||||
using (Runtime.ConnectionsService.BatchedSavingContext())
|
||||
{
|
||||
var importer = new PortScanImporter(protocol);
|
||||
PortScanImporter importer = new(protocol);
|
||||
importer.Import(hosts, importDestinationContainer);
|
||||
}
|
||||
}
|
||||
@@ -110,10 +144,25 @@ namespace mRemoteNG.App
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ImportFromPutty(ContainerInfo selectedNodeAsContainer)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Runtime.ConnectionsService.BatchedSavingContext())
|
||||
{
|
||||
RegistryImporter.Import("Software\\SimonTatham\\PuTTY\\Sessions", selectedNodeAsContainer);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage("App.Import.ImportFromPutty() failed.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static IConnectionImporter<string> BuildConnectionImporterFromFileExtension(string fileName)
|
||||
{
|
||||
// TODO: Use the file contents to determine the file type instead of trusting the extension
|
||||
var extension = Path.GetExtension(fileName) ?? "";
|
||||
string extension = Path.GetExtension(fileName) ?? "";
|
||||
switch (extension.ToLowerInvariant())
|
||||
{
|
||||
case ".xml":
|
||||
@@ -126,6 +175,8 @@ namespace mRemoteNG.App
|
||||
return new RemoteDesktopConnectionManagerImporter();
|
||||
case ".dat":
|
||||
return new PuttyConnectionManagerImporter();
|
||||
case ".crt":
|
||||
return new SecureCRTImporter();
|
||||
default:
|
||||
throw new FileFormatException("Unrecognized file format.");
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
public static class ConnectionsFileInfo
|
||||
{
|
||||
public static readonly string DefaultConnectionsPath = SettingsFileInfo.SettingsPath;
|
||||
public static readonly string DefaultConnectionsFile = "confCons.xml";
|
||||
public static readonly string DefaultConnectionsFileNew = "confConsNew.xml";
|
||||
public static readonly double ConnectionFileVersion = 2.8;
|
||||
}
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class ConnectionsFileInfo
|
||||
{
|
||||
public static readonly string DefaultConnectionsPath = SettingsFileInfo.SettingsPath;
|
||||
public static readonly string DefaultConnectionsFile = "confCons.xml";
|
||||
public static readonly string DefaultConnectionsFileNew = "confConsNew.xml";
|
||||
public static readonly Version ConnectionFileVersion = new(3, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace mRemoteNG.App.Info
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class CredentialsFileInfo
|
||||
{
|
||||
public static readonly string CredentialsPath = SettingsFileInfo.SettingsPath;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using static System.Environment;
|
||||
@@ -9,36 +10,33 @@ using static System.Environment;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class GeneralAppInfo
|
||||
{
|
||||
public const string UrlHome = "https://www.mremoteng.org";
|
||||
public const string UrlHome = "https://mremoteng.org";
|
||||
public const string UrlDonate = "https://mremoteng.org/contribute";
|
||||
public const string UrlForum = "https://www.reddit.com/r/mRemoteNG";
|
||||
public const string UrlBugs = "https://bugs.mremoteng.org";
|
||||
public static string ApplicationVersion = Application.ProductVersion;
|
||||
public const string UrlDocumentation = "https://mremoteng.readthedocs.io/en/latest/";
|
||||
public static readonly string ApplicationVersion = Application.ProductVersion;
|
||||
public static readonly string ProductName = Application.ProductName;
|
||||
|
||||
public static readonly string Copyright =
|
||||
((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
|
||||
typeof(AssemblyCopyrightAttribute), false))
|
||||
.Copyright;
|
||||
|
||||
public static readonly string Copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute), false))?.Copyright;
|
||||
public static readonly string HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
|
||||
//public static string ReportingFilePath = "";
|
||||
public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe";
|
||||
private static readonly string puttyPath = HomePath + "\\PuTTYNG.exe";
|
||||
|
||||
public static string UserAgent
|
||||
{
|
||||
get
|
||||
{
|
||||
var details = new List<string>
|
||||
{
|
||||
List<string> details =
|
||||
[
|
||||
"compatible",
|
||||
OSVersion.Platform == PlatformID.Win32NT
|
||||
? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}"
|
||||
: OSVersion.VersionString
|
||||
};
|
||||
];
|
||||
if (Is64BitProcess)
|
||||
{
|
||||
details.Add("WOW64");
|
||||
@@ -46,15 +44,17 @@ namespace mRemoteNG.App.Info
|
||||
|
||||
details.Add(Thread.CurrentThread.CurrentUICulture.Name);
|
||||
details.Add($".NET CLR {Environment.Version}");
|
||||
var detailsString = string.Join("; ", details.ToArray());
|
||||
string detailsString = string.Join("; ", [.. details]);
|
||||
|
||||
return $"Mozilla/5.0 ({detailsString}) {ProductName}/{ApplicationVersion}";
|
||||
}
|
||||
}
|
||||
|
||||
public static string PuttyPath => puttyPath;
|
||||
|
||||
public static Version GetApplicationVersion()
|
||||
{
|
||||
System.Version.TryParse(ApplicationVersion, out var v);
|
||||
_ = System.Version.TryParse(ApplicationVersion, out Version v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class SettingsFileInfo
|
||||
{
|
||||
private static readonly string ExePath =
|
||||
Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
|
||||
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
|
||||
|
||||
public static string SettingsPath =>
|
||||
Runtime.IsPortableEdition
|
||||
? ExePath
|
||||
: Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
|
||||
public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
|
||||
|
||||
public static string LayoutFileName { get; } = "pnlLayout.xml";
|
||||
public static string ExtAppsFilesName { get; } = "extApps.xml";
|
||||
public static string ThemesFileName { get; } = "Themes.xml";
|
||||
public static string LocalConnectionProperties { get; } = "LocalConnectionProperties.xml";
|
||||
|
||||
public static string ThemeFolder { get; } =
|
||||
SettingsPath != null ? Path.Combine(SettingsPath, "Themes") : String.Empty;
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Properties;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class UpdateChannelInfo
|
||||
{
|
||||
public const string STABLE = "Stable";
|
||||
public const string BETA = "Beta";
|
||||
public const string DEV = "Development";
|
||||
public const string PREVIEW = "Preview";
|
||||
public const string NIGHTLY = "Nightly";
|
||||
|
||||
/* no #if here since they are used for unit tests as well */
|
||||
public const string STABLE_PORTABLE = "update-portable.txt";
|
||||
public const string BETA_PORTABLE = "beta-update-portable.txt";
|
||||
public const string DEV_PORTABLE = "dev-update-portable.txt";
|
||||
public const string PREVIEW_PORTABLE = "preview-update-portable.txt";
|
||||
public const string NIGHTLY_PORTABLE = "nightly-update-portable.txt";
|
||||
|
||||
public const string STABLE_MSI = "update.txt";
|
||||
public const string BETA_MSI = "beta-update.txt";
|
||||
public const string DEV_MSI = "dev-update.txt";
|
||||
public const string PREVIEW_MSI = "preview-update.txt";
|
||||
public const string NIGHTLY_MSI = "nightly-update.txt";
|
||||
|
||||
|
||||
public static Uri GetUpdateChannelInfo()
|
||||
{
|
||||
var channel = IsValidChannel(Settings.Default.UpdateChannel) ? Settings.Default.UpdateChannel : STABLE;
|
||||
string channel = IsValidChannel(Properties.OptionsUpdatesPage.Default.UpdateChannel) ? Properties.OptionsUpdatesPage.Default.UpdateChannel : STABLE;
|
||||
return GetUpdateTxtUri(channel);
|
||||
}
|
||||
|
||||
@@ -40,10 +41,10 @@ namespace mRemoteNG.App.Info
|
||||
{
|
||||
case STABLE:
|
||||
return STABLE_MSI;
|
||||
case BETA:
|
||||
return BETA_MSI;
|
||||
case DEV:
|
||||
return DEV_MSI;
|
||||
case PREVIEW:
|
||||
return PREVIEW_MSI;
|
||||
case NIGHTLY:
|
||||
return NIGHTLY_MSI;
|
||||
default:
|
||||
return STABLE_MSI;
|
||||
}
|
||||
@@ -55,10 +56,10 @@ namespace mRemoteNG.App.Info
|
||||
{
|
||||
case STABLE:
|
||||
return STABLE_PORTABLE;
|
||||
case BETA:
|
||||
return BETA_PORTABLE;
|
||||
case DEV:
|
||||
return DEV_PORTABLE;
|
||||
case PREVIEW:
|
||||
return PREVIEW_PORTABLE;
|
||||
case NIGHTLY:
|
||||
return NIGHTLY_PORTABLE;
|
||||
default:
|
||||
return STABLE_PORTABLE;
|
||||
}
|
||||
@@ -66,13 +67,13 @@ namespace mRemoteNG.App.Info
|
||||
|
||||
private static Uri GetUpdateTxtUri(string channel)
|
||||
{
|
||||
return new Uri(new Uri(Settings.Default.UpdateAddress),
|
||||
return new Uri(new Uri(Properties.OptionsUpdatesPage.Default.UpdateAddress),
|
||||
new Uri(GetChannelFileName(channel), UriKind.Relative));
|
||||
}
|
||||
|
||||
private static bool IsValidChannel(string s)
|
||||
{
|
||||
return s.Equals(STABLE) || s.Equals(BETA) || s.Equals(DEV);
|
||||
return s.Equals(STABLE) || s.Equals(PREVIEW) || s.Equals(NIGHTLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
mRemoteNG/App/Info/WindowsRegistryInfo.cs
Normal file
87
mRemoteNG/App/Info/WindowsRegistryInfo.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using Microsoft.Win32;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class WindowsRegistryInfo
|
||||
{
|
||||
#region General Parameters
|
||||
|
||||
public const RegistryHive Hive = RegistryHive.LocalMachine;
|
||||
public const string RootKey = "SOFTWARE\\mRemoteNG";
|
||||
private const string OptionsSubKey = "Options";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Key Locations
|
||||
|
||||
// StartupExit
|
||||
// Registry subkey for general application startup and exit settings
|
||||
// Registry subkey for startup and exit options page settings
|
||||
public const string StartupExit = RootKey + "\\StartupExit";
|
||||
public const string StartupExitOptions = StartupExit + "\\" + OptionsSubKey;
|
||||
|
||||
// Appearance
|
||||
// Registry subkey for general application appearance settings
|
||||
// Registry subkey for appearance options page settings
|
||||
public const string Appearance = RootKey + "\\Appearance";
|
||||
public const string AppearanceOptions = Appearance + "\\" + OptionsSubKey;
|
||||
|
||||
// Connections
|
||||
// Registry subkey for general application connection settings
|
||||
// Registry subkey for connections options page settings
|
||||
public const string Connection = RootKey + "\\Connections";
|
||||
public const string ConnectionOptions = Connection + "\\" + OptionsSubKey;
|
||||
|
||||
// Tabs & Panels
|
||||
// Registry subkey for general application tabs and panels settings
|
||||
// Registry subkey for tabs and panels options page settings
|
||||
public const string TabsAndPanels = RootKey + "\\TabsAndPanels";
|
||||
public const string TabsAndPanelsOptions = TabsAndPanels + "\\" + OptionsSubKey;
|
||||
|
||||
// Notifications
|
||||
// Registry subkey for general application notifications settings
|
||||
// Registry subkey for notifications options page settings
|
||||
public const string Notification = RootKey + "\\Notifications";
|
||||
public const string NotificationOptions = Notification + "\\" + OptionsSubKey;
|
||||
|
||||
// Credential
|
||||
// Registry subkey for general application credentials settings
|
||||
// Registry subkey for credentials options page settings
|
||||
public const string Credential = RootKey + "\\Credentials";
|
||||
public const string CredentialOptions = Credential + "\\" + OptionsSubKey;
|
||||
|
||||
// SQL Server
|
||||
// Registry subkey for general application SQL server settings
|
||||
// Registry subkey for SQL server options page settings
|
||||
public const string SQLServer = RootKey + "\\SQLServer";
|
||||
public const string SQLServerOptions = SQLServer + "\\" + OptionsSubKey;
|
||||
|
||||
// Updates
|
||||
// Registry subkey for general application update settings
|
||||
// Registry subkey for updates options page settings
|
||||
public const string Update = RootKey + "\\Updates";
|
||||
public const string UpdateOptions = Update + "\\" + OptionsSubKey;
|
||||
|
||||
// Security
|
||||
// Registry subkey for general application security settings
|
||||
// Registry subkey for security options page settings
|
||||
public const string Security = RootKey + "\\Security";
|
||||
public const string SecurityOptions = Security + "\\" + OptionsSubKey;
|
||||
|
||||
// Advanced
|
||||
// Registry subkey for general application advanced settings
|
||||
// Registry subkey for advanced options page settings
|
||||
public const string Advanced = RootKey + "\\Advanced";
|
||||
public const string AdvancedOptions = Advanced + "\\" + OptionsSubKey;
|
||||
|
||||
// Backup
|
||||
// Registry subkey for general application backup settings
|
||||
// Registry subkey for backup options page settings
|
||||
public const string Backup = RootKey + "\\Backup";
|
||||
public const string BackupOptions = Backup + "\\" + OptionsSubKey;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ConnectionIconLoader
|
||||
{
|
||||
private readonly string _path;
|
||||
@@ -22,9 +24,9 @@ namespace mRemoteNG.App.Initialization
|
||||
if (Directory.Exists(_path) == false)
|
||||
return;
|
||||
|
||||
foreach (var f in Directory.GetFiles(_path, "*.ico", SearchOption.AllDirectories))
|
||||
foreach (string f in Directory.GetFiles(_path, "*.ico", SearchOption.AllDirectories))
|
||||
{
|
||||
var fInfo = new FileInfo(f);
|
||||
FileInfo fInfo = new(f);
|
||||
Array.Resize(ref ConnectionIcon.Icons, ConnectionIcon.Icons.Length + 1);
|
||||
ConnectionIcon.Icons.SetValue(fInfo.Name.Replace(".ico", ""), ConnectionIcon.Icons.Length - 1);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Properties;
|
||||
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class CredsAndConsSetup
|
||||
{
|
||||
public void LoadCredsAndCons()
|
||||
{
|
||||
new SaveConnectionsOnEdit(Runtime.ConnectionsService);
|
||||
|
||||
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation &&
|
||||
!File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
|
||||
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService
|
||||
.GetStartupConnectionFileName());
|
||||
if (Properties.App.Default.FirstStart && !Properties.OptionsBackupPage.Default.LoadConsFromCustomLocation && !File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
|
||||
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService.GetStartupConnectionFileName());
|
||||
|
||||
Runtime.LoadConnections();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Messages.MessageFilteringOptions;
|
||||
using mRemoteNG.Messages.MessageWriters;
|
||||
@@ -7,17 +8,24 @@ using mRemoteNG.Messages.WriterDecorators;
|
||||
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class MessageCollectorSetup
|
||||
{
|
||||
public static void SetupMessageCollector(MessageCollector messageCollector,
|
||||
IList<IMessageWriter> messageWriterList)
|
||||
public static void SetupMessageCollector(MessageCollector messageCollector, IList<IMessageWriter> messageWriterList)
|
||||
{
|
||||
messageCollector.CollectionChanged += (o, args) =>
|
||||
{
|
||||
var messages = args.NewItems.Cast<IMessage>().ToArray();
|
||||
foreach (var printer in messageWriterList)
|
||||
foreach (var message in messages)
|
||||
if (args.NewItems == null) return;
|
||||
|
||||
IMessage[] messages = args.NewItems.Cast<IMessage>().ToArray();
|
||||
|
||||
foreach (IMessageWriter printer in messageWriterList)
|
||||
{
|
||||
foreach (IMessage message in messages)
|
||||
{
|
||||
printer.Write(message);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,37 +47,30 @@ namespace mRemoteNG.App.Initialization
|
||||
private static IMessageWriter BuildTextLogMessageWriter()
|
||||
{
|
||||
return new MessageTypeFilterDecorator(
|
||||
new LogMessageTypeFilteringOptions(),
|
||||
new TextLogMessageWriter(Logger.Instance)
|
||||
);
|
||||
new LogMessageTypeFilteringOptions(),
|
||||
new TextLogMessageWriter(Logger.Instance)
|
||||
);
|
||||
}
|
||||
|
||||
private static IMessageWriter BuildNotificationPanelMessageWriter()
|
||||
{
|
||||
return new OnlyLogMessageFilter(
|
||||
new MessageTypeFilterDecorator(
|
||||
new
|
||||
NotificationPanelMessageFilteringOptions(),
|
||||
new MessageFocusDecorator(
|
||||
Windows.ErrorsForm,
|
||||
new
|
||||
NotificationPanelSwitchOnMessageFilteringOptions(),
|
||||
new
|
||||
NotificationPanelMessageWriter(Windows
|
||||
.ErrorsForm)
|
||||
)
|
||||
)
|
||||
);
|
||||
new MessageTypeFilterDecorator(
|
||||
new NotificationPanelMessageFilteringOptions(),
|
||||
new MessageFocusDecorator(Windows.ErrorsForm,
|
||||
new NotificationPanelSwitchOnMessageFilteringOptions(),
|
||||
new NotificationPanelMessageWriter(Windows.ErrorsForm))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static IMessageWriter BuildPopupMessageWriter()
|
||||
{
|
||||
return new OnlyLogMessageFilter(
|
||||
new MessageTypeFilterDecorator(
|
||||
new PopupMessageFilteringOptions(),
|
||||
new PopupMessageWriter()
|
||||
)
|
||||
);
|
||||
new MessageTypeFilterDecorator(
|
||||
new PopupMessageFilteringOptions(),
|
||||
new PopupMessageWriter())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Management;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Messages;
|
||||
@@ -7,16 +8,14 @@ using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class StartupDataLogger
|
||||
{
|
||||
private readonly MessageCollector _messageCollector;
|
||||
|
||||
public StartupDataLogger(MessageCollector messageCollector)
|
||||
{
|
||||
if (messageCollector == null)
|
||||
throw new ArgumentNullException(nameof(messageCollector));
|
||||
|
||||
_messageCollector = messageCollector;
|
||||
_messageCollector = messageCollector ?? throw new ArgumentNullException(nameof(messageCollector));
|
||||
}
|
||||
|
||||
public void LogStartupData()
|
||||
@@ -30,25 +29,25 @@ namespace mRemoteNG.App.Initialization
|
||||
|
||||
private void LogSystemData()
|
||||
{
|
||||
var osData = GetOperatingSystemData();
|
||||
var architecture = GetArchitectureData();
|
||||
var nonEmptyData = Array.FindAll(new[] {osData, architecture}, s => !string.IsNullOrEmpty(s));
|
||||
var data = string.Join(" ", nonEmptyData);
|
||||
string osData = GetOperatingSystemData();
|
||||
string architecture = GetArchitectureData();
|
||||
string[] nonEmptyData = Array.FindAll(new[] {osData, architecture}, s => !string.IsNullOrEmpty(s));
|
||||
string data = string.Join(" ", nonEmptyData);
|
||||
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
|
||||
}
|
||||
|
||||
private string GetOperatingSystemData()
|
||||
{
|
||||
var osVersion = string.Empty;
|
||||
var servicePack = string.Empty;
|
||||
string osVersion = string.Empty;
|
||||
string servicePack = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True")
|
||||
foreach (ManagementBaseObject o in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True")
|
||||
.Get())
|
||||
{
|
||||
var managementObject = (ManagementObject)o;
|
||||
osVersion = Convert.ToString(managementObject.GetPropertyValue("Caption")).Trim();
|
||||
ManagementObject managementObject = (ManagementObject)o;
|
||||
osVersion = Convert.ToString(managementObject.GetPropertyValue("Caption"))?.Trim();
|
||||
servicePack = GetOSServicePack(servicePack, managementObject);
|
||||
}
|
||||
}
|
||||
@@ -57,13 +56,13 @@ namespace mRemoteNG.App.Initialization
|
||||
_messageCollector.AddExceptionMessage("Error retrieving operating system information from WMI.", ex);
|
||||
}
|
||||
|
||||
var osData = string.Join(" ", osVersion, servicePack);
|
||||
string osData = string.Join(" ", osVersion, servicePack);
|
||||
return osData;
|
||||
}
|
||||
|
||||
private string GetOSServicePack(string servicePack, ManagementObject managementObject)
|
||||
{
|
||||
var servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
|
||||
int servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
|
||||
if (servicePackNumber != 0)
|
||||
{
|
||||
servicePack = $"Service Pack {servicePackNumber}";
|
||||
@@ -74,14 +73,13 @@ namespace mRemoteNG.App.Initialization
|
||||
|
||||
private string GetArchitectureData()
|
||||
{
|
||||
var architecture = string.Empty;
|
||||
string architecture = string.Empty;
|
||||
try
|
||||
{
|
||||
foreach (var o in new ManagementObjectSearcher("SELECT AddressWidth FROM Win32_Processor WHERE DeviceID=\'CPU0\'")
|
||||
.Get())
|
||||
foreach (ManagementBaseObject o in new ManagementObjectSearcher("SELECT AddressWidth FROM Win32_Processor WHERE DeviceID=\'CPU0\'").Get())
|
||||
{
|
||||
var managementObject = (ManagementObject)o;
|
||||
var addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
|
||||
ManagementObject managementObject = (ManagementObject)o;
|
||||
int addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
|
||||
architecture = $"{addressWidth}-bit";
|
||||
}
|
||||
}
|
||||
@@ -95,7 +93,7 @@ namespace mRemoteNG.App.Initialization
|
||||
|
||||
private void LogApplicationData()
|
||||
{
|
||||
var data = $"{Application.ProductName} {Application.ProductVersion}";
|
||||
string data = $"{Application.ProductName} {Application.ProductVersion}";
|
||||
if (Runtime.IsPortableEdition)
|
||||
data += $" {Language.PortableEdition}";
|
||||
data += " starting.";
|
||||
@@ -104,20 +102,19 @@ namespace mRemoteNG.App.Initialization
|
||||
|
||||
private void LogCmdLineArgs()
|
||||
{
|
||||
var data = $"Command Line: {string.Join(" ", Environment.GetCommandLineArgs())}";
|
||||
string data = $"Command Line: {string.Join(" ", Environment.GetCommandLineArgs())}";
|
||||
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
|
||||
}
|
||||
|
||||
private void LogClrData()
|
||||
{
|
||||
var data = $"Microsoft .NET CLR {Environment.Version}";
|
||||
string data = $"Microsoft .NET CLR {Environment.Version}";
|
||||
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
|
||||
}
|
||||
|
||||
private void LogCultureData()
|
||||
{
|
||||
var data =
|
||||
$"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}";
|
||||
string data = $"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}";
|
||||
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Windows.Forms;
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Config;
|
||||
using mRemoteNG.Properties;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
using log4net.Repository;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class Logger
|
||||
{
|
||||
public static readonly Logger Instance = new Logger();
|
||||
public static readonly Logger Instance = new();
|
||||
|
||||
public ILog Log { get; private set; }
|
||||
|
||||
@@ -26,21 +26,27 @@ namespace mRemoteNG.App
|
||||
private void Initialize()
|
||||
{
|
||||
XmlConfigurator.Configure(LogManager.CreateRepository("mRemoteNG"));
|
||||
if (string.IsNullOrEmpty(Settings.Default.LogFilePath))
|
||||
Settings.Default.LogFilePath = BuildLogFilePath();
|
||||
|
||||
SetLogPath(Settings.Default.LogToApplicationDirectory ? DefaultLogPath : Settings.Default.LogFilePath);
|
||||
if (string.IsNullOrEmpty(Properties.OptionsNotificationsPage.Default.LogFilePath))
|
||||
{
|
||||
Properties.OptionsNotificationsPage.Default.LogFilePath = BuildLogFilePath();
|
||||
}
|
||||
|
||||
SetLogPath(Properties.OptionsNotificationsPage.Default.LogToApplicationDirectory ? DefaultLogPath : Properties.OptionsNotificationsPage.Default.LogFilePath);
|
||||
}
|
||||
|
||||
public void SetLogPath(string path)
|
||||
{
|
||||
var repository = LogManager.GetRepository("mRemoteNG");
|
||||
var appenders = repository.GetAppenders();
|
||||
ILoggerRepository repository = LogManager.GetRepository("mRemoteNG");
|
||||
|
||||
foreach (var appender in appenders)
|
||||
XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));
|
||||
|
||||
IAppender[] appenders = repository.GetAppenders();
|
||||
|
||||
foreach (IAppender appender in appenders)
|
||||
{
|
||||
var fileAppender = (RollingFileAppender)appender;
|
||||
if (fileAppender == null || fileAppender.Name != "LogFileAppender") continue;
|
||||
RollingFileAppender fileAppender = (RollingFileAppender)appender;
|
||||
if (fileAppender is not { Name: "LogFileAppender" }) continue;
|
||||
fileAppender.File = path;
|
||||
fileAppender.ActivateOptions();
|
||||
}
|
||||
@@ -50,22 +56,26 @@ namespace mRemoteNG.App
|
||||
|
||||
private static string BuildLogFilePath()
|
||||
{
|
||||
var logFilePath = Runtime.IsPortableEdition ? GetLogPathPortableEdition() : GetLogPathNormalEdition();
|
||||
var logFileName = Path.ChangeExtension(Application.ProductName, ".log");
|
||||
string logFilePath = Runtime.IsPortableEdition ? GetLogPathPortableEdition() : GetLogPathNormalEdition();
|
||||
|
||||
string logFileName = Path.ChangeExtension(Application.ProductName, ".log");
|
||||
|
||||
if (logFileName == null) return "mRemoteNG.log";
|
||||
var logFile = Path.Combine(logFilePath, logFileName);
|
||||
|
||||
string logFile = Path.Combine(logFilePath, logFileName);
|
||||
|
||||
return logFile;
|
||||
}
|
||||
|
||||
private static string GetLogPathNormalEdition()
|
||||
{
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
Application.ProductName);
|
||||
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Application.ProductName);
|
||||
}
|
||||
|
||||
private static string GetLogPathPortableEdition()
|
||||
{
|
||||
return Application.StartupPath;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text;
|
||||
|
||||
#pragma warning disable 649
|
||||
@@ -9,6 +10,7 @@ using System.Text;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class NativeMethods
|
||||
{
|
||||
#region Functions
|
||||
@@ -71,6 +73,12 @@ namespace mRemoteNG.App
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
|
||||
|
||||
[DllImport("User32.dll", CharSet = CharSet.Auto)]
|
||||
internal static extern bool ChangeClipboardChain(
|
||||
IntPtr hWndRemove, // handle to window to remove
|
||||
IntPtr hWndNewNext // handle to next window
|
||||
);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
|
||||
@@ -106,7 +114,6 @@ namespace mRemoteNG.App
|
||||
internal static extern bool SetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
|
||||
|
||||
[DllImport("kernel32", SetLastError = true)]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
internal static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Config.Settings;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class ProgramRoot
|
||||
{
|
||||
private static Mutex _mutex;
|
||||
private static FrmSplashScreenNew _frmSplashScreen = null;
|
||||
private static string customResourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Languages");
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
@@ -17,19 +24,79 @@ namespace mRemoteNG.App
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
if (Settings.Default.SingleInstance)
|
||||
Trace.WriteLine("!!!!!!=============== TEST ==================!!!!!!!!!!!!!");
|
||||
// Forcing to load System.Configuration.ConfigurationManager before any other assembly to be able to check settings
|
||||
try
|
||||
{
|
||||
string assemblyFile = "System.Configuration.ConfigurationManager" + ".dll";
|
||||
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
|
||||
|
||||
|
||||
if (File.Exists(assemblyPath))
|
||||
{
|
||||
Assembly.LoadFrom(assemblyPath);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
Trace.WriteLine("Error occured: " + ex.Message);
|
||||
}
|
||||
|
||||
//Subscribe to AssemblyResolve event
|
||||
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
|
||||
|
||||
//Check if local settings DB exist or accessible
|
||||
CheckLockalDB();
|
||||
|
||||
Lazy<bool> singleInstanceOption = new Lazy<bool>(() => Properties.OptionsStartupExitPage.Default.SingleInstance);
|
||||
|
||||
if (singleInstanceOption.Value)
|
||||
{
|
||||
StartApplicationAsSingleInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartApplication();
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckLockalDB()
|
||||
{
|
||||
LocalSettingsDBManager settingsManager = new LocalSettingsDBManager(dbPath: "mRemoteNG.appSettings", useEncryption: false, schemaFilePath: "");
|
||||
}
|
||||
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs resolveArgs)
|
||||
{
|
||||
string assemblyName = new AssemblyName(resolveArgs.Name).Name.Replace(".resources", string.Empty);
|
||||
string assemblyFile = assemblyName + ".dll";
|
||||
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
|
||||
|
||||
|
||||
if (File.Exists(assemblyPath))
|
||||
{
|
||||
return Assembly.LoadFrom(assemblyPath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void StartApplication()
|
||||
{
|
||||
CatchAllUnhandledExceptions();
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
var frmSplashScreen = FrmSplashScreen.getInstance();
|
||||
frmSplashScreen.Show();
|
||||
|
||||
_frmSplashScreen = FrmSplashScreenNew.GetInstance();
|
||||
|
||||
Screen targetScreen = Screen.PrimaryScreen;
|
||||
|
||||
Rectangle viewport = targetScreen.WorkingArea;
|
||||
_frmSplashScreen.Top = viewport.Top;
|
||||
_frmSplashScreen.Left = viewport.Left;
|
||||
// normally it should be screens[1] however due DPI apply 1 size "same" as default with 100%
|
||||
_frmSplashScreen.Left = viewport.Left + (targetScreen.Bounds.Size.Width - _frmSplashScreen.Width) / 2;
|
||||
_frmSplashScreen.Top = viewport.Top + (targetScreen.Bounds.Size.Height - _frmSplashScreen.Height) / 2;
|
||||
_frmSplashScreen.ShowInTaskbar = false;
|
||||
_frmSplashScreen.Show();
|
||||
|
||||
Application.Run(FrmMain.Default);
|
||||
}
|
||||
|
||||
@@ -41,7 +108,7 @@ namespace mRemoteNG.App
|
||||
private static void StartApplicationAsSingleInstance()
|
||||
{
|
||||
const string mutexID = "mRemoteNG_SingleInstanceMutex";
|
||||
_mutex = new Mutex(false, mutexID, out var newInstanceCreated);
|
||||
_mutex = new Mutex(false, mutexID, out bool newInstanceCreated);
|
||||
if (!newInstanceCreated)
|
||||
{
|
||||
SwitchToCurrentInstance();
|
||||
@@ -54,18 +121,18 @@ namespace mRemoteNG.App
|
||||
|
||||
private static void SwitchToCurrentInstance()
|
||||
{
|
||||
var singletonInstanceWindowHandle = GetRunningSingletonInstanceWindowHandle();
|
||||
IntPtr singletonInstanceWindowHandle = GetRunningSingletonInstanceWindowHandle();
|
||||
if (singletonInstanceWindowHandle == IntPtr.Zero) return;
|
||||
if (NativeMethods.IsIconic(singletonInstanceWindowHandle) != 0)
|
||||
NativeMethods.ShowWindow(singletonInstanceWindowHandle, (int)NativeMethods.SW_RESTORE);
|
||||
_ = NativeMethods.ShowWindow(singletonInstanceWindowHandle, (int)NativeMethods.SW_RESTORE);
|
||||
NativeMethods.SetForegroundWindow(singletonInstanceWindowHandle);
|
||||
}
|
||||
|
||||
private static IntPtr GetRunningSingletonInstanceWindowHandle()
|
||||
{
|
||||
var windowHandle = IntPtr.Zero;
|
||||
var currentProcess = Process.GetCurrentProcess();
|
||||
foreach (var enumeratedProcess in Process.GetProcessesByName(currentProcess.ProcessName))
|
||||
IntPtr windowHandle = IntPtr.Zero;
|
||||
Process currentProcess = Process.GetCurrentProcess();
|
||||
foreach (Process enumeratedProcess in Process.GetProcessesByName(currentProcess.ProcessName))
|
||||
{
|
||||
if (enumeratedProcess.Id != currentProcess.Id &&
|
||||
enumeratedProcess.MainModule.FileName == currentProcess.MainModule.FileName &&
|
||||
@@ -78,30 +145,31 @@ namespace mRemoteNG.App
|
||||
|
||||
private static void CatchAllUnhandledExceptions()
|
||||
{
|
||||
Application.ThreadException += ApplicationOnThreadException;
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
System.Windows.Forms.Application.ThreadException += ApplicationOnThreadException;
|
||||
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
|
||||
}
|
||||
|
||||
private static void ApplicationOnThreadException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
if (!FrmSplashScreen.getInstance().IsDisposed)
|
||||
FrmSplashScreen.getInstance().Close();
|
||||
// if (PresentationSource.FromVisual(FrmSplashScreenNew))
|
||||
FrmSplashScreenNew.GetInstance().Close();
|
||||
|
||||
if (FrmMain.Default.IsDisposed) return;
|
||||
|
||||
var window = new FrmUnhandledException(e.Exception, false);
|
||||
|
||||
FrmUnhandledException window = new(e.Exception, false);
|
||||
window.ShowDialog(FrmMain.Default);
|
||||
|
||||
}
|
||||
|
||||
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (!FrmSplashScreen.getInstance().IsDisposed)
|
||||
FrmSplashScreen.getInstance().Close();
|
||||
//TODO: Check if splash closed properly
|
||||
//if (!FrmSplashScreenNew.GetInstance().IsDisposed)
|
||||
// FrmSplashScreenNew.GetInstance().Close();
|
||||
|
||||
var window = new FrmUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
||||
FrmUnhandledException window = new(e.ExceptionObject as Exception, e.IsTerminating);
|
||||
window.ShowDialog(FrmMain.Default);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,11 @@ using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class Runtime
|
||||
{
|
||||
public static bool IsPortableEdition
|
||||
@@ -44,19 +46,19 @@ namespace mRemoteNG.App
|
||||
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
|
||||
public static ExternalToolsService ExternalToolsService { get; } = new ExternalToolsService();
|
||||
|
||||
public static SecureString EncryptionKey { get; set; } =
|
||||
new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
|
||||
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
|
||||
|
||||
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
|
||||
|
||||
public static ConnectionsService ConnectionsService { get; } =
|
||||
new ConnectionsService(PuttySessionsManager.Instance);
|
||||
public static ConnectionInitiator ConnectionInitiator { get; set; } = new ConnectionInitiator();
|
||||
|
||||
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance);
|
||||
|
||||
#region Connections Loading/Saving
|
||||
|
||||
public static void LoadConnectionsAsync()
|
||||
{
|
||||
var t = new Thread(LoadConnectionsBGd);
|
||||
Thread t = new(LoadConnectionsBGd);
|
||||
t.SetApartmentState(ApartmentState.STA);
|
||||
t.Start();
|
||||
}
|
||||
@@ -75,7 +77,7 @@ namespace mRemoteNG.App
|
||||
/// </param>
|
||||
public static void LoadConnections(bool withDialog = false)
|
||||
{
|
||||
var connectionFileName = "";
|
||||
string connectionFileName = "";
|
||||
|
||||
try
|
||||
{
|
||||
@@ -84,24 +86,28 @@ namespace mRemoteNG.App
|
||||
|
||||
if (withDialog)
|
||||
{
|
||||
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
|
||||
OpenFileDialog loadDialog = DialogFactory.BuildLoadConnectionsDialog();
|
||||
if (loadDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
connectionFileName = loadDialog.FileName;
|
||||
Settings.Default.UseSQLServer = false;
|
||||
Settings.Default.Save();
|
||||
Properties.OptionsDBsPage.Default.UseSQLServer = false;
|
||||
Properties.OptionsDBsPage.Default.Save();
|
||||
}
|
||||
else if (!Settings.Default.UseSQLServer)
|
||||
else if (!Properties.OptionsDBsPage.Default.UseSQLServer)
|
||||
{
|
||||
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
|
||||
}
|
||||
|
||||
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
|
||||
ConnectionsService.LoadConnections(Properties.OptionsDBsPage.Default.UseSQLServer, false, connectionFileName);
|
||||
|
||||
if (Settings.Default.UseSQLServer)
|
||||
if (Properties.OptionsDBsPage.Default.UseSQLServer)
|
||||
{
|
||||
ConnectionsService.LastSqlUpdate = DateTime.Now;
|
||||
ConnectionsService.LastSqlUpdate = DateTime.Now.ToUniversalTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectionsService.LastFileUpdate = System.IO.File.GetLastWriteTime(connectionFileName);
|
||||
}
|
||||
|
||||
// re-enable sql update checking after updates are loaded
|
||||
@@ -109,26 +115,20 @@ namespace mRemoteNG.App
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
FrmSplashScreen.getInstance().Close();
|
||||
FrmSplashScreenNew.GetInstance().Close();
|
||||
|
||||
if (Settings.Default.UseSQLServer)
|
||||
if (Properties.OptionsDBsPage.Default.UseSQLServer)
|
||||
{
|
||||
MessageCollector.AddExceptionMessage(Language.LoadFromSqlFailed, ex);
|
||||
var commandButtons = string.Join("|", Language._TryAgain,
|
||||
Language.CommandOpenConnectionFile,
|
||||
string.Format(Language.CommandExitProgram,
|
||||
Application.ProductName));
|
||||
CTaskDialog.ShowCommandBox(Application.ProductName, Language.LoadFromSqlFailed,
|
||||
Language.LoadFromSqlFailedContent,
|
||||
MiscTools.GetExceptionMessageRecursive(ex), "", "",
|
||||
commandButtons, false, ESysIcons.Error, ESysIcons.Error);
|
||||
string commandButtons = string.Join("|", Language._TryAgain, Language.CommandOpenConnectionFile, string.Format(Language.CommandExitProgram, Application.ProductName));
|
||||
CTaskDialog.ShowCommandBox(Application.ProductName, Language.LoadFromSqlFailed, Language.LoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error);
|
||||
switch (CTaskDialog.CommandButtonResult)
|
||||
{
|
||||
case 0:
|
||||
LoadConnections(withDialog);
|
||||
return;
|
||||
case 1:
|
||||
Settings.Default.UseSQLServer = false;
|
||||
Properties.OptionsDBsPage.Default.UseSQLServer = false;
|
||||
LoadConnections(true);
|
||||
return;
|
||||
default:
|
||||
@@ -152,19 +152,12 @@ namespace mRemoteNG.App
|
||||
Language.Exit
|
||||
};
|
||||
|
||||
var answered = false;
|
||||
bool answered = false;
|
||||
while (!answered)
|
||||
{
|
||||
try
|
||||
{
|
||||
CTaskDialog.ShowTaskDialogBox(
|
||||
GeneralAppInfo.ProductName,
|
||||
Language.ConnectionFileNotFound,
|
||||
"", "", "", "", "",
|
||||
string.Join(" | ", commandButtons),
|
||||
ETaskDialogButtons.None,
|
||||
ESysIcons.Question,
|
||||
ESysIcons.Question);
|
||||
CTaskDialog.ShowTaskDialogBox(GeneralAppInfo.ProductName, Language.ConnectionFileNotFound, "", "", "", "", "", string.Join(" | ", commandButtons), ETaskDialogButtons.None, ESysIcons.Question, ESysIcons.Question);
|
||||
|
||||
switch (CTaskDialog.CommandButtonResult)
|
||||
{
|
||||
@@ -189,11 +182,7 @@ namespace mRemoteNG.App
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
MessageCollector.AddExceptionMessage(
|
||||
string
|
||||
.Format(Language.ConnectionsFileCouldNotBeLoadedNew,
|
||||
connectionFileName), exc,
|
||||
MessageClass.InformationMsg);
|
||||
MessageCollector.AddExceptionMessage(string.Format(Language.ConnectionsFileCouldNotBeLoadedNew, connectionFileName), exc, MessageClass.InformationMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,12 +198,7 @@ namespace mRemoteNG.App
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(FrmMain.Default,
|
||||
string.Format(Language.ErrorStartupConnectionFileLoad, Environment.NewLine,
|
||||
Application.ProductName,
|
||||
ConnectionsService.GetStartupConnectionFileName(),
|
||||
MiscTools.GetExceptionMessageRecursive(ex)),
|
||||
@"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
MessageBox.Show(FrmMain.Default, string.Format(Language.ErrorStartupConnectionFileLoad, Environment.NewLine, Application.ProductName, ConnectionsService.GetStartupConnectionFileName(), MiscTools.GetExceptionMessageRecursive(ex)), @"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
@@ -6,10 +7,11 @@ namespace mRemoteNG.App
|
||||
{
|
||||
public static class Screens
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static void SendFormToScreen(Screen screen)
|
||||
{
|
||||
var frmMain = FrmMain.Default;
|
||||
var wasMax = false;
|
||||
FrmMain frmMain = FrmMain.Default;
|
||||
bool wasMax = false;
|
||||
|
||||
if (frmMain.WindowState == FormWindowState.Maximized)
|
||||
{
|
||||
|
||||
@@ -2,16 +2,19 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI.Controls;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class Shutdown
|
||||
{
|
||||
private static string _updateFilePath;
|
||||
@@ -60,8 +63,33 @@ namespace mRemoteNG.App
|
||||
|
||||
private static void SaveConnections()
|
||||
{
|
||||
if (Settings.Default.SaveConsOnExit)
|
||||
DateTime lastUpdate;
|
||||
DateTime updateDate;
|
||||
DateTime currentDate = DateTime.Now;
|
||||
|
||||
if ((Properties.OptionsBackupPage.Default.SaveConnectionsFrequency == (int)ConnectionsBackupFrequencyEnum.OnExit))
|
||||
{
|
||||
Runtime.ConnectionsService.SaveConnections();
|
||||
return;
|
||||
}
|
||||
lastUpdate = Runtime.ConnectionsService.UsingDatabase ? Runtime.ConnectionsService.LastSqlUpdate : Runtime.ConnectionsService.LastFileUpdate;
|
||||
|
||||
switch (Properties.OptionsBackupPage.Default.SaveConnectionsFrequency)
|
||||
{
|
||||
case (int)ConnectionsBackupFrequencyEnum.Daily:
|
||||
updateDate = lastUpdate.AddDays(1);
|
||||
break;
|
||||
case (int)ConnectionsBackupFrequencyEnum.Weekly:
|
||||
updateDate = lastUpdate.AddDays(7);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentDate >= updateDate)
|
||||
{
|
||||
Runtime.ConnectionsService.SaveConnections();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SaveSettings(Control quickConnectToolStrip,
|
||||
@@ -93,7 +121,7 @@ namespace mRemoteNG.App
|
||||
private static void RunUpdateFile()
|
||||
{
|
||||
if (UpdatePending)
|
||||
Process.Start(_updateFilePath);
|
||||
Process.Start(new ProcessStartInfo(_updateFilePath) { UseShellExecute = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.App.Initialization;
|
||||
using mRemoteNG.App.Update;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.Settings.Registry;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
@@ -17,8 +19,10 @@ using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class Startup
|
||||
{
|
||||
private RegistryLoader _RegistryLoader;
|
||||
private AppUpdater _appUpdate;
|
||||
private readonly ConnectionIconLoader _connectionIconLoader;
|
||||
private readonly FrmMain _frmMain = FrmMain.Default;
|
||||
@@ -27,19 +31,15 @@ namespace mRemoteNG.App
|
||||
|
||||
private Startup()
|
||||
{
|
||||
_appUpdate = new AppUpdater();
|
||||
_RegistryLoader = RegistryLoader.Instance; //created instance
|
||||
_appUpdate = new AppUpdater();
|
||||
_connectionIconLoader = new ConnectionIconLoader(GeneralAppInfo.HomePath + "\\Icons\\");
|
||||
}
|
||||
|
||||
static Startup()
|
||||
{
|
||||
}
|
||||
|
||||
public void InitializeProgram(MessageCollector messageCollector)
|
||||
{
|
||||
Debug.Print("---------------------------" + Environment.NewLine + "[START] - " +
|
||||
Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture));
|
||||
var startupLogger = new StartupDataLogger(messageCollector);
|
||||
Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture));
|
||||
StartupDataLogger startupLogger = new(messageCollector);
|
||||
startupLogger.LogStartupData();
|
||||
CompatibilityChecker.CheckCompatibility(messageCollector);
|
||||
ParseCommandLineArgs(messageCollector);
|
||||
@@ -51,21 +51,20 @@ namespace mRemoteNG.App
|
||||
|
||||
private static void ParseCommandLineArgs(MessageCollector messageCollector)
|
||||
{
|
||||
var interpreter = new StartupArgumentsInterpreter(messageCollector);
|
||||
StartupArgumentsInterpreter interpreter = new(messageCollector);
|
||||
interpreter.ParseArguments(Environment.GetCommandLineArgs());
|
||||
}
|
||||
|
||||
public void CreateConnectionsProvider(MessageCollector messageCollector)
|
||||
{
|
||||
messageCollector.AddMessage(MessageClass.DebugMsg, "Determining if we need a database syncronizer");
|
||||
if (!Settings.Default.UseSQLServer) return;
|
||||
if (!Properties.OptionsDBsPage.Default.UseSQLServer) return;
|
||||
messageCollector.AddMessage(MessageClass.DebugMsg, "Creating database syncronizer");
|
||||
Runtime.ConnectionsService.RemoteConnectionsSyncronizer =
|
||||
new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker());
|
||||
Runtime.ConnectionsService.RemoteConnectionsSyncronizer = new RemoteConnectionsSyncronizer(new SqlConnectionsUpdateChecker());
|
||||
Runtime.ConnectionsService.RemoteConnectionsSyncronizer.Enable();
|
||||
}
|
||||
|
||||
public void CheckForUpdate()
|
||||
public async Task CheckForUpdate()
|
||||
{
|
||||
if (_appUpdate == null)
|
||||
{
|
||||
@@ -76,43 +75,15 @@ namespace mRemoteNG.App
|
||||
return;
|
||||
}
|
||||
|
||||
var nextUpdateCheck =
|
||||
Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add(
|
||||
TimeSpan
|
||||
.FromDays(Convert.ToDouble(Settings
|
||||
.Default
|
||||
.CheckForUpdatesFrequencyDays))));
|
||||
if (!Settings.Default.UpdatePending && DateTime.UtcNow < nextUpdateCheck)
|
||||
DateTime nextUpdateCheck = Convert.ToDateTime(Properties.OptionsUpdatesPage.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Properties.OptionsUpdatesPage.Default.CheckForUpdatesFrequencyDays))));
|
||||
if (!Properties.OptionsUpdatesPage.Default.UpdatePending && DateTime.UtcNow < nextUpdateCheck)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_appUpdate.GetUpdateInfoCompletedEvent += GetUpdateInfoCompleted;
|
||||
_appUpdate.GetUpdateInfoAsync();
|
||||
}
|
||||
|
||||
private void GetUpdateInfoCompleted(object sender, AsyncCompletedEventArgs e)
|
||||
{
|
||||
if (_frmMain.InvokeRequired)
|
||||
{
|
||||
_frmMain.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), sender, e);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_appUpdate.GetUpdateInfoCompletedEvent -= GetUpdateInfoCompleted;
|
||||
|
||||
if (e.Cancelled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Error != null)
|
||||
{
|
||||
throw e.Error;
|
||||
}
|
||||
|
||||
await _appUpdate.GetUpdateInfoAsync();
|
||||
if (_appUpdate.IsUpdateAvailable())
|
||||
{
|
||||
Windows.Show(WindowType.Update);
|
||||
@@ -120,7 +91,7 @@ namespace mRemoteNG.App
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage("GetUpdateInfoCompleted() failed.", ex);
|
||||
Runtime.MessageCollector.AddExceptionMessage("CheckForUpdate() failed.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Properties;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
[Serializable]
|
||||
public sealed class SupportedCultures : Dictionary<string, string>
|
||||
{
|
||||
@@ -22,11 +24,11 @@ namespace mRemoteNG.App
|
||||
|
||||
private SupportedCultures()
|
||||
{
|
||||
foreach (var CultureName in Settings.Default.SupportedUICultures.Split(','))
|
||||
foreach (string CultureName in Properties.AppUI.Default.SupportedUICultures.Split(','))
|
||||
{
|
||||
try
|
||||
{
|
||||
var CultureInfo = new CultureInfo(CultureName.Trim());
|
||||
CultureInfo CultureInfo = new(CultureName.Trim());
|
||||
Add(CultureInfo.Name, CultureInfo.TextInfo.ToTitleCase(CultureInfo.NativeName));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -55,13 +57,13 @@ namespace mRemoteNG.App
|
||||
|
||||
public static string get_CultureName(string CultureNativeName)
|
||||
{
|
||||
var Names = new string[SingletonInstance.Count + 1];
|
||||
var NativeNames = new string[SingletonInstance.Count + 1];
|
||||
string[] Names = new string[SingletonInstance.Count + 1];
|
||||
string[] NativeNames = new string[SingletonInstance.Count + 1];
|
||||
|
||||
SingletonInstance.Keys.CopyTo(Names, 0);
|
||||
SingletonInstance.Values.CopyTo(NativeNames, 0);
|
||||
|
||||
for (var Index = 0; Index <= SingletonInstance.Count; Index++)
|
||||
for (int Index = 0; Index <= SingletonInstance.Count; Index++)
|
||||
{
|
||||
if (NativeNames[Index] == CultureNativeName)
|
||||
{
|
||||
@@ -81,8 +83,8 @@ namespace mRemoteNG.App
|
||||
{
|
||||
get
|
||||
{
|
||||
var ValueList = new List<string>();
|
||||
foreach (var Value in SingletonInstance.Values)
|
||||
List<string> ValueList = new();
|
||||
foreach (string Value in SingletonInstance.Values)
|
||||
{
|
||||
ValueList.Add(Value);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.ComponentModel;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using mRemoteNG.Properties;
|
||||
using System.Runtime.Versioning;
|
||||
#if !PORTABLE
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
@@ -19,31 +20,33 @@ using System.Windows.Forms;
|
||||
|
||||
namespace mRemoteNG.App.Update
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class AppUpdater
|
||||
{
|
||||
private const int _bufferLength = 8192;
|
||||
private WebProxy _webProxy;
|
||||
private Thread _getUpdateInfoThread;
|
||||
private Thread _getChangeLogThread;
|
||||
private HttpClient _httpClient;
|
||||
private CancellationTokenSource _changeLogCancelToken;
|
||||
private CancellationTokenSource _getUpdateInfoCancelToken;
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public UpdateInfo CurrentUpdateInfo { get; private set; }
|
||||
|
||||
public string ChangeLog { get; private set; }
|
||||
|
||||
public bool IsGetUpdateInfoRunning
|
||||
{
|
||||
get { return _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive; }
|
||||
get
|
||||
{
|
||||
return _getUpdateInfoCancelToken != null;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsGetChangeLogRunning
|
||||
{
|
||||
get { return _getChangeLogThread != null && _getChangeLogThread.IsAlive; }
|
||||
}
|
||||
|
||||
public bool IsDownloadUpdateRunning
|
||||
{
|
||||
get { return _downloadUpdateWebClient != null; }
|
||||
get
|
||||
{
|
||||
return _changeLogCancelToken != null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -52,39 +55,35 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
public AppUpdater()
|
||||
{
|
||||
SetProxySettings();
|
||||
SetDefaultProxySettings();
|
||||
}
|
||||
|
||||
private void SetProxySettings()
|
||||
private void SetDefaultProxySettings()
|
||||
{
|
||||
var shouldWeUseProxy = Settings.Default.UpdateUseProxy;
|
||||
var proxyAddress = Settings.Default.UpdateProxyAddress;
|
||||
var port = Settings.Default.UpdateProxyPort;
|
||||
var useAuthentication = Settings.Default.UpdateProxyUseAuthentication;
|
||||
var username = Settings.Default.UpdateProxyAuthUser;
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
|
||||
bool shouldWeUseProxy = Properties.OptionsUpdatesPage.Default.UpdateUseProxy;
|
||||
string proxyAddress = Properties.OptionsUpdatesPage.Default.UpdateProxyAddress;
|
||||
int port = Properties.OptionsUpdatesPage.Default.UpdateProxyPort;
|
||||
bool useAuthentication = Properties.OptionsUpdatesPage.Default.UpdateProxyUseAuthentication;
|
||||
string username = Properties.OptionsUpdatesPage.Default.UpdateProxyAuthUser;
|
||||
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
|
||||
string password = cryptographyProvider.Decrypt(Properties.OptionsUpdatesPage.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
|
||||
|
||||
SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password);
|
||||
}
|
||||
|
||||
public void SetProxySettings(bool useProxy,
|
||||
string address,
|
||||
int port,
|
||||
bool useAuthentication,
|
||||
string username,
|
||||
string password)
|
||||
public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password)
|
||||
{
|
||||
if (useProxy && !string.IsNullOrEmpty(address))
|
||||
{
|
||||
_webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address);
|
||||
|
||||
_webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_webProxy = null;
|
||||
}
|
||||
|
||||
UpdateHttpClient();
|
||||
}
|
||||
|
||||
public bool IsUpdateAvailable()
|
||||
@@ -96,54 +95,24 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion();
|
||||
}
|
||||
|
||||
public void GetUpdateInfoAsync()
|
||||
|
||||
public async Task DownloadUpdateAsync(IProgress<int> progress)
|
||||
{
|
||||
if (IsGetUpdateInfoRunning)
|
||||
{
|
||||
_getUpdateInfoThread.Abort();
|
||||
}
|
||||
_getUpdateInfoCancelToken.Cancel();
|
||||
_getUpdateInfoCancelToken.Dispose();
|
||||
_getUpdateInfoCancelToken = null;
|
||||
|
||||
_getUpdateInfoThread = new Thread(GetUpdateInfo);
|
||||
_getUpdateInfoThread.SetApartmentState(ApartmentState.STA);
|
||||
_getUpdateInfoThread.IsBackground = true;
|
||||
_getUpdateInfoThread.Start();
|
||||
}
|
||||
|
||||
public void GetChangeLogAsync()
|
||||
{
|
||||
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync().");
|
||||
}
|
||||
|
||||
if (IsGetChangeLogRunning)
|
||||
{
|
||||
_getChangeLogThread.Abort();
|
||||
}
|
||||
|
||||
_getChangeLogThread = new Thread(GetChangeLog);
|
||||
_getChangeLogThread.SetApartmentState(ApartmentState.STA);
|
||||
_getChangeLogThread.IsBackground = true;
|
||||
_getChangeLogThread.Start();
|
||||
}
|
||||
|
||||
public void DownloadUpdateAsync()
|
||||
{
|
||||
if (_downloadUpdateWebClient != null)
|
||||
{
|
||||
throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress.");
|
||||
}
|
||||
|
||||
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
|
||||
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
|
||||
}
|
||||
#if !PORTABLE
|
||||
CurrentUpdateInfo.UpdateFilePath =
|
||||
Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi"));
|
||||
CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi"));
|
||||
#else
|
||||
var sfd = new SaveFileDialog
|
||||
{
|
||||
@@ -160,137 +129,40 @@ namespace mRemoteNG.App.Update
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress,
|
||||
CurrentUpdateInfo.UpdateFilePath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private WebClient _downloadUpdateWebClient;
|
||||
|
||||
private WebClient DownloadUpdateWebClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_downloadUpdateWebClient != null)
|
||||
{
|
||||
return _downloadUpdateWebClient;
|
||||
}
|
||||
|
||||
_downloadUpdateWebClient = CreateWebClient();
|
||||
|
||||
_downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged;
|
||||
_downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted;
|
||||
|
||||
return _downloadUpdateWebClient;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private WebClient CreateWebClient()
|
||||
{
|
||||
var webClient = new WebClient();
|
||||
webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent);
|
||||
webClient.Proxy = _webProxy;
|
||||
return webClient;
|
||||
}
|
||||
|
||||
private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result,
|
||||
Exception exception,
|
||||
bool cancelled,
|
||||
object userToken)
|
||||
{
|
||||
var type = typeof(DownloadStringCompletedEventArgs);
|
||||
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)};
|
||||
var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null);
|
||||
object[] arguments = {result, exception, cancelled, userToken};
|
||||
|
||||
if (constructor == null)
|
||||
return null;
|
||||
return (DownloadStringCompletedEventArgs)constructor.Invoke(arguments);
|
||||
}
|
||||
|
||||
private DownloadStringCompletedEventArgs DownloadString(Uri address)
|
||||
{
|
||||
var webClient = CreateWebClient();
|
||||
var result = string.Empty;
|
||||
Exception exception = null;
|
||||
var cancelled = false;
|
||||
|
||||
try
|
||||
{
|
||||
result = webClient.DownloadString(address);
|
||||
}
|
||||
catch (ThreadAbortException)
|
||||
{
|
||||
cancelled = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exception = ex;
|
||||
}
|
||||
_getUpdateInfoCancelToken = new CancellationTokenSource();
|
||||
using HttpResponseMessage response = await _httpClient.GetAsync(CurrentUpdateInfo.DownloadAddress, HttpCompletionOption.ResponseHeadersRead, _getUpdateInfoCancelToken.Token);
|
||||
byte[] buffer = new byte[_bufferLength];
|
||||
long totalBytes = response.Content.Headers.ContentLength ?? 0;
|
||||
long readBytes = 0L;
|
||||
|
||||
return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null);
|
||||
}
|
||||
|
||||
private void GetUpdateInfo()
|
||||
{
|
||||
var e = DownloadString(UpdateChannelInfo.GetUpdateChannelInfo());
|
||||
|
||||
if (!e.Cancelled && e.Error == null)
|
||||
{
|
||||
try
|
||||
await using (Stream httpStream = await response.Content.ReadAsStreamAsync(_getUpdateInfoCancelToken.Token))
|
||||
{
|
||||
CurrentUpdateInfo = UpdateInfo.FromString(e.Result);
|
||||
await using FileStream fileStream = new(CurrentUpdateInfo.UpdateFilePath, FileMode.Create,
|
||||
FileAccess.Write, FileShare.None, _bufferLength, true);
|
||||
|
||||
Settings.Default.CheckForUpdatesLastCheck = DateTime.UtcNow;
|
||||
if (!Settings.Default.UpdatePending)
|
||||
while (readBytes <= totalBytes || !_getUpdateInfoCancelToken.IsCancellationRequested)
|
||||
{
|
||||
Settings.Default.UpdatePending = IsUpdateAvailable();
|
||||
int bytesRead =
|
||||
await httpStream.ReadAsync(buffer.AsMemory(0, _bufferLength), _getUpdateInfoCancelToken.Token);
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
progress.Report(100);
|
||||
break;
|
||||
}
|
||||
|
||||
await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead), _getUpdateInfoCancelToken.Token);
|
||||
|
||||
readBytes += bytesRead;
|
||||
|
||||
int percentComplete = (int)(readBytes * 100 / totalBytes);
|
||||
progress.Report(percentComplete);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
e = NewDownloadStringCompletedEventArgs(e.Result, ex, e.Cancelled, null);
|
||||
}
|
||||
}
|
||||
|
||||
GetUpdateInfoCompletedEventEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void GetChangeLog()
|
||||
{
|
||||
var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress);
|
||||
|
||||
if (!e.Cancelled && e.Error == null)
|
||||
{
|
||||
ChangeLog = e.Result;
|
||||
}
|
||||
|
||||
GetChangeLogCompletedEventEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e)
|
||||
{
|
||||
DownloadUpdateProgressChangedEventEvent?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e)
|
||||
{
|
||||
var raiseEventArgs = e;
|
||||
|
||||
if (!e.Cancelled && e.Error == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if !PORTABLE
|
||||
var updateAuthenticode = new Authenticode(CurrentUpdateInfo.UpdateFilePath)
|
||||
Authenticode updateAuthenticode = new(CurrentUpdateInfo.UpdateFilePath)
|
||||
{
|
||||
RequireThumbprintMatch = true,
|
||||
ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint
|
||||
@@ -307,101 +179,85 @@ namespace mRemoteNG.App.Update
|
||||
}
|
||||
#endif
|
||||
|
||||
using (var cksum = SHA512.Create())
|
||||
{
|
||||
using (var stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath))
|
||||
{
|
||||
var hash = cksum.ComputeHash(stream);
|
||||
var hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
|
||||
if (!hashString.Equals(CurrentUpdateInfo.Checksum))
|
||||
throw new Exception("SHA512 Hashes didn't match!");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null);
|
||||
}
|
||||
using SHA512 checksum = SHA512.Create();
|
||||
await using FileStream stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath);
|
||||
byte[] hash = await checksum.ComputeHashAsync(stream);
|
||||
string hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
|
||||
if (!hashString.Equals(CurrentUpdateInfo.Checksum))
|
||||
throw new Exception("SHA512 Hashes didn't match!");
|
||||
} finally{
|
||||
_getUpdateInfoCancelToken?.Dispose();
|
||||
_getUpdateInfoCancelToken = null;
|
||||
}
|
||||
|
||||
if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null)
|
||||
{
|
||||
File.Delete(CurrentUpdateInfo.UpdateFilePath);
|
||||
}
|
||||
|
||||
DownloadUpdateCompletedEventEvent?.Invoke(this, raiseEventArgs);
|
||||
|
||||
_downloadUpdateWebClient.Dispose();
|
||||
_downloadUpdateWebClient = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
#region Private Methods
|
||||
|
||||
private AsyncCompletedEventHandler GetUpdateInfoCompletedEventEvent;
|
||||
|
||||
public event AsyncCompletedEventHandler GetUpdateInfoCompletedEvent
|
||||
private void UpdateHttpClient()
|
||||
{
|
||||
add
|
||||
if (_httpClient != null)
|
||||
{
|
||||
GetUpdateInfoCompletedEventEvent =
|
||||
(AsyncCompletedEventHandler)Delegate.Combine(GetUpdateInfoCompletedEventEvent, value);
|
||||
_httpClient.Dispose();
|
||||
}
|
||||
remove
|
||||
|
||||
HttpClientHandler httpClientHandler = new();
|
||||
if (_webProxy != null)
|
||||
{
|
||||
GetUpdateInfoCompletedEventEvent =
|
||||
(AsyncCompletedEventHandler)Delegate.Remove(GetUpdateInfoCompletedEventEvent, value);
|
||||
httpClientHandler.UseProxy = true;
|
||||
httpClientHandler.Proxy = _webProxy;
|
||||
}
|
||||
_httpClient = new HttpClient(httpClientHandler);
|
||||
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(GeneralAppInfo.UserAgent);
|
||||
}
|
||||
|
||||
public async Task GetUpdateInfoAsync()
|
||||
{
|
||||
if (IsGetUpdateInfoRunning)
|
||||
{
|
||||
_getUpdateInfoCancelToken.Cancel();
|
||||
_getUpdateInfoCancelToken.Dispose();
|
||||
_getUpdateInfoCancelToken = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_getUpdateInfoCancelToken = new CancellationTokenSource();
|
||||
string updateInfo = await _httpClient.GetStringAsync(UpdateChannelInfo.GetUpdateChannelInfo(), _getUpdateInfoCancelToken.Token);
|
||||
CurrentUpdateInfo = UpdateInfo.FromString(updateInfo);
|
||||
Properties.OptionsUpdatesPage.Default.CheckForUpdatesLastCheck = DateTime.UtcNow;
|
||||
|
||||
if (!Properties.OptionsUpdatesPage.Default.UpdatePending)
|
||||
{
|
||||
Properties.OptionsUpdatesPage.Default.UpdatePending = IsUpdateAvailable();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_getUpdateInfoCancelToken?.Dispose();
|
||||
_getUpdateInfoCancelToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
private AsyncCompletedEventHandler GetChangeLogCompletedEventEvent;
|
||||
|
||||
public event AsyncCompletedEventHandler GetChangeLogCompletedEvent
|
||||
public async Task<string> GetChangeLogAsync()
|
||||
{
|
||||
add
|
||||
if (IsGetChangeLogRunning)
|
||||
{
|
||||
GetChangeLogCompletedEventEvent =
|
||||
(AsyncCompletedEventHandler)Delegate.Combine(GetChangeLogCompletedEventEvent, value);
|
||||
_changeLogCancelToken.Cancel();
|
||||
_changeLogCancelToken.Dispose();
|
||||
_changeLogCancelToken = null;
|
||||
}
|
||||
remove
|
||||
{
|
||||
GetChangeLogCompletedEventEvent =
|
||||
(AsyncCompletedEventHandler)Delegate.Remove(GetChangeLogCompletedEventEvent, value);
|
||||
}
|
||||
}
|
||||
|
||||
private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent;
|
||||
|
||||
public event DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEvent
|
||||
{
|
||||
add
|
||||
try
|
||||
{
|
||||
DownloadUpdateProgressChangedEventEvent =
|
||||
(DownloadProgressChangedEventHandler)Delegate.Combine(DownloadUpdateProgressChangedEventEvent,
|
||||
value);
|
||||
_changeLogCancelToken = new CancellationTokenSource();
|
||||
return await _httpClient.GetStringAsync(CurrentUpdateInfo.ChangeLogAddress, _changeLogCancelToken.Token);
|
||||
}
|
||||
remove
|
||||
finally
|
||||
{
|
||||
DownloadUpdateProgressChangedEventEvent =
|
||||
(DownloadProgressChangedEventHandler)Delegate.Remove(DownloadUpdateProgressChangedEventEvent,
|
||||
value);
|
||||
}
|
||||
}
|
||||
|
||||
private AsyncCompletedEventHandler DownloadUpdateCompletedEventEvent;
|
||||
|
||||
public event AsyncCompletedEventHandler DownloadUpdateCompletedEvent
|
||||
{
|
||||
add
|
||||
{
|
||||
DownloadUpdateCompletedEventEvent =
|
||||
(AsyncCompletedEventHandler)Delegate.Combine(DownloadUpdateCompletedEventEvent, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
DownloadUpdateCompletedEventEvent =
|
||||
(AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value);
|
||||
_changeLogCancelToken?.Dispose();
|
||||
_changeLogCancelToken = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,19 +34,19 @@ namespace mRemoteNG.App.Update
|
||||
// no separators means no valid update data...
|
||||
if (content.Trim().IndexOfAny(keyValueSeparators) == -1) return;
|
||||
|
||||
using (var sr = new StringReader(content))
|
||||
using (StringReader sr = new(content))
|
||||
{
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
var trimmedLine = line.Trim();
|
||||
string trimmedLine = line.Trim();
|
||||
if (trimmedLine.Length == 0)
|
||||
continue;
|
||||
|
||||
if (trimmedLine.Substring(0, 1).IndexOfAny(commentCharacters) != -1)
|
||||
continue;
|
||||
|
||||
var parts = trimmedLine.Split(keyValueSeparators, 2);
|
||||
string[] parts = trimmedLine.Split(keyValueSeparators, 2);
|
||||
if (parts.Length != 2)
|
||||
continue;
|
||||
|
||||
@@ -68,13 +68,13 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
public Version GetVersion(string key = "Version")
|
||||
{
|
||||
var value = GetString(key);
|
||||
string value = GetString(key);
|
||||
return string.IsNullOrEmpty(value) ? null : new Version(value);
|
||||
}
|
||||
|
||||
public Uri GetUri(string key)
|
||||
{
|
||||
var value = GetString(key);
|
||||
string value = GetString(key);
|
||||
return string.IsNullOrEmpty(value) ? null : new Uri(value);
|
||||
}
|
||||
|
||||
@@ -85,8 +85,8 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
public string GetFileName()
|
||||
{
|
||||
var value = GetString("dURL");
|
||||
var sv = value.Split('/');
|
||||
string value = GetString("dURL");
|
||||
string[] sv = value.Split('/');
|
||||
return sv[sv.Length - 1];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@ namespace mRemoteNG.App.Update
|
||||
|
||||
public static UpdateInfo FromString(string input)
|
||||
{
|
||||
var newInfo = new UpdateInfo();
|
||||
UpdateInfo newInfo = new();
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
newInfo.IsValid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var updateFile = new UpdateFile(input);
|
||||
UpdateFile updateFile = new(input);
|
||||
newInfo.Version = updateFile.GetVersion();
|
||||
newInfo.DownloadAddress = updateFile.GetUri("dURL");
|
||||
newInfo.ChangeLogAddress = updateFile.GetUri("clURL");
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
using System;
|
||||
#region Usings
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Window;
|
||||
#endregion
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class Windows
|
||||
{
|
||||
private static ActiveDirectoryImportWindow _adimportForm;
|
||||
private static HelpWindow _helpForm;
|
||||
private static ExternalToolsWindow _externalappsForm;
|
||||
private static PortScanWindow _portscanForm;
|
||||
private static ScreenshotManagerWindow _screenshotmanagerForm;
|
||||
private static UltraVNCWindow _ultravncscForm;
|
||||
private static ConnectionTreeWindow _treeForm;
|
||||
|
||||
@@ -23,7 +26,6 @@ namespace mRemoteNG.App
|
||||
|
||||
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
|
||||
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
|
||||
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
|
||||
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
|
||||
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
|
||||
|
||||
@@ -32,7 +34,7 @@ namespace mRemoteNG.App
|
||||
{
|
||||
try
|
||||
{
|
||||
var dockPanel = FrmMain.Default.pnlDock;
|
||||
WeifenLuo.WinFormsUI.Docking.DockPanel dockPanel = FrmMain.Default.pnlDock;
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (windowType)
|
||||
{
|
||||
@@ -42,11 +44,8 @@ namespace mRemoteNG.App
|
||||
_adimportForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.Options:
|
||||
using (var optionsForm = new FrmOptions())
|
||||
{
|
||||
optionsForm.ShowDialog(dockPanel);
|
||||
}
|
||||
|
||||
FrmMain.OptionsForm.SetActivatedPage(Language.StartupExit);
|
||||
FrmMain.OptionsForm.Visible = true;
|
||||
break;
|
||||
case WindowType.SSHTransfer:
|
||||
if (SshtransferForm == null || SshtransferForm.IsDisposed)
|
||||
@@ -58,11 +57,6 @@ namespace mRemoteNG.App
|
||||
UpdateForm = new UpdateWindow();
|
||||
UpdateForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.Help:
|
||||
if (_helpForm == null || _helpForm.IsDisposed)
|
||||
_helpForm = new HelpWindow();
|
||||
_helpForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.ExternalApps:
|
||||
if (_externalappsForm == null || _externalappsForm.IsDisposed)
|
||||
_externalappsForm = new ExternalToolsWindow();
|
||||
@@ -72,10 +66,6 @@ namespace mRemoteNG.App
|
||||
_portscanForm = new PortScanWindow();
|
||||
_portscanForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.ScreenshotManager:
|
||||
_screenshotmanagerForm = new ScreenshotManagerWindow();
|
||||
_screenshotmanagerForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.UltraVNCSC:
|
||||
if (_ultravncscForm == null || _ultravncscForm.IsDisposed)
|
||||
_ultravncscForm = new UltraVNCWindow();
|
||||
|
||||
9
mRemoteNG/Config/ACLPermissions.cs
Normal file
9
mRemoteNG/Config/ACLPermissions.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace mRemoteNG.Config.ACL
|
||||
{
|
||||
public enum ACLPermissions
|
||||
{
|
||||
Hidden = 0,
|
||||
ReadOnly = 1,
|
||||
WriteAllow = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public enum ConnectionsBackupFrequencyEnum
|
||||
{
|
||||
Unassigned = 0,
|
||||
Never = 1,
|
||||
OnEdit = 2,
|
||||
OnExit = 3,
|
||||
Daily = 4,
|
||||
Weekly = 5,
|
||||
Custom = 6
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.Csv;
|
||||
@@ -7,6 +8,7 @@ using mRemoteNG.Tree;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class CsvConnectionsSaver : ISaver<ConnectionTreeModel>
|
||||
{
|
||||
private readonly string _connectionFileName;
|
||||
@@ -25,10 +27,10 @@ namespace mRemoteNG.Config.Connections
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
var csvConnectionsSerializer =
|
||||
new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
|
||||
var dataProvider = new FileDataProvider(_connectionFileName);
|
||||
var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
|
||||
CsvConnectionsSerializerMremotengFormat csvConnectionsSerializer =
|
||||
new(_saveFilter, Runtime.CredentialProviderCatalog);
|
||||
FileDataProvider dataProvider = new(_connectionFileName);
|
||||
string csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
|
||||
dataProvider.Save(csvContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
using mRemoteNG.App;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Timers;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.Config.Connections.Multiuser
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class RemoteConnectionsSyncronizer : IConnectionsUpdateChecker
|
||||
{
|
||||
private readonly Timer _updateTimer;
|
||||
private readonly System.Timers.Timer _updateTimer;
|
||||
private readonly IConnectionsUpdateChecker _updateChecker;
|
||||
|
||||
public double TimerIntervalInMilliseconds
|
||||
@@ -19,7 +21,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
public RemoteConnectionsSyncronizer(IConnectionsUpdateChecker updateChecker)
|
||||
{
|
||||
_updateChecker = updateChecker;
|
||||
_updateTimer = new Timer(3000);
|
||||
_updateTimer = new System.Timers.Timer(3000);
|
||||
SetEventListeners();
|
||||
}
|
||||
|
||||
@@ -27,8 +29,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
{
|
||||
_updateChecker.UpdateCheckStarted += OnUpdateCheckStarted;
|
||||
_updateChecker.UpdateCheckFinished += OnUpdateCheckFinished;
|
||||
_updateChecker.ConnectionsUpdateAvailable +=
|
||||
(sender, args) => ConnectionsUpdateAvailable?.Invoke(sender, args);
|
||||
_updateChecker.ConnectionsUpdateAvailable += (sender, args) => ConnectionsUpdateAvailable?.Invoke(sender, args);
|
||||
_updateTimer.Elapsed += (sender, args) => _updateChecker.IsUpdateAvailableAsync();
|
||||
ConnectionsUpdateAvailable += Load;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
@@ -8,6 +9,7 @@ using mRemoteNG.Messages;
|
||||
|
||||
namespace mRemoteNG.Config.Connections.Multiuser
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlConnectionsUpdateChecker : IConnectionsUpdateChecker
|
||||
{
|
||||
private readonly IDatabaseConnector _dbConnector;
|
||||
@@ -27,7 +29,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
{
|
||||
RaiseUpdateCheckStartedEvent();
|
||||
ConnectToSqlDb();
|
||||
var updateIsAvailable = DatabaseIsMoreUpToDateThanUs();
|
||||
bool updateIsAvailable = DatabaseIsMoreUpToDateThanUs();
|
||||
if (updateIsAvailable)
|
||||
RaiseConnectionsUpdateAvailableEvent();
|
||||
RaiseUpdateCheckFinishedEvent(updateIsAvailable);
|
||||
@@ -36,7 +38,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
|
||||
public void IsUpdateAvailableAsync()
|
||||
{
|
||||
var thread = new Thread(() => IsUpdateAvailable());
|
||||
Thread thread = new(() => IsUpdateAvailable());
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
}
|
||||
@@ -49,46 +51,44 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
|
||||
"Unable to connect to Sql DB to check for updates." +
|
||||
Environment.NewLine + e.Message, true);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"Unable to connect to SQL DB to check for updates.{Environment.NewLine}{e.Message}", true);
|
||||
}
|
||||
}
|
||||
|
||||
private bool DatabaseIsMoreUpToDateThanUs()
|
||||
{
|
||||
var lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
|
||||
var amTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
|
||||
DateTime lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
|
||||
bool amTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
|
||||
return (lastUpdateInDb > LastUpdateTime && !amTheLastoneUpdated);
|
||||
}
|
||||
|
||||
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
|
||||
{
|
||||
DateTime lastSqlUpdateWithoutMilliseconds =
|
||||
new DateTime(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond),
|
||||
LastUpdateTime.Kind);
|
||||
DateTime lastSqlUpdateWithoutMilliseconds = new(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond), LastUpdateTime.Kind);
|
||||
return lastUpdateInDb == lastSqlUpdateWithoutMilliseconds;
|
||||
}
|
||||
|
||||
private DateTime GetLastUpdateTimeFromDbResponse()
|
||||
{
|
||||
var lastUpdateInDb = default(DateTime);
|
||||
DateTime lastUpdateInDb = default(DateTime);
|
||||
|
||||
try
|
||||
{
|
||||
var sqlReader = _dbQuery.ExecuteReader(CommandBehavior.CloseConnection);
|
||||
DbDataReader sqlReader = _dbQuery.ExecuteReader(CommandBehavior.CloseConnection);
|
||||
sqlReader.Read();
|
||||
if (sqlReader.HasRows)
|
||||
{
|
||||
lastUpdateInDb = Convert.ToDateTime(sqlReader["LastUpdate"]);
|
||||
}
|
||||
sqlReader.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
|
||||
"Error executing Sql query to get updates from the DB." +
|
||||
Environment.NewLine + ex.Message, true);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Error executing SQL query to get updates from the DB." + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
|
||||
_lastDatabaseUpdateTime = lastUpdateInDb;
|
||||
|
||||
return lastUpdateInDb;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
|
||||
private void RaiseUpdateCheckFinishedEvent(bool updateAvailable)
|
||||
{
|
||||
var args = new ConnectionsUpdateCheckFinishedEventArgs {UpdateAvailable = updateAvailable};
|
||||
ConnectionsUpdateCheckFinishedEventArgs args = new() { UpdateAvailable = updateAvailable};
|
||||
UpdateCheckFinished?.Invoke(this, args);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
private void RaiseConnectionsUpdateAvailableEvent()
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Remote connection update is available");
|
||||
var args = new ConnectionsUpdateAvailableEventArgs(_dbConnector, _lastDatabaseUpdateTime);
|
||||
ConnectionsUpdateAvailableEventArgs args = new(_dbConnector, _lastDatabaseUpdateTime);
|
||||
ConnectionsUpdateAvailable?.Invoke(this, args);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,12 @@ using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.Properties;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SaveConnectionsOnEdit
|
||||
{
|
||||
private readonly ConnectionsService _connectionsService;
|
||||
@@ -19,41 +22,38 @@ namespace mRemoteNG.Config.Connections
|
||||
connectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded;
|
||||
}
|
||||
|
||||
private void ConnectionsServiceOnConnectionsLoaded(object sender,
|
||||
ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
|
||||
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
|
||||
{
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged +=
|
||||
ConnectionTreeModelOnCollectionChanged;
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
|
||||
|
||||
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
|
||||
foreach (Tree.ConnectionTreeModel oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
|
||||
{
|
||||
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
|
||||
oldTree.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectionTreeModelOnPropertyChanged(object sender,
|
||||
PropertyChangedEventArgs propertyChangedEventArgs)
|
||||
private void ConnectionTreeModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
|
||||
{
|
||||
SaveConnectionOnEdit(propertyChangedEventArgs.PropertyName);
|
||||
}
|
||||
|
||||
private void ConnectionTreeModelOnCollectionChanged(object sender,
|
||||
NotifyCollectionChangedEventArgs
|
||||
notifyCollectionChangedEventArgs)
|
||||
private void ConnectionTreeModelOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
|
||||
{
|
||||
SaveConnectionOnEdit();
|
||||
}
|
||||
|
||||
private void SaveConnectionOnEdit(string propertyName = "")
|
||||
{
|
||||
if (!Properties.Settings.Default.SaveConnectionsAfterEveryEdit)
|
||||
return;
|
||||
if (FrmMain.Default.IsClosing)
|
||||
return;
|
||||
//OBSOLETE: mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit is obsolete and should be removed in a future release
|
||||
if (Properties.OptionsBackupPage.Default.SaveConnectionsAfterEveryEdit || (Properties.OptionsBackupPage.Default.SaveConnectionsFrequency == (int)ConnectionsBackupFrequencyEnum.OnEdit))
|
||||
{
|
||||
if (FrmMain.Default.IsClosing)
|
||||
return;
|
||||
|
||||
_connectionsService.SaveConnectionsAsync(propertyName);
|
||||
_connectionsService.SaveConnectionsAsync(propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.Sql;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
@@ -17,66 +18,58 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlConnectionsLoader : IConnectionsLoader
|
||||
{
|
||||
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>>
|
||||
_localConnectionPropertiesDeserializer;
|
||||
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
|
||||
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; } =
|
||||
() => MiscTools.PasswordDialog("", false);
|
||||
private Func<Optional<SecureString>> AuthenticationRequestor { get; set; } = () => MiscTools.PasswordDialog("", false);
|
||||
|
||||
public SqlConnectionsLoader(
|
||||
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
|
||||
IDataProvider<string> dataProvider)
|
||||
{
|
||||
_localConnectionPropertiesDeserializer =
|
||||
localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
|
||||
_localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
|
||||
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Load()
|
||||
{
|
||||
var connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
|
||||
var dataProvider = new SqlDataProvider(connector);
|
||||
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
|
||||
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
|
||||
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
|
||||
|
||||
var metaData = metaDataRetriever.GetDatabaseMetaData(connector) ??
|
||||
HandleFirstRun(metaDataRetriever, connector);
|
||||
var decryptionKey = GetDecryptionKey(metaData);
|
||||
IDatabaseConnector connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
|
||||
SqlDataProvider dataProvider = new(connector);
|
||||
SqlDatabaseMetaDataRetriever metaDataRetriever = new();
|
||||
SqlDatabaseVersionVerifier databaseVersionVerifier = new(connector);
|
||||
LegacyRijndaelCryptographyProvider cryptoProvider = new();
|
||||
SqlConnectionListMetaData metaData = metaDataRetriever.GetDatabaseMetaData(connector) ?? HandleFirstRun(metaDataRetriever, connector);
|
||||
Optional<SecureString> decryptionKey = GetDecryptionKey(metaData);
|
||||
|
||||
if (!decryptionKey.Any())
|
||||
throw new Exception("Could not load SQL connections");
|
||||
|
||||
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
|
||||
var dataTable = dataProvider.Load();
|
||||
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
|
||||
var connectionTree = deserializer.Deserialize(dataTable);
|
||||
System.Data.DataTable dataTable = dataProvider.Load();
|
||||
DataTableDeserializer deserializer = new(cryptoProvider, decryptionKey.First());
|
||||
ConnectionTreeModel connectionTree = deserializer.Deserialize(dataTable);
|
||||
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
|
||||
return connectionTree;
|
||||
}
|
||||
|
||||
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
var cipherText = metaData.Protected;
|
||||
var authenticator = new PasswordAuthenticator(cryptographyProvider, cipherText, AuthenticationRequestor);
|
||||
var authenticated =
|
||||
authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword
|
||||
.ConvertToSecureString());
|
||||
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
|
||||
string cipherText = metaData.Protected;
|
||||
PasswordAuthenticator authenticator = new(cryptographyProvider, cipherText, AuthenticationRequestor);
|
||||
bool authenticated = authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword.ConvertToSecureString());
|
||||
|
||||
if (authenticated)
|
||||
return authenticator.LastAuthenticatedPassword;
|
||||
return Optional<SecureString>.Empty;
|
||||
return authenticated ? authenticator.LastAuthenticatedPassword : Optional<SecureString>.Empty;
|
||||
}
|
||||
|
||||
private void ApplyLocalConnectionProperties(ContainerInfo rootNode)
|
||||
{
|
||||
var localPropertiesXml = _dataProvider.Load();
|
||||
var localConnectionProperties = _localConnectionPropertiesDeserializer.Deserialize(localPropertiesXml);
|
||||
string localPropertiesXml = _dataProvider.Load();
|
||||
IEnumerable<LocalConnectionPropertiesModel> localConnectionProperties = _localConnectionPropertiesDeserializer.Deserialize(localPropertiesXml);
|
||||
|
||||
rootNode
|
||||
.GetRecursiveChildList()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user