mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Compare commits
1272 Commits
v1.75RC1
...
release/v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8077149b9 | ||
|
|
51514d78e6 | ||
|
|
42f60b0db3 | ||
|
|
5aec72f164 | ||
|
|
068f5942e7 | ||
|
|
703cefaf19 | ||
|
|
ea1f72b8b7 | ||
|
|
993b6759cc | ||
|
|
15f23769d6 | ||
|
|
2d175fd575 | ||
|
|
bdeb4b4dcc | ||
|
|
bdfbb57504 | ||
|
|
6c89913bc6 | ||
|
|
efa72cb697 | ||
|
|
a31fec5fb9 | ||
|
|
ed81030976 | ||
|
|
54322ca949 | ||
|
|
738b159e95 | ||
|
|
e8f2e4f50c | ||
|
|
5cd201440e | ||
|
|
5c6c76b898 | ||
|
|
4847ce054b | ||
|
|
ec42fe7d7d | ||
|
|
07a20ed5ad | ||
|
|
08201b0f00 | ||
|
|
92416b4661 | ||
|
|
75e0b8f4c2 | ||
|
|
8d29ff2d61 | ||
|
|
eea79da1ae | ||
|
|
cb5447f86e | ||
|
|
8cb31ad524 | ||
|
|
6ca52a0db1 | ||
|
|
25e30672c8 | ||
|
|
abcab2aadf | ||
|
|
19bb8f7595 | ||
|
|
0427956e8b | ||
|
|
78bf40282a | ||
|
|
6c6a82f8e6 | ||
|
|
4b9cc7be08 | ||
|
|
dc2d6b8160 | ||
|
|
083456e33a | ||
|
|
80e43e8634 | ||
|
|
e99b8ed453 | ||
|
|
4aba36b756 | ||
|
|
2ebf654973 | ||
|
|
f560fb86d8 | ||
|
|
21e51c8455 | ||
|
|
3234896caf | ||
|
|
b00dd1c5f5 | ||
|
|
992a3f9d1c | ||
|
|
1c12b52ada | ||
|
|
722fe40899 | ||
|
|
b2e7ebf43d | ||
|
|
3ed8e768aa | ||
|
|
d362691389 | ||
|
|
4b7c54d5b5 | ||
|
|
ec80a5aa70 | ||
|
|
0c95f178ca | ||
|
|
e0405b15df | ||
|
|
e029f30acf | ||
|
|
44ed836b7c | ||
|
|
00401201d1 | ||
|
|
20f46bea61 | ||
|
|
a5d22d287c | ||
|
|
793095900b | ||
|
|
f10e54e47b | ||
|
|
704e0c1dc1 | ||
|
|
0c79a9acde | ||
|
|
ebfc2715e7 | ||
|
|
b0dbc9dc18 | ||
|
|
507cdf75a5 | ||
|
|
8f8492b0be | ||
|
|
457e715188 | ||
|
|
1724521ebf | ||
|
|
b0fb3596aa | ||
|
|
fb228d72b1 | ||
|
|
916361a3be | ||
|
|
408c40f699 | ||
|
|
4173f6d775 | ||
|
|
e6f3c22064 | ||
|
|
a013518eac | ||
|
|
9c88cacb3d | ||
|
|
d49bf04b15 | ||
|
|
1dbd5dc5bc | ||
|
|
c103706a54 | ||
|
|
b0a027df52 | ||
|
|
868641378a | ||
|
|
11baae3107 | ||
|
|
ed8125042e | ||
|
|
25b2655d0f | ||
|
|
145a264154 | ||
|
|
3e33170ae0 | ||
|
|
d18bf68f0e | ||
|
|
368917e108 | ||
|
|
cdea4c3911 | ||
|
|
b4b9b55bbf | ||
|
|
6092c63df4 | ||
|
|
fda5132184 | ||
|
|
6a9fb25a18 | ||
|
|
18d7344690 | ||
|
|
ba50cf20a0 | ||
|
|
7bd6e126e2 | ||
|
|
f7521c81d5 | ||
|
|
f483a2dc2f | ||
|
|
9769d5af06 | ||
|
|
0a2dc3563e | ||
|
|
e9f0157b2b | ||
|
|
e8e566fcdd | ||
|
|
72b7d22cef | ||
|
|
f79da476fd | ||
|
|
ef31b7844c | ||
|
|
f1ed1bf115 | ||
|
|
23ea028965 | ||
|
|
42046a614f | ||
|
|
36055f56e6 | ||
|
|
b693cb30fc | ||
|
|
20377d4ff5 | ||
|
|
570d732b0e | ||
|
|
d9d2b1de70 | ||
|
|
0a7eaaf36f | ||
|
|
36dd3e496d | ||
|
|
83fd914d7b | ||
|
|
281c6b13fa | ||
|
|
00b7b1221c | ||
|
|
56cbf0ff3f | ||
|
|
f852a4d341 | ||
|
|
7c8c7d482a | ||
|
|
9e95ae2cb0 | ||
|
|
0d2d935f17 | ||
|
|
eeb320a825 | ||
|
|
9452d4dbe3 | ||
|
|
03d2387cdd | ||
|
|
61b325ccb9 | ||
|
|
e57de9a4de | ||
|
|
96946f3a1e | ||
|
|
8cd6fb7ae2 | ||
|
|
a5afa90790 | ||
|
|
f634eb8d37 | ||
|
|
694b61a67b | ||
|
|
88f0d00a15 | ||
|
|
e31088fd2e | ||
|
|
1d7bb63710 | ||
|
|
af1ed5349f | ||
|
|
9dcf71dc31 | ||
|
|
8bf9af0ed8 | ||
|
|
aecfad5871 | ||
|
|
3edd155898 | ||
|
|
2c419c0b2e | ||
|
|
2fb67e7042 | ||
|
|
29483b2625 | ||
|
|
7fc59e79f3 | ||
|
|
79b3e21148 | ||
|
|
ee91117010 | ||
|
|
0548037ff3 | ||
|
|
46002632bb | ||
|
|
9659ac1611 | ||
|
|
bbc497e68d | ||
|
|
d7ec7574ad | ||
|
|
2f476d9e61 | ||
|
|
c74f37f0de | ||
|
|
d27a62cbfc | ||
|
|
8029e491a3 | ||
|
|
fe56268421 | ||
|
|
2db6fabbe9 | ||
|
|
035e89801a | ||
|
|
3bdcf655fd | ||
|
|
284755f298 | ||
|
|
ad5eed96e7 | ||
|
|
431c830ea0 | ||
|
|
da047427a5 | ||
|
|
69da1dca5f | ||
|
|
cc61501f63 | ||
|
|
4ced2d3392 | ||
|
|
7c72bfdf6b | ||
|
|
b8878e1458 | ||
|
|
abd40cec1b | ||
|
|
cc18da4f28 | ||
|
|
1a39039162 | ||
|
|
cf9dd72ea5 | ||
|
|
b7cdf81665 | ||
|
|
8497a05fd1 | ||
|
|
7db4eec45c | ||
|
|
cd822b545a | ||
|
|
e872581d3c | ||
|
|
defe9e094c | ||
|
|
5662735cb8 | ||
|
|
8646dce21b | ||
|
|
99a3eabbaf | ||
|
|
c57bd386f2 | ||
|
|
f2a52b03df | ||
|
|
860e1ccfaa | ||
|
|
49967b38d4 | ||
|
|
36038fff6d | ||
|
|
c5958954b0 | ||
|
|
d0d63016ca | ||
|
|
35f2484adf | ||
|
|
c2cf496ded | ||
|
|
8a172f02a9 | ||
|
|
f27935ea61 | ||
|
|
043df0aec3 | ||
|
|
63a2e18760 | ||
|
|
c3ced7ed03 | ||
|
|
f597e14b3d | ||
|
|
aff4ba9115 | ||
|
|
554e0805e3 | ||
|
|
f4efa74a23 | ||
|
|
ddc19587fa | ||
|
|
5f1232727e | ||
|
|
9c373e8f0a | ||
|
|
83942d788f | ||
|
|
73d6fec6f3 | ||
|
|
a37b5deaa1 | ||
|
|
3b9de847e7 | ||
|
|
924f1f1e48 | ||
|
|
7bdebbe25b | ||
|
|
8f46c25dc9 | ||
|
|
8bb4a03639 | ||
|
|
7b5bc5e057 | ||
|
|
35582a5e6a | ||
|
|
20340fd31f | ||
|
|
d6d7664b48 | ||
|
|
ce97e63876 | ||
|
|
378b98ff89 | ||
|
|
ce31199e57 | ||
|
|
227f3b2924 | ||
|
|
5076f1354c | ||
|
|
e5a34388ae | ||
|
|
6a5f65c018 | ||
|
|
6d5f41b3d8 | ||
|
|
64f10ead63 | ||
|
|
575dae446f | ||
|
|
9b438576f2 | ||
|
|
cbd32f1a07 | ||
|
|
516182ec40 | ||
|
|
4ad3a68d80 | ||
|
|
2f9ba32c07 | ||
|
|
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 | ||
|
|
f0faec9def | ||
|
|
e6ef28050c | ||
|
|
547ec3cb3a | ||
|
|
5bfc67af4f | ||
|
|
c72d9b544e | ||
|
|
cd34619acd | ||
|
|
f091817d66 | ||
|
|
f2c65314b4 | ||
|
|
a9fcdd3341 | ||
|
|
36a5cc7446 | ||
|
|
fc0f278962 | ||
|
|
1f3db15892 | ||
|
|
e3e4c49427 | ||
|
|
1520b8bf73 | ||
|
|
c9e7f82905 | ||
|
|
14a1a665ef | ||
|
|
d2357fa779 | ||
|
|
703178ddf1 | ||
|
|
ec836e2e79 | ||
|
|
4e9c5de16c | ||
|
|
2a677aaf02 | ||
|
|
2a141cd9b3 | ||
|
|
3d1fcc35df | ||
|
|
e20d7afb72 | ||
|
|
5ade8b208e | ||
|
|
9c5e4f7a7c | ||
|
|
07e2bc3858 | ||
|
|
5c785ca1c6 | ||
|
|
b389b20ca3 | ||
|
|
6f1d496a9e | ||
|
|
fe12cb345e | ||
|
|
2607994c4c | ||
|
|
47a02afea6 | ||
|
|
a2e0a0c6f7 | ||
|
|
f3b11d6f72 | ||
|
|
edac8f764b | ||
|
|
4fa68e3bb0 | ||
|
|
69f310c02c | ||
|
|
09789e163c | ||
|
|
84c8851ff8 | ||
|
|
95dacdd6da | ||
|
|
3308f1146c | ||
|
|
37b9e46e96 | ||
|
|
8e8cf3df8d | ||
|
|
f4b188a9ac | ||
|
|
35c886a59c | ||
|
|
26fdd924ef | ||
|
|
e87a49796f | ||
|
|
7e0b1e479c | ||
|
|
1af2f7848e | ||
|
|
ea3494f6e7 | ||
|
|
0e7b93771e | ||
|
|
ea5a21e487 | ||
|
|
dc72b87479 | ||
|
|
2f20acfa34 | ||
|
|
4869058f46 | ||
|
|
fa006afd0d | ||
|
|
8e06255758 | ||
|
|
ba57b25cd4 | ||
|
|
4fa9d98171 | ||
|
|
6d19832d01 | ||
|
|
bdaa059fa3 | ||
|
|
f7bfc51735 | ||
|
|
998e156b21 | ||
|
|
491bf850e8 | ||
|
|
9bf53c6b25 | ||
|
|
e2fb49037a | ||
|
|
3291c24c8c | ||
|
|
f0bc375421 | ||
|
|
e3c223dc0a | ||
|
|
53c8b3b66d | ||
|
|
af5000b0f8 | ||
|
|
d5d4fdefc8 | ||
|
|
1caa0c6210 | ||
|
|
5b646617d1 | ||
|
|
9f028d9104 | ||
|
|
f40be696c7 | ||
|
|
95a503a390 | ||
|
|
88c51f4933 | ||
|
|
d63177f3c7 | ||
|
|
e9d41fd01b | ||
|
|
224d2987db | ||
|
|
8439d6d3aa | ||
|
|
13b38955e6 | ||
|
|
ae3fb9a2dd | ||
|
|
9d78d769c4 | ||
|
|
e436a31a18 | ||
|
|
929ade554c | ||
|
|
d6c7066bfa | ||
|
|
2387f183e9 | ||
|
|
e8d645467f | ||
|
|
a8e022cab4 | ||
|
|
579e8abda1 | ||
|
|
4d44440e90 | ||
|
|
709f914561 | ||
|
|
0afa8e092e | ||
|
|
e886619b22 | ||
|
|
fa5f423bbd | ||
|
|
bfbf5c70d5 | ||
|
|
2c19a442a7 | ||
|
|
984ca69e8c | ||
|
|
544d7a15d4 | ||
|
|
858f49d265 | ||
|
|
1b66d446f9 | ||
|
|
6e92fc0505 | ||
|
|
ea84403811 | ||
|
|
65a02795d6 | ||
|
|
c5549367eb | ||
|
|
6aa4a4d205 | ||
|
|
9e20f1dd33 | ||
|
|
16be19b5d3 | ||
|
|
80ac0259b8 | ||
|
|
9f7911923c | ||
|
|
686005071e | ||
|
|
e16d31d605 | ||
|
|
8b201d22cb | ||
|
|
0f6f8d43bd | ||
|
|
8f171cddd9 | ||
|
|
c77c323f73 | ||
|
|
9e358309e4 | ||
|
|
485438f38d | ||
|
|
fe26a60337 | ||
|
|
d2c2de4dd7 | ||
|
|
d49d58f7f8 | ||
|
|
c0c5579027 | ||
|
|
164d4fff8b | ||
|
|
6e7e4a129b | ||
|
|
7726406674 | ||
|
|
ed38b39fec | ||
|
|
9188d4316e | ||
|
|
cf374c6b8b | ||
|
|
82388dcbc3 | ||
|
|
7a6a99e2b6 | ||
|
|
c383736834 | ||
|
|
6e5e78df3b | ||
|
|
311bf1b641 | ||
|
|
5c9933791c | ||
|
|
039d4d11aa | ||
|
|
c0f2d2aa84 | ||
|
|
45099bfa07 | ||
|
|
695ae9d970 | ||
|
|
21eb0064b1 | ||
|
|
513fe402af | ||
|
|
b27e5754e8 | ||
|
|
fa7231d77b | ||
|
|
f5a30ecb33 | ||
|
|
7f22289889 | ||
|
|
f80c39077a | ||
|
|
75c60a1cc4 | ||
|
|
2cf38d6b7c | ||
|
|
482c9c1574 | ||
|
|
882e59a260 | ||
|
|
7a036956b7 | ||
|
|
7520b20cf9 | ||
|
|
d47ccd75d5 | ||
|
|
56ff81a0ed | ||
|
|
8db76f5324 | ||
|
|
a9442ea06e | ||
|
|
92bd0d3ea0 | ||
|
|
512d7322b2 | ||
|
|
45645c439f | ||
|
|
84ebb82cae | ||
|
|
576f6a3bd6 | ||
|
|
96df821eca | ||
|
|
8589778e92 | ||
|
|
a8a7de9ee6 | ||
|
|
1d99340425 | ||
|
|
a8cdfb56f3 | ||
|
|
0958cdaa2d | ||
|
|
ebfb3dd31e | ||
|
|
2293a14a90 | ||
|
|
3e664a7c2c | ||
|
|
30b37951b2 | ||
|
|
0d177d12fe | ||
|
|
f7c8a570f8 | ||
|
|
1814aa86b7 | ||
|
|
d0a5e658d1 | ||
|
|
2cbc1da286 | ||
|
|
75d21231ae | ||
|
|
f2d340a012 | ||
|
|
1b28111c6d | ||
|
|
4f4efcbc23 | ||
|
|
7006d18e93 | ||
|
|
049959b567 | ||
|
|
7cd8c0475e | ||
|
|
207accf21f | ||
|
|
bd1e62abc1 | ||
|
|
d2e33ee423 | ||
|
|
f2934f8453 | ||
|
|
20fb269828 | ||
|
|
cc13707fea | ||
|
|
a9db6a0473 | ||
|
|
282ddb85c7 | ||
|
|
3943b8753f | ||
|
|
9e26ea1866 | ||
|
|
8152a87514 | ||
|
|
b28775c2c6 | ||
|
|
9b27200793 | ||
|
|
0b7d7dac38 | ||
|
|
3eb96ef765 | ||
|
|
8805584cbe | ||
|
|
c2edf314c2 | ||
|
|
2da2d54013 | ||
|
|
f433b911a0 | ||
|
|
8b44815b70 | ||
|
|
788f597a3f | ||
|
|
4ee70acf12 | ||
|
|
be5c66bd93 | ||
|
|
5347e5a3aa | ||
|
|
9b22254b6c | ||
|
|
e5ccd27fd9 | ||
|
|
d34ad62c8a | ||
|
|
0d0bee674d | ||
|
|
279747d3a4 | ||
|
|
1e4bf38402 | ||
|
|
93d1163c5f | ||
|
|
a3e436e42d | ||
|
|
e824886e19 | ||
|
|
9c724b31de | ||
|
|
6a67e0ea8b | ||
|
|
7b118995ea | ||
|
|
35b4564644 | ||
|
|
30df947365 | ||
|
|
b1ec975612 | ||
|
|
a4851c8d81 | ||
|
|
469f48f473 | ||
|
|
c915ac4a74 | ||
|
|
9b74c470da | ||
|
|
1034e434c4 | ||
|
|
0a4935d193 | ||
|
|
5995f6fbef | ||
|
|
0ca15a6c65 | ||
|
|
72193833a9 | ||
|
|
e40ffabe4a | ||
|
|
f419bff545 | ||
|
|
69eec0135e | ||
|
|
a267e32e0e | ||
|
|
92a5249e45 | ||
|
|
fbfe664438 | ||
|
|
b52b5b4287 | ||
|
|
ba3513341a | ||
|
|
de06ce909e | ||
|
|
fa29b746e7 | ||
|
|
5527ebf085 | ||
|
|
cca2052b15 | ||
|
|
ec0338bb30 | ||
|
|
f40a1b6de8 | ||
|
|
7110337dcd | ||
|
|
cbfe850351 | ||
|
|
d6d768029b | ||
|
|
d003e086bb | ||
|
|
a3b66ec456 | ||
|
|
1c3d41c03b | ||
|
|
56b1751c3f | ||
|
|
93724063e2 | ||
|
|
72b8cd2ac8 | ||
|
|
e5b22255e9 | ||
|
|
a4639e295d | ||
|
|
8dc4246c98 | ||
|
|
a187832cdc | ||
|
|
d08a46a573 | ||
|
|
e86fcc9636 | ||
|
|
1f60405d43 | ||
|
|
8f568cc6ac | ||
|
|
4d61820a78 | ||
|
|
b6d49233fb | ||
|
|
beac6be7db | ||
|
|
b99931df95 | ||
|
|
00ba661456 | ||
|
|
2ffde30340 | ||
|
|
f97a84d2df | ||
|
|
c5bb10db4c | ||
|
|
acf4d2f740 | ||
|
|
1c2f6913bb | ||
|
|
31be8bee95 | ||
|
|
2a113efe5c | ||
|
|
801791b4df | ||
|
|
643a2ee739 | ||
|
|
cd9c97ffc0 | ||
|
|
c105319b08 | ||
|
|
d98fa381e8 | ||
|
|
1f39b43869 | ||
|
|
3aeb6a662a | ||
|
|
d7c176d4fd | ||
|
|
cac1df7a66 | ||
|
|
aafa383f56 | ||
|
|
af6e2abdb2 | ||
|
|
05430f7e47 | ||
|
|
2daf4cf46a | ||
|
|
52333beabe | ||
|
|
49d1e0622b | ||
|
|
eebd87c6b7 | ||
|
|
c1b6b30144 | ||
|
|
7703986c9e | ||
|
|
6c272d9336 | ||
|
|
73b0416dbe | ||
|
|
c7760b0ed9 | ||
|
|
c0db476f80 | ||
|
|
7999c29b51 | ||
|
|
1d111a252e | ||
|
|
93d085e23e | ||
|
|
67e0e34f40 | ||
|
|
098e61295c | ||
|
|
1d2666a343 | ||
|
|
b8c2c86c59 | ||
|
|
edf0342404 | ||
|
|
dc6815045c | ||
|
|
23ed1cf5e5 | ||
|
|
97715f260f | ||
|
|
87411ee952 | ||
|
|
d0bbf1e4ad | ||
|
|
3bbd088733 | ||
|
|
d96dd5fe82 | ||
|
|
6028e3f299 | ||
|
|
37bfce1905 | ||
|
|
5993b30ccf | ||
|
|
2fc6c4c0bc | ||
|
|
0195a6bab5 | ||
|
|
ccb35bdc5a | ||
|
|
bfadfaf261 | ||
|
|
d0180a6633 | ||
|
|
afbc580ae6 | ||
|
|
2b2e01f3d1 | ||
|
|
529f1ca835 | ||
|
|
ee7993b918 | ||
|
|
8239a40c72 | ||
|
|
2c9f9a36c5 | ||
|
|
307169fcc3 | ||
|
|
5ee69d24f7 | ||
|
|
077106b71b | ||
|
|
141e660d91 | ||
|
|
be73699013 | ||
|
|
65e3649999 | ||
|
|
994f1ae7ed | ||
|
|
548e633b72 | ||
|
|
87b98e7949 | ||
|
|
5692baf1f3 | ||
|
|
8a10a2aa18 | ||
|
|
797bbf8870 | ||
|
|
edb3f9e885 | ||
|
|
a0008e165b | ||
|
|
3d55b033d6 | ||
|
|
93fb0efc67 | ||
|
|
b7585ef02c | ||
|
|
fce07288e9 | ||
|
|
3ccfdb2e97 | ||
|
|
5840e2ba07 | ||
|
|
4daba88970 | ||
|
|
3180feb874 | ||
|
|
17a430f31f | ||
|
|
20d330f0f1 | ||
|
|
27d0467e08 | ||
|
|
5437967218 | ||
|
|
1228f0572d | ||
|
|
9cf44c3050 | ||
|
|
aa9b641787 | ||
|
|
2e3c4f33a2 | ||
|
|
39ef6ebdbf | ||
|
|
4d08c22204 | ||
|
|
4041dd3ad5 | ||
|
|
a38de8198f | ||
|
|
3369374e43 | ||
|
|
d74631bbdb | ||
|
|
be8c392562 | ||
|
|
f564efb4d6 | ||
|
|
dee9e3c326 | ||
|
|
4ff8d7d68e | ||
|
|
789e467573 | ||
|
|
745b85a3ac | ||
|
|
4f84c2cb01 | ||
|
|
83414acb1d | ||
|
|
356effc6a9 | ||
|
|
88ec186b98 | ||
|
|
530615f049 | ||
|
|
afec12822f | ||
|
|
f117620ead | ||
|
|
1c9f34ba1b | ||
|
|
c26cd9876a | ||
|
|
32f7d37768 | ||
|
|
3873e680e4 | ||
|
|
ddc8a9a286 | ||
|
|
399bde7588 | ||
|
|
5e51febee8 | ||
|
|
6e8200a380 | ||
|
|
fc9961b2de | ||
|
|
d750e3e996 | ||
|
|
1cd15c6f7c | ||
|
|
5c47acbcc3 | ||
|
|
1363c2893b | ||
|
|
cbc426014b | ||
|
|
17178e3ae3 | ||
|
|
b9299d90df | ||
|
|
aff5b46c5e | ||
|
|
2e83f81672 | ||
|
|
e352cc76cf | ||
|
|
cab2ee4fa4 | ||
|
|
bdfc839080 | ||
|
|
6beb21349b | ||
|
|
b2240e8f1a | ||
|
|
32f43d46b5 | ||
|
|
803d689bd3 | ||
|
|
66255bf443 | ||
|
|
338a486513 | ||
|
|
b543343045 | ||
|
|
28c60332e8 | ||
|
|
9ddc45721f | ||
|
|
2849baf857 | ||
|
|
768fdcd0e4 | ||
|
|
5280ef32cd | ||
|
|
59a7e4179b | ||
|
|
bd2054e5a4 | ||
|
|
69be19c02b | ||
|
|
fcffeb5734 | ||
|
|
11b67208f4 | ||
|
|
03e8342c90 | ||
|
|
fcd070066c | ||
|
|
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/)
|
||||
|
||||
38
.github/ISSUE_TEMPLATE.md
vendored
38
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,16 +1,30 @@
|
||||
<!--
|
||||
Only file GitHub issues for bugs and feature requests. All other topics will be closed.
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
Before opening an issue, please search for a duplicate or closed issue.
|
||||
Please provide as much detail as possible for us to fix your issue.
|
||||
-->
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
<!-- Bug -->
|
||||
|||
|
||||
|--:|---|
|
||||
|Operating system | Windows 7 x64 |
|
||||
|mRemoteNG version| 1.75 aplha 3 |
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
<!-- Feature Request -->
|
||||
<!-- If you file a feature request, please delete the bug section -->
|
||||
## Steps to Reproduce (for bugs)
|
||||
<!--- Provide an unambiguous set of steps to reproduce -->
|
||||
<!--- this bug. Include code to reproduce, if relevant -->
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
* Version used:
|
||||
* Operating System and version (e.g. Windows 10 1709 x64):
|
||||
|
||||
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,4 +1,29 @@
|
||||
<!--
|
||||
Please provide as much detail as possible with what your pull request does.
|
||||
Include a reference to a filed issue if it exists.
|
||||
-->
|
||||
<!--- Provide a general summary of your changes in the Title above -->
|
||||
|
||||
## Description
|
||||
<!--- Describe your changes in detail -->
|
||||
|
||||
## Motivation and Context
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
## How Has This Been Tested?
|
||||
<!--- Please describe in detail how you tested your changes. -->
|
||||
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||
<!--- see how your change affects other areas of the code, etc. -->
|
||||
|
||||
## Screenshots (if appropriate):
|
||||
|
||||
## Types of changes
|
||||
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
|
||||
## Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] My code follows the code style of this project.
|
||||
- [ ] My change requires a change to the documentation.
|
||||
- [ ] I have updated the documentation accordingly.
|
||||
- [ ] I have read the **CONTRIBUTING** document.
|
||||
|
||||
401
CHANGELOG.TXT
401
CHANGELOG.TXT
@@ -1,12 +1,409 @@
|
||||
1.75 RC1 (2017-01-27):
|
||||
1.76.20 (2019-04-12):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1401: Connections corrupted when importing RDC Manager files that are missing certain fields
|
||||
|
||||
|
||||
1.76.19 (2019-04-04):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1374: Vertical Scroll Bar missing in PuTTYNG after 0.70.0.1 & 0.71 updates
|
||||
|
||||
|
||||
1.76.18 (2019-03-20):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1365: PuTTY window not centered after 0.71 update
|
||||
|
||||
|
||||
1.76.17 (2019-03-20):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1362: Updated PuTTYNG to 0.71
|
||||
|
||||
|
||||
1.76.16 (2019-03-14):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1347: Remote Desktop Gateway username field encrypted instead of password
|
||||
|
||||
|
||||
1.76.15 (2019-03-09):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1303: Exception on first connection with new SQL server database
|
||||
#1304: Resolved several issues with importing multiple RDP Manager v2.7 files
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
Importing multiple files now only causes 1 save event, rather than 1 per file imported.
|
||||
|
||||
|
||||
1.76.14 (2019-02-08):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#222: Allow FIPS to be enabled
|
||||
|
||||
|
||||
1.76.13 (2018-12-22):
|
||||
|
||||
Changes:
|
||||
--------
|
||||
#222: Pre-Release Test build for running on systems with FIPS Enabled
|
||||
|
||||
|
||||
1.76.12 (2018-11-08):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#1180: Allow saving certain connection properties locally when using database
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1181: Connections sometimes dont immediately load when switching to sql feature
|
||||
#1173: Fixed memory leak when loading connections multiple times
|
||||
#1168: Autohide Connection and Config tab won't open when ssh connection active
|
||||
#1134: Fixed issue where opening a connection opens same connection on other clients when using database feature
|
||||
#449: Encrypt passwords saved to database
|
||||
|
||||
|
||||
1.76.11 (2018-10-18):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1139: Feature "Reconnect to previously opened sessions" not working
|
||||
#1136: Putty window not maximized
|
||||
|
||||
|
||||
1.76.10 (2018-10-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1124: Enabling themes causes an exception
|
||||
|
||||
|
||||
1.76.9 (2018-10-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1117: Duplicate panel created when "Reconnect on Startup" and "Create Empty Panel" settings enabled
|
||||
#1115: Exception when changing from xml data storage to SQL
|
||||
#1110: Pressing Delete button during connection rename attempts to delete the connection instead of the text
|
||||
#1106: Inheritance does not work when parent has C# default type set
|
||||
#1092: Invalid Cast Exceptions loading default connectioninfo
|
||||
#1091: Minor themeing issues
|
||||
#853: Added some additional safety checks and logging to help address RDP crashes
|
||||
|
||||
|
||||
1.76.8 (2018-08-25):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1088: Delete and Launch buttons are not disabled when last external tool deleted
|
||||
#1087: 'Save connections after every edit' setting not honored
|
||||
#1082: Connections not given GUID if Id is empty in connection xml
|
||||
|
||||
|
||||
1.76.7 (2018-08-22):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1076: Wrong object selected when duplicating connection then switching between properties and inheritance in config window
|
||||
#1068: Fixed some toolbar positioning bugs
|
||||
|
||||
|
||||
1.76.6 (2018-08-03):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1062: Entering correct password when starting app does not load connections file
|
||||
|
||||
1.76.5 (2018-08-02):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1057: Hitting F2 with no connection node selected caused unhandled exception
|
||||
#1052: 'Switch to notification panel' feature does not always switch
|
||||
#1051: Tooltips always displayed regardless of 'Show description tooltips in connection tree' setting
|
||||
#1050: Config window retains access to previously selected node after loading new connections file
|
||||
#1045: Config window shows several incorrect properties for HTTPS connections
|
||||
#1040: Canceling "select panel" form does not cancel
|
||||
#1039: Set default theme when themes disabled
|
||||
#1038: Unable to add connection with active filter
|
||||
#1036: Exception when themes are active and options page closed on Connections then reopened
|
||||
#1034: Connection context menu not being translated
|
||||
#1030: Exception thrown if importing from port scan and no tree node is selected
|
||||
#1020: BackupFileKeepCount setting not limiting backup file count
|
||||
#1004: Duplicating root or PuTTy node through hotkey causes unhandled exception
|
||||
#1002: Disabling filtering without clearing keyword leaves filtered state
|
||||
#1001: Connection tree context menu hotkeys stop working and disappear in some cases
|
||||
#999: Some hotkeys stop working if File menu was called when PuTTy Saved Sessions was selected
|
||||
#998: Can sometimes add connection under PuTTY Sessions node
|
||||
#991: Error when deleting host in filtered view
|
||||
#971: Portable Settings now apply to any machine they are used on
|
||||
#961: Connections file overwritten if correct decryption password not provided
|
||||
#893: Removed unneeded files from build/package
|
||||
#868: if statement returned the same value
|
||||
#762: Increased button size to fit locaized text
|
||||
|
||||
|
||||
1.76.4 Alpha 6 (2018-06-03):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#948: Fixed issue where many menu item translations were not being used
|
||||
#942: Improved Russian translation of several items
|
||||
#924: Notification for "No Host Specified" when clicking folders in quick-connect menu
|
||||
#902: Menu bar can once again be moved. View -> "Lock toolbar positions" now also locks the menu position
|
||||
Added option for creating an empty panel on startup
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#938: Minor layout improvements on the Port Scan screen
|
||||
#916: Default properties were not being saved
|
||||
|
||||
|
||||
1.76.3 Alpha 5 (2018-03-14):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#911: Csv exports sometimes do not include all fields
|
||||
#807: Inheritance is sometimes turned on for nodes under root Connections node
|
||||
|
||||
|
||||
1.76.2 Alpha 4 (2018-03-03):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#899: DoNotPlay is Case Sensitive in XML Serialization
|
||||
|
||||
|
||||
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:
|
||||
------
|
||||
#410: Update PuTTYNG to 0.68
|
||||
#434: Fix complier warnings CA1049 & CA2111
|
||||
#442: Fixed issue loading PuTTY sessions that have spaces in the name
|
||||
#502: Problems with ParentID for Duplicated Containers/Connections with SQL Connection Storage
|
||||
#514: Expanded property not saved/loaded properly from SQL
|
||||
#518: Exception when Importing File
|
||||
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
Minor code cleanup/optimizations/null checks
|
||||
|
||||
|
||||
1.75.7003 (2017-03-24):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#464: Resolved issue when importing a connections file while using SQL server feature
|
||||
|
||||
|
||||
1.75.7002 (2017-03-10):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#448: Resolved issue with SQL saving
|
||||
|
||||
|
||||
1.75.7001 (2017-03-10):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#408: Update SQL scripts
|
||||
|
||||
|
||||
1.75 hotfix 1 (2017-03-06):
|
||||
|
||||
General Changes:
|
||||
----------------
|
||||
#437: Modify version numbering scheme
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#422: Uncaught exception when clicking in connection tree whitespace
|
||||
#312: Resolved KeePass auto-type issue
|
||||
#427: Export does not respect filtering user/password/domain
|
||||
|
||||
|
||||
|
||||
1.75 (2017-03-01):
|
||||
|
||||
Known Issue:
|
||||
------------
|
||||
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
|
||||
File hash check will fail when updating from 1.75 Beta 1 to newer versions.
|
||||
Exception will be: "MD5 Hashes didn't match!" for 1.75 Beta 1 - 1.75 RC1
|
||||
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#344 - Use SHA512 File Hashes to validate downloads (in the update mechanism & posted to the Downloads page)
|
||||
Added Release Channels to the update check functionality allowing users to select one of 3 release channels for updates: Stable, Beta, Dev
|
||||
#360: Help -> About, Version # is now selectable/copyable
|
||||
#221: RDP: Optional disconnect after X number of minutes of inactivity
|
||||
|
||||
54
CREDITS.TXT
54
CREDITS.TXT
@@ -11,7 +11,20 @@ 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
|
||||
Vladimir Semenov (github.com/sli-pro)
|
||||
Stephan (github.com/st-schuler)
|
||||
|
||||
|
||||
Past Contributors
|
||||
@@ -44,12 +57,18 @@ 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
|
||||
Vladimir Semenov (github.com/sli-pro)
|
||||
Marco Sousa (github.com/marcomsousa)
|
||||
|
||||
|
||||
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 +77,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,37 +85,41 @@ IP TextBox
|
||||
Copyright <20> 2005 mawnkay
|
||||
http://www.codeproject.com/Articles/11576/IP-TextBox
|
||||
|
||||
PortableSettingsProvider
|
||||
Copyright <20> 2014 crdx
|
||||
https://github.com/crdx/PortableSettingsProvider
|
||||
|
||||
|
||||
Included Components
|
||||
===================
|
||||
|
||||
ADTree 1.0
|
||||
ADTree
|
||||
Copyright <20> 2004 Marc Merritt
|
||||
Copyright <20> 2008 Felix Deimel
|
||||
http://www.codeproject.com/KB/selection/ADPickerCtrl.aspx
|
||||
|
||||
DockPanel Suite 2.10.0
|
||||
DockPanel Suite
|
||||
Copyright <20> 2016 @roken and @lextm (formerly Weifen Luo)
|
||||
MIT License
|
||||
https://github.com/dockpanelsuite/dockpanelsuite
|
||||
|
||||
GeckoFX 45
|
||||
GeckoFX
|
||||
Copyright <20> 2016 Tom Hindle
|
||||
Mozilla Public License
|
||||
https://bitbucket.org/geckofx/
|
||||
|
||||
log4net 1.2.15.0
|
||||
log4net
|
||||
Copyright <20> 2001-2015 The Apache Software Foundation
|
||||
Apache License Version 2.0
|
||||
http://logging.apache.org/log4net/
|
||||
|
||||
Magic Library 1.7.4
|
||||
Magic Library
|
||||
Copyright <20> 2002-2003 Crownwood Consulting, Ltd.
|
||||
Freely redistributable with attribution
|
||||
http://www.dotnetmagic.com/magic_download.html
|
||||
|
||||
PuTTY 0.67
|
||||
Copyright <20> 1997-2016 Simon Tatham
|
||||
PuTTY
|
||||
Copyright <20> 1997-2017 Simon Tatham
|
||||
MIT License
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/putty/
|
||||
|
||||
@@ -109,12 +128,17 @@ Copyright
|
||||
Creative Commons Attribution 2.5 License
|
||||
http://www.famfamfam.com/
|
||||
|
||||
SSH.NET v2016.0.0
|
||||
SSH.NET
|
||||
Copyright <20> 2016
|
||||
MIT License
|
||||
https://github.com/sshnet/SSH.NET
|
||||
|
||||
VncSharp 1.1
|
||||
VncSharp
|
||||
Copyright <20> 2004-2009 David Humphrey
|
||||
GNU General Public License (GPL) Version 2
|
||||
https://github.com/humphd/VncSharp
|
||||
|
||||
ObjectListView
|
||||
Copyright <20> 2006-2016 Phillip Piper
|
||||
GNU General Public License (GPL) Version 3
|
||||
https://sourceforge.net/projects/objectlistview/
|
||||
@@ -17,7 +17,7 @@
|
||||
<?define RequiredDotNetFrameworkServicePackLevel = "" ?>
|
||||
<?define RequiredDotNetFrameworkVersion = "$(var.RequiredDotNetFrameworkMajorVersion).$(var.RequiredDotNetFrameworkMinorVersion)" ?>
|
||||
<?define Rdp80Kb = "KB2592687" ?>
|
||||
<?define Rdp81Kb = "KB2923545" ?>
|
||||
<?define Rdp81Kb = "KB2830477" ?>
|
||||
<?define MinimumRdpKb = $(var.Rdp80Kb) ?>
|
||||
<?define RdpDtlsKb = "KB2574819" ?>
|
||||
<?define IGNOREPREREQUISITES = 0 ?>
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
<Compile Include="mRemoteNGV1.wxs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Dependencies\PuTTYNG.exe">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Filters\Harvest_Filter.xslt" />
|
||||
<Content Include="Includes\Config.wxi" />
|
||||
<Content Include="Resources\header.bmp" />
|
||||
@@ -57,7 +54,6 @@
|
||||
<Folder Include="Localizations" />
|
||||
<Folder Include="Filters" />
|
||||
<Folder Include="bin" />
|
||||
<Folder Include="Dependencies" />
|
||||
<Folder Include="Resources" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -68,6 +64,10 @@
|
||||
<EmbeddedResource Include="Localizations\en-US.wxl" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WixExtension Include="WixUtilExtension">
|
||||
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
|
||||
<Name>WixUtilExtension</Name>
|
||||
</WixExtension>
|
||||
<WixExtension Include="WixUIExtension">
|
||||
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
|
||||
<Name>WixUIExtension</Name>
|
||||
@@ -115,20 +115,19 @@
|
||||
<DefineConstants>HarvestPath=$(SolutionDir)mRemoteV1\bin\Release Portable;HelpFilesHarvestPath=$(SolutionDir)mRemoteV1\Resources\Help</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>set /p buildenv=<buildenv.tmp
|
||||
<PostBuildEvent>:: When passing paths to powershell scripts, check if the path ends with a backslash "\"
|
||||
:: If it does, then the backslash may be interpreted as an escape character. Add another backslash to cancel the first one.
|
||||
|
||||
REM Sign MSI
|
||||
IF EXIST C:\mRemoteNG_code_signing_cert.pfx (
|
||||
IF %25buildenv: Portable=%25==Release (
|
||||
powershell "&""$(SolutionDir)Tools\signfiles.ps1""" %27%25cd%25%27
|
||||
)
|
||||
)
|
||||
powershell -noprofile -command "sleep 2"
|
||||
set /p buildenv=<buildenv.tmp
|
||||
set solutionDir=$(SolutionDir)\
|
||||
set targetDir=%25cd%25
|
||||
set psScriptsDir=$(SolutionDir)Tools
|
||||
set certPath=$(CertPath)
|
||||
set certPassword=$(CertPassword)
|
||||
|
||||
REM Rename MSI to include version number
|
||||
powershell -ExecutionPolicy Bypass -File "$(SolutionDir)Tools\rename_installer_with_version.ps1" $(SolutionDir)
|
||||
|
||||
REM Copy MSI to Release folder
|
||||
IF %25buildenv: Portable=%25==Release (powershell -ExecutionPolicy Bypass -File "$(SolutionDir)Tools\copy_release_installer.ps1" $(TargetDir) $(SolutionDir)Release)</PostBuildEvent>
|
||||
:: Call the post build powershell script
|
||||
powershell.exe -ExecutionPolicy Bypass -File "%25psScriptsDir%25\postbuild_installer.ps1" -SolutionDir "%25solutionDir%25" -TargetDir "%25targetDir%25" -TargetFileName "mRemoteNG.exe" -ConfigurationName "%25buildenv%25" -CertificatePath "%25certPath%25" -CertificatePassword "%25certPassword%25"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>REM Clean the TargetDir
|
||||
@@ -137,9 +136,9 @@ rmdir /S /Q "$(TargetDir)"
|
||||
echo $(ConfigurationName) > buildenv.tmp
|
||||
|
||||
REM Harvest bin directory of the mRemoteV1 project
|
||||
call "$(WIX)bin\heat.exe" dir "$(SolutionDir)mRemoteV1\bin\$(Configuration)" -ag -dr INSTALLDIR -var var.HarvestPath -srd -cg MandatoryComponents -template fragment -out "$(ProjectDir)Fragments\FilesFragment.wxs" -t "$(ProjectDir)Filters\Harvest_Filter.xslt" -v
|
||||
"$(WIX)bin\heat.exe" dir "$(SolutionDir)mRemoteV1\bin\$(Configuration)" -ag -nologo -dr INSTALLDIR -var var.HarvestPath -srd -cg MandatoryComponents -template fragment -out "$(ProjectDir)Fragments\FilesFragment.wxs" -t "$(ProjectDir)Filters\Harvest_Filter.xslt"
|
||||
|
||||
REM Convert the license file "COPYING.TXT" to "License.rtf" to be shown in the installer GUI
|
||||
call "$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
|
||||
"$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -6,7 +6,7 @@
|
||||
<String Id="Install_NeedToBeAdminToInstall">You need to be an administrator to install this product.</String>
|
||||
<String Id="Install_NeedDotNetFrameworkVersion">mRemoteNG requires Microsoft .NET Framework [REQUIREDDOTNETFRAMEWORKVERSION] or higher.</String>
|
||||
<String Id="Install_OSVersionRequirement">mRemoteNG requires Windows 7 SP1 or higher to run. Please update your operating system and try again.</String>
|
||||
<String Id="Install_RDP80Requirement">mRemoteNG requires RDP 8.0 or higher to run. Windows 7 users will need to install KB2592687</String>
|
||||
<String Id="Install_RDP80Requirement">mRemoteNG requires RDP 8.0 or higher to run. Windows 7 users will need to install either KB2592687 (RDP 8.0) or KB2830477 (RDP 8.1)</String>
|
||||
<String Id="Install_RDPDtlsRequirement">mRemoteNG requires KB2574819 in order to create RDP connections. Windows 7 users will need to install this KB.</String>
|
||||
<String Id="Install_Win7RequiresSP1">For mRemoteNG to run on Windows 7, it requires Service Pack 1 to be installed. Please install Service Pack 1 and try again.</String>
|
||||
|
||||
@@ -22,6 +22,6 @@
|
||||
<String Id="Feature_StartMenuShortcut">Start menu shortcut</String>
|
||||
|
||||
<!-- GUI Page Text -->
|
||||
<String Id="FinishPage_LaunchMremoteNow" Overridable="yes">Launch [ProductName] Now</String>
|
||||
<String Id="FinishPage_LaunchMremoteNow" Overridable="yes">Launch mRemoteNG Now</String>
|
||||
|
||||
</WixLocalization>
|
||||
@@ -10,6 +10,7 @@
|
||||
<MajorUpgrade DowngradeErrorMessage="!(loc.Upgrade_NewerVersionInstalled)" Schedule="afterInstallExecute" />
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
<Binary Id="CustomActions.CA.dll" SourceFile="$(var.SolutionDir)InstallerProjects\CustomActions\bin\$(var.Configuration)\CustomActions.CA.dll" />
|
||||
<Property Id="MsiLogging" Value="v" />
|
||||
<Property Id="ARPPRODUCTICON" Value="mRemoteNG.ico" />
|
||||
<Property Id="ARPHELPLINK" Value="http://www.mremoteng.org" />
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize" />
|
||||
@@ -67,7 +68,7 @@
|
||||
<Condition Message="!(loc.Install_RDPDtlsRequirement)">
|
||||
<![CDATA[Installed OR (IGNOREPREREQUISITES = 1) OR (VersionNT >= 602 OR VersionNT64 >= 602) OR ((VersionNT = 601 OR VersionNT64 = 601) AND (RDP_DTLS_UPDATE_INSTALLED = 1))]]>
|
||||
</Condition>
|
||||
<!-- If Win7, require RDP 8.0 update (KB2592687) -->
|
||||
<!-- If Win7, require RDP 8.0 (KB2592687) or 8.1 (KB2830477) update -->
|
||||
<Condition Message="!(loc.Install_RDP80Requirement)">
|
||||
<![CDATA[Installed OR (IGNOREPREREQUISITES = 1) OR (VersionNT >= 602 OR VersionNT64 >= 602) OR ((VersionNT = 601 OR VersionNT64 = 601) AND (MINIMUM_RDP_VERSION_INSTALLED = 1))]]>
|
||||
</Condition>
|
||||
@@ -95,10 +96,22 @@
|
||||
</Feature>
|
||||
</Feature>
|
||||
|
||||
<UI>
|
||||
<UIRef Id="WixUI_FeatureTree"/>
|
||||
<UIRef Id="WixUI_ErrorProgressText" />
|
||||
<Publish Dialog="ExitDialog"
|
||||
Control="Finish"
|
||||
Event="DoAction"
|
||||
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
|
||||
</UI>
|
||||
|
||||
<UIRef Id="WixUI_FeatureTree"/>
|
||||
<WixVariable Id="WixUILicenseRtf" Value="Resources\License.rtf" />
|
||||
<WixVariable Id="WixUIDialogBmp" Value="Resources\welcome.bmp" />
|
||||
<WixVariable Id="WixUIBannerBmp" Value="Resources\header.bmp" />
|
||||
|
||||
<!-- Provide option to run app after install -->
|
||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="!(loc.FinishPage_LaunchMremoteNow)" />
|
||||
<Property Id="WixShellExecTarget" Value="[#MainExeFile]" />
|
||||
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
|
||||
</Product>
|
||||
</Wix>
|
||||
68
Jenkinsfile
vendored
68
Jenkinsfile
vendored
@@ -1,23 +1,63 @@
|
||||
#!groovy
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
|
||||
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def reportGeneratorPath = "${jobDir}\\packages\\ReportGenerator.3.0.2\\tools\\ReportGenerator.exe"
|
||||
def testResultFilePrefix = "TestResult"
|
||||
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"
|
||||
def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml"
|
||||
def testResultFileAcceptance = "${testResultFilePrefix}_AcceptanceTests.xml"
|
||||
def coverageReport = "code_coverage_report.xml"
|
||||
def codeCoverageHtml = "CodeCoverageReport.html"
|
||||
|
||||
stage 'Checkout Branch'
|
||||
checkout scm
|
||||
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 "\"${msBuild}\" /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 "\"${msBuild}\" /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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
71
Jenkinsfile_publish.groovy
Normal file
71
Jenkinsfile_publish.groovy
Normal file
@@ -0,0 +1,71 @@
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def testResultFilePrefix = "TestResult"
|
||||
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"
|
||||
def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml"
|
||||
def coverageReport = "code_coverage_report.xml"
|
||||
|
||||
|
||||
stage ('Clean output dir') {
|
||||
bat script: "rmdir /S /Q \"${jobDir}\\Release\" 2>nul", returnStatus: true
|
||||
}
|
||||
|
||||
stage ('Checkout Branch') {
|
||||
checkout([
|
||||
$class: 'GitSCM',
|
||||
branches: [[name: '*/${TargetBranch}']],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
submoduleCfg: [],
|
||||
userRemoteConfigs: [[
|
||||
credentialsId: '9c3fbff4-5b90-402f-a298-00e607fcec87',
|
||||
url: 'https://github.com/mRemoteNG/mRemoteNG.git'
|
||||
]]
|
||||
])
|
||||
}
|
||||
|
||||
stage ('Restore NuGet Packages') {
|
||||
def nugetPath = "C:\\nuget.exe"
|
||||
bat "${nugetPath} restore ${solutionFilePath}"
|
||||
}
|
||||
|
||||
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
|
||||
stage ('Build mRemoteNG (Normal - MSI)') {
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Normal - MSI)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86"
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86"
|
||||
}
|
||||
|
||||
stage ('Generate UpdateCheck Files') {
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\""
|
||||
archiveArtifacts artifacts: "Release\\*.txt", caseSensitive: false, onlyIfSuccessful: true
|
||||
}
|
||||
|
||||
stage ('Publish to GitHub') {
|
||||
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
|
||||
def releaseFolder = "${jobDir}\\Release"
|
||||
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell
|
||||
def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString()
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ReleaseFolderPath \"${releaseFolder}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
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.7012) |
|
||||
| Beta | | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7012) |
|
||||
| Development | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76Alpha5) |
|
||||
|
||||
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/)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (C) 1999-2016 Igor Pavlov.
|
||||
Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
7-Zip Extra files are under the GNU LGPL license.
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
7-Zip Extra history
|
||||
-------------------
|
||||
|
||||
This file contains only information about changes related to that package exclusively.
|
||||
The full history of changes is listed in history.txt in main 7-Zip program.
|
||||
|
||||
|
||||
18.05 2018-04-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased
|
||||
by 8% for fastest/fast compression levels and
|
||||
by 3% for normal/maximum compression levels.
|
||||
|
||||
|
||||
18.03 beta 2018-03-04
|
||||
-------------------------
|
||||
- The speed for single-thread LZMA/LZMA2 decoding
|
||||
was increased by 30% in x64 version and by 3% in x86 version.
|
||||
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
|
||||
if there are multiple independent data chunks in LZMA2 stream.
|
||||
|
||||
|
||||
9.35 beta 2014-12-07
|
||||
------------------------------
|
||||
- SFX modules were moved to LZMA SDK package.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
7-Zip Extra 16.02
|
||||
7-Zip Extra 18.05
|
||||
-----------------
|
||||
|
||||
7-Zip Extra is package of extra modules of 7-Zip.
|
||||
|
||||
7-Zip Copyright (C) 1999-2016 Igor Pavlov.
|
||||
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
7-Zip is free software. Read License.txt for more information about license.
|
||||
|
||||
|
||||
114
Tools/CreateBulkConnections_ConfCons2_6.ps1
Normal file
114
Tools/CreateBulkConnections_ConfCons2_6.ps1
Normal file
@@ -0,0 +1,114 @@
|
||||
#####################################
|
||||
# Author: David Sparer
|
||||
# Summary:
|
||||
# This is intended to be a template for creating connections in bulk. This uses the serializers directly from the mRemoteNG binaries.
|
||||
# You will still need to create the connection info objects, but the library will handle serialization. It is expected that you
|
||||
# are familiar with PowerShell. If this is not the case, reach out to the mRemoteNG community for help.
|
||||
# Usage:
|
||||
# Replace or modify the examples that are shown toward the end of the script to create your own connection info objects.
|
||||
#####################################
|
||||
|
||||
$EncryptionKey = (Get-Credential -Message "Enter the encryption key you would like to use. This must match the encryption key used by the rest of the confCons file." -UserName "DontNeedUsername").Password
|
||||
$PathToMrngFolder = ""
|
||||
|
||||
if ($PathToMrngFolder -eq "") {
|
||||
Write-Error -Message 'You must set the $PathToMrngFolder variable in this script to the folder which contains mRemoteNG.exe'
|
||||
}
|
||||
|
||||
$assembly = [System.Reflection.Assembly]::LoadFile((Join-Path -Path $PathToMrngFolder -ChildPath "mRemoteNG.exe"))
|
||||
$assembly = [System.Reflection.Assembly]::LoadFile((Join-Path -Path $PathToMrngFolder -ChildPath "BouncyCastle.Crypto.dll"))
|
||||
|
||||
function New-mRemoteNGXmlSerializer {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[SecureString]
|
||||
$EncryptionKey
|
||||
)
|
||||
|
||||
PROCESS {
|
||||
$cryptoProvider = New-Object -TypeName mRemoteNG.Security.SymmetricEncryption.AeadCryptographyProvider
|
||||
$saveFilter = New-Object -TypeName mRemoteNG.Security.SaveFilter -ArgumentList @($false)
|
||||
$xmlSerializer = New-Object -TypeName mRemoteNG.Config.Serializers.XmlConnectionNodeSerializer -ArgumentList @($cryptoProvider, $encryptionKey, $saveFilter)
|
||||
Write-Output $xmlSerializer
|
||||
}
|
||||
}
|
||||
|
||||
function New-mRemoteNGConnectionInfo {
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
|
||||
PROCESS {
|
||||
$connectionInfo = New-Object -TypeName mRemoteNG.Connection.ConnectionInfo
|
||||
Write-Output $connectionInfo
|
||||
}
|
||||
}
|
||||
|
||||
function New-mRemoteNGContainerInfo {
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
|
||||
PROCESS {
|
||||
$connectionInfo = New-Object -TypeName mRemoteNG.Container.ContainerInfo
|
||||
Write-Output $connectionInfo
|
||||
}
|
||||
}
|
||||
|
||||
# Setup the services needed to do serialization
|
||||
$xmlSerializer = New-mRemoteNGXmlSerializer -EncryptionKey $EncryptionKey
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Example 1: serialize many connections, no containers
|
||||
# Here you can define the number of connection info objects to create
|
||||
# You can also provide a list of desired hostnames and iterate over those
|
||||
$xml = ""
|
||||
foreach($i in 1..5)
|
||||
{
|
||||
$connectionInfo = New-mRemoteNGConnectionInfo
|
||||
|
||||
# Set connection info properties
|
||||
$connectionInfo.Name = "server-$i"
|
||||
$connectionInfo.Hostname = "some-win-server-$i"
|
||||
$connectionInfo.Protocol = [mRemoteNG.Connection.Protocol.ProtocolType]::RDP
|
||||
$connectionInfo.Inheritance.Username = $true
|
||||
$connectionInfo.Inheritance.Domain = $true
|
||||
$connectionInfo.Inheritance.Password = $true
|
||||
|
||||
$serializedConnection = $xmlSerializer.SerializeConnectionInfo($connectionInfo).ToString()
|
||||
$xml += $serializedConnection + [System.Environment]::NewLine
|
||||
}
|
||||
|
||||
Write-Output $xml
|
||||
|
||||
|
||||
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Example 2: serialize a container which has connections
|
||||
# You can also create containers and add connections to them, which will be nested correctly when serialized
|
||||
$xml = ""
|
||||
$container = New-mRemoteNGContainerInfo
|
||||
$container.Name = "ProductionServers"
|
||||
$serializedContainer = $xmlSerializer.SerializeConnectionInfo($container)
|
||||
|
||||
foreach($i in 1..3)
|
||||
{
|
||||
$connectionInfo = New-mRemoteNGConnectionInfo
|
||||
|
||||
# Set connection info properties
|
||||
$connectionInfo.Name = "server-$i"
|
||||
$connectionInfo.Hostname = "some-linux-server-$i"
|
||||
$connectionInfo.Protocol = [mRemoteNG.Connection.Protocol.ProtocolType]::SSH2
|
||||
$connectionInfo.Inheritance.Username = $true
|
||||
$connectionInfo.Inheritance.Domain = $true
|
||||
$connectionInfo.Inheritance.Password = $true
|
||||
|
||||
# serialize the connection
|
||||
$serializedConnection = $xmlSerializer.SerializeConnectionInfo($connectionInfo)
|
||||
# add the connection to the container
|
||||
$serializedContainer.Add($serializedConnection)
|
||||
}
|
||||
|
||||
# Call ToString() on the top-level container to get the XML of it and all its children
|
||||
Write-Output $serializedContainer.ToString()
|
||||
@@ -5,7 +5,7 @@ setlocal enabledelayedexpansion
|
||||
set SOLUTIONDIR=%~dp0..
|
||||
|
||||
rem Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
set SIGCHECK="%SOLUTIONDIR%\Tools\sigcheck.exe"
|
||||
set SIGCHECK="%SOLUTIONDIR%\Tools\exes\sigcheck.exe"
|
||||
set SEVENZIP="%SOLUTIONDIR%\Tools\7zip\7za.exe"
|
||||
|
||||
set VCVARSALL="%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
|
||||
|
||||
15
Tools/copy_puttyng.ps1
Normal file
15
Tools/copy_puttyng.ps1
Normal file
@@ -0,0 +1,15 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying PUTTYNG to correct directory"
|
||||
Copy-Item -Path (Join-Path -Path $SolutionDir -ChildPath "mRemoteV1\Resources\PuTTYNG.exe") -Destination $TargetDir -Force
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,16 +1,23 @@
|
||||
$sourcePath = $args[0]
|
||||
$destinationDir = $args[1]
|
||||
param (
|
||||
[string]
|
||||
$SourcePath,
|
||||
|
||||
Write-Host $sourcePath
|
||||
Write-Host $destinationDir
|
||||
[string]
|
||||
$DestinationDir
|
||||
)
|
||||
|
||||
if (!(Test-Path -Path $destinationDir))
|
||||
Write-Host $SourcePath
|
||||
Write-Host $DestinationDir
|
||||
|
||||
if (!(Test-Path -Path $DestinationDir))
|
||||
{
|
||||
New-Item -Path $destinationDir -ItemType "directory"
|
||||
New-Item -Path $DestinationDir -ItemType "directory"
|
||||
}
|
||||
|
||||
$sourceFiles = Get-ChildItem -Path $sourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
|
||||
$sourceFiles = Get-ChildItem -Path $SourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
|
||||
foreach ($item in $sourceFiles)
|
||||
{
|
||||
Copy-Item -Path $item.FullName -Destination $destinationDir -Force
|
||||
$item.Name
|
||||
(Get-FileHash -Path $item.fullName -Algorithm SHA512).Hash
|
||||
Copy-Item -Path $item.FullName -Destination $DestinationDir -Force
|
||||
}
|
||||
19
Tools/copy_themes.ps1
Normal file
19
Tools/copy_themes.ps1
Normal file
@@ -0,0 +1,19 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying THEMES folder to output"
|
||||
|
||||
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteV1\Resources\Themes' )
|
||||
$DestinationDir = [io.path]::combine($TargetDir , 'Themes')
|
||||
|
||||
robocopy $sourceFiles $DestinationDir *.vstheme /s
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,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 MD5 $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 MD5 $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
|
||||
235
Tools/github_functions.ps1
Normal file
235
Tools/github_functions.ps1
Normal file
@@ -0,0 +1,235 @@
|
||||
$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,
|
||||
|
||||
[string]
|
||||
# A short description label for the asset
|
||||
$Label = ""
|
||||
)
|
||||
|
||||
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$"
|
||||
$files = Get-Item -Path $FilePath
|
||||
|
||||
$labelParam = ""
|
||||
if ($Label -ne "") {
|
||||
$labelParam = "&label=$Label"
|
||||
}
|
||||
|
||||
# Get-Item could produce an array of files if a wildcard is provided. (C:\*.txt)
|
||||
# Upload each matching item individually
|
||||
foreach ($file in $files) {
|
||||
Write-Output "Uploading asset to GitHub release: '$($file.FullName)'"
|
||||
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)$labelParam" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function New-GitHubReleaseRequestBody {
|
||||
param (
|
||||
[string]
|
||||
#
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
# Either the SHA of the commit to target or the branch name.
|
||||
$TargetCommitish,
|
||||
|
||||
[string]
|
||||
# Title of the release
|
||||
$ReleaseTitle,
|
||||
|
||||
[string]
|
||||
# Description of the release
|
||||
$Description,
|
||||
|
||||
[bool]
|
||||
# Is this a draft?
|
||||
$IsDraft,
|
||||
|
||||
[bool]
|
||||
# Is this a pre-release?
|
||||
$IsPrerelease
|
||||
)
|
||||
|
||||
$body_params = [ordered]@{}
|
||||
if ($TagName -ne "") { $body_params.Add("tag_name", $TagName) }
|
||||
if ($TargetCommitish -ne "") { $body_params.Add("target_commitish", $TargetCommitish) }
|
||||
if ($ReleaseTitle -ne "") { $body_params.Add("name", $ReleaseTitle) }
|
||||
if ($Description -ne "") { $body_params.Add("body", $Description) }
|
||||
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("draft", $IsDraft) }
|
||||
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("prerelease", $IsPrerelease) }
|
||||
|
||||
$json_body = ConvertTo-Json -InputObject $body_params -Compress
|
||||
Write-Output $json_body
|
||||
}
|
||||
23
Tools/move_help_files.ps1
Normal file
23
Tools/move_help_files.ps1
Normal file
@@ -0,0 +1,23 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_HelpFilesDir = Join-Path -Path $TargetDir -ChildPath "Help"
|
||||
|
||||
Write-Output "Moving Help files to correct directory"
|
||||
|
||||
# Remove stale Help files, if they exist
|
||||
if (Test-Path -Path $path_HelpFilesDir) {
|
||||
Remove-Item -Path $path_HelpFilesDir -Recurse -Force
|
||||
}
|
||||
|
||||
# Move Help files
|
||||
Move-Item -Path (Join-Path -Path $TargetDir -ChildPath "Resources\Help") -Destination $path_HelpFilesDir -Force
|
||||
Start-Sleep -Seconds 2
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "Resources") -Recurse -Force
|
||||
|
||||
Write-Output ""
|
||||
43
Tools/postbuild_installer.ps1
Normal file
43
Tools/postbuild_installer.ps1
Normal file
@@ -0,0 +1,43 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
$CertificatePassword,
|
||||
|
||||
[string[]]
|
||||
$ExcludeFromSigning
|
||||
)
|
||||
|
||||
Write-Output "+=================================================================+"
|
||||
Write-Output "| Beginning mRemoteNG Installer Post Build |"
|
||||
Write-Output "+=================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath
|
||||
& "$PSScriptRoot\rename_installer_with_version.ps1" -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\copy_release_installer.ps1" -SourcePath $TargetDir -DestinationDir (Join-Path -Path $SolutionDir -ChildPath "Release")
|
||||
50
Tools/postbuild_mremotev1.ps1
Normal file
50
Tools/postbuild_mremotev1.ps1
Normal file
@@ -0,0 +1,50 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
$CertificatePassword,
|
||||
|
||||
[string[]]
|
||||
$ExcludeFromSigning
|
||||
)
|
||||
|
||||
Write-Output "+=================================================================+"
|
||||
Write-Output "| Beginning mRemoteV1 Post Build |"
|
||||
Write-Output "+=================================================================+"
|
||||
Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"SolutionDir" = $SolutionDir
|
||||
"TargetDir" = $TargetDir
|
||||
"TargetFileName" = $TargetFileName
|
||||
"ConfigurationName" = $ConfigurationName
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
|
||||
& "$PSScriptRoot\copy_puttyng.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\copy_themes.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\move_help_files.ps1" -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
& "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath
|
||||
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
25
Tools/publish_draft_github_release.ps1
Normal file
25
Tools/publish_draft_github_release.ps1
Normal file
@@ -0,0 +1,25 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseId,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
Edit-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $ReleaseId -AuthToken $AuthToken -IsDraft $false
|
||||
81
Tools/publish_to_github.ps1
Normal file
81
Tools/publish_to_github.ps1
Normal file
@@ -0,0 +1,81 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Owner,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Repository,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$ReleaseTitle,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$TagName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Either the SHA of the commit to target or the branch name.
|
||||
$TargetCommitish,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#
|
||||
$Description,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("true","false")]
|
||||
# true/false
|
||||
$IsDraft,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
[ValidateSet("true","false")]
|
||||
# true/false
|
||||
$IsPrerelease,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Path to the folder which contains release assets to upload
|
||||
$ReleaseFolderPath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken,
|
||||
|
||||
[switch]
|
||||
# Enable this switch to treat $Description as a Base64 encoded string. It will be decoded before being used elsewhere in the script.
|
||||
$DescriptionIsBase64Encoded
|
||||
)
|
||||
|
||||
|
||||
if ($DescriptionIsBase64Encoded) {
|
||||
$Description = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Description)))
|
||||
}
|
||||
|
||||
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
|
||||
$releaseFolderItems = Get-ChildItem -Path $ReleaseFolderPath
|
||||
$mrngPortablePath = ($releaseFolderItems | ?{$_.Name -match "portable-[\d\.]+\.zip"}).FullName
|
||||
$mrngNormalPath = ($releaseFolderItems | ?{$_.Name -match "installer-[\d\.]+\.msi"}).FullName
|
||||
$mrngPortableSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-portable-symbols-[\d\.]+\.zip"}).FullName
|
||||
$mrngNormalSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-symbols-[\d\.]+\.zip"}).FullName
|
||||
|
||||
|
||||
$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 $mrngPortablePath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition (zip)"
|
||||
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalPath -ContentType "application/octet-stream" -AuthToken $AuthToken -Label "Normal Edition (msi)"
|
||||
|
||||
$portableEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortableSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition Debug Symbols"
|
||||
$normalEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Normal Edition Debug Symbols"
|
||||
Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken)
|
||||
@@ -1,11 +1,15 @@
|
||||
$solutionDir = $args[0]
|
||||
$renameTarget = $solutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
param (
|
||||
[string]
|
||||
$SolutionDir
|
||||
)
|
||||
|
||||
Write-Host $solutionDir
|
||||
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
|
||||
Write-Host $SolutionDir
|
||||
Write-Host $renameTarget
|
||||
|
||||
$targetVersionedFile = "$solutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
|
||||
$version = &"$solutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
$targetVersionedFile = "$SolutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
|
||||
$version = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile
|
||||
|
||||
|
||||
$renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue
|
||||
|
||||
22
Tools/set_LargeAddressAware.ps1
Normal file
22
Tools/set_LargeAddressAware.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
[CmdletBinding()]
|
||||
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_editBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\editbin.exe"
|
||||
$path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
|
||||
# Set LargeAddressAware
|
||||
Write-Output "Setting LargeAddressAware on binary file:`n`"$path_outputExe`" `nwith:`n`"$path_editBin`""
|
||||
& "$path_editBin" /largeaddressaware "$path_outputExe"
|
||||
|
||||
Write-Output ""
|
||||
76
Tools/sign_binaries.ps1
Normal file
76
Tools/sign_binaries.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string[]]
|
||||
# File names to exclude from signing
|
||||
$Exclude,
|
||||
|
||||
[string]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath,
|
||||
|
||||
[string]
|
||||
# Password to unlock the code signing certificate.
|
||||
$CertificatePassword
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
|
||||
|
||||
if ($ConfigurationName -notmatch "Release") {
|
||||
Write-Output "This is not a release build - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf)) {
|
||||
Write-Output "Certificate is not present - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
if ($CertificatePassword -eq "") {
|
||||
Write-Output "No certificate password was provided - we won't sign files."
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$certKeyStore = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword, $certKeyStore) -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Output "Error loading certificate file - we won't sign files."
|
||||
Write-Output $Error[0]
|
||||
return
|
||||
}
|
||||
|
||||
# Sign MSI if we are building a release version and the certificate is available
|
||||
Write-Output "Signing Binaries"
|
||||
Write-Output "Getting files from path: $TargetDir"
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
|
||||
|
||||
$excluded_files = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -contains $_.Name}
|
||||
$excluded_files | ForEach-Object `
|
||||
-Begin { Write-Output "The following files were excluded from signing due to being on the exclusion list:" } `
|
||||
-Process { Write-Output "-- $($_.FullName)" }
|
||||
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
|
||||
}
|
||||
|
||||
|
||||
# Release certificate
|
||||
if ($cert -ne $null) {
|
||||
$cert.Dispose()
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,13 +1,31 @@
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
$certPath = "C:\mRemoteNG_code_signing_cert.pfx"
|
||||
$certPassword = (Get-Credential -Message "Enter the password for the certificate" -UserName "USERNAME NOT NEEDED").Password
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath, $certPassword)
|
||||
$targetPath = $args[0]
|
||||
param(
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Folder path that contains the files you would like to sign. Recursive.
|
||||
$PathToSignableFiles,
|
||||
|
||||
[string]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath = "C:\mRemoteNG_code_signing_cert.pfx",
|
||||
|
||||
[SecureString]
|
||||
# Password to unlock the code signing certificate.
|
||||
$CertificatePassword = (Get-Credential -Message "Enter password for the mRemoteNG code signing certificate" -UserName "USERNAME NOT NEEDED").Password,
|
||||
|
||||
[string[]]
|
||||
# File names to exclude from signing
|
||||
$Exclude
|
||||
)
|
||||
|
||||
|
||||
Write-Output "Getting files from path: $targetPath"
|
||||
$signableFiles = Get-ChildItem -Path $targetPath -Recurse | ?{$_.Extension -match "dll|exe|msi"}
|
||||
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword)
|
||||
|
||||
|
||||
Write-Output "Getting files from path: $PathToSignableFiles"
|
||||
$signableFiles = Get-ChildItem -Path $PathToSignableFiles -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
|
||||
foreach ($file in $signableFiles) {
|
||||
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
|
||||
}
|
||||
32
Tools/tidy_files_for_release.ps1
Normal file
32
Tools/tidy_files_for_release.ps1
Normal file
@@ -0,0 +1,32 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# Remove unnecessary files from Release versions
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Removing unnecessary files from Release versions"
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
|
||||
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
|
||||
"*.publish",
|
||||
"*.xml",
|
||||
"*.backup",
|
||||
"*.log",
|
||||
"*vshost*",
|
||||
"*.tmp"
|
||||
)
|
||||
Remove-Item -Path $filesToDelete.FullName
|
||||
Write-Output $filesToDelete.FullName
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not remove anything - this is not a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
17
Tools/validate_microsoft_tool.ps1
Normal file
17
Tools/validate_microsoft_tool.ps1
Normal file
@@ -0,0 +1,17 @@
|
||||
# $FullPath Full path to the Microsoft executable to validate
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$FullPath
|
||||
)
|
||||
|
||||
$validMSCertThumbprints = @("3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC", "108E2BA23632620C427C570B6D9DB51AC31387FE", "98ED99A67886D020C564923B7DF25E9AC019DF26", "5EAD300DC7E4D637948ECB0ED829A072BD152E17")
|
||||
$exeSignature = Get-AuthenticodeSignature -FilePath $FullPath
|
||||
$baseErrorMsg = "Could not validate the certificate of $FullPath. "
|
||||
|
||||
if ($exeSignature.Status -ne "Valid") {
|
||||
Write-Error -Message ($baseErrorMsg+"The signature was invalid.") -ErrorAction Stop
|
||||
}
|
||||
elseif ($validMSCertThumbprints -notcontains $exeSignature.SignerCertificate.Thumbprint) {
|
||||
Write-Error -Message ($baseErrorMsg+"The certificate thumbprint ($($exeSignature.SignerCertificate.Thumbprint)) is not trusted.") -ErrorAction Stop
|
||||
}
|
||||
30
Tools/verify_LargeAddressAware.ps1
Normal file
30
Tools/verify_LargeAddressAware.ps1
Normal file
@@ -0,0 +1,30 @@
|
||||
[CmdletBinding()]
|
||||
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetFileName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$path_dumpBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\dumpbin.exe"
|
||||
$path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
|
||||
# Dump exe header
|
||||
$output = & "$path_dumpBin" /NOLOGO /HEADERS "$path_outputExe" | Select-String large
|
||||
|
||||
if ($output -eq $null)
|
||||
{
|
||||
Write-Warning "Could not validate LargeAddressAware"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output $output.ToString().TrimStart(" ")
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
48
Tools/verify_binary_signatures.ps1
Normal file
48
Tools/verify_binary_signatures.ps1
Normal file
@@ -0,0 +1,48 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The code signing certificate to use when signing the files.
|
||||
$CertificatePath
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
# validate release versions and if the certificate is available
|
||||
if ($ConfigurationName -match "Release") {
|
||||
|
||||
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
|
||||
{
|
||||
Write-Output "Certificate is not present - files likely not signed - we won't verify file signatures."
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Verifying signature of binaries"
|
||||
Write-Output "Getting files from path: $TargetDir"
|
||||
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"}
|
||||
Write-Output "Signable files count: $($signableFiles.Count)"
|
||||
$badSignatureFound = $false
|
||||
foreach ($file in $signableFiles) {
|
||||
$signature = Get-AuthenticodeSignature -FilePath $file.FullName
|
||||
if ($signature.Status -ne "Valid") {
|
||||
Write-Warning "File $($file.FullName) does not have a valid signature."
|
||||
$badSignatureFound = $true
|
||||
}
|
||||
}
|
||||
if ($badSignatureFound) {
|
||||
Write-Output "One or more files were improperly signed."
|
||||
} else {
|
||||
Write-Output "All files have valid signatures."
|
||||
}
|
||||
} else {
|
||||
Write-Output "This is not a release build - we won't verify file signatures."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
66
Tools/zip_portable_files.ps1
Normal file
66
Tools/zip_portable_files.ps1
Normal file
@@ -0,0 +1,66 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
$tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteV1\bin\package"
|
||||
Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item $tempFolderPath -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination $tempFolderPath
|
||||
|
||||
#Write-Output "$($SolutionDir)mRemoteV1\bin\$ConfigurationName"
|
||||
#Write-Output "$($SolutionDir)mRemoteV1\bin\package"
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force
|
||||
# Delete any PDB files that accidentally get copied into the temp folder
|
||||
Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*")
|
||||
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
|
||||
(Get-FileHash -Path $PortableZip -Algorithm SHA512).Hash
|
||||
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
39
Tools/zip_portable_files_appv.ps1
Normal file
39
Tools/zip_portable_files_appv.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "NOT running via Appveyor - Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
$appvDir = $Env:APPVEYOR_BUILD_FOLDER
|
||||
|
||||
Write-Output "Appveyor Build Dir: '$($appvDir)'"
|
||||
$ConfigurationName = $Env:CONFIGURATION.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
Remove-Item -Recurse "$($SolutionDir)mRemoteV1\bin\package" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item "$($SolutionDir)mRemoteV1\bin\package" -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination "$($SolutionDir)mRemoteV1\bin\package"
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination "$($SolutionDir)mRemoteV1\bin\package" -Recurse -Force
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination "$($SolutionDir)mRemoteV1\bin\package"
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip "$($SolutionDir)mRemoteV1\bin\package\*.*"
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
56
Tools/zip_symbols.ps1
Normal file
56
Tools/zip_symbols.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Packaging debug symbols"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
if ($ConfigurationName -match "Portable") {
|
||||
$zipFilePrefix = "mRemoteNG-Portable-symbols"
|
||||
} else {
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
}
|
||||
|
||||
$outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
|
||||
|
||||
Write-Output "Creating debug symbols ZIP file $($outputZipPath)"
|
||||
Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb")
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not package debug symbols - this isnt a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -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>
|
||||
28
appveyor.yml
Normal file
28
appveyor.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
version: 1.76.{build}
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
image: Visual Studio 2017
|
||||
configuration:
|
||||
- Release
|
||||
- Release Portable
|
||||
- Release Installer
|
||||
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
|
||||
after_build:
|
||||
- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"$($SolutionDir)Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"$($SolutionDir)Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"$($SolutionDir)mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"$($SolutionDir)Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"$($SolutionDir)mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"$($SolutionDir)mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"$($SolutionDir)mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Copy-Item \"$($SolutionDir)mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"$($SolutionDir)*.txt\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \"$($SolutionDir)mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}"
|
||||
test:
|
||||
assemblies:
|
||||
only:
|
||||
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
|
||||
artifacts:
|
||||
- path: Release\*.msi
|
||||
name: mRemoteNG-installer.msi
|
||||
- path: Release\*.zip
|
||||
name: mRemoteNG-portable.zip
|
||||
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>
|
||||
47
mRemoteNGTests/App/ImportTests.cs
Normal file
47
mRemoteNGTests/App/ImportTests.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.IO;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNGTests.Properties;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.App
|
||||
{
|
||||
public class ImportTests
|
||||
{
|
||||
[Test]
|
||||
public void ErrorHandlerCalledWhenUnsupportedFileExtensionFound()
|
||||
{
|
||||
using (FileTestHelpers.DisposableTempFile(out var file, ".blah"))
|
||||
{
|
||||
var conService = new ConnectionsService(PuttySessionsManager.Instance);
|
||||
var container = new ContainerInfo();
|
||||
var exceptionOccurred = false;
|
||||
|
||||
Import.HeadlessFileImport(new []{file}, container, conService, s => exceptionOccurred = true);
|
||||
|
||||
Assert.That(exceptionOccurred);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnErrorInOneFileDoNotPreventOtherFilesFromProcessing()
|
||||
{
|
||||
using (FileTestHelpers.DisposableTempFile(out var badFile, ".blah"))
|
||||
using (FileTestHelpers.DisposableTempFile(out var rdpFile, ".rdp"))
|
||||
{
|
||||
File.AppendAllText(rdpFile, Resources.test_remotedesktopconnection_rdp);
|
||||
var conService = new ConnectionsService(PuttySessionsManager.Instance);
|
||||
var container = new ContainerInfo();
|
||||
var exceptionCount = 0;
|
||||
|
||||
Import.HeadlessFileImport(new[] { badFile, rdpFile }, container, conService, s => exceptionCount++);
|
||||
|
||||
Assert.That(exceptionCount, Is.EqualTo(1));
|
||||
Assert.That(container.Children, Has.One.Items);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,185 @@
|
||||
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 CsvConnectionsSerializerMremotengFormat _serializer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_deserializer = new CsvConnectionsDeserializerMremotengFormat();
|
||||
var credentialRepositoryList = Substitute.For<ICredentialRepositoryList>();
|
||||
_serializer = new CsvConnectionsSerializerMremotengFormat(new SaveFilter(), credentialRepositoryList);
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(DeserializationTestSource), nameof(DeserializationTestSource.ConnectionPropertyTestCases))]
|
||||
public object ConnectionPropertiesDeserializedCorrectly(string propertyToCheck)
|
||||
{
|
||||
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 csv = _serializer.Serialize(GetTestConnectionWithAllInherited());
|
||||
var deserializedConnections = _deserializer.Deserialize(csv);
|
||||
var connection = deserializedConnections.GetRecursiveChildList().FirstOrDefault();
|
||||
connection?.RemoveParent();
|
||||
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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Collections;
|
||||
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 +9,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 +18,8 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
|
||||
public void Setup(string confCons, string password)
|
||||
{
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(confCons, password.ConvertToSecureString);
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize();
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -104,6 +104,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,22 +29,26 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider);
|
||||
_connectionTreeModel = SetupConnectionTreeModel();
|
||||
_cryptographyProvider = new CryptoProviderFactory(BlockCipherEngines.AES, BlockCipherModes.GCM).Build();
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
_cryptographyProvider,
|
||||
_connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider, connectionNodeSerializer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void XDocumentHasXmlDeclaration()
|
||||
{
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, false, false);
|
||||
var xdoc = _documentCompiler.CompileDocument(_connectionTreeModel, false);
|
||||
Assert.That(xdoc.Declaration, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DocumentHasRootConnectionElement()
|
||||
{
|
||||
var xdoc =_documentCompiler.CompileDocument(_connectionTreeModel, false, false);
|
||||
var xdoc =_documentCompiler.CompileDocument(_connectionTreeModel, false);
|
||||
var rootElementName = xdoc.Root?.Name.LocalName;
|
||||
Assert.That(rootElementName, Is.EqualTo("Connections"));
|
||||
}
|
||||
@@ -50,7 +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);
|
||||
}
|
||||
@@ -58,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,8 +21,12 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
var connectionTreeModel = SetupConnectionTreeModel();
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider).CompileDocument(connectionTreeModel, false, false);
|
||||
var cryptoProvider = new CryptoProviderFactory(BlockCipherEngines.AES, BlockCipherModes.GCM).Build();
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
cryptoProvider,
|
||||
connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider, connectionNodeSerializer).CompileDocument(connectionTreeModel, false);
|
||||
_documentEncryptor = new XmlConnectionsDocumentEncryptor(cryptoProvider);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,35 @@
|
||||
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;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
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]
|
||||
@@ -45,6 +53,28 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(connectionNode, Is.Not.Null);
|
||||
}
|
||||
|
||||
[TestCase("Username", "")]
|
||||
[TestCase("Domain", "")]
|
||||
[TestCase("Password", "")]
|
||||
[TestCase("InheritAutomaticResize", "false")]
|
||||
public void SerializerRespectsSaveFilterSettings(string attributeName, string expectedValue)
|
||||
{
|
||||
var connectionNodeSerializer = new XmlConnectionNodeSerializer26(
|
||||
_cryptographyProvider,
|
||||
_connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter(true));
|
||||
var serializer = new XmlConnectionsSerializer(_cryptographyProvider, connectionNodeSerializer);
|
||||
var connectionInfo = new ConnectionInfo
|
||||
{
|
||||
Name = "myConnection",
|
||||
Inheritance = {AutomaticResize = true}
|
||||
};
|
||||
var serializedConnections = serializer.Serialize(connectionInfo);
|
||||
var xdoc = XDocument.Parse(serializedConnections);
|
||||
var attributeValue = xdoc.Root?.Element("Node")?.Attribute(attributeName)?.Value;
|
||||
Assert.That(attributeValue, Is.EqualTo(expectedValue));
|
||||
}
|
||||
|
||||
private ConnectionTreeModel SetupConnectionTreeModel()
|
||||
{
|
||||
/*
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Data;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
public class DataTableDeserializerTests
|
||||
{
|
||||
private DataTableDeserializer _deserializer;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeATree()
|
||||
{
|
||||
var model = CreateConnectionTreeModel();
|
||||
var dataTable = CreateDataTable(model.RootNodes[0]);
|
||||
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(model.GetRecursiveChildList().Count));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeASingleEntry()
|
||||
{
|
||||
var dataTable = CreateDataTable(new ConnectionInfo());
|
||||
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
private DataTable CreateDataTable(ConnectionInfo tableContent)
|
||||
{
|
||||
var serializer = new DataTableSerializer(new SaveFilter(), _cryptographyProvider, new SecureString());
|
||||
return serializer.Serialize(tableContent);
|
||||
}
|
||||
|
||||
private ConnectionTreeModel CreateConnectionTreeModel()
|
||||
{
|
||||
var builder = new ConnectionTreeModelBuilder();
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
@@ -17,14 +23,10 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
_saveFilter = new SaveFilter();
|
||||
_dataTableSerializer = new DataTableSerializer(_saveFilter);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_saveFilter = null;
|
||||
_dataTableSerializer = null;
|
||||
_dataTableSerializer = new DataTableSerializer(
|
||||
_saveFilter,
|
||||
new LegacyRijndaelCryptographyProvider(),
|
||||
new SecureString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -32,7 +34,15 @@ 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]
|
||||
public void ReturnsEmptyDataTableWhenGivenEmptyConnectionTreeModel()
|
||||
{
|
||||
var model = new ConnectionTreeModel();
|
||||
var dataTable = _dataTableSerializer.Serialize(model);
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -109,20 +119,18 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
Assert.That(dataTable.Rows[0]["InheritUsername"], Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSerializeEmptyConnectionInfo()
|
||||
{
|
||||
var dataTable = _dataTableSerializer.Serialize(new ConnectionInfo());
|
||||
Assert.That(dataTable.Rows.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
private ConnectionTreeModel CreateConnectionTreeModel()
|
||||
{
|
||||
var model = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var folder1 = new ContainerInfo {Name = "folder1", Username = "user1", Domain = "domain1", Password = "password1"};
|
||||
var con1 = new ConnectionInfo {Name = "Con1", Username = "user1", Domain = "domain1", Password = "password1" };
|
||||
var con2 = new ConnectionInfo {Name = "Con2", Username = "user2", Domain = "domain2", Password = "password2" };
|
||||
|
||||
root.AddChild(folder1);
|
||||
root.AddChild(con2);
|
||||
folder1.AddChild(con1);
|
||||
model.AddRootNode(root);
|
||||
return model;
|
||||
var builder = new ConnectionTreeModelBuilder();
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,198 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionManager27DeserializerTests
|
||||
{
|
||||
private string _connectionFileContents;
|
||||
private RemoteDesktopConnectionManagerDeserializer _deserializer;
|
||||
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();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionTreeModelHasARootNode()
|
||||
{
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
var numberOfRootNodes = connectionTreeModel.RootNodes.Count;
|
||||
Assert.That(numberOfRootNodes, Is.GreaterThan(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootNodeHasContents()
|
||||
{
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
var rootNodeContents = connectionTreeModel.RootNodes.First().Children;
|
||||
Assert.That(rootNodeContents, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllSubRootFoldersImported()
|
||||
{
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
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));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(ExpectedPropertyValues))]
|
||||
public void PropertiesWithValuesAreCorrectlyImported(Func<ConnectionInfo, object> propSelector, object expectedValue)
|
||||
{
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
|
||||
var connection = connectionTreeModel
|
||||
.GetRecursiveChildList()
|
||||
.OfType<ContainerInfo>()
|
||||
.First(node => node.Name == "Group1")
|
||||
.Children
|
||||
.First();
|
||||
|
||||
Assert.That(propSelector(connection), Is.EqualTo(expectedValue));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(NullPropertyValues))]
|
||||
public void PropertiesWithoutValuesAreIgnored(Func<ConnectionInfo, object> propSelector)
|
||||
{
|
||||
var connectionTreeModel = _deserializer.Deserialize(Resources.test_rdcman_v2_7_schema3_empty_values);
|
||||
|
||||
var importedConnection = connectionTreeModel
|
||||
.GetRecursiveChildList()
|
||||
.OfType<ContainerInfo>()
|
||||
.First(node => node.Name == "Group1")
|
||||
.Children
|
||||
.First();
|
||||
|
||||
Assert.That(propSelector(importedConnection), Is.EqualTo(propSelector(new ConnectionInfo())));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(NullPropertyValues))]
|
||||
public void NonExistantPropertiesAreIgnored(Func<ConnectionInfo, object> propSelector)
|
||||
{
|
||||
var connectionTreeModel = _deserializer.Deserialize(Resources.test_rdcman_v2_7_schema3_null_values);
|
||||
|
||||
var importedConnection = connectionTreeModel
|
||||
.GetRecursiveChildList()
|
||||
.OfType<ContainerInfo>()
|
||||
.First(node => node.Name == "Group1")
|
||||
.Children
|
||||
.First();
|
||||
|
||||
Assert.That(propSelector(importedConnection), Is.EqualTo(propSelector(new ConnectionInfo())));
|
||||
}
|
||||
|
||||
[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>());
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> ExpectedPropertyValues()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Name), ExpectedName).SetName(nameof(ConnectionInfo.Name)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Hostname), ExpectedHostname).SetName(nameof(ConnectionInfo.Hostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Description), ExpectedDescription).SetName(nameof(ConnectionInfo.Description)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Username), ExpectedUsername).SetName(nameof(ConnectionInfo.Username)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Domain), ExpectedDomain).SetName(nameof(ConnectionInfo.Domain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Protocol), ProtocolType.RDP).SetName(nameof(ConnectionInfo.Protocol)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.UseConsoleSession), ExpectedUseConsoleSession).SetName(nameof(ConnectionInfo.UseConsoleSession)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Port), ExpectedPort).SetName(nameof(ConnectionInfo.Port)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsageMethod), ExpectedGatewayUsageMethod).SetName(nameof(ConnectionInfo.RDGatewayUsageMethod)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayHostname), ExpectedGatewayHostname).SetName(nameof(ConnectionInfo.RDGatewayHostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsername), ExpectedGatewayUsername).SetName(nameof(ConnectionInfo.RDGatewayUsername)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayDomain), ExpectedGatewayDomain).SetName(nameof(ConnectionInfo.RDGatewayDomain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Resolution), ExpectedRdpResolution).SetName(nameof(ConnectionInfo.Resolution)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Colors), ExpectedRdpColorDepth).SetName(nameof(ConnectionInfo.Colors)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSound), ExpectedAudioRedirection).SetName(nameof(ConnectionInfo.RedirectSound)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectKeys), ExpectedKeyRedirection).SetName(nameof(ConnectionInfo.RedirectKeys)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDPAuthenticationLevel), ExpectedAuthLevel).SetName(nameof(ConnectionInfo.RDPAuthenticationLevel)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSmartCards), ExpectedSmartcardRedirection).SetName(nameof(ConnectionInfo.RedirectSmartCards)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPrinters), ExpectedPrinterRedirection).SetName(nameof(ConnectionInfo.RedirectPrinters)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPorts), ExpectedPortRedirection).SetName(nameof(ConnectionInfo.RedirectPorts)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectDiskDrives), ExpectedDriveRedirection).SetName(nameof(ConnectionInfo.RedirectDiskDrives)),
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> NullPropertyValues()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Name)).SetName(nameof(ConnectionInfo.Name)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Hostname)).SetName(nameof(ConnectionInfo.Hostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Description)).SetName(nameof(ConnectionInfo.Description)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Username)).SetName(nameof(ConnectionInfo.Username)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Domain)).SetName(nameof(ConnectionInfo.Domain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Protocol)).SetName(nameof(ConnectionInfo.Protocol)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.UseConsoleSession)).SetName(nameof(ConnectionInfo.UseConsoleSession)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Port)).SetName(nameof(ConnectionInfo.Port)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsageMethod)).SetName(nameof(ConnectionInfo.RDGatewayUsageMethod)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayHostname)).SetName(nameof(ConnectionInfo.RDGatewayHostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsername)).SetName(nameof(ConnectionInfo.RDGatewayUsername)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayDomain)).SetName(nameof(ConnectionInfo.RDGatewayDomain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Resolution)).SetName(nameof(ConnectionInfo.Resolution)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Colors)).SetName(nameof(ConnectionInfo.Colors)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSound)).SetName(nameof(ConnectionInfo.RedirectSound)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectKeys)).SetName(nameof(ConnectionInfo.RedirectKeys)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDPAuthenticationLevel)).SetName(nameof(ConnectionInfo.RDPAuthenticationLevel)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSmartCards)).SetName(nameof(ConnectionInfo.RedirectSmartCards)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPrinters)).SetName(nameof(ConnectionInfo.RedirectPrinters)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPorts)).SetName(nameof(ConnectionInfo.RedirectPorts)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectDiskDrives)).SetName(nameof(ConnectionInfo.RedirectDiskDrives)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,255 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
{
|
||||
public class XmlConnectionNodeSerializerTests
|
||||
{
|
||||
private XmlConnectionNodeSerializer _connectionNodeSerializer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(
|
||||
BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReturnsXElement()
|
||||
{
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(new ConnectionInfo());
|
||||
Assert.That(returnVal, Is.TypeOf<XElement>());
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.AttributesAndExpectedValues))]
|
||||
public void XmlElementContainsSerializedAttribute(string attributeName, string expectedValue, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.EqualTo(expectedValue));
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.PasswordAttributes))]
|
||||
public void PasswordFieldsAreSerialized(string attributeName, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.SaveFilterTests))]
|
||||
public void AttributesNotSerializedWhenFiltered(string attributeName, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var saveFilter = new SaveFilter(true);
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString(), saveFilter);
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[TestCaseSource(typeof(TestCaseDataSource), nameof(TestCaseDataSource.InheritanceFilterTests))]
|
||||
public void InheritanceNotSerialiedWhenFiltered(string attributeName, ConnectionInfo connectionInfo)
|
||||
{
|
||||
var saveFilter = new SaveFilter(true);
|
||||
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
|
||||
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString(), saveFilter);
|
||||
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
|
||||
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
|
||||
Assert.That(targetAttribute?.Value, Is.EqualTo(false.ToString()));
|
||||
}
|
||||
|
||||
private class TestCaseDataSource
|
||||
{
|
||||
private static readonly ConnectionInfo ConnectionInfo = new ConnectionInfo
|
||||
{
|
||||
Name = "HeresACustomName",
|
||||
Description = "myDescription",
|
||||
Username = "myuser",
|
||||
Domain = "superdomain",
|
||||
Password = "pass",
|
||||
Hostname = "somehost",
|
||||
ExtApp = "myextapp",
|
||||
PreExtApp = "preext1",
|
||||
PostExtApp = "postext1",
|
||||
MacAddress = "asdf-asdf-asdf-asdf23423",
|
||||
LoadBalanceInfo = "loadbalanceinfohere",
|
||||
RDGatewayUsername = "gatewayuser",
|
||||
RDGatewayDomain = "somegatewaydomain",
|
||||
RDGatewayHostname = "somegatewayhost",
|
||||
RDGatewayPassword = "gatewaypass",
|
||||
UserField = "userfield data here",
|
||||
VNCProxyIP = "192.168.1.1",
|
||||
VNCProxyUsername = "vncproxyuser",
|
||||
VNCProxyPassword = "vncproxypass",
|
||||
};
|
||||
|
||||
private static readonly ConnectionInfo ConnectionInfoWithInheritance = new ConnectionInfo
|
||||
{
|
||||
Inheritance = {EverythingInherited = true}
|
||||
};
|
||||
|
||||
private static readonly ContainerInfo ContainerInfo = new ContainerInfo();
|
||||
|
||||
public static IEnumerable SaveFilterTests
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Username", ConnectionInfo);
|
||||
yield return new TestCaseData("Domain", ConnectionInfo);
|
||||
yield return new TestCaseData("Password", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUsername", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayDomain", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayPassword", ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyUsername", ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyPassword", ConnectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable InheritanceFilterTests
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("InheritUsername", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritDomain", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritPassword", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritRDGatewayUsername", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritRDGatewayDomain", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritRDGatewayPassword", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritVNCProxyUsername", ConnectionInfoWithInheritance);
|
||||
yield return new TestCaseData("InheritVNCProxyPassword", ConnectionInfoWithInheritance);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable PasswordAttributes
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Password", ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyPassword", ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayPassword", ConnectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable AttributesAndExpectedValues
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("Name", ConnectionInfo.Name, ConnectionInfo);
|
||||
yield return new TestCaseData("Type", "Connection", ConnectionInfo);
|
||||
yield return new TestCaseData("Type", "Container", ContainerInfo);
|
||||
yield return new TestCaseData("Expanded", ContainerInfo.IsExpanded.ToString(), ContainerInfo);
|
||||
yield return new TestCaseData("Descr", ConnectionInfo.Description, ConnectionInfo);
|
||||
yield return new TestCaseData("Icon", ConnectionInfo.Icon, ConnectionInfo);
|
||||
yield return new TestCaseData("Panel", "General", ConnectionInfo);
|
||||
yield return new TestCaseData("Username", ConnectionInfo.Username, ConnectionInfo);
|
||||
yield return new TestCaseData("Domain", ConnectionInfo.Domain, ConnectionInfo);
|
||||
yield return new TestCaseData("Hostname", ConnectionInfo.Hostname, ConnectionInfo);
|
||||
yield return new TestCaseData("Protocol", "RDP", ConnectionInfo);
|
||||
yield return new TestCaseData("PuttySession", ConnectionInfo.PuttySession, ConnectionInfo);
|
||||
yield return new TestCaseData("Port", ConnectionInfo.Port.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("ConnectToConsole", ConnectionInfo.UseConsoleSession.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("UseCredSsp", ConnectionInfo.UseCredSsp.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RenderingEngine", ConnectionInfo.RenderingEngine.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("ICAEncryptionStrength", ConnectionInfo.ICAEncryptionStrength.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDPAuthenticationLevel", ConnectionInfo.RDPAuthenticationLevel.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("LoadBalanceInfo", ConnectionInfo.LoadBalanceInfo, ConnectionInfo);
|
||||
yield return new TestCaseData("Colors", ConnectionInfo.Colors.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("Resolution", ConnectionInfo.Resolution.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("AutomaticResize", ConnectionInfo.AutomaticResize.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("DisplayWallpaper", ConnectionInfo.DisplayWallpaper.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("DisplayThemes", ConnectionInfo.DisplayThemes.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("EnableFontSmoothing", ConnectionInfo.EnableFontSmoothing.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("EnableDesktopComposition", ConnectionInfo.EnableDesktopComposition.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("CacheBitmaps", ConnectionInfo.CacheBitmaps.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectDiskDrives", ConnectionInfo.RedirectDiskDrives.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectPorts", ConnectionInfo.RedirectPorts.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectPrinters", ConnectionInfo.RedirectPrinters.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectSmartCards", ConnectionInfo.RedirectSmartCards.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectSound", ConnectionInfo.RedirectSound.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RedirectKeys", ConnectionInfo.RedirectKeys.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("Connected", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("PreExtApp", ConnectionInfo.PreExtApp, ConnectionInfo);
|
||||
yield return new TestCaseData("PostExtApp", ConnectionInfo.PostExtApp, ConnectionInfo);
|
||||
yield return new TestCaseData("MacAddress", ConnectionInfo.MacAddress, ConnectionInfo);
|
||||
yield return new TestCaseData("UserField", ConnectionInfo.UserField, ConnectionInfo);
|
||||
yield return new TestCaseData("ExtApp", ConnectionInfo.ExtApp, ConnectionInfo);
|
||||
yield return new TestCaseData("VNCCompression", ConnectionInfo.VNCCompression.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCEncoding", ConnectionInfo.VNCEncoding.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCAuthMode", ConnectionInfo.VNCAuthMode.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyType", ConnectionInfo.VNCProxyType.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyIP", ConnectionInfo.VNCProxyIP, ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyPort", ConnectionInfo.VNCProxyPort.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCProxyUsername", ConnectionInfo.VNCProxyUsername, ConnectionInfo);
|
||||
yield return new TestCaseData("VNCColors", ConnectionInfo.VNCColors.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCSmartSizeMode", ConnectionInfo.VNCSmartSizeMode.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("VNCViewOnly", ConnectionInfo.VNCViewOnly.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUsageMethod", ConnectionInfo.RDGatewayUsageMethod.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayHostname", ConnectionInfo.RDGatewayHostname, ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUseConnectionCredentials", ConnectionInfo.RDGatewayUseConnectionCredentials.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayUsername", ConnectionInfo.RDGatewayUsername, ConnectionInfo);
|
||||
yield return new TestCaseData("RDGatewayDomain", ConnectionInfo.RDGatewayDomain, ConnectionInfo);
|
||||
yield return new TestCaseData("InheritCacheBitmaps", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritColors", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDescription", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDisplayThemes", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDisplayWallpaper", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritEnableFontSmoothing", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritEnableDesktopComposition", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritDomain", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritIcon", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPanel", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPassword", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPort", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritProtocol", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPuttySession", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectDiskDrives", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectKeys", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectPorts", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectPrinters", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectSmartCards", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRedirectSound", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritSoundQuality", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritResolution", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritAutomaticResize", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUseConsoleSession", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUseCredSsp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRenderingEngine", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUsername", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritICAEncryptionStrength", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDPAuthenticationLevel", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritLoadBalanceInfo", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPreExtApp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritPostExtApp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritMacAddress", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritUserField", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritExtApp", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCCompression", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCEncoding", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCAuthMode", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyType", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyIP", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyPort", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyUsername", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCProxyPassword", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCColors", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCSmartSizeMode", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritVNCViewOnly", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayUsageMethod", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayHostname", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayUseConnectionCredentials", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayUsername", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayPassword", false.ToString(), ConnectionInfo);
|
||||
yield return new TestCaseData("InheritRDGatewayDomain", false.ToString(), ConnectionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
mRemoteNGTests/Config/Settings/DockPanelSerializerTests.cs
Normal file
35
mRemoteNGTests/Config/Settings/DockPanelSerializerTests.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Settings;
|
||||
using NUnit.Framework;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
|
||||
namespace mRemoteNGTests.Config.Settings
|
||||
{
|
||||
public class DockPanelSerializerTests
|
||||
{
|
||||
private DockPanelLayoutSerializer _dockPanelLayoutSerializer;
|
||||
private DockPanel _dockPanel;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_dockPanelLayoutSerializer = new DockPanelLayoutSerializer();
|
||||
_dockPanel = new DockPanel();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializerProducesValidDockPanelXml()
|
||||
{
|
||||
var serializedData = _dockPanelLayoutSerializer.Serialize(_dockPanel);
|
||||
var serializedDataAsXDoc = XDocument.Parse(serializedData);
|
||||
Assert.That(serializedDataAsXDoc.Root?.Name.ToString(), Is.EqualTo("DockPanel"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CantProvideNullDockPanel()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _dockPanelLayoutSerializer.Serialize(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,8 +1,9 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using NUnit.Framework;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
@@ -74,6 +75,22 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(hasEverythingInheritedProperty, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AlwaysReturnInheritedValueIfRequested()
|
||||
{
|
||||
var expectedSetting = false;
|
||||
|
||||
var container = new ContainerInfo { AutomaticResize = expectedSetting };
|
||||
var con1 = new ConnectionInfo
|
||||
{
|
||||
AutomaticResize = true,
|
||||
Inheritance = {AutomaticResize = true}
|
||||
};
|
||||
container.AddChild(con1);
|
||||
|
||||
Assert.That(con1.AutomaticResize, Is.EqualTo(expectedSetting));
|
||||
}
|
||||
|
||||
private bool AllInheritancePropertiesAreTrue()
|
||||
{
|
||||
var allPropertiesTrue = true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user