mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Compare commits
1152 Commits
v1.75Beta2
...
refactor_r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bd43afcd3 | ||
|
|
d85c46930f | ||
|
|
4614de1dea | ||
|
|
f33102d545 | ||
|
|
8003f410a7 | ||
|
|
b21dc9a062 | ||
|
|
36ed189177 | ||
|
|
b3b961c647 | ||
|
|
a212121f4a | ||
|
|
3d9d57b7fa | ||
|
|
2c1734aea6 | ||
|
|
301c39aad0 | ||
|
|
5be346c89d | ||
|
|
e4eaf0037e | ||
|
|
8f97be82cb | ||
|
|
4ab7f92b82 | ||
|
|
0ec95a7729 | ||
|
|
98c38716cd | ||
|
|
6a46df780c | ||
|
|
7788198f26 | ||
|
|
3010963283 | ||
|
|
6522524c0f | ||
|
|
160434c114 | ||
|
|
36acb9ac12 | ||
|
|
1a06783dab | ||
|
|
ec38ee9abc | ||
|
|
2e82551b7c | ||
|
|
49121fb945 | ||
|
|
6e436f55c3 | ||
|
|
afb0131a28 | ||
|
|
92588282a6 | ||
|
|
765e997976 | ||
|
|
ddbf6a2e7a | ||
|
|
8567e912a3 | ||
|
|
42e4f168d1 | ||
|
|
7c98f2809c | ||
|
|
e68b529a34 | ||
|
|
1ed4987277 | ||
|
|
a5d1f0995c | ||
|
|
b6951df72e | ||
|
|
b1c31048a9 | ||
|
|
e13faa1b66 | ||
|
|
9349aca76e | ||
|
|
4946726d1e | ||
|
|
72c7800c02 | ||
|
|
e4c35b2ba2 | ||
|
|
bccb885508 | ||
|
|
7b7e0e0522 | ||
|
|
991d1d82b8 | ||
|
|
5832205624 | ||
|
|
8aeea4d212 | ||
|
|
e1934cd1b0 | ||
|
|
056cce2f97 | ||
|
|
61f6463e59 | ||
|
|
a929552c3d | ||
|
|
10cd02d2e7 | ||
|
|
afac50c18f | ||
|
|
24ade35df8 | ||
|
|
d50341ff8e | ||
|
|
54bd6d5336 | ||
|
|
7bc26787db | ||
|
|
e923f816a4 | ||
|
|
c6e4439ab9 | ||
|
|
94f66da84e | ||
|
|
384399c1c8 | ||
|
|
7bac63310f | ||
|
|
f85de2c960 | ||
|
|
173b516270 | ||
|
|
3af25610b8 | ||
|
|
0898ed8c00 | ||
|
|
0d0b056f6b | ||
|
|
3f6b572f51 | ||
|
|
1a2b906e0a | ||
|
|
d48331b706 | ||
|
|
d95cc62c8e | ||
|
|
f04aa78fd7 | ||
|
|
b03d355d69 | ||
|
|
834e7c1abb | ||
|
|
c37caa95a4 | ||
|
|
3ffcc5d5ba | ||
|
|
52fa87a7c6 | ||
|
|
0ddcfbeed7 | ||
|
|
a2f56682e6 | ||
|
|
edc4af6da5 | ||
|
|
283354d4d9 | ||
|
|
c3fbc573e2 | ||
|
|
e7f0091b48 | ||
|
|
446327dffd | ||
|
|
03a0449662 | ||
|
|
3fb72dfc24 | ||
|
|
7c4ccde69b | ||
|
|
167a50816f | ||
|
|
a753b868e6 | ||
|
|
0958c9da44 | ||
|
|
bdee98feb0 | ||
|
|
6f9c76c9ba | ||
|
|
c4fdf075b3 | ||
|
|
0a19874ef3 | ||
|
|
39af07cc22 | ||
|
|
7ac3a264da | ||
|
|
8951b45a39 | ||
|
|
a4e4315002 | ||
|
|
3a9d108b76 | ||
|
|
651a4ae2bf | ||
|
|
75007db630 | ||
|
|
d0adfebf7a | ||
|
|
f9e8496d3f | ||
|
|
f583b741d4 | ||
|
|
1d80b166b1 | ||
|
|
42e59ee564 | ||
|
|
e2c82086be | ||
|
|
e9d47f046d | ||
|
|
4acc73ac19 | ||
|
|
96c27efa68 | ||
|
|
52ad4435ac | ||
|
|
b6426dd202 | ||
|
|
abbdbdbc18 | ||
|
|
9ad6c20d42 | ||
|
|
d96c854756 | ||
|
|
ac4c578396 | ||
|
|
5d527c8e72 | ||
|
|
15ef6c77dc | ||
|
|
8b990ac273 | ||
|
|
99ffe9eac2 | ||
|
|
3d8dda23ce | ||
|
|
4fe5df51fa | ||
|
|
d7d6aa78f5 | ||
|
|
3646cb0ce6 | ||
|
|
e2bd1b8ba3 | ||
|
|
b061f7e405 | ||
|
|
78f38f1a48 | ||
|
|
eeec81bf3b | ||
|
|
4682096d98 | ||
|
|
ca369e2df5 | ||
|
|
1a6efebea4 | ||
|
|
bba3a45f0f | ||
|
|
de83a273a9 | ||
|
|
ba2954baf4 | ||
|
|
9e4f2ee3e7 | ||
|
|
0c6ad58bca | ||
|
|
8319ec988f | ||
|
|
fc65476918 | ||
|
|
42b45408ed | ||
|
|
792f0b5c7a | ||
|
|
b68e0600bd | ||
|
|
a667502836 | ||
|
|
254d545e58 | ||
|
|
cdde4b0cc9 | ||
|
|
0346497f45 | ||
|
|
af3527d6cf | ||
|
|
08186d98f5 | ||
|
|
9b8b01515c | ||
|
|
49e5b71235 | ||
|
|
f63980f122 | ||
|
|
9cee827f6b | ||
|
|
9c57976906 | ||
|
|
ef5b09b6fa | ||
|
|
469b4224dc | ||
|
|
afc410cfe6 | ||
|
|
b686bc1112 | ||
|
|
25bee76fff | ||
|
|
98a8b9944e | ||
|
|
66745d2ddf | ||
|
|
cf9e1fe54c | ||
|
|
9bf59bed2f | ||
|
|
48a9968d20 | ||
|
|
d23355b147 | ||
|
|
83ec5658c4 | ||
|
|
aed509155b | ||
|
|
0120762dbe | ||
|
|
85b67ecd0b | ||
|
|
7451383c24 | ||
|
|
88d735ed56 | ||
|
|
7a002e4b89 | ||
|
|
01ad0b4875 | ||
|
|
4defa5fa9c | ||
|
|
32a1dd64ab | ||
|
|
5ce8171f12 | ||
|
|
e3121cb043 | ||
|
|
99e52ab0b5 | ||
|
|
2b672dc4fc | ||
|
|
6db7adf900 | ||
|
|
65782285a3 | ||
|
|
64bd5a93ad | ||
|
|
93d7ef48eb | ||
|
|
a90b7abff7 | ||
|
|
a479b4b109 | ||
|
|
326e1118da | ||
|
|
90f1e324ce | ||
|
|
41e0228c03 | ||
|
|
e72691a164 | ||
|
|
7b1d2a0b38 | ||
|
|
470d76faab | ||
|
|
aec9a75bba | ||
|
|
fcbac22577 | ||
|
|
1153a5dd3c | ||
|
|
04fccad19c | ||
|
|
1bce756bd6 | ||
|
|
68f052efcb | ||
|
|
4a8baf79fb | ||
|
|
499ac0295e | ||
|
|
29c422501a | ||
|
|
8efe74f614 | ||
|
|
4e0f12f4b9 | ||
|
|
cbd3a61259 | ||
|
|
2406a7be49 | ||
|
|
87322a36ca | ||
|
|
bbe4d28a40 | ||
|
|
dd40b56047 | ||
|
|
f14a0d5ee3 | ||
|
|
2994419381 | ||
|
|
81f06026d0 | ||
|
|
2df9441c20 | ||
|
|
47190d9c02 | ||
|
|
e0383d6c59 | ||
|
|
a436d9c070 | ||
|
|
eeabcd94ed | ||
|
|
8a3e37041a | ||
|
|
a1e9aefeb2 | ||
|
|
670cb51352 | ||
|
|
a43dff88c5 | ||
|
|
fb3c87359f | ||
|
|
a49dec7e6d | ||
|
|
a7156235c3 | ||
|
|
3cb52ba3f1 | ||
|
|
024f1a7047 | ||
|
|
b77c7e922f | ||
|
|
9335c4706b | ||
|
|
e09a9dabd6 | ||
|
|
e4e2f50015 | ||
|
|
61865050c7 | ||
|
|
05d90c26ff | ||
|
|
43cdb29eb6 | ||
|
|
87ff1cb2b2 | ||
|
|
f73c9c9d02 | ||
|
|
d15e444cb7 | ||
|
|
2eff6c3dc4 | ||
|
|
41fe211aec | ||
|
|
2acfa6d88d | ||
|
|
348b0c728c | ||
|
|
ece2bda680 | ||
|
|
875e1573a4 | ||
|
|
926dc868ef | ||
|
|
4a69ff6428 | ||
|
|
75cf17e2ce | ||
|
|
af3f66a5fa | ||
|
|
61adf1f784 | ||
|
|
1d0311a194 | ||
|
|
bda9974eb8 | ||
|
|
0306296ae9 | ||
|
|
86ecb38ae2 | ||
|
|
f3ca58111c | ||
|
|
3124d3ca1c | ||
|
|
9012506209 | ||
|
|
adb874ca74 | ||
|
|
f006a8aab6 | ||
|
|
6aaf2f031b | ||
|
|
1669377938 | ||
|
|
da45abaafb | ||
|
|
2b942f03b2 | ||
|
|
985b5e6724 | ||
|
|
198c235765 | ||
|
|
e82ee97666 | ||
|
|
8be7dac209 | ||
|
|
d2e35d8b2c | ||
|
|
5938bc72b4 | ||
|
|
23860e5897 | ||
|
|
11adbed079 | ||
|
|
07eb45ad76 | ||
|
|
726e908b5a | ||
|
|
526c6d8852 | ||
|
|
6d2be2e0a1 | ||
|
|
a8a9423ab0 | ||
|
|
78a82be4a0 | ||
|
|
1acdb27996 | ||
|
|
66f2c55343 | ||
|
|
0f3fa86bed | ||
|
|
e5c2cfd243 | ||
|
|
1a7ce13ec3 | ||
|
|
b4c535c76a | ||
|
|
1c7592c707 | ||
|
|
e4f8f96b83 | ||
|
|
105baa0557 | ||
|
|
ec554dae2e | ||
|
|
da86f113b8 | ||
|
|
ef1c397f11 | ||
|
|
12e0cc3d7b | ||
|
|
ff6bb6ebb0 | ||
|
|
6b78215b2e | ||
|
|
29a25b708c | ||
|
|
376f22ce08 | ||
|
|
6f25a72fb7 | ||
|
|
ec50078f18 | ||
|
|
c4900f5a66 | ||
|
|
edb5dff064 | ||
|
|
3961e1844c | ||
|
|
d09ecac35d | ||
|
|
5d9a02657f | ||
|
|
792edd9146 | ||
|
|
fd045fcc39 | ||
|
|
7a2ab59346 | ||
|
|
dc7970ac80 | ||
|
|
d08d4fa488 | ||
|
|
0807e7fec1 | ||
|
|
1c4b5d1ca5 | ||
|
|
a3d9b2b9cb | ||
|
|
d0df08de2c | ||
|
|
14d670a9a2 | ||
|
|
67801506e0 | ||
|
|
e98291498b | ||
|
|
d82a86e01b | ||
|
|
760d053cd7 | ||
|
|
48eb6dbbe0 | ||
|
|
d520c6a816 | ||
|
|
a3894323db | ||
|
|
a4b902d5af | ||
|
|
5f9f0769eb | ||
|
|
49390574bf | ||
|
|
71fab09581 | ||
|
|
9225df85da | ||
|
|
81160ac1ea | ||
|
|
5dd02602b7 | ||
|
|
a92dfa3920 | ||
|
|
0c19a1aafe | ||
|
|
5429bb7d2b | ||
|
|
664799c01b | ||
|
|
d88c5b9db2 | ||
|
|
509acd1192 | ||
|
|
8db74a4514 | ||
|
|
0d6f98f50a | ||
|
|
0fe7a693f8 | ||
|
|
d368fbbf5b | ||
|
|
1e7c123145 | ||
|
|
9a2efd9686 | ||
|
|
069b0b0153 | ||
|
|
c12c64380d | ||
|
|
88961fbdb5 | ||
|
|
a11ceced09 | ||
|
|
9da94b38b3 | ||
|
|
ca35662ca2 | ||
|
|
e7c4bbe1e8 | ||
|
|
1bc56b5c9e | ||
|
|
25a0630bcb | ||
|
|
1f7d122bee | ||
|
|
d9cb32ca53 | ||
|
|
9cdfc61a30 | ||
|
|
760587ee2e | ||
|
|
d2fe8a2ddb | ||
|
|
d2dc76baf1 | ||
|
|
232de66683 | ||
|
|
3d61d1bca0 | ||
|
|
c2c9531c1b | ||
|
|
461df14cf7 | ||
|
|
81b0be0489 | ||
|
|
3074a211f8 | ||
|
|
0659b140f5 | ||
|
|
0b8160ae34 | ||
|
|
dbf2b7b4b6 | ||
|
|
1e8afc8ea4 | ||
|
|
70bd2e8a78 | ||
|
|
b1dfe6e714 | ||
|
|
46bc0fe8b4 | ||
|
|
8045544051 | ||
|
|
0cef4dc9b3 | ||
|
|
f1cfa4330a | ||
|
|
a50b370262 | ||
|
|
7cc3639758 | ||
|
|
24b5dd0c8c | ||
|
|
32afdfc257 | ||
|
|
10e61e28c6 | ||
|
|
d88be9aca4 | ||
|
|
064fd217ba | ||
|
|
dd2e2734ce | ||
|
|
390c230de9 | ||
|
|
b43f868eba | ||
|
|
119a18aa15 | ||
|
|
b79c35042a | ||
|
|
12f8e0fe71 | ||
|
|
0b065b16b1 | ||
|
|
b4d5451b11 | ||
|
|
2fb4c8d227 | ||
|
|
9d8f3db511 | ||
|
|
76813e9df4 | ||
|
|
35da9cfb54 | ||
|
|
3f28594376 | ||
|
|
64c142d21e | ||
|
|
36304e8356 | ||
|
|
4090930142 | ||
|
|
cd4d5df4db | ||
|
|
b921964c88 | ||
|
|
6dcef71ebc | ||
|
|
c69d4107d8 | ||
|
|
d6c34f2312 | ||
|
|
8666c491ce | ||
|
|
7f4cfc267e | ||
|
|
9d48eb6d74 | ||
|
|
7f80cad356 | ||
|
|
36b3278698 | ||
|
|
2633b4c876 | ||
|
|
fd26e9755d | ||
|
|
c5623a10c1 | ||
|
|
4049695425 | ||
|
|
25b0d12576 | ||
|
|
cb1c490a1c | ||
|
|
565a20a83e | ||
|
|
077965f083 | ||
|
|
eae4f569c2 | ||
|
|
3f999e525a | ||
|
|
509606dbda | ||
|
|
1b12a689a3 | ||
|
|
f91d09b2ae | ||
|
|
89c02483eb | ||
|
|
9725082b06 | ||
|
|
4c9471c415 | ||
|
|
2bee87916d | ||
|
|
7838b6dc0e | ||
|
|
6ae279c292 | ||
|
|
28aea45f95 | ||
|
|
38d0be992c | ||
|
|
73b0c8c68c | ||
|
|
b8002ce577 | ||
|
|
5eebcd01ef | ||
|
|
5a455e1558 | ||
|
|
c2d0eec9d2 | ||
|
|
97104d820e | ||
|
|
f334f804b6 | ||
|
|
38bcafbfe5 | ||
|
|
72196c705e | ||
|
|
eb4d800e40 | ||
|
|
ad508a30ea | ||
|
|
7068309b04 | ||
|
|
06ab054118 | ||
|
|
4f5c929a9b | ||
|
|
268a146775 | ||
|
|
7151c347a0 | ||
|
|
98d813c172 | ||
|
|
7b5a805eda | ||
|
|
d2b6429c8b | ||
|
|
450c9bb755 | ||
|
|
a45cd01e26 | ||
|
|
28f7a7315e | ||
|
|
d9e7e359f9 | ||
|
|
bee41e0e75 | ||
|
|
5e826a3392 | ||
|
|
635ff88a53 | ||
|
|
83156bf28e | ||
|
|
9ba081f241 | ||
|
|
179c3725ca | ||
|
|
645fedb1ed | ||
|
|
104ee3829f | ||
|
|
9f80eb2f74 | ||
|
|
44b3a643dd | ||
|
|
cf61a6bbe7 | ||
|
|
93b45fba84 | ||
|
|
0d1851a73b | ||
|
|
5d6377f71c | ||
|
|
28872f39c1 | ||
|
|
c0b8eab4b8 | ||
|
|
75ba00735d | ||
|
|
fdd7951d13 | ||
|
|
e0427ae200 | ||
|
|
ec269f7177 | ||
|
|
2226082b6b | ||
|
|
c69c188de9 | ||
|
|
8499655c94 | ||
|
|
4c0c13e792 | ||
|
|
9d2d693a63 | ||
|
|
e8d4db3f80 | ||
|
|
e7ebea535e | ||
|
|
c3a7e91a1d | ||
|
|
44be066b26 | ||
|
|
47f4efe60c | ||
|
|
a4d7aff651 | ||
|
|
d55b41963b | ||
|
|
6bfad8e2d0 | ||
|
|
e06ba65e6c | ||
|
|
3acd77a63d | ||
|
|
25b32a6444 | ||
|
|
62ae4fb265 | ||
|
|
57fe2a6cc2 | ||
|
|
a6ef8e0b40 | ||
|
|
467ceb89b1 | ||
|
|
873bc3f582 | ||
|
|
9ebb37c524 | ||
|
|
ccf4ba2269 | ||
|
|
e377a72f75 | ||
|
|
4ed806ea97 | ||
|
|
57ba991673 | ||
|
|
21a48ccab5 | ||
|
|
0f0c27ad09 | ||
|
|
40ed6450ff | ||
|
|
a0c0ea4c4c | ||
|
|
2dc413ca3a | ||
|
|
692b26622c | ||
|
|
72a56d33d0 | ||
|
|
ce4bfc55c1 | ||
|
|
faba53fa5f | ||
|
|
f0faec9def | ||
|
|
e6ef28050c | ||
|
|
547ec3cb3a | ||
|
|
5bfc67af4f | ||
|
|
c72d9b544e | ||
|
|
cd34619acd | ||
|
|
f091817d66 | ||
|
|
f2c65314b4 | ||
|
|
a9fcdd3341 | ||
|
|
36a5cc7446 | ||
|
|
fc0f278962 | ||
|
|
1f3db15892 | ||
|
|
e3e4c49427 | ||
|
|
1520b8bf73 | ||
|
|
c9e7f82905 | ||
|
|
14a1a665ef | ||
|
|
d2357fa779 | ||
|
|
703178ddf1 | ||
|
|
ec836e2e79 | ||
|
|
4e9c5de16c | ||
|
|
2a677aaf02 | ||
|
|
2a141cd9b3 | ||
|
|
3d1fcc35df | ||
|
|
e20d7afb72 | ||
|
|
5ade8b208e | ||
|
|
9c5e4f7a7c | ||
|
|
07e2bc3858 | ||
|
|
5c785ca1c6 | ||
|
|
b389b20ca3 | ||
|
|
6f1d496a9e | ||
|
|
fe12cb345e | ||
|
|
2607994c4c | ||
|
|
47a02afea6 | ||
|
|
a2e0a0c6f7 | ||
|
|
f3b11d6f72 | ||
|
|
edac8f764b | ||
|
|
4fa68e3bb0 | ||
|
|
69f310c02c | ||
|
|
09789e163c | ||
|
|
84c8851ff8 | ||
|
|
95dacdd6da | ||
|
|
3308f1146c | ||
|
|
37b9e46e96 | ||
|
|
8e8cf3df8d | ||
|
|
f4b188a9ac | ||
|
|
35c886a59c | ||
|
|
26fdd924ef | ||
|
|
e87a49796f | ||
|
|
7e0b1e479c | ||
|
|
1af2f7848e | ||
|
|
ea3494f6e7 | ||
|
|
0e7b93771e | ||
|
|
ea5a21e487 | ||
|
|
dc72b87479 | ||
|
|
2f20acfa34 | ||
|
|
4869058f46 | ||
|
|
fa006afd0d | ||
|
|
8e06255758 | ||
|
|
ba57b25cd4 | ||
|
|
4fa9d98171 | ||
|
|
6d19832d01 | ||
|
|
bdaa059fa3 | ||
|
|
f7bfc51735 | ||
|
|
998e156b21 | ||
|
|
491bf850e8 | ||
|
|
9bf53c6b25 | ||
|
|
e2fb49037a | ||
|
|
3291c24c8c | ||
|
|
f0bc375421 | ||
|
|
e3c223dc0a | ||
|
|
53c8b3b66d | ||
|
|
af5000b0f8 | ||
|
|
d5d4fdefc8 | ||
|
|
1caa0c6210 | ||
|
|
5b646617d1 | ||
|
|
9f028d9104 | ||
|
|
f40be696c7 | ||
|
|
95a503a390 | ||
|
|
88c51f4933 | ||
|
|
d63177f3c7 | ||
|
|
e9d41fd01b | ||
|
|
224d2987db | ||
|
|
8439d6d3aa | ||
|
|
13b38955e6 | ||
|
|
ae3fb9a2dd | ||
|
|
9d78d769c4 | ||
|
|
e436a31a18 | ||
|
|
929ade554c | ||
|
|
d6c7066bfa | ||
|
|
2387f183e9 | ||
|
|
e8d645467f | ||
|
|
a8e022cab4 | ||
|
|
579e8abda1 | ||
|
|
4d44440e90 | ||
|
|
709f914561 | ||
|
|
0afa8e092e | ||
|
|
e886619b22 | ||
|
|
fa5f423bbd | ||
|
|
bfbf5c70d5 | ||
|
|
2c19a442a7 | ||
|
|
984ca69e8c | ||
|
|
544d7a15d4 | ||
|
|
858f49d265 | ||
|
|
1b66d446f9 | ||
|
|
6e92fc0505 | ||
|
|
ea84403811 | ||
|
|
65a02795d6 | ||
|
|
c5549367eb | ||
|
|
6aa4a4d205 | ||
|
|
9e20f1dd33 | ||
|
|
16be19b5d3 | ||
|
|
80ac0259b8 | ||
|
|
9f7911923c | ||
|
|
686005071e | ||
|
|
e16d31d605 | ||
|
|
8b201d22cb | ||
|
|
0f6f8d43bd | ||
|
|
8f171cddd9 | ||
|
|
c77c323f73 | ||
|
|
9e358309e4 | ||
|
|
485438f38d | ||
|
|
fe26a60337 | ||
|
|
d2c2de4dd7 | ||
|
|
d49d58f7f8 | ||
|
|
c0c5579027 | ||
|
|
164d4fff8b | ||
|
|
6e7e4a129b | ||
|
|
7726406674 | ||
|
|
ed38b39fec | ||
|
|
9188d4316e | ||
|
|
cf374c6b8b | ||
|
|
82388dcbc3 | ||
|
|
7a6a99e2b6 | ||
|
|
c383736834 | ||
|
|
6e5e78df3b | ||
|
|
311bf1b641 | ||
|
|
5c9933791c | ||
|
|
039d4d11aa | ||
|
|
c0f2d2aa84 | ||
|
|
45099bfa07 | ||
|
|
695ae9d970 | ||
|
|
21eb0064b1 | ||
|
|
513fe402af | ||
|
|
b27e5754e8 | ||
|
|
fa7231d77b | ||
|
|
f5a30ecb33 | ||
|
|
7f22289889 | ||
|
|
f80c39077a | ||
|
|
75c60a1cc4 | ||
|
|
2cf38d6b7c | ||
|
|
482c9c1574 | ||
|
|
882e59a260 | ||
|
|
7a036956b7 | ||
|
|
7520b20cf9 | ||
|
|
d47ccd75d5 | ||
|
|
56ff81a0ed | ||
|
|
8db76f5324 | ||
|
|
a9442ea06e | ||
|
|
92bd0d3ea0 | ||
|
|
512d7322b2 | ||
|
|
45645c439f | ||
|
|
84ebb82cae | ||
|
|
576f6a3bd6 | ||
|
|
96df821eca | ||
|
|
8589778e92 | ||
|
|
a8a7de9ee6 | ||
|
|
1d99340425 | ||
|
|
a8cdfb56f3 | ||
|
|
0958cdaa2d | ||
|
|
ebfb3dd31e | ||
|
|
2293a14a90 | ||
|
|
3e664a7c2c | ||
|
|
30b37951b2 | ||
|
|
0d177d12fe | ||
|
|
f7c8a570f8 | ||
|
|
1814aa86b7 | ||
|
|
d0a5e658d1 | ||
|
|
2cbc1da286 | ||
|
|
75d21231ae | ||
|
|
f2d340a012 | ||
|
|
1b28111c6d | ||
|
|
4f4efcbc23 | ||
|
|
7006d18e93 | ||
|
|
049959b567 | ||
|
|
7cd8c0475e | ||
|
|
207accf21f | ||
|
|
bd1e62abc1 | ||
|
|
d2e33ee423 | ||
|
|
f2934f8453 | ||
|
|
20fb269828 | ||
|
|
cc13707fea | ||
|
|
a9db6a0473 | ||
|
|
282ddb85c7 | ||
|
|
3943b8753f | ||
|
|
9e26ea1866 | ||
|
|
8152a87514 | ||
|
|
b28775c2c6 | ||
|
|
9b27200793 | ||
|
|
0b7d7dac38 | ||
|
|
3eb96ef765 | ||
|
|
8805584cbe | ||
|
|
c2edf314c2 | ||
|
|
2da2d54013 | ||
|
|
f433b911a0 | ||
|
|
8b44815b70 | ||
|
|
788f597a3f | ||
|
|
4ee70acf12 | ||
|
|
be5c66bd93 | ||
|
|
5347e5a3aa | ||
|
|
9b22254b6c | ||
|
|
e5ccd27fd9 | ||
|
|
d34ad62c8a | ||
|
|
0d0bee674d | ||
|
|
279747d3a4 | ||
|
|
1e4bf38402 | ||
|
|
93d1163c5f | ||
|
|
a3e436e42d | ||
|
|
e824886e19 | ||
|
|
9c724b31de | ||
|
|
6a67e0ea8b | ||
|
|
7b118995ea | ||
|
|
35b4564644 | ||
|
|
30df947365 | ||
|
|
b1ec975612 | ||
|
|
a4851c8d81 | ||
|
|
469f48f473 | ||
|
|
c915ac4a74 | ||
|
|
9b74c470da | ||
|
|
1034e434c4 | ||
|
|
0a4935d193 | ||
|
|
5995f6fbef | ||
|
|
0ca15a6c65 | ||
|
|
72193833a9 | ||
|
|
e40ffabe4a | ||
|
|
f419bff545 | ||
|
|
69eec0135e | ||
|
|
a267e32e0e | ||
|
|
92a5249e45 | ||
|
|
fbfe664438 | ||
|
|
b52b5b4287 | ||
|
|
ba3513341a | ||
|
|
de06ce909e | ||
|
|
fa29b746e7 | ||
|
|
5527ebf085 | ||
|
|
cca2052b15 | ||
|
|
ec0338bb30 | ||
|
|
f40a1b6de8 | ||
|
|
7110337dcd | ||
|
|
cbfe850351 | ||
|
|
d6d768029b | ||
|
|
d003e086bb | ||
|
|
a3b66ec456 | ||
|
|
1c3d41c03b | ||
|
|
56b1751c3f | ||
|
|
93724063e2 | ||
|
|
72b8cd2ac8 | ||
|
|
e5b22255e9 | ||
|
|
a4639e295d | ||
|
|
8dc4246c98 | ||
|
|
a187832cdc | ||
|
|
d08a46a573 | ||
|
|
e86fcc9636 | ||
|
|
1f60405d43 | ||
|
|
8f568cc6ac | ||
|
|
4d61820a78 | ||
|
|
b6d49233fb | ||
|
|
beac6be7db | ||
|
|
b99931df95 | ||
|
|
00ba661456 | ||
|
|
2ffde30340 | ||
|
|
f97a84d2df | ||
|
|
c5bb10db4c | ||
|
|
acf4d2f740 | ||
|
|
1c2f6913bb | ||
|
|
31be8bee95 | ||
|
|
2a113efe5c | ||
|
|
801791b4df | ||
|
|
643a2ee739 | ||
|
|
cd9c97ffc0 | ||
|
|
c105319b08 | ||
|
|
d98fa381e8 | ||
|
|
1f39b43869 | ||
|
|
3aeb6a662a | ||
|
|
d7c176d4fd | ||
|
|
cac1df7a66 | ||
|
|
aafa383f56 | ||
|
|
af6e2abdb2 | ||
|
|
05430f7e47 | ||
|
|
2daf4cf46a | ||
|
|
52333beabe | ||
|
|
49d1e0622b | ||
|
|
eebd87c6b7 | ||
|
|
c1b6b30144 | ||
|
|
7703986c9e | ||
|
|
6c272d9336 | ||
|
|
73b0416dbe | ||
|
|
c7760b0ed9 | ||
|
|
c0db476f80 | ||
|
|
7999c29b51 | ||
|
|
1d111a252e | ||
|
|
93d085e23e | ||
|
|
67e0e34f40 | ||
|
|
098e61295c | ||
|
|
1d2666a343 | ||
|
|
b8c2c86c59 | ||
|
|
edf0342404 | ||
|
|
dc6815045c | ||
|
|
23ed1cf5e5 | ||
|
|
97715f260f | ||
|
|
87411ee952 | ||
|
|
d0bbf1e4ad | ||
|
|
3bbd088733 | ||
|
|
d96dd5fe82 | ||
|
|
6028e3f299 | ||
|
|
37bfce1905 | ||
|
|
5993b30ccf | ||
|
|
2fc6c4c0bc | ||
|
|
0195a6bab5 | ||
|
|
ccb35bdc5a | ||
|
|
bfadfaf261 | ||
|
|
d0180a6633 | ||
|
|
afbc580ae6 | ||
|
|
2b2e01f3d1 | ||
|
|
529f1ca835 | ||
|
|
ee7993b918 | ||
|
|
8239a40c72 | ||
|
|
2c9f9a36c5 | ||
|
|
307169fcc3 | ||
|
|
5ee69d24f7 | ||
|
|
077106b71b | ||
|
|
141e660d91 | ||
|
|
be73699013 | ||
|
|
65e3649999 | ||
|
|
994f1ae7ed | ||
|
|
548e633b72 | ||
|
|
87b98e7949 | ||
|
|
5692baf1f3 | ||
|
|
8a10a2aa18 | ||
|
|
797bbf8870 | ||
|
|
edb3f9e885 | ||
|
|
a0008e165b | ||
|
|
3d55b033d6 | ||
|
|
93fb0efc67 | ||
|
|
b7585ef02c | ||
|
|
fce07288e9 | ||
|
|
3ccfdb2e97 | ||
|
|
5840e2ba07 | ||
|
|
4daba88970 | ||
|
|
3180feb874 | ||
|
|
17a430f31f | ||
|
|
20d330f0f1 | ||
|
|
27d0467e08 | ||
|
|
5437967218 | ||
|
|
1228f0572d | ||
|
|
9cf44c3050 | ||
|
|
aa9b641787 | ||
|
|
2e3c4f33a2 | ||
|
|
39ef6ebdbf | ||
|
|
4d08c22204 | ||
|
|
4041dd3ad5 | ||
|
|
a38de8198f | ||
|
|
3369374e43 | ||
|
|
d74631bbdb | ||
|
|
be8c392562 | ||
|
|
f564efb4d6 | ||
|
|
dee9e3c326 | ||
|
|
4ff8d7d68e | ||
|
|
789e467573 | ||
|
|
745b85a3ac | ||
|
|
4f84c2cb01 | ||
|
|
83414acb1d | ||
|
|
356effc6a9 | ||
|
|
88ec186b98 | ||
|
|
530615f049 | ||
|
|
afec12822f | ||
|
|
f117620ead | ||
|
|
1c9f34ba1b | ||
|
|
c26cd9876a | ||
|
|
32f7d37768 | ||
|
|
3873e680e4 | ||
|
|
ddc8a9a286 | ||
|
|
399bde7588 | ||
|
|
5e51febee8 | ||
|
|
6e8200a380 | ||
|
|
fc9961b2de | ||
|
|
d750e3e996 | ||
|
|
1cd15c6f7c | ||
|
|
5c47acbcc3 | ||
|
|
1363c2893b | ||
|
|
cbc426014b | ||
|
|
17178e3ae3 | ||
|
|
b9299d90df | ||
|
|
aff5b46c5e | ||
|
|
2e83f81672 | ||
|
|
e352cc76cf | ||
|
|
cab2ee4fa4 | ||
|
|
bdfc839080 | ||
|
|
6beb21349b | ||
|
|
b2240e8f1a | ||
|
|
32f43d46b5 | ||
|
|
803d689bd3 | ||
|
|
66255bf443 | ||
|
|
338a486513 | ||
|
|
b543343045 | ||
|
|
28c60332e8 | ||
|
|
9ddc45721f | ||
|
|
2849baf857 | ||
|
|
768fdcd0e4 | ||
|
|
5280ef32cd | ||
|
|
59a7e4179b | ||
|
|
bd2054e5a4 | ||
|
|
69be19c02b | ||
|
|
fcffeb5734 | ||
|
|
11b67208f4 | ||
|
|
03e8342c90 | ||
|
|
fcd070066c | ||
|
|
9b38308ad1 | ||
|
|
5d79ad527e | ||
|
|
afcdf96e5c | ||
|
|
ffc8b5619e | ||
|
|
3e40b08525 | ||
|
|
9be49b3738 | ||
|
|
724488911e | ||
|
|
8ac0bf5865 | ||
|
|
57c1c38d52 | ||
|
|
237cf037be | ||
|
|
8b98181752 | ||
|
|
21993a4862 | ||
|
|
6e8e1ad74b | ||
|
|
03da5b3cf1 | ||
|
|
f348ef1f96 | ||
|
|
193cebed81 | ||
|
|
f2f6156bd0 | ||
|
|
0d7c3838f6 | ||
|
|
105e3360be | ||
|
|
23dd3b4f41 | ||
|
|
bc225f9656 | ||
|
|
dd9f76f73b | ||
|
|
47ae8b903e | ||
|
|
3dcfd3738d | ||
|
|
8993794a88 | ||
|
|
a530e7e70a | ||
|
|
4791b8e53c | ||
|
|
6ddd19ac54 | ||
|
|
6a871e73e0 | ||
|
|
7ba106d97b | ||
|
|
69c021cc54 | ||
|
|
7a63bb395f | ||
|
|
1931695b03 | ||
|
|
b953240966 | ||
|
|
e1c06af3b2 | ||
|
|
1cc7bfcb2d | ||
|
|
2445c74638 | ||
|
|
6a69ed48a9 | ||
|
|
714c7eb8d1 | ||
|
|
6790287470 | ||
|
|
217693937f | ||
|
|
94a8a5c753 | ||
|
|
22300577cf | ||
|
|
6a07f4e731 | ||
|
|
63ace60dcc | ||
|
|
601951582d | ||
|
|
ca4d22602f | ||
|
|
42774a6227 | ||
|
|
7f65bfeebb | ||
|
|
88178a6b6b | ||
|
|
3f9ca1454e | ||
|
|
9a3f1bd5cf | ||
|
|
0186254f74 | ||
|
|
6dc432e6a9 | ||
|
|
01db774e05 | ||
|
|
aaef3dc19c | ||
|
|
bb8009363d | ||
|
|
5fd403cf08 | ||
|
|
168c77eac5 | ||
|
|
bf865cbe5d | ||
|
|
3e3029461b | ||
|
|
c750e0a64e | ||
|
|
fc2662c402 | ||
|
|
29dad51ff7 | ||
|
|
9250dde5b0 | ||
|
|
29ca72d8ca | ||
|
|
87c89a0de5 | ||
|
|
73f72e39d3 | ||
|
|
e00ba62606 | ||
|
|
48d53cecce | ||
|
|
da44bba3fe | ||
|
|
b55e42ba78 | ||
|
|
233a9843d7 | ||
|
|
6184087456 | ||
|
|
237ad2fa3c | ||
|
|
b8037c04d0 | ||
|
|
cdb9c2eddb | ||
|
|
8a284f0767 | ||
|
|
83a57b08ab | ||
|
|
d1a251ff6c | ||
|
|
12f0c826c8 | ||
|
|
4aa5da8c0d | ||
|
|
e0fd81e938 | ||
|
|
58509bcf41 | ||
|
|
8aa0eb1d64 | ||
|
|
ece974c1be | ||
|
|
56dd3c32cb | ||
|
|
118e3a3bd3 | ||
|
|
8cd3c2a89f | ||
|
|
9c4672fd68 | ||
|
|
04f6f4f9cf | ||
|
|
7b851e7ac8 | ||
|
|
6c0b33c0dc | ||
|
|
4d951c9827 | ||
|
|
172232be48 | ||
|
|
d749a13611 | ||
|
|
3998be3f93 | ||
|
|
a381827890 | ||
|
|
eecfe45443 | ||
|
|
ad5eb7b594 | ||
|
|
9ce09eb406 | ||
|
|
9c23f3d1d9 | ||
|
|
3f779b7ceb | ||
|
|
3bc53bd7f8 | ||
|
|
27b61fe9a4 | ||
|
|
4d94c7ac7a | ||
|
|
4eb1125b7b | ||
|
|
496b481c31 | ||
|
|
77120cf156 | ||
|
|
80f11c0f70 | ||
|
|
bee8059cbe | ||
|
|
0f2e72172b | ||
|
|
25d1e0a74d | ||
|
|
cbd9d16e4c | ||
|
|
cb708b3217 | ||
|
|
4e5a22a7e8 | ||
|
|
3722db93c6 | ||
|
|
b43331dc27 | ||
|
|
80c6ce81e1 | ||
|
|
1a776359c4 | ||
|
|
113e4035e5 | ||
|
|
a03095ab8e | ||
|
|
d03f830622 | ||
|
|
9b42dc9f10 | ||
|
|
fd7adf3c64 | ||
|
|
d0b7e72f15 | ||
|
|
5a61c6b7df | ||
|
|
c897eae04e | ||
|
|
c33095cd0e | ||
|
|
05d8b7983a | ||
|
|
166d9f7133 | ||
|
|
2ce31f35cc | ||
|
|
ce5d0cefe3 | ||
|
|
6cc668fe83 | ||
|
|
ac0aa8daf4 | ||
|
|
16b094be44 | ||
|
|
b3e6fd7b96 | ||
|
|
893d5d92f3 | ||
|
|
77add0b39d | ||
|
|
b4f8ab0a49 | ||
|
|
1d46c44c21 | ||
|
|
12da35f875 | ||
|
|
8970a15d4e | ||
|
|
82217478d9 | ||
|
|
4c792308bb | ||
|
|
978d94a2cd | ||
|
|
b195d89b76 | ||
|
|
875888a341 | ||
|
|
6631a13d20 | ||
|
|
28728fe29f | ||
|
|
aa954cbea9 | ||
|
|
dae339f494 | ||
|
|
5bcb59f876 | ||
|
|
9132592fd7 | ||
|
|
ca592fac77 | ||
|
|
ea657824c2 | ||
|
|
99e7072e27 | ||
|
|
ad32f4a0a3 | ||
|
|
b9cdd0996d | ||
|
|
e92a76f95b | ||
|
|
10d152342f | ||
|
|
7e4b0635b2 | ||
|
|
eec17f10d5 | ||
|
|
ac9d5dfa95 | ||
|
|
4c2b3738c2 | ||
|
|
6f29183b45 | ||
|
|
dd65c9c588 | ||
|
|
cb8bb05627 | ||
|
|
256f6d8fdd | ||
|
|
a88fdddecb | ||
|
|
fd5e3e24df | ||
|
|
244d27427d | ||
|
|
55c42a3cca | ||
|
|
3c9cfbdf92 | ||
|
|
46dd58d26e | ||
|
|
051dd2e567 | ||
|
|
17ccf40082 | ||
|
|
0f2b61694d | ||
|
|
0aed66df47 | ||
|
|
94a6e9a886 | ||
|
|
355f48b6ba | ||
|
|
d1a6526c22 | ||
|
|
975a308647 | ||
|
|
5138eaeb68 | ||
|
|
45dfaa1b21 | ||
|
|
715f92f3d5 | ||
|
|
8d5a765040 | ||
|
|
34fa6b158b | ||
|
|
78c1f6b8e3 | ||
|
|
adccb91106 | ||
|
|
1e213dfff7 | ||
|
|
d469fa1d40 | ||
|
|
737db469ba | ||
|
|
a44a33d508 | ||
|
|
a518d41c78 | ||
|
|
d5360c6568 | ||
|
|
d468107311 | ||
|
|
3f65e1bfa0 | ||
|
|
a22758f5cd | ||
|
|
88b5b9d1e7 | ||
|
|
e38f7c880e | ||
|
|
6367b58994 | ||
|
|
5a54b5ee64 | ||
|
|
002e41f418 | ||
|
|
f7787c748a | ||
|
|
f9b18b45a4 | ||
|
|
8966f44272 | ||
|
|
3dbcbae61f | ||
|
|
24508abe7a | ||
|
|
27f8f2542e | ||
|
|
44ee3ceec8 | ||
|
|
b08112aec0 | ||
|
|
9d2bbda2b9 | ||
|
|
6eff685b18 | ||
|
|
2d08146de8 | ||
|
|
f131420a44 | ||
|
|
245ea5463e | ||
|
|
c7b205dbde | ||
|
|
ffff2636ae | ||
|
|
c69e1bb091 | ||
|
|
49531285c9 | ||
|
|
b9824d0095 | ||
|
|
3dc04f9246 | ||
|
|
656e3ff022 | ||
|
|
94f1a80323 | ||
|
|
db6c32891a | ||
|
|
6d819206ea | ||
|
|
b3bf86d404 | ||
|
|
296c337eb6 | ||
|
|
a6f71911fe | ||
|
|
b91a781d27 | ||
|
|
6aa363830b | ||
|
|
fffc0f9eae | ||
|
|
1d2889f5b8 | ||
|
|
6ed7568cd9 | ||
|
|
22ca5b76b4 | ||
|
|
a03ce5bf7b | ||
|
|
2994806a35 | ||
|
|
be17960ce6 |
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
@@ -11,7 +11,7 @@ There are many ways that you can help improve mRemoteNG, even if you don't know
|
||||
For example, you might:
|
||||
- add documentation or "how-to" articles on the [Wiki](https://github.com/mRemoteNG/mRemoteNG/wiki)
|
||||
- answer support questions on the [forum](http://forum.mremoteng.org)
|
||||
- [add or improve a translation](https://github.com/mRemoteNG/mRemoteNG/wiki/How to Help Translating mRemoteNG)
|
||||
- [add or improve a translation](https://github.com/mRemoteNG/mRemoteNG/wiki/How-to-Help-Translating-mRemoteNG)
|
||||
- submit a [pull request](https://github.com/mRemoteNG/mRemoteNG/pulls) for a [bug or feature ticket](https://github.com/mRemoteNG/mRemoteNG/issues)
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ Guidelines for bug reports:
|
||||
1. Do not open bug reports for questions.
|
||||
1. Use the GitHub Issue search to make sure your bug hasn't already been reported.
|
||||
1. Include as much detailed information as possible. We've included a default template when opening an issue to make this easier.
|
||||
1. Please tag your your bug report with the [`Bug`](https://github.com/mRemoteNG/mRemoteNG/issues?q=is%3Aissue+is%3Aopen+label%3ABug) label.
|
||||
|
||||
### Feature requests
|
||||
Feature requests are great! Take some time to compose a well thought out proposal. It's up to you to convince the project maintainers that your feature is a good idea. To ensure your request receives the consideration that it deserves, include as much detail as possible. For example:
|
||||
@@ -35,7 +34,6 @@ Feature requests are great! Take some time to compose a well thought out proposa
|
||||
- What situation led you to want this feature?
|
||||
- How does the application perform now and how would the new feature change this?
|
||||
- If applicable, consider including visual mock-ups to show us what you mean.
|
||||
- Please tag your feature request with the [`Feature Request`](https://github.com/mRemoteNG/mRemoteNG/issues?q=is%3Aissue+is%3Aopen+label%3A%22Feature+Request%22) label.
|
||||
|
||||
# Pull requests
|
||||
Good pull requests are a huge help! If you haven't already, please consider reading [GitHub's guide to contributing to open source](https://guides.github.com/activities/contributing-to-open-source/)
|
||||
|
||||
6
.github/ISSUE_TEMPLATE.md
vendored
6
.github/ISSUE_TEMPLATE.md
vendored
@@ -6,10 +6,10 @@ Please provide as much detail as possible for us to fix your issue.
|
||||
-->
|
||||
|
||||
<!-- Bug -->
|
||||
|||
|
||||
|Detail|Value|
|
||||
|--:|---|
|
||||
|Operating system | Windows 7 x64 |
|
||||
|mRemoteNG version| 1.75 aplha 3 |
|
||||
|Operating system | Windows 10 x64 |
|
||||
|mRemoteNG version| 1.75.7008 |
|
||||
|
||||
|
||||
<!-- Feature Request -->
|
||||
|
||||
265
CHANGELOG.TXT
265
CHANGELOG.TXT
@@ -1,3 +1,258 @@
|
||||
1.76.0 Alpha 3 (2018-xx-xx):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#625: Added ability to import mRemoteNG formatted CSV files
|
||||
|
||||
Fixes:
|
||||
------
|
||||
|
||||
|
||||
|
||||
1.76.0 Alpha 2 (2018-02-01):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#838: Added an option to lock toolbars
|
||||
#836: Added a Read Only option for SQL connections
|
||||
#829: Add option that fixes connecting to Azure instances with LoadBalanceInfo
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#840: Fix theme loading issue in installer version
|
||||
#800: Fixed issue with PuTTY sessions not showing some extended characters
|
||||
Fixed a few toolbar layout issues
|
||||
|
||||
|
||||
1.76.0 Alpha 1 (2017-12-08):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#799: Added option to save connections on every edit
|
||||
#798: Added button to test SQL database connections on SQL options page
|
||||
#784: Rearranged some settings in the Options pages to prevent overlap with some translations
|
||||
#704: Portable version now saves settings in application directory
|
||||
#671: Revamped UI theme system
|
||||
#611: Added multi-ssh toolbar for sending commands to many SSH clients at once
|
||||
#558: Connection tree now shows customizable icons instead of play/pause icon
|
||||
#519: You can now import normal mRemoteNG files - they do not have to be exports
|
||||
#504: Added Korean translation
|
||||
#485: The Domain field is now visible/editable for connection with the IntApp protocol
|
||||
#468: Default connection info Panel property is now saved
|
||||
#429: Added Czech translation
|
||||
#421: When a connection file cannot be loaded, we will now prompt for how to proceed rather than always exiting.
|
||||
#338: Added option to filter connection tree when searching
|
||||
#357: Updated GeckoFX to v45.45.0.32
|
||||
#225: Added support for importing Remote Desktop Connection Manager v2.7 RDG files
|
||||
#207: Can now specify a working directory for external tools
|
||||
#197: Selecting a quick connect protocol will start a connection with that host
|
||||
#184: Improve search to include description and hostname fields
|
||||
#152: Added option "Show on Toolbar" to external tools
|
||||
Added more logging/notifications options
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#747: Fixed unnecessary "PuttySessions.Watcher.StartWatching" error message
|
||||
#650: Fixed German translation typo
|
||||
#639: Fixed Italian translation typo
|
||||
#479: New connection tree nodes not starting in edit mode
|
||||
#233: Fixed crash that can occur when disconnecting from VNC server
|
||||
#195: Access to https with self-signed certificates not working
|
||||
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
#797: Removed duplicate translation strings
|
||||
#608: The Help -> Support Forum menu item now directs users to our Reddit community
|
||||
#493: Changed backup file name time stamp to use local system time rather than UTC
|
||||
Improved compatability between environments when building mRemoteNG from source
|
||||
|
||||
|
||||
1.75.7012 (2017-12-01):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#814: Fixed bug that prevented reordering connections by dragging
|
||||
#810: Official mRemoteNG builds will now be signed with a DigiCert certificate
|
||||
#803: File path command line argument not working with network path
|
||||
|
||||
|
||||
1.75.7011 (2017-11-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#778: Custom connection file path command line argument (/c) not working
|
||||
#763: Sometimes minimizing folder causes connection tree to disappear
|
||||
#761: Connections using external tools do not start (introduced in v1.75.7009)
|
||||
#758: "Decryption failed" message when loading from SQL server
|
||||
Fixed issues with /resetpanels and /resetpos command line arguments
|
||||
Resolved bug where connection tree hotkeys would sometimes be disabled
|
||||
|
||||
|
||||
1.75.7010 (2017-10-29):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#756: CustomConsPath always null
|
||||
|
||||
|
||||
1.75.7009 (2017-10-28):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#676: Portable version ignores /cons param on first run
|
||||
#675: Attempting to add new connection/folder does not work in some situations
|
||||
#665: Can not add new connection or new folder in some situations
|
||||
#658: Keep Port Scan tab open after import
|
||||
#646: Exception after click on import port scan
|
||||
#635: Updated PuTTYNG to 0.70
|
||||
#610: mRemoteNG cannot start /crashes for some users on Windows server 2012 R2 server
|
||||
#600: Missing horizontal scrollbar on Connections Panel
|
||||
#596: Exception when launching external tool without a connection selected
|
||||
#550: Sometimes double-clicking connection tree node began rename instead of connecting
|
||||
#536: Prevented log file creation when writeLogFile option is not set
|
||||
#529: Erratic Tree Selection when using SQL Database
|
||||
#482: Default connection password not decrypted when loaded
|
||||
#335: The Quick Connect Toolbar > Connection view does not show open connections with the play icon
|
||||
#176: Unable to enter text in Quick Connect when SSH connection active
|
||||
Minor error message correction
|
||||
Minor code refactoring
|
||||
|
||||
|
||||
NO.RELEASE (2017-06-15):
|
||||
|
||||
Fixed in previous releases:
|
||||
---------------------------
|
||||
#466: Installer still failing on Win7 for updates - v1.75.7005 (Hotifx 5)
|
||||
#462: Remove no longer used files from portable version - v1.75.7003 (Hotfix 4)
|
||||
|
||||
|
||||
1.75.7008 (2017-06-15):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#589: MSI doesn't update with newer PuTTYNG version that fixes #583 (Again, Sorry!)
|
||||
Minor updates to the installer build
|
||||
|
||||
|
||||
1.75.7007 (2017-06-14):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#583: SSH (PuTTYNG) Sessions are not properly integrated into the main mRemoteNG window (Sorry!)
|
||||
|
||||
|
||||
1.75.7006 (2017-06-13):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#377: Use all space on About page
|
||||
#527: Additional protections to avoid problems on update check in heavily firewalled environments
|
||||
#530: Fixed issue where using External Tool on existing connection causes creation of 'New Connection' entry
|
||||
#531: Update PuTTYNG to 0.69
|
||||
#546: Quick Connect from notification area icon displays warning when clicking on a folder (see #334)
|
||||
|
||||
|
||||
1.75.7005 (2017-04-27):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#410: Update PuTTYNG to 0.68
|
||||
#434: Fix complier warnings CA1049 & CA2111
|
||||
#442: Fixed issue loading PuTTY sessions that have spaces in the name
|
||||
#502: Problems with ParentID for Duplicated Containers/Connections with SQL Connection Storage
|
||||
#514: Expanded property not saved/loaded properly from SQL
|
||||
#518: Exception when Importing File
|
||||
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
Minor code cleanup/optimizations/null checks
|
||||
|
||||
|
||||
1.75.7003 (2017-03-24):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#464: Resolved issue when importing a connections file while using SQL server feature
|
||||
|
||||
|
||||
1.75.7002 (2017-03-10):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#448: Resolved issue with SQL saving
|
||||
|
||||
|
||||
1.75.7001 (2017-03-10):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#408: Update SQL scripts
|
||||
|
||||
|
||||
1.75 hotfix 1 (2017-03-06):
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
#437: Modify version numbering scheme
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#422: Uncaught exception when clicking in connection tree whitespace
|
||||
#312: Resolved KeePass auto-type issue
|
||||
#427: Export does not respect filtering user/password/domain
|
||||
|
||||
|
||||
|
||||
1.75 (2017-03-01):
|
||||
|
||||
Known Issue:
|
||||
------------
|
||||
File hash check will fail when updating from 1.75 Beta 1 to newer versions.
|
||||
Exception will be: "MD5 Hashes didn't match!" for 1.75 Beta 1 - 1.75 RC1
|
||||
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#344 - Use SHA512 File Hashes to validate downloads (in the update mechanism & posted to the Downloads page)
|
||||
Added Release Channels to the update check functionality allowing users to select one of 3 release channels for updates: Stable, Beta, Dev
|
||||
#360: Help -> About, Version # is now selectable/copyable
|
||||
#221: RDP: Optional disconnect after X number of minutes of inactivity
|
||||
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#369: Reset Layout Option Does Not Reset Notification Pane
|
||||
#362: Invalid cast exception when using the Notification Area Icon minimize/restore
|
||||
#334: Quick Connect displays warning when clicking on a folder
|
||||
#325: When using a connection with an external app, results in opening the same external app continuously
|
||||
#311: Import from Active Directory does not use machine's domain by default
|
||||
#258: Rename Tab dialog - populate original name in dialog (1.72 functionality)
|
||||
#211, #267: Recursive AD Import wasn't fully functional
|
||||
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
The usual general code clean up and refactoring
|
||||
#325: Code clean up and additional logging for External Tools based connections
|
||||
#298: Code clean up and additional logging around application startup
|
||||
#291, #236: External Tools code clean up and additional logging
|
||||
|
||||
|
||||
|
||||
1.75 Beta 3 (2016-12-01):
|
||||
|
||||
Known Issue:
|
||||
------------
|
||||
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
|
||||
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#289: Install fails during update process (only affects v1.75 beta 1 - v1.75 beta 2)
|
||||
|
||||
|
||||
1.75 Beta 2 (2016-12-01):
|
||||
|
||||
Features/Enhancements:
|
||||
@@ -10,7 +265,7 @@ Fixes:
|
||||
------
|
||||
#254: Component check window position issues and uncaught exception
|
||||
#260: Crash when attempting to load fully encrypted confCons v2.5
|
||||
#261: Double clicking folder in treeview doesnt expand it in 1.75 beta1
|
||||
#261: Double clicking folder in treeview doesn't expand it in 1.75 beta1
|
||||
#271: Install package is not using the last installation path
|
||||
#278: Silent installs not detecting prerequisites
|
||||
|
||||
@@ -54,7 +309,7 @@ Fixes:
|
||||
MR-965, MR-871, MR-629: Error 264 on RDP Connect attempt - Added timeout value to Tools -> Options -> Connections
|
||||
MR-946: Remove old/insecure SharpSSH and related components. Replace with SSH.NET for File Transfer Functionality
|
||||
MR-896: Added prerequisite installer check for KB2574819. Prevents "Class not registered" errors when opening RDP connections.
|
||||
PR-130: Fix Scan button width to fit russian translation
|
||||
PR-130: Fix Scan button width to fit Russian translation
|
||||
|
||||
|
||||
|
||||
@@ -62,7 +317,7 @@ PR-130: Fix Scan button width to fit russian translation
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
Updated GeckoFx pacakge
|
||||
Updated GeckoFx package
|
||||
Updated DockPanelSuite library to 2.10 Final
|
||||
Japanese translation updated
|
||||
MR-942: Refactored code relating to loading the connections file
|
||||
@@ -137,7 +392,7 @@ Port Scan is now Asynchronous (and is significantly faster)
|
||||
Fixes:
|
||||
------
|
||||
MR-874: Added work-around to installer to ignore installation prerequisites
|
||||
MR-884: Slow startup in some scnearios checking authenticode certificate
|
||||
MR-884: Slow startup in some scenarios checking authenticode certificate
|
||||
MR-872: Crash in External Tools when arguments aren't quoted
|
||||
MR-854: crashes when right clicking on connection tab
|
||||
MR-852: Option "Allow only a single instance of the application" non-functional
|
||||
@@ -278,7 +533,7 @@ Fixed issue MR-398 - Full Screen mode doesn't correctly make use of available sp
|
||||
Fixed issue MR-402 - scrollbar touch moves putty window
|
||||
Fixed issue MR-406 - Items disappear from External Tools toolbar when accessing External Tools panel
|
||||
Fixed issue MR-410 - Unhandled exception when clicking New button under Theme
|
||||
Fixed issue MR-413 - Can't use aplication
|
||||
Fixed issue MR-413 - Can't use application
|
||||
Fixed new connections having a globe icon.
|
||||
Fixed the category names in the themes tab of the options dialog on Windows XP not showing correctly.
|
||||
Fixed PuTTY saved sessions with spaces or special characters not being listed.
|
||||
|
||||
51
CREDITS.TXT
51
CREDITS.TXT
@@ -8,7 +8,21 @@ Sean Kaim (github.com/kmscode)
|
||||
Thanks for the awesome new website!
|
||||
Bennett Blodinger (github.com/benwa)
|
||||
|
||||
Joe Cefoli (github.com/jcefoli)
|
||||
countchappy (github.com/countchappy)
|
||||
Tony Lambert
|
||||
Julien Roncaglia (github.com/vbfox)
|
||||
github.com/peterchenadded
|
||||
Brandon Wulf (github.com/mrwulf)
|
||||
Pedro Rodrigues (github.com/pedro2555)
|
||||
github.com/dekelMP
|
||||
github.com/farosch
|
||||
Bruce (github.com/brucetp)
|
||||
Camilo Alvarez (github.com/jotatsu)
|
||||
github.com/DamianBis
|
||||
github.com/pfjason
|
||||
github.com/sirLoaf
|
||||
github.com/Fyers
|
||||
|
||||
|
||||
Past Contributors
|
||||
@@ -41,12 +55,16 @@ Robert Siwiec
|
||||
Hayato Iriumi
|
||||
Sebastien Thieury (github.com/SebThieu)
|
||||
Riza Emet
|
||||
Lukas Plachy (github.com/rheingold)
|
||||
Gyuha Shin
|
||||
Stefan (github.com/polluks)
|
||||
github.com/emazv72
|
||||
|
||||
|
||||
Included Source Code
|
||||
====================
|
||||
|
||||
Command Line Arguments Parser 1.0
|
||||
Command Line Arguments Parser
|
||||
Copyright <20> 2002 Richard Lopes
|
||||
MIT License
|
||||
http://www.codeproject.com/KB/recipes/command_line.aspx
|
||||
@@ -55,10 +73,6 @@ FilteredPropertyGrid
|
||||
Copyright <20> 2006 Azuria
|
||||
http://www.codeproject.com/KB/cs/FilteredPropertyGrid.aspx
|
||||
|
||||
Hotkey Selection Control for .NET
|
||||
Copyright <20> 2006 Thomas Backman
|
||||
http://www.codeproject.com/Articles/15085/A-simple-hotkey-selection-control-for-NET
|
||||
|
||||
InputBox
|
||||
Copyright <20> 2016 Jan Slama
|
||||
http://www.csharp-examples.net/inputbox/
|
||||
@@ -67,37 +81,41 @@ IP TextBox
|
||||
Copyright <20> 2005 mawnkay
|
||||
http://www.codeproject.com/Articles/11576/IP-TextBox
|
||||
|
||||
PortableSettingsProvider
|
||||
Copyright <20> 2014 crdx
|
||||
https://github.com/crdx/PortableSettingsProvider
|
||||
|
||||
|
||||
Included Components
|
||||
===================
|
||||
|
||||
ADTree 1.0
|
||||
ADTree
|
||||
Copyright <20> 2004 Marc Merritt
|
||||
Copyright <20> 2008 Felix Deimel
|
||||
http://www.codeproject.com/KB/selection/ADPickerCtrl.aspx
|
||||
|
||||
DockPanel Suite 2.10.0
|
||||
DockPanel Suite
|
||||
Copyright <20> 2016 @roken and @lextm (formerly Weifen Luo)
|
||||
MIT License
|
||||
https://github.com/dockpanelsuite/dockpanelsuite
|
||||
|
||||
GeckoFX 45
|
||||
GeckoFX
|
||||
Copyright <20> 2016 Tom Hindle
|
||||
Mozilla Public License
|
||||
https://bitbucket.org/geckofx/
|
||||
|
||||
log4net 1.2.15.0
|
||||
log4net
|
||||
Copyright <20> 2001-2015 The Apache Software Foundation
|
||||
Apache License Version 2.0
|
||||
http://logging.apache.org/log4net/
|
||||
|
||||
Magic Library 1.7.4
|
||||
Magic Library
|
||||
Copyright <20> 2002-2003 Crownwood Consulting, Ltd.
|
||||
Freely redistributable with attribution
|
||||
http://www.dotnetmagic.com/magic_download.html
|
||||
|
||||
PuTTY 0.67
|
||||
Copyright <20> 1997-2016 Simon Tatham
|
||||
PuTTY
|
||||
Copyright <20> 1997-2017 Simon Tatham
|
||||
MIT License
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/putty/
|
||||
|
||||
@@ -106,12 +124,17 @@ Copyright
|
||||
Creative Commons Attribution 2.5 License
|
||||
http://www.famfamfam.com/
|
||||
|
||||
SSH.NET v2016.0.0
|
||||
SSH.NET
|
||||
Copyright <20> 2016
|
||||
MIT License
|
||||
https://github.com/sshnet/SSH.NET
|
||||
|
||||
VncSharp 1.1
|
||||
VncSharp
|
||||
Copyright <20> 2004-2009 David Humphrey
|
||||
GNU General Public License (GPL) Version 2
|
||||
https://github.com/humphd/VncSharp
|
||||
|
||||
ObjectListView
|
||||
Copyright <20> 2006-2016 Phillip Piper
|
||||
GNU General Public License (GPL) Version 3
|
||||
https://sourceforge.net/projects/objectlistview/
|
||||
@@ -17,7 +17,7 @@
|
||||
<?define RequiredDotNetFrameworkServicePackLevel = "" ?>
|
||||
<?define RequiredDotNetFrameworkVersion = "$(var.RequiredDotNetFrameworkMajorVersion).$(var.RequiredDotNetFrameworkMinorVersion)" ?>
|
||||
<?define Rdp80Kb = "KB2592687" ?>
|
||||
<?define Rdp81Kb = "KB2923545" ?>
|
||||
<?define Rdp81Kb = "KB2830477" ?>
|
||||
<?define MinimumRdpKb = $(var.Rdp80Kb) ?>
|
||||
<?define RdpDtlsKb = "KB2574819" ?>
|
||||
<?define IGNOREPREREQUISITES = 0 ?>
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
<Compile Include="mRemoteNGV1.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Dependencies\PuTTYNG.exe">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Filters\Harvest_Filter.xslt" />
|
||||
<Content Include="Includes\Config.wxi" />
|
||||
<Content Include="Resources\header.bmp" />
|
||||
@@ -57,7 +54,6 @@
|
||||
<Folder Include="Localizations" />
|
||||
<Folder Include="Filters" />
|
||||
<Folder Include="bin" />
|
||||
<Folder Include="Dependencies" />
|
||||
<Folder Include="Resources" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -68,6 +64,10 @@
|
||||
<EmbeddedResource Include="Localizations\en-US.wxl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WixExtension Include="WixUtilExtension">
|
||||
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
|
||||
<Name>WixUtilExtension</Name>
|
||||
</WixExtension>
|
||||
<WixExtension Include="WixUIExtension">
|
||||
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
|
||||
<Name>WixUIExtension</Name>
|
||||
@@ -115,20 +115,19 @@
|
||||
<DefineConstants>HarvestPath=$(SolutionDir)mRemoteV1\bin\Release Portable;HelpFilesHarvestPath=$(SolutionDir)mRemoteV1\Resources\Help</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>set /p buildenv=<buildenv.tmp
|
||||
<PostBuildEvent>:: When passing paths to powershell scripts, check if the path ends with a backslash "\"
|
||||
:: If it does, then the backslash may be interpreted as an escape character. Add another backslash to cancel the first one.
|
||||
|
||||
REM Sign MSI
|
||||
IF EXIST C:\mRemoteNG_code_signing_cert.pfx (
|
||||
IF %25buildenv: Portable=%25==Release (
|
||||
powershell "&""$(SolutionDir)Tools\signfiles.ps1""" %27%25cd%25%27
|
||||
)
|
||||
)
|
||||
powershell -noprofile -command "sleep 2"
|
||||
set /p buildenv=<buildenv.tmp
|
||||
set solutionDir=$(SolutionDir)\
|
||||
set targetDir=%25cd%25
|
||||
set psScriptsDir=$(SolutionDir)Tools
|
||||
set certPath=$(CertPath)
|
||||
set certPassword=$(CertPassword)
|
||||
|
||||
REM Rename MSI to include version number
|
||||
powershell -ExecutionPolicy Bypass -File "$(SolutionDir)Tools\rename_installer_with_version.ps1" $(SolutionDir)
|
||||
|
||||
REM Copy MSI to Release folder
|
||||
IF %25buildenv: Portable=%25==Release (powershell -ExecutionPolicy Bypass -File "$(SolutionDir)Tools\copy_release_installer.ps1" $(TargetDir) $(SolutionDir)Release)</PostBuildEvent>
|
||||
:: Call the post build powershell script
|
||||
powershell.exe -ExecutionPolicy Bypass -File "%25psScriptsDir%25\postbuild_installer.ps1" -SolutionDir "%25solutionDir%25" -TargetDir "%25targetDir%25" -TargetFileName "mRemoteNG.exe" -ConfigurationName "%25buildenv%25" -CertificatePath "%25certPath%25" -CertificatePassword "%25certPassword%25"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>REM Clean the TargetDir
|
||||
@@ -137,9 +136,9 @@ rmdir /S /Q "$(TargetDir)"
|
||||
echo $(ConfigurationName) > buildenv.tmp
|
||||
|
||||
REM Harvest bin directory of the mRemoteV1 project
|
||||
call "$(WIX)bin\heat.exe" dir "$(SolutionDir)mRemoteV1\bin\$(Configuration)" -ag -dr INSTALLDIR -var var.HarvestPath -srd -cg MandatoryComponents -template fragment -out "$(ProjectDir)Fragments\FilesFragment.wxs" -t "$(ProjectDir)Filters\Harvest_Filter.xslt" -v
|
||||
"$(WIX)bin\heat.exe" dir "$(SolutionDir)mRemoteV1\bin\$(Configuration)" -ag -nologo -dr INSTALLDIR -var var.HarvestPath -srd -cg MandatoryComponents -template fragment -out "$(ProjectDir)Fragments\FilesFragment.wxs" -t "$(ProjectDir)Filters\Harvest_Filter.xslt"
|
||||
|
||||
REM Convert the license file "COPYING.TXT" to "License.rtf" to be shown in the installer GUI
|
||||
call "$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
|
||||
"$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -6,7 +6,7 @@
|
||||
<String Id="Install_NeedToBeAdminToInstall">You need to be an administrator to install this product.</String>
|
||||
<String Id="Install_NeedDotNetFrameworkVersion">mRemoteNG requires Microsoft .NET Framework [REQUIREDDOTNETFRAMEWORKVERSION] or higher.</String>
|
||||
<String Id="Install_OSVersionRequirement">mRemoteNG requires Windows 7 SP1 or higher to run. Please update your operating system and try again.</String>
|
||||
<String Id="Install_RDP80Requirement">mRemoteNG requires RDP 8.0 or higher to run. Windows 7 users will need to install KB2592687</String>
|
||||
<String Id="Install_RDP80Requirement">mRemoteNG requires RDP 8.0 or higher to run. Windows 7 users will need to install either KB2592687 (RDP 8.0) or KB2830477 (RDP 8.1)</String>
|
||||
<String Id="Install_RDPDtlsRequirement">mRemoteNG requires KB2574819 in order to create RDP connections. Windows 7 users will need to install this KB.</String>
|
||||
<String Id="Install_Win7RequiresSP1">For mRemoteNG to run on Windows 7, it requires Service Pack 1 to be installed. Please install Service Pack 1 and try again.</String>
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
<String Id="Feature_StartMenuShortcut">Start menu shortcut</String>
|
||||
|
||||
<!-- GUI Page Text -->
|
||||
<String Id="FinishPage_LaunchMremoteNow" Overridable="yes">Launch [ProductName] Now</String>
|
||||
<String Id="FinishPage_LaunchMremoteNow" Overridable="yes">Launch mRemoteNG Now</String>
|
||||
|
||||
</WixLocalization>
|
||||
@@ -10,6 +10,7 @@
|
||||
<MajorUpgrade DowngradeErrorMessage="!(loc.Upgrade_NewerVersionInstalled)" Schedule="afterInstallExecute" />
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
<Binary Id="CustomActions.CA.dll" SourceFile="$(var.SolutionDir)InstallerProjects\CustomActions\bin\$(var.Configuration)\CustomActions.CA.dll" />
|
||||
<Property Id="MsiLogging" Value="v" />
|
||||
<Property Id="ARPPRODUCTICON" Value="mRemoteNG.ico" />
|
||||
<Property Id="ARPHELPLINK" Value="http://www.mremoteng.org" />
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize" />
|
||||
@@ -67,7 +68,7 @@
|
||||
<Condition Message="!(loc.Install_RDPDtlsRequirement)">
|
||||
<![CDATA[Installed OR (IGNOREPREREQUISITES = 1) OR (VersionNT >= 602 OR VersionNT64 >= 602) OR ((VersionNT = 601 OR VersionNT64 = 601) AND (RDP_DTLS_UPDATE_INSTALLED = 1))]]>
|
||||
</Condition>
|
||||
<!-- If Win7, require RDP 8.0 update (KB2592687) -->
|
||||
<!-- If Win7, require RDP 8.0 (KB2592687) or 8.1 (KB2830477) update -->
|
||||
<Condition Message="!(loc.Install_RDP80Requirement)">
|
||||
<![CDATA[Installed OR (IGNOREPREREQUISITES = 1) OR (VersionNT >= 602 OR VersionNT64 >= 602) OR ((VersionNT = 601 OR VersionNT64 = 601) AND (MINIMUM_RDP_VERSION_INSTALLED = 1))]]>
|
||||
</Condition>
|
||||
@@ -95,10 +96,22 @@
|
||||
</Feature>
|
||||
</Feature>
|
||||
|
||||
<UI>
|
||||
<UIRef Id="WixUI_FeatureTree"/>
|
||||
<UIRef Id="WixUI_ErrorProgressText" />
|
||||
<Publish Dialog="ExitDialog"
|
||||
Control="Finish"
|
||||
Event="DoAction"
|
||||
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
|
||||
</UI>
|
||||
|
||||
<UIRef Id="WixUI_FeatureTree"/>
|
||||
<WixVariable Id="WixUILicenseRtf" Value="Resources\License.rtf" />
|
||||
<WixVariable Id="WixUIDialogBmp" Value="Resources\welcome.bmp" />
|
||||
<WixVariable Id="WixUIBannerBmp" Value="Resources\header.bmp" />
|
||||
|
||||
<!-- Provide option to run app after install -->
|
||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="!(loc.FinishPage_LaunchMremoteNow)" />
|
||||
<Property Id="WixShellExecTarget" Value="[#MainExeFile]" />
|
||||
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
|
||||
</Product>
|
||||
</Wix>
|
||||
68
Jenkinsfile
vendored
68
Jenkinsfile
vendored
@@ -3,25 +3,61 @@ node('windows') {
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
|
||||
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
|
||||
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([
|
||||
$class: 'GitSCM',
|
||||
branches: scm.branches,
|
||||
userRemoteConfigs: scm.userRemoteConfigs
|
||||
])
|
||||
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 ('Restore NuGet Packages') {
|
||||
def nugetPath = "C:\\nuget.exe"
|
||||
bat "${nugetPath} restore ${solutionFilePath}"
|
||||
}
|
||||
|
||||
stage 'Build mRemoteNG (Normal)'
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
stage ('Build mRemoteNG (Normal)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
}
|
||||
|
||||
stage 'Build mRemoteNG (Portable)'
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
}
|
||||
|
||||
stage 'Run Unit Tests'
|
||||
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions"
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\debug\\mRemoteNGTests.dll\""
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
68
Jenkinsfile_publish.groovy
Normal file
68
Jenkinsfile_publish.groovy
Normal file
@@ -0,0 +1,68 @@
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
|
||||
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
|
||||
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions"
|
||||
|
||||
|
||||
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 "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /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 "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /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 "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\""
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\""
|
||||
}
|
||||
|
||||
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 zipPath = "${jobDir}\\Release\\*.zip"
|
||||
def msiPath = "${jobDir}\\Release\\*.msi"
|
||||
// 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} -ZipFilePath \"${zipPath}\" -MsiFilePath \"${msiPath}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
66
README.MD
66
README.MD
@@ -1,43 +1,59 @@
|
||||
# Welcome to the mRemoteNG project!
|
||||
|
||||
[](https://twitter.com/intent/follow?screen_name=mRemoteNG)
|
||||
|
||||
|
||||
[](https://gitter.im/mRemoteNG/PublicChat)
|
||||
|
||||
[](https://www.paypal.me/DavidSparer)
|
||||
|
||||
[](http://ec2-52-39-111-114.us-west-2.compute.amazonaws.com:8080/job/mRemoteNG/job/mRemoteNG/job/develop/)
|
||||
[](https://waffle.io/mRemoteNG/mRemoteNG)
|
||||
[](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74)
|
||||
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/529)
|
||||
|
||||
[](https://waffle.io/mRemoteNG/mRemoteNG)
|
||||
|
||||
| Update Channel | Build Status | Downloads |
|
||||
| ---------------|--------------|-----------|
|
||||
| Stable | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/master) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7011) |
|
||||
| Beta | | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7011) |
|
||||
| Development | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76Alpha2) |
|
||||
|
||||
mRemoteNG is the next generation of mRemote, a full-featured, multi-tab remote connections manager.
|
||||
|
||||
It allows you to store all your remote connections in a simple yet powerful interface.
|
||||
## Features
|
||||
|
||||
Currently these protocols are supported:
|
||||
mRemoteNG is a fork of mRemote: an open source, tabbed, multi-protocol, remote connections manager. mRemoteNG adds bug fixes and new features to mRemote.
|
||||
|
||||
* RDP (Remote Desktop)
|
||||
* VNC (Virtual Network Computing)
|
||||
* ICA (Independent Computing Architecture)
|
||||
* SSH (Secure Shell)
|
||||
* Telnet (TELecommunication NETwork)
|
||||
* HTTP/S (Hypertext Transfer Protocol)
|
||||
* Rlogin (Rlogin)
|
||||
* RAW
|
||||
It allows you to view all of your remote connections in a simple yet powerful tabbed interface.
|
||||
|
||||
mRemoteNG can be installed on Windows 7 or later.
|
||||
mRemoteNG supports the following protocols:
|
||||
|
||||
Windows 7 systems require RDP version 8:
|
||||
https://support.microsoft.com/en-us/kb/2592687
|
||||
OR
|
||||
https://support.microsoft.com/en-us/kb/2923545
|
||||
* RDP (Remote Desktop/Terminal Server)
|
||||
* VNC (Virtual Network Computing)
|
||||
* ICA (Citrix Independent Computing Architecture)
|
||||
* SSH (Secure Shell)
|
||||
* Telnet (TELecommunication NETwork)
|
||||
* HTTP/HTTPS (Hypertext Transfer Protocol)
|
||||
* rlogin (Remote Login)
|
||||
* Raw Socket Connections
|
||||
|
||||
Windows 8+ support RDP version 8+ out of the box.
|
||||
For a detailed feature list and general usage support, refer to the [User Manual](https://github.com/mRemoteNG/mRemoteNG/wiki/User-Manual).
|
||||
|
||||
RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connection successfully to a Windows 2003 host (for example).
|
||||
## Installation
|
||||
|
||||
Before installing make sure you have all the required [prerequisites](https://github.com/mRemoteNG/mRemoteNG/wiki/Prerequisites).
|
||||
|
||||
mRemoteNG is available as a redistributable msi package, and can be downloaded from the following locations:
|
||||
* [GitHub](https://github.com/mRemoteNG/mRemoteNG/releases)
|
||||
* [Project Website](https://mremoteng.org/download)
|
||||
|
||||
[](https://www.jetbrains.com/resharper/)
|
||||
mRemoteNG is supported on Windows 7 or later.
|
||||
Windows 7 and Windows Server 2008 installations must ensure the [listed required updates](https://github.com/mRemoteNG/mRemoteNG/wiki/Prerequisites#full-list-of-required-windows-updates-for-windows-7--server-2008-clients) are installed and active.
|
||||
|
||||
## Contribute
|
||||
|
||||
If you find mRemoteNG useful and would like to contribute, it would be greatly appreciated. When you contribute, you make it possible for the team to cover the costs of producing mRemoteNG.
|
||||
|
||||
### Submit Code
|
||||
Check out the [Wiki page](https://github.com/mRemoteNG/mRemoteNG/wiki/Development) on how to configure your development environment and submit a pull request.
|
||||
|
||||
### Translate
|
||||
Check out the [Wiki page](https://github.com/mRemoteNG/mRemoteNG/wiki/How%20to%20Help%20Translating%20mRemoteNG) on how to help make mRemoteNG a polygot
|
||||
|
||||
[](https://www.jetbrains.com/resharper/)
|
||||
|
||||
@@ -5,7 +5,7 @@ setlocal enabledelayedexpansion
|
||||
set SOLUTIONDIR=%~dp0..
|
||||
|
||||
rem Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
set SIGCHECK="%SOLUTIONDIR%\Tools\sigcheck.exe"
|
||||
set SIGCHECK="%SOLUTIONDIR%\Tools\exes\sigcheck.exe"
|
||||
set SEVENZIP="%SOLUTIONDIR%\Tools\7zip\7za.exe"
|
||||
|
||||
set VCVARSALL="%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
|
||||
15
Tools/copy_puttyng.ps1
Normal file
15
Tools/copy_puttyng.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
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 "mRemoteV1\Resources\PuTTYNG.exe") -Destination $TargetDir -Force
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,16 +1,21 @@
|
||||
$sourcePath = $args[0]
|
||||
$destinationDir = $args[1]
|
||||
param (
|
||||
[string]
|
||||
$SourcePath,
|
||||
|
||||
Write-Host $sourcePath
|
||||
Write-Host $destinationDir
|
||||
[string]
|
||||
$DestinationDir
|
||||
)
|
||||
|
||||
if (!(Test-Path -Path $destinationDir))
|
||||
Write-Host $SourcePath
|
||||
Write-Host $DestinationDir
|
||||
|
||||
if (!(Test-Path -Path $DestinationDir))
|
||||
{
|
||||
New-Item -Path $destinationDir -ItemType "directory"
|
||||
New-Item -Path $DestinationDir -ItemType "directory"
|
||||
}
|
||||
|
||||
$sourceFiles = Get-ChildItem -Path $sourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
|
||||
$sourceFiles = Get-ChildItem -Path $SourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
|
||||
foreach ($item in $sourceFiles)
|
||||
{
|
||||
Copy-Item -Path $item.FullName -Destination $destinationDir -Force
|
||||
Copy-Item -Path $item.FullName -Destination $DestinationDir -Force
|
||||
}
|
||||
19
Tools/copy_themes.ps1
Normal file
19
Tools/copy_themes.ps1
Normal file
@@ -0,0 +1,19 @@
|
||||
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 , 'mRemoteV1\Resources\Themes' )
|
||||
$DestinationDir = [io.path]::combine($TargetDir , 'Themes')
|
||||
|
||||
robocopy $sourceFiles $DestinationDir *.vstheme /s
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,41 +1,109 @@
|
||||
#Requires -Version 4.0
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName,
|
||||
|
||||
$tag = Read-Host -Prompt 'Tag name'
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("Stable","Beta","Development")]
|
||||
$UpdateChannel
|
||||
)
|
||||
|
||||
Write-Host
|
||||
Write-Host
|
||||
Write-Host
|
||||
|
||||
Write-Host PORTABLE
|
||||
Write-Host --------
|
||||
$file = gci ..\Release\*.zip | sort LastWriteTime | select -last 1 | % { $_.FullName }
|
||||
$filename = $file.Split("\") | select -last 1
|
||||
|
||||
$version = $file.tostring().Split("-")[2].trim(".zip")
|
||||
Write-Host Version: $version
|
||||
function New-MsiUpdateFileContent {
|
||||
param (
|
||||
[System.IO.FileInfo]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$MsiFile,
|
||||
|
||||
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
|
||||
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName
|
||||
)
|
||||
|
||||
$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 MD5 $file | % { $_.Hash }
|
||||
Write-Host Checksum: $hash
|
||||
|
||||
$fileContents = `
|
||||
"Version: $version
|
||||
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$TagName/$($MsiFile.Name)
|
||||
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$TagName/CHANGELOG.TXT
|
||||
CertificateThumbprint: $certThumbprint
|
||||
Checksum: $hash"
|
||||
Write-Output $fileContents
|
||||
}
|
||||
|
||||
Write-Host
|
||||
Write-Host
|
||||
Write-Host
|
||||
|
||||
Write-Host MSI
|
||||
Write-Host ---
|
||||
$file = gci ..\Release\*.msi | sort LastWriteTime | select -last 1 | % { $_.FullName }
|
||||
$filename = $file.Split("\") | select -last 1
|
||||
function New-ZipUpdateFileContent {
|
||||
param (
|
||||
[System.IO.FileInfo]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ZipFile,
|
||||
|
||||
$version = $file.tostring().Split("-")[2].trim(".msi")
|
||||
Write-Host Version: $version
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName
|
||||
)
|
||||
|
||||
$version = $ZipFile.BaseName -replace "[a-zA-Z-]*"
|
||||
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | % { $_.Hash }
|
||||
|
||||
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
|
||||
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
|
||||
$fileContents = `
|
||||
"Version: $version
|
||||
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$TagName/$($ZipFile.Name)
|
||||
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$TagName/CHANGELOG.TXT
|
||||
Checksum: $hash"
|
||||
Write-Output $fileContents
|
||||
}
|
||||
|
||||
Write-Host CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
|
||||
$hash = Get-FileHash -Algorithm MD5 $file | % { $_.Hash }
|
||||
Write-Host Checksum: $hash
|
||||
|
||||
function Resolve-UpdateCheckFileName {
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("Stable","Beta","Development")]
|
||||
$UpdateChannel,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("Normal","Portable")]
|
||||
$Type
|
||||
)
|
||||
|
||||
$fileName = ""
|
||||
|
||||
if ($UpdateChannel -eq "Beta") { $fileName += "beta-" }
|
||||
elseif ($UpdateChannel -eq "Development") { $fileName += "dev-" }
|
||||
|
||||
$fileName += "update"
|
||||
|
||||
if ($Type -eq "Portable") { $fileName += "-portable" }
|
||||
|
||||
$fileName += ".txt"
|
||||
|
||||
Write-Output $fileName
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$releaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
|
||||
|
||||
# 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" | 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"
|
||||
BIN
Tools/exes/dumpbin.exe
Normal file
BIN
Tools/exes/dumpbin.exe
Normal file
Binary file not shown.
BIN
Tools/exes/editbin.exe
Normal file
BIN
Tools/exes/editbin.exe
Normal file
Binary file not shown.
BIN
Tools/exes/link.exe
Normal file
BIN
Tools/exes/link.exe
Normal file
Binary file not shown.
BIN
Tools/exes/mspdbcore.dll
Normal file
BIN
Tools/exes/mspdbcore.dll
Normal file
Binary file not shown.
61
Tools/find_vstool.ps1
Normal file
61
Tools/find_vstool.ps1
Normal file
@@ -0,0 +1,61 @@
|
||||
[CmdletBinding()]
|
||||
|
||||
param (
|
||||
[string]
|
||||
# Name of the file to find
|
||||
$FileName
|
||||
)
|
||||
|
||||
|
||||
|
||||
function EditBinCertificateIsValid() {
|
||||
param (
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
|
||||
# Verify file certificate
|
||||
$valid_microsoft_cert_thumbprints = @(
|
||||
"3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC",
|
||||
"98ED99A67886D020C564923B7DF25E9AC019DF26",
|
||||
"108E2BA23632620C427C570B6D9DB51AC31387FE",
|
||||
"5EAD300DC7E4D637948ECB0ED829A072BD152E17"
|
||||
)
|
||||
$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"
|
||||
return $false
|
||||
} else {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ToolCanBeExecuted {
|
||||
param (
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
$null = & $Path
|
||||
Write-Output ($LASTEXITCODE -gt 0)
|
||||
}
|
||||
|
||||
$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)
|
||||
)
|
||||
|
||||
# Returns the first full path to the $FileName that our search can find
|
||||
foreach ($searchPath in $rootSearchPaths) {
|
||||
foreach ($visualStudioFolder in $searchPath) {
|
||||
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)) {
|
||||
return $matchingExe
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Error "Could not find any valid file by the name $FileName." -ErrorAction Stop
|
||||
220
Tools/github_functions.ps1
Normal file
220
Tools/github_functions.ps1
Normal file
@@ -0,0 +1,220 @@
|
||||
$githubUrl = 'https://api.github.com'
|
||||
|
||||
|
||||
function Publish-GitHubRelease {
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseTitle,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Either the SHA of the commit to target or the branch name.
|
||||
$TargetCommitish,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Description,
|
||||
|
||||
[bool]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$IsDraft,
|
||||
|
||||
[bool]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$IsPrerelease,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
)
|
||||
|
||||
$body = New-GitHubReleaseRequestBody -TagName $TagName -TargetCommitish $TargetCommitish -ReleaseTitle $ReleaseTitle -Description $Description -IsDraft $IsDraft -IsPrerelease $IsPrerelease
|
||||
$req_publishRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body $body -ErrorAction Stop
|
||||
$response_publishRelease = ConvertFrom-Json -InputObject $req_publishRelease.Content
|
||||
|
||||
Write-Output $response_publishRelease
|
||||
}
|
||||
|
||||
|
||||
function Edit-GitHubRelease {
|
||||
param (
|
||||
[string]
|
||||
#[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
#[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
#[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseId,
|
||||
|
||||
[string]
|
||||
#
|
||||
$ReleaseTitle,
|
||||
|
||||
[string]
|
||||
#
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
# Either the SHA of the commit to target or the branch name.
|
||||
$TargetCommitish,
|
||||
|
||||
[string]
|
||||
#
|
||||
$Description,
|
||||
|
||||
[bool]
|
||||
#
|
||||
$IsDraft,
|
||||
|
||||
[bool]
|
||||
#
|
||||
$IsPrerelease,
|
||||
|
||||
[string]
|
||||
#[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
)
|
||||
|
||||
$body_params = @{
|
||||
"TagName" = $TagName
|
||||
"TargetCommitish" = $TargetCommitish
|
||||
"ReleaseTitle" = $ReleaseTitle
|
||||
"Description" = $Description
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("IsDraft", $IsDraft) }
|
||||
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("IsPrerelease", $IsPrerelease) }
|
||||
|
||||
$body = New-GitHubReleaseRequestBody @body_params
|
||||
$req_editRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases/$ReleaseId" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body $body -ErrorAction Stop
|
||||
$response_editRelease = ConvertFrom-Json -InputObject $req_editRelease.Content
|
||||
|
||||
Write-Output $response_editRelease
|
||||
}
|
||||
|
||||
|
||||
function Get-GitHubRelease {
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseId,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
)
|
||||
|
||||
$req_getRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases/$ReleaseId" -Method Get -Headers @{"Authorization"="token $AuthToken"} -ErrorAction Stop
|
||||
$response_getRelease = ConvertFrom-Json -InputObject $req_getRelease.Content
|
||||
|
||||
Write-Output $response_getRelease
|
||||
}
|
||||
|
||||
|
||||
function Upload-GitHubReleaseAsset {
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$UploadUri,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Path to the file to upload with the release
|
||||
$FilePath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Content type of the file
|
||||
$ContentType,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
)
|
||||
|
||||
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$"
|
||||
$file = Get-Item -Path $FilePath
|
||||
|
||||
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
|
||||
}
|
||||
|
||||
|
||||
function New-GitHubReleaseRequestBody {
|
||||
param (
|
||||
[string]
|
||||
#
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
# Either the SHA of the commit to target or the branch name.
|
||||
$TargetCommitish,
|
||||
|
||||
[string]
|
||||
# Title of the release
|
||||
$ReleaseTitle,
|
||||
|
||||
[string]
|
||||
# Description of the release
|
||||
$Description,
|
||||
|
||||
[bool]
|
||||
# Is this a draft?
|
||||
$IsDraft,
|
||||
|
||||
[bool]
|
||||
# Is this a pre-release?
|
||||
$IsPrerelease
|
||||
)
|
||||
|
||||
$body_params = [ordered]@{}
|
||||
if ($TagName -ne "") { $body_params.Add("tag_name", $TagName) }
|
||||
if ($TargetCommitish -ne "") { $body_params.Add("target_commitish", $TargetCommitish) }
|
||||
if ($ReleaseTitle -ne "") { $body_params.Add("name", $ReleaseTitle) }
|
||||
if ($Description -ne "") { $body_params.Add("body", $Description) }
|
||||
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("draft", $IsDraft) }
|
||||
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("prerelease", $IsPrerelease) }
|
||||
|
||||
$json_body = ConvertTo-Json -InputObject $body_params -Compress
|
||||
Write-Output $json_body
|
||||
}
|
||||
23
Tools/move_help_files.ps1
Normal file
23
Tools/move_help_files.ps1
Normal file
@@ -0,0 +1,23 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_HelpFilesDir = Join-Path -Path $TargetDir -ChildPath "Help"
|
||||
|
||||
Write-Output "Moving Help files to correct directory"
|
||||
|
||||
# Remove stale Help files, if they exist
|
||||
if (Test-Path -Path $path_HelpFilesDir) {
|
||||
Remove-Item -Path $path_HelpFilesDir -Recurse -Force
|
||||
}
|
||||
|
||||
# Move Help files
|
||||
Move-Item -Path (Join-Path -Path $TargetDir -ChildPath "Resources\Help") -Destination $path_HelpFilesDir -Force
|
||||
Start-Sleep -Seconds 2
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "Resources") -Recurse -Force
|
||||
|
||||
Write-Output ""
|
||||
43
Tools/postbuild_installer.ps1
Normal file
43
Tools/postbuild_installer.ps1
Normal file
@@ -0,0 +1,43 @@
|
||||
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 Installer Post Build |"
|
||||
Write-Output "+=================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath
|
||||
& "$PSScriptRoot\rename_installer_with_version.ps1" -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\copy_release_installer.ps1" -SourcePath $TargetDir -DestinationDir (Join-Path -Path $SolutionDir -ChildPath "Release")
|
||||
49
Tools/postbuild_mremotev1.ps1
Normal file
49
Tools/postbuild_mremotev1.ps1
Normal file
@@ -0,0 +1,49 @@
|
||||
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 mRemoteV1 Post Build |"
|
||||
Write-Output "+=================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
|
||||
& "$PSScriptRoot\copy_puttyng.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\copy_themes.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\move_help_files.ps1" -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
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
25
Tools/publish_draft_github_release.ps1
Normal file
25
Tools/publish_draft_github_release.ps1
Normal file
@@ -0,0 +1,25 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseId,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
Edit-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $ReleaseId -AuthToken $AuthToken -IsDraft $false
|
||||
76
Tools/publish_to_github.ps1
Normal file
76
Tools/publish_to_github.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseTitle,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Either the SHA of the commit to target or the branch name.
|
||||
$TargetCommitish,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Description,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("true","false")]
|
||||
# true/false
|
||||
$IsDraft,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("true","false")]
|
||||
# true/false
|
||||
$IsPrerelease,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Path to the zip file to upload with the release
|
||||
$ZipFilePath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#Path to the msi file to upload with the release
|
||||
$MsiFilePath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken,
|
||||
|
||||
[switch]
|
||||
# Enable this switch to treat $Description as a Base64 encoded string. It will be decoded before being used elsewhere in the script.
|
||||
$DescriptionIsBase64Encoded
|
||||
)
|
||||
|
||||
|
||||
if ($DescriptionIsBase64Encoded) {
|
||||
$Description = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Description)))
|
||||
}
|
||||
|
||||
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
|
||||
$release = Publish-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken
|
||||
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken
|
||||
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken
|
||||
Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken)
|
||||
@@ -1,11 +1,15 @@
|
||||
$solutionDir = $args[0]
|
||||
$renameTarget = $solutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
param (
|
||||
[string]
|
||||
$SolutionDir
|
||||
)
|
||||
|
||||
Write-Host $solutionDir
|
||||
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
|
||||
Write-Host $SolutionDir
|
||||
Write-Host $renameTarget
|
||||
|
||||
$targetVersionedFile = "$solutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
|
||||
$version = &"$solutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
$targetVersionedFile = "$SolutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
|
||||
$version = &"$SolutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
|
||||
|
||||
$renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue
|
||||
|
||||
22
Tools/set_LargeAddressAware.ps1
Normal file
22
Tools/set_LargeAddressAware.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
[CmdletBinding()]
|
||||
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_editBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\editbin.exe"
|
||||
$path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
|
||||
# Set LargeAddressAware
|
||||
Write-Output "Setting LargeAddressAware on binary file:`n`"$path_outputExe`" `nwith:`n`"$path_editBin`""
|
||||
& "$path_editBin" /largeaddressaware "$path_outputExe"
|
||||
|
||||
Write-Output ""
|
||||
76
Tools/sign_binaries.ps1
Normal file
76
Tools/sign_binaries.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string[]]
|
||||
# File names to exclude from signing
|
||||
$Exclude,
|
||||
|
||||
[string]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
# Password to unlock the code signing certificate.
|
||||
$CertificatePassword
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
|
||||
|
||||
if ($ConfigurationName -notmatch "Release") {
|
||||
Write-Output "This is not a release build - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,13 +1,31 @@
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
$certPath = "C:\mRemoteNG_code_signing_cert.pfx"
|
||||
$certPassword = (Get-Credential -Message "Enter the password for the certificate" -UserName "USERNAME NOT NEEDED").Password
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath, $certPassword)
|
||||
$targetPath = $args[0]
|
||||
param(
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Folder path that contains the files you would like to sign. Recursive.
|
||||
$PathToSignableFiles,
|
||||
|
||||
[string]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath = "C:\mRemoteNG_code_signing_cert.pfx",
|
||||
|
||||
[SecureString]
|
||||
# Password to unlock the code signing certificate.
|
||||
$CertificatePassword = (Get-Credential -Message "Enter password for the mRemoteNG code signing certificate" -UserName "USERNAME NOT NEEDED").Password,
|
||||
|
||||
[string[]]
|
||||
# File names to exclude from signing
|
||||
$Exclude
|
||||
)
|
||||
|
||||
|
||||
Write-Output "Getting files from path: $targetPath"
|
||||
$signableFiles = Get-ChildItem -Path $targetPath -Recurse | ?{$_.Extension -match "dll|exe|msi"}
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword)
|
||||
|
||||
|
||||
Write-Output "Getting files from path: $PathToSignableFiles"
|
||||
$signableFiles = Get-ChildItem -Path $PathToSignableFiles -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
|
||||
}
|
||||
33
Tools/tidy_files_for_release.ps1
Normal file
33
Tools/tidy_files_for_release.ps1
Normal file
@@ -0,0 +1,33 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# Remove unnecessary files from Release versions
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Removing unnecessary files from Release versions"
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
|
||||
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
|
||||
"*.pdb",
|
||||
"*.publish",
|
||||
"*.xml",
|
||||
"*.backup",
|
||||
"*.log",
|
||||
"*vshost*",
|
||||
"*.tmp"
|
||||
)
|
||||
Remove-Item -Path $filesToDelete.FullName
|
||||
Write-Output $filesToDelete.FullName
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not remove anything - this is not a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
17
Tools/validate_microsoft_tool.ps1
Normal file
17
Tools/validate_microsoft_tool.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
# $FullPath Full path to the Microsoft executable to validate
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$FullPath
|
||||
)
|
||||
|
||||
$validMSCertThumbprints = @("3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC", "108E2BA23632620C427C570B6D9DB51AC31387FE", "98ED99A67886D020C564923B7DF25E9AC019DF26", "5EAD300DC7E4D637948ECB0ED829A072BD152E17")
|
||||
$exeSignature = Get-AuthenticodeSignature -FilePath $FullPath
|
||||
$baseErrorMsg = "Could not validate the certificate of $FullPath. "
|
||||
|
||||
if ($exeSignature.Status -ne "Valid") {
|
||||
Write-Error -Message ($baseErrorMsg+"The signature was invalid.") -ErrorAction Stop
|
||||
}
|
||||
elseif ($validMSCertThumbprints -notcontains $exeSignature.SignerCertificate.Thumbprint) {
|
||||
Write-Error -Message ($baseErrorMsg+"The certificate thumbprint ($($exeSignature.SignerCertificate.Thumbprint)) is not trusted.") -ErrorAction Stop
|
||||
}
|
||||
30
Tools/verify_LargeAddressAware.ps1
Normal file
30
Tools/verify_LargeAddressAware.ps1
Normal file
@@ -0,0 +1,30 @@
|
||||
[CmdletBinding()]
|
||||
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_dumpBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\dumpbin.exe"
|
||||
$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)
|
||||
{
|
||||
Write-Warning "Could not validate LargeAddressAware"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $output.ToString().TrimStart(" ")
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
47
Tools/verify_binary_signatures.ps1
Normal file
47
Tools/verify_binary_signatures.ps1
Normal file
@@ -0,0 +1,47 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# validate release versions and if the certificate is available
|
||||
if ($ConfigurationName -match "Release") {
|
||||
|
||||
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
|
||||
{
|
||||
Write-Output "Certificate is not present - files likely not signed - we won't verify file signatures."
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Verifying signature of binaries"
|
||||
Write-Output "Getting files from path: $TargetDir"
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.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") {
|
||||
Write-Warning "File $($file.FullName) does not have a valid signature."
|
||||
$badSignatureFound = $true
|
||||
}
|
||||
}
|
||||
if ($badSignatureFound) {
|
||||
Write-Output "One or more files were improperly signed."
|
||||
} else {
|
||||
Write-Output "All files have valid signatures."
|
||||
}
|
||||
} else {
|
||||
Write-Output "This is not a release build - we won't verify file signatures."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
28
Tools/zip_portable_files.ps1
Normal file
28
Tools/zip_portable_files.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
$path_packageZipScript = Join-Path -Path $SolutionDir -ChildPath "Tools\build-relport.cmd"
|
||||
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
& $path_packageZipScript
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -1 +0,0 @@
|
||||
<Playlist Version="1.0"><Add Test="mRemoteNGTests.UI.WindowListTests.TestMethod1" /><Add Test="mRemoteNGTests.UI.WindowListTests.AddWindowToList" /><Add Test="mRemoteNGTests.UI.WindowListTests.CountReturnsCorrectNumber" /></Playlist>
|
||||
20
appveyor.yml
Normal file
20
appveyor.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
version: 1.0.{build}
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
image: Visual Studio 2017
|
||||
configuration:
|
||||
- Release
|
||||
- Release Portable
|
||||
platform: x86
|
||||
clone_depth: 1
|
||||
install:
|
||||
- ps: C:\projects\mremoteng\mRemoteV1\Resources\CitrixReceiver.exe DONOTSTARTCC=1 ENABLE_SSON="No" /silent | out-null
|
||||
before_build:
|
||||
- cmd: nuget restore
|
||||
build:
|
||||
project: mRemoteV1.sln
|
||||
verbosity: normal
|
||||
test:
|
||||
assemblies:
|
||||
only:
|
||||
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
|
||||
26
mRemoteNG.Specs/App.config
Normal file
26
mRemoteNG.Specs/App.config
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
|
||||
</configSections>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="WeifenLuo.WinFormsUI.Docking" publicKeyToken="5cded1a1a0a7b481" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.16.0.0" newVersion="2.16.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
|
||||
</startup>
|
||||
<specFlow>
|
||||
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
|
||||
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
|
||||
<unitTestProvider name="NUnit" />
|
||||
</specFlow>
|
||||
</configuration>
|
||||
25
mRemoteNG.Specs/Features/CredentialRepository.feature
Normal file
25
mRemoteNG.Specs/Features/CredentialRepository.feature
Normal file
@@ -0,0 +1,25 @@
|
||||
Feature: CredentialRepository
|
||||
As a user with several environments
|
||||
I would like to load multiple credential repositories
|
||||
In order to keep credentials separate
|
||||
|
||||
@credentials
|
||||
Scenario: Load credential repository
|
||||
Given I have a credential repository
|
||||
And the credential repository is unloaded
|
||||
When I click load
|
||||
Then the credential repository is loaded
|
||||
|
||||
Scenario: Add credential record
|
||||
Given I have a credential repository
|
||||
And The credential repository is loaded
|
||||
And The repository has 0 credentials
|
||||
When I click add credential
|
||||
Then the repository has 1 credentials
|
||||
|
||||
Scenario: Unload credential repository
|
||||
Given I have a credential repository
|
||||
And The credential repository is loaded
|
||||
And The repository has 1 credentials
|
||||
When I click unload
|
||||
Then the credentials in the repository will no longer be available
|
||||
138
mRemoteNG.Specs/Features/CredentialRepository.feature.cs
generated
Normal file
138
mRemoteNG.Specs/Features/CredentialRepository.feature.cs
generated
Normal file
@@ -0,0 +1,138 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:2.2.0.0
|
||||
// SpecFlow Generator Version:2.2.0.0
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
// ------------------------------------------------------------------------------
|
||||
#region Designer generated code
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
#pragma warning disable
|
||||
namespace mRemoteNG.Specs.Features
|
||||
{
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.2.0.0")]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[NUnit.Framework.TestFixtureAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("CredentialRepository")]
|
||||
public partial class CredentialRepositoryFeature
|
||||
{
|
||||
|
||||
private TechTalk.SpecFlow.ITestRunner testRunner;
|
||||
|
||||
#line 1 "CredentialRepository.feature"
|
||||
#line hidden
|
||||
|
||||
[NUnit.Framework.OneTimeSetUpAttribute()]
|
||||
public virtual void FeatureSetup()
|
||||
{
|
||||
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
|
||||
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "CredentialRepository", "\tAs a user with several environments\r\n\tI would like to load multiple credential r" +
|
||||
"epositories\r\n\tIn order to keep credentials separate", ProgrammingLanguage.CSharp, ((string[])(null)));
|
||||
testRunner.OnFeatureStart(featureInfo);
|
||||
}
|
||||
|
||||
[NUnit.Framework.OneTimeTearDownAttribute()]
|
||||
public virtual void FeatureTearDown()
|
||||
{
|
||||
testRunner.OnFeatureEnd();
|
||||
testRunner = null;
|
||||
}
|
||||
|
||||
[NUnit.Framework.SetUpAttribute()]
|
||||
public virtual void TestInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
[NUnit.Framework.TearDownAttribute()]
|
||||
public virtual void ScenarioTearDown()
|
||||
{
|
||||
testRunner.OnScenarioEnd();
|
||||
}
|
||||
|
||||
public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
|
||||
{
|
||||
testRunner.OnScenarioStart(scenarioInfo);
|
||||
}
|
||||
|
||||
public virtual void ScenarioCleanup()
|
||||
{
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Load credential repository")]
|
||||
[NUnit.Framework.CategoryAttribute("credentials")]
|
||||
[Ignore("Cred Repo not implmented currently.")]
|
||||
public virtual void LoadCredentialRepository()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Load credential repository", new string[] {
|
||||
"credentials"});
|
||||
#line 7
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 8
|
||||
testRunner.Given("I have a credential repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 9
|
||||
testRunner.And("the credential repository is unloaded", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 10
|
||||
testRunner.When("I click load", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 11
|
||||
testRunner.Then("the credential repository is loaded", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Add credential record")]
|
||||
[Ignore("Cred Repo not implmented currently.")]
|
||||
public virtual void AddCredentialRecord()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add credential record", ((string[])(null)));
|
||||
#line 13
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 14
|
||||
testRunner.Given("I have a credential repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 15
|
||||
testRunner.And("The credential repository is loaded", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 16
|
||||
testRunner.And("The repository has 0 credentials", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 17
|
||||
testRunner.When("I click add credential", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 18
|
||||
testRunner.Then("the repository has 1 credentials", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Unload credential repository")]
|
||||
[Ignore("Cred Repo not implmented currently.")]
|
||||
public virtual void UnloadCredentialRepository()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Unload credential repository", ((string[])(null)));
|
||||
#line 20
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 21
|
||||
testRunner.Given("I have a credential repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 22
|
||||
testRunner.And("The credential repository is loaded", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 23
|
||||
testRunner.And("The repository has 1 credentials", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 24
|
||||
testRunner.When("I click unload", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 25
|
||||
testRunner.Then("the credentials in the repository will no longer be available", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endregion
|
||||
17
mRemoteNG.Specs/Features/CredentialRepositoryList.feature
Normal file
17
mRemoteNG.Specs/Features/CredentialRepositoryList.feature
Normal file
@@ -0,0 +1,17 @@
|
||||
Feature: CredentialRepositoryList
|
||||
As a user with several environments
|
||||
I would like to load multiple credential repositories
|
||||
In order to keep credentials separate
|
||||
|
||||
@credentials
|
||||
Scenario: Add a new credential repository
|
||||
Given I have a credential repository list
|
||||
And It has 0 repositories set up
|
||||
When I press add and complete the creation wizard
|
||||
Then I will have 1 credential repository
|
||||
|
||||
Scenario: Remove a credential repository
|
||||
Given I have a credential repository list
|
||||
And It has 2 repositories set up
|
||||
When I remove the first repository
|
||||
Then I will have 1 credential repository
|
||||
115
mRemoteNG.Specs/Features/CredentialRepositoryList.feature.cs
generated
Normal file
115
mRemoteNG.Specs/Features/CredentialRepositoryList.feature.cs
generated
Normal file
@@ -0,0 +1,115 @@
|
||||
// ------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by SpecFlow (http://www.specflow.org/).
|
||||
// SpecFlow Version:2.2.0.0
|
||||
// SpecFlow Generator Version:2.2.0.0
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
// ------------------------------------------------------------------------------
|
||||
#region Designer generated code
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
#pragma warning disable
|
||||
namespace mRemoteNG.Specs.Features
|
||||
{
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "2.2.0.0")]
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[NUnit.Framework.TestFixtureAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("CredentialRepositoryList")]
|
||||
[Ignore("Cred Repo not implmented currently.")]
|
||||
public partial class CredentialRepositoryListFeature
|
||||
{
|
||||
|
||||
private TechTalk.SpecFlow.ITestRunner testRunner;
|
||||
|
||||
#line 1 "CredentialRepositoryList.feature"
|
||||
#line hidden
|
||||
|
||||
[NUnit.Framework.OneTimeSetUpAttribute()]
|
||||
public virtual void FeatureSetup()
|
||||
{
|
||||
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
|
||||
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "CredentialRepositoryList", "\tAs a user with several environments\r\n\tI would like to load multiple credential r" +
|
||||
"epositories\r\n\tIn order to keep credentials separate", ProgrammingLanguage.CSharp, ((string[])(null)));
|
||||
testRunner.OnFeatureStart(featureInfo);
|
||||
}
|
||||
|
||||
[NUnit.Framework.OneTimeTearDownAttribute()]
|
||||
public virtual void FeatureTearDown()
|
||||
{
|
||||
testRunner.OnFeatureEnd();
|
||||
testRunner = null;
|
||||
}
|
||||
|
||||
[NUnit.Framework.SetUpAttribute()]
|
||||
public virtual void TestInitialize()
|
||||
{
|
||||
}
|
||||
|
||||
[NUnit.Framework.TearDownAttribute()]
|
||||
public virtual void ScenarioTearDown()
|
||||
{
|
||||
testRunner.OnScenarioEnd();
|
||||
}
|
||||
|
||||
public virtual void ScenarioSetup(TechTalk.SpecFlow.ScenarioInfo scenarioInfo)
|
||||
{
|
||||
testRunner.OnScenarioStart(scenarioInfo);
|
||||
}
|
||||
|
||||
public virtual void ScenarioCleanup()
|
||||
{
|
||||
testRunner.CollectScenarioErrors();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Add a new credential repository")]
|
||||
[NUnit.Framework.CategoryAttribute("credentials")]
|
||||
[Ignore("Cred Repo not implmented currently.")]
|
||||
public virtual void AddANewCredentialRepository()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Add a new credential repository", new string[] {
|
||||
"credentials"});
|
||||
#line 7
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 8
|
||||
testRunner.Given("I have a credential repository list", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 9
|
||||
testRunner.And("It has 0 repositories set up", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 10
|
||||
testRunner.When("I press add and complete the creation wizard", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 11
|
||||
testRunner.Then("I will have 1 credential repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
|
||||
[NUnit.Framework.TestAttribute()]
|
||||
[NUnit.Framework.DescriptionAttribute("Remove a credential repository")]
|
||||
[Ignore("Cred Repo not implmented currently.")]
|
||||
public virtual void RemoveACredentialRepository()
|
||||
{
|
||||
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Remove a credential repository", ((string[])(null)));
|
||||
#line 13
|
||||
this.ScenarioSetup(scenarioInfo);
|
||||
#line 14
|
||||
testRunner.Given("I have a credential repository list", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given ");
|
||||
#line 15
|
||||
testRunner.And("It has 2 repositories set up", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And ");
|
||||
#line 16
|
||||
testRunner.When("I remove the first repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When ");
|
||||
#line 17
|
||||
testRunner.Then("I will have 1 credential repository", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then ");
|
||||
#line hidden
|
||||
this.ScenarioCleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endregion
|
||||
36
mRemoteNG.Specs/Properties/AssemblyInfo.cs
Normal file
36
mRemoteNG.Specs/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("mRemoteNG.Specs")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("mRemoteNG.Specs")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("16aa21e2-d6b7-427d-ab7d-aa8c611b724e")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Linq;
|
||||
using mRemoteNG.Credential.Repositories;
|
||||
using mRemoteNG.Specs.Utilities;
|
||||
using NUnit.Framework;
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
namespace mRemoteNG.Specs.StepDefinitions
|
||||
{
|
||||
[Binding]
|
||||
public class CredentialRepositoryListSteps
|
||||
{
|
||||
private CredentialRepositoryList _credentialRepositoryList;
|
||||
private readonly XmlCredentialRepoBuilder _credentialRepoUtilities = new XmlCredentialRepoBuilder();
|
||||
|
||||
[Given(@"I have a credential repository list")]
|
||||
public void GivenIHaveACredentialRepositoryList()
|
||||
{
|
||||
_credentialRepositoryList = new CredentialRepositoryList();
|
||||
}
|
||||
|
||||
[Given(@"It has (.*) repositories set up")]
|
||||
public void GivenItHasRepositoriesSetUp(int numberOfCredentialRepos)
|
||||
{
|
||||
for (var i = 0; i < numberOfCredentialRepos; i++)
|
||||
_credentialRepositoryList.AddProvider(_credentialRepoUtilities.BuildXmlCredentialRepo());
|
||||
}
|
||||
|
||||
[When(@"I press add and complete the creation wizard")]
|
||||
public void WhenIPressAddAndCompleteTheCreationWizard()
|
||||
{
|
||||
var credentialRepo = _credentialRepoUtilities.BuildXmlCredentialRepo();
|
||||
_credentialRepositoryList.AddProvider(credentialRepo);
|
||||
}
|
||||
|
||||
[When(@"I remove the first repository")]
|
||||
public void WhenIRemoveTheFirstRepository()
|
||||
{
|
||||
var firstRepo = _credentialRepositoryList.CredentialProviders.First();
|
||||
_credentialRepositoryList.RemoveProvider(firstRepo);
|
||||
}
|
||||
|
||||
[Then(@"I will have (.*) credential repository")]
|
||||
public void ThenIWillHaveCredentialRepository(int expectedCredRepoCount)
|
||||
{
|
||||
Assert.That(_credentialRepositoryList.CredentialProviders.Count(), Is.EqualTo(expectedCredRepoCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
80
mRemoteNG.Specs/StepDefinitions/CredentialRepositorySteps.cs
Normal file
80
mRemoteNG.Specs/StepDefinitions/CredentialRepositorySteps.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Security;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Specs.Utilities;
|
||||
using NUnit.Framework;
|
||||
using TechTalk.SpecFlow;
|
||||
|
||||
namespace mRemoteNG.Specs.StepDefinitions
|
||||
{
|
||||
[Binding]
|
||||
public class CredentialRepositorySteps
|
||||
{
|
||||
private ICredentialRepository _credentialRepository;
|
||||
private readonly SecureString _key = "somePassword".ConvertToSecureString();
|
||||
|
||||
[Given(@"I have a credential repository")]
|
||||
public void GivenIHaveACredentialRepository()
|
||||
{
|
||||
var utilityFactory = new XmlCredentialRepoBuilder {EncryptionKey = _key};
|
||||
_credentialRepository = utilityFactory.BuildXmlCredentialRepo();
|
||||
}
|
||||
|
||||
[Given(@"The repository has (.*) credentials")]
|
||||
public void GivenTheRepositoryHasCredentials(int numberOfCreds)
|
||||
{
|
||||
for (var i = 0; i < numberOfCreds; i++)
|
||||
_credentialRepository.CredentialRecords.Add(new CredentialRecord());
|
||||
Assert.That(_credentialRepository.CredentialRecords.Count, Is.EqualTo(numberOfCreds));
|
||||
}
|
||||
|
||||
[Given(@"The credential repository is loaded")]
|
||||
public void GivenTheCredentialRepositoryIsLoaded()
|
||||
{
|
||||
_credentialRepository.LoadCredentials(_key);
|
||||
Assert.That(_credentialRepository.IsLoaded);
|
||||
}
|
||||
|
||||
[Given(@"the credential repository is unloaded")]
|
||||
public void GivenTheCredentialRepositoryIsUnloaded()
|
||||
{
|
||||
Assert.That(_credentialRepository.IsLoaded, Is.False);
|
||||
}
|
||||
|
||||
[When(@"I click load")]
|
||||
public void WhenIClickLoad()
|
||||
{
|
||||
_credentialRepository.LoadCredentials(_key);
|
||||
}
|
||||
|
||||
[Then(@"the credential repository is loaded")]
|
||||
public void ThenTheCredentialRepositoryIsLoaded()
|
||||
{
|
||||
Assert.That(_credentialRepository.IsLoaded);
|
||||
}
|
||||
|
||||
[When(@"I click add credential")]
|
||||
public void WhenIClickAddCredential()
|
||||
{
|
||||
_credentialRepository.CredentialRecords.Add(new CredentialRecord());
|
||||
}
|
||||
|
||||
[Then(@"the repository has (.*) credentials")]
|
||||
public void ThenTheRepositoryHasCredentials(int numberOfCreds)
|
||||
{
|
||||
Assert.That(_credentialRepository.CredentialRecords.Count, Is.EqualTo(numberOfCreds));
|
||||
}
|
||||
|
||||
[When(@"I click unload")]
|
||||
public void WhenIClickUnload()
|
||||
{
|
||||
_credentialRepository.UnloadCredentials();
|
||||
}
|
||||
|
||||
[Then(@"the credentials in the repository will no longer be available")]
|
||||
public void ThenTheCredentialsInTheRepositoryWillNoLongerBeAvailable()
|
||||
{
|
||||
Assert.That(_credentialRepository.CredentialRecords, Is.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
mRemoteNG.Specs/Utilities/CredRepoXmlFileBuilder.cs
Normal file
12
mRemoteNG.Specs/Utilities/CredRepoXmlFileBuilder.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace mRemoteNG.Specs.Utilities
|
||||
{
|
||||
public class CredRepoXmlFileBuilder
|
||||
{
|
||||
public string Build(string authHeader)
|
||||
{
|
||||
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
$"<Credentials EncryptionEngine=\"AES\" BlockCipherMode=\"GCM\" KdfIterations=\"1000\" Auth=\"{authHeader}\" SchemaVersion=\"1.0\">" +
|
||||
"</Credentials>";
|
||||
}
|
||||
}
|
||||
}
|
||||
42
mRemoteNG.Specs/Utilities/XmlCredentialRepoBuilder.cs
Normal file
42
mRemoteNG.Specs/Utilities/XmlCredentialRepoBuilder.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Security;
|
||||
using mRemoteNG.Config;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Credential.Repositories;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
|
||||
namespace mRemoteNG.Specs.Utilities
|
||||
{
|
||||
public class XmlCredentialRepoBuilder
|
||||
{
|
||||
public SecureString EncryptionKey { get; set; } = "someKey1".ConvertToSecureString();
|
||||
public ICryptographyProvider CryptographyProvider { get; set; } = new AeadCryptographyProvider();
|
||||
|
||||
public ICredentialRepository BuildXmlCredentialRepo()
|
||||
{
|
||||
var xmlFileBuilder = new CredRepoXmlFileBuilder();
|
||||
var xmlFileContent = xmlFileBuilder.Build(CryptographyProvider.Encrypt("someheaderdata", EncryptionKey));
|
||||
var dataProvider = new InMemoryStringDataProvider(xmlFileContent);
|
||||
var encryptor = new XmlCredentialPasswordEncryptorDecorator(
|
||||
CryptographyProvider,
|
||||
new XmlCredentialRecordSerializer()
|
||||
);
|
||||
var decryptor = new XmlCredentialPasswordDecryptorDecorator(
|
||||
new XmlCredentialRecordDeserializer()
|
||||
);
|
||||
|
||||
return new XmlCredentialRepository(
|
||||
new CredentialRepositoryConfig(),
|
||||
new CredentialRecordSaver(
|
||||
dataProvider,
|
||||
encryptor
|
||||
), new CredentialRecordLoader(
|
||||
dataProvider,
|
||||
decryptor
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
99
mRemoteNG.Specs/mRemoteNG.Specs.csproj
Normal file
99
mRemoteNG.Specs/mRemoteNG.Specs.csproj
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>mRemoteNG.Specs</RootNamespace>
|
||||
<AssemblyName>mRemoteNG.Specs</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.9.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="TechTalk.SpecFlow, Version=2.2.0.0, Culture=neutral, PublicKeyToken=0778194805d6db41, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SpecFlow.2.2.1\lib\net45\TechTalk.SpecFlow.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Features\CredentialRepository.feature.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>CredentialRepository.feature</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Features\CredentialRepositoryList.feature.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>CredentialRepositoryList.feature</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="StepDefinitions\CredentialRepositoryListSteps.cs" />
|
||||
<Compile Include="StepDefinitions\CredentialRepositorySteps.cs" />
|
||||
<Compile Include="Utilities\CredRepoXmlFileBuilder.cs" />
|
||||
<Compile Include="Utilities\XmlCredentialRepoBuilder.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="Features\CredentialRepository.feature">
|
||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||
<LastGenOutput>CredentialRepository.feature.cs</LastGenOutput>
|
||||
</None>
|
||||
<None Include="Features\CredentialRepositoryList.feature">
|
||||
<Generator>SpecFlowSingleFileGenerator</Generator>
|
||||
<LastGenOutput>CredentialRepositoryList.feature.cs</LastGenOutput>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\mRemoteV1\mRemoteV1.csproj">
|
||||
<Project>{4934a491-40bc-4e5b-9166-ea1169a220f6}</Project>
|
||||
<Name>mRemoteV1</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
16
mRemoteNG.Specs/packages.config
Normal file
16
mRemoteNG.Specs/packages.config
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net46" />
|
||||
<package id="NUnit" version="3.9.0" targetFramework="net46" />
|
||||
<package id="NUnit.Console" version="3.7.0" targetFramework="net46" />
|
||||
<package id="NUnit.ConsoleRunner" version="3.7.0" targetFramework="net46" />
|
||||
<package id="NUnit.Extension.NUnitProjectLoader" version="3.6.0" targetFramework="net46" />
|
||||
<package id="NUnit.Extension.NUnitV2Driver" version="3.7.0" targetFramework="net46" />
|
||||
<package id="NUnit.Extension.NUnitV2ResultWriter" version="3.6.0" targetFramework="net46" />
|
||||
<package id="NUnit.Extension.TeamCityEventListener" version="1.0.3" targetFramework="net46" />
|
||||
<package id="NUnit.Extension.VSProjectLoader" version="3.7.0" targetFramework="net46" />
|
||||
<package id="NUnit.Runners" version="3.7.0" targetFramework="net46" />
|
||||
<package id="SpecFlow" version="2.2.1" targetFramework="net46" />
|
||||
<package id="SpecFlow.NUnit" version="2.2.1" targetFramework="net46" />
|
||||
<package id="SpecFlow.NUnit.Runners" version="2.2.1" targetFramework="net46" />
|
||||
</packages>
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using mRemoteNG.App;
|
||||
using log4net;
|
||||
|
||||
namespace mRemoteNGTests.App
|
||||
{
|
||||
[TestFixture]
|
||||
public class LoggerTests
|
||||
{
|
||||
[Test]
|
||||
public void GetSingletonInstanceReturnsAnILogObject()
|
||||
{
|
||||
Assert.That(Logger.Instance, Is.InstanceOf<ILog>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SingletonOnlyEverReturnsTheSameInstance()
|
||||
{
|
||||
ILog log1 = Logger.Instance;
|
||||
ILog log2 = Logger.Instance;
|
||||
Assert.That(log1, Is.EqualTo(log2));
|
||||
}
|
||||
}
|
||||
}
|
||||
84
mRemoteNGTests/App/UpdaterTests.cs
Normal file
84
mRemoteNGTests/App/UpdaterTests.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.App.Update;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.App
|
||||
{
|
||||
[TestFixture]
|
||||
public class UpdaterTests
|
||||
{
|
||||
[Test]
|
||||
public void UpdateStableChannel()
|
||||
{
|
||||
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
|
||||
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update);
|
||||
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
|
||||
Version v;
|
||||
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
|
||||
var IsNewer = CurrentUpdateInfo.Version > v;
|
||||
Assert.That(IsNewer, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateBetaChannel()
|
||||
{
|
||||
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
|
||||
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update);
|
||||
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
|
||||
Version v;
|
||||
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
|
||||
var IsNewer = CurrentUpdateInfo.Version > v;
|
||||
Assert.That(IsNewer, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateDevChannel()
|
||||
{
|
||||
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
|
||||
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update);
|
||||
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
|
||||
Version v;
|
||||
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
|
||||
var IsNewer = CurrentUpdateInfo.Version > v;
|
||||
Assert.That(IsNewer, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateStablePortableChannel()
|
||||
{
|
||||
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
|
||||
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update_portable);
|
||||
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
|
||||
Version v;
|
||||
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
|
||||
var IsNewer = CurrentUpdateInfo.Version > v;
|
||||
Assert.That(IsNewer, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateBetaPortableChannel()
|
||||
{
|
||||
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
|
||||
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update_portable);
|
||||
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
|
||||
Version v;
|
||||
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
|
||||
var IsNewer = CurrentUpdateInfo.Version > v;
|
||||
Assert.That(IsNewer, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateDevPortableChannel()
|
||||
{
|
||||
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
|
||||
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update_portable);
|
||||
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
|
||||
Version v;
|
||||
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
|
||||
var IsNewer = CurrentUpdateInfo.Version > v;
|
||||
Assert.That(IsNewer, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using NUnit.Framework;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace mRemoteNGTests
|
||||
{
|
||||
@@ -13,41 +14,42 @@ namespace mRemoteNGTests
|
||||
Assert.That(IsLargeAware(exePath), Is.True);
|
||||
}
|
||||
|
||||
static string GetTargetPath([System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "")
|
||||
public string GetTargetPath([CallerFilePath] string sourceFilePath = "")
|
||||
{
|
||||
string debugOrRelease = "";
|
||||
string normalOrPortable = "";
|
||||
const string debugOrRelease =
|
||||
#if DEBUG
|
||||
debugOrRelease = "Debug";
|
||||
"Debug";
|
||||
#else
|
||||
debugOrRelease = "Release";
|
||||
"Release";
|
||||
#endif
|
||||
|
||||
const string normalOrPortable =
|
||||
#if PORTABLE
|
||||
normalOrPortable = " Portable";
|
||||
" Portable";
|
||||
#else
|
||||
normalOrPortable = "";
|
||||
"";
|
||||
#endif
|
||||
var path = Path.GetDirectoryName(sourceFilePath);
|
||||
string FilePath = $"{path}\\..\\mRemoteV1\\bin\\{debugOrRelease}{normalOrPortable}\\mRemoteNG.exe";
|
||||
return FilePath;
|
||||
var filePath = $"{path}\\..\\mRemoteV1\\bin\\{debugOrRelease}{normalOrPortable}\\mRemoteNG.exe";
|
||||
return filePath;
|
||||
}
|
||||
|
||||
static bool IsLargeAware(string file)
|
||||
private bool IsLargeAware(string file)
|
||||
{
|
||||
using (var fs = File.OpenRead(file))
|
||||
{
|
||||
return IsLargeAware(fs);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the stream is a MZ header and if it is large address aware
|
||||
/// </summary>
|
||||
/// <param name="stream">Stream to check, make sure its at the start of the MZ header</param>
|
||||
/// <exception cref=""></exception>
|
||||
/// <returns></returns>
|
||||
static bool IsLargeAware(Stream stream)
|
||||
private bool IsLargeAware(Stream stream)
|
||||
{
|
||||
const int IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x20;
|
||||
const int imageFileLargeAddressAware = 0x20;
|
||||
|
||||
var br = new BinaryReader(stream);
|
||||
|
||||
@@ -55,14 +57,14 @@ namespace mRemoteNGTests
|
||||
return false;
|
||||
|
||||
br.BaseStream.Position = 0x3C;
|
||||
var peloc = br.ReadInt32(); //Get the PE header location.
|
||||
var peHeaderLocation = br.ReadInt32(); //Get the PE header location.
|
||||
|
||||
br.BaseStream.Position = peloc;
|
||||
br.BaseStream.Position = peHeaderLocation;
|
||||
if (br.ReadInt32() != 0x4550) //No PE header
|
||||
return false;
|
||||
|
||||
br.BaseStream.Position += 0x12;
|
||||
return (br.ReadInt16() & IMAGE_FILE_LARGE_ADDRESS_AWARE) == IMAGE_FILE_LARGE_ADDRESS_AWARE;
|
||||
return (br.ReadInt16() & imageFileLargeAddressAware) == imageFileLargeAddressAware;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
// ReSharper disable ObjectCreationAsStatement
|
||||
|
||||
namespace mRemoteNGTests.Config.Connections.Multiuser
|
||||
{
|
||||
public class ConnectionsUpdateAvailableEventArgsTests
|
||||
{
|
||||
private IDatabaseConnector _databaseConnector;
|
||||
private DateTime _dateTime;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_databaseConnector = Substitute.For<IDatabaseConnector>();
|
||||
_dateTime = DateTime.MinValue;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullDatabaseConnectorToCtor()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new ConnectionsUpdateAvailableEventArgs(null, _dateTime));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DatabaseConnectorPropertySet()
|
||||
{
|
||||
var eventArgs = new ConnectionsUpdateAvailableEventArgs(_databaseConnector, _dateTime);
|
||||
Assert.That(eventArgs.DatabaseConnector, Is.EqualTo(_databaseConnector));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateTimePropertySet()
|
||||
{
|
||||
var eventArgs = new ConnectionsUpdateAvailableEventArgs(_databaseConnector, _dateTime);
|
||||
Assert.That(eventArgs.UpdateTime, Is.EqualTo(_dateTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mRemoteNGTests.Config.Connections
|
||||
{
|
||||
class XmlConnectionsLoaderTests
|
||||
{
|
||||
[Test]
|
||||
public void ThrowsFileNotFound()
|
||||
{
|
||||
Assert.Throws<FileNotFoundException>(() => (new XmlConnectionsLoader(FileTestHelpers.NewTempFilePath())).Load());
|
||||
}
|
||||
}
|
||||
}
|
||||
131
mRemoteNGTests/Config/CredentialHarvesterTests.cs
Normal file
131
mRemoteNGTests/Config/CredentialHarvesterTests.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config
|
||||
{
|
||||
#pragma warning disable 618
|
||||
public class CredentialHarvesterTests
|
||||
{
|
||||
|
||||
private CredentialHarvester _credentialHarvester;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
private SecureString _key;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialHarvester = new CredentialHarvester();
|
||||
_cryptographyProvider = new CryptoProviderFactory(BlockCipherEngines.AES, BlockCipherModes.GCM).Build();
|
||||
_key = "testKey123".ConvertToSecureString();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HarvestsUsername()
|
||||
{
|
||||
var connection = new ConnectionInfo { Username = "myuser", Domain = "somedomain", Password = "mypass" };
|
||||
var xdoc = CreateTestData(connection);
|
||||
var credentials = _credentialHarvester.Harvest(xdoc, _key);
|
||||
Assert.That(credentials.Single().Username, Is.EqualTo(connection.Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HarvestsDomain()
|
||||
{
|
||||
var connection = new ConnectionInfo { Username = "myuser", Domain = "somedomain", Password = "mypass" };
|
||||
var xdoc = CreateTestData(connection);
|
||||
var credentials = _credentialHarvester.Harvest(xdoc, _key);
|
||||
Assert.That(credentials.Single().Domain, Is.EqualTo(connection.Domain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HarvestsPassword()
|
||||
{
|
||||
var connection = new ConnectionInfo { Username = "myuser", Domain = "somedomain", Password = "mypass" };
|
||||
var xdoc = CreateTestData(connection);
|
||||
var credentials = _credentialHarvester.Harvest(xdoc, _key);
|
||||
Assert.That(credentials.Single().Password.ConvertToUnsecureString(), Is.EqualTo(connection.Password));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotHarvestEmptyCredentials()
|
||||
{
|
||||
var connection = new ConnectionInfo();
|
||||
var xdoc = CreateTestData(connection);
|
||||
var credentials = _credentialHarvester.Harvest(xdoc, _key);
|
||||
Assert.That(credentials.Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HarvestsAllCredentials()
|
||||
{
|
||||
var container = new ContainerInfo();
|
||||
var con1 = new ConnectionInfo {Username = "blah"};
|
||||
var con2 = new ConnectionInfo {Username = "something"};
|
||||
container.AddChildRange(new [] {con1, con2});
|
||||
var xdoc = CreateTestData(container);
|
||||
var credentials = _credentialHarvester.Harvest(xdoc, _key);
|
||||
Assert.That(credentials.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OnlyReturnsUniqueCredentials()
|
||||
{
|
||||
var container = new ContainerInfo();
|
||||
var con1 = new ConnectionInfo { Username = "something" };
|
||||
var con2 = new ConnectionInfo { Username = "something" };
|
||||
container.AddChildRange(new[] { con1, con2 });
|
||||
var xdoc = CreateTestData(container);
|
||||
var credentials = _credentialHarvester.Harvest(xdoc, _key);
|
||||
Assert.That(credentials.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CredentialMapCorrectForSingleCredential()
|
||||
{
|
||||
var connection = new ConnectionInfo { Username = "myuser", Domain = "somedomain", Password = "mypass" };
|
||||
var connectionGuid = Guid.Parse(connection.ConstantID);
|
||||
var xdoc = CreateTestData(connection);
|
||||
_credentialHarvester.Harvest(xdoc, _key);
|
||||
var map = _credentialHarvester.ConnectionToCredentialMap;
|
||||
Assert.That(map[connectionGuid].Username, Is.EqualTo(connection.Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CredentialMapDoesntContainDuplicateCredentialObjects()
|
||||
{
|
||||
var container = new ContainerInfo();
|
||||
var con1 = new ConnectionInfo { Username = "something" };
|
||||
var con2 = new ConnectionInfo { Username = "something" };
|
||||
container.AddChildRange(new[] { con1, con2 });
|
||||
var xdoc = CreateTestData(container);
|
||||
var con1Id = Guid.Parse(con1.ConstantID);
|
||||
var con2Id = Guid.Parse(con2.ConstantID);
|
||||
_credentialHarvester.Harvest(xdoc, _key);
|
||||
var map = _credentialHarvester.ConnectionToCredentialMap;
|
||||
Assert.That(map[con1Id], Is.EqualTo(map[con2Id]));
|
||||
}
|
||||
|
||||
|
||||
private XDocument CreateTestData(ConnectionInfo connectionInfo)
|
||||
{
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection) {PasswordString = _key.ConvertToUnsecureString()};
|
||||
rootNode.AddChild(connectionInfo);
|
||||
var nodeSerializer = new XmlConnectionNodeSerializer26(_cryptographyProvider, _key, new SaveFilter());
|
||||
var serializer = new XmlConnectionsSerializer(_cryptographyProvider, nodeSerializer);
|
||||
var serializedData = serializer.Serialize(rootNode);
|
||||
return XDocument.Parse(serializedData);
|
||||
}
|
||||
}
|
||||
#pragma warning restore 618
|
||||
}
|
||||
42
mRemoteNGTests/Config/CredentialRecordLoaderTests.cs
Normal file
42
mRemoteNGTests/Config/CredentialRecordLoaderTests.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config
|
||||
{
|
||||
public class CredentialRecordLoaderTests
|
||||
{
|
||||
private CredentialRecordLoader _credentialRecordLoader;
|
||||
private IDataProvider<string> _dataProvider;
|
||||
private ISecureDeserializer<string, IEnumerable<ICredentialRecord>> _deserializer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_dataProvider = Substitute.For<IDataProvider<string>>();
|
||||
_deserializer = Substitute.For<ISecureDeserializer<string, IEnumerable<ICredentialRecord>>>();
|
||||
_credentialRecordLoader = new CredentialRecordLoader(_dataProvider, _deserializer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadsFromDataProvider()
|
||||
{
|
||||
_credentialRecordLoader.Load(new SecureString());
|
||||
_dataProvider.Received(1).Load();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializesDataFromDataProvider()
|
||||
{
|
||||
var key = new SecureString();
|
||||
_dataProvider.Load().Returns("mydata");
|
||||
_credentialRecordLoader.Load(key);
|
||||
_deserializer.Received(1).Deserialize("mydata", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.IO;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.DataProviders
|
||||
{
|
||||
public class FileBackupCreatorTests
|
||||
{
|
||||
private FileBackupCreator _fileBackupCreator;
|
||||
private string _testFilePath;
|
||||
private string _testFilePathBackup;
|
||||
private string _testFileDirectory;
|
||||
private string _testFileRollingBackup;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_testFilePath = FileTestHelpers.NewTempFilePath();
|
||||
_testFileDirectory = Path.GetDirectoryName(_testFilePath);
|
||||
_testFileRollingBackup = Path.GetFileName(_testFilePath) + ".*-*.backup";
|
||||
_testFilePathBackup = _testFilePath + ".backup";
|
||||
_fileBackupCreator = new FileBackupCreator();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (Directory.Exists(_testFileDirectory))
|
||||
Directory.Delete(_testFileDirectory, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BackupCreatedWhenFileAlreadyExists()
|
||||
{
|
||||
File.WriteAllText(_testFilePath, "");
|
||||
_fileBackupCreator.CreateBackupFile(_testFilePath);
|
||||
var rollingBackupFiles = Directory.GetFiles(_testFileDirectory, _testFileRollingBackup);
|
||||
Assert.That(rollingBackupFiles.Length, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BackupNotCreatedIfFileDidntAlreadyExist()
|
||||
{
|
||||
_fileBackupCreator.CreateBackupFile(_testFilePath);
|
||||
var backupFileExists = File.Exists(_testFilePathBackup);
|
||||
Assert.That(backupFileExists, Is.False);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
mRemoteNGTests/Config/DataProviders/FileDataProviderTests.cs
Normal file
60
mRemoteNGTests/Config/DataProviders/FileDataProviderTests.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.DataProviders
|
||||
{
|
||||
public class FileDataProviderTests
|
||||
{
|
||||
private FileDataProvider _dataProvider;
|
||||
private string _testFilePath;
|
||||
private string _testFileDirectory;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_testFilePath = FileTestHelpers.NewTempFilePath();
|
||||
_testFileDirectory = Path.GetDirectoryName(_testFilePath);
|
||||
_dataProvider = new FileDataProvider(_testFilePath);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (Directory.Exists(_testFileDirectory))
|
||||
Directory.Delete(_testFileDirectory, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SetsFileContent()
|
||||
{
|
||||
Assert.That(File.Exists(_testFilePath), Is.False);
|
||||
var expectedFileContent = Guid.NewGuid().ToString();
|
||||
_dataProvider.Save(expectedFileContent);
|
||||
var fileContent = File.ReadAllText(_testFilePath);
|
||||
Assert.That(fileContent, Is.EqualTo(expectedFileContent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadingFileThatDoesntExistProvidesEmptyString()
|
||||
{
|
||||
var fileThatShouldntExist = Guid.NewGuid().ToString();
|
||||
var dataProvider = new FileDataProvider(fileThatShouldntExist);
|
||||
var loadedData = dataProvider.Load();
|
||||
Assert.That(loadedData, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveCreatesDirectoriesThatDontExist()
|
||||
{
|
||||
var folder1 = Guid.NewGuid().ToString();
|
||||
var folder2 = Guid.NewGuid().ToString();
|
||||
var fileThatShouldExist = Path.Combine(_testFileDirectory, folder1, folder2, Path.GetRandomFileName());
|
||||
_dataProvider.FilePath = fileThatShouldExist;
|
||||
_dataProvider.Save("");
|
||||
Assert.That(File.Exists(fileThatShouldExist), Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.DataProviders
|
||||
{
|
||||
public class FileDataProviderWithRollingBackupTests
|
||||
{
|
||||
private FileDataProviderWithRollingBackup _dataProvider;
|
||||
private string _testFilePath;
|
||||
private string _testFileDirectory;
|
||||
private string _testFileRollingBackup;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_testFilePath = FileTestHelpers.NewTempFilePath();
|
||||
_testFileDirectory = Path.GetDirectoryName(_testFilePath);
|
||||
_testFileRollingBackup = Path.GetFileName(_testFilePath) + ".*-*.backup";
|
||||
_dataProvider = new FileDataProviderWithRollingBackup(_testFilePath);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
if (Directory.Exists(_testFileDirectory))
|
||||
Directory.Delete(_testFileDirectory, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RollingBackupCreatedIfRegularBackupExists()
|
||||
{
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
_dataProvider.Save("");
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
||||
var rollingBackupFiles = Directory.GetFiles(_testFileDirectory, _testFileRollingBackup);
|
||||
Assert.That(rollingBackupFiles.Length, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NoRollingBackupCreatedIfRegularFileDoesntExists()
|
||||
{
|
||||
_dataProvider.Save("");
|
||||
var rollingBackupFiles = Directory.GetFiles(_testFileDirectory, _testFileRollingBackup);
|
||||
Assert.That(rollingBackupFiles.Length, Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
public class ConfConsEnsureConnectionsHaveIdsTests
|
||||
{
|
||||
private ConfConsEnsureConnectionsHaveIds _consEnsureConnectionsHaveIds;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_consEnsureConnectionsHaveIds = new ConfConsEnsureConnectionsHaveIds();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IdAttributeIsAddedIfItDidntExist()
|
||||
{
|
||||
var xdoc = CreateTestDocument();
|
||||
_consEnsureConnectionsHaveIds.EnsureElementsHaveIds(xdoc);
|
||||
var attribute = xdoc.Root?.Element("Node")?.Attribute("Id");
|
||||
Assert.That(attribute, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NewIdAttributeShouldNotBeAnEmptyGuid()
|
||||
{
|
||||
var xdoc = CreateTestDocument();
|
||||
_consEnsureConnectionsHaveIds.EnsureElementsHaveIds(xdoc);
|
||||
var attribute = xdoc.Root?.Element("Node")?.Attribute("Id");
|
||||
Assert.That(attribute?.Value, Is.Not.EqualTo(Guid.Empty.ToString()));
|
||||
}
|
||||
|
||||
private XDocument CreateTestDocument()
|
||||
{
|
||||
var xdoc = new XDocument();
|
||||
xdoc.Add(new XElement("Root",
|
||||
new XElement("Node",
|
||||
new XAttribute("Thingy",""))));
|
||||
return xdoc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers
|
||||
{
|
||||
public class XmlConnectionsDeserializerTests
|
||||
{
|
||||
@@ -18,8 +18,8 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
|
||||
public void Setup(string confCons, string password)
|
||||
{
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(confCons, password.ConvertToSecureString);
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize();
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(password.ConvertToSecureString);
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -1,16 +1,17 @@
|
||||
using System.Xml.XPath;
|
||||
using System.Linq;
|
||||
using System.Xml.XPath;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers
|
||||
{
|
||||
public class XmlConnectionsDocumentCompilerTests
|
||||
public class XmlConnectionsDocumentCompilerTests
|
||||
{
|
||||
private XmlConnectionsDocumentCompiler _documentCompiler;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
@@ -27,22 +28,26 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider);
|
||||
_connectionTreeModel = SetupConnectionTreeModel();
|
||||
_cryptographyProvider = new CryptoProviderFactory(BlockCipherEngines.AES, BlockCipherModes.GCM).Build();
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
_cryptographyProvider,
|
||||
_connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider, connectionNodeSerializer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XDocumentHasXmlDeclaration()
|
||||
{
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, false, false);
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, false);
|
||||
Assert.That(xdoc.Declaration, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DocumentHasRootConnectionElement()
|
||||
{
|
||||
var xdoc =_documentCompiler.CompileDocument(_connectionTreeModel, false, false);
|
||||
var xdoc =_documentCompiler.CompileDocument(_connectionTreeModel, false);
|
||||
var rootElementName = xdoc.Root?.Name.LocalName;
|
||||
Assert.That(rootElementName, Is.EqualTo("Connections"));
|
||||
}
|
||||
@@ -50,7 +55,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[Test]
|
||||
public void ConnectionNodesSerializedRecursively()
|
||||
{
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, false, false);
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, false);
|
||||
var con4 = xdoc.Root?.XPathSelectElement("Node[@Name='folder2']/Node[@Name='folder3']/Node[@Name='con4']");
|
||||
Assert.That(con4, Is.Not.Null);
|
||||
}
|
||||
@@ -58,7 +63,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[Test]
|
||||
public void XmlContentEncryptedWhenFullFileEncryptionTurnedOn()
|
||||
{
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, true, false);
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, true);
|
||||
var rootElementValue = xdoc.Root?.Value;
|
||||
Assert.That(rootElementValue, Is.Not.EqualTo(string.Empty));
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers
|
||||
{
|
||||
public class XmlConnectionsDocumentEncryptorTests
|
||||
public class XmlConnectionsDocumentEncryptorTests
|
||||
{
|
||||
private XmlConnectionsDocumentEncryptor _documentEncryptor;
|
||||
private XDocument _originalDocument;
|
||||
@@ -19,8 +20,12 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
var connectionTreeModel = SetupConnectionTreeModel();
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider).CompileDocument(connectionTreeModel, false, false);
|
||||
var cryptoProvider = new CryptoProviderFactory(BlockCipherEngines.AES, BlockCipherModes.GCM).Build();
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
cryptoProvider,
|
||||
connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider, connectionNodeSerializer).CompileDocument(connectionTreeModel, false);
|
||||
_documentEncryptor = new XmlConnectionsDocumentEncryptor(cryptoProvider);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
using System.Xml;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers
|
||||
{
|
||||
public class XmlConnectionsSerializerTests
|
||||
public class XmlConnectionsSerializerTests
|
||||
{
|
||||
private XmlConnectionsSerializer _serializer;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var encryptor = new AeadCryptographyProvider();
|
||||
_serializer = new XmlConnectionsSerializer(encryptor);
|
||||
_connectionTreeModel = SetupConnectionTreeModel();
|
||||
_cryptographyProvider = new AeadCryptographyProvider();
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
_cryptographyProvider,
|
||||
_connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(_cryptographyProvider, connectionNodeSerializer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -45,6 +52,28 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(connectionNode, Is.Not.Null);
|
||||
}
|
||||
|
||||
[TestCase("Username", "")]
|
||||
[TestCase("Domain", "")]
|
||||
[TestCase("Password", "")]
|
||||
[TestCase("InheritAutomaticResize", "False")]
|
||||
public void SerializerRespectsSaveFilterSettings(string attributeName, string expectedValue)
|
||||
{
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
_cryptographyProvider,
|
||||
_connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter(true));
|
||||
var serializer = new XmlConnectionsSerializer(_cryptographyProvider, connectionNodeSerializer);
|
||||
var connectionInfo = new ConnectionInfo
|
||||
{
|
||||
Name = "myConnection",
|
||||
Inheritance = {AutomaticResize = true}
|
||||
};
|
||||
var serializedConnections = serializer.Serialize(connectionInfo);
|
||||
var xdoc = XDocument.Parse(serializedConnections);
|
||||
var attributeValue = xdoc.Root?.Element("Node")?.Attribute(attributeName)?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo(expectedValue));
|
||||
}
|
||||
|
||||
private ConnectionTreeModel SetupConnectionTreeModel()
|
||||
{
|
||||
/*
|
||||
@@ -3,12 +3,12 @@ using System.Collections;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers
|
||||
{
|
||||
public class XmlRootNodeSerializerTests
|
||||
{
|
||||
@@ -39,19 +39,10 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(attributeValue, Is.EqualTo("Connections"));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void ExportValueSerialized(bool export)
|
||||
{
|
||||
var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, _cryptographyProvider, export:export);
|
||||
var attributeValue = element.Attribute(XName.Get("Export"))?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo(export.ToString()));
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseSources), nameof(TestCaseSources.AllEngineAndModeCombos))]
|
||||
public void EncryptionEngineSerialized(BlockCipherEngines engine, BlockCipherModes mode)
|
||||
{
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(engine, mode);
|
||||
var cryptoProvider = new CryptoProviderFactory(engine, mode).Build();
|
||||
var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, cryptoProvider);
|
||||
var attributeValue = element.Attribute(XName.Get("EncryptionEngine"))?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo(engine.ToString()));
|
||||
@@ -60,7 +51,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[TestCaseSource(typeof(TestCaseSources), nameof(TestCaseSources.AllEngineAndModeCombos))]
|
||||
public void EncryptionModeSerialized(BlockCipherEngines engine, BlockCipherModes mode)
|
||||
{
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(engine, mode);
|
||||
var cryptoProvider = new CryptoProviderFactory(engine, mode).Build();
|
||||
var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, cryptoProvider);
|
||||
var attributeValue = element.Attribute(XName.Get("BlockCipherMode"))?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo(mode.ToString()));
|
||||
@@ -100,23 +91,13 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(attributeValuePlainText, Is.EqualTo(expectedPlainText));
|
||||
}
|
||||
|
||||
[TestCase("", "ThisIsNotProtected")]
|
||||
[TestCase("customPassword1", "ThisIsNotProtected")]
|
||||
public void EncryptWithDefaultPasswordWhenExporting(string customPassword, string expectedPlainText)
|
||||
{
|
||||
_rootNodeInfo.PasswordString = customPassword;
|
||||
var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, _cryptographyProvider, export:true);
|
||||
var attributeValue = element.Attribute(XName.Get("Protected"))?.Value;
|
||||
var attributeValuePlainText = _cryptographyProvider.Decrypt(attributeValue, _rootNodeInfo.DefaultPassword.ConvertToSecureString());
|
||||
Assert.That(attributeValuePlainText, Is.EqualTo(expectedPlainText));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConfVersionSerialized()
|
||||
{
|
||||
var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, _cryptographyProvider);
|
||||
var attributeValue = element.Attribute(XName.Get("ConfVersion"))?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo("2.6"));
|
||||
var attributeValue = element.Attribute(XName.Get("ConfVersion"))?.Value ?? "";
|
||||
var versionAsNumber = double.Parse(attributeValue);
|
||||
Assert.That(versionAsNumber, Is.GreaterThan(0));
|
||||
}
|
||||
|
||||
private class TestCaseSources
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
public class CredentialProviderSerializerTests
|
||||
{
|
||||
private CredentialRepositoryListSerializer _credentialProviderSerializer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialProviderSerializer = new CredentialRepositoryListSerializer();
|
||||
}
|
||||
|
||||
private ICredentialRepository InitializeMockProvider()
|
||||
{
|
||||
var provider = Substitute.For<ICredentialRepository>();
|
||||
provider.Config.TypeName.Returns("ProviderName");
|
||||
provider.Config.Id.Returns(Guid.NewGuid());
|
||||
return provider;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeExists()
|
||||
{
|
||||
var mockProvider = InitializeMockProvider();
|
||||
var providers = new[] { mockProvider };
|
||||
var serializedContent = _credentialProviderSerializer.Serialize(providers);
|
||||
Assert.That(serializedContent, Is.Not.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.CredentialSerializers
|
||||
{
|
||||
public class XmlCredentialPasswordDecryptorDecoratorTests
|
||||
{
|
||||
private XmlCredentialPasswordDecryptorDecorator _sut;
|
||||
private readonly SecureString _decryptionKey = "myKey1".ConvertToSecureString();
|
||||
private string _unencryptedPassword = "myPassword1";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var baseDeserializer = new XmlCredentialRecordDeserializer();
|
||||
_sut = new XmlCredentialPasswordDecryptorDecorator(baseDeserializer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OutputedCredentialHasDecryptedPassword()
|
||||
{
|
||||
var xml = GenerateCredentialXml();
|
||||
var output = _sut.Deserialize(xml, _decryptionKey);
|
||||
Assert.That(output.First().Password.ConvertToUnsecureString(), Is.EqualTo(_unencryptedPassword));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DecryptionThrowsExceptionWhenAuthHeaderNotFound()
|
||||
{
|
||||
var xml = GenerateCredentialXml(false);
|
||||
Assert.Throws<EncryptionException>(() => _sut.Deserialize(xml, _decryptionKey));
|
||||
}
|
||||
|
||||
|
||||
private string GenerateCredentialXml(bool includeAuthHeader = true)
|
||||
{
|
||||
var cryptoProvider = new AeadCryptographyProvider();
|
||||
var authHeader = includeAuthHeader ? $"Auth=\"{cryptoProvider.Encrypt("someheader", _decryptionKey)}\"" : "";
|
||||
var encryptedPassword = cryptoProvider.Encrypt(_unencryptedPassword, _decryptionKey);
|
||||
return
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
$"<Credentials EncryptionEngine=\"{cryptoProvider.CipherEngine}\" BlockCipherMode=\"{cryptoProvider.CipherMode}\" KdfIterations=\"{cryptoProvider.KeyDerivationIterations}\" {authHeader} SchemaVersion=\"1.0\">" +
|
||||
$"<Credential Id=\"ce6b0397-d476-4ffe-884b-dbe9347a88a8\" Title=\"New Credential\" Username=\"asdfasdf\" Domain=\"\" Password=\"{encryptedPassword}\" />" +
|
||||
"</Credentials>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.CredentialSerializers
|
||||
{
|
||||
public class XmlCredentialPasswordEncryptorDecoratorTests
|
||||
{
|
||||
private XmlCredentialPasswordEncryptorDecorator _sut;
|
||||
private const BlockCipherEngines CipherEngine = BlockCipherEngines.Twofish;
|
||||
private const BlockCipherModes CipherMode = BlockCipherModes.EAX;
|
||||
private const int KdfIterations = 2000;
|
||||
private SecureString _key = "myKey1".ConvertToSecureString();
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = SetupCryptoProvider();
|
||||
var baseSerializer = SetupBaseSerializer();
|
||||
_sut = new XmlCredentialPasswordEncryptorDecorator(cryptoProvider, baseSerializer);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void CantPassNullCredentialList()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _sut.Serialize(null, new SecureString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EncryptsPasswordAttributesInXml()
|
||||
{
|
||||
var credList = Substitute.For<IEnumerable<ICredentialRecord>>();
|
||||
var output = _sut.Serialize(credList, _key);
|
||||
var outputAsXdoc = XDocument.Parse(output);
|
||||
var firstElementPassword = outputAsXdoc.Root?.Descendants().First().FirstAttribute.Value;
|
||||
Assert.That(firstElementPassword, Is.EqualTo("encrypted"));
|
||||
}
|
||||
|
||||
[TestCase("EncryptionEngine", CipherEngine)]
|
||||
[TestCase("BlockCipherMode", CipherMode)]
|
||||
[TestCase("KdfIterations", KdfIterations)]
|
||||
[TestCase("Auth", "encrypted")]
|
||||
public void SetsRootNodeEncryptionAttributes(string attributeName, object expectedValue)
|
||||
{
|
||||
var credList = Substitute.For<IEnumerable<ICredentialRecord>>();
|
||||
var output = _sut.Serialize(credList, _key);
|
||||
var outputAsXdoc = XDocument.Parse(output);
|
||||
var authField = outputAsXdoc.Root?.Attribute(attributeName)?.Value;
|
||||
Assert.That(authField, Is.EqualTo(expectedValue.ToString()));
|
||||
}
|
||||
|
||||
private ISerializer<IEnumerable<ICredentialRecord>, string> SetupBaseSerializer()
|
||||
{
|
||||
var baseSerializer = Substitute.For<ISerializer<IEnumerable<ICredentialRecord>, string>>();
|
||||
var randomString = Guid.NewGuid().ToString();
|
||||
baseSerializer.Serialize(null).ReturnsForAnyArgs(
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<Root>" +
|
||||
$"<Element1 Password=\"{randomString}\" />" +
|
||||
$"<Element1 Password=\"{randomString}\">" +
|
||||
$"<Element1 Password=\"{randomString}\" />" +
|
||||
"</Element1>" +
|
||||
"</Root>");
|
||||
return baseSerializer;
|
||||
}
|
||||
|
||||
private ICryptographyProvider SetupCryptoProvider()
|
||||
{
|
||||
var cryptoProvider = Substitute.For<ICryptographyProvider>();
|
||||
cryptoProvider.CipherEngine.Returns(CipherEngine);
|
||||
cryptoProvider.CipherMode.Returns(CipherMode);
|
||||
cryptoProvider.KeyDerivationIterations.Returns(KdfIterations);
|
||||
cryptoProvider.Encrypt(null, null).ReturnsForAnyArgs("encrypted");
|
||||
return cryptoProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Security;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.CredentialSerializers
|
||||
{
|
||||
public class XmlCredentialRecordDeserializerTests
|
||||
{
|
||||
private XmlCredentialRecordDeserializer _deserializer;
|
||||
private readonly Guid _id = Guid.NewGuid();
|
||||
private const string Title = "sometitle";
|
||||
private const string Username = "myusername";
|
||||
private const string Domain = "mydomain";
|
||||
private const string PlaintextPassword = "mypassword";
|
||||
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_deserializer = new XmlCredentialRecordDeserializer();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasCorrectId()
|
||||
{
|
||||
var xml = GenerateXml();
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.First().Id, Is.EqualTo(_id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasCorrectTitle()
|
||||
{
|
||||
var xml = GenerateXml();
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.First().Title, Is.EqualTo(Title));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasCorrectUsername()
|
||||
{
|
||||
var xml = GenerateXml();
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.First().Username, Is.EqualTo(Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasCorrectDomain()
|
||||
{
|
||||
var xml = GenerateXml();
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.First().Domain, Is.EqualTo(Domain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasCorrectPassword()
|
||||
{
|
||||
var xml = GenerateXml();
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.First().Password.ConvertToUnsecureString(), Is.EqualTo(PlaintextPassword));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializesAllCredentials()
|
||||
{
|
||||
var xml = GenerateXml();
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDecryptNonStandardEncryptions()
|
||||
{
|
||||
var xml = GenerateXml(BlockCipherEngines.Serpent, BlockCipherModes.EAX, 3000);
|
||||
var creds = _deserializer.Deserialize(xml);
|
||||
Assert.That(creds.First().Password.ConvertToUnsecureString(), Is.EqualTo(PlaintextPassword));
|
||||
}
|
||||
|
||||
|
||||
private string GenerateXml(BlockCipherEngines engine = BlockCipherEngines.AES, BlockCipherModes mode = BlockCipherModes.GCM, int interations = 1000)
|
||||
{
|
||||
return $"<Credentials EncryptionEngine=\"{engine}\" BlockCipherMode=\"{mode}\" KdfIterations=\"{interations}\" SchemaVersion=\"1.0\">" +
|
||||
$"<Credential Id=\"{_id}\" Title=\"{Title}\" Username=\"{Username}\" Domain=\"{Domain}\" Password=\"{PlaintextPassword}\" />" +
|
||||
$"<Credential Id=\"{Guid.NewGuid()}\" Title=\"{Title}\" Username=\"{Username}\" Domain=\"{Domain}\" Password=\"{PlaintextPassword}\" />" +
|
||||
"</Credentials>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.CredentialSerializers
|
||||
{
|
||||
public class XmlCredentialSerializerTests
|
||||
{
|
||||
private XmlCredentialRecordSerializer _serializer;
|
||||
private ICredentialRecord _cred1;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_serializer = new XmlCredentialRecordSerializer();
|
||||
_cred1 = new CredentialRecord { Title = "testcred", Username = "davids", Domain = "mydomain", Password = "mypass".ConvertToSecureString() };
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProducesValidXml()
|
||||
{
|
||||
var serialized = _serializer.Serialize(new[] { _cred1 });
|
||||
// ReSharper disable once ReturnValueOfPureMethodIsNotUsed
|
||||
Assert.DoesNotThrow(() => XDocument.Parse(serialized));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllCredentialsSerialized()
|
||||
{
|
||||
var cred2 = new CredentialRecord { Title = "testcred2", Username = "admin", Domain = "otherdomain", Password = "somepass".ConvertToSecureString() };
|
||||
var serialized = _serializer.Serialize(new[] { _cred1, cred2 });
|
||||
var serializedCount = XDocument.Parse(serialized).Descendants("Credential").Count();
|
||||
Assert.That(serializedCount, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IncludesSchemaVersionParameter()
|
||||
{
|
||||
var serialized = _serializer.Serialize(new[] { _cred1 });
|
||||
var xdoc = XDocument.Parse(serialized);
|
||||
Assert.That(xdoc.Root?.Attribute("SchemaVersion")?.Value, Is.EqualTo(_serializer.SchemaVersion));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
public class DataTableDeserializerTests
|
||||
{
|
||||
private DataTableDeserializer _deserializer;
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeATree()
|
||||
{
|
||||
var model = CreateConnectionTreeModel();
|
||||
var dataTable = CreateDataTable(model.RootNodes[0]);
|
||||
_deserializer = new DataTableDeserializer();
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeASingleEntry()
|
||||
{
|
||||
var dataTable = CreateDataTable(new ConnectionInfo());
|
||||
_deserializer = new DataTableDeserializer();
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
private DataTable CreateDataTable(ConnectionInfo tableContent)
|
||||
{
|
||||
var serializer = new DataTableSerializer(new SaveFilter());
|
||||
return serializer.Serialize(tableContent);
|
||||
}
|
||||
|
||||
private ConnectionTreeModel CreateConnectionTreeModel()
|
||||
{
|
||||
var builder = new ConnectionTreeModelBuilder();
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
@@ -20,13 +21,6 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
_dataTableSerializer = new DataTableSerializer(_saveFilter);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_saveFilter = null;
|
||||
_dataTableSerializer = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllItemsSerialized()
|
||||
{
|
||||
@@ -35,6 +29,14 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReturnsEmptyDataTableWhenGivenEmptyConnectionTreeModel()
|
||||
{
|
||||
var model = new ConnectionTreeModel();
|
||||
var dataTable = _dataTableSerializer.Serialize(model);
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UsernameSerializedWhenSaveSecurityAllowsIt()
|
||||
{
|
||||
@@ -109,20 +111,18 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(dataTable.Rows[0]["InheritUsername"], Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSerializeEmptyConnectionInfo()
|
||||
{
|
||||
var dataTable = _dataTableSerializer.Serialize(new ConnectionInfo());
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
private ConnectionTreeModel CreateConnectionTreeModel()
|
||||
{
|
||||
var model = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var folder1 = new ContainerInfo {Name = "folder1", Username = "user1", Domain = "domain1", Password = "password1"};
|
||||
var con1 = new ConnectionInfo {Name = "Con1", Username = "user1", Domain = "domain1", Password = "password1" };
|
||||
var con2 = new ConnectionInfo {Name = "Con2", Username = "user2", Domain = "domain2", Password = "password2" };
|
||||
|
||||
root.AddChild(folder1);
|
||||
root.AddChild(con2);
|
||||
folder1.AddChild(con1);
|
||||
model.AddRootNode(root);
|
||||
return model;
|
||||
var builder = new ConnectionTreeModelBuilder();
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MiscSerializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.ICA;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class CsvConnectionsDeserializerMremotengFormatTests
|
||||
{
|
||||
private CsvConnectionsDeserializerMremotengFormat _deserializer;
|
||||
private ICredentialRepositoryList _credentialRepositoryList;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_deserializer = new CsvConnectionsDeserializerMremotengFormat();
|
||||
_credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.ConnectionPropertyTestCases))]
|
||||
public object ConnectionPropertiesDeserializedCorrectly(string propertyToCheck)
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var csv = serializer.Serialize(GetTestConnection());
|
||||
var deserializedConnections = _deserializer.Deserialize(csv);
|
||||
var connection = deserializedConnections.GetRecursiveChildList().FirstOrDefault();
|
||||
var propertyValue = typeof(ConnectionInfo).GetProperty(propertyToCheck)?.GetValue(connection);
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.InheritanceTestCases))]
|
||||
public object InheritancePropertiesDeserializedCorrectly(string propertyToCheck)
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var csv = serializer.Serialize(GetTestConnectionWithAllInherited());
|
||||
var deserializedConnections = _deserializer.Deserialize(csv);
|
||||
var connection = deserializedConnections.GetRecursiveChildList().FirstOrDefault();
|
||||
var propertyValue = typeof(ConnectionInfoInheritance).GetProperty(propertyToCheck)?.GetValue(connection?.Inheritance);
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
internal static ConnectionInfo GetTestConnection()
|
||||
{
|
||||
return new ConnectionInfo
|
||||
{
|
||||
Name = "SomeName",
|
||||
Description = "SomeDescription",
|
||||
Icon = "SomeIcon",
|
||||
Panel = "SomePanel",
|
||||
Username = "SomeUsername",
|
||||
Password = "SomePassword",
|
||||
Domain = "SomeDomain",
|
||||
Hostname = "SomeHostname",
|
||||
PuttySession = "SomePuttySession",
|
||||
LoadBalanceInfo = "SomeLoadBalanceInfo",
|
||||
PreExtApp = "SomePreExtApp",
|
||||
PostExtApp = "SomePostExtApp",
|
||||
MacAddress = "SomeMacAddress",
|
||||
UserField = "SomeUserField",
|
||||
ExtApp = "SomeExtApp",
|
||||
VNCProxyUsername = "SomeVNCProxyUsername",
|
||||
VNCProxyPassword = "SomeVNCProxyPassword",
|
||||
RDGatewayUsername = "SomeRDGatewayUsername",
|
||||
RDGatewayPassword = "SomeRDGatewayPassword",
|
||||
RDGatewayDomain = "SomeRDGatewayDomain",
|
||||
VNCProxyIP = "SomeVNCProxyIP",
|
||||
RDGatewayHostname = "SomeRDGatewayHostname",
|
||||
Protocol = ProtocolType.ICA,
|
||||
Port = 999,
|
||||
UseConsoleSession = true,
|
||||
UseCredSsp = true,
|
||||
RenderingEngine = HTTPBase.RenderingEngine.Gecko,
|
||||
ICAEncryptionStrength = IcaProtocol.EncryptionStrength.Encr40Bit,
|
||||
RDPAuthenticationLevel = RdpAuthenticationLevel.WarnOnFailedAuth,
|
||||
Colors = RdpColors.Colors16Bit,
|
||||
Resolution = RdpResolutions.Res1366x768,
|
||||
AutomaticResize = true,
|
||||
DisplayWallpaper = true,
|
||||
DisplayThemes = true,
|
||||
EnableFontSmoothing = true,
|
||||
EnableDesktopComposition = true,
|
||||
CacheBitmaps = true,
|
||||
RedirectDiskDrives = true,
|
||||
RedirectPorts = true,
|
||||
RedirectPrinters = true,
|
||||
RedirectSmartCards = true,
|
||||
RedirectSound = RdpSounds.LeaveAtRemoteComputer,
|
||||
RedirectKeys = true,
|
||||
VNCCompression = ProtocolVNC.Compression.Comp4,
|
||||
VNCEncoding = ProtocolVNC.Encoding.EncRRE,
|
||||
VNCAuthMode = ProtocolVNC.AuthMode.AuthVNC,
|
||||
VNCProxyType = ProtocolVNC.ProxyType.ProxySocks5,
|
||||
VNCProxyPort = 123,
|
||||
VNCColors = ProtocolVNC.Colors.Col8Bit,
|
||||
VNCSmartSizeMode = ProtocolVNC.SmartSizeMode.SmartSAspect,
|
||||
VNCViewOnly = true,
|
||||
RDGatewayUsageMethod = RDGatewayUsageMethod.Detect,
|
||||
RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.SmartCard
|
||||
};
|
||||
}
|
||||
|
||||
internal static ConnectionInfo GetTestConnectionWithAllInherited()
|
||||
{
|
||||
var connectionInfo = new ConnectionInfo();
|
||||
connectionInfo.Inheritance.TurnOnInheritanceCompletely();
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
private class DeserializationTestSource
|
||||
{
|
||||
public static IEnumerable ConnectionPropertyTestCases()
|
||||
{
|
||||
var ignoreProperties = new[]
|
||||
{
|
||||
nameof(ConnectionInfo.Inheritance),
|
||||
nameof(ConnectionInfo.ConstantID),
|
||||
nameof(ConnectionInfo.Parent)
|
||||
};
|
||||
var properties = typeof(ConnectionInfo)
|
||||
.GetProperties()
|
||||
.Where(property => !ignoreProperties.Contains(property.Name));
|
||||
var testCases = new List<TestCaseData>();
|
||||
var testConnectionInfo = GetTestConnection();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
testCases.Add(
|
||||
new TestCaseData(property.Name)
|
||||
.Returns(property.GetValue(testConnectionInfo)));
|
||||
}
|
||||
|
||||
return testCases;
|
||||
}
|
||||
|
||||
public static IEnumerable InheritanceTestCases()
|
||||
{
|
||||
var ignoreProperties = new[]
|
||||
{
|
||||
nameof(ConnectionInfoInheritance.EverythingInherited),
|
||||
nameof(ConnectionInfoInheritance.Parent)
|
||||
};
|
||||
var properties = typeof(ConnectionInfoInheritance)
|
||||
.GetProperties()
|
||||
.Where(property => !ignoreProperties.Contains(property.Name));
|
||||
var testCases = new List<TestCaseData>();
|
||||
var testInheritance = GetTestConnectionWithAllInherited().Inheritance;
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
testCases.Add(
|
||||
new TestCaseData(property.Name)
|
||||
.Returns(property.GetValue(testInheritance)));
|
||||
}
|
||||
|
||||
return testCases;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class CsvConnectionsSerializerMremotengFormatTests
|
||||
{
|
||||
private ICredentialRepositoryList _credentialRepositoryList;
|
||||
private const string ConnectionName = "myconnection";
|
||||
private const string Username = "myuser";
|
||||
private const string Domain = "mydomain";
|
||||
private const string Password = "mypass123";
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
var credRecord = Substitute.For<ICredentialRecord>();
|
||||
credRecord.Username.Returns(Username);
|
||||
credRecord.Domain.Returns(Domain);
|
||||
credRecord.Password.Returns(Password.ConvertToSecureString());
|
||||
_credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
|
||||
_credentialRepositoryList.GetCredentialRecord(new Guid()).ReturnsForAnyArgs(credRecord);
|
||||
}
|
||||
|
||||
[TestCase(Username)]
|
||||
[TestCase(Domain)]
|
||||
[TestCase(Password)]
|
||||
[TestCase("InheritColors")]
|
||||
public void CreatesCsv(string valueThatShouldExist)
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var connectionInfo = BuildConnectionInfo();
|
||||
var csv = serializer.Serialize(connectionInfo);
|
||||
Assert.That(csv, Does.Match(valueThatShouldExist));
|
||||
}
|
||||
|
||||
[TestCase(Username)]
|
||||
[TestCase(Domain)]
|
||||
[TestCase(Password)]
|
||||
[TestCase("InheritColors")]
|
||||
public void SerializerRespectsSaveFilterSettings(string valueThatShouldntExist)
|
||||
{
|
||||
var saveFilter = new SaveFilter(true);
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, _credentialRepositoryList);
|
||||
var connectionInfo = BuildConnectionInfo();
|
||||
var csv = serializer.Serialize(connectionInfo);
|
||||
Assert.That(csv, Does.Not.Match(valueThatShouldntExist));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSerializeEmptyConnectionInfo()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var connectionInfo = new ConnectionInfo();
|
||||
var csv = serializer.Serialize(connectionInfo);
|
||||
Assert.That(csv, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantPassNullToConstructor()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new CsvConnectionsSerializerMremotengFormat(null, _credentialRepositoryList));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantPassNullToSerializeConnectionInfo()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
Assert.Throws<ArgumentNullException>(() => serializer.Serialize((ConnectionInfo)null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantPassNullToSerializeConnectionTreeModel()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
Assert.Throws<ArgumentNullException>(() => serializer.Serialize((ConnectionTreeModel)null));
|
||||
}
|
||||
|
||||
private ConnectionInfo BuildConnectionInfo()
|
||||
{
|
||||
return new ConnectionInfo
|
||||
{
|
||||
Name = ConnectionName,
|
||||
Username = Username,
|
||||
Domain = Domain,
|
||||
Password = Password,
|
||||
Inheritance = {Colors = true}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@ using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Tools;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class PortScanDeserializerTests
|
||||
{
|
||||
@@ -24,11 +23,10 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
var host = new ScanHost("10.20.30.40")
|
||||
{
|
||||
HostName = "server1.domain.com",
|
||||
SSH = true
|
||||
Ssh = true
|
||||
};
|
||||
_deserializer = new PortScanDeserializer(new [] {host}, ProtocolType.SSH2);
|
||||
_deserializer.Deserialize();
|
||||
var connectionTreeModel = _deserializer.Deserialize();
|
||||
_deserializer = new PortScanDeserializer(ProtocolType.SSH2);
|
||||
var connectionTreeModel = _deserializer.Deserialize(new[] { host });
|
||||
var root = connectionTreeModel.RootNodes.First();
|
||||
_importedConnectionInfo = root.Children.First();
|
||||
}
|
||||
@@ -6,8 +6,7 @@ using mRemoteNG.Container;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class PuttyConnectionManagerDeserializerTests
|
||||
{
|
||||
@@ -28,8 +27,8 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void OnetimeSetup()
|
||||
{
|
||||
var fileContents = Resources.test_puttyConnectionManager_database;
|
||||
_deserializer = new PuttyConnectionManagerDeserializer(fileContents);
|
||||
var connectionTreeModel = _deserializer.Deserialize();
|
||||
_deserializer = new PuttyConnectionManagerDeserializer();
|
||||
var connectionTreeModel = _deserializer.Deserialize(fileContents);
|
||||
var rootNode = connectionTreeModel.RootNodes.First();
|
||||
_rootImportedFolder = rootNode.Children.Cast<ContainerInfo>().First();
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
@@ -7,13 +6,11 @@ using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionDeserializerTests
|
||||
public class RemoteDesktopConnectionDeserializerTests
|
||||
{
|
||||
// .rdp file schema: https://technet.microsoft.com/en-us/library/ff393699(v=ws.10).aspx
|
||||
private string[] _connectionFileContents;
|
||||
private RemoteDesktopConnectionDeserializer _deserializer;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
private const string ExpectedHostname = "testhostname.domain.com";
|
||||
@@ -21,9 +18,9 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
private const string ExpectedDomain = "myspecialdomain";
|
||||
private const string ExpectedGatewayHostname = "gatewayhostname.domain.com";
|
||||
private const int ExpectedPort = 9933;
|
||||
private const ProtocolRDP.RDPColors ExpectedColors = ProtocolRDP.RDPColors.Colors24Bit;
|
||||
private const RdpColors ExpectedColors = RdpColors.Colors24Bit;
|
||||
private const bool ExpectedBitmapCaching = false;
|
||||
private const ProtocolRDP.RDPResolutions ExpectedResolutionMode = ProtocolRDP.RDPResolutions.FitToWindow;
|
||||
private const RdpResolutions ExpectedResolutionMode = RdpResolutions.FitToWindow;
|
||||
private const bool ExpectedWallpaperDisplay = true;
|
||||
private const bool ExpectedThemesDisplay = true;
|
||||
private const bool ExpectedFontSmoothing = true;
|
||||
@@ -32,21 +29,15 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
private const bool ExpectedDriveRedirection = true;
|
||||
private const bool ExpectedPortRedirection = true;
|
||||
private const bool ExpectedPrinterRedirection = true;
|
||||
private const ProtocolRDP.RDPSounds ExpectedSoundRedirection = ProtocolRDP.RDPSounds.BringToThisComputer;
|
||||
private const RdpSounds ExpectedSoundRedirection = RdpSounds.BringToThisComputer;
|
||||
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OnetimeSetup()
|
||||
{
|
||||
_connectionFileContents = Resources.test_remotedesktopconnection_rdp.Split(Environment.NewLine.ToCharArray());
|
||||
_deserializer = new RemoteDesktopConnectionDeserializer(_connectionFileContents);
|
||||
_connectionTreeModel = _deserializer.Deserialize();
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OnetimeTeardown()
|
||||
{
|
||||
_deserializer = null;
|
||||
var connectionFileContents = Resources.test_remotedesktopconnection_rdp;
|
||||
_deserializer = new RemoteDesktopConnectionDeserializer();
|
||||
_connectionTreeModel = _deserializer.Deserialize(connectionFileContents);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -0,0 +1,326 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionManager27DeserializerTests
|
||||
{
|
||||
private string _connectionFileContents;
|
||||
private RemoteDesktopConnectionManagerDeserializer _deserializer;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
private const string ExpectedName = "server1_displayname";
|
||||
private const string ExpectedHostname = "server1";
|
||||
private const string ExpectedDescription = "Comment text here";
|
||||
private const string ExpectedUsername = "myusername1";
|
||||
private const string ExpectedDomain = "mydomain";
|
||||
private const string ExpectedPassword = "passwordHere!";
|
||||
private const bool ExpectedUseConsoleSession = true;
|
||||
private const int ExpectedPort = 9933;
|
||||
private const RDGatewayUsageMethod ExpectedGatewayUsageMethod = RDGatewayUsageMethod.Always;
|
||||
private const string ExpectedGatewayHostname = "gatewayserverhost.innerdomain.net";
|
||||
private const string ExpectedGatewayUsername = "gatewayusername";
|
||||
private const string ExpectedGatewayDomain = "innerdomain";
|
||||
private const string ExpectedGatewayPassword = "gatewayPassword123";
|
||||
private const RdpResolutions ExpectedRdpResolution = RdpResolutions.FitToWindow;
|
||||
private const RdpColors ExpectedRdpColorDepth = RdpColors.Colors24Bit;
|
||||
private const RdpSounds ExpectedAudioRedirection = RdpSounds.DoNotPlay;
|
||||
private const bool ExpectedKeyRedirection = true;
|
||||
private const bool ExpectedSmartcardRedirection = true;
|
||||
private const bool ExpectedDriveRedirection = true;
|
||||
private const bool ExpectedPortRedirection = true;
|
||||
private const bool ExpectedPrinterRedirection = true;
|
||||
private const RdpAuthenticationLevel ExpectedAuthLevel = RdpAuthenticationLevel.WarnOnFailedAuth;
|
||||
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OnetimeSetup()
|
||||
{
|
||||
_connectionFileContents = Resources.test_rdcman_v2_7_schema3;
|
||||
_deserializer = new RemoteDesktopConnectionManagerDeserializer();
|
||||
_connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionTreeModelHasARootNode()
|
||||
{
|
||||
var numberOfRootNodes = _connectionTreeModel.RootNodes.Count;
|
||||
Assert.That(numberOfRootNodes, Is.GreaterThan(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootNodeHasContents()
|
||||
{
|
||||
var rootNodeContents = _connectionTreeModel.RootNodes.First().Children;
|
||||
Assert.That(rootNodeContents, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllSubRootFoldersImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var rootNodeContents = importedRdcmanRootNode.Children.Count(node => node.Name == "Group1" || node.Name == "Group2");
|
||||
Assert.That(rootNodeContents, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDisplayNameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Name, Is.EqualTo(ExpectedName));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionHostnameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Hostname, Is.EqualTo(ExpectedHostname));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDescriptionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Description, Is.EqualTo(ExpectedDescription));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionUsernameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Username, Is.EqualTo(ExpectedUsername));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDomainImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Domain, Is.EqualTo(ExpectedDomain));
|
||||
}
|
||||
|
||||
// Since password is encrypted with a machine key, cant test decryption on another machine
|
||||
//[Test]
|
||||
//public void ConnectionPasswordImported()
|
||||
//{
|
||||
// var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
// var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
// var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
// var connection = group1.Children.First();
|
||||
// Assert.That(connection.Password, Is.EqualTo(ExpectedPassword));
|
||||
//}
|
||||
|
||||
[Test]
|
||||
public void ConnectionProtocolSetToRdp()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Protocol, Is.EqualTo(ProtocolType.RDP));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionUseConsoleSessionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.UseConsoleSession, Is.EqualTo(ExpectedUseConsoleSession));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionPortImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Port, Is.EqualTo(ExpectedPort));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayUsageMethodImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayUsageMethod, Is.EqualTo(ExpectedGatewayUsageMethod));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayHostnameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayHostname, Is.EqualTo(ExpectedGatewayHostname));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayUsernameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayUsername, Is.EqualTo(ExpectedGatewayUsername));
|
||||
}
|
||||
|
||||
// Since password is encrypted with a machine key, cant test decryption on another machine
|
||||
//[Test]
|
||||
//public void ConnectionGatewayPasswordImported()
|
||||
//{
|
||||
// var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
// var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
// var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
// var connection = group1.Children.First();
|
||||
// Assert.That(connection.RDGatewayPassword, Is.EqualTo(ExpectedGatewayPassword));
|
||||
//}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayDomainImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayDomain, Is.EqualTo(ExpectedGatewayDomain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionResolutionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Resolution, Is.EqualTo(ExpectedRdpResolution));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionColorDepthImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Colors, Is.EqualTo(ExpectedRdpColorDepth));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionAudioRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectSound, Is.EqualTo(ExpectedAudioRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionKeyRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectKeys, Is.EqualTo(ExpectedKeyRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDriveRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectDiskDrives, Is.EqualTo(ExpectedDriveRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionPortRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectPorts, Is.EqualTo(ExpectedPortRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionPrinterRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectPrinters, Is.EqualTo(ExpectedPrinterRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionSmartcardRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectSmartCards, Is.EqualTo(ExpectedSmartcardRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionauthenticationLevelImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDPAuthenticationLevel, Is.EqualTo(ExpectedAuthLevel));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExceptionThrownOnBadSchemaVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_v2_2_badschemaversion;
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExceptionThrownOnUnsupportedVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_badVersionNumber;
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExceptionThrownOnNoVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_noversion;
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
@@ -6,11 +7,10 @@ using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
using System.IO;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionManagerDeserializerTests
|
||||
public class RemoteDesktopConnectionManagerDeserializerTests
|
||||
{
|
||||
private string _connectionFileContents;
|
||||
private RemoteDesktopConnectionManagerDeserializer _deserializer;
|
||||
@@ -23,34 +23,28 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
private const string ExpectedPassword = "passwordHere!";
|
||||
private const bool ExpectedUseConsoleSession = true;
|
||||
private const int ExpectedPort = 9933;
|
||||
private const ProtocolRDP.RDGatewayUsageMethod ExpectedGatewayUsageMethod = ProtocolRDP.RDGatewayUsageMethod.Always;
|
||||
private const RDGatewayUsageMethod ExpectedGatewayUsageMethod = RDGatewayUsageMethod.Always;
|
||||
private const string ExpectedGatewayHostname = "gatewayserverhost.innerdomain.net";
|
||||
private const string ExpectedGatewayUsername = "gatewayusername";
|
||||
private const string ExpectedGatewayDomain = "innerdomain";
|
||||
private const string ExpectedGatewayPassword = "gatewayPassword123";
|
||||
private const ProtocolRDP.RDPResolutions ExpectedRdpResolution = ProtocolRDP.RDPResolutions.FitToWindow;
|
||||
private const ProtocolRDP.RDPColors ExpectedRdpColorDepth = ProtocolRDP.RDPColors.Colors24Bit;
|
||||
private const ProtocolRDP.RDPSounds ExpectedAudioRedirection = ProtocolRDP.RDPSounds.DoNotPlay;
|
||||
private const RdpResolutions ExpectedRdpResolution = RdpResolutions.FitToWindow;
|
||||
private const RdpColors ExpectedRdpColorDepth = RdpColors.Colors24Bit;
|
||||
private const RdpSounds ExpectedAudioRedirection = RdpSounds.DoNotPlay;
|
||||
private const bool ExpectedKeyRedirection = true;
|
||||
private const bool ExpectedSmartcardRedirection = true;
|
||||
private const bool ExpectedDriveRedirection = true;
|
||||
private const bool ExpectedPortRedirection = true;
|
||||
private const bool ExpectedPrinterRedirection = true;
|
||||
private const ProtocolRDP.AuthenticationLevel ExpectedAuthLevel = ProtocolRDP.AuthenticationLevel.AuthRequired;
|
||||
private const RdpAuthenticationLevel ExpectedAuthLevel = RdpAuthenticationLevel.AuthRequired;
|
||||
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void OnetimeSetup()
|
||||
{
|
||||
_connectionFileContents = Resources.test_rdcman_v2_2_schema1;
|
||||
_deserializer = new RemoteDesktopConnectionManagerDeserializer(_connectionFileContents);
|
||||
_connectionTreeModel = _deserializer.Deserialize();
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
public void OnetimeTeardown()
|
||||
{
|
||||
_deserializer = null;
|
||||
_deserializer = new RemoteDesktopConnectionManagerDeserializer();
|
||||
_connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -312,24 +306,21 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void ExceptionThrownOnBadSchemaVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_v2_2_badschemaversion;
|
||||
var deserializer = new RemoteDesktopConnectionManagerDeserializer(badFileContents);
|
||||
Assert.That(() => deserializer.Deserialize(), Throws.TypeOf<FileFormatException>());
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExceptionThrownOnUnsupportedVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_badVersionNumber;
|
||||
var deserializer = new RemoteDesktopConnectionManagerDeserializer(badFileContents);
|
||||
Assert.That(() => deserializer.Deserialize(), Throws.TypeOf<FileFormatException>());
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExceptionThrownOnNoVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_noversion;
|
||||
var deserializer = new RemoteDesktopConnectionManagerDeserializer(badFileContents);
|
||||
Assert.That(() => deserializer.Deserialize(), Throws.TypeOf<FileFormatException>());
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.Versioning
|
||||
{
|
||||
public class SqlVersion22To23UpgraderTests
|
||||
{
|
||||
private SqlVersion22To23Upgrader _versionUpgrader;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var sqlConnector = Substitute.For<SqlDatabaseConnector>("", "", "", "");
|
||||
_versionUpgrader = new SqlVersion22To23Upgrader(sqlConnector);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUpgradeIfVersionIs22()
|
||||
{
|
||||
var currentVersion = new Version(2, 2);
|
||||
var canUpgrade = _versionUpgrader.CanUpgrade(currentVersion);
|
||||
Assert.That(canUpgrade, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.Versioning
|
||||
{
|
||||
public class SqlVersion23To24UpgraderTests
|
||||
{
|
||||
private SqlVersion23To24Upgrader _versionUpgrader;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var sqlConnector = Substitute.For<SqlDatabaseConnector>("", "", "", "");
|
||||
_versionUpgrader = new SqlVersion23To24Upgrader(sqlConnector);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUpgradeIfVersionIs23()
|
||||
{
|
||||
var currentVersion = new Version(2, 3);
|
||||
var canUpgrade = _versionUpgrader.CanUpgrade(currentVersion);
|
||||
Assert.That(canUpgrade, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.Versioning
|
||||
{
|
||||
public class SqlVersion24To25UpgraderTests
|
||||
{
|
||||
private SqlVersion24To25Upgrader _versionUpgrader;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var sqlConnector = Substitute.For<SqlDatabaseConnector>("", "", "", "");
|
||||
_versionUpgrader = new SqlVersion24To25Upgrader(sqlConnector);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUpgradeIfVersionIs24()
|
||||
{
|
||||
var currentVersion = new Version(2, 4);
|
||||
var canUpgrade = _versionUpgrader.CanUpgrade(currentVersion);
|
||||
Assert.That(canUpgrade, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.Versioning
|
||||
{
|
||||
public class SqlVersion25To26UpgraderTests
|
||||
{
|
||||
private SqlVersion25To26Upgrader _versionUpgrader;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var sqlConnector = Substitute.For<SqlDatabaseConnector>("", "", "", "");
|
||||
_versionUpgrader = new SqlVersion25To26Upgrader(sqlConnector);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUpgradeIfVersionIs25()
|
||||
{
|
||||
var currentVersion = new Version(2, 5);
|
||||
var canUpgrade = _versionUpgrader.CanUpgrade(currentVersion);
|
||||
Assert.That(canUpgrade, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
public class XmlConnectionNodeSerializerTests
|
||||
{
|
||||
private XmlConnectionNodeSerializer _connectionNodeSerializer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(
|
||||
BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReturnsXElement()
|
||||
{
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(new ConnectionInfo());
|
||||
Assert.That(returnVal, Is.TypeOf<XElement>());
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.AttributesAndExpectedValues))]
|
||||
public void XmlElementContainsSerializedAttribute(string attributeName, string expectedValue, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.EqualTo(expectedValue));
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.PasswordAttributes))]
|
||||
public void PasswordFieldsAreSerialized(string attributeName, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.SaveFilterTests))]
|
||||
public void AttributesNotSerializedWhenFiltered(string attributeName, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var saveFilter = new SaveFilter(true);
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString(), saveFilter);
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.InheritanceFilterTests))]
|
||||
public void InheritanceNotSerialiedWhenFiltered(string attributeName, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var saveFilter = new SaveFilter(true);
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString(), saveFilter);
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.EqualTo(false.ToString()));
|
||||
}
|
||||
|
||||
private class TestCaseDataSource
|
||||
{
|
||||
private static readonly ConnectionInfo ConnectionInfo = new ConnectionInfo
|
||||
{
|
||||
Name = "HeresACustomName",
|
||||
Description = "myDescription",
|
||||
Username = "myuser",
|
||||
Domain = "superdomain",
|
||||
Password = "pass",
|
||||
Hostname = "somehost",
|
||||
ExtApp = "myextapp",
|
||||
PreExtApp = "preext1",
|
||||
PostExtApp = "postext1",
|
||||
MacAddress = "asdf-asdf-asdf-asdf23423",
|
||||
LoadBalanceInfo = "loadbalanceinfohere",
|
||||
RDGatewayUsername = "gatewayuser",
|
||||
RDGatewayDomain = "somegatewaydomain",
|
||||
RDGatewayHostname = "somegatewayhost",
|
||||
RDGatewayPassword = "gatewaypass",
|
||||
UserField = "userfield data here",
|
||||
VNCProxyIP = "192.168.1.1",
|
||||
VNCProxyUsername = "vncproxyuser",
|
||||
VNCProxyPassword = "vncproxypass",
|
||||
};
|
||||
|
||||
private static readonly ConnectionInfo ConnectionInfoWithInheritance = new ConnectionInfo
|
||||
{
|
||||
Inheritance = {EverythingInherited = true}
|
||||
};
|
||||
|
||||
private static readonly ContainerInfo ContainerInfo = new ContainerInfo();
|
||||
|
||||
public static IEnumerable SaveFilterTests
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Username", ConnectionInfo);
|
||||
yield return new TestCaseData("Domain", ConnectionInfo);
|
||||
yield return new TestCaseData("Password", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUsername", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayDomain", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayPassword", ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyUsername", ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyPassword", ConnectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable InheritanceFilterTests
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("InheritUsername", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritDomain", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritPassword", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritRDGatewayUsername", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritRDGatewayDomain", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritRDGatewayPassword", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritVNCProxyUsername", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritVNCProxyPassword", ConnectionInfoWithInheritance);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable PasswordAttributes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Password", ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyPassword", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayPassword", ConnectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable AttributesAndExpectedValues
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Name", ConnectionInfo.Name, ConnectionInfo);
|
||||
yield return new TestCaseData("Type", "Connection", ConnectionInfo);
|
||||
yield return new TestCaseData("Type", "Container", ContainerInfo);
|
||||
yield return new TestCaseData("Expanded", ContainerInfo.IsExpanded.ToString(), ContainerInfo);
|
||||
yield return new TestCaseData("Descr", ConnectionInfo.Description, ConnectionInfo);
|
||||
yield return new TestCaseData("Icon", ConnectionInfo.Icon, ConnectionInfo);
|
||||
yield return new TestCaseData("Panel", "General", ConnectionInfo);
|
||||
yield return new TestCaseData("Username", ConnectionInfo.Username, ConnectionInfo);
|
||||
yield return new TestCaseData("Domain", ConnectionInfo.Domain, ConnectionInfo);
|
||||
yield return new TestCaseData("Hostname", ConnectionInfo.Hostname, ConnectionInfo);
|
||||
yield return new TestCaseData("Protocol", "RDP", ConnectionInfo);
|
||||
yield return new TestCaseData("PuttySession", ConnectionInfo.PuttySession, ConnectionInfo);
|
||||
yield return new TestCaseData("Port", ConnectionInfo.Port.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("ConnectToConsole", ConnectionInfo.UseConsoleSession.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("UseCredSsp", ConnectionInfo.UseCredSsp.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RenderingEngine", ConnectionInfo.RenderingEngine.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("ICAEncryptionStrength", ConnectionInfo.ICAEncryptionStrength.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDPAuthenticationLevel", ConnectionInfo.RDPAuthenticationLevel.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("LoadBalanceInfo", ConnectionInfo.LoadBalanceInfo, ConnectionInfo);
|
||||
yield return new TestCaseData("Colors", ConnectionInfo.Colors.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("Resolution", ConnectionInfo.Resolution.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("AutomaticResize", ConnectionInfo.AutomaticResize.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("DisplayWallpaper", ConnectionInfo.DisplayWallpaper.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("DisplayThemes", ConnectionInfo.DisplayThemes.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("EnableFontSmoothing", ConnectionInfo.EnableFontSmoothing.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("EnableDesktopComposition", ConnectionInfo.EnableDesktopComposition.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("CacheBitmaps", ConnectionInfo.CacheBitmaps.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectDiskDrives", ConnectionInfo.RedirectDiskDrives.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectPorts", ConnectionInfo.RedirectPorts.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectPrinters", ConnectionInfo.RedirectPrinters.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectSmartCards", ConnectionInfo.RedirectSmartCards.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectSound", ConnectionInfo.RedirectSound.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectKeys", ConnectionInfo.RedirectKeys.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("Connected", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("PreExtApp", ConnectionInfo.PreExtApp, ConnectionInfo);
|
||||
yield return new TestCaseData("PostExtApp", ConnectionInfo.PostExtApp, ConnectionInfo);
|
||||
yield return new TestCaseData("MacAddress", ConnectionInfo.MacAddress, ConnectionInfo);
|
||||
yield return new TestCaseData("UserField", ConnectionInfo.UserField, ConnectionInfo);
|
||||
yield return new TestCaseData("ExtApp", ConnectionInfo.ExtApp, ConnectionInfo);
|
||||
yield return new TestCaseData("VNCCompression", ConnectionInfo.VNCCompression.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCEncoding", ConnectionInfo.VNCEncoding.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCAuthMode", ConnectionInfo.VNCAuthMode.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyType", ConnectionInfo.VNCProxyType.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyIP", ConnectionInfo.VNCProxyIP, ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyPort", ConnectionInfo.VNCProxyPort.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyUsername", ConnectionInfo.VNCProxyUsername, ConnectionInfo);
|
||||
yield return new TestCaseData("VNCColors", ConnectionInfo.VNCColors.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCSmartSizeMode", ConnectionInfo.VNCSmartSizeMode.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCViewOnly", ConnectionInfo.VNCViewOnly.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUsageMethod", ConnectionInfo.RDGatewayUsageMethod.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayHostname", ConnectionInfo.RDGatewayHostname, ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUseConnectionCredentials", ConnectionInfo.RDGatewayUseConnectionCredentials.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUsername", ConnectionInfo.RDGatewayUsername, ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayDomain", ConnectionInfo.RDGatewayDomain, ConnectionInfo);
|
||||
yield return new TestCaseData("InheritCacheBitmaps", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritColors", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDescription", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDisplayThemes", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDisplayWallpaper", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritEnableFontSmoothing", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritEnableDesktopComposition", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDomain", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritIcon", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPanel", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPassword", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPort", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritProtocol", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPuttySession", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectDiskDrives", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectKeys", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectPorts", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectPrinters", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectSmartCards", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectSound", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritSoundQuality", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritResolution", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritAutomaticResize", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUseConsoleSession", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUseCredSsp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRenderingEngine", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUsername", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritICAEncryptionStrength", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDPAuthenticationLevel", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritLoadBalanceInfo", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPreExtApp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPostExtApp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritMacAddress", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUserField", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritExtApp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCCompression", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCEncoding", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCAuthMode", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyType", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyIP", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyPort", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyUsername", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyPassword", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCColors", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCSmartSizeMode", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCViewOnly", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayUsageMethod", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayHostname", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayUseConnectionCredentials", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayUsername", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayPassword", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayDomain", false.ToString(), ConnectionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
mRemoteNGTests/Config/Settings/DockPanelSerializerTests.cs
Normal file
35
mRemoteNGTests/Config/Settings/DockPanelSerializerTests.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Settings;
|
||||
using NUnit.Framework;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
namespace mRemoteNGTests.Config.Settings
|
||||
{
|
||||
public class DockPanelSerializerTests
|
||||
{
|
||||
private DockPanelLayoutSerializer _dockPanelLayoutSerializer;
|
||||
private DockPanel _dockPanel;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_dockPanelLayoutSerializer = new DockPanelLayoutSerializer();
|
||||
_dockPanel = new DockPanel();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializerProducesValidDockPanelXml()
|
||||
{
|
||||
var serializedData = _dockPanelLayoutSerializer.Serialize(_dockPanel);
|
||||
var serializedDataAsXDoc = XDocument.Parse(serializedData);
|
||||
Assert.That(serializedDataAsXDoc.Root?.Name.ToString(), Is.EqualTo("DockPanel"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullDockPanel()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _dockPanelLayoutSerializer.Serialize(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,11 @@ using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
public class AbstractConnectionInfoDataTests
|
||||
public class AbstractConnectionInfoDataTests
|
||||
{
|
||||
private class TestAbstractConnectionInfoData : AbstractConnectionInfoData {}
|
||||
#pragma warning disable 618
|
||||
private class TestAbstractConnectionInfoData : AbstractConnectionRecord {}
|
||||
#pragma warning restore 618
|
||||
private TestAbstractConnectionInfoData _testAbstractConnectionInfoData;
|
||||
|
||||
[SetUp]
|
||||
@@ -140,7 +142,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.ICAEncryptionStrength = ProtocolICA.EncryptionStrength.Encr128BitLogonOnly;
|
||||
_testAbstractConnectionInfoData.ICAEncryptionStrength = IcaProtocol.EncryptionStrength.Encr128BitLogonOnly;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -158,7 +160,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RDPAuthenticationLevel = ProtocolRDP.AuthenticationLevel.AuthRequired;
|
||||
_testAbstractConnectionInfoData.RDPAuthenticationLevel = RdpAuthenticationLevel.AuthRequired;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -194,7 +196,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RDGatewayUsageMethod = ProtocolRDP.RDGatewayUsageMethod.Always;
|
||||
_testAbstractConnectionInfoData.RDGatewayUsageMethod = RDGatewayUsageMethod.Always;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -212,7 +214,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RDGatewayUseConnectionCredentials = ProtocolRDP.RDGatewayUseConnectionCredentials.SmartCard;
|
||||
_testAbstractConnectionInfoData.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.SmartCard;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -248,7 +250,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.Resolution = ProtocolRDP.RDPResolutions.Res1366x768;
|
||||
_testAbstractConnectionInfoData.Resolution = RdpResolutions.Res1366x768;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -266,7 +268,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.Colors = ProtocolRDP.RDPColors.Colors16Bit;
|
||||
_testAbstractConnectionInfoData.Colors = RdpColors.Colors16Bit;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -365,7 +367,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RedirectSound = ProtocolRDP.RDPSounds.DoNotPlay;
|
||||
_testAbstractConnectionInfoData.RedirectSound = RdpSounds.DoNotPlay;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
using mRemoteNG.Connection;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.SSH;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
public class ConnectionInfoTests
|
||||
public class ConnectionInfoTests
|
||||
{
|
||||
private ConnectionInfo _connectionInfo;
|
||||
private const string TestDomain = "somedomain";
|
||||
@@ -48,6 +51,14 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(secondConnection.Domain, Is.EqualTo(_connectionInfo.Domain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CloneDoesNotSetParentOfNewConnectionInfo()
|
||||
{
|
||||
_connectionInfo.SetParent(new ContainerInfo());
|
||||
var clonedConnection = _connectionInfo.Clone();
|
||||
Assert.That(clonedConnection.Parent, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyFromCopiesProperties()
|
||||
{
|
||||
@@ -70,7 +81,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var eventWasCalled = false;
|
||||
_connectionInfo.PropertyChanged += (sender, args) => eventWasCalled = true;
|
||||
_connectionInfo.OpenConnections.Add(new ProtocolSSH2());
|
||||
_connectionInfo.OpenConnections.Add(new ProtocolSSH2(_connectionInfo));
|
||||
Assert.That(eventWasCalled);
|
||||
}
|
||||
|
||||
@@ -79,11 +90,33 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var nameOfModifiedProperty = "";
|
||||
_connectionInfo.PropertyChanged += (sender, args) => nameOfModifiedProperty = args.PropertyName;
|
||||
_connectionInfo.OpenConnections.Add(new ProtocolSSH2());
|
||||
_connectionInfo.OpenConnections.Add(new ProtocolSSH2(_connectionInfo));
|
||||
Assert.That(nameOfModifiedProperty, Is.EqualTo("OpenConnections"));
|
||||
}
|
||||
|
||||
[TestCase(ProtocolType.HTTP, ExpectedResult = 80)]
|
||||
[TestCaseSource(typeof(InheritancePropertyProvider), nameof(InheritancePropertyProvider.GetProperties))]
|
||||
public void MovingAConnectionUnderRootNodeDisablesInheritance(PropertyInfo property)
|
||||
{
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection);
|
||||
_connectionInfo.Inheritance.EverythingInherited = true;
|
||||
_connectionInfo.SetParent(rootNode);
|
||||
var propertyValue = property.GetValue(_connectionInfo.Inheritance);
|
||||
Assert.That(propertyValue, Is.False);
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(InheritancePropertyProvider), nameof(InheritancePropertyProvider.GetProperties))]
|
||||
public void MovingAConnectionFromUnderRootNodeToUnderADifferentNodeEnablesInheritance(PropertyInfo property)
|
||||
{
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection);
|
||||
var otherContainer = new ContainerInfo();
|
||||
_connectionInfo.Inheritance.EverythingInherited = true;
|
||||
_connectionInfo.SetParent(rootNode);
|
||||
_connectionInfo.SetParent(otherContainer);
|
||||
var propertyValue = property.GetValue(_connectionInfo.Inheritance);
|
||||
Assert.That(propertyValue, Is.True);
|
||||
}
|
||||
|
||||
[TestCase(ProtocolType.HTTP, ExpectedResult = 80)]
|
||||
[TestCase(ProtocolType.HTTPS, ExpectedResult = 443)]
|
||||
[TestCase(ProtocolType.ICA, ExpectedResult = 1494)]
|
||||
[TestCase(ProtocolType.IntApp, ExpectedResult = 0)]
|
||||
@@ -99,5 +132,13 @@ namespace mRemoteNGTests.Connection
|
||||
_connectionInfo.Protocol = protocolType;
|
||||
return _connectionInfo.GetDefaultPort();
|
||||
}
|
||||
|
||||
private class InheritancePropertyProvider
|
||||
{
|
||||
public static IEnumerable<PropertyInfo> GetProperties()
|
||||
{
|
||||
return new ConnectionInfoInheritance(new object()).GetProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
@@ -30,5 +31,43 @@ namespace mRemoteNGTests.Connection
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSaveEnumValuesToString()
|
||||
{
|
||||
const ProtocolType targetProtocol = ProtocolType.RAW;
|
||||
var saveTarget = new AllStringPropertySaveTarget();
|
||||
DefaultConnectionInfo.Instance.Protocol = targetProtocol;
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.Protocol, Is.EqualTo(targetProtocol.ToString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSaveIntegerValuesToString()
|
||||
{
|
||||
const int targetValue = 123;
|
||||
var saveTarget = new AllStringPropertySaveTarget();
|
||||
DefaultConnectionInfo.Instance.RDPMinutesToIdleTimeout = targetValue;
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.RDPMinutesToIdleTimeout, Is.EqualTo(targetValue.ToString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSaveStringValuesToString()
|
||||
{
|
||||
const string targetName = "hello";
|
||||
var saveTarget = new AllStringPropertySaveTarget();
|
||||
DefaultConnectionInfo.Instance.Username = targetName;
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.Username, Is.EqualTo(targetName));
|
||||
}
|
||||
|
||||
|
||||
private class AllStringPropertySaveTarget
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Protocol { get; set; }
|
||||
public string RDPMinutesToIdleTimeout { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
57
mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs
Normal file
57
mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools.CustomCollections;
|
||||
using mRemoteNG.UI.Window;
|
||||
using NUnit.Framework;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
namespace mRemoteNGTests.Connection.Protocol
|
||||
{
|
||||
public class IntegratedProgramTests
|
||||
{
|
||||
private readonly ExternalTool _extTool = new ExternalTool
|
||||
{
|
||||
DisplayName = "notepad",
|
||||
FileName = @"%windir%\system32\notepad.exe",
|
||||
Arguments = "",
|
||||
TryIntegrate = true
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void CanStartExternalApp()
|
||||
{
|
||||
SetExternalToolList(_extTool);
|
||||
var connectionInfo = new ConnectionInfo { ExtApp = _extTool.DisplayName };
|
||||
var sut = new IntegratedProgram(connectionInfo);
|
||||
sut.InterfaceControl = BuildInterfaceControl(sut);
|
||||
sut.Initialize();
|
||||
var appStarted = sut.Connect();
|
||||
sut.Disconnect();
|
||||
Assert.That(appStarted);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectingToExternalAppThatDoesntExistDoesNothing()
|
||||
{
|
||||
SetExternalToolList(_extTool);
|
||||
var connectionInfo = new ConnectionInfo { ExtApp = "doesntExist" };
|
||||
var sut = new IntegratedProgram(connectionInfo);
|
||||
sut.InterfaceControl = BuildInterfaceControl(sut);
|
||||
var appInitialized = sut.Initialize();
|
||||
Assert.That(appInitialized, Is.False);
|
||||
}
|
||||
|
||||
private void SetExternalToolList(ExternalTool externalTool)
|
||||
{
|
||||
Runtime.ExternalToolsService.ExternalTools = new FullyObservableCollection<ExternalTool> {externalTool};
|
||||
}
|
||||
|
||||
private InterfaceControl BuildInterfaceControl(ProtocolBase sut)
|
||||
{
|
||||
var connectionWindow = new ConnectionWindow(new DockContent());
|
||||
return new InterfaceControl(connectionWindow, sut);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.SSH;
|
||||
using mRemoteNG.Connection.Protocol.Telnet;
|
||||
@@ -21,9 +22,9 @@ namespace mRemoteNGTests.Connection.Protocol
|
||||
public void Setup()
|
||||
{
|
||||
_protocolList = new ProtocolList();
|
||||
_protocol1 = new ProtocolTelnet();
|
||||
_protocol2 = new ProtocolSSH2();
|
||||
_protocol3 = new ProtocolVNC();
|
||||
_protocol1 = new ProtocolTelnet(new ConnectionInfo());
|
||||
_protocol2 = new ProtocolSSH2(new ConnectionInfo());
|
||||
_protocol3 = new ProtocolVNC(new ConnectionInfo());
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
|
||||
@@ -263,6 +263,14 @@ namespace mRemoteNGTests.Container
|
||||
Assert.That(clone.ConstantID, Is.Not.EqualTo(_containerInfo.ConstantID));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClonedContainerDoesNotHaveParentSet()
|
||||
{
|
||||
_containerInfo.SetParent(new ContainerInfo());
|
||||
var clone = _containerInfo.Clone();
|
||||
Assert.That(clone.Parent, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClonedContainerContainsClonedChildren()
|
||||
{
|
||||
|
||||
104
mRemoteNGTests/Credential/CompositeRepositoryUnlockerTests.cs
Normal file
104
mRemoteNGTests/Credential/CompositeRepositoryUnlockerTests.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Security;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Credential.Repositories;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CompositeRepositoryUnlockerTests
|
||||
{
|
||||
private CompositeRepositoryUnlocker _repositoryUnlocker;
|
||||
private IList<ICredentialRepository> _repos;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_repos = BuildRepos(3);
|
||||
_repositoryUnlocker = new CompositeRepositoryUnlocker(_repos);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanCreateAnUnlockerThatWillHandleSomeRepos()
|
||||
{
|
||||
Assert.That(_repositoryUnlocker.Repositories, Is.EquivalentTo(_repos));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TheFirstRepoIsInitiallySelected()
|
||||
{
|
||||
Assert.That(_repositoryUnlocker.SelectedRepository, Is.EqualTo(_repos[0]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanUnlockARepository()
|
||||
{
|
||||
var key = new SecureString();
|
||||
_repositoryUnlocker.Unlock(key);
|
||||
_repositoryUnlocker.SelectedRepository.Received(1).LoadCredentials(key);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanSelectTheNextLockedRepository()
|
||||
{
|
||||
_repos[1].IsLoaded.Returns(true);
|
||||
_repositoryUnlocker.SelectNextLockedRepository();
|
||||
Assert.That(_repositoryUnlocker.SelectedRepository, Is.EqualTo(_repos[2]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectingTheNextRepoWhenOnlyOneRepoExistsDoesNothing()
|
||||
{
|
||||
var repos = BuildRepos(1);
|
||||
var repositoryUnlocker = new CompositeRepositoryUnlocker(repos);
|
||||
repositoryUnlocker.SelectNextLockedRepository();
|
||||
Assert.That(repositoryUnlocker.SelectedRepository, Is.EqualTo(repos[0]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectionIsClearedIfThereAreNoMoreLockedRepositories()
|
||||
{
|
||||
foreach(var repo in _repos)
|
||||
repo.IsLoaded.Returns(true);
|
||||
_repositoryUnlocker.SelectNextLockedRepository();
|
||||
Assert.That(_repositoryUnlocker.SelectedRepository, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SelectionRemainsTheSameIfTheCurrentRepoIsTheOnlyOneLocked()
|
||||
{
|
||||
foreach (var repo in _repos)
|
||||
repo.IsLoaded.Returns(true);
|
||||
_repos[0].IsLoaded.Returns(false);
|
||||
_repositoryUnlocker.SelectNextLockedRepository();
|
||||
Assert.That(_repositoryUnlocker.SelectedRepository, Is.EqualTo(_repos[0]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NothingIsSelectedIfNoReposExist()
|
||||
{
|
||||
var repositoryUnlocker = new CompositeRepositoryUnlocker(new ICredentialRepository[0]);
|
||||
repositoryUnlocker.SelectNextLockedRepository();
|
||||
Assert.That(repositoryUnlocker.SelectedRepository, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FirstLockedRepoSelectedIfNoRepoCurrentlySelected()
|
||||
{
|
||||
var repo = BuildRepos(1);
|
||||
repo[0].IsLoaded.Returns(false);
|
||||
var repositoryUnlocker = new CompositeRepositoryUnlocker(repo);
|
||||
repositoryUnlocker.SelectNextLockedRepository();
|
||||
Assert.That(repositoryUnlocker.SelectedRepository, Is.EqualTo(repo[0]));
|
||||
}
|
||||
|
||||
private IList<ICredentialRepository> BuildRepos(int count)
|
||||
{
|
||||
var list = new List<ICredentialRepository>();
|
||||
for (var i=0; i < count; i++)
|
||||
list.Add(Substitute.For<ICredentialRepository>());
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
mRemoteNGTests/Credential/CredentialChangedEventArgsTests.cs
Normal file
48
mRemoteNGTests/Credential/CredentialChangedEventArgsTests.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialChangedEventArgsTests
|
||||
{
|
||||
private ICredentialRecord _credentialRecord;
|
||||
private ICredentialRepository _credentialRepository;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialRecord = Substitute.For<ICredentialRecord>();
|
||||
_credentialRepository = Substitute.For<ICredentialRepository>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullCredentialRecord()
|
||||
{
|
||||
// ReSharper disable once ObjectCreationAsStatement
|
||||
Assert.Throws<ArgumentNullException>(() => new CredentialChangedEventArgs(null, _credentialRepository));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullCredentialRepository()
|
||||
{
|
||||
// ReSharper disable once ObjectCreationAsStatement
|
||||
Assert.Throws<ArgumentNullException>(() => new CredentialChangedEventArgs(_credentialRecord, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CredentialRecordPropertySetFromCtor()
|
||||
{
|
||||
var sut = new CredentialChangedEventArgs(_credentialRecord, _credentialRepository);
|
||||
Assert.That(sut.CredentialRecord, Is.EqualTo(_credentialRecord));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RepositoryPropertySetFromCtor()
|
||||
{
|
||||
var sut = new CredentialChangedEventArgs(_credentialRecord, _credentialRepository);
|
||||
Assert.That(sut.Repository, Is.EqualTo(_credentialRepository));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialDeletionMsgBoxConfirmerTests
|
||||
{
|
||||
private ICredentialRecord _credentialRecord;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialRecord = Substitute.For<ICredentialRecord>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClickingYesReturnsTrue()
|
||||
{
|
||||
var deletionConfirmer = new CredentialDeletionMsgBoxConfirmer(MockClickYes);
|
||||
Assert.That(deletionConfirmer.Confirm(new[] { _credentialRecord }), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ClickingNoReturnsFalse()
|
||||
{
|
||||
var deletionConfirmer = new CredentialDeletionMsgBoxConfirmer(MockClickNo);
|
||||
Assert.That(deletionConfirmer.Confirm(new [] { _credentialRecord }), Is.False);
|
||||
}
|
||||
|
||||
private DialogResult MockClickYes(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
return DialogResult.Yes;
|
||||
}
|
||||
|
||||
private DialogResult MockClickNo(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
return DialogResult.No;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialDomainUserComparerTests
|
||||
{
|
||||
private CredentialDomainUserComparer _comparer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_comparer = new CredentialDomainUserComparer();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CredentialsWithTheSameUsernameAndDomainAreEqual()
|
||||
{
|
||||
const string user = "user1";
|
||||
const string domain = "domain";
|
||||
var cred1 = Substitute.For<ICredentialRecord>();
|
||||
cred1.Username.Returns(user);
|
||||
cred1.Domain.Returns(domain);
|
||||
var cred2 = Substitute.For<ICredentialRecord>();
|
||||
cred2.Username.Returns(user);
|
||||
cred2.Domain.Returns(domain);
|
||||
Assert.That(_comparer.Equals(cred1, cred2), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CredentialsWithDifferentUsernamesAreNotEqual()
|
||||
{
|
||||
const string domain = "domain";
|
||||
var cred1 = Substitute.For<ICredentialRecord>();
|
||||
cred1.Username.Returns("user1");
|
||||
cred1.Domain.Returns(domain);
|
||||
var cred2 = Substitute.For<ICredentialRecord>();
|
||||
cred2.Username.Returns("user2");
|
||||
cred2.Domain.Returns(domain);
|
||||
Assert.That(_comparer.Equals(cred1, cred2), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CredentialsWithDifferentDomainsAreNotEqual()
|
||||
{
|
||||
const string user = "user1";
|
||||
var cred1 = Substitute.For<ICredentialRecord>();
|
||||
cred1.Username.Returns(user);
|
||||
cred1.Domain.Returns("domain1");
|
||||
var cred2 = Substitute.For<ICredentialRecord>();
|
||||
cred2.Username.Returns(user);
|
||||
cred2.Domain.Returns("domain2");
|
||||
Assert.That(_comparer.Equals(cred1, cred2), Is.False);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
mRemoteNGTests/Credential/CredentialRecordTests.cs
Normal file
86
mRemoteNGTests/Credential/CredentialRecordTests.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialRecordTests
|
||||
{
|
||||
private CredentialRecord _credentialRecord;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialRecord = new CredentialRecord
|
||||
{
|
||||
Username = "userHere",
|
||||
Domain = "domainHere",
|
||||
Password = "somepass".ConvertToSecureString()
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IdIsUnique()
|
||||
{
|
||||
var credRecord2 = new CredentialRecord();
|
||||
Assert.That(_credentialRecord.Id, Is.Not.EqualTo(credRecord2.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasUsername()
|
||||
{
|
||||
Assert.That(_credentialRecord.Username, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PasswordIsSecureString()
|
||||
{
|
||||
Assert.That(_credentialRecord.Password, Is.TypeOf<SecureString>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasDomain()
|
||||
{
|
||||
Assert.That(_credentialRecord.Domain, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateWithExistingGuid()
|
||||
{
|
||||
var customGuid = new Guid();
|
||||
_credentialRecord = new CredentialRecord(customGuid);
|
||||
Assert.That(_credentialRecord.Id, Is.EqualTo(customGuid));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyConstructorGeneratesNewGuid()
|
||||
{
|
||||
var cred2 = new CredentialRecord(_credentialRecord);
|
||||
Assert.That(cred2.Id, Is.Not.EqualTo(_credentialRecord.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyConstructorCopiesUsername()
|
||||
{
|
||||
var cred2 = new CredentialRecord(_credentialRecord);
|
||||
Assert.That(cred2.Username, Is.EqualTo(_credentialRecord.Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyConstructorCopiesPassword()
|
||||
{
|
||||
var cred2 = new CredentialRecord(_credentialRecord);
|
||||
Assert.That(cred2.Password, Is.EqualTo(_credentialRecord.Password));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyConstructorCopiesDomain()
|
||||
{
|
||||
var cred2 = new CredentialRecord(_credentialRecord);
|
||||
Assert.That(cred2.Domain, Is.EqualTo(_credentialRecord.Domain));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialRecordTypeConverterTests
|
||||
{
|
||||
private CredentialRecordTypeConverter _converter;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_converter = new CredentialRecordTypeConverter();
|
||||
}
|
||||
|
||||
[TestCase(typeof(Guid), true)]
|
||||
public void CanConvertFrom(Type typeToConvertFrom, bool expectedOutcome)
|
||||
{
|
||||
var actualOutcome = _converter.CanConvertFrom(typeToConvertFrom);
|
||||
Assert.That(actualOutcome, Is.EqualTo(expectedOutcome));
|
||||
}
|
||||
|
||||
[TestCase(typeof(Guid), true)]
|
||||
[TestCase(typeof(ICredentialRecord), true)]
|
||||
public void CanConvertTo(Type typeToConvertFrom, bool expectedOutcome)
|
||||
{
|
||||
var actualOutcome = _converter.CanConvertTo(typeToConvertFrom);
|
||||
Assert.That(actualOutcome, Is.EqualTo(expectedOutcome));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertingToGuidReturnsCorrectValue()
|
||||
{
|
||||
var credRecord = Substitute.For<ICredentialRecord>();
|
||||
credRecord.Id.Returns(Guid.NewGuid());
|
||||
var convertedValue = _converter.ConvertTo(credRecord, typeof(Guid));
|
||||
Assert.That(convertedValue, Is.EqualTo(credRecord.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
90
mRemoteNGTests/Credential/CredentialRepositoryListTests.cs
Normal file
90
mRemoteNGTests/Credential/CredentialRepositoryListTests.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Credential.Repositories;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialRepositoryListTests
|
||||
{
|
||||
private CredentialRepositoryList _credentialCatalog;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialCatalog = new CredentialRepositoryList();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RepositoryListIsInitiallyEmpty()
|
||||
{
|
||||
Assert.That(_credentialCatalog.CredentialProviders, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RepositoryIsInListAfterBeingAdded()
|
||||
{
|
||||
var provider = Substitute.For<ICredentialRepository>();
|
||||
_credentialCatalog.AddProvider(provider);
|
||||
Assert.That(_credentialCatalog.CredentialProviders, Does.Contain(provider));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillNotAddDuplicateRepositories()
|
||||
{
|
||||
var provider1 = Substitute.For<ICredentialRepository>();
|
||||
var provider2 = Substitute.For<ICredentialRepository>();
|
||||
var id = Guid.NewGuid();
|
||||
provider1.Config.Id.Returns(id);
|
||||
provider2.Config.Id.Returns(id);
|
||||
_credentialCatalog.AddProvider(provider1);
|
||||
_credentialCatalog.AddProvider(provider2);
|
||||
Assert.That(_credentialCatalog.CredentialProviders.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RepositoryNotInListAfterBeingRemoved()
|
||||
{
|
||||
var provider1 = Substitute.For<ICredentialRepository>();
|
||||
provider1.Config.Id.Returns(Guid.NewGuid());
|
||||
var provider2 = Substitute.For<ICredentialRepository>();
|
||||
provider2.Config.Id.Returns(Guid.NewGuid());
|
||||
_credentialCatalog.AddProvider(provider1);
|
||||
_credentialCatalog.AddProvider(provider2);
|
||||
_credentialCatalog.RemoveProvider(provider1);
|
||||
Assert.That(_credentialCatalog.CredentialProviders, Is.EquivalentTo(new[] {provider2}));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryingToRemoveRepositoryThatIsntInTheListDoesNothing()
|
||||
{
|
||||
_credentialCatalog.RemoveProvider(Substitute.For<ICredentialRepository>());
|
||||
Assert.That(_credentialCatalog.CredentialProviders, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanRetrieveASpecificCredentialRecord()
|
||||
{
|
||||
var expectedCredential = Substitute.For<ICredentialRecord>();
|
||||
expectedCredential.Id.Returns(new Guid());
|
||||
var repo = Substitute.For<ICredentialRepository>();
|
||||
repo.CredentialRecords.Returns(new List<ICredentialRecord> {expectedCredential});
|
||||
_credentialCatalog.AddProvider(repo);
|
||||
var retrievedCredential = _credentialCatalog.GetCredentialRecord(expectedCredential.Id);
|
||||
Assert.That(retrievedCredential, Is.EqualTo(expectedCredential));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCredentialReturnsNullIfNoRecordFound()
|
||||
{
|
||||
var repo = Substitute.For<ICredentialRepository>();
|
||||
_credentialCatalog.AddProvider(repo);
|
||||
var retrievedCredential = _credentialCatalog.GetCredentialRecord(Guid.NewGuid());
|
||||
Assert.That(retrievedCredential, Is.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user