mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Compare commits
938 Commits
v1.75Hotfi
...
v1.76Alpha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfc45a2904 | ||
|
|
563fdffb67 | ||
|
|
f2e9c5e2c0 | ||
|
|
86a591364c | ||
|
|
2a82485f81 | ||
|
|
e13549d361 | ||
|
|
a85c1bd7d3 | ||
|
|
946679f490 | ||
|
|
b6f27eac18 | ||
|
|
2cc82145a3 | ||
|
|
2dae0f2d8e | ||
|
|
412f6edc36 | ||
|
|
764791b8e5 | ||
|
|
bd20d6ae7d | ||
|
|
8db0bf7bea | ||
|
|
cff6aa72fc | ||
|
|
63ddf06057 | ||
|
|
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 | ||
|
|
5bfc67af4f | ||
|
|
c72d9b544e | ||
|
|
cd34619acd | ||
|
|
f091817d66 | ||
|
|
f2c65314b4 | ||
|
|
a9fcdd3341 | ||
|
|
36a5cc7446 | ||
|
|
14a1a665ef | ||
|
|
ec836e2e79 | ||
|
|
2a677aaf02 | ||
|
|
2a141cd9b3 | ||
|
|
5ade8b208e | ||
|
|
9c5e4f7a7c | ||
|
|
5c785ca1c6 | ||
|
|
b389b20ca3 | ||
|
|
6f1d496a9e | ||
|
|
fe12cb345e | ||
|
|
2607994c4c | ||
|
|
47a02afea6 | ||
|
|
a2e0a0c6f7 | ||
|
|
edac8f764b | ||
|
|
4fa68e3bb0 | ||
|
|
09789e163c | ||
|
|
84c8851ff8 | ||
|
|
95dacdd6da | ||
|
|
37b9e46e96 | ||
|
|
f4b188a9ac | ||
|
|
35c886a59c | ||
|
|
e87a49796f | ||
|
|
7e0b1e479c | ||
|
|
1af2f7848e | ||
|
|
0e7b93771e | ||
|
|
ea5a21e487 | ||
|
|
dc72b87479 | ||
|
|
2f20acfa34 | ||
|
|
4869058f46 | ||
|
|
fa006afd0d | ||
|
|
8e06255758 | ||
|
|
ba57b25cd4 | ||
|
|
4fa9d98171 | ||
|
|
6d19832d01 | ||
|
|
bdaa059fa3 | ||
|
|
f7bfc51735 | ||
|
|
998e156b21 | ||
|
|
491bf850e8 | ||
|
|
9bf53c6b25 | ||
|
|
e2fb49037a | ||
|
|
3291c24c8c | ||
|
|
f0bc375421 | ||
|
|
e3c223dc0a | ||
|
|
53c8b3b66d | ||
|
|
af5000b0f8 | ||
|
|
d5d4fdefc8 | ||
|
|
1caa0c6210 | ||
|
|
5b646617d1 | ||
|
|
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 | ||
|
|
c0c5579027 | ||
|
|
6e7e4a129b | ||
|
|
2293a14a90 | ||
|
|
3e664a7c2c | ||
|
|
30b37951b2 | ||
|
|
0d177d12fe | ||
|
|
f7c8a570f8 | ||
|
|
1814aa86b7 | ||
|
|
d0a5e658d1 | ||
|
|
2cbc1da286 | ||
|
|
75d21231ae | ||
|
|
f2d340a012 | ||
|
|
1b28111c6d | ||
|
|
4f4efcbc23 | ||
|
|
7006d18e93 | ||
|
|
049959b567 | ||
|
|
7cd8c0475e | ||
|
|
207accf21f | ||
|
|
bd1e62abc1 | ||
|
|
d2e33ee423 | ||
|
|
f2934f8453 | ||
|
|
20fb269828 | ||
|
|
cc13707fea | ||
|
|
a9db6a0473 | ||
|
|
282ddb85c7 | ||
|
|
9b27200793 | ||
|
|
0b7d7dac38 | ||
|
|
c2edf314c2 | ||
|
|
2da2d54013 | ||
|
|
f433b911a0 | ||
|
|
8b44815b70 | ||
|
|
788f597a3f | ||
|
|
4ee70acf12 | ||
|
|
e5ccd27fd9 | ||
|
|
d34ad62c8a | ||
|
|
0d0bee674d | ||
|
|
279747d3a4 | ||
|
|
1e4bf38402 | ||
|
|
93d1163c5f | ||
|
|
a3e436e42d | ||
|
|
e824886e19 | ||
|
|
9c724b31de | ||
|
|
a4851c8d81 | ||
|
|
469f48f473 | ||
|
|
c915ac4a74 | ||
|
|
9b74c470da | ||
|
|
0a4935d193 | ||
|
|
5995f6fbef | ||
|
|
0ca15a6c65 | ||
|
|
72193833a9 | ||
|
|
e40ffabe4a | ||
|
|
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 | ||
|
|
5280ef32cd | ||
|
|
59a7e4179b | ||
|
|
bd2054e5a4 | ||
|
|
69be19c02b | ||
|
|
fcffeb5734 | ||
|
|
11b67208f4 | ||
|
|
03e8342c90 | ||
|
|
fcd070066c | ||
|
|
5d79ad527e | ||
|
|
ffc8b5619e | ||
|
|
9be49b3738 | ||
|
|
724488911e | ||
|
|
8ac0bf5865 | ||
|
|
57c1c38d52 | ||
|
|
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 | ||
|
|
714c7eb8d1 | ||
|
|
6790287470 | ||
|
|
94a8a5c753 | ||
|
|
ca4d22602f | ||
|
|
42774a6227 | ||
|
|
7f65bfeebb | ||
|
|
88178a6b6b | ||
|
|
3f9ca1454e | ||
|
|
9a3f1bd5cf | ||
|
|
0186254f74 | ||
|
|
6dc432e6a9 | ||
|
|
01db774e05 | ||
|
|
aaef3dc19c | ||
|
|
bb8009363d | ||
|
|
5fd403cf08 | ||
|
|
168c77eac5 | ||
|
|
bf865cbe5d | ||
|
|
3e3029461b | ||
|
|
c750e0a64e | ||
|
|
fc2662c402 | ||
|
|
29dad51ff7 | ||
|
|
da44bba3fe | ||
|
|
b55e42ba78 | ||
|
|
233a9843d7 | ||
|
|
6184087456 | ||
|
|
237ad2fa3c | ||
|
|
b8037c04d0 | ||
|
|
cdb9c2eddb | ||
|
|
8a284f0767 | ||
|
|
83a57b08ab | ||
|
|
d1a251ff6c | ||
|
|
12f0c826c8 | ||
|
|
4aa5da8c0d | ||
|
|
58509bcf41 | ||
|
|
8aa0eb1d64 | ||
|
|
ece974c1be | ||
|
|
56dd3c32cb | ||
|
|
118e3a3bd3 | ||
|
|
8cd3c2a89f | ||
|
|
9c4672fd68 | ||
|
|
7b851e7ac8 | ||
|
|
6c0b33c0dc | ||
|
|
4d951c9827 | ||
|
|
172232be48 | ||
|
|
d749a13611 | ||
|
|
3998be3f93 | ||
|
|
a381827890 | ||
|
|
eecfe45443 | ||
|
|
ad5eb7b594 | ||
|
|
9ce09eb406 | ||
|
|
9c23f3d1d9 | ||
|
|
3f779b7ceb | ||
|
|
3bc53bd7f8 | ||
|
|
27b61fe9a4 | ||
|
|
4d94c7ac7a | ||
|
|
4eb1125b7b | ||
|
|
496b481c31 | ||
|
|
77120cf156 | ||
|
|
80f11c0f70 | ||
|
|
bee8059cbe | ||
|
|
0f2e72172b | ||
|
|
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 -->
|
||||
|
||||
170
CHANGELOG.TXT
170
CHANGELOG.TXT
@@ -1,4 +1,160 @@
|
||||
1.75.7005 (2017-04-27)
|
||||
1.76.1 Alpha 3 (2018-02-24):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#625: Added ability to import mRemoteNG formatted CSV files
|
||||
#648: The port scan ping timeout is now configurable
|
||||
|
||||
Fixes:
|
||||
------
|
||||
Fixed a few Xml serialization bugs that would occur if boolean values weren't capitalized
|
||||
|
||||
|
||||
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:
|
||||
------
|
||||
@@ -49,6 +205,7 @@ Fixes:
|
||||
#427: Export does not respect filtering user/password/domain
|
||||
|
||||
|
||||
|
||||
1.75 (2017-03-01):
|
||||
|
||||
Known Issue:
|
||||
@@ -60,17 +217,6 @@ File hash check will fail when updating from 1.75 Beta 1 to newer versions.
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#344 - Use SHA512 File Hashes to validate downloads (in the update mechanism & posted to the Downloads page)
|
||||
|
||||
|
||||
1.75 RC1 (2017-01-27):
|
||||
|
||||
Known Issue:
|
||||
------------
|
||||
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
|
||||
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
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
|
||||
|
||||
48
CREDITS.TXT
48
CREDITS.TXT
@@ -11,7 +11,18 @@ 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
|
||||
@@ -44,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
|
||||
@@ -58,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/
|
||||
@@ -70,36 +81,40 @@ 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.68
|
||||
PuTTY
|
||||
Copyright <20> 1997-2017 Simon Tatham
|
||||
MIT License
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/putty/
|
||||
@@ -109,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/
|
||||
@@ -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>
|
||||
@@ -114,18 +114,6 @@
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Portable|x86' ">
|
||||
<DefineConstants>HarvestPath=$(SolutionDir)mRemoteV1\bin\Release Portable;HelpFilesHarvestPath=$(SolutionDir)mRemoteV1\Resources\Help</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>REM Clean the TargetDir
|
||||
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
|
||||
|
||||
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>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<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.
|
||||
@@ -141,4 +129,16 @@ set certPassword=$(CertPassword)
|
||||
:: 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
|
||||
rmdir /S /Q "$(TargetDir)"
|
||||
|
||||
echo $(ConfigurationName) > buildenv.tmp
|
||||
|
||||
REM Harvest bin directory of the mRemoteV1 project
|
||||
"$(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
|
||||
"$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -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" />
|
||||
@@ -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>
|
||||
64
Jenkinsfile
vendored
64
Jenkinsfile
vendored
@@ -3,21 +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 scm
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ node('windows') {
|
||||
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 /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
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 /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,11 @@ node('windows') {
|
||||
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')]) {
|
||||
|
||||
56
README.MD
56
README.MD
@@ -10,38 +10,50 @@
|
||||
|
||||
| Update Channel | Build Status | Downloads |
|
||||
| ---------------|--------------|-----------|
|
||||
| Stable | [](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74) |
|
||||
| Beta | [](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/beta_channel/) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Beta3) |
|
||||
| Development | [](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) | - |
|
||||
|
||||
|
||||
| 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 connect 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)
|
||||
|
||||
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"
|
||||
|
||||
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,42 +1,109 @@
|
||||
#Requires -Version 4.0
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("Stable","Beta","Development")]
|
||||
$UpdateChannel
|
||||
)
|
||||
|
||||
|
||||
|
||||
function New-MsiUpdateFileContent {
|
||||
param (
|
||||
[System.IO.FileInfo]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$MsiFile,
|
||||
|
||||
[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 }
|
||||
|
||||
$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
|
||||
}
|
||||
|
||||
|
||||
function New-ZipUpdateFileContent {
|
||||
param (
|
||||
[System.IO.FileInfo]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ZipFile,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TagName
|
||||
)
|
||||
|
||||
$version = $ZipFile.BaseName -replace "[a-zA-Z-]*"
|
||||
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | % { $_.Hash }
|
||||
|
||||
$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
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
$tag = Read-Host -Prompt 'Tag name'
|
||||
|
||||
Write-Host
|
||||
Write-Host
|
||||
Write-Host
|
||||
# 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"
|
||||
|
||||
Write-Host PORTABLE
|
||||
Write-Host --------
|
||||
$file = Get-ChildItem -Path "$releaseFolder\*.zip" | sort LastWriteTime | select -last 1 | % { $_.FullName }
|
||||
$filename = $file.Split("\") | select -last 1
|
||||
|
||||
$version = $file.tostring().Split("-")[2].trim(".zip")
|
||||
Write-Host Version: $version
|
||||
|
||||
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
|
||||
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
|
||||
|
||||
$hash = Get-FileHash -Algorithm SHA512 $file | % { $_.Hash }
|
||||
Write-Host Checksum: $hash
|
||||
|
||||
|
||||
Write-Host
|
||||
Write-Host
|
||||
Write-Host
|
||||
|
||||
Write-Host MSI
|
||||
Write-Host ---
|
||||
$file = Get-ChildItem -Path "$releaseFolder\*.msi" | sort LastWriteTime | select -last 1 | % { $_.FullName }
|
||||
$filename = $file.Split("\") | select -last 1
|
||||
|
||||
$version = $file.tostring().Split("-")[2].trim(".msi")
|
||||
Write-Host Version: $version
|
||||
|
||||
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
|
||||
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
|
||||
|
||||
Write-Host CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
|
||||
$hash = Get-FileHash -Algorithm SHA512 $file | % { $_.Hash }
|
||||
Write-Host Checksum: $hash
|
||||
# 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
|
||||
221
Tools/github_functions.ps1
Normal file
221
Tools/github_functions.ps1
Normal file
@@ -0,0 +1,221 @@
|
||||
$githubUrl = 'https://api.github.com'
|
||||
# GitHub doesn't support the default powershell protocol (TLS 1.0)
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
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
|
||||
}
|
||||
@@ -37,7 +37,7 @@ Format-Table -AutoSize -Wrap -InputObject @{
|
||||
}
|
||||
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.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 -CertificatePath $CertificatePath
|
||||
& "$PSScriptRoot\rename_installer_with_version.ps1" -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\copy_release_installer.ps1" -SourcePath $TargetDir -DestinationDir (Join-Path -Path $SolutionDir -ChildPath "Release")
|
||||
@@ -39,9 +39,11 @@ Format-Table -AutoSize -Wrap -InputObject @{
|
||||
|
||||
|
||||
& "$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" -SolutionDir $SolutionDir -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.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 -CertificatePath $CertificatePath
|
||||
& "$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
|
||||
@@ -62,137 +62,15 @@ param (
|
||||
)
|
||||
|
||||
|
||||
$githubUrl = 'https://api.github.com'
|
||||
if ($DescriptionIsBase64Encoded) {
|
||||
$Description = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Description)))
|
||||
}
|
||||
|
||||
|
||||
function Publish-Release {
|
||||
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_publishRelease = @{
|
||||
"tag_name" = $TagName
|
||||
"target_commitish" = $TargetCommitish
|
||||
"name" = $ReleaseTitle
|
||||
"body" = $Description
|
||||
"draft" = $IsDraft
|
||||
"prerelease" = $IsPrerelease
|
||||
}
|
||||
|
||||
$req_publishRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body (ConvertTo-Json -InputObject $body_publishRelease -Compress) -ErrorAction Stop
|
||||
$response_publishRelease = ConvertFrom-Json -InputObject $req_publishRelease.Content
|
||||
|
||||
Write-Output $response_publishRelease
|
||||
}
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
|
||||
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-ReleaseAsset {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
$release = Publish-Release -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken
|
||||
$zipUpload = Upload-ReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken
|
||||
$msiUpload = Upload-ReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken
|
||||
$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)
|
||||
@@ -9,7 +9,7 @@ Write-Host $SolutionDir
|
||||
Write-Host $renameTarget
|
||||
|
||||
$targetVersionedFile = "$SolutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
|
||||
$version = &"$SolutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
$version = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
|
||||
|
||||
$renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
[CmdletBinding()]
|
||||
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
@@ -10,21 +12,11 @@ param (
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# Find editbin.exe
|
||||
$path_editBin = @((Resolve-Path -Path "C:\Program Files*\Microsoft Visual Studio*\VC\bin\editbin.exe").Path)[0]
|
||||
|
||||
# Verify editbin certificate
|
||||
$microsoft_cert_thumbprint = "3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC"
|
||||
$editbin_signature = Get-AuthenticodeSignature -FilePath $path_editBin
|
||||
if (($editbin_signature.Status -ne "Valid") -or ($editbin_signature.SignerCertificate.Thumbprint -ne $microsoft_cert_thumbprint)) {
|
||||
Write-Error "Could not validate the signature of editbin.exe - we can not set LargeAddressAware" -ErrorAction Stop
|
||||
}
|
||||
|
||||
|
||||
$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 `"$path_outputExe`""
|
||||
& $path_editBin "/largeaddressaware" "$path_outputExe"
|
||||
Write-Output "Setting LargeAddressAware on binary file:`n`"$path_outputExe`" `nwith:`n`"$path_editBin`""
|
||||
& "$path_editBin" /largeaddressaware "$path_outputExe"
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,8 +1,4 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
31
Tools/signfiles.ps1
Normal file
31
Tools/signfiles.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
$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
|
||||
}
|
||||
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 ""
|
||||
@@ -5,13 +5,25 @@ param (
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# Sign MSI if we are building a release version and the certificate is available
|
||||
# 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"}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
132
mRemoteNGTests/Config/CredentialHarvesterTests.cs
Normal file
132
mRemoteNGTests/Config/CredentialHarvesterTests.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers.Csv;
|
||||
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 mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TreeStructureDeserializedCorrectly()
|
||||
{
|
||||
//Root
|
||||
// |- folder1
|
||||
// | |- Con1
|
||||
// |- Con2
|
||||
var treeModel = new ConnectionTreeModelBuilder().Build();
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var csv = serializer.Serialize(treeModel);
|
||||
var deserializedConnections = _deserializer.Deserialize(csv);
|
||||
var con1 = deserializedConnections.GetRecursiveChildList().First(info => info.Name == "Con1");
|
||||
var folder1 = deserializedConnections.GetRecursiveChildList().First(info => info.Name == "folder1");
|
||||
Assert.That(con1.Parent, Is.EqualTo(folder1));
|
||||
}
|
||||
|
||||
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 = RdpProtocol.AuthenticationLevel.WarnOnFailedAuth,
|
||||
Colors = RdpProtocol.RDPColors.Colors16Bit,
|
||||
Resolution = RdpProtocol.RDPResolutions.Res1366x768,
|
||||
AutomaticResize = true,
|
||||
DisplayWallpaper = true,
|
||||
DisplayThemes = true,
|
||||
EnableFontSmoothing = true,
|
||||
EnableDesktopComposition = true,
|
||||
CacheBitmaps = true,
|
||||
RedirectDiskDrives = true,
|
||||
RedirectPorts = true,
|
||||
RedirectPrinters = true,
|
||||
RedirectSmartCards = true,
|
||||
RedirectSound = RdpProtocol.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 = RdpProtocol.RDGatewayUsageMethod.Detect,
|
||||
RDGatewayUseConnectionCredentials = RdpProtocol.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,156 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Csv;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Csv
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializesNodeId()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var connectionInfo = BuildConnectionInfo();
|
||||
var csv = serializer.Serialize(connectionInfo);
|
||||
Assert.That(csv, Does.Match(connectionInfo.ConstantID));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesntSerializeTheRootNode()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var treeModel = new ConnectionTreeModelBuilder().Build();
|
||||
var csv = serializer.Serialize(treeModel);
|
||||
Assert.That(csv, Does.Not.Match($"{treeModel.RootNodes[0].ConstantID};.*;{TreeNodeType.Root}"));
|
||||
}
|
||||
|
||||
[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));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void FoldersAreSerialized()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var container = BuildContainer();
|
||||
var csv = serializer.Serialize(container);
|
||||
Assert.That(csv, Does.Match(container.Name));
|
||||
Assert.That(csv, Does.Match(container.Username));
|
||||
Assert.That(csv, Does.Match(container.Domain));
|
||||
Assert.That(csv, Does.Match(container.Password));
|
||||
Assert.That(csv, Does.Contain(TreeNodeType.Container.ToString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializationIncludesRawInheritedValuesIfObjectInheritsFromParentOutsideOfSerializationScope()
|
||||
{
|
||||
var serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), _credentialRepositoryList);
|
||||
var treeModel = new ConnectionTreeModelBuilder().Build();
|
||||
var serializationTarget = treeModel.GetRecursiveChildList().First(info => info.Name == "folder3");
|
||||
var csv = serializer.Serialize(serializationTarget);
|
||||
var lineWithFolder3 = csv.Split(new[] {Environment.NewLine}, StringSplitOptions.None).First(s => s.Contains(serializationTarget.Name));
|
||||
Assert.That(lineWithFolder3, Does.Contain(serializationTarget.Username));
|
||||
Assert.That(lineWithFolder3, Does.Contain(serializationTarget.Domain));
|
||||
Assert.That(lineWithFolder3, Does.Contain(serializationTarget.Password));
|
||||
}
|
||||
|
||||
private ConnectionInfo BuildConnectionInfo()
|
||||
{
|
||||
return new ConnectionInfo
|
||||
{
|
||||
Name = ConnectionName,
|
||||
Username = Username,
|
||||
Domain = Domain,
|
||||
Password = Password,
|
||||
Inheritance = {Colors = true}
|
||||
};
|
||||
}
|
||||
|
||||
private ContainerInfo BuildContainer()
|
||||
{
|
||||
return new ContainerInfo
|
||||
{
|
||||
Name = "MyFolder",
|
||||
Username = "BlahBlah1",
|
||||
Domain = "aklkskkksh8",
|
||||
Password = "qweraslkdjf87"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
public class ValidateXmlSchemas
|
||||
{
|
||||
private XmlConnectionsSerializer _serializer;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
private XmlReaderSettings _xmlReaderSettings;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_connectionTreeModel = new ConnectionTreeModelBuilder().Build();
|
||||
_cryptographyProvider = new AeadCryptographyProvider();
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
_cryptographyProvider,
|
||||
_connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(_cryptographyProvider, connectionNodeSerializer);
|
||||
_xmlReaderSettings = new XmlReaderSettings
|
||||
{
|
||||
ValidationType = ValidationType.Schema,
|
||||
ValidationFlags = XmlSchemaValidationFlags.ProcessInlineSchema |
|
||||
XmlSchemaValidationFlags.ProcessSchemaLocation |
|
||||
XmlSchemaValidationFlags.ReportValidationWarnings
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ValidateSchema()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var xml = _serializer.Serialize(_connectionTreeModel);
|
||||
|
||||
var schemaFile = GetTargetPath("mremoteng_confcons_v2_6.xsd");
|
||||
_xmlReaderSettings.Schemas.Add("http://mremoteng.org", schemaFile);
|
||||
_xmlReaderSettings.ValidationEventHandler += (sender, args) =>
|
||||
{
|
||||
sb.AppendLine($"{args.Severity}: {args.Message}");
|
||||
};
|
||||
|
||||
using (var stream = GenerateStreamFromString(xml))
|
||||
{
|
||||
var reader = XmlReader.Create(stream, _xmlReaderSettings);
|
||||
while (reader.Read()) ;
|
||||
}
|
||||
|
||||
Assert.That(sb.ToString(), Is.Empty);
|
||||
}
|
||||
|
||||
public string GetTargetPath(string fileName, [CallerFilePath] string sourceFilePath = "")
|
||||
{
|
||||
const string debugOrRelease =
|
||||
#if DEBUG
|
||||
"Debug";
|
||||
#else
|
||||
"Release";
|
||||
#endif
|
||||
|
||||
const string normalOrPortable =
|
||||
#if PORTABLE
|
||||
" Portable";
|
||||
#else
|
||||
"";
|
||||
#endif
|
||||
var path = Path.GetDirectoryName(sourceFilePath);
|
||||
var filePath = $@"{path}\..\..\..\..\bin\{debugOrRelease}{normalOrPortable}\Schemas\{fileName}";
|
||||
return filePath;
|
||||
}
|
||||
|
||||
private Stream GenerateStreamFromString(string s)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(s);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
@@ -9,7 +10,7 @@ using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
public class XmlConnectionsDeserializerTests
|
||||
{
|
||||
@@ -18,8 +19,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]
|
||||
@@ -104,6 +105,14 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(folder22.Inheritance.Username, Is.True);
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(XmlConnectionsDeserializerFixtureData), nameof(XmlConnectionsDeserializerFixtureData.FixtureParams))]
|
||||
public void ExpandedPropertyGetsDeserialized(Datagram testData)
|
||||
{
|
||||
Setup(testData.ConfCons, testData.Password);
|
||||
var folder1 = GetFolderNamed("Folder1", _connectionTreeModel.GetRecursiveChildList());
|
||||
Assert.That(folder1.IsExpanded, Is.True);
|
||||
}
|
||||
|
||||
private bool ContainsNodeNamed(string name, IEnumerable<ConnectionInfo> list)
|
||||
{
|
||||
return list.Any(node => node.Name == name);
|
||||
@@ -1,16 +1,18 @@
|
||||
using System.Xml.XPath;
|
||||
using System.Linq;
|
||||
using System.Xml.XPath;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
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.Xml
|
||||
{
|
||||
public class XmlConnectionsDocumentCompilerTests
|
||||
public class XmlConnectionsDocumentCompilerTests
|
||||
{
|
||||
private XmlConnectionsDocumentCompiler _documentCompiler;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
@@ -27,23 +29,26 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
var saveFilter = new SaveFilter();
|
||||
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider, saveFilter);
|
||||
_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"));
|
||||
}
|
||||
@@ -51,7 +56,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);
|
||||
}
|
||||
@@ -59,7 +64,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,18 @@
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
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.Xml
|
||||
{
|
||||
public class XmlConnectionsDocumentEncryptorTests
|
||||
public class XmlConnectionsDocumentEncryptorTests
|
||||
{
|
||||
private XmlConnectionsDocumentEncryptor _documentEncryptor;
|
||||
private XDocument _originalDocument;
|
||||
@@ -19,9 +21,12 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
var connectionTreeModel = SetupConnectionTreeModel();
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
var saveFilter = new SaveFilter();
|
||||
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider, saveFilter).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,6 +1,8 @@
|
||||
using System.Xml;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
@@ -9,21 +11,25 @@ using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
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]
|
||||
@@ -50,19 +56,20 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[TestCase("Username", "")]
|
||||
[TestCase("Domain", "")]
|
||||
[TestCase("Password", "")]
|
||||
[TestCase("InheritAutomaticResize", "False")]
|
||||
[TestCase("InheritAutomaticResize", "false")]
|
||||
public void SerializerRespectsSaveFilterSettings(string attributeName, string expectedValue)
|
||||
{
|
||||
_serializer.SaveFilter = new SaveFilter(true);
|
||||
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",
|
||||
Username = "somefilteredstuff",
|
||||
Domain = "somefilteredstuff",
|
||||
Password = "somefilteredstuff",
|
||||
Inheritance = {AutomaticResize = true}
|
||||
};
|
||||
var serializedConnections = _serializer.Serialize(connectionInfo);
|
||||
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));
|
||||
@@ -2,13 +2,14 @@
|
||||
using System.Collections;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
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.Xml
|
||||
{
|
||||
public class XmlRootNodeSerializerTests
|
||||
{
|
||||
@@ -39,19 +40,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 +52,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()));
|
||||
@@ -84,7 +76,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
var element = _rootNodeSerializer.SerializeRootNodeInfo(_rootNodeInfo, _cryptographyProvider, fullFileEncryption);
|
||||
var attributeValue = element.Attribute(XName.Get("FullFileEncryption"))?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo(fullFileEncryption.ToString()));
|
||||
Assert.That(bool.Parse(attributeValue), Is.EqualTo(fullFileEncryption));
|
||||
}
|
||||
|
||||
[TestCase("", "ThisIsNotProtected")]
|
||||
@@ -100,23 +92,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,20 +13,13 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
private DataTableDeserializer _deserializer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeATree()
|
||||
{
|
||||
var model = CreateConnectionTreeModel();
|
||||
var dataTable = CreateDataTable(model.RootNodes[0]);
|
||||
_deserializer = new DataTableDeserializer(dataTable);
|
||||
var output = _deserializer.Deserialize();
|
||||
_deserializer = new DataTableDeserializer();
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
|
||||
}
|
||||
|
||||
@@ -34,8 +27,8 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void WeCanDeserializeASingleEntry()
|
||||
{
|
||||
var dataTable = CreateDataTable(new ConnectionInfo());
|
||||
_deserializer = new DataTableDeserializer(dataTable);
|
||||
var output = _deserializer.Deserialize();
|
||||
_deserializer = new DataTableDeserializer();
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
@@ -26,7 +27,7 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
var model = CreateConnectionTreeModel();
|
||||
var dataTable = _dataTableSerializer.Serialize(model);
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(3));
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(model.GetRecursiveChildList().Count()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -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
|
||||
{
|
||||
// .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 RdpProtocol.RDPColors ExpectedColors = RdpProtocol.RDPColors.Colors24Bit;
|
||||
private const bool ExpectedBitmapCaching = false;
|
||||
private const ProtocolRDP.RDPResolutions ExpectedResolutionMode = ProtocolRDP.RDPResolutions.FitToWindow;
|
||||
private const RdpProtocol.RDPResolutions ExpectedResolutionMode = RdpProtocol.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 RdpProtocol.RDPSounds ExpectedSoundRedirection = RdpProtocol.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 RdpProtocol.RDGatewayUsageMethod ExpectedGatewayUsageMethod = RdpProtocol.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 RdpProtocol.RDPResolutions ExpectedRdpResolution = RdpProtocol.RDPResolutions.FitToWindow;
|
||||
private const RdpProtocol.RDPColors ExpectedRdpColorDepth = RdpProtocol.RDPColors.Colors24Bit;
|
||||
private const RdpProtocol.RDPSounds ExpectedAudioRedirection = RdpProtocol.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 RdpProtocol.AuthenticationLevel ExpectedAuthLevel = RdpProtocol.AuthenticationLevel.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,9 +7,8 @@ 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
|
||||
{
|
||||
@@ -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 RdpProtocol.RDGatewayUsageMethod ExpectedGatewayUsageMethod = RdpProtocol.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 RdpProtocol.RDPResolutions ExpectedRdpResolution = RdpProtocol.RDPResolutions.FitToWindow;
|
||||
private const RdpProtocol.RDPColors ExpectedRdpColorDepth = RdpProtocol.RDPColors.Colors24Bit;
|
||||
private const RdpProtocol.RDPSounds ExpectedAudioRedirection = RdpProtocol.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 RdpProtocol.AuthenticationLevel ExpectedAuthLevel = RdpProtocol.AuthenticationLevel.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,254 +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;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(
|
||||
BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, "myPassword1".ConvertToSecureString(), new SaveFilter());
|
||||
}
|
||||
|
||||
[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);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, "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);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, "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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using mRemoteNG.Connection;
|
||||
using System;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.ICA;
|
||||
@@ -9,9 +10,15 @@ using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
public class AbstractConnectionInfoDataTests
|
||||
public class AbstractConnectionInfoDataTests
|
||||
{
|
||||
private class TestAbstractConnectionInfoData : AbstractConnectionInfoData {}
|
||||
#pragma warning disable 618
|
||||
private class TestAbstractConnectionInfoData : AbstractConnectionRecord {
|
||||
public TestAbstractConnectionInfoData() : base(Guid.NewGuid().ToString())
|
||||
{
|
||||
}
|
||||
}
|
||||
#pragma warning restore 618
|
||||
private TestAbstractConnectionInfoData _testAbstractConnectionInfoData;
|
||||
|
||||
[SetUp]
|
||||
@@ -140,7 +147,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 +165,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RDPAuthenticationLevel = ProtocolRDP.AuthenticationLevel.AuthRequired;
|
||||
_testAbstractConnectionInfoData.RDPAuthenticationLevel = RdpProtocol.AuthenticationLevel.AuthRequired;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -194,7 +201,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RDGatewayUsageMethod = ProtocolRDP.RDGatewayUsageMethod.Always;
|
||||
_testAbstractConnectionInfoData.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Always;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -212,7 +219,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RDGatewayUseConnectionCredentials = ProtocolRDP.RDGatewayUseConnectionCredentials.SmartCard;
|
||||
_testAbstractConnectionInfoData.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.SmartCard;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -248,7 +255,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.Resolution = ProtocolRDP.RDPResolutions.Res1366x768;
|
||||
_testAbstractConnectionInfoData.Resolution = RdpProtocol.RDPResolutions.Res1366x768;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -266,7 +273,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.Colors = ProtocolRDP.RDPColors.Colors16Bit;
|
||||
_testAbstractConnectionInfoData.Colors = RdpProtocol.RDPColors.Colors16Bit;
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
@@ -365,7 +372,7 @@ namespace mRemoteNGTests.Connection
|
||||
{
|
||||
var wasCalled = false;
|
||||
_testAbstractConnectionInfoData.PropertyChanged += (sender, args) => wasCalled = true;
|
||||
_testAbstractConnectionInfoData.RedirectSound = ProtocolRDP.RDPSounds.DoNotPlay;
|
||||
_testAbstractConnectionInfoData.RedirectSound = RdpProtocol.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";
|
||||
@@ -24,22 +27,6 @@ namespace mRemoteNGTests.Connection
|
||||
_connectionInfo = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreatingConnectionInfoWithParentSetsTheParentProperty()
|
||||
{
|
||||
var container = new ContainerInfo();
|
||||
var connectionInfo = new ConnectionInfo(container);
|
||||
Assert.That(connectionInfo.Parent, Is.EqualTo(container));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreatingConnectionInfoWithParentAddsToTheParentsChildList()
|
||||
{
|
||||
var container = new ContainerInfo();
|
||||
var connectionInfo = new ConnectionInfo(container);
|
||||
Assert.That(container.Children, Does.Contain(connectionInfo));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyCreatesMemberwiseCopy()
|
||||
{
|
||||
@@ -48,6 +35,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()
|
||||
{
|
||||
@@ -83,7 +78,29 @@ namespace mRemoteNGTests.Connection
|
||||
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 +116,13 @@ namespace mRemoteNGTests.Connection
|
||||
_connectionInfo.Protocol = protocolType;
|
||||
return _connectionInfo.GetDefaultPort();
|
||||
}
|
||||
|
||||
private class InheritancePropertyProvider
|
||||
{
|
||||
public static IEnumerable<PropertyInfo> GetProperties()
|
||||
{
|
||||
return new ConnectionInfoInheritance(new object()).GetProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
58
mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs
Normal file
58
mRemoteNGTests/Connection/Protocol/IntegratedProgramTests.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Collections.ObjectModel;
|
||||
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 sut = new IntegratedProgram();
|
||||
sut.InterfaceControl = BuildInterfaceControl("notepad", sut);
|
||||
sut.Initialize();
|
||||
var appStarted = sut.Connect();
|
||||
sut.Disconnect();
|
||||
Assert.That(appStarted);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectingToExternalAppThatDoesntExistDoesNothing()
|
||||
{
|
||||
SetExternalToolList(_extTool);
|
||||
var sut = new IntegratedProgram();
|
||||
sut.InterfaceControl = BuildInterfaceControl("doesntExist", 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(string extAppName, ProtocolBase sut)
|
||||
{
|
||||
var connectionWindow = new ConnectionWindow(new DockContent());
|
||||
var connectionInfo = new ConnectionInfo {ExtApp = extAppName};
|
||||
return new InterfaceControl(connectionWindow, sut, connectionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
mRemoteNGTests/Credential/CredentialServiceFacadeTests.cs
Normal file
92
mRemoteNGTests/Credential/CredentialServiceFacadeTests.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Config;
|
||||
using mRemoteNG.Credential;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
// ReSharper disable ObjectCreationAsStatement
|
||||
|
||||
namespace mRemoteNGTests.Credential
|
||||
{
|
||||
public class CredentialServiceFacadeTests
|
||||
{
|
||||
private CredentialServiceFacade _credentialService;
|
||||
private ICredentialRepositoryList _credentialRepositoryList;
|
||||
private ILoader<IEnumerable<ICredentialRepository>> _loader;
|
||||
private ISaver<IEnumerable<ICredentialRepository>> _saver;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
|
||||
_loader = Substitute.For<ILoader<IEnumerable<ICredentialRepository>>>();
|
||||
_saver = Substitute.For<ISaver<IEnumerable<ICredentialRepository>>>();
|
||||
_credentialService = new CredentialServiceFacade(_credentialRepositoryList, _loader, _saver);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullRepoListToCtor()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new CredentialServiceFacade(null, _loader, _saver));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullRepoLoaderToCtor()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new CredentialServiceFacade(_credentialRepositoryList, null, _saver));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullRepoSaverToCtor()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new CredentialServiceFacade(_credentialRepositoryList, _loader, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddRepoCallsUnderlyingList()
|
||||
{
|
||||
var newRepo = Substitute.For<ICredentialRepository>();
|
||||
_credentialService.AddRepository(newRepo);
|
||||
_credentialRepositoryList.Received().AddProvider(newRepo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveRepoCallsUnderlyingList()
|
||||
{
|
||||
var repo = Substitute.For<ICredentialRepository>();
|
||||
_credentialService.RemoveRepository(repo);
|
||||
_credentialRepositoryList.Received().RemoveProvider(repo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCredentialRecordsCallsUnderlyingList()
|
||||
{
|
||||
_credentialService.GetCredentialRecords();
|
||||
_credentialRepositoryList.Received().GetCredentialRecords();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetCredentialRecordCallsUnderlyingList()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
_credentialService.GetCredentialRecord(guid);
|
||||
_credentialRepositoryList.Received().GetCredentialRecord(guid);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadRepoListsAddsRepoFromLoader()
|
||||
{
|
||||
var repo = Substitute.For<ICredentialRepository>();
|
||||
_loader.Load().Returns(new[] { repo });
|
||||
_credentialService.LoadRepositoryList();
|
||||
_credentialRepositoryList.Received().AddProvider(repo);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SaveRepoListsAddsRepoFromLoader()
|
||||
{
|
||||
_credentialService.SaveRepositoryList();
|
||||
_saver.Received().Save(_credentialRepositoryList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,39 +34,39 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
* ------Connection2
|
||||
* ----Connection3 (inherits username)
|
||||
*/
|
||||
var folder1 = new ContainerInfo {Username = "folder1User"};
|
||||
var folder2 = new ContainerInfo {Username = "folder2User"};
|
||||
var folder1 = new ContainerInfo { Icon = "someicon1" };
|
||||
var folder2 = new ContainerInfo { Icon = "someicon2" };
|
||||
var connection1 = new ConnectionInfo();
|
||||
var connection2 = new ConnectionInfo();
|
||||
var connection3 = new ConnectionInfo {Inheritance = {Username = true}};
|
||||
var connection3 = new ConnectionInfo {Inheritance = {Icon = true}};
|
||||
_rootNode.AddChild(folder1);
|
||||
folder1.AddChildRange(new []{connection1, folder2, connection3});
|
||||
folder2.AddChild(connection2);
|
||||
Assert.That(connection3.Username, Is.EqualTo(folder1.Username));
|
||||
Assert.That(connection3.Icon, Is.EqualTo(folder1.Icon));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionWillInheritAllFromFolder()
|
||||
{
|
||||
var folder = new ContainerInfo() {Protocol = ProtocolType.SSH2, Username = "folderUser", Domain = "CoolDomain"};
|
||||
var connection = new ConnectionInfo() {Inheritance = {EverythingInherited = true}};
|
||||
var folder = new ContainerInfo {Protocol = ProtocolType.SSH2, Icon = "someicon", CacheBitmaps = true};
|
||||
var connection = new ConnectionInfo {Inheritance = {EverythingInherited = true}};
|
||||
_rootNode.AddChild(folder);
|
||||
folder.AddChild(connection);
|
||||
Assert.That(new object[] { connection.Protocol, connection.Username, connection.Domain }, Is.EquivalentTo(new object[] {folder.Protocol, folder.Username, folder.Domain}));
|
||||
Assert.That(new object[] { connection.Protocol, connection.Icon, connection.CacheBitmaps }, Is.EquivalentTo(new object[] {folder.Protocol, folder.Icon, folder.CacheBitmaps }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanInheritThroughMultipleFolderLevels()
|
||||
{
|
||||
var folder1 = new ContainerInfo {Username = "folder1User"};
|
||||
var folder2 = new ContainerInfo {Inheritance = {Username = true}};
|
||||
var folder3 = new ContainerInfo {Inheritance = {Username = true}};
|
||||
var connection = new ConnectionInfo {Inheritance = {Username = true}};
|
||||
var folder1 = new ContainerInfo { Icon = "someicon"};
|
||||
var folder2 = new ContainerInfo {Inheritance = { Icon = true}};
|
||||
var folder3 = new ContainerInfo {Inheritance = { Icon = true}};
|
||||
var connection = new ConnectionInfo {Inheritance = { Icon = true}};
|
||||
_rootNode.AddChild(folder1);
|
||||
folder1.AddChild(folder2);
|
||||
folder2.AddChild(folder3);
|
||||
folder3.AddChild(connection);
|
||||
Assert.That(connection.Username, Is.EqualTo(folder1.Username));
|
||||
Assert.That(connection.Icon, Is.EqualTo(folder1.Icon));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.IntegrationTests
|
||||
{
|
||||
public class XmlCredentialSerializerLifeCycleTests
|
||||
{
|
||||
private ISecureSerializer<IEnumerable<ICredentialRecord>, string> _serializer;
|
||||
private ISecureDeserializer<string, IEnumerable<ICredentialRecord>> _deserializer;
|
||||
private readonly Guid _id = Guid.NewGuid();
|
||||
private const string Title = "mycredential1";
|
||||
private const string Username = "user1";
|
||||
private const string Domain = "domain1";
|
||||
private readonly SecureString _key = "myPassword1!".ConvertToSecureString();
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var keyProvider = Substitute.For<IKeyProvider>();
|
||||
keyProvider.GetKey().Returns(_key);
|
||||
var cryptoProvider = new CryptoProviderFactory(BlockCipherEngines.AES, BlockCipherModes.CCM).Build();
|
||||
_serializer = new XmlCredentialPasswordEncryptorDecorator(cryptoProvider, new XmlCredentialRecordSerializer());
|
||||
_deserializer = new XmlCredentialPasswordDecryptorDecorator(new XmlCredentialRecordDeserializer());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanSerializeAndDeserializeXmlCredentials()
|
||||
{
|
||||
var credentials = new[] { new CredentialRecord(), new CredentialRecord() };
|
||||
var serializedCredentials = _serializer.Serialize(credentials, _key);
|
||||
var deserializedCredentials = _deserializer.Deserialize(serializedCredentials, _key);
|
||||
Assert.That(deserializedCredentials.Count(), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IdConsistentAfterSerialization()
|
||||
{
|
||||
var sut = SerializeThenDeserializeCredential();
|
||||
Assert.That(sut.Id, Is.EqualTo(_id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TitleConsistentAfterSerialization()
|
||||
{
|
||||
var sut = SerializeThenDeserializeCredential();
|
||||
Assert.That(sut.Title, Is.EqualTo(Title));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UsernameConsistentAfterSerialization()
|
||||
{
|
||||
var sut = SerializeThenDeserializeCredential();
|
||||
Assert.That(sut.Username, Is.EqualTo(Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DomainConsistentAfterSerialization()
|
||||
{
|
||||
var sut = SerializeThenDeserializeCredential();
|
||||
Assert.That(sut.Domain, Is.EqualTo(Domain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PasswordConsistentAfterSerialization()
|
||||
{
|
||||
var sut = SerializeThenDeserializeCredential();
|
||||
Assert.That(sut.Password.ConvertToUnsecureString(), Is.EqualTo(_key.ConvertToUnsecureString()));
|
||||
}
|
||||
|
||||
private ICredentialRecord SerializeThenDeserializeCredential()
|
||||
{
|
||||
var credentials = new[]
|
||||
{
|
||||
new CredentialRecord(_id) {Title = Title, Username = Username, Domain = Domain, Password = _key}
|
||||
};
|
||||
var serializedCredentials = _serializer.Serialize(credentials, _key);
|
||||
var deserializedCredentials = _deserializer.Deserialize(serializedCredentials, _key);
|
||||
return deserializedCredentials.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
@@ -10,16 +12,23 @@ using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.IntegrationTests
|
||||
{
|
||||
public class XmlSerializationLifeCycleTests
|
||||
public class XmlSerializationLifeCycleTests
|
||||
{
|
||||
private XmlConnectionsSerializer _serializer;
|
||||
private XmlConnectionsDeserializer _deserializer;
|
||||
private ConnectionTreeModel _originalModel;
|
||||
private readonly ICryptoProviderFactory _cryptoFactory = new CryptoProviderFactory(BlockCipherEngines.AES , BlockCipherModes.GCM);
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider);
|
||||
_originalModel = SetupConnectionTreeModel();
|
||||
var cryptoProvider = _cryptoFactory.Build();
|
||||
var nodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
cryptoProvider,
|
||||
_originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -32,52 +41,53 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
[Test]
|
||||
public void SerializeThenDeserialize()
|
||||
{
|
||||
var originalModel = SetupConnectionTreeModel();
|
||||
var serializedContent = _serializer.Serialize(originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer(serializedContent);
|
||||
var deserializedModel = _deserializer.Deserialize();
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeThenDeserializeWithFullEncryption()
|
||||
{
|
||||
var originalModel = SetupConnectionTreeModel();
|
||||
_serializer.UseFullEncryption = true;
|
||||
var serializedContent = _serializer.Serialize(originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer(serializedContent);
|
||||
var deserializedModel = _deserializer.Deserialize();
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeAndDeserializePropertiesWithInternationalCharacters()
|
||||
{
|
||||
var originalConnectionInfo = new ConnectionInfo {Name = "con1", Password = "£°úg¶┬ä" };
|
||||
var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" };
|
||||
var serializedContent = _serializer.Serialize(originalConnectionInfo);
|
||||
_deserializer = new XmlConnectionsDeserializer(serializedContent);
|
||||
var deserializedModel = _deserializer.Deserialize();
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
|
||||
Assert.That(deserializedConnectionInfo.Password, Is.EqualTo(originalConnectionInfo.Password));
|
||||
Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void SerializeAndDeserializeWithCustomKdfIterationsValue()
|
||||
{
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
var cryptoProvider = _cryptoFactory.Build();
|
||||
cryptoProvider.KeyDerivationIterations = 5000;
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider);
|
||||
var originalModel = SetupConnectionTreeModel();
|
||||
var serializedContent = _serializer.Serialize(originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer(serializedContent);
|
||||
var deserializedModel = _deserializer.Deserialize();
|
||||
var nodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
cryptoProvider,
|
||||
_originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,9 @@
|
||||
|
||||
using System.Collections;
|
||||
using System.Windows.Forms;
|
||||
using NUnit.Extensions.Forms;
|
||||
|
||||
namespace NUnit.Extensions.Forms
|
||||
namespace mRemoteNGTests
|
||||
{
|
||||
/// <summary>
|
||||
/// A ControlTester for testing List Views.
|
||||
|
||||
92
mRemoteNGTests/Messages/MessageCollectorTests.cs
Normal file
92
mRemoteNGTests/Messages/MessageCollectorTests.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using mRemoteNG.Messages;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Messages
|
||||
{
|
||||
public class MessageCollectorTests
|
||||
{
|
||||
private MessageCollector _messageCollector;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_messageCollector = new MessageCollector();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InitializesWithNoMessages()
|
||||
{
|
||||
Assert.That(_messageCollector.Messages, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MessageAddedToList()
|
||||
{
|
||||
var message = Substitute.For<IMessage>();
|
||||
_messageCollector.AddMessage(message);
|
||||
Assert.That(_messageCollector.Messages, Does.Contain(message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ListCanBeCleared()
|
||||
{
|
||||
var message = Substitute.For<IMessage>();
|
||||
_messageCollector.AddMessage(message);
|
||||
_messageCollector.ClearMessages();
|
||||
Assert.That(_messageCollector.Messages, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MessagesAreUnique()
|
||||
{
|
||||
var message = Substitute.For<IMessage>();
|
||||
_messageCollector.AddMessage(message);
|
||||
_messageCollector.AddMessage(message);
|
||||
Assert.That(_messageCollector.Messages, Is.Unique);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NotifiedWhenMessageAdded()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_messageCollector.CollectionChanged += (sender, args) => wasCalled = true;
|
||||
var message = Substitute.For<IMessage>();
|
||||
_messageCollector.AddMessage(message);
|
||||
Assert.That(wasCalled, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BatchAddAddsAllItems()
|
||||
{
|
||||
var msg1 = Substitute.For<IMessage>();
|
||||
var msg2 = Substitute.For<IMessage>();
|
||||
var msgCollection = new[] {msg1, msg2};
|
||||
_messageCollector.AddMessages(msgCollection);
|
||||
Assert.That(_messageCollector.Messages, Is.EquivalentTo(msgCollection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OneNotificationRaisedForBatchAdd()
|
||||
{
|
||||
var notificationCount = 0;
|
||||
_messageCollector.CollectionChanged += (sender, args) => notificationCount++;
|
||||
var msg1 = Substitute.For<IMessage>();
|
||||
var msg2 = Substitute.For<IMessage>();
|
||||
_messageCollector.AddMessages(new[] { msg1, msg2 });
|
||||
Assert.That(notificationCount, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EventNotRaisedIfMsgIsntUnique()
|
||||
{
|
||||
var notificationCount = 0;
|
||||
var msg1 = Substitute.For<IMessage>();
|
||||
_messageCollector.AddMessage(msg1);
|
||||
_messageCollector.CollectionChanged += (sender, args) => notificationCount++;
|
||||
_messageCollector.AddMessage(msg1);
|
||||
Assert.That(notificationCount, Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Messages.MessageWriters;
|
||||
using mRemoteNG.Messages.WriterDecorators;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Messages.MessageWriters
|
||||
{
|
||||
public class MessageTypeFilterDecoratorTests
|
||||
{
|
||||
private MessageTypeFilterDecorator _sut;
|
||||
private IMessageWriter _mockWriter;
|
||||
private IMessageTypeFilteringOptions _filter;
|
||||
private IMessage _message;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_mockWriter = Substitute.For<IMessageWriter>();
|
||||
_filter = Substitute.For<IMessageTypeFilteringOptions>();
|
||||
_sut = new MessageTypeFilterDecorator(_filter, _mockWriter);
|
||||
_message = Substitute.For<IMessage>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DebugMessageWrittenIfAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.DebugMsg);
|
||||
_filter.AllowDebugMessages.Returns(true);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.Received().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DebugMessageNotWrittenIfNotAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.DebugMsg);
|
||||
_filter.AllowDebugMessages.Returns(false);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.DidNotReceive().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InfoMessageWrittenIfAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.InformationMsg);
|
||||
_filter.AllowInfoMessages.Returns(true);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.Received().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InfoMessageNotWrittenIfNotAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.InformationMsg);
|
||||
_filter.AllowInfoMessages.Returns(false);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.DidNotReceive().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WarningMessageWrittenIfAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.WarningMsg);
|
||||
_filter.AllowWarningMessages.Returns(true);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.Received().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WarningMessageNotWrittenIfNotAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.WarningMsg);
|
||||
_filter.AllowWarningMessages.Returns(false);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.DidNotReceive().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ErrorMessageWrittenIfAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.ErrorMsg);
|
||||
_filter.AllowErrorMessages.Returns(true);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.Received().Write(_message);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ErrorMessageNotWrittenIfNotAllowed()
|
||||
{
|
||||
_message.Class.Returns(MessageClass.ErrorMsg);
|
||||
_filter.AllowErrorMessages.Returns(false);
|
||||
_sut.Write(_message);
|
||||
_mockWriter.DidNotReceive().Write(_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Messages.MessageWriters;
|
||||
using mRemoteNG.Messages.WriterDecorators;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Messages.MessageWriters
|
||||
{
|
||||
public class OnlyLogMessageFilterTests
|
||||
{
|
||||
private OnlyLogMessageFilter _sut;
|
||||
private IMessageWriter _mockWriter;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_mockWriter = Substitute.For<IMessageWriter>();
|
||||
_sut = new OnlyLogMessageFilter(_mockWriter);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillWriteIfTheOnlyLogFlagIsNotSet()
|
||||
{
|
||||
var msg = Substitute.For<IMessage>();
|
||||
msg.OnlyLog.Returns(false);
|
||||
_sut.Write(msg);
|
||||
_mockWriter.Received().Write(msg);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WillNotWriteIfTheOnlyLogFlagIsSet()
|
||||
{
|
||||
var msg = Substitute.For<IMessage>();
|
||||
msg.OnlyLog.Returns(true);
|
||||
_sut.Write(msg);
|
||||
_mockWriter.DidNotReceiveWithAnyArgs().Write(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user