Compare commits

...

312 Commits

Author SHA1 Message Date
David Sparer
68f052efcb Merge branch 'hotfix10' 2017-10-29 12:44:53 -05:00
David Sparer
4a8baf79fb bumped assembly version 2017-10-29 12:44:18 -05:00
David Sparer
499ac0295e fixed one case where visible connection tree width wasnt being updated correctly 2017-10-29 12:33:29 -05:00
David Sparer
29c422501a resolves #756 2017-10-29 12:17:18 -05:00
David Sparer
8efe74f614 bump assembly version 2017-10-28 16:25:08 -05:00
David Sparer
4e0f12f4b9 Merge branch 'Patch9' 2017-10-28 15:55:09 -05:00
David Sparer
cbd3a61259 updated changelog and credits 2017-10-28 15:48:16 -05:00
David Sparer
2406a7be49 fixes #600 2017-10-28 15:12:30 -05:00
David Sparer
dd40b56047 Merge pull request #728 from dekelMP/Patch9
Fixed #529
2017-10-27 18:55:22 -05:00
Sean Kaim
f14a0d5ee3 Merge pull request #710 from pedro2555/issue#649-cannot-integrate-cli-apps
Fixed integrated cli apps?
2017-10-19 09:54:07 -04:00
Dekel Asaf
e0383d6c59 Fixed #529 2017-09-22 20:57:46 +03:00
Pedro Rodrigues
eeabcd94ed re-removed WaitForInputIdle
later consideration
2017-09-19 23:07:55 +01:00
Sean Kaim
8a3e37041a remove unnecessary converts 2017-09-18 17:37:04 -04:00
Sean Kaim
a1e9aefeb2 Merge branch 'Patch9' of https://github.com/mRemoteNG/mRemoteNG into Patch9 2017-09-18 10:02:09 -04:00
Sean Kaim
670cb51352 unnecessary convert.tostring's 2017-09-18 10:02:07 -04:00
Sean Kaim
a43dff88c5 Merge pull request #715 from pedro2555/492
fallback to empty credentials settings in external apps
2017-09-18 09:58:24 -04:00
David Sparer
fb3c87359f Merge pull request #724 from mRemoteNG/482_proposed_fix
Default connection password must be decrypted before first use
2017-09-18 08:48:06 -05:00
kmscode
a49dec7e6d just claify a comment. 2017-09-17 14:57:56 -04:00
kmscode
a7156235c3 puttyng 0.70
fixes #635
2017-09-17 14:22:36 -04:00
David Sparer
3cb52ba3f1 rearranged program init to ensure ConDefaultPassword is decrypted before assignment to DefaultConnectionInfo object 2017-09-17 11:10:32 -05:00
Sean Kaim
024f1a7047 minor code clean up 2017-09-15 17:37:28 -04:00
Sean Kaim
b77c7e922f Merge pull request #720 from pedro2555/676
First startup ignores cons param
2017-09-15 17:33:22 -04:00
Sean Kaim
9335c4706b fix editbin post build on jenkins 2017-09-15 16:52:42 -04:00
Sean Kaim
e09a9dabd6 update nuget packages 2017-09-15 15:42:28 -04:00
Pedro Rodrigues
e4e2f50015 Saving settings before exiting, and avoid early return 2017-09-15 20:38:34 +01:00
Sean Kaim
61865050c7 minor code cleanup 2017-09-15 15:34:54 -04:00
Sean Kaim
05d90c26ff Merge pull request #709 from pedro2555/issue#335
Changed quick connect connection icon image to play icon when there a…
2017-09-15 15:31:16 -04:00
Sean Kaim
43cdb29eb6 we don't need to look in ProgramData 2017-09-15 15:28:29 -04:00
Pedro Rodrigues
87ff1cb2b2 preparing ConsParam, and use Path.Combine in favor of string concatenation 2017-09-15 19:36:00 +01:00
Pedro Rodrigues
f73c9c9d02 Refactored cons param, corrected fallback override on first initialization.
Fixes 676
2017-09-15 19:17:08 +01:00
Sean Kaim
d15e444cb7 code clean up / null checks & logging 2017-09-15 13:58:32 -04:00
Pedro Rodrigues
2eff6c3dc4 if ( == false) is confusing, no need for it, if no else then ! 2017-09-15 18:49:06 +01:00
David Sparer
41fe211aec resolved #610 2017-09-15 08:07:12 -05:00
David Sparer
2acfa6d88d added another valid MS certificate thumbprint for build tools 2017-09-14 14:57:40 -05:00
Pedro Rodrigues
348b0c728c fallback to empty credentials settings in external apps #492 2017-09-14 20:16:53 +01:00
Pedro Rodrigues
875e1573a4 Fixed integrated cli apps?
What was WaitForInputIdle() then?
2017-09-11 01:01:18 +01:00
Pedro Rodrigues
926dc868ef Changed quick connect connection icon image to play icon when there are open connections 2017-09-10 22:42:29 +01:00
kmscode
86ecb38ae2 minor code cleanup 2017-09-09 15:36:53 -04:00
Sean Kaim
f3ca58111c Merge pull request #705 from pedro2555/fix-proposal-issue#665
Fix proposal for issue 'Can not add new connection or new folder'
2017-09-09 15:34:44 -04:00
kmscode
3124d3ca1c minor code cleanup 2017-09-09 15:10:33 -04:00
Sean Kaim
9012506209 Merge pull request #700 from pedro2555/fix-write-log-file-option
Prevented log file creation when writeLogFile option is not set
2017-09-09 15:01:06 -04:00
kmscode
adb874ca74 avoid writing to the log when configured not to
plus some minor optimization.
2017-09-09 14:59:42 -04:00
kmscode
6aaf2f031b find editbin for vs 2017 community
updated acceptable authenticode for editbin.
2017-09-09 14:26:38 -04:00
Pedro Rodrigues
1669377938 Use root node when creating new connection/folder and no node is selected 2017-09-09 17:17:23 +01:00
Pedro Rodrigues
198c235765 Prevent log file writing when option is not set 2017-09-06 22:19:32 +01:00
David Sparer
66f2c55343 Merge remote-tracking branch 'origin/master' into Patch9 2017-08-10 17:19:29 -05:00
David Sparer
0f3fa86bed Merge pull request #677 from mRemoteNG/improve_publish_automation
Improve publish automation
2017-08-10 17:18:19 -05:00
David Sparer
e5c2cfd243 fix github release body builder function 2017-08-10 16:35:17 -05:00
David Sparer
ef1c397f11 updated changelog 2017-08-05 11:02:16 -05:00
David Sparer
12e0cc3d7b Merge pull request #652 from mrwulf/Issue550
Issue #550 Fix - Don't propagate edit if it didn't come from the menu item
2017-08-05 10:59:06 -05:00
David Sparer
ff6bb6ebb0 update changelog and credits 2017-08-05 10:52:36 -05:00
David Sparer
6b78215b2e Merge pull request #651 from mrwulf/Issue176
Only do ActivateConnection when one of our known controls wasn't clicked (Addresses Issue #176)
2017-08-05 10:45:16 -05:00
Sean Kaim
5d9a02657f Fixes #658
Also fix a comment.
2017-07-28 15:25:56 -04:00
Brandon Wulf
14d670a9a2 Don't propagate edit if it didn't come from the menu item 2017-07-21 15:38:46 -07:00
Brandon Wulf
67801506e0 Only do ActivateConnection when one of our known controls wasn't clicked. 2017-07-21 14:19:08 -07:00
Sean Kaim
48eb6dbbe0 updated changelog 2017-07-18 15:13:48 -04:00
Sean Kaim
d520c6a816 Exception after clicking on import port scan
Fixes #646
2017-07-18 14:31:21 -04:00
David Sparer
664799c01b minor fix to allow building on some older machines
Oder editbin.exe files from Microsoft were signed with a different cert thumbprint. This update makes it easier to add additional valid thumbprints for MS signed tools
2017-06-27 12:20:39 -05:00
David Sparer
d88c5b9db2 minor error message correction
changed an error message that referred to File -> Load Connections (which doesn't exist). Changed this to File -> Open Connection File
2017-06-27 12:15:38 -05:00
Sean Kaim
0fe7a693f8 changelog 2017-06-16 10:08:04 -04:00
Sean Kaim
9a2efd9686 Exception launching ExtTool without con selected 2017-06-16 09:54:52 -04:00
Sean Kaim
88961fbdb5 Merge pull request #593 from mRemoteNG/kmscode-patch-1
changelog update
2017-06-15 15:02:20 -04:00
Sean Kaim
a11ceced09 changelog update 2017-06-15 15:00:34 -04:00
Sean Kaim
ca35662ca2 Merge pull request #592 from mRemoteNG/hotfix7
Hotfix8
2017-06-15 11:52:59 -04:00
Sean Kaim
e7c4bbe1e8 increment version 2017-06-15 11:33:50 -04:00
Sean Kaim
1bc56b5c9e Merge remote-tracking branch 'refs/remotes/origin/master' into hotfix7 2017-06-15 11:29:55 -04:00
Sean Kaim
25a0630bcb updated putty build
New version number: 0.69.0.1

Fixes #589
2017-06-15 11:28:41 -04:00
Sean Kaim
1f7d122bee clean up installer build a bit 2017-06-15 11:19:30 -04:00
Sean Kaim
d9cb32ca53 enable verbose logging within the MSI 2017-06-15 11:19:02 -04:00
David Sparer
760587ee2e Merge pull request #590 from mRemoteNG/update_jenkinsfile
jenkins release builds will now clean then build
2017-06-14 11:21:21 -05:00
David Sparer
d2fe8a2ddb builds will now clean then build 2017-06-14 11:14:36 -05:00
Sean Kaim
81b0be0489 Merge pull request #588 from mRemoteNG/hotfix7
Hotfix7 changelog
2017-06-14 11:10:19 -04:00
Sean Kaim
3074a211f8 changelog 2017-06-14 11:08:55 -04:00
Sean Kaim
0659b140f5 Merge pull request #587 from mRemoteNG/hotfix7
Hotfix7
2017-06-14 10:59:06 -04:00
Sean Kaim
0b8160ae34 changelog 2017-06-14 10:57:49 -04:00
Sean Kaim
dbf2b7b4b6 increment version 2017-06-14 10:51:24 -04:00
Sean Kaim
1e8afc8ea4 update readme 2017-06-14 10:48:57 -04:00
Sean Kaim
70bd2e8a78 rebuilt & signed puttyng 0.69 2017-06-14 10:48:46 -04:00
Sean Kaim
8045544051 Merge pull request #581 from mRemoteNG/hotfix6
Hotfix6
2017-06-13 11:15:08 -04:00
Sean Kaim
0cef4dc9b3 changelog update 2017-06-13 10:49:05 -04:00
Sean Kaim
f1cfa4330a fix build/porting problem for about window 2017-06-13 10:42:31 -04:00
Sean Kaim
a50b370262 Use all space on about page
Fixed 377
9c5e4f7a7c
2017-06-13 10:24:40 -04:00
Sean Kaim
064fd217ba initial Hotfix 6 commit 2017-06-02 16:45:23 -04:00
David Sparer
692b26622c Merge pull request #534 from mRemoteNG/530_fix_tree_node_entry_creation_on_exttool_run
530 fix tree node entry creation on exttool run
2017-05-02 10:00:30 -06:00
David Sparer
72a56d33d0 updated changelog 2017-05-02 09:08:49 -06:00
David Sparer
ce4bfc55c1 ConnectionInfo.Clone no longer sets the Parent property
this resolves undesirable tree nodes from being created
2017-05-02 08:49:04 -06:00
David Sparer
f0faec9def Merge pull request #528 from mRemoteNG/hotfix5
1.75 Hotfix5
2017-04-27 15:36:16 -06:00
David Sparer
e6ef28050c set release date in changelog for 1.75.7005 2017-04-27 15:20:07 -06:00
David Sparer
547ec3cb3a updated msi installer requirements
Replaced KB2923545 with KB2830477 (which is the REAL rdp 8.1 update)
2017-04-25 21:06:25 -06:00
David Sparer
fc0f278962 signed putty v0.68 exe 2017-04-20 09:27:14 -06:00
David Sparer
1f3db15892 Merge branch '442_fix_importing_putty_session_with_spaces_in_name' into hotfix5 2017-04-20 09:17:22 -06:00
David Sparer
e3e4c49427 changelog update 2017-04-20 09:16:31 -06:00
David Sparer
1520b8bf73 fixed bug where any sessions with spaces in the name would be filtered out
this fixes the bug, but the entire putty sessions loading component should be refactored heavily
2017-04-20 09:07:21 -06:00
David Sparer
c9e7f82905 fixed minor bug with adding a duplicate default session in some situations 2017-04-20 08:53:57 -06:00
Sean Kaim
d2357fa779 changelog update 2017-04-19 12:38:54 -04:00
Sean Kaim
703178ddf1 Fix NPE when importing from the connection tree
Fixes #518
2017-04-19 12:37:56 -04:00
Sean Kaim
4e9c5de16c changelog 2017-04-17 17:34:09 -04:00
Sean Kaim
3d1fcc35df Update credits.txt 2017-04-17 17:30:14 -04:00
Sean Kaim
e20d7afb72 update changelog 2017-04-17 17:29:32 -04:00
Sean Kaim
07e2bc3858 update change log 2017-04-17 11:56:47 -04:00
Sean Kaim
f3b11d6f72 Fix for #434 - SysTray SafeHandle 2017-04-14 17:25:40 -04:00
Sean Kaim
69f310c02c PuTTYNG.exe 0.68 2017-04-14 17:00:22 -04:00
Sean Kaim
3308f1146c load expanded data properly
and minor optimization
2017-04-14 15:50:20 -04:00
Sean Kaim
8e8cf3df8d check for nulls 2017-04-14 15:34:55 -04:00
Sean Kaim
26fdd924ef Increment version number
And make it match the hotfix number - you have no idea how much that was
annoying me...
2017-04-14 14:44:26 -04:00
Sean Kaim
ea3494f6e7 Merge pull request #512 from mRemoteNG/483_make_datatable_serializer_safer
483 make datatable serializer safer
2017-04-14 14:37:33 -04:00
David Sparer
9f028d9104 added some safety checking for data table deserialization
added some tests for the data table deserializer
2017-04-09 17:36:56 -06:00
David Sparer
f40be696c7 made utility for creating test connection tree models 2017-04-09 17:35:52 -06:00
David Sparer
95a503a390 fix issue with setting up data table 2017-04-09 17:05:36 -06:00
David Sparer
88c51f4933 added some safety checks to the data table serialier 2017-04-09 16:57:56 -06:00
David Sparer
9e20f1dd33 created script for publishing a github release that is currently in draft mode 2017-03-24 18:08:27 -06:00
David Sparer
16be19b5d3 split github functions to a library script 2017-03-24 18:07:23 -06:00
David Sparer
80ac0259b8 fix script name 2017-03-24 16:50:15 -06:00
David Sparer
9f7911923c updated the create_upg_check_files script to be parameterized for use within jenkins 2017-03-24 16:40:41 -06:00
David Sparer
686005071e Merge branch 'resolve_sql_deserialization_issue' 2017-03-24 15:26:28 -06:00
David Sparer
e16d31d605 fixed stupid transposition typo 2017-03-24 15:14:57 -06:00
David Sparer
8b201d22cb added authkey requirement to get-githubrelease in order to show drafts 2017-03-24 15:07:31 -06:00
David Sparer
0f6f8d43bd added cmdlet for retrieving a github release 2017-03-24 14:28:18 -06:00
David Sparer
8f171cddd9 fix content type of msi upload to github 2017-03-24 14:23:38 -06:00
David Sparer
c77c323f73 fix jenkinsfile variable 2017-03-24 14:22:17 -06:00
David Sparer
9e358309e4 Merge branch 'master' into resolve_sql_deserialization_issue 2017-03-24 12:14:26 -06:00
David Sparer
485438f38d Merge pull request #472 from mRemoteNG/fix_jenkinsfile_publish
fixed hard coded branch names in jenkinsfile_publish
2017-03-24 12:06:55 -06:00
David Sparer
fe26a60337 fixed hard coded branch names in jenkinsfile_publish 2017-03-24 12:04:52 -06:00
David Sparer
d2c2de4dd7 Merge branch 'master' into resolve_sql_deserialization_issue 2017-03-24 11:42:01 -06:00
David Sparer
d49d58f7f8 fixed parent reference update issue in mRemoteNGImporter 2017-03-24 11:40:28 -06:00
David Sparer
164d4fff8b Merge pull request #470 from mRemoteNG/pipeline_tests
Create jenkins pipeline script for release automation
2017-03-23 16:46:13 -06:00
David Sparer
7726406674 added loggers to the test runners 2017-03-23 09:40:31 -06:00
David Sparer
ed38b39fec attempting to resolve bug with accessing correct key store 2017-03-23 08:59:09 -06:00
David Sparer
9188d4316e fix variable issue 2017-03-23 08:52:24 -06:00
David Sparer
cf374c6b8b added cert password as an auto-injected resource 2017-03-23 08:29:47 -06:00
David Sparer
82388dcbc3 added finger-printing to artifacting step 2017-03-23 08:26:18 -06:00
David Sparer
7a6a99e2b6 attempting to use the publishing jenkinsfile from scm 2017-03-23 08:08:29 -06:00
David Sparer
c383736834 more debug code 2017-03-22 17:06:30 -06:00
David Sparer
6e5e78df3b investigating certificate unlock issues 2017-03-22 17:03:38 -06:00
David Sparer
311bf1b641 fix issue with retrieving fuzzy file name 2017-03-22 16:48:38 -06:00
David Sparer
5c9933791c do base64 decoding in the script 2017-03-22 16:39:47 -06:00
David Sparer
039d4d11aa add a cast to help aleviate bat file issues 2017-03-22 16:33:12 -06:00
David Sparer
c0f2d2aa84 fixed bug 2017-03-22 16:27:28 -06:00
David Sparer
45099bfa07 try to get around weird type casting issue 2017-03-22 16:22:53 -06:00
David Sparer
695ae9d970 added script for publishing a release to github 2017-03-22 14:41:35 -06:00
David Sparer
21eb0064b1 enable code signing for installer 2017-03-22 08:45:25 -06:00
David Sparer
513fe402af signed the firefox binaries 2017-03-21 12:47:47 -06:00
David Sparer
b27e5754e8 fix arg passing 2017-03-21 12:07:49 -06:00
David Sparer
fa7231d77b added puttyng.exe to the sign files exclusion list 2017-03-21 11:52:52 -06:00
David Sparer
f5a30ecb33 added some more support for excluding files from signing 2017-03-21 11:42:50 -06:00
David Sparer
7f22289889 add previously signed puttyng binary 2017-03-21 11:21:12 -06:00
David Sparer
f80c39077a Added ability to exclude items from signing 2017-03-21 11:19:09 -06:00
David Sparer
75c60a1cc4 release certificate resources after we've used them 2017-03-21 11:16:05 -06:00
David Sparer
2cf38d6b7c removed some debug code 2017-03-21 11:15:16 -06:00
David Sparer
482c9c1574 added some temp debugging code 2017-03-21 11:10:33 -06:00
David Sparer
882e59a260 normalized the unit test output folder for the portable builds 2017-03-21 10:55:18 -06:00
David Sparer
7a036956b7 added some certificate checks to be more sure that the editbin we're using is legit 2017-03-21 10:29:48 -06:00
David Sparer
7520b20cf9 fixed bug in setting largeaddressaware 2017-03-21 10:28:49 -06:00
David Sparer
d47ccd75d5 Revert "removed unnecessary build configs for the unit tests project"
This reverts commit 56ff81a0ed.
2017-03-21 10:20:20 -06:00
David Sparer
56ff81a0ed removed unnecessary build configs for the unit tests project
im not even sure we need to distinguish between debug and portable builds, but ill leave it like this for now
2017-03-21 10:10:48 -06:00
David Sparer
8db76f5324 actually fix the sensitive param leakage 2017-03-18 17:25:30 -06:00
David Sparer
a9442ea06e added some error output for cert loading action 2017-03-18 16:30:03 -06:00
David Sparer
92bd0d3ea0 do not echo sensitive params 2017-03-18 16:29:44 -06:00
David Sparer
512d7322b2 request cert path and password as script parameters 2017-03-18 16:13:20 -06:00
David Sparer
45645c439f test of msbuild param passing 2017-03-18 15:13:23 -06:00
David Sparer
84ebb82cae the installer project now uses a powershell script for post build actions 2017-03-18 00:24:39 -06:00
David Sparer
576f6a3bd6 fixed issue with tidying release files 2017-03-18 00:24:07 -06:00
David Sparer
96df821eca changed signature failures from errors to warnings 2017-03-18 00:23:44 -06:00
David Sparer
8589778e92 split postbuild actions into powershell scripts 2017-03-17 23:53:59 -06:00
David Sparer
a8a7de9ee6 began converting all post build actions to powershell 2017-03-17 18:01:08 -06:00
David Sparer
1d99340425 remove quoting 2017-03-17 16:33:27 -06:00
David Sparer
a8cdfb56f3 single quote might be safer 2017-03-17 16:18:20 -06:00
David Sparer
0958cdaa2d ensure paths are quoted 2017-03-17 16:13:12 -06:00
David Sparer
ebfb3dd31e added a build config for the installer 2017-03-17 16:01:50 -06:00
David Sparer
3943b8753f split releases 2017-03-10 14:41:14 -07:00
David Sparer
9e26ea1866 bumped assembly version 2017-03-10 14:26:35 -07:00
David Sparer
8152a87514 bumped patch version 2017-03-10 14:20:23 -07:00
David Sparer
b28775c2c6 made sqlbulkcopy column-position independant 2017-03-10 14:18:55 -07:00
David Sparer
3eb96ef765 set changelog and bumped patch version 2017-03-10 11:40:20 -07:00
David Sparer
8805584cbe updated sql code
- added upgrade script to bring db version up to 2.6
- refactored db upgrade code to a new class
- resolved an issue with db column naming for one of the new features
- updated new sql db creation script
2017-03-10 11:13:26 -07:00
David Sparer
be5c66bd93 Merge pull request #438 from mRemoteNG/1_75_hotfixes
1.75 hotfix 1
2017-03-06 10:33:04 -07:00
David Sparer
5347e5a3aa implemented new versioning scheme. resolves #437 2017-03-06 10:27:25 -07:00
David Sparer
9b22254b6c update changelog 2017-03-06 10:24:41 -07:00
David Sparer
6a67e0ea8b resolved issue with export filter not being respected. resolves #427 2017-03-02 16:42:00 -07:00
David Sparer
7b118995ea updated changelog 2017-03-02 13:26:40 -07:00
David Sparer
35b4564644 turned off a feature of ObjectListView that was stealing focus from keepass autotype events. resolves #312 2017-03-02 13:02:51 -07:00
David Sparer
30df947365 resolved issue when clicking in connection tree white space #422 2017-03-02 08:55:10 -07:00
David Sparer
b1ec975612 Merge pull request #425 from mRemoteNG/1_75_release
1 75 release
2017-03-02 08:51:19 -07:00
David Sparer
1034e434c4 updated changelog with release date 2017-03-01 16:23:40 -07:00
David Sparer
f419bff545 #394 resolved bug where export flag would not get set on the exported connections file 2017-02-16 08:29:31 -07:00
Sean Kaim
69eec0135e Update to SHA512 file hashes 2017-02-15 15:21:18 -05:00
David Sparer
2849baf857 Merge branch '378_ssh_connection_launched_on_single_click' into v1_75_release_candidates 2017-01-30 11:37:10 -07:00
David Sparer
768fdcd0e4 using MouseClick events rather than the OLV CellClick events. this should resolve #378 2017-01-30 11:33:27 -07:00
David Sparer
9b38308ad1 set date for rc1 build in changelog 2017-01-27 15:28:36 -07:00
Sean Kaim
afcdf96e5c changelog / credits update 2017-01-27 17:13:50 -05:00
David Sparer
3e40b08525 Merge pull request #348 from countchappy/develop
RDP Minutes to Idle Timeout - users cant enter invalid timeout values
2017-01-27 14:58:05 -07:00
countchappy
237cf037be RDP Minutes to Idle Timeout - Update 5
Incorrect values entered in the Minutes to Idle Timout setting will be
corrected to fit in the range of 0-240, rather than be truncated.
2017-01-27 14:56:40 -05:00
Sean Kaim
2445c74638 code clean up and minor refactoring 2017-01-25 17:50:10 -05:00
Sean Kaim
6a69ed48a9 Merge pull request #372 from mRemoteNG/serialize_connectioninfo_id
Serialize connectioninfo ID
2017-01-25 17:01:29 -05:00
David Sparer
217693937f connectioninfo id is now serialized to the confCons file 2017-01-25 14:02:20 -07:00
Sean Kaim
22300577cf Merge pull request #371 from jcefoli/develop
Quick fix for #369 (Reset Layout Ignores Notification Pane)
2017-01-25 15:06:39 -05:00
Joe Cefoli
6a07f4e731 Quick fix for #369 2017-01-25 14:02:16 -05:00
David Sparer
63ace60dcc Merge pull request #367 from mRemoteNG/295_default_con_values_not_saved
resolved issue where saving default con properties would fail
2017-01-25 09:58:50 -07:00
David Sparer
601951582d resolved issue where saving default con properties would fail
enum, int, bool -> string was throwing an exception. now using a simpler strategy for type conversion
resolves #295
2017-01-25 09:54:54 -07:00
Sean Kaim
9250dde5b0 Merge pull request #364 from mRemoteNG/176_scheduled_updates
1.76 scheduled updates to 1.75
2017-01-24 20:04:47 -05:00
Sean Kaim
29ca72d8ca Change log update 2017-01-24 20:03:20 -05:00
Sean Kaim
87c89a0de5 reformat code 2017-01-24 19:55:18 -05:00
Sean Kaim
73f72e39d3 Fix incorrect cast & code clean up
Fixes #362
2017-01-24 19:49:22 -05:00
Sean Kaim
e00ba62606 Refactored Tools.Controls.cs
Fixes #363
2017-01-24 17:52:15 -05:00
Sean Kaim
48d53cecce Rename Tab dialog - populate original name
Fixes #258
2017-01-24 17:36:41 -05:00
David Sparer
e0fd81e938 resolved bug when clicking in blank space in the connection tree 2017-01-23 15:32:06 -07:00
Sean Kaim
04f6f4f9cf Make version selectable/copyable
fixes #360

Also update copyright year since it's 2017 now...
2017-01-23 12:59:29 -05:00
David Sparer
25d1e0a74d Merge pull request #352 from mRemoteNG/299_better_testing_of_connection_tree
Refactor connection tree to be more testable
2017-01-18 09:03:26 -07:00
David Sparer
cbd9d16e4c simplified the connection tree refresh method.
the complexity of trying to add refresh optimizations was causing bugs. i will need to find a new way of reducing flicker
2017-01-17 15:31:40 -07:00
David Sparer
cb708b3217 resolved bug where some context menu hot keys would not work after opening the menu on the root node 2017-01-17 13:45:25 -07:00
David Sparer
4e5a22a7e8 resolved a minor bug where creating a new node would screw up the selected node in the tree
We were trying to do multiselection when it is currently not supported by our implementation.
2017-01-17 09:47:00 -07:00
Sean Kaim
3722db93c6 Merge pull request #349 from jogleasonjr/patch-1
Fix typo in README.MD
2017-01-16 17:56:59 -05:00
John Gleason
b43331dc27 Fix typo in README.MD 2017-01-16 15:20:07 -06:00
countchappy
80c6ce81e1 RDP Minutes to Idle Timeout - Update 4
Added an option to alert if disconnected due to inactivity.
2017-01-16 15:14:27 -05:00
David Sparer
1a776359c4 added test for folder expander 2017-01-14 11:44:09 -07:00
David Sparer
113e4035e5 refactored the deletion confirmer to make it testable 2017-01-14 11:14:30 -07:00
David Sparer
a03095ab8e refactored the node deletion confirmer to be interface-based. this will lead to improved testability 2017-01-14 10:38:11 -07:00
David Sparer
d03f830622 added null test for the composite click handler 2017-01-14 10:36:54 -07:00
David Sparer
9b42dc9f10 Refactored some click handlers and created a test for it
During testing I realized that the double and single click handlers were exactly the same thing, so i combined them into the composite click handler.
2017-01-14 10:11:22 -07:00
David Sparer
fd7adf3c64 added some more tests 2017-01-13 17:43:06 -07:00
David Sparer
d0b7e72f15 Merge pull request #342 from countchappy/develop
RDP Optional Minutes to Idle Timeout
2017-01-13 17:05:25 -07:00
countchappy
5a61c6b7df RDP Minutes to Idle Timeout - Update 3.1 2017-01-13 18:49:39 -05:00
countchappy
c897eae04e RDP Minutes to Idle Timeout - Update 3
Fixed name and description not showing up in the config window.
2017-01-13 18:08:36 -05:00
countchappy
c33095cd0e RDP Minutes to Idle Timeout - Update 2.1
Fixed my goof!
2017-01-13 17:11:07 -05:00
David Sparer
05d8b7983a reorganized some test files and added tests for null args 2017-01-13 12:12:22 -07:00
countchappy
166d9f7133 RDP Minutes to Idle Timeout - Update 2
Added null conditional operator to prevent throwing a null reference
error for beta users.
2017-01-13 13:41:19 -05:00
David Sparer
2ce31f35cc more file organizing 2017-01-13 10:54:39 -07:00
David Sparer
ce5d0cefe3 organized some files 2017-01-13 10:41:28 -07:00
David Sparer
6cc668fe83 added more tests for connectiontree delegates 2017-01-12 15:30:30 -07:00
David Sparer
ac0aa8daf4 added a method to the IConnectionTree interface to make testing another class possible 2017-01-12 15:20:32 -07:00
David Sparer
16b094be44 we no longer need the extensions now that we are subclassing TreeListView 2017-01-12 15:16:55 -07:00
David Sparer
b3e6fd7b96 created test for another tree handler 2017-01-12 15:09:24 -07:00
David Sparer
893d5d92f3 made all relevant classes use IConnectionTree 2017-01-12 15:09:05 -07:00
David Sparer
77add0b39d added an interface for iconnectiontree. this kind of hacky and really just exists to make the tests work. this indicates we have some coupling on ConnectionTree that shouldn't be there.. 2017-01-12 15:08:12 -07:00
David Sparer
b4f8ab0a49 moved a call to settings further up in the abstraction level to make testing easier 2017-01-12 14:13:35 -07:00
David Sparer
1d46c44c21 added tests for another click handler 2017-01-12 13:57:44 -07:00
David Sparer
12da35f875 made the rest of the connectioninitiator functions non-static 2017-01-12 13:57:15 -07:00
David Sparer
8970a15d4e added tests for one of the click handlers 2017-01-12 13:33:12 -07:00
David Sparer
82217478d9 made one of the methods for the connectioninitiator non-static (they should eventually all be non-static).
This change was made to making testing easier (make connectioninitiator mockable)
2017-01-12 13:31:29 -07:00
David Sparer
4c792308bb moved all click-actions for the tree to separate classes to make them easily composable
this has the nice effect of also pushing any calls to the settings class outside the classes that are actualy doing work, making them much easier to test in isolation
2017-01-12 12:47:23 -07:00
David Sparer
978d94a2cd resolved issue with unit test. we could not select a tree object without that object being visible 2017-01-12 11:12:18 -07:00
David Sparer
b195d89b76 moved a few more functions closer to their call site 2017-01-12 11:02:11 -07:00
David Sparer
875888a341 moved a method closer to its call site 2017-01-12 10:51:05 -07:00
David Sparer
6631a13d20 cleanup 2017-01-12 10:31:50 -07:00
David Sparer
28728fe29f moved some connectiontree post setup actions into their own classes. post setup actions are now managed by a composite 2017-01-12 10:29:30 -07:00
David Sparer
aa954cbea9 minor cleanup 2017-01-12 09:24:59 -07:00
David Sparer
dae339f494 moved the image getter delegate code into its imagelist since the img names have to match up. seems like a better division of responsibility 2017-01-12 09:17:34 -07:00
David Sparer
5bcb59f876 moved the setup of the tree image list to its own class 2017-01-12 08:59:34 -07:00
David Sparer
9132592fd7 moved the setup of the name column to its own class 2017-01-12 08:58:52 -07:00
Sean Kaim
ca592fac77 update change log 2017-01-11 17:56:37 -05:00
Sean Kaim
ea657824c2 Streamlined non-integrated IntApp connections
This seems to fix #325
2017-01-11 17:49:37 -05:00
Sean Kaim
99e7072e27 code clean up
relates to #325
2017-01-11 17:01:08 -05:00
David Sparer
ad32f4a0a3 Merge branch 'develop' into 299_better_testing_of_connection_tree 2017-01-11 15:00:44 -07:00
David Sparer
b9cdd0996d moved click handling responsibility out of the connectiontreewindow and into the context menu class 2017-01-11 14:58:29 -07:00
Sean Kaim
e92a76f95b "return ;" annoyed me...
And I did a find and replace in the solution instead of the one file I
was working on... So I'm going with it...
2017-01-11 16:56:14 -05:00
countchappy
10d152342f RDP Minutes to Idle Timeout - Update 1
Fixed some language file stuff.
2017-01-11 16:44:53 -05:00
countchappy
7e4b0635b2 RDP Minutes To Idle Timeout
Allows users to configure a number of minutes until the session will
automatically disconnect if left idle.
2017-01-11 15:23:43 -05:00
Sean Kaim
eec17f10d5 update changelog 2017-01-10 10:54:03 -05:00
Sean Kaim
ac9d5dfa95 code clean up 2017-01-10 10:51:34 -05:00
Sean Kaim
4c2b3738c2 Don't attempt to connect to folders
Fixes #334
2017-01-10 10:46:34 -05:00
Sean Kaim
6f29183b45 code clean up and logging / exception handling 2017-01-09 11:32:04 -05:00
Sean Kaim
dd65c9c588 update changelog 2017-01-06 12:53:56 -05:00
Sean Kaim
cb8bb05627 Merge pull request #329 from mRemoteNG/release_channels
Add Release channels
2017-01-06 12:32:05 -05:00
David Sparer
256f6d8fdd extracted and renamed some methods 2017-01-06 10:15:33 -07:00
Sean Kaim
a88fdddecb allow all tests to pass regardless of build type 2017-01-06 11:58:00 -05:00
Sean Kaim
fd5e3e24df Run tests from local resources 2017-01-06 11:16:02 -05:00
Sean Kaim
244d27427d update some log messages 2017-01-05 14:30:24 -05:00
Sean Kaim
55c42a3cca Merge remote-tracking branch 'refs/remotes/origin/develop' into release_channels 2017-01-05 11:21:46 -05:00
Sean Kaim
3c9cfbdf92 log exception messages only 2017-01-05 11:13:43 -05:00
Sean Kaim
46dd58d26e External Tool/Connection - code clean up & logging
Relates to #325
2017-01-05 11:05:59 -05:00
Sean Kaim
051dd2e567 Add Beta and Dev tests 2017-01-04 11:15:51 -05:00
Sean Kaim
17ccf40082 re-add version check & adjust CPU target for tests
fixed compliler warning regarding architecture mismatch.
2017-01-04 10:47:23 -05:00
Sean Kaim
0f2b61694d Merge remote-tracking branch 'refs/remotes/origin/develop' into release_channels 2017-01-04 09:15:22 -05:00
Sean Kaim
0aed66df47 fix build & test failure 2017-01-03 18:17:03 -05:00
Sean Kaim
94a6e9a886 code clean up around startup / frmMain
Slightly related to #298
2016-12-22 10:01:20 -05:00
Sean Kaim
355f48b6ba We want only Valid info! 2016-12-16 17:29:03 -05:00
Sean Kaim
d1a6526c22 Added functional UpdateStableChannel test
It's working! It's working!
2016-12-16 17:27:57 -05:00
Sean Kaim
975a308647 reworking code to better test & code cleanup 2016-12-15 17:44:55 -05:00
Sean Kaim
5138eaeb68 Merge remote-tracking branch 'refs/remotes/origin/develop' into release_channels 2016-12-15 15:02:30 -05:00
David Sparer
45dfaa1b21 removed unused code 2016-12-13 13:11:50 -07:00
David Sparer
715f92f3d5 removed unnecessary code 2016-12-13 13:07:52 -07:00
Sean Kaim
8d5a765040 pass importSubOU option in to recursive calls
Fixes remaining problems reported in #211
2016-12-13 14:22:39 -05:00
Sean Kaim
34fa6b158b load the default domain when opening the form
Related to #311
2016-12-13 13:34:44 -05:00
David Sparer
78c1f6b8e3 Fixed bug where we could not drop between items (rearrange) 2016-12-13 10:28:38 -07:00
David Sparer
adccb91106 removed unnecessary code 2016-12-13 10:06:50 -07:00
David Sparer
1e213dfff7 resolved issue with deleting the last folder in the tree 2016-12-13 09:58:24 -07:00
David Sparer
d469fa1d40 Made the deletion confirmation functionality plugable to make testing easier 2016-12-13 09:51:18 -07:00
David Sparer
737db469ba Fixed test name 2016-12-13 09:27:32 -07:00
David Sparer
a44a33d508 minor cleanup 2016-12-13 09:16:05 -07:00
David Sparer
a518d41c78 updated connection tree window tests 2016-12-13 09:07:21 -07:00
David Sparer
d5360c6568 Completed splitting the connection tree from the connection tree window 2016-12-13 09:00:38 -07:00
Sean Kaim
d468107311 Load users default/current domain
Fixes #311

Caused by 97a0e2413e

Some code clean up as well...
2016-12-13 10:50:36 -05:00
Sean Kaim
3f65e1bfa0 add tests for update channels
Some code clean up as well...
2016-12-13 10:31:16 -05:00
David Sparer
a22758f5cd organized code into regions to help prepare for later refactoring 2016-12-09 12:57:26 -07:00
David Sparer
88b5b9d1e7 began moving connectiontree functions out of the code for the window and into its own class.
this will improve testability and reduce class complexity
2016-12-07 15:07:15 -07:00
Sean Kaim
e38f7c880e code clean up
Added some log messages for #298
2016-12-06 19:13:09 -05:00
David Sparer
6367b58994 began adding unit tests for the connectiontree ui 2016-12-06 15:28:56 -07:00
David Sparer
5a54b5ee64 Merge pull request #292 from ForensicITGuy/develop
Added code and screenshots for Quick Connect help files
2016-12-06 08:36:00 -07:00
ForensicITGuy
002e41f418 Added Quick Connect screenshots into project. Modified folder name and HTML code to include spaces as observed in the other screenshot folders. Set to track content and copy if newer in output. 2016-12-06 01:04:52 -06:00
David Sparer
f7787c748a Added multiple build badges based on update channel to readme.md 2016-12-03 11:17:41 -07:00
David Sparer
f9b18b45a4 updated the jenkins build badge to point to the sanitized url. added a title to readme.md 2016-12-03 10:46:20 -07:00
David Sparer
8966f44272 resolved issue with Jenkins not being about the build PRs 2016-12-02 16:49:49 -07:00
Tony M Lambert
3dbcbae61f Added code for Quick Connect documentation
Added HTML code to document Quick Connect functionality
2016-12-02 15:49:04 -06:00
Sean Kaim
24508abe7a rename channels 2016-12-02 16:41:37 -05:00
Tony M Lambert
27f8f2542e Added screenshots for Quickconnect documentation 2016-12-02 15:25:05 -06:00
Sean Kaim
44ee3ceec8 User Selectable Release Channels
Final = Final
Beta = Beta & RC
Pre-Release = Alpha, Beta & RC
2016-12-02 14:57:49 -05:00
Sean Kaim
b08112aec0 Load Ext Tools - add logging
Relates to #291 & #236
2016-12-02 12:20:02 -05:00
Sean Kaim
9d2bbda2b9 ExtTools code clean up
Relates to #291 & #236
2016-12-02 12:11:46 -05:00
David Sparer
6eff685b18 updated changelog 2016-12-01 15:40:04 -07:00
David Sparer
2d08146de8 updated changelog for 1.75beta3 2016-12-01 15:38:26 -07:00
Sean Kaim
f131420a44 Change from .exe to .msi
Fixes #289
2016-12-01 17:22:50 -05:00
David Sparer
245ea5463e updated the folder path resolution for the release folder to be a bit safer 2016-12-01 15:04:49 -07:00
205 changed files with 5621 additions and 5423 deletions

View File

@@ -1,3 +1,177 @@
1.75.7010 (2017-10-29):
Fixes:
------
#756: CustomConsPath always null
1.75.7009 (2017-10-28):
Fixes:
------
#676: Portable version ignores /cons param on first run
#675: Attempting to add new connection/folder does not work in some situations
#665: Can not add new connection or new folder in some situations
#658: Keep Port Scan tab open after import
#646: Exception after click on import port scan
#635: Updated PuTTYNG to 0.70
#610: mRemoteNG cannot start /crashes for some users on Windows server 2012 R2 server
#600: Missing horizontal scrollbar on Connections Panel
#596: Exception when launching external tool without a connection selected
#550: Sometimes double-clicking connection tree node began rename instead of connecting
#536: Prevented log file creation when writeLogFile option is not set
#529: Erratic Tree Selection when using SQL Database
#482: Default connection password not decrypted when loaded
#335: The Quick Connect Toolbar > Connection view does not show open connections with the play icon
#176: Unable to enter text in Quick Connect when SSH connection active
Minor error message correction
Minor code refactoring
NO.RELEASE (2017-06-15):
Fixed in previous releases:
---------------------------
#466: Installer still failing on Win7 for updates - v1.75.7005 (Hotifx 5)
#462: Remove no longer used files from portable version - v1.75.7003 (Hotfix 4)
1.75.7008 (2017-06-15):
Fixes:
------
#589: MSI doesn't update with newer PuTTYNG version that fixes #583 (Again, Sorry!)
Minor updates to the installer build
1.75.7007 (2017-06-14):
Fixes:
------
#583: SSH (PuTTYNG) Sessions are not properly integrated into the main mRemoteNG window (Sorry!)
1.75.7006 (2017-06-13):
Fixes:
------
#377: Use all space on About page
#527: Additional protections to avoid problems on update check in heavily firewalled environments
#530: Fixed issue where using External Tool on existing connection causes creation of 'New Connection' entry
#531: Update PuTTYNG to 0.69
#546: Quick Connect from notification area icon displays warning when clicking on a folder (see #334)
1.75.7005 (2017-04-27):
Fixes:
------
#410: Update PuTTYNG to 0.68
#434: Fix complier warnings CA1049 & CA2111
#442: Fixed issue loading PuTTY sessions that have spaces in the name
#502: Problems with ParentID for Duplicated Containers/Connections with SQL Connection Storage
#514: Expanded property not saved/loaded properly from SQL
#518: Exception when Importing File
General Changes:
----------------
Minor code cleanup/optimizations/null checks
1.75.7003 (2017-03-24):
Fixes:
------
#464: Resolved issue when importing a connections file while using SQL server feature
1.75.7002 (2017-03-10):
Fixes:
------
#448: Resolved issue with SQL saving
1.75.7001 (2017-03-10):
Fixes:
------
#408: Update SQL scripts
1.75 hotfix 1 (2017-03-06):
General Changes:
----------------
#437: Modify version numbering scheme
Fixes:
------
#422: Uncaught exception when clicking in connection tree whitespace
#312: Resolved KeePass auto-type issue
#427: Export does not respect filtering user/password/domain
1.75 (2017-03-01):
Known Issue:
------------
File hash check will fail when updating from 1.75 Beta 1 to newer versions.
Exception will be: "MD5 Hashes didn't match!" for 1.75 Beta 1 - 1.75 RC1
Features/Enhancements:
----------------------
#344 - Use SHA512 File Hashes to validate downloads (in the update mechanism & posted to the Downloads page)
1.75 RC1 (2017-01-27):
Known Issue:
------------
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
Features/Enhancements:
----------------------
Added Release Channels to the update check functionality allowing users to select one of 3 release channels for updates: Stable, Beta, Dev
#360: Help -> About, Version # is now selectable/copyable
#221: RDP: Optional disconnect after X number of minutes of inactivity
Fixes:
------
#369: Reset Layout Option Does Not Reset Notification Pane
#362: Invalid cast exception when using the Notification Area Icon minimize/restore
#334: Quick Connect displays warning when clicking on a folder
#325: When using a connection with an external app, results in opening the same external app continuously
#311: Import from Active Directory does not use machine's domain by default
#258: Rename Tab dialog - populate original name in dialog (1.72 functionality)
#211, #267: Recursive AD Import wasn't fully functional
General Changes:
----------------
The usual general code clean up and refactoring
#325: Code clean up and additional logging for External Tools based connections
#298: Code clean up and additional logging around application startup
#291, #236: External Tools code clean up and additional logging
1.75 Beta 3 (2016-12-01):
Known Issue:
------------
Portable build MD5 check will fail when updating from 1.75 Beta 1 to newer versions.
Fixes:
------
#289: Install fails during update process (only affects v1.75 beta 1 - v1.75 beta 2)
1.75 Beta 2 (2016-12-01):
Features/Enhancements:
@@ -10,7 +184,7 @@ Fixes:
------
#254: Component check window position issues and uncaught exception
#260: Crash when attempting to load fully encrypted confCons v2.5
#261: Double clicking folder in treeview doesnt expand it in 1.75 beta1
#261: Double clicking folder in treeview doesn't expand it in 1.75 beta1
#271: Install package is not using the last installation path
#278: Silent installs not detecting prerequisites
@@ -54,7 +228,7 @@ Fixes:
MR-965, MR-871, MR-629: Error 264 on RDP Connect attempt - Added timeout value to Tools -> Options -> Connections
MR-946: Remove old/insecure SharpSSH and related components. Replace with SSH.NET for File Transfer Functionality
MR-896: Added prerequisite installer check for KB2574819. Prevents "Class not registered" errors when opening RDP connections.
PR-130: Fix Scan button width to fit russian translation
PR-130: Fix Scan button width to fit Russian translation
@@ -62,7 +236,7 @@ PR-130: Fix Scan button width to fit russian translation
General Changes:
----------------
Updated GeckoFx pacakge
Updated GeckoFx package
Updated DockPanelSuite library to 2.10 Final
Japanese translation updated
MR-942: Refactored code relating to loading the connections file
@@ -137,7 +311,7 @@ Port Scan is now Asynchronous (and is significantly faster)
Fixes:
------
MR-874: Added work-around to installer to ignore installation prerequisites
MR-884: Slow startup in some scnearios checking authenticode certificate
MR-884: Slow startup in some scenarios checking authenticode certificate
MR-872: Crash in External Tools when arguments aren't quoted
MR-854: crashes when right clicking on connection tab
MR-852: Option "Allow only a single instance of the application" non-functional
@@ -278,7 +452,7 @@ Fixed issue MR-398 - Full Screen mode doesn't correctly make use of available sp
Fixed issue MR-402 - scrollbar touch moves putty window
Fixed issue MR-406 - Items disappear from External Tools toolbar when accessing External Tools panel
Fixed issue MR-410 - Unhandled exception when clicking New button under Theme
Fixed issue MR-413 - Can't use aplication
Fixed issue MR-413 - Can't use application
Fixed new connections having a globe icon.
Fixed the category names in the themes tab of the options dialog on Windows XP not showing correctly.
Fixed PuTTY saved sessions with spaces or special characters not being listed.

View File

@@ -8,7 +8,12 @@ Sean Kaim (github.com/kmscode)
Thanks for the awesome new website!
Bennett Blodinger (github.com/benwa)
Joe Cefoli (github.com/jcefoli)
countchappy (github.com/countchappy)
Tony Lambert
Brandon Wulf (github.com/mrwulf)
Pedro Rodrigues (github.com/pedro2555)
github.com/dekelMP
Past Contributors
@@ -96,8 +101,8 @@ Copyright
Freely redistributable with attribution
http://www.dotnetmagic.com/magic_download.html
PuTTY 0.67
Copyright <20> 1997-2016 Simon Tatham
PuTTY 0.68
Copyright <20> 1997-2017 Simon Tatham
MIT License
http://www.chiark.greenend.org.uk/~sgtatham/putty/

View File

@@ -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 ?>

View File

@@ -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>
@@ -115,20 +111,19 @@
<DefineConstants>HarvestPath=$(SolutionDir)mRemoteV1\bin\Release Portable;HelpFilesHarvestPath=$(SolutionDir)mRemoteV1\Resources\Help</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>set /p buildenv=&lt;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 "&amp;""$(SolutionDir)Tools\signfiles.ps1""" %27%25cd%25%27
)
)
powershell -noprofile -command "sleep 2"
set /p buildenv=&lt;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 +132,9 @@ rmdir /S /Q "$(TargetDir)"
echo $(ConfigurationName) &gt; 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>

View File

@@ -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>

View File

@@ -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>

6
Jenkinsfile vendored
View File

@@ -5,11 +5,7 @@ node('windows') {
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
stage 'Checkout Branch'
checkout([
$class: 'GitSCM',
branches: scm.branches,
userRemoteConfigs: scm.userRemoteConfigs
])
checkout scm
stage 'Restore NuGet Packages'
def nugetPath = "C:\\nuget.exe"

View File

@@ -0,0 +1,68 @@
node('windows') {
def jobDir = pwd()
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions"
stage ('Clean output dir') {
bat script: "rmdir /S /Q \"${jobDir}\\Release\" 2>nul", returnStatus: true
}
stage ('Checkout Branch') {
checkout([
$class: 'GitSCM',
branches: [[name: '*/${TargetBranch}']],
doGenerateSubmoduleConfigurations: false,
extensions: [],
submoduleCfg: [],
userRemoteConfigs: [[
credentialsId: '9c3fbff4-5b90-402f-a298-00e607fcec87',
url: 'https://github.com/mRemoteNG/mRemoteNG.git'
]]
])
}
stage ('Restore NuGet Packages') {
def nugetPath = "C:\\nuget.exe"
bat "${nugetPath} restore ${solutionFilePath}"
}
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) {
withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
stage ('Build mRemoteNG (Normal - MSI)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
}
stage ('Build mRemoteNG (Portable)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
}
}
}
stage ('Run Unit Tests (Normal - MSI)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\""
}
stage ('Run Unit Tests (Portable)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\""
}
stage ('Generate UpdateCheck Files') {
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\""
archiveArtifacts artifacts: "Release\\*.txt", caseSensitive: false, onlyIfSuccessful: true
}
stage ('Publish to GitHub') {
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
def zipPath = "${jobDir}\\Release\\*.zip"
def msiPath = "${jobDir}\\Release\\*.msi"
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell
def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString()
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ZipFilePath \"${zipPath}\" -MsiFilePath \"${msiPath}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
}
}
}

View File

@@ -1,16 +1,20 @@
# Welcome to the mRemoteNG project!
[![Twitter Follow](https://img.shields.io/twitter/follow/mRemoteNG.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=mRemoteNG)
[![Join the chat at https://gitter.im/mRemoteNG/PublicChat/](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mRemoteNG/PublicChat)
[![PayPal](https://img.shields.io/badge/%24-PayPal-blue.svg)](https://www.paypal.me/DavidSparer)
[![Build Status](http://ec2-52-39-111-114.us-west-2.compute.amazonaws.com:8080/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](http://ec2-52-39-111-114.us-west-2.compute.amazonaws.com:8080/job/mRemoteNG/job/mRemoteNG/job/develop/)
[![Issues In Progress](https://badge.waffle.io/mRemoteNG/mRemoteNG.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/mRemoteNG/mRemoteNG)
[![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.74/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/529/badge)](https://bestpractices.coreinfrastructure.org/projects/529)
[![Issues In Progress](https://badge.waffle.io/mRemoteNG/mRemoteNG.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/mRemoteNG/mRemoteNG)
| Update Channel | Build Status | Downloads |
| ---------------|--------------|-----------|
| Stable | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/master)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Hotfix7/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Hotfix7) |
| Beta | | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Hotfix7/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Hotfix7) |
| Development | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) | - |
mRemoteNG is the next generation of mRemote, a full-featured, multi-tab remote connections manager.
@@ -22,9 +26,9 @@ Currently these protocols are supported:
* VNC (Virtual Network Computing)
* ICA (Independent Computing Architecture)
* SSH (Secure Shell)
* Telnet (TELecommunication NETwork)
* HTTP/S (Hypertext Transfer Protocol)
* Rlogin (Rlogin)
* Telnet (Teletype Network)
* HTTP/S (Hypertext Transfer Protocol Secure)
* Rlogin (Remote Login)
* RAW
mRemoteNG can be installed on Windows 7 or later.
@@ -36,8 +40,8 @@ https://support.microsoft.com/en-us/kb/2923545
Windows 8+ support RDP version 8+ out of the box.
RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connection successfully to a Windows 2003 host (for example).
RDP versions are backwards compatible, so an mRemoteNG client running on Windows 10 can connect successfully to a Windows 2003 host (for example).
[![Developed with ReSharper](https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/.github/icon_ReSharper.png)](https://www.jetbrains.com/resharper/)
[![Developed with ReSharper](https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/.github/icon_ReSharper.png)](https://www.jetbrains.com/resharper/)

15
Tools/copy_puttyng.ps1 Normal file
View 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 ""

View File

@@ -1,16 +1,21 @@
$sourcePath = $args[0]
$destinationDir = $args[1]
param (
[string]
$SourcePath,
Write-Host $sourcePath
Write-Host $destinationDir
[string]
$DestinationDir
)
if (!(Test-Path -Path $destinationDir))
Write-Host $SourcePath
Write-Host $DestinationDir
if (!(Test-Path -Path $DestinationDir))
{
New-Item -Path $destinationDir -ItemType "directory"
New-Item -Path $DestinationDir -ItemType "directory"
}
$sourceFiles = Get-ChildItem -Path $sourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
$sourceFiles = Get-ChildItem -Path $SourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
foreach ($item in $sourceFiles)
{
Copy-Item -Path $item.FullName -Destination $destinationDir -Force
Copy-Item -Path $item.FullName -Destination $DestinationDir -Force
}

View File

@@ -1,41 +1,109 @@
#Requires -Version 4.0
param (
[string]
[Parameter(Mandatory=$true)]
$TagName,
$tag = Read-Host -Prompt 'Tag name'
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Stable","Beta","Development")]
$UpdateChannel
)
Write-Host
Write-Host
Write-Host
Write-Host PORTABLE
Write-Host --------
$file = gci ..\Release\*.zip | sort LastWriteTime | select -last 1 | % { $_.FullName }
$filename = $file.Split("\") | select -last 1
$version = $file.tostring().Split("-")[2].trim(".zip")
Write-Host Version: $version
function New-MsiUpdateFileContent {
param (
[System.IO.FileInfo]
[Parameter(Mandatory=$true)]
$MsiFile,
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
[string]
[Parameter(Mandatory=$true)]
$TagName
)
$version = $MsiFile.BaseName -replace "[a-zA-Z-]*"
$certThumbprint = (Get-AuthenticodeSignature -FilePath $MsiFile).SignerCertificate.Thumbprint
$hash = Get-FileHash -Algorithm SHA512 $MsiFile | % { $_.Hash }
$hash = Get-FileHash -Algorithm MD5 $file | % { $_.Hash }
Write-Host Checksum: $hash
$fileContents = `
"Version: $version
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$TagName/$($MsiFile.Name)
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$TagName/CHANGELOG.TXT
CertificateThumbprint: $certThumbprint
Checksum: $hash"
Write-Output $fileContents
}
Write-Host
Write-Host
Write-Host
Write-Host MSI
Write-Host ---
$file = gci ..\Release\*.msi | sort LastWriteTime | select -last 1 | % { $_.FullName }
$filename = $file.Split("\") | select -last 1
function New-ZipUpdateFileContent {
param (
[System.IO.FileInfo]
[Parameter(Mandatory=$true)]
$ZipFile,
$version = $file.tostring().Split("-")[2].trim(".msi")
Write-Host Version: $version
[string]
[Parameter(Mandatory=$true)]
$TagName
)
$version = $ZipFile.BaseName -replace "[a-zA-Z-]*"
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | % { $_.Hash }
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
$fileContents = `
"Version: $version
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$TagName/$($ZipFile.Name)
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$TagName/CHANGELOG.TXT
Checksum: $hash"
Write-Output $fileContents
}
Write-Host CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
$hash = Get-FileHash -Algorithm MD5 $file | % { $_.Hash }
Write-Host Checksum: $hash
function Resolve-UpdateCheckFileName {
param (
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Stable","Beta","Development")]
$UpdateChannel,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Normal","Portable")]
$Type
)
$fileName = ""
if ($UpdateChannel -eq "Beta") { $fileName += "beta-" }
elseif ($UpdateChannel -eq "Development") { $fileName += "dev-" }
$fileName += "update"
if ($Type -eq "Portable") { $fileName += "-portable" }
$fileName += ".txt"
Write-Output $fileName
}
$releaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
# build msi update file
$msiFile = Get-ChildItem -Path "$releaseFolder\*.msi" | sort LastWriteTime | select -last 1
$msiUpdateContents = New-MsiUpdateFileContent -MsiFile $msiFile -TagName $TagName
$msiUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Normal
Write-Output "`n`nMSI Update Check File Contents ($msiUpdateFileName)`n------------------------------"
Tee-Object -InputObject $msiUpdateContents -FilePath "$releaseFolder\$msiUpdateFileName"
# build zip update file
$zipFile = Get-ChildItem -Path "$releaseFolder\*.zip" | sort LastWriteTime | select -last 1
$zipUpdateContents = New-ZipUpdateFileContent -ZipFile $zipFile -TagName $TagName
$zipUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Portable
Write-Output "`n`nZip Update Check File Contents ($zipUpdateFileName)`n------------------------------"
Tee-Object -InputObject $zipUpdateContents -FilePath "$releaseFolder\$zipUpdateFileName"

220
Tools/github_functions.ps1 Normal file
View File

@@ -0,0 +1,220 @@
$githubUrl = 'https://api.github.com'
function Publish-GitHubRelease {
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseTitle,
[string]
[Parameter(Mandatory=$true)]
#
$TagName,
[string]
[Parameter(Mandatory=$true)]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
[Parameter(Mandatory=$true)]
#
$Description,
[bool]
[Parameter(Mandatory=$true)]
#
$IsDraft,
[bool]
[Parameter(Mandatory=$true)]
#
$IsPrerelease,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$body = New-GitHubReleaseRequestBody -TagName $TagName -TargetCommitish $TargetCommitish -ReleaseTitle $ReleaseTitle -Description $Description -IsDraft $IsDraft -IsPrerelease $IsPrerelease
$req_publishRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body $body -ErrorAction Stop
$response_publishRelease = ConvertFrom-Json -InputObject $req_publishRelease.Content
Write-Output $response_publishRelease
}
function Edit-GitHubRelease {
param (
[string]
#[Parameter(Mandatory=$true)]
#
$Owner,
[string]
#[Parameter(Mandatory=$true)]
#
$Repository,
[string]
#[Parameter(Mandatory=$true)]
#
$ReleaseId,
[string]
#
$ReleaseTitle,
[string]
#
$TagName,
[string]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
#
$Description,
[bool]
#
$IsDraft,
[bool]
#
$IsPrerelease,
[string]
#[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$body_params = @{
"TagName" = $TagName
"TargetCommitish" = $TargetCommitish
"ReleaseTitle" = $ReleaseTitle
"Description" = $Description
}
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("IsDraft", $IsDraft) }
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("IsPrerelease", $IsPrerelease) }
$body = New-GitHubReleaseRequestBody @body_params
$req_editRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases/$ReleaseId" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body $body -ErrorAction Stop
$response_editRelease = ConvertFrom-Json -InputObject $req_editRelease.Content
Write-Output $response_editRelease
}
function Get-GitHubRelease {
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseId,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$req_getRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases/$ReleaseId" -Method Get -Headers @{"Authorization"="token $AuthToken"} -ErrorAction Stop
$response_getRelease = ConvertFrom-Json -InputObject $req_getRelease.Content
Write-Output $response_getRelease
}
function Upload-GitHubReleaseAsset {
param (
[string]
[Parameter(Mandatory=$true)]
$UploadUri,
[string]
[Parameter(Mandatory=$true)]
# Path to the file to upload with the release
$FilePath,
[string]
[Parameter(Mandatory=$true)]
# Content type of the file
$ContentType,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$"
$file = Get-Item -Path $FilePath
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
}
function New-GitHubReleaseRequestBody {
param (
[string]
#
$TagName,
[string]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
# Title of the release
$ReleaseTitle,
[string]
# Description of the release
$Description,
[bool]
# Is this a draft?
$IsDraft,
[bool]
# Is this a pre-release?
$IsPrerelease
)
$body_params = [ordered]@{}
if ($TagName -ne "") { $body_params.Add("tag_name", $TagName) }
if ($TargetCommitish -ne "") { $body_params.Add("target_commitish", $TargetCommitish) }
if ($ReleaseTitle -ne "") { $body_params.Add("name", $ReleaseTitle) }
if ($Description -ne "") { $body_params.Add("body", $Description) }
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("draft", $IsDraft) }
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("prerelease", $IsPrerelease) }
$json_body = ConvertTo-Json -InputObject $body_params -Compress
Write-Output $json_body
}

23
Tools/move_help_files.ps1 Normal file
View 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 ""

View 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" -SolutionDir $SolutionDir -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")

View File

@@ -0,0 +1,47 @@
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\move_help_files.ps1" -TargetDir $TargetDir
& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\sign_binaries.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName

View 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

View File

@@ -0,0 +1,76 @@
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseTitle,
[string]
[Parameter(Mandatory=$true)]
#
$TagName,
[string]
[Parameter(Mandatory=$true)]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
[Parameter(Mandatory=$true)]
#
$Description,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("true","false")]
# true/false
$IsDraft,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("true","false")]
# true/false
$IsPrerelease,
[string]
[Parameter(Mandatory=$true)]
# Path to the zip file to upload with the release
$ZipFilePath,
[string]
[Parameter(Mandatory=$true)]
#Path to the msi file to upload with the release
$MsiFilePath,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken,
[switch]
# Enable this switch to treat $Description as a Base64 encoded string. It will be decoded before being used elsewhere in the script.
$DescriptionIsBase64Encoded
)
if ($DescriptionIsBase64Encoded) {
$Description = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Description)))
}
. "$PSScriptRoot\github_functions.ps1"
$release = Publish-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken
Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken)

View File

@@ -1,11 +1,15 @@
$solutionDir = $args[0]
$renameTarget = $solutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
param (
[string]
$SolutionDir
)
Write-Host $solutionDir
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
Write-Host $SolutionDir
Write-Host $renameTarget
$targetVersionedFile = "$solutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
$version = &"$solutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
$targetVersionedFile = "$SolutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
$version = &"$SolutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
$renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue

View File

@@ -0,0 +1,43 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
# Find editbin.exe
#Resolve-Path tends to be faster, but since editbin's are all over the place it's not 100% effective
$editBinPath = @((Resolve-Path -Path "C:\Program Files*\Microsoft Visual Studio*\VC\bin\editbin.exe").Path)
if(!$editBinPath)
{
# This should work on all VS versions, but doesn't on our Jenkin's build for some reason...
# This is needed VC Community
$editBinPath = @((gci -Path "C:\Program*\Microsoft Visual Studio\" -Filter editbin.exe -Recurse)[0].FullName)
}
# if we STILL can't find it, just return. Same end result NUnit test will fail.
if(!$editBinPath)
{
echo "Could not find editbin.exe - Can't set LargeAddressAware"
return
}
echo "editBinPath value:"
echo $editBinPath
# Verify editbin certificate
& "$PSScriptRoot\validate_microsoft_tool.ps1" -FullPath "$editBinPath"
$outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
# Set LargeAddressAware
Write-Output "Setting LargeAddressAware on binary file `"$outputExe`""
& $editBinPath "/largeaddressaware" "$outputExe"
Write-Output ""

80
Tools/sign_binaries.ps1 Normal file
View File

@@ -0,0 +1,80 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[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 ""

View File

@@ -1,13 +0,0 @@
$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]
Write-Output "Getting files from path: $targetPath"
$signableFiles = Get-ChildItem -Path $targetPath -Recurse | ?{$_.Extension -match "dll|exe|msi"}
Write-Output "Signable files count: $($signableFiles.Count)"
foreach ($file in $signableFiles) {
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
}

View File

@@ -0,0 +1,33 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
# Remove unnecessary files from Release versions
if ($ConfigurationName -match "Release") {
Write-Output "Removing unnecessary files from Release versions"
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
"*.pdb",
"*.publish",
"*.xml",
"*.backup",
"*.log",
"*vshost*",
"*.tmp"
)
Remove-Item -Path $filesToDelete.FullName
Write-Output $filesToDelete.FullName
}
else {
Write-Output "We will not remove anything - this is not a release build."
}
Write-Output ""

View 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
}

View File

@@ -0,0 +1,47 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
# The code signing certificate to use when signing the files.
$CertificatePath
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
# validate release versions and if the certificate is available
if ($ConfigurationName -match "Release") {
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
{
Write-Output "Certificate is not present - files likely not signed - we won't verify file signatures."
return
}
Write-Output "Verifying signature of binaries"
Write-Output "Getting files from path: $TargetDir"
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"}
Write-Output "Signable files count: $($signableFiles.Count)"
$badSignatureFound = $false
foreach ($file in $signableFiles) {
$signature = Get-AuthenticodeSignature -FilePath $file.FullName
if ($signature.Status -ne "Valid") {
Write-Warning "File $($file.FullName) does not have a valid signature."
$badSignatureFound = $true
}
}
if ($badSignatureFound) {
Write-Output "One or more files were improperly signed."
} else {
Write-Output "All files have valid signatures."
}
} else {
Write-Output "This is not a release build - we won't verify file signatures."
}
Write-Output ""

View File

@@ -0,0 +1,28 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
$path_packageZipScript = Join-Path -Path $SolutionDir -ChildPath "Tools\build-relport.cmd"
# Package Zip
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") {
Write-Output "Packaging Release Portable ZIP"
& $path_packageZipScript
}
else {
Write-Output "We will not zip anything - this isnt a portable release build."
}
Write-Output ""

View File

@@ -0,0 +1,84 @@
using System;
using mRemoteNG.App.Info;
using mRemoteNG.App.Update;
using mRemoteNGTests.Properties;
using NUnit.Framework;
namespace mRemoteNGTests.App
{
[TestFixture]
public class UpdaterTests
{
[Test]
public void UpdateStableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateBetaChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateDevChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateStablePortableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.update_portable);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateBetaPortableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.beta_update_portable);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
[Test]
public void UpdateDevPortableChannel()
{
GeneralAppInfo.ApplicationVersion = "1.0.0.0";
var CurrentUpdateInfo = UpdateInfo.FromString(Resources.dev_update_portable);
Assert.That(CurrentUpdateInfo.CheckIfValid(), Is.True);
Version v;
Version.TryParse(GeneralAppInfo.ApplicationVersion, out v);
var IsNewer = CurrentUpdateInfo.Version > v;
Assert.That(IsNewer, Is.True);
}
}
}

View File

@@ -0,0 +1,55 @@
using System.Data;
using System.Linq;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Connection;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNGTests.TestHelpers;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
{
public class DataTableDeserializerTests
{
private DataTableDeserializer _deserializer;
[SetUp]
public void Setup()
{
}
[Test]
public void WeCanDeserializeATree()
{
var model = CreateConnectionTreeModel();
var dataTable = CreateDataTable(model.RootNodes[0]);
_deserializer = new DataTableDeserializer(dataTable);
var output = _deserializer.Deserialize();
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
}
[Test]
public void WeCanDeserializeASingleEntry()
{
var dataTable = CreateDataTable(new ConnectionInfo());
_deserializer = new DataTableDeserializer(dataTable);
var output = _deserializer.Deserialize();
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
}
private DataTable CreateDataTable(ConnectionInfo tableContent)
{
var serializer = new DataTableSerializer(new SaveFilter());
return serializer.Serialize(tableContent);
}
private ConnectionTreeModel CreateConnectionTreeModel()
{
var builder = new ConnectionTreeModelBuilder();
return builder.Build();
}
}
}

View File

@@ -4,6 +4,7 @@ using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNGTests.TestHelpers;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
@@ -20,13 +21,6 @@ namespace mRemoteNGTests.Config.Serializers
_dataTableSerializer = new DataTableSerializer(_saveFilter);
}
[TearDown]
public void Teardown()
{
_saveFilter = null;
_dataTableSerializer = null;
}
[Test]
public void AllItemsSerialized()
{
@@ -35,6 +29,14 @@ namespace mRemoteNGTests.Config.Serializers
Assert.That(dataTable.Rows.Count, Is.EqualTo(3));
}
[Test]
public void ReturnsEmptyDataTableWhenGivenEmptyConnectionTreeModel()
{
var model = new ConnectionTreeModel();
var dataTable = _dataTableSerializer.Serialize(model);
Assert.That(dataTable.Rows.Count, Is.EqualTo(0));
}
[Test]
public void UsernameSerializedWhenSaveSecurityAllowsIt()
{
@@ -109,20 +111,18 @@ namespace mRemoteNGTests.Config.Serializers
Assert.That(dataTable.Rows[0]["InheritUsername"], Is.False);
}
[Test]
public void CanSerializeEmptyConnectionInfo()
{
var dataTable = _dataTableSerializer.Serialize(new ConnectionInfo());
Assert.That(dataTable.Rows.Count, Is.EqualTo(1));
}
private ConnectionTreeModel CreateConnectionTreeModel()
{
var model = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var folder1 = new ContainerInfo {Name = "folder1", Username = "user1", Domain = "domain1", Password = "password1"};
var con1 = new ConnectionInfo {Name = "Con1", Username = "user1", Domain = "domain1", Password = "password1" };
var con2 = new ConnectionInfo {Name = "Con2", Username = "user2", Domain = "domain2", Password = "password2" };
root.AddChild(folder1);
root.AddChild(con2);
folder1.AddChild(con1);
model.AddRootNode(root);
return model;
var builder = new ConnectionTreeModelBuilder();
return builder.Build();
}
}
}

View File

@@ -12,13 +12,14 @@ namespace mRemoteNGTests.Config.Serializers
public class XmlConnectionNodeSerializerTests
{
private XmlConnectionNodeSerializer _connectionNodeSerializer;
private ICryptographyProvider _cryptographyProvider;
[SetUp]
public void Setup()
{
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(
BlockCipherEngines.AES, BlockCipherModes.GCM);
_connectionNodeSerializer = new XmlConnectionNodeSerializer(cryptoProvider, "myPassword1".ConvertToSecureString());
_connectionNodeSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, "myPassword1".ConvertToSecureString(), new SaveFilter());
}
[Test]
@@ -48,8 +49,7 @@ namespace mRemoteNGTests.Config.Serializers
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);
_connectionNodeSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, "myPassword1".ConvertToSecureString(), saveFilter);
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
Assert.That(targetAttribute?.Value, Is.EqualTo(string.Empty));
@@ -59,8 +59,7 @@ namespace mRemoteNGTests.Config.Serializers
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);
_connectionNodeSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, "myPassword1".ConvertToSecureString(), saveFilter);
var returnVal = _connectionNodeSerializer.SerializeConnectionInfo(connectionInfo);
var targetAttribute = returnVal.Attribute(XName.Get(attributeName));
Assert.That(targetAttribute?.Value, Is.EqualTo(false.ToString()));

View File

@@ -28,7 +28,8 @@ namespace mRemoteNGTests.Config.Serializers
public void Setup()
{
_cryptographyProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider);
var saveFilter = new SaveFilter();
_documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider, saveFilter);
_connectionTreeModel = SetupConnectionTreeModel();
}

View File

@@ -20,7 +20,8 @@ namespace mRemoteNGTests.Config.Serializers
{
var connectionTreeModel = SetupConnectionTreeModel();
var cryptoProvider = new CryptographyProviderFactory().CreateAeadCryptographyProvider(BlockCipherEngines.AES, BlockCipherModes.GCM);
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider).CompileDocument(connectionTreeModel, false, false);
var saveFilter = new SaveFilter();
_originalDocument = new XmlConnectionsDocumentCompiler(cryptoProvider, saveFilter).CompileDocument(connectionTreeModel, false, false);
_documentEncryptor = new XmlConnectionsDocumentEncryptor(cryptoProvider);
}

View File

@@ -1,7 +1,9 @@
using System.Xml;
using System.Xml.Linq;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
@@ -45,6 +47,27 @@ 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)
{
_serializer.SaveFilter = new SaveFilter(true);
var connectionInfo = new ConnectionInfo
{
Name = "myConnection",
Username = "somefilteredstuff",
Domain = "somefilteredstuff",
Password = "somefilteredstuff",
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()
{
/*

View File

@@ -48,6 +48,14 @@ namespace mRemoteNGTests.Connection
Assert.That(secondConnection.Domain, Is.EqualTo(_connectionInfo.Domain));
}
[Test]
public void CloneDoesNotSetParentOfNewConnectionInfo()
{
_connectionInfo.SetParent(new ContainerInfo());
var clonedConnection = _connectionInfo.Clone();
Assert.That(clonedConnection.Parent, Is.Null);
}
[Test]
public void CopyFromCopiesProperties()
{

View File

@@ -1,4 +1,5 @@
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using NUnit.Framework;
@@ -30,5 +31,43 @@ namespace mRemoteNGTests.Connection
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain));
}
[Test]
public void CanSaveEnumValuesToString()
{
const ProtocolType targetProtocol = ProtocolType.RAW;
var saveTarget = new AllStringPropertySaveTarget();
DefaultConnectionInfo.Instance.Protocol = targetProtocol;
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.Protocol, Is.EqualTo(targetProtocol.ToString()));
}
[Test]
public void CanSaveIntegerValuesToString()
{
const int targetValue = 123;
var saveTarget = new AllStringPropertySaveTarget();
DefaultConnectionInfo.Instance.RDPMinutesToIdleTimeout = targetValue;
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.RDPMinutesToIdleTimeout, Is.EqualTo(targetValue.ToString()));
}
[Test]
public void CanSaveStringValuesToString()
{
const string targetName = "hello";
var saveTarget = new AllStringPropertySaveTarget();
DefaultConnectionInfo.Instance.Username = targetName;
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
Assert.That(saveTarget.Username, Is.EqualTo(targetName));
}
private class AllStringPropertySaveTarget
{
public string Username { get; set; }
public string Protocol { get; set; }
public string RDPMinutesToIdleTimeout { get; set; }
}
}
}

View File

@@ -263,6 +263,14 @@ namespace mRemoteNGTests.Container
Assert.That(clone.ConstantID, Is.Not.EqualTo(_containerInfo.ConstantID));
}
[Test]
public void ClonedContainerDoesNotHaveParentSet()
{
_containerInfo.SetParent(new ContainerInfo());
var clone = _containerInfo.Clone();
Assert.That(clone.Parent, Is.Null);
}
[Test]
public void ClonedContainerContainsClonedChildren()
{

View File

@@ -60,6 +60,32 @@ namespace mRemoteNGTests.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6164.27544
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
///Checksum: A1E50ACAC4CB8023527E1E7A0E682459
///.
/// </summary>
internal static string beta_update {
get {
return ResourceManager.GetString("beta_update", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6170.27478
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C.
/// </summary>
internal static string beta_update_portable {
get {
return ResourceManager.GetString("beta_update_portable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
///&lt;Connections Name=&quot;Connections&quot; Export=&quot;False&quot; Protected=&quot;95syzRuZ4mRxpNkZQzoyX8SDpQXLyMq3GncO8o4SyTBoYvn3TAWgn05ZEU2DrjkM&quot; ConfVersion=&quot;2.5&quot;&gt;
@@ -142,6 +168,32 @@ namespace mRemoteNGTests.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6164.27544
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
///Checksum: A1E50ACAC4CB8023527E1E7A0E682459
///.
/// </summary>
internal static string dev_update {
get {
return ResourceManager.GetString("dev_update", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6170.27478
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C.
/// </summary>
internal static string dev_update_portable {
get {
return ResourceManager.GetString("dev_update_portable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-16&quot;?&gt;
///&lt;!-- ****************************************************************--&gt;
@@ -276,5 +328,30 @@ namespace mRemoteNGTests.Properties {
return ResourceManager.GetString("test_remotedesktopconnection_rdp", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.72.5065.32737
///dURL: http://downloads.mremoteng.org/mRemoteNG-Installer-1.72.exe
///clURL: http://update.mremoteng.org/changes-1.72.txt
///CertificateThumbprint: 1cbd910dbd6e77f26506e7f600736972f700673f
///.
/// </summary>
internal static string update {
get {
return ResourceManager.GetString("update", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version: 1.75.6170.27478
///dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
///clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
///Checksum: 1C35EA199F58001BC4EBB164D8B3D11C.
/// </summary>
internal static string update_portable {
get {
return ResourceManager.GetString("update_portable", resourceCulture);
}
}
}
}

View File

@@ -118,6 +118,12 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="beta_update" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\beta-update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="beta_update_portable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\beta-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="confCons_v2_5" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\confCons_v2_5.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
@@ -142,6 +148,12 @@
<data name="confCons_v2_6_passwordis_Password_fullencryption" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\confCons_v2_6_passwordis_Password_fullencryption.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="dev_update" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\dev-update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="dev_update_portable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\dev-update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="test_puttyConnectionManager_database" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\test_puttyConnectionManager_database.dat;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
</data>
@@ -163,4 +175,10 @@
<data name="test_remotedesktopconnection_rdp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\test_remotedesktopconnection.rdp;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
</data>
<data name="update" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\update.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="update_portable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\update-portable.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>

View File

@@ -0,0 +1,5 @@
Version: 1.75.6170.27478
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: 1C35EA199F58001BC4EBB164D8B3D11C

View File

@@ -0,0 +1,5 @@
Version: 1.75.6164.27544
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: A1E50ACAC4CB8023527E1E7A0E682459

View File

@@ -0,0 +1,5 @@
Version: 1.75.6170.27478
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: 1C35EA199F58001BC4EBB164D8B3D11C

View File

@@ -0,0 +1,5 @@
Version: 1.75.6164.27544
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: A1E50ACAC4CB8023527E1E7A0E682459

View File

@@ -0,0 +1,5 @@
Version: 1.75.6170.27478
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Portable-1.75.6179.28241.zip
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: 1C35EA199F58001BC4EBB164D8B3D11C

View File

@@ -0,0 +1,5 @@
Version: 1.75.6164.27544
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/v1.75Beta3/mRemoteNG-Installer-1.75.6179.28160.msi
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/v1.75Beta3/CHANGELOG.TXT
CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
Checksum: A1E50ACAC4CB8023527E1E7A0E682459

View File

@@ -0,0 +1,25 @@
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNGTests.TestHelpers
{
public class ConnectionTreeModelBuilder
{
public ConnectionTreeModel Build()
{
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;
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class ExpandNodeClickHandlerTests
{
private ExpandNodeClickHandler _clickHandler;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_connectionTree = Substitute.For<IConnectionTree>();
_clickHandler = new ExpandNodeClickHandler(_connectionTree);
}
[Test]
public void TargetedNodeIsExpanded()
{
var folder = new ContainerInfo();
_clickHandler.Execute(folder);
_connectionTree.Received().ToggleExpansion(folder);
}
[Test]
public void NothingHappensWhenConnectionInfoProvided()
{
_clickHandler.Execute(new ConnectionInfo());
_connectionTree.DidNotReceiveWithAnyArgs().ToggleExpansion(new ConnectionInfo());
}
[Test]
public void ExceptionThrownOnConstructorNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new ExpandNodeClickHandler(null));
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class OpenConnectionClickHandlerTests
{
private OpenConnectionClickHandler _clickHandler;
private IConnectionInitiator _connectionInitiator;
[SetUp]
public void Setup()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
_clickHandler = new OpenConnectionClickHandler(_connectionInitiator);
}
[Test]
public void ConnectionOpened()
{
var connectionInfo = new ConnectionInfo();
_clickHandler.Execute(connectionInfo);
_connectionInitiator.Received().OpenConnection(connectionInfo);
}
[Test]
public void DoesNothingWhenGivenContainerInfo()
{
_clickHandler.Execute(new ContainerInfo());
_connectionInitiator.DidNotReceiveWithAnyArgs().OpenConnection(new ConnectionInfo());
}
[Test]
public void ExceptionThrownWhenConstructorGivenNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new OpenConnectionClickHandler(null));
}
[Test]
public void ThrowWhenExecuteGivenNullArg()
{
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class SwitchToConnectionClickHandlerTests
{
private SwitchToConnectionClickHandler _clickHandler;
private IConnectionInitiator _connectionInitiator;
[SetUp]
public void Setup()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
_clickHandler = new SwitchToConnectionClickHandler(_connectionInitiator);
}
[Test]
public void SwitchesToConnection()
{
var connectionInfo = new ConnectionInfo();
_clickHandler.Execute(connectionInfo);
_connectionInitiator.Received().SwitchToOpenConnection(connectionInfo);
}
[Test]
public void DoesNothingWhenGivenContainerInfo()
{
_clickHandler.Execute(new ContainerInfo());
_connectionInitiator.DidNotReceiveWithAnyArgs().SwitchToOpenConnection(new ConnectionInfo());
}
[Test]
public void ExceptionThrownWhenConstructorGivenNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new SwitchToConnectionClickHandler(null));
}
[Test]
public void ThrowWhenExecuteGivenNullArg()
{
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class TreeNodeCompositeClickHandlerTests
{
private TreeNodeCompositeClickHandler _clickHandler;
private ConnectionInfo _connectionInfo;
[SetUp]
public void Setup()
{
_clickHandler = new TreeNodeCompositeClickHandler();
_connectionInfo = new ConnectionInfo();
}
[Test]
public void ExecutesAllItsHandlers()
{
var handler1 = Substitute.For<ITreeNodeClickHandler>();
var handler2 = Substitute.For<ITreeNodeClickHandler>();
_clickHandler.ClickHandlers = new[] {handler1, handler2};
_clickHandler.Execute(_connectionInfo);
handler1.Received().Execute(_connectionInfo);
handler2.Received().Execute(_connectionInfo);
}
[Test]
public void ThrowWhenExecuteGivenNullArg()
{
Assert.Throws<ArgumentNullException>(() => _clickHandler.Execute(null));
}
}
}

View File

@@ -0,0 +1,51 @@
using System.Threading;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class ConnectionTreeTests
{
private ConnectionTree _connectionTree;
private ConnectionTreeModel _connectionTreeModel;
[SetUp]
public void Setup()
{
_connectionTreeModel = CreateConnectionTreeModel();
_connectionTree = new ConnectionTree
{
PostSetupActions = new IConnectionTreeDelegate[] {new RootNodeExpander()}
};
}
[TearDown]
public void Teardown()
{
_connectionTree.Dispose();
}
[Test, Apartment(ApartmentState.STA)]
public void CanDeleteLastFolderInTheTree()
{
var lastFolder = new ContainerInfo();
_connectionTreeModel.RootNodes[0].AddChild(lastFolder);
_connectionTree.ConnectionTreeModel = _connectionTreeModel;
_connectionTree.SelectObject(lastFolder);
_connectionTree.DeleteSelectedNode();
Assert.That(_connectionTree.GetRootConnectionNode().HasChildren, Is.False);
}
private ConnectionTreeModel CreateConnectionTreeModel()
{
var connectionTreeModel = new ConnectionTreeModel();
connectionTreeModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
return connectionTreeModel;
}
}
}

View File

@@ -0,0 +1,50 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class PreviousSessionOpenerTests
{
private PreviousSessionOpener _previousSessionOpener;
private IConnectionInitiator _connectionInitiator;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_connectionInitiator = Substitute.For<IConnectionInitiator>();
_previousSessionOpener = new PreviousSessionOpener(_connectionInitiator);
_connectionTree = Substitute.For<IConnectionTree>();
_connectionTree.GetRootConnectionNode().Returns(BuildTree());
}
[Test]
public void AllRequestedSessionsAreReopened()
{
_previousSessionOpener.Execute(_connectionTree);
_connectionInitiator.ReceivedWithAnyArgs(2).OpenConnection(new ConnectionInfo());
}
[Test]
public void ExceptionThrownWhenConstructorGivenNullArg()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<ArgumentNullException>(() => new PreviousSessionOpener(null));
}
private RootNodeInfo BuildTree()
{
var root = new RootNodeInfo(RootNodeType.Connection);
root.AddChild(new ConnectionInfo { PleaseConnect = true });
root.AddChild(new ConnectionInfo());
root.AddChild(new ConnectionInfo { PleaseConnect = true });
return root;
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class PreviouslyOpenedFolderExpanderTests
{
private PreviouslyOpenedFolderExpander _folderExpander;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_folderExpander = new PreviouslyOpenedFolderExpander();
_connectionTree = Substitute.For<IConnectionTree>();
}
[Test]
public void ExpandsAllFoldersThatAreMarkedForExpansion()
{
var connectionTreeModel = GenerateConnectionTreeModel();
_connectionTree.ConnectionTreeModel.Returns(connectionTreeModel);
_connectionTree.GetRootConnectionNode().Returns(connectionTreeModel.RootNodes[0]);
_folderExpander.Execute(_connectionTree);
Assert.That(_connectionTree.ExpandedObjects, Is.EquivalentTo(connectionTreeModel.GetRecursiveChildList().OfType<ContainerInfo>().Where(info => info.IsExpanded)));
}
private ConnectionTreeModel GenerateConnectionTreeModel()
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection) { IsExpanded = true };
var folder1 = new ContainerInfo { IsExpanded = true };
var folder2 = new ContainerInfo();
var con1 = new ConnectionInfo();
root.AddChild(folder1);
folder1.AddChild(folder2);
root.AddChild(con1);
connectionTreeModel.AddRootNode(root);
return connectionTreeModel;
}
}
}

View File

@@ -0,0 +1,47 @@
using System.Windows.Forms;
using mRemoteNG.Connection;
using mRemoteNG.Tree;
using mRemoteNG.UI.Controls;
using NSubstitute;
using NUnit.Framework;
namespace mRemoteNGTests.Tree
{
public class SelectedConnectionDeletionConfirmerTests
{
private SelectedConnectionDeletionConfirmer _deletionConfirmer;
private IConnectionTree _connectionTree;
[SetUp]
public void Setup()
{
_connectionTree = Substitute.For<IConnectionTree>();
_connectionTree.SelectedNode.Returns(new ConnectionInfo());
}
[Test]
public void ClickingYesReturnsTrue()
{
_deletionConfirmer = new SelectedConnectionDeletionConfirmer(_connectionTree, MockClickYes);
Assert.That(_deletionConfirmer.Confirm(), Is.True);
}
[Test]
public void ClickingNoReturnsFalse()
{
_deletionConfirmer = new SelectedConnectionDeletionConfirmer(_connectionTree, MockClickNo);
Assert.That(_deletionConfirmer.Confirm(), Is.False);
}
private DialogResult MockClickYes(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
{
return DialogResult.Yes;
}
private DialogResult MockClickNo(string promptMessage, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
{
return DialogResult.No;
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Threading;
using mRemoteNG.UI.Window;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.UI.Window
{
public class ConnectionTreeWindowTests
{
private ConnectionTreeWindow _connectionTreeWindow;
[SetUp]
public void Setup()
{
_connectionTreeWindow = new ConnectionTreeWindow(new DockContent());
}
[TearDown]
public void Teardown()
{
_connectionTreeWindow.Close();
}
[Test, Apartment(ApartmentState.STA)]
public void CanShowWindow()
{
_connectionTreeWindow.Show();
Assert.That(_connectionTreeWindow.Visible);
}
}
}

View File

@@ -22,7 +22,7 @@
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -31,25 +31,25 @@
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug Portable|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug Portable\</OutputPath>
<OutputPath>bin\Debug Portable\</OutputPath>
<DefineConstants>TRACE;DEBUG;PORTABLE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release Portable|x86'">
<OutputPath>bin\x86\Release Portable\</OutputPath>
<OutputPath>bin\Release Portable\</OutputPath>
<DefineConstants>TRACE;PORTABLE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -62,13 +62,11 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\mRemoteV1\References\log4net.dll</HintPath>
</Reference>
<Reference Include="NSubstitute, Version=1.10.0.0, Culture=neutral, PublicKeyToken=92dd2e9066daa5ca, processorArchitecture=MSIL">
<HintPath>..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll</HintPath>
<Private>True</Private>
<Reference Include="NSubstitute, Version=2.0.3.0, Culture=neutral, PublicKeyToken=92dd2e9066daa5ca, processorArchitecture=MSIL">
<HintPath>..\packages\NSubstitute.2.0.3\lib\net45\NSubstitute.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="NUnitForms">
<HintPath>nUnitForms\bin\NUnitForms.dll</HintPath>
@@ -101,13 +99,17 @@
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
<Private>False</Private>
</Reference>
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="App\LoggerTests.cs" />
<Compile Include="App\UpdaterTests.cs" />
<Compile Include="BinaryFileTests.cs" />
<Compile Include="Config\Serializers\DataTableDeserializerTests.cs" />
<Compile Include="Config\Serializers\DataTableSerializerTests.cs" />
<Compile Include="Config\Serializers\PortScanDeserializerTests.cs" />
<Compile Include="Config\Serializers\PuttyConnectionManagerDeserializerTests.cs" />
@@ -126,7 +128,9 @@
<Compile Include="Security\Authentication\PasswordAuthenticatorTests.cs" />
<Compile Include="Security\KeyDerivation\Pkcs5S2KeyGeneratorTests.cs" />
<Compile Include="Security\SecureStringExtensionsTests.cs" />
<Compile Include="TestHelpers\ConnectionTreeModelBuilder.cs" />
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
<Compile Include="Tree\ClickHandlers\TreeNodeCompositeClickHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeDragAndDropHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeModelTests.cs" />
<Compile Include="Connection\ConnectionInfoInheritanceTests.cs" />
@@ -146,8 +150,15 @@
<Compile Include="Security\CryptographyProviderFactoryTests.cs" />
<Compile Include="Security\EncryptedSecureStringTests.cs" />
<Compile Include="Security\LegacyRijndaelCryptographyProviderTests.cs" />
<Compile Include="Tree\ConnectionTreeTests.cs" />
<Compile Include="Tree\ClickHandlers\ExpandNodeClickHandlerTests.cs" />
<Compile Include="Tree\NodeSearcherTests.cs" />
<Compile Include="Tree\ClickHandlers\OpenConnectionClickHandlerTests.cs" />
<Compile Include="Tree\PreviouslyOpenedFolderExpanderTests.cs" />
<Compile Include="Tree\PreviousSessionOpenerTests.cs" />
<Compile Include="Tree\RootNodeInfoTests.cs" />
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
<Compile Include="UI\Controls\TestForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -157,6 +168,7 @@
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
<Compile Include="UI\Forms\PasswordFormTests.cs" />
<Compile Include="UI\WindowListTests.cs" />
<Compile Include="UI\Window\ConnectionTreeWindowTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@@ -207,6 +219,14 @@
<ItemGroup>
<None Include="Resources\confCons_v2_5_passwordis_Password_fullencryption.xml" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\beta-update-portable.txt" />
<Content Include="Resources\beta-update.txt" />
<Content Include="Resources\dev-update-portable.txt" />
<Content Include="Resources\dev-update.txt" />
<Content Include="Resources\update-portable.txt" />
<Content Include="Resources\update.txt" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>

View File

@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tree_005Cclickhandlers/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -3,7 +3,7 @@
<package id="BouncyCastle" version="1.8.1" targetFramework="net45" />
<package id="DockPanelSuite" version="2.10.0" targetFramework="net45" />
<package id="DockPanelSuite.ThemeVS2012Light" version="2.10.0" targetFramework="net45" />
<package id="NSubstitute" version="1.10.0.0" targetFramework="net45" />
<package id="NUnit" version="3.5.0" targetFramework="net45" />
<package id="NSubstitute" version="2.0.3" targetFramework="net45" />
<package id="NUnit" version="3.8.1" targetFramework="net45" />
<package id="ObjectListView.Official" version="2.9.1" targetFramework="net45" />
</packages>

View File

@@ -20,6 +20,7 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug Portable|x86 = Debug Portable|x86
Debug|x86 = Debug|x86
Release Installer|x86 = Release Installer|x86
Release Portable|x86 = Release Portable|x86
Release|x86 = Release|x86
EndGlobalSection
@@ -28,6 +29,8 @@ Global
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.ActiveCfg = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.ActiveCfg = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.ActiveCfg = Release|x86
@@ -36,6 +39,8 @@ Global
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.ActiveCfg = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.ActiveCfg = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.ActiveCfg = Release|x86
@@ -43,11 +48,14 @@ Global
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.Build.0 = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x86.Build.0 = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x86.ActiveCfg = Debug|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.ActiveCfg = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|x86.ActiveCfg = Release Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|x86.ActiveCfg = Release|x86
EndGlobalSection

View File

@@ -8,24 +8,23 @@ using System.Windows.Forms;
namespace mRemoteNG.App
{
public class CompatibilityChecker
public static class CompatibilityChecker
{
public void CheckCompatibility()
public static void CheckCompatibility()
{
CheckFipsPolicy();
CheckLenovoAutoScrollUtility();
}
private void CheckFipsPolicy()
private static void CheckFipsPolicy()
{
if (FipsPolicyEnabledForServer2003() || FipsPolicyEnabledForServer2008AndNewer())
{
MessageBox.Show(frmMain.Default, string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error));
Environment.Exit(1);
}
Logger.Instance.InfoFormat("Checking FIPS Policy...");
if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return;
MessageBox.Show(frmMain.Default, string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName, GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error));
Environment.Exit(1);
}
private bool FipsPolicyEnabledForServer2003()
private static bool FipsPolicyEnabledForServer2003()
{
var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa");
var fipsPolicy = regKey?.GetValue("FIPSAlgorithmPolicy");
@@ -34,7 +33,7 @@ namespace mRemoteNG.App
return (int)fipsPolicy != 0;
}
private bool FipsPolicyEnabledForServer2008AndNewer()
private static bool FipsPolicyEnabledForServer2008AndNewer()
{
var regKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Lsa\\FIPSAlgorithmPolicy");
var fipsPolicy = regKey?.GetValue("Enabled");
@@ -43,12 +42,14 @@ namespace mRemoteNG.App
return (int)fipsPolicy != 0;
}
private void CheckLenovoAutoScrollUtility()
private static void CheckLenovoAutoScrollUtility()
{
Logger.Instance.InfoFormat("Checking Lenovo AutoScroll Utility...");
if (!Settings.Default.CompatibilityWarnLenovoAutoScrollUtility)
return;
Process[] proccesses = new Process[] { };
var proccesses = new Process[] { };
try
{
proccesses = Process.GetProcessesByName("virtscrl");
@@ -58,12 +59,10 @@ namespace mRemoteNG.App
Runtime.MessageCollector.AddExceptionMessage("Error in CheckLenovoAutoScrollUtility", ex);
}
if (proccesses.Length > 0)
{
CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, string.Format(Language.strCompatibilityLenovoAutoScrollUtilityDetected, Application.ProductName), "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.Ok, ESysIcons.Warning, ESysIcons.Warning);
if (CTaskDialog.VerificationChecked)
Settings.Default.CompatibilityWarnLenovoAutoScrollUtility = false;
}
if (proccesses.Length <= 0) return;
CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, string.Format(Language.strCompatibilityLenovoAutoScrollUtilityDetected, Application.ProductName), "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.Ok, ESysIcons.Warning, ESysIcons.Warning);
if (CTaskDialog.VerificationChecked)
Settings.Default.CompatibilityWarnLenovoAutoScrollUtility = false;
}
}
}

View File

@@ -34,7 +34,7 @@ namespace mRemoteNG.App
}
if (exportForm.ShowDialog(frmMain.Default) != DialogResult.OK)
return ;
return;
ConnectionInfo exportTarget;
switch (exportForm.Scope)
@@ -76,12 +76,17 @@ namespace mRemoteNG.App
var factory = new CryptographyProviderFactory();
var cryptographyProvider = factory.CreateAeadCryptographyProvider(mRemoteNG.Settings.Default.EncryptionEngine, mRemoteNG.Settings.Default.EncryptionBlockCipherMode);
cryptographyProvider.KeyDerivationIterations = Settings.Default.EncryptionKeyDerivationIterations;
serializer = new XmlConnectionsSerializer(cryptographyProvider);
((XmlConnectionsSerializer) serializer).SaveFilter = saveFilter;
serializer = new XmlConnectionsSerializer(cryptographyProvider)
{
Export = true,
SaveFilter = saveFilter
};
break;
case ConnectionsSaver.Format.mRCSV:
serializer = new CsvConnectionsSerializerMremotengFormat();
((CsvConnectionsSerializerMremotengFormat)serializer).SaveFilter = saveFilter;
serializer = new CsvConnectionsSerializerMremotengFormat
{
SaveFilter = saveFilter
};
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);

View File

@@ -11,23 +11,27 @@ namespace mRemoteNG.App.Info
{
public static class GeneralAppInfo
{
public static readonly string UrlHome = "http://www.mremoteng.org/";
public static readonly string UrlDonate = "http://donate.mremoteng.org/";
public static readonly string UrlForum = "http://forum.mremoteng.org/";
public static readonly string UrlBugs = "http://bugs.mremoteng.org/";
public static readonly string ApplicationVersion = Application.ProductVersion;
public const string UrlHome = "http://www.mremoteng.org/";
public const string UrlDonate = "http://donate.mremoteng.org/";
public const string UrlForum = "http://forum.mremoteng.org/";
public const string UrlBugs = "http://bugs.mremoteng.org/";
public static string ApplicationVersion = Application.ProductVersion;
public static readonly string ProductName = Application.ProductName;
public static readonly string Copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute), false)).Copyright;
public static readonly string HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
public static string ReportingFilePath = "";
//public static string ReportingFilePath = "";
public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe";
public static string UserAgent
{
get
{
var details = new List<string>();
details.Add("compatible");
details.Add(OSVersion.Platform == PlatformID.Win32NT ? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}": OSVersion.VersionString);
var details = new List<string>
{
"compatible",
OSVersion.Platform == PlatformID.Win32NT
? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}"
: OSVersion.VersionString
};
if (Is64BitProcess)
{
details.Add("WOW64");

View File

@@ -1,34 +1,72 @@
namespace mRemoteNG.App.Info
using System;
namespace mRemoteNG.App.Info
{
public static class UpdateChannelInfo
{
public static string FileName
public const string STABLE = "Stable";
public const string BETA = "Beta";
public const string DEV = "Development";
/* no #if here since they are used for unit tests as well */
public const string STABLE_PORTABLE = "update-portable.txt";
public const string BETA_PORTABLE = "beta-update-portable.txt";
public const string DEV_PORTABLE = "dev-update-portable.txt";
public const string STABLE_MSI = "update.txt";
public const string BETA_MSI = "beta-update.txt";
public const string DEV_MSI = "dev-update.txt";
public static Uri GetUpdateChannelInfo()
{
var channel = IsValidChannel(Settings.Default.UpdateChannel) ? Settings.Default.UpdateChannel : STABLE;
return GetUpdateTxtUri(channel);
}
private static string GetChannelFileName(string channel)
{
#if PORTABLE
get
{
/* */
/* return PORTABLE update files here */
/* */
#if DEBUG
return "update-portable-debug.txt";
#else
return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-portable-debug.txt" : "update-portable.txt";
#endif
}
switch (channel)
{
case STABLE:
return STABLE_PORTABLE;
case BETA:
return BETA_PORTABLE;
case DEV:
return DEV_PORTABLE;
default:
return STABLE_PORTABLE;
}
#else //NOT portable
get
{
/* */
/* return INSTALLER update files here */
/* */
#if DEBUG
return "update-debug.txt";
#else
return Settings.Default.UpdateChannel.ToLowerInvariant() == "debug" ? "update-debug.txt" : "update.txt";
#endif
}
switch (channel)
{
case STABLE:
return STABLE_MSI;
case BETA:
return BETA_MSI;
case DEV:
return DEV_MSI;
default:
return STABLE_MSI;
}
#endif //endif for PORTABLE
}
private static Uri GetUpdateTxtUri(string channel)
{
return new Uri(new Uri(Settings.Default.UpdateAddress), new Uri(GetChannelFileName(channel), UriKind.Relative));
}
private static bool IsValidChannel(string s)
{
return s.Equals(STABLE) || s.Equals(BETA) || s.Equals(DEV);
}
}
}

View File

@@ -1,4 +1,5 @@
using log4net;
using System.Diagnostics;
using log4net;
using log4net.Appender;
using log4net.Config;
#if !PORTABLE
@@ -45,14 +46,23 @@ namespace mRemoteNG.App
private static string BuildLogFilePath()
{
if (!Settings.Default.WriteLogFile)
return "";
#if !PORTABLE
var logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.ProductName);
#else
var logFilePath = Application.StartupPath;
#endif
var logFileName = Path.ChangeExtension(Application.ProductName, ".log");
var logFile = Path.Combine(logFilePath, logFileName);
return logFile;
if (logFileName != null)
{
var logFile = Path.Combine(logFilePath, logFileName);
return logFile;
}
Debug.Print("Error: Could not determine log file path.");
return "";
}
}
}

View File

@@ -1,6 +1,10 @@
using System;
using System.Drawing;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable 169
namespace mRemoteNG.App
{
@@ -41,11 +45,17 @@ namespace mRemoteNG.App
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, System.Text.StringBuilder lParam);
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, string lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage([In] IntPtr hWnd, [In] uint msg, [Out] StringBuilder wParam, [In] IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
@@ -75,6 +85,10 @@ namespace mRemoteNG.App
[DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern bool SetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("kernel32", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal static extern bool CloseHandle(IntPtr handle);
#endregion
#region Structures
@@ -285,7 +299,10 @@ namespace mRemoteNG.App
public const int WA_ACTIVE = 0x1;
/// <summary>
///
/// Sent to both the window being activated and the window being deactivated.
/// If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the
/// top-level window being deactivated, then to the window procedure of the top-level window being activated. If the
/// windows use different input queues, the message is sent asynchronously, so the window is activated immediately.
/// </summary>
public const int WA_CLICKACTIVE = 0x2;
#endregion
@@ -326,6 +343,11 @@ namespace mRemoteNG.App
/// </summary>
public const int WM_ACTIVATEAPP = 0x1C;
/// <summary>
/// Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured.
/// </summary>
public const int WM_SETCURSOR = 0x20;
/// <summary>
/// Sent when the cursor is in an inactive window and the user presses a mouse button. The parent window receives this message only if the child window passes it to the DefWindowProc function.
/// </summary>
@@ -449,6 +471,12 @@ namespace mRemoteNG.App
public const int VK_C = 0x67;
#endregion
#region EM
public const uint ECM_FIRST = 0x1500;
public const uint EM_SETCUEBANNER = ECM_FIRST + 1;
public const uint EM_GETCUEBANNER = ECM_FIRST + 2;
#endregion
#region LB
public const int LB_ERR = -1;
public const int LB_SELECTSTRING = 0x18C;

View File

@@ -33,17 +33,17 @@ namespace mRemoteNG.App
#region Public Properties
public static WindowList WindowList { get; set; }
public static MessageCollector MessageCollector { get; set; }
public static Controls.NotificationAreaIcon NotificationAreaIcon { get; set; }
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
public static bool IsConnectionsFileLoaded { get; set; }
public static RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private static DateTime LastSqlUpdate { get; set; }
public static DateTime LastSqlUpdate { get; set; }
public static ArrayList ExternalTools { get; set; } = new ArrayList();
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ConnectionTreeModel ConnectionTreeModel
{
get { return Windows.TreeForm.ConnectionTreeModel; }
set { Windows.TreeForm.ConnectionTreeModel = value; }
get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; }
set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; }
}
#endregion
@@ -237,7 +237,7 @@ namespace mRemoteNG.App
// Load config
connectionsLoader.ConnectionFileName = filename;
ConnectionTreeModel = connectionsLoader.LoadConnections(false);
Windows.TreeForm.ConnectionTreeModel = ConnectionTreeModel;
Windows.TreeForm.ConnectionTree.ConnectionTreeModel = ConnectionTreeModel;
}
catch (Exception ex)
{
@@ -274,7 +274,7 @@ namespace mRemoteNG.App
{
if (withDialog)
{
var loadDialog = Controls.ConnectionsLoadDialog();
var loadDialog = ConnectionsLoadDialog();
if (loadDialog.ShowDialog() != DialogResult.OK) return;
connectionsLoader.ConnectionFileName = loadDialog.FileName;
}
@@ -283,12 +283,12 @@ namespace mRemoteNG.App
connectionsLoader.ConnectionFileName = GetStartupConnectionFileName();
}
CreateBackupFile(Convert.ToString(connectionsLoader.ConnectionFileName));
CreateBackupFile(connectionsLoader.ConnectionFileName);
}
connectionsLoader.UseDatabase = Settings.Default.UseSQLServer;
ConnectionTreeModel = connectionsLoader.LoadConnections(false);
Windows.TreeForm.ConnectionTreeModel = ConnectionTreeModel;
Windows.TreeForm.ConnectionTree.ConnectionTreeModel = ConnectionTreeModel;
if (Settings.Default.UseSQLServer)
{
@@ -334,7 +334,7 @@ namespace mRemoteNG.App
if (ex is FileNotFoundException && !withDialog)
{
MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionsLoader.ConnectionFileName), ex, MessageClass.InformationMsg);
NewConnections(Convert.ToString(connectionsLoader.ConnectionFileName));
NewConnections(connectionsLoader.ConnectionFileName);
return;
}
@@ -353,6 +353,16 @@ namespace mRemoteNG.App
}
}
private static OpenFileDialog ConnectionsLoadDialog()
{
return new OpenFileDialog
{
CheckFileExists = true,
InitialDirectory = ConnectionsFileInfo.DefaultConnectionsPath,
Filter = Language.strFiltermRemoteXML + @"|*.xml|" + Language.strFilterAll + @"|*.*"
};
}
private static void CreateBackupFile(string fileName)
{
// This intentionally doesn't prune any existing backup files. We just assume the user doesn't want any new ones created.
@@ -455,11 +465,11 @@ namespace mRemoteNG.App
if (Settings.Default.UseSQLServer)
{
connectionsSaver.SaveFormat = ConnectionsSaver.Format.SQL;
connectionsSaver.SQLHost = Convert.ToString(Settings.Default.SQLHost);
connectionsSaver.SQLDatabaseName = Convert.ToString(Settings.Default.SQLDatabaseName);
connectionsSaver.SQLUsername = Convert.ToString(Settings.Default.SQLUser);
connectionsSaver.SQLHost = Settings.Default.SQLHost;
connectionsSaver.SQLDatabaseName = Settings.Default.SQLDatabaseName;
connectionsSaver.SQLUsername = Settings.Default.SQLUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
connectionsSaver.SQLPassword = cryptographyProvider.Decrypt(Convert.ToString(Settings.Default.SQLPass), EncryptionKey);
connectionsSaver.SQLPassword = cryptographyProvider.Decrypt(Settings.Default.SQLUser, EncryptionKey);
}
connectionsSaver.SaveConnections();
@@ -593,7 +603,8 @@ namespace mRemoteNG.App
connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP;
connectionInfo.SetDefaultPort();
connectionInfo.IsQuickConnect = true;
ConnectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
var connectionInitiator = new ConnectionInitiator();
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
}
public static void GoToWebsite()

View File

@@ -1,11 +1,4 @@
using mRemoteNG.App.Info;
using mRemoteNG.App.Update;
using mRemoteNG.Config.Connections;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
using System;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
@@ -14,22 +7,26 @@ using System.IO;
using System.Management;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App.Info;
using mRemoteNG.App.Update;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
using mRemoteNG.UI;
using WeifenLuo.WinFormsUI.Docking;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
public class Startup
{
private CompatibilityChecker _compatibilityChecker;
private AppUpdater _appUpdate;
public static Startup Instance { get; } = new Startup();
private Startup()
{
_compatibilityChecker = new CompatibilityChecker();
_appUpdate = new AppUpdater();
}
@@ -41,49 +38,29 @@ namespace mRemoteNG.App
{
Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture));
LogStartupData();
_compatibilityChecker.CheckCompatibility();
CompatibilityChecker.CheckCompatibility();
ParseCommandLineArgs();
IeBrowserEmulation.Register();
GetConnectionIcons();
DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, (a)=>"ConDefault"+a);
DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, (a)=>"InhDefault"+a);
}
public void SetDefaultLayout()
private static void GetConnectionIcons()
{
frmMain.Default.pnlDock.Visible = false;
frmMain.Default.pnlDock.DockLeftPortion = frmMain.Default.pnlDock.Width * 0.2;
frmMain.Default.pnlDock.DockRightPortion = frmMain.Default.pnlDock.Width * 0.2;
frmMain.Default.pnlDock.DockTopPortion = frmMain.Default.pnlDock.Height * 0.25;
frmMain.Default.pnlDock.DockBottomPortion = frmMain.Default.pnlDock.Height * 0.25;
Windows.TreePanel.Show(frmMain.Default.pnlDock, DockState.DockLeft);
Windows.ConfigPanel.Show(frmMain.Default.pnlDock);
Windows.ConfigPanel.DockTo(Windows.TreePanel.Pane, DockStyle.Bottom, -1);
Windows.ScreenshotForm.Hide();
frmMain.Default.pnlDock.Visible = true;
}
private void GetConnectionIcons()
{
string iPath = GeneralAppInfo.HomePath + "\\Icons\\";
var iPath = GeneralAppInfo.HomePath + "\\Icons\\";
if (Directory.Exists(iPath) == false)
{
return;
}
foreach (string f in Directory.GetFiles(iPath, "*.ico", SearchOption.AllDirectories))
foreach (var f in Directory.GetFiles(iPath, "*.ico", SearchOption.AllDirectories))
{
FileInfo fInfo = new FileInfo(f);
var fInfo = new FileInfo(f);
Array.Resize(ref ConnectionIcon.Icons, ConnectionIcon.Icons.Length + 1);
ConnectionIcon.Icons.SetValue(fInfo.Name.Replace(".ico", ""), ConnectionIcon.Icons.Length - 1);
}
}
private void LogStartupData()
private static void LogStartupData()
{
if (!Settings.Default.WriteLogFile) return;
LogApplicationData();
@@ -93,17 +70,17 @@ namespace mRemoteNG.App
LogCultureData();
}
private void LogSystemData()
private static void LogSystemData()
{
string osData = GetOperatingSystemData();
string architecture = GetArchitectureData();
Logger.Instance.InfoFormat(string.Join(" ", Array.FindAll(new[] { osData, architecture }, s => !string.IsNullOrEmpty(Convert.ToString(s)))));
var osData = GetOperatingSystemData();
var architecture = GetArchitectureData();
Logger.Instance.InfoFormat(string.Join(" ", Array.FindAll(new[] { osData, architecture }, s => !string.IsNullOrEmpty(s))));
}
private string GetOperatingSystemData()
private static string GetOperatingSystemData()
{
string osVersion = string.Empty;
string servicePack = string.Empty;
var osVersion = string.Empty;
var servicePack = string.Empty;
try
{
@@ -118,13 +95,13 @@ namespace mRemoteNG.App
{
Logger.Instance.WarnFormat($"Error retrieving operating system information from WMI. {ex.Message}");
}
string osData = string.Join(" ", new string[] { osVersion, servicePack });
var osData = string.Join(" ", osVersion, servicePack);
return osData;
}
private string GetOSServicePack(string servicePack, ManagementObject managementObject)
private static string GetOSServicePack(string servicePack, ManagementObject managementObject)
{
int servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
var servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
if (servicePackNumber != 0)
{
servicePack = $"Service Pack {servicePackNumber}";
@@ -132,15 +109,15 @@ namespace mRemoteNG.App
return servicePack;
}
private string GetArchitectureData()
private static string GetArchitectureData()
{
string architecture = string.Empty;
var architecture = string.Empty;
try
{
foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_Processor WHERE DeviceID=\'CPU0\'").Get())
{
var managementObject = (ManagementObject) o;
int addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
var addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
architecture = $"{addressWidth}-bit";
}
}
@@ -151,7 +128,7 @@ namespace mRemoteNG.App
return architecture;
}
private void LogApplicationData()
private static void LogApplicationData()
{
#if !PORTABLE
Logger.Instance.InfoFormat($"{Application.ProductName} {Application.ProductVersion} starting.");
@@ -161,17 +138,17 @@ namespace mRemoteNG.App
#endif
}
private void LogCmdLineArgs()
private static void LogCmdLineArgs()
{
Logger.Instance.InfoFormat($"Command Line: {Environment.GetCommandLineArgs()}");
}
private void LogCLRData()
private static void LogCLRData()
{
Logger.Instance.InfoFormat($"Microsoft .NET CLR {Environment.Version}");
}
private void LogCultureData()
private static void LogCultureData()
{
Logger.Instance.InfoFormat(
$"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}");
@@ -197,7 +174,7 @@ namespace mRemoteNG.App
return;
}
DateTime nextUpdateCheck = Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays))));
var nextUpdateCheck = Convert.ToDateTime(Settings.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Settings.Default.CheckForUpdatesFrequencyDays))));
if (!Settings.Default.UpdatePending && DateTime.UtcNow < nextUpdateCheck)
{
return;
@@ -211,7 +188,7 @@ namespace mRemoteNG.App
{
if (frmMain.Default.InvokeRequired)
{
frmMain.Default.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), new object[] { sender, e });
frmMain.Default.Invoke(new AsyncCompletedEventHandler(GetUpdateInfoCompleted), sender, e);
return;
}
@@ -225,7 +202,7 @@ namespace mRemoteNG.App
}
if (e.Error != null)
{
throw (e.Error);
throw e.Error;
}
if (_appUpdate.IsUpdateAvailable())
@@ -235,18 +212,45 @@ namespace mRemoteNG.App
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("GetUpdateInfoCompleted() failed.", ex, MessageClass.ErrorMsg, true);
Runtime.MessageCollector.AddExceptionMessage("GetUpdateInfoCompleted() failed.", ex);
}
}
/// <summary>
/// Returns a path to a file connections XML file for a given absolute or relative path
/// </summary>
/// <param name="ConsParam">The absolute or relative path to the connection XML file</param>
/// <returns>string or null</returns>
private static string GetCustomConsPath(string ConsParam)
{
// early exit condition
if (string.IsNullOrEmpty(ConsParam))
return null;
private void ParseCommandLineArgs()
// trim invalid characters for the Combine method (see: https://msdn.microsoft.com/en-us/library/fyy7a5kt.aspx#Anchor_2)
ConsParam = ConsParam.Trim().TrimStart('\\').Trim();
// fallback paths
if (File.Exists(ConsParam))
return ConsParam;
if (File.Exists(Path.Combine(GeneralAppInfo.HomePath, ConsParam)))
return GeneralAppInfo.HomePath + Path.DirectorySeparatorChar + ConsParam;
if (File.Exists(Path.Combine(ConnectionsFileInfo.DefaultConnectionsPath, ConsParam)))
return ConnectionsFileInfo.DefaultConnectionsPath + Path.DirectorySeparatorChar + ConsParam;
// default case
return null;
}
private static void ParseCommandLineArgs()
{
try
{
CmdArgumentsInterpreter cmd = new CmdArgumentsInterpreter(Environment.GetCommandLineArgs());
var cmd = new CmdArgumentsInterpreter(Environment.GetCommandLineArgs());
string ConsParam = "";
var ConsParam = "";
if (cmd["cons"] != null)
{
ConsParam = "cons";
@@ -256,7 +260,7 @@ namespace mRemoteNG.App
ConsParam = "c";
}
string ResetPosParam = "";
var ResetPosParam = "";
if (cmd["resetpos"] != null)
{
ResetPosParam = "resetpos";
@@ -266,7 +270,7 @@ namespace mRemoteNG.App
ResetPosParam = "rp";
}
string ResetPanelsParam = "";
var ResetPanelsParam = "";
if (cmd["resetpanels"] != null)
{
ResetPanelsParam = "resetpanels";
@@ -276,7 +280,7 @@ namespace mRemoteNG.App
ResetPanelsParam = "rpnl";
}
string ResetToolbarsParam = "";
var ResetToolbarsParam = "";
if (cmd["resettoolbar"] != null)
{
ResetToolbarsParam = "resettoolbar";
@@ -293,7 +297,7 @@ namespace mRemoteNG.App
ResetToolbarsParam = "rtbr";
}
string NoReconnectParam = "";
var NoReconnectParam = "";
if (cmd["noreconnect"] != null)
{
NoReconnectParam = "noreconnect";
@@ -303,29 +307,12 @@ namespace mRemoteNG.App
NoReconnectParam = "norc";
}
if (!string.IsNullOrEmpty(ConsParam))
// Handle custom connection file location
var consPathFromParam = GetCustomConsPath(ConsParam);
if (consPathFromParam != null)
{
if (File.Exists(cmd[ConsParam]) == false)
{
if (File.Exists(GeneralAppInfo.HomePath + "\\" + cmd[ConsParam]))
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = GeneralAppInfo.HomePath + "\\" + cmd[ConsParam];
return;
}
else if (File.Exists(ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam]))
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam];
return;
}
}
else
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = cmd[ConsParam];
return;
}
Settings.Default.CustomConsPath = consPathFromParam;
Settings.Default.LoadConsFromCustomLocation = true;
}
if (!string.IsNullOrEmpty(ResetPosParam))
@@ -350,6 +337,8 @@ namespace mRemoteNG.App
{
Settings.Default.ResetToolbars = true;
}
Settings.Default.Save();
}
catch (Exception ex)
{

View File

@@ -9,118 +9,122 @@ using mRemoteNG.Security.SymmetricEncryption;
using System.Security.Cryptography;
#if !PORTABLE
using mRemoteNG.Tools;
#else
using System.Windows.Forms;
#endif
namespace mRemoteNG.App.Update
{
public class AppUpdater
{
private WebProxy _webProxy;
public class AppUpdater
{
private WebProxy _webProxy;
private Thread _getUpdateInfoThread;
private Thread _getChangeLogThread;
#region Public Properties
#region Public Properties
public UpdateInfo CurrentUpdateInfo { get; private set; }
public string ChangeLog { get; private set; }
public string ChangeLog { get; private set; }
public bool IsGetUpdateInfoRunning => _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive;
public bool IsGetUpdateInfoRunning => _getUpdateInfoThread != null && _getUpdateInfoThread.IsAlive;
private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive;
private bool IsGetChangeLogRunning => _getChangeLogThread != null && _getChangeLogThread.IsAlive;
public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null;
public bool IsDownloadUpdateRunning => _downloadUpdateWebClient != null;
#endregion
#region Public Methods
public AppUpdater()
{
SetProxySettings();
}
#endregion
private void SetProxySettings()
{
var shouldWeUseProxy = Settings.Default.UpdateUseProxy;
var proxyAddress = Settings.Default.UpdateProxyAddress;
var port = Settings.Default.UpdateProxyPort;
var useAuthentication = Settings.Default.UpdateProxyUseAuthentication;
var username = Settings.Default.UpdateProxyAuthUser;
#region Public Methods
public AppUpdater()
{
SetProxySettings();
}
private void SetProxySettings()
{
var shouldWeUseProxy = Settings.Default.UpdateUseProxy;
var proxyAddress = Settings.Default.UpdateProxyAddress;
var port = Settings.Default.UpdateProxyPort;
var useAuthentication = Settings.Default.UpdateProxyUseAuthentication;
var username = Settings.Default.UpdateProxyAuthUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
var password = cryptographyProvider.Decrypt(Settings.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password);
}
public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password)
{
if (useProxy && !string.IsNullOrEmpty(address))
{
_webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address);
}
_webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null;
}
else
{
_webProxy = null;
}
}
public bool IsUpdateAvailable()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
return false;
}
return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion();
}
public void GetUpdateInfoAsync()
{
if (IsGetUpdateInfoRunning)
{
_getUpdateInfoThread.Abort();
}
_getUpdateInfoThread = new Thread(GetUpdateInfo);
_getUpdateInfoThread.SetApartmentState(ApartmentState.STA);
_getUpdateInfoThread.IsBackground = true;
_getUpdateInfoThread.Start();
}
public void GetChangeLogAsync()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync().");
}
if (IsGetChangeLogRunning)
{
_getChangeLogThread.Abort();
}
_getChangeLogThread = new Thread(GetChangeLog);
_getChangeLogThread.SetApartmentState(ApartmentState.STA);
_getChangeLogThread.IsBackground = true;
_getChangeLogThread.Start();
}
public void DownloadUpdateAsync()
{
if (_downloadUpdateWebClient != null)
{
throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress.");
}
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
}
public void SetProxySettings(bool useProxy, string address, int port, bool useAuthentication, string username, string password)
{
if (useProxy && !string.IsNullOrEmpty(address))
{
_webProxy = port != 0 ? new WebProxy(address, port) : new WebProxy(address);
_webProxy.Credentials = useAuthentication ? new NetworkCredential(username, password) : null;
}
else
{
_webProxy = null;
}
}
public bool IsUpdateAvailable()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
return false;
}
return CurrentUpdateInfo.Version > GeneralAppInfo.GetApplicationVersion();
}
public void GetUpdateInfoAsync()
{
if (IsGetUpdateInfoRunning)
{
_getUpdateInfoThread.Abort();
}
_getUpdateInfoThread = new Thread(GetUpdateInfo);
_getUpdateInfoThread.SetApartmentState(ApartmentState.STA);
_getUpdateInfoThread.IsBackground = true;
_getUpdateInfoThread.Start();
}
public void GetChangeLogAsync()
{
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException("CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling GetChangeLogAsync().");
}
if (IsGetChangeLogRunning)
{
_getChangeLogThread.Abort();
}
_getChangeLogThread = new Thread(GetChangeLog);
_getChangeLogThread.SetApartmentState(ApartmentState.STA);
_getChangeLogThread.IsBackground = true;
_getChangeLogThread.Start();
}
public void DownloadUpdateAsync()
{
if (_downloadUpdateWebClient != null)
{
throw new InvalidOperationException("A previous call to DownloadUpdateAsync() is still in progress.");
}
if (CurrentUpdateInfo == null || !CurrentUpdateInfo.IsValid)
{
throw new InvalidOperationException(
"CurrentUpdateInfo is not valid. GetUpdateInfoAsync() must be called before calling DownloadUpdateAsync().");
}
#if !PORTABLE
CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "exe"));
CurrentUpdateInfo.UpdateFilePath = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "msi"));
#else
var sfd = new SaveFileDialog
{
@@ -138,166 +142,174 @@ namespace mRemoteNG.App.Update
}
#endif
DownloadUpdateWebClient.DownloadFileAsync(CurrentUpdateInfo.DownloadAddress, CurrentUpdateInfo.UpdateFilePath);
}
#endregion
#region Private Properties
private WebClient _downloadUpdateWebClient;
private WebClient DownloadUpdateWebClient
{
get
{
if (_downloadUpdateWebClient != null)
{
return _downloadUpdateWebClient;
}
_downloadUpdateWebClient = CreateWebClient();
_downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged;
_downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted;
return _downloadUpdateWebClient;
}
}
#endregion
#region Private Methods
private WebClient CreateWebClient()
{
var webClient = new WebClient();
webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent);
webClient.Proxy = _webProxy;
return webClient;
}
private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result, Exception exception, bool cancelled, object userToken)
{
var type = typeof(DownloadStringCompletedEventArgs);
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)};
var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null);
object[] arguments = {result, exception, cancelled, userToken};
}
return (DownloadStringCompletedEventArgs)constructor.Invoke(arguments);
}
private DownloadStringCompletedEventArgs DownloadString(Uri address)
{
var webClient = CreateWebClient();
var result = string.Empty;
Exception exception = null;
var cancelled = false;
try
{
result = webClient.DownloadString(address);
}
catch (ThreadAbortException)
{
cancelled = true;
}
catch (Exception ex)
{
exception = ex;
}
return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null);
}
private void GetUpdateInfo()
{
var updateFileUri = new Uri(new Uri(Convert.ToString(Settings.Default.UpdateAddress)), new Uri(UpdateChannelInfo.FileName, UriKind.Relative));
var e = DownloadString(updateFileUri);
if (!e.Cancelled && e.Error == null)
{
CurrentUpdateInfo = UpdateInfo.FromString(e.Result);
#endregion
#region Private Properties
private WebClient _downloadUpdateWebClient;
private WebClient DownloadUpdateWebClient
{
get
{
if (_downloadUpdateWebClient != null)
{
return _downloadUpdateWebClient;
}
_downloadUpdateWebClient = CreateWebClient();
_downloadUpdateWebClient.DownloadProgressChanged += DownloadUpdateProgressChanged;
_downloadUpdateWebClient.DownloadFileCompleted += DownloadUpdateCompleted;
return _downloadUpdateWebClient;
}
}
#endregion
#region Private Methods
private WebClient CreateWebClient()
{
var webClient = new WebClient();
webClient.Headers.Add("user-agent", GeneralAppInfo.UserAgent);
webClient.Proxy = _webProxy;
return webClient;
}
private static DownloadStringCompletedEventArgs NewDownloadStringCompletedEventArgs(string result,
Exception exception, bool cancelled, object userToken)
{
var type = typeof(DownloadStringCompletedEventArgs);
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
Type[] argumentTypes = {typeof(string), typeof(Exception), typeof(bool), typeof(object)};
var constructor = type.GetConstructor(bindingFlags, null, argumentTypes, null);
object[] arguments = {result, exception, cancelled, userToken};
return (DownloadStringCompletedEventArgs) constructor.Invoke(arguments);
}
public DownloadStringCompletedEventArgs DownloadString(Uri address)
{
var webClient = CreateWebClient();
var result = string.Empty;
Exception exception = null;
var cancelled = false;
try
{
result = webClient.DownloadString(address);
}
catch (ThreadAbortException)
{
cancelled = true;
}
catch (Exception ex)
{
exception = ex;
}
return NewDownloadStringCompletedEventArgs(result, exception, cancelled, null);
}
private void GetUpdateInfo()
{
var e = DownloadString(UpdateChannelInfo.GetUpdateChannelInfo());
if (!e.Cancelled && e.Error == null)
{
CurrentUpdateInfo = UpdateInfo.FromString(e.Result);
Settings.Default.CheckForUpdatesLastCheck = DateTime.UtcNow;
if (!Settings.Default.UpdatePending)
{
if (!Settings.Default.UpdatePending)
{
Settings.Default.UpdatePending = IsUpdateAvailable();
}
}
}
}
GetUpdateInfoCompletedEventEvent?.Invoke(this, e);
}
private void GetChangeLog()
{
var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress);
if (!e.Cancelled && e.Error == null)
{
ChangeLog = e.Result;
}
private void GetChangeLog()
{
var e = DownloadString(CurrentUpdateInfo.ChangeLogAddress);
if (!e.Cancelled && e.Error == null)
{
ChangeLog = e.Result;
}
GetChangeLogCompletedEventEvent?.Invoke(this, e);
}
private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
private void DownloadUpdateProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
DownloadUpdateProgressChangedEventEvent?.Invoke(sender, e);
}
private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e)
{
var raiseEventArgs = e;
if (!e.Cancelled && e.Error == null)
{
try
{
private void DownloadUpdateCompleted(object sender, AsyncCompletedEventArgs e)
{
var raiseEventArgs = e;
if (!e.Cancelled && e.Error == null)
{
try
{
#if !PORTABLE
var updateAuthenticode = new Authenticode(CurrentUpdateInfo.UpdateFilePath)
{
RequireThumbprintMatch = true,
ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint
};
{
RequireThumbprintMatch = true,
ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint
};
if (updateAuthenticode.Verify() != Authenticode.StatusValue.Verified)
{
if (updateAuthenticode.Status == Authenticode.StatusValue.UnhandledException)
{
throw (updateAuthenticode.Exception);
}
if (updateAuthenticode.Verify() != Authenticode.StatusValue.Verified)
{
if (updateAuthenticode.Status == Authenticode.StatusValue.UnhandledException)
{
throw updateAuthenticode.Exception;
}
throw (new Exception(updateAuthenticode.StatusMessage));
}
throw new Exception(updateAuthenticode.StatusMessage);
}
#endif
using (var md5 = MD5.Create())
using (var cksum = SHA512.Create())
{
using (var stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath))
{
var hash = md5.ComputeHash(stream);
var hash = cksum.ComputeHash(stream);
var hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
if (!hashString.Equals(CurrentUpdateInfo.Checksum))
throw new Exception("MD5 Hashes didn't match!");
throw new Exception("SHA512 Hashes didn't match!");
}
}
}
catch (Exception ex)
{
raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null);
}
}
if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null)
{
File.Delete(CurrentUpdateInfo.UpdateFilePath);
}
catch (Exception ex)
{
raiseEventArgs = new AsyncCompletedEventArgs(ex, false, null);
}
}
if (raiseEventArgs.Cancelled || raiseEventArgs.Error != null)
{
File.Delete(CurrentUpdateInfo.UpdateFilePath);
}
DownloadUpdateCompletedEventEvent?.Invoke(this, raiseEventArgs);
_downloadUpdateWebClient.Dispose();
_downloadUpdateWebClient = null;
}
#endregion
#region Events
_downloadUpdateWebClient = null;
}
#endregion
#region Events
private AsyncCompletedEventHandler GetUpdateInfoCompletedEventEvent;
public event AsyncCompletedEventHandler GetUpdateInfoCompletedEvent
{
add
@@ -311,6 +323,7 @@ namespace mRemoteNG.App.Update
}
private AsyncCompletedEventHandler GetChangeLogCompletedEventEvent;
public event AsyncCompletedEventHandler GetChangeLogCompletedEvent
{
add
@@ -323,7 +336,8 @@ namespace mRemoteNG.App.Update
}
}
private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent;
private DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEventEvent;
public event DownloadProgressChangedEventHandler DownloadUpdateProgressChangedEvent
{
add
@@ -337,6 +351,7 @@ namespace mRemoteNG.App.Update
}
private AsyncCompletedEventHandler DownloadUpdateCompletedEventEvent;
public event AsyncCompletedEventHandler DownloadUpdateCompletedEvent
{
add
@@ -348,6 +363,7 @@ namespace mRemoteNG.App.Update
DownloadUpdateCompletedEventEvent = (AsyncCompletedEventHandler)Delegate.Remove(DownloadUpdateCompletedEventEvent, value);
}
}
#endregion
}
#endregion
}
}

View File

@@ -27,6 +27,9 @@ namespace mRemoteNG.App.Update
char[] keyValueSeparators = { ':', '=' };
char[] commentCharacters = { '#', ';', '\'' };
// no separators means no valid update data...
if (content.Trim().IndexOfAny(keyValueSeparators) == -1) return;
using (var sr = new StringReader(content))
{
string line;
@@ -43,6 +46,10 @@ namespace mRemoteNG.App.Update
if (parts.Length != 2)
continue;
// make sure we have valid data in both parts before adding to the collection. If either part is empty, then it's not valid data.
if(string.IsNullOrEmpty(parts[0].Trim()) || string.IsNullOrEmpty(parts[1].Trim()))
continue;
Items.Add(parts[0].Trim(), parts[1].Trim());
}
}

View File

@@ -1,4 +1,5 @@
using System;
// ReSharper disable UnusedAutoPropertyAccessor.Local
namespace mRemoteNG.App.Update
{
@@ -14,7 +15,8 @@ namespace mRemoteNG.App.Update
#if !PORTABLE
public string CertificateThumbprint { get; private set; }
#endif
public string FileName { get; private set; }
// ReSharper disable once MemberCanBePrivate.Global
public string FileName { get; set; }
public string Checksum { get; private set; }
public static UpdateInfo FromString(string input)
@@ -30,16 +32,45 @@ namespace mRemoteNG.App.Update
newInfo.Version = updateFile.GetVersion();
newInfo.DownloadAddress = updateFile.GetUri("dURL");
newInfo.ChangeLogAddress = updateFile.GetUri("clURL");
#if false
newInfo.ImageAddress = updateFile.GetUri("imgURL");
newInfo.ImageLinkAddress = updateFile.GetUri("imgURLLink");
#endif
#if !PORTABLE
newInfo.CertificateThumbprint = updateFile.GetThumbprint();
#endif
newInfo.FileName = updateFile.GetFileName();
newInfo.Checksum = updateFile.GetChecksum();
newInfo.IsValid = true;
newInfo.IsValid = newInfo.CheckIfValid();
}
return newInfo;
}
public bool CheckIfValid()
{
if (string.IsNullOrEmpty(Version.ToString()))
return false;
if(string.IsNullOrEmpty(DownloadAddress.AbsoluteUri))
return false;
if (string.IsNullOrEmpty(ChangeLogAddress.AbsoluteUri))
return false;
#if false
if (string.IsNullOrEmpty(ImageAddress.AbsoluteUri))
return false;
if (string.IsNullOrEmpty(ImageLinkAddress.AbsoluteUri))
return false;
#endif
#if !PORTABLE
if (string.IsNullOrEmpty(CertificateThumbprint))
return false;
#endif
if (string.IsNullOrEmpty(FileName))
return false;
// ReSharper disable once ConvertIfStatementToReturnStatement
if (string.IsNullOrEmpty(Checksum))
return false;
return true;
}
}
}

View File

@@ -23,7 +23,9 @@ namespace mRemoteNG.Config.Connections
{
var connector = new SqlDatabaseConnector();
var dataProvider = new SqlDataProvider(connector);
var dataTable = dataProvider.Load();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
databaseVersionVerifier.VerifyDatabaseVersion();
var dataTable = dataProvider.Load();
deserializer = new DataTableDeserializer(dataTable);
}
else

View File

@@ -85,11 +85,12 @@ namespace mRemoteNG.Config.Connections
{
var sqlConnector = new SqlDatabaseConnector();
sqlConnector.Connect();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(sqlConnector);
if (!VerifyDatabaseVersion(sqlConnector))
if (!databaseVersionVerifier.VerifyDatabaseVersion())
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorConnectionListSaveFailed);
return ;
return;
}
var rootTreeNode = Runtime.ConnectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
@@ -102,83 +103,6 @@ namespace mRemoteNG.Config.Connections
sqlConnector.Dispose();
}
private bool VerifyDatabaseVersion(SqlDatabaseConnector sqlDatabaseConnector)
{
var isVerified = false;
try
{
var databaseVersion = GetDatabaseVersion(sqlDatabaseConnector);
SqlCommand sqlCommand;
if (databaseVersion.Equals(new Version()))
{
return true;
}
if (databaseVersion.CompareTo(new Version(2, 2)) == 0) // 2.2
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Upgrading database from version {databaseVersion} to version 2.3.");
sqlCommand = new SqlCommand("ALTER TABLE tblCons ADD EnableFontSmoothing bit NOT NULL DEFAULT 0, EnableDesktopComposition bit NOT NULL DEFAULT 0, InheritEnableFontSmoothing bit NOT NULL DEFAULT 0, InheritEnableDesktopComposition bit NOT NULL DEFAULT 0;", sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
databaseVersion = new Version(2, 3);
}
if (databaseVersion.CompareTo(new Version(2, 3)) == 0) // 2.3
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Upgrading database from version {databaseVersion} to version 2.4.");
sqlCommand = new SqlCommand("ALTER TABLE tblCons ADD UseCredSsp bit NOT NULL DEFAULT 1, InheritUseCredSsp bit NOT NULL DEFAULT 0;", sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
databaseVersion = new Version(2, 4);
}
if (databaseVersion.CompareTo(new Version(2, 4)) == 0) // 2.4
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Upgrading database from version {databaseVersion} to version 2.5.");
sqlCommand = new SqlCommand("ALTER TABLE tblCons ADD LoadBalanceInfo varchar (1024) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, AutomaticResize bit NOT NULL DEFAULT 1, InheritLoadBalanceInfo bit NOT NULL DEFAULT 0, InheritAutomaticResize bit NOT NULL DEFAULT 0;", sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
databaseVersion = new Version(2, 5);
}
if (databaseVersion.CompareTo(new Version(2, 5)) == 0) // 2.5
isVerified = true;
if (isVerified == false)
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, string.Format(Language.strErrorBadDatabaseVersion, databaseVersion, GeneralAppInfo.ProductName));
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strErrorVerifyDatabaseVersionFailed, ex.Message));
}
return isVerified;
}
private Version GetDatabaseVersion(SqlDatabaseConnector sqlDatabaseConnector)
{
Version databaseVersion;
SqlDataReader sqlDataReader = null;
try
{
var sqlCommand = new SqlCommand("SELECT * FROM tblRoot", sqlDatabaseConnector.SqlConnection);
sqlDataReader = sqlCommand.ExecuteReader();
if (!sqlDataReader.HasRows)
return new Version(); // assume new empty database
else
sqlDataReader.Read();
databaseVersion = new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture));
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Retrieving database version failed. {ex}");
throw;
}
finally
{
if (sqlDataReader != null && !sqlDataReader.IsClosed)
sqlDataReader.Close();
}
return databaseVersion;
}
private void UpdateRootNodeTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();

View File

@@ -57,7 +57,15 @@ namespace mRemoteNG.Config.Connections
private bool DatabaseIsMoreUpToDateThanUs()
{
return GetLastUpdateTimeFromDbResponse() > _lastUpdateTime;
var lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
var IAmTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
return (lastUpdateInDb > _lastUpdateTime && !IAmTheLastoneUpdated);
}
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
{
DateTime LastSqlUpdateWithoutMilliseconds = new DateTime(Runtime.LastSqlUpdate.Ticks - (Runtime.LastSqlUpdate.Ticks % TimeSpan.TicksPerSecond), Runtime.LastSqlUpdate.Kind);
return lastUpdateInDb == LastSqlUpdateWithoutMilliseconds;
}
private DateTime GetLastUpdateTimeFromDbResponse()

View File

@@ -33,9 +33,13 @@ namespace mRemoteNG.Config.DataProviders
{
if (!SqlDatabaseConnector.IsConnected)
OpenConnection();
var sqlBulkCopy = new SqlBulkCopy(SqlDatabaseConnector.SqlConnection) {DestinationTableName = "dbo.tblCons"};
sqlBulkCopy.WriteToServer(dataTable);
sqlBulkCopy.Close();
using (var sqlBulkCopy = new SqlBulkCopy(SqlDatabaseConnector.SqlConnection))
{
foreach (DataColumn col in dataTable.Columns)
sqlBulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
sqlBulkCopy.DestinationTableName = "dbo.tblCons";
sqlBulkCopy.WriteToServer(dataTable);
}
}
public void OpenConnection()

View File

@@ -35,7 +35,7 @@ namespace mRemoteNG.Config.Import
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(true);
var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) };
rootImportContainer.Children.AddRange(connectionTreeModel.RootNodes.First().Children);
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
destinationContainer.AddChild(rootImportContainer);
}
}

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using mRemoteNG.Connection;
using mRemoteNG.Tree.Root;
@@ -42,7 +43,8 @@ namespace mRemoteNG.Config.Putty
private IEnumerable<PuttySessionInfo> GetSessionToRemove(IEnumerable<string> sessionNamesFromProvider)
{
var currentlyKnownSessionNames = Sessions.Select(session => session.Name);
var sessionNamesToRemove = currentlyKnownSessionNames.Except(sessionNamesFromProvider);
var normalizedSessionNames = sessionNamesFromProvider.Select(HttpUtility.UrlDecode);
var sessionNamesToRemove = currentlyKnownSessionNames.Except(normalizedSessionNames);
return Sessions.Where(session => sessionNamesToRemove.Contains(session.Name));
}

View File

@@ -31,7 +31,7 @@ namespace mRemoteNG.Config.Putty
if (raw && !sessionNames.Contains("Default%20Settings"))
sessionNames.Insert(0, "Default%20Settings");
else if (!sessionNames.Contains("Default Settings"))
else if (!raw && !sessionNames.Contains("Default Settings"))
sessionNames.Insert(0, "Default Settings");
return sessionNames.ToArray();

View File

@@ -130,7 +130,7 @@ namespace mRemoteNG.Config.Putty
if (_eventWatcher != null)
{
return ;
return;
}
try
@@ -158,7 +158,7 @@ namespace mRemoteNG.Config.Putty
if (_eventWatcher == null)
{
return ;
return;
}
_eventWatcher.EnableRaisingEvents = false;
_eventWatcher.Dispose();
@@ -231,7 +231,7 @@ namespace mRemoteNG.Config.Putty
{
if (!File.Exists(_puttyConfFile))
{
return ;
return;
}
using (var streamReader = new StreamReader(_puttyConfFile))
{
@@ -299,7 +299,7 @@ namespace mRemoteNG.Config.Putty
{
if (!File.Exists(_sessionFile))
{
return ;
return;
}
using (var streamReader = new StreamReader(_sessionFile))
{

View File

@@ -66,7 +66,7 @@ namespace mRemoteNG.Config.Serializers
// check/continue here so we don't create empty connection objects
if(!_importSubOU) continue;
ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer);
ActiveDirectoryImporter.Import(ldapResult.Path, parentContainer, _importSubOU);
continue;
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Data;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.Http;
@@ -33,6 +34,7 @@ namespace mRemoteNG.Config.Serializers
{
var connectionList = CreateNodesFromTable();
var connectionTreeModel = CreateNodeHierarchy(connectionList);
Runtime.IsConnectionsFileLoaded = true;
return connectionTreeModel;
}
@@ -41,10 +43,16 @@ namespace mRemoteNG.Config.Serializers
var nodeList = new List<ConnectionInfo>();
foreach (DataRow row in _dataTable.Rows)
{
if ((string)row["Type"] == "Connection")
// ReSharper disable once SwitchStatementMissingSomeCases
switch ((string)row["Type"])
{
case "Connection":
nodeList.Add(DeserializeConnectionInfo(row));
else if ((string)row["Type"] == "Container")
break;
case "Container":
nodeList.Add(DeserializeContainerInfo(row));
break;
}
}
return nodeList;
}
@@ -67,8 +75,15 @@ namespace mRemoteNG.Config.Serializers
{
connectionInfo.Name = (string)dataRow["Name"];
connectionInfo.ConstantID = (string)dataRow["ConstantID"];
// This throws a NPE - Parent is a connectionInfo object which will be null at this point.
// The Parent object is linked properly later in CreateNodeHierarchy()
//connectionInfo.Parent.ConstantID = (string)dataRow["ParentID"];
//connectionInfo is ContainerInfo ? ((ContainerInfo)connectionInfo).IsExpanded.ToString() : "" = dataRow["Expanded"];
var info = connectionInfo as ContainerInfo;
if(info != null)
info.IsExpanded = (bool)dataRow["Expanded"];
connectionInfo.Description = (string)dataRow["Description"];
connectionInfo.Icon = (string)dataRow["Icon"];
connectionInfo.Panel = (string)dataRow["Panel"];
@@ -84,6 +99,8 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.RenderingEngine = (HTTPBase.RenderingEngine)Enum.Parse(typeof(HTTPBase.RenderingEngine), (string)dataRow["RenderingEngine"]);
connectionInfo.ICAEncryptionStrength = (ProtocolICA.EncryptionStrength)Enum.Parse(typeof(ProtocolICA.EncryptionStrength), (string)dataRow["ICAEncryptionStrength"]);
connectionInfo.RDPAuthenticationLevel = (ProtocolRDP.AuthenticationLevel)Enum.Parse(typeof(ProtocolRDP.AuthenticationLevel), (string)dataRow["RDPAuthenticationLevel"]);
connectionInfo.RDPMinutesToIdleTimeout = (int)dataRow["RDPMinutesToIdleTimeout"];
connectionInfo.RDPAlertIdleTimeout = (bool)dataRow["RDPAlertIdleTimeout"];
connectionInfo.LoadBalanceInfo = (string)dataRow["LoadBalanceInfo"];
connectionInfo.Colors = (ProtocolRDP.RDPColors)Enum.Parse(typeof(ProtocolRDP.RDPColors) ,(string)dataRow["Colors"]);
connectionInfo.Resolution = (ProtocolRDP.RDPResolutions)Enum.Parse(typeof(ProtocolRDP.RDPResolutions), (string)dataRow["Resolution"]);
@@ -153,6 +170,8 @@ namespace mRemoteNG.Config.Serializers
connectionInfo.Inheritance.Username = (bool)dataRow["InheritUsername"];
connectionInfo.Inheritance.ICAEncryptionStrength = (bool)dataRow["InheritICAEncryptionStrength"];
connectionInfo.Inheritance.RDPAuthenticationLevel = (bool)dataRow["InheritRDPAuthenticationLevel"];
connectionInfo.Inheritance.RDPAlertIdleTimeout = (bool)dataRow["InheritRDPAlertIdleTimeout"];
connectionInfo.Inheritance.RDPMinutesToIdleTimeout = (bool)dataRow["InheritRDPMinutesToIdleTimeout"];
connectionInfo.Inheritance.LoadBalanceInfo = (bool)dataRow["InheritLoadBalanceInfo"];
connectionInfo.Inheritance.PreExtApp = (bool)dataRow["InheritPreExtApp"];
connectionInfo.Inheritance.PostExtApp = (bool)dataRow["InheritPostExtApp"];
@@ -189,7 +208,7 @@ namespace mRemoteNG.Config.Serializers
var id = (string) row["ConstantID"];
var connectionInfo = connectionList.First(node => node.ConstantID == id);
var parentId = (string) row["ParentID"];
if (parentId == "0")
if (parentId == "0" || connectionList.All(node => node.ConstantID != parentId))
rootNode.AddChild(connectionInfo);
else
(connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(connectionInfo);

View File

@@ -25,141 +25,162 @@ namespace mRemoteNG.Config.Serializers
public DataTable Serialize(ConnectionTreeModel connectionTreeModel)
{
var rootNode = (RootNodeInfo)connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
return Serialize(rootNode);
try
{
_dataTable = BuildTable();
_currentNodeIndex = 0;
var rootNode = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
return Serialize(rootNode);
}
catch
{
return _dataTable;
}
}
public DataTable Serialize(ConnectionInfo serializationTarget)
{
_dataTable = new DataTable(TableName);
CreateSchema();
SetPrimaryKey();
_dataTable = BuildTable();
_currentNodeIndex = 0;
SerializeNodesRecursive(serializationTarget);
return _dataTable;
}
private void CreateSchema()
private DataTable BuildTable()
{
_dataTable.Columns.Add("ID", typeof(int));
_dataTable.Columns[0].AutoIncrement = true;
_dataTable.Columns.Add("ConstantID", typeof(string));
_dataTable.Columns.Add("PositionID", typeof(int));
_dataTable.Columns.Add("ParentID", typeof(string));
_dataTable.Columns.Add("LastChange", typeof(SqlDateTime));
_dataTable.Columns.Add("Name", typeof(string));
_dataTable.Columns.Add("Type", typeof(string));
_dataTable.Columns.Add("Expanded", typeof(bool));
_dataTable.Columns.Add("Description", typeof(string));
_dataTable.Columns.Add("Icon", typeof(string));
_dataTable.Columns.Add("Panel", typeof(string));
_dataTable.Columns.Add("Username", typeof(string));
_dataTable.Columns.Add("DomainName", typeof(string));
_dataTable.Columns.Add("Password", typeof(string));
_dataTable.Columns.Add("Hostname", typeof(string));
_dataTable.Columns.Add("Protocol", typeof(string));
_dataTable.Columns.Add("PuttySession", typeof(string));
_dataTable.Columns.Add("Port", typeof(int));
_dataTable.Columns.Add("ConnectToConsole", typeof(bool));
_dataTable.Columns.Add("UseCredSsp", typeof(bool));
_dataTable.Columns.Add("RenderingEngine", typeof(string));
_dataTable.Columns.Add("ICAEncryptionStrength", typeof(string));
_dataTable.Columns.Add("RDPAuthenticationLevel", typeof(string));
_dataTable.Columns.Add("Colors", typeof(string));
_dataTable.Columns.Add("Resolution", typeof(string));
_dataTable.Columns.Add("DisplayWallpaper", typeof(bool));
_dataTable.Columns.Add("DisplayThemes", typeof(bool));
_dataTable.Columns.Add("EnableFontSmoothing", typeof(bool));
_dataTable.Columns.Add("EnableDesktopComposition", typeof(bool));
_dataTable.Columns.Add("CacheBitmaps", typeof(bool));
_dataTable.Columns.Add("RedirectDiskDrives", typeof(bool));
_dataTable.Columns.Add("RedirectPorts", typeof(bool));
_dataTable.Columns.Add("RedirectPrinters", typeof(bool));
_dataTable.Columns.Add("RedirectSmartCards", typeof(bool));
_dataTable.Columns.Add("RedirectSound", typeof(string));
_dataTable.Columns.Add("RedirectKeys", typeof(bool));
_dataTable.Columns.Add("Connected", typeof(bool));
_dataTable.Columns.Add("PreExtApp", typeof(string));
_dataTable.Columns.Add("PostExtApp", typeof(string));
_dataTable.Columns.Add("MacAddress", typeof(string));
_dataTable.Columns.Add("UserField", typeof(string));
_dataTable.Columns.Add("ExtApp", typeof(string));
_dataTable.Columns.Add("VNCCompression", typeof(string));
_dataTable.Columns.Add("VNCEncoding", typeof(string));
_dataTable.Columns.Add("VNCAuthMode", typeof(string));
_dataTable.Columns.Add("VNCProxyType", typeof(string));
_dataTable.Columns.Add("VNCProxyIP", typeof(string));
_dataTable.Columns.Add("VNCProxyPort", typeof(int));
_dataTable.Columns.Add("VNCProxyUsername", typeof(string));
_dataTable.Columns.Add("VNCProxyPassword", typeof(string));
_dataTable.Columns.Add("VNCColors", typeof(string));
_dataTable.Columns.Add("VNCSmartSizeMode", typeof(string));
_dataTable.Columns.Add("VNCViewOnly", typeof(bool));
_dataTable.Columns.Add("RDGatewayUsageMethod", typeof(string));
_dataTable.Columns.Add("RDGatewayHostname", typeof(string));
_dataTable.Columns.Add("RDGatewayUseConnectionCredentials", typeof(string));
_dataTable.Columns.Add("RDGatewayUsername", typeof(string));
_dataTable.Columns.Add("RDGatewayPassword", typeof(string));
_dataTable.Columns.Add("RDGatewayDomain", typeof(string));
_dataTable.Columns.Add("InheritCacheBitmaps", typeof(bool));
_dataTable.Columns.Add("InheritColors", typeof(bool));
_dataTable.Columns.Add("InheritDescription", typeof(bool));
_dataTable.Columns.Add("InheritDisplayThemes", typeof(bool));
_dataTable.Columns.Add("InheritDisplayWallpaper", typeof(bool));
_dataTable.Columns.Add("InheritEnableFontSmoothing", typeof(bool));
_dataTable.Columns.Add("InheritEnableDesktopComposition", typeof(bool));
_dataTable.Columns.Add("InheritDomain", typeof(bool));
_dataTable.Columns.Add("InheritIcon", typeof(bool));
_dataTable.Columns.Add("InheritPanel", typeof(bool));
_dataTable.Columns.Add("InheritPassword", typeof(bool));
_dataTable.Columns.Add("InheritPort", typeof(bool));
_dataTable.Columns.Add("InheritProtocol", typeof(bool));
_dataTable.Columns.Add("InheritPuttySession", typeof(bool));
_dataTable.Columns.Add("InheritRedirectDiskDrives", typeof(bool));
_dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
_dataTable.Columns.Add("InheritRedirectPorts", typeof(bool));
_dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool));
_dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool));
_dataTable.Columns.Add("InheritRedirectSound", typeof(bool));
_dataTable.Columns.Add("InheritSoundQuality", typeof(bool));
_dataTable.Columns.Add("InheritResolution", typeof(bool));
_dataTable.Columns.Add("InheritUseConsoleSession", typeof(bool));
_dataTable.Columns.Add("InheritUseCredSsp", typeof(bool));
_dataTable.Columns.Add("InheritRenderingEngine", typeof(bool));
_dataTable.Columns.Add("InheritICAEncryptionStrength", typeof(bool));
_dataTable.Columns.Add("InheritRDPAuthenticationLevel", typeof(bool));
_dataTable.Columns.Add("InheritUsername", typeof(bool));
_dataTable.Columns.Add("InheritPreExtApp", typeof(bool));
_dataTable.Columns.Add("InheritPostExtApp", typeof(bool));
_dataTable.Columns.Add("InheritMacAddress", typeof(bool));
_dataTable.Columns.Add("InheritUserField", typeof(bool));
_dataTable.Columns.Add("InheritExtApp", typeof(bool));
_dataTable.Columns.Add("InheritVNCCompression", typeof(bool));
_dataTable.Columns.Add("InheritVNCEncoding", typeof(bool));
_dataTable.Columns.Add("InheritVNCAuthMode", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyType", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyIP", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyPort", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyUsername", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyPassword", typeof(bool));
_dataTable.Columns.Add("InheritVNCColors", typeof(bool));
_dataTable.Columns.Add("InheritVNCSmartSizeMode", typeof(bool));
_dataTable.Columns.Add("InheritVNCViewOnly", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayUsageMethod", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayHostname", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayUseConnectionCredentials", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayUsername", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayPassword", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayDomain", typeof(bool));
_dataTable.Columns.Add("LoadBalanceInfo", typeof(string));
_dataTable.Columns.Add("AutomaticResize", typeof(bool));
_dataTable.Columns.Add("InheritLoadBalanceInfo", typeof(bool));
_dataTable.Columns.Add("InheritAutomaticResize", typeof(bool));
var dataTable = new DataTable(TableName);
CreateSchema(dataTable);
SetPrimaryKey(dataTable);
return dataTable;
}
private void SetPrimaryKey()
private void CreateSchema(DataTable dataTable)
{
_dataTable.PrimaryKey = new[] { _dataTable.Columns["ConstantID"] };
// Note: these columns must be defined in the same order that they exist in the DB
dataTable.Columns.Add("ID", typeof(int));
dataTable.Columns[0].AutoIncrement = true;
dataTable.Columns.Add("ConstantID", typeof(string));
dataTable.Columns.Add("PositionID", typeof(int));
dataTable.Columns.Add("ParentID", typeof(string));
dataTable.Columns.Add("LastChange", typeof(SqlDateTime));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("Type", typeof(string));
dataTable.Columns.Add("Expanded", typeof(bool));
dataTable.Columns.Add("Description", typeof(string));
dataTable.Columns.Add("Icon", typeof(string));
dataTable.Columns.Add("Panel", typeof(string));
dataTable.Columns.Add("Username", typeof(string));
dataTable.Columns.Add("DomainName", typeof(string));
dataTable.Columns.Add("Password", typeof(string));
dataTable.Columns.Add("Hostname", typeof(string));
dataTable.Columns.Add("Protocol", typeof(string));
dataTable.Columns.Add("PuttySession", typeof(string));
dataTable.Columns.Add("Port", typeof(int));
dataTable.Columns.Add("ConnectToConsole", typeof(bool));
dataTable.Columns.Add("UseCredSsp", typeof(bool));
dataTable.Columns.Add("RenderingEngine", typeof(string));
dataTable.Columns.Add("ICAEncryptionStrength", typeof(string));
dataTable.Columns.Add("RDPAuthenticationLevel", typeof(string));
dataTable.Columns.Add("Colors", typeof(string));
dataTable.Columns.Add("Resolution", typeof(string));
dataTable.Columns.Add("DisplayWallpaper", typeof(bool));
dataTable.Columns.Add("DisplayThemes", typeof(bool));
dataTable.Columns.Add("EnableFontSmoothing", typeof(bool));
dataTable.Columns.Add("EnableDesktopComposition", typeof(bool));
dataTable.Columns.Add("CacheBitmaps", typeof(bool));
dataTable.Columns.Add("RedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("RedirectPorts", typeof(bool));
dataTable.Columns.Add("RedirectPrinters", typeof(bool));
dataTable.Columns.Add("RedirectSmartCards", typeof(bool));
dataTable.Columns.Add("RedirectSound", typeof(string));
dataTable.Columns.Add("RedirectKeys", typeof(bool));
dataTable.Columns.Add("Connected", typeof(bool));
dataTable.Columns.Add("PreExtApp", typeof(string));
dataTable.Columns.Add("PostExtApp", typeof(string));
dataTable.Columns.Add("MacAddress", typeof(string));
dataTable.Columns.Add("UserField", typeof(string));
dataTable.Columns.Add("ExtApp", typeof(string));
dataTable.Columns.Add("VNCCompression", typeof(string));
dataTable.Columns.Add("VNCEncoding", typeof(string));
dataTable.Columns.Add("VNCAuthMode", typeof(string));
dataTable.Columns.Add("VNCProxyType", typeof(string));
dataTable.Columns.Add("VNCProxyIP", typeof(string));
dataTable.Columns.Add("VNCProxyPort", typeof(int));
dataTable.Columns.Add("VNCProxyUsername", typeof(string));
dataTable.Columns.Add("VNCProxyPassword", typeof(string));
dataTable.Columns.Add("VNCColors", typeof(string));
dataTable.Columns.Add("VNCSmartSizeMode", typeof(string));
dataTable.Columns.Add("VNCViewOnly", typeof(bool));
dataTable.Columns.Add("RDGatewayUsageMethod", typeof(string));
dataTable.Columns.Add("RDGatewayHostname", typeof(string));
dataTable.Columns.Add("RDGatewayUseConnectionCredentials", typeof(string));
dataTable.Columns.Add("RDGatewayUsername", typeof(string));
dataTable.Columns.Add("RDGatewayPassword", typeof(string));
dataTable.Columns.Add("RDGatewayDomain", typeof(string));
dataTable.Columns.Add("InheritCacheBitmaps", typeof(bool));
dataTable.Columns.Add("InheritColors", typeof(bool));
dataTable.Columns.Add("InheritDescription", typeof(bool));
dataTable.Columns.Add("InheritDisplayThemes", typeof(bool));
dataTable.Columns.Add("InheritDisplayWallpaper", typeof(bool));
dataTable.Columns.Add("InheritEnableFontSmoothing", typeof(bool));
dataTable.Columns.Add("InheritEnableDesktopComposition", typeof(bool));
dataTable.Columns.Add("InheritDomain", typeof(bool));
dataTable.Columns.Add("InheritIcon", typeof(bool));
dataTable.Columns.Add("InheritPanel", typeof(bool));
dataTable.Columns.Add("InheritPassword", typeof(bool));
dataTable.Columns.Add("InheritPort", typeof(bool));
dataTable.Columns.Add("InheritProtocol", typeof(bool));
dataTable.Columns.Add("InheritPuttySession", typeof(bool));
dataTable.Columns.Add("InheritRedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
dataTable.Columns.Add("InheritRedirectPorts", typeof(bool));
dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool));
dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool));
dataTable.Columns.Add("InheritRedirectSound", typeof(bool));
dataTable.Columns.Add("InheritResolution", typeof(bool));
dataTable.Columns.Add("InheritUseConsoleSession", typeof(bool));
dataTable.Columns.Add("InheritUseCredSsp", typeof(bool));
dataTable.Columns.Add("InheritRenderingEngine", typeof(bool));
dataTable.Columns.Add("InheritICAEncryptionStrength", typeof(bool));
dataTable.Columns.Add("InheritRDPAuthenticationLevel", typeof(bool));
dataTable.Columns.Add("InheritUsername", typeof(bool));
dataTable.Columns.Add("InheritPreExtApp", typeof(bool));
dataTable.Columns.Add("InheritPostExtApp", typeof(bool));
dataTable.Columns.Add("InheritMacAddress", typeof(bool));
dataTable.Columns.Add("InheritUserField", typeof(bool));
dataTable.Columns.Add("InheritExtApp", typeof(bool));
dataTable.Columns.Add("InheritVNCCompression", typeof(bool));
dataTable.Columns.Add("InheritVNCEncoding", typeof(bool));
dataTable.Columns.Add("InheritVNCAuthMode", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyType", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyIP", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyPort", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyUsername", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyPassword", typeof(bool));
dataTable.Columns.Add("InheritVNCColors", typeof(bool));
dataTable.Columns.Add("InheritVNCSmartSizeMode", typeof(bool));
dataTable.Columns.Add("InheritVNCViewOnly", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayUsageMethod", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayHostname", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayUseConnectionCredentials", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayUsername", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayPassword", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayDomain", typeof(bool));
dataTable.Columns.Add("LoadBalanceInfo", typeof(string));
dataTable.Columns.Add("AutomaticResize", typeof(bool));
dataTable.Columns.Add("InheritLoadBalanceInfo", typeof(bool));
dataTable.Columns.Add("InheritAutomaticResize", typeof(bool));
dataTable.Columns.Add("RDPMinutesToIdleTimeout", typeof(int));
dataTable.Columns.Add("RDPAlertIdleTimeout", typeof(bool));
dataTable.Columns.Add("SoundQuality", typeof(string));
dataTable.Columns.Add("InheritRDPMinutesToIdleTimeout", typeof(bool));
dataTable.Columns.Add("InheritRDPAlertIdleTimeout", typeof(bool));
dataTable.Columns.Add("InheritSoundQuality", typeof(bool));
}
private void SetPrimaryKey(DataTable dataTable)
{
dataTable.PrimaryKey = new[] { dataTable.Columns["ConstantID"] };
}
private void SerializeNodesRecursive(ConnectionInfo connectionInfo)
@@ -180,7 +201,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["Name"] = connectionInfo.Name;
dataRow["Type"] = connectionInfo.GetTreeNodeType().ToString();
dataRow["ConstantID"] = connectionInfo.ConstantID;
dataRow["ParentID"] = connectionInfo.Parent.ConstantID;
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
dataRow["PositionID"] = _currentNodeIndex;
dataRow["LastChange"] = (SqlDateTime)DateTime.Now;
var info = connectionInfo as ContainerInfo;
@@ -200,6 +221,8 @@ namespace mRemoteNG.Config.Serializers
dataRow["RenderingEngine"] = connectionInfo.RenderingEngine;
dataRow["ICAEncryptionStrength"] = connectionInfo.ICAEncryptionStrength;
dataRow["RDPAuthenticationLevel"] = connectionInfo.RDPAuthenticationLevel;
dataRow["RDPMinutesToIdleTimeout"] = connectionInfo.RDPMinutesToIdleTimeout;
dataRow["RDPAlertIdleTimeout"] = connectionInfo.RDPAlertIdleTimeout;
dataRow["LoadBalanceInfo"] = connectionInfo.LoadBalanceInfo;
dataRow["Colors"] = connectionInfo.Colors;
dataRow["Resolution"] = connectionInfo.Resolution;
@@ -214,7 +237,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["RedirectPrinters"] = connectionInfo.RedirectPrinters;
dataRow["RedirectSmartCards"] = connectionInfo.RedirectSmartCards;
dataRow["RedirectSound"] = connectionInfo.RedirectSound;
//dataRow["SoundQuality"] = connectionInfo.SoundQuality;
dataRow["SoundQuality"] = connectionInfo.SoundQuality;
dataRow["RedirectKeys"] = connectionInfo.RedirectKeys;
dataRow["Connected"] = connectionInfo.OpenConnections.Count > 0;
dataRow["PreExtApp"] = connectionInfo.PreExtApp;
@@ -261,7 +284,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritRedirectPrinters"] = connectionInfo.Inheritance.RedirectPrinters;
dataRow["InheritRedirectSmartCards"] = connectionInfo.Inheritance.RedirectSmartCards;
dataRow["InheritRedirectSound"] = connectionInfo.Inheritance.RedirectSound;
//dataRow["InheritSoundQuality"] = connectionInfo.Inheritance.SoundQuality;
dataRow["InheritSoundQuality"] = connectionInfo.Inheritance.SoundQuality;
dataRow["InheritResolution"] = connectionInfo.Inheritance.Resolution;
dataRow["InheritAutomaticResize"] = connectionInfo.Inheritance.AutomaticResize;
dataRow["InheritUseConsoleSession"] = connectionInfo.Inheritance.UseConsoleSession;
@@ -270,6 +293,8 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritUsername"] = connectionInfo.Inheritance.Username;
dataRow["InheritICAEncryptionStrength"] = connectionInfo.Inheritance.ICAEncryptionStrength;
dataRow["InheritRDPAuthenticationLevel"] = connectionInfo.Inheritance.RDPAuthenticationLevel;
dataRow["InheritRDPMinutesToIdleTimeout"] = connectionInfo.Inheritance.RDPMinutesToIdleTimeout;
dataRow["InheritRDPAlertIdleTimeout"] = connectionInfo.Inheritance.RDPAlertIdleTimeout;
dataRow["InheritLoadBalanceInfo"] = connectionInfo.Inheritance.LoadBalanceInfo;
dataRow["InheritPreExtApp"] = connectionInfo.Inheritance.PreExtApp;
dataRow["InheritPostExtApp"] = connectionInfo.Inheritance.PostExtApp;
@@ -316,7 +341,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritRedirectPrinters"] = false;
dataRow["InheritRedirectSmartCards"] = false;
dataRow["InheritRedirectSound"] = false;
//dataRow["InheritSoundQuality"] = false;
dataRow["InheritSoundQuality"] = false;
dataRow["InheritResolution"] = false;
dataRow["InheritAutomaticResize"] = false;
dataRow["InheritUseConsoleSession"] = false;
@@ -325,6 +350,8 @@ namespace mRemoteNG.Config.Serializers
dataRow["InheritUsername"] = false;
dataRow["InheritICAEncryptionStrength"] = false;
dataRow["InheritRDPAuthenticationLevel"] = false;
dataRow["InheritRDPMinutesToIdleTimeout"] = false;
dataRow["InheritRDPAlertIdleTimeout"] = false;
dataRow["InheritLoadBalanceInfo"] = false;
dataRow["InheritPreExtApp"] = false;
dataRow["InheritPostExtApp"] = false;

View File

@@ -0,0 +1,158 @@
using System;
using System.Data.SqlClient;
using System.Globalization;
using mRemoteNG.App;
using mRemoteNG.App.Info;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Messages;
namespace mRemoteNG.Config.Serializers
{
public class SqlDatabaseVersionVerifier
{
private readonly SqlDatabaseConnector _sqlDatabaseConnector;
public SqlDatabaseVersionVerifier(SqlDatabaseConnector sqlDatabaseConnector)
{
if (sqlDatabaseConnector == null)
throw new ArgumentNullException(nameof(sqlDatabaseConnector));
_sqlDatabaseConnector = sqlDatabaseConnector;
}
public bool VerifyDatabaseVersion()
{
var isVerified = false;
try
{
var databaseVersion = GetDatabaseVersion(_sqlDatabaseConnector);
if (databaseVersion.Equals(new Version()))
{
return true;
}
if (databaseVersion.CompareTo(new Version(2, 2)) == 0) // 2.2
{
UpgradeFrom2_2();
databaseVersion = new Version(2, 3);
}
if (databaseVersion.CompareTo(new Version(2, 3)) == 0) // 2.3
{
UpgradeFrom2_3();
databaseVersion = new Version(2, 4);
}
if (databaseVersion.CompareTo(new Version(2, 4)) == 0) // 2.4
{
UpgradeFrom2_4();
databaseVersion = new Version(2, 5);
}
if (databaseVersion.CompareTo(new Version(2, 5)) == 0) // 2.5
{
UpgradeFrom2_5();
databaseVersion = new Version(2, 6);
}
if (databaseVersion.CompareTo(new Version(2, 6)) == 0) // 2.6
isVerified = true;
if (isVerified == false)
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
string.Format(Language.strErrorBadDatabaseVersion, databaseVersion, GeneralAppInfo.ProductName));
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
string.Format(Language.strErrorVerifyDatabaseVersionFailed, ex.Message));
}
return isVerified;
}
private Version GetDatabaseVersion(SqlDatabaseConnector sqlDatabaseConnector)
{
Version databaseVersion;
SqlDataReader sqlDataReader = null;
try
{
var sqlCommand = new SqlCommand("SELECT * FROM tblRoot", sqlDatabaseConnector.SqlConnection);
if (!sqlDatabaseConnector.IsConnected)
sqlDatabaseConnector.Connect();
sqlDataReader = sqlCommand.ExecuteReader();
if (!sqlDataReader.HasRows)
return new Version(); // assume new empty database
else
sqlDataReader.Read();
databaseVersion =
new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture));
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Retrieving database version failed. {ex}");
throw;
}
finally
{
if (sqlDataReader != null && !sqlDataReader.IsClosed)
sqlDataReader.Close();
}
return databaseVersion;
}
private void UpgradeFrom2_2()
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.2 to version 2.3.");
const string sqlText = @"
ALTER TABLE tblCons
ADD EnableFontSmoothing bit NOT NULL DEFAULT 0,
EnableDesktopComposition bit NOT NULL DEFAULT 0,
InheritEnableFontSmoothing bit NOT NULL DEFAULT 0,
InheritEnableDesktopComposition bit NOT NULL DEFAULT 0;";
var sqlCommand = new SqlCommand(sqlText, _sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
}
private void UpgradeFrom2_3()
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.3 to version 2.4.");
const string sqlText = @"
ALTER TABLE tblCons
ADD UseCredSsp bit NOT NULL DEFAULT 1,
InheritUseCredSsp bit NOT NULL DEFAULT 0;";
var sqlCommand = new SqlCommand(sqlText, _sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
}
private void UpgradeFrom2_4()
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.4 to version 2.5.");
const string sqlText = @"
ALTER TABLE tblCons
ADD LoadBalanceInfo varchar (1024) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
AutomaticResize bit NOT NULL DEFAULT 1,
InheritLoadBalanceInfo bit NOT NULL DEFAULT 0,
InheritAutomaticResize bit NOT NULL DEFAULT 0;";
var sqlCommand = new SqlCommand(sqlText, _sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
}
private void UpgradeFrom2_5()
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Upgrading database from version 2.5 to version 2.6.");
const string sqlText = @"
ALTER TABLE tblCons
ADD RDPMinutesToIdleTimeout int NOT NULL DEFAULT 0,
RDPAlertIdleTimeout bit NOT NULL DEFAULT 0,
SoundQuality varchar (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL DEFAULT 'Dynamic',
InheritRDPMinutesToIdleTimeout bit NOT NULL DEFAULT 0,
InheritRDPAlertIdleTimeout bit NOT NULL DEFAULT 0,
InheritSoundQuality bit NOT NULL DEFAULT 0;
UPDATE tblRoot
SET ConfVersion='2.6'";
var sqlCommand = new SqlCommand(sqlText, _sqlDatabaseConnector.SqlConnection);
sqlCommand.ExecuteNonQuery();
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Security;
using System;
using System.Security;
using System.Xml.Linq;
using mRemoteNG.Connection;
using mRemoteNG.Container;
@@ -13,14 +14,15 @@ namespace mRemoteNG.Config.Serializers
private readonly SecureString _encryptionKey;
private readonly SaveFilter _saveFilter = new SaveFilter();
public XmlConnectionNodeSerializer(ICryptographyProvider cryptographyProvider, SecureString encryptionKey)
{
_cryptographyProvider = cryptographyProvider;
_encryptionKey = encryptionKey;
}
public XmlConnectionNodeSerializer(ICryptographyProvider cryptographyProvider, SecureString encryptionKey, SaveFilter saveFilter)
{
if (cryptographyProvider == null)
throw new ArgumentNullException(nameof(cryptographyProvider));
if (encryptionKey == null)
throw new ArgumentNullException(nameof(encryptionKey));
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_cryptographyProvider = cryptographyProvider;
_encryptionKey = encryptionKey;
_saveFilter = saveFilter;
@@ -44,6 +46,7 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("Descr", connectionInfo.Description));
element.Add(new XAttribute("Icon", connectionInfo.Icon));
element.Add(new XAttribute("Panel", connectionInfo.Panel));
element.Add(new XAttribute("Id", connectionInfo.ConstantID));
element.Add(_saveFilter.SaveUsername
? new XAttribute("Username", connectionInfo.Username)
@@ -67,6 +70,8 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("RenderingEngine", connectionInfo.RenderingEngine));
element.Add(new XAttribute("ICAEncryptionStrength", connectionInfo.ICAEncryptionStrength));
element.Add(new XAttribute("RDPAuthenticationLevel", connectionInfo.RDPAuthenticationLevel));
element.Add(new XAttribute("RDPMinutesToIdleTimeout", connectionInfo.RDPMinutesToIdleTimeout));
element.Add(new XAttribute("RDPAlertIdleTimeout", connectionInfo.RDPAlertIdleTimeout));
element.Add(new XAttribute("LoadBalanceInfo", connectionInfo.LoadBalanceInfo));
element.Add(new XAttribute("Colors", connectionInfo.Colors));
element.Add(new XAttribute("Resolution", connectionInfo.Resolution));
@@ -159,6 +164,8 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("InheritUsername", connectionInfo.Inheritance.Username.ToString()));
element.Add(new XAttribute("InheritICAEncryptionStrength", connectionInfo.Inheritance.ICAEncryptionStrength.ToString()));
element.Add(new XAttribute("InheritRDPAuthenticationLevel", connectionInfo.Inheritance.RDPAuthenticationLevel.ToString()));
element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", connectionInfo.Inheritance.RDPMinutesToIdleTimeout.ToString()));
element.Add(new XAttribute("InheritRDPAlertIdleTimeout", connectionInfo.Inheritance.RDPAlertIdleTimeout.ToString()));
element.Add(new XAttribute("InheritLoadBalanceInfo", connectionInfo.Inheritance.LoadBalanceInfo.ToString()));
element.Add(new XAttribute("InheritPreExtApp", connectionInfo.Inheritance.PreExtApp.ToString()));
element.Add(new XAttribute("InheritPostExtApp", connectionInfo.Inheritance.PostExtApp.ToString()));
@@ -214,6 +221,8 @@ namespace mRemoteNG.Config.Serializers
element.Add(new XAttribute("InheritUsername", false.ToString()));
element.Add(new XAttribute("InheritICAEncryptionStrength", false.ToString()));
element.Add(new XAttribute("InheritRDPAuthenticationLevel", false.ToString()));
element.Add(new XAttribute("InheritRDPMinutesToIdleTimeout", false.ToString()));
element.Add(new XAttribute("InheritRDPAlertIdleTimeout", false.ToString()));
element.Add(new XAttribute("InheritLoadBalanceInfo", false.ToString()));
element.Add(new XAttribute("InheritPreExtApp", false.ToString()));
element.Add(new XAttribute("InheritPostExtApp", false.ToString()));

View File

@@ -485,8 +485,13 @@ namespace mRemoteNG.Config.Serializers
if (_confVersion >= 2.6)
{
connectionInfo.ConstantID = xmlnode.Attributes["Id"]?.Value ?? connectionInfo.ConstantID;
connectionInfo.SoundQuality = (ProtocolRDP.RDPSoundQuality)Tools.MiscTools.StringToEnum(typeof(ProtocolRDP.RDPSoundQuality), Convert.ToString(xmlnode.Attributes["SoundQuality"].Value));
connectionInfo.Inheritance.SoundQuality = bool.Parse(xmlnode.Attributes["InheritSoundQuality"].Value);
connectionInfo.RDPMinutesToIdleTimeout = Convert.ToInt32(xmlnode.Attributes["RDPMinutesToIdleTimeout"]?.Value ?? "0");
connectionInfo.Inheritance.RDPMinutesToIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPMinutesToIdleTimeout"]?.Value ?? "False");
connectionInfo.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["RDPAlertIdleTimeout"]?.Value ?? "False");
connectionInfo.Inheritance.RDPAlertIdleTimeout = bool.Parse(xmlnode.Attributes["InheritRDPAlertIdleTimeout"]?.Value ?? "False");
}
}
catch (Exception ex)

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Security;
using System.Xml.Linq;
using mRemoteNG.Connection;
@@ -14,10 +15,17 @@ namespace mRemoteNG.Config.Serializers
{
private readonly ICryptographyProvider _cryptographyProvider;
private SecureString _encryptionKey;
private readonly SaveFilter _saveFilter;
public XmlConnectionsDocumentCompiler(ICryptographyProvider cryptographyProvider)
public XmlConnectionsDocumentCompiler(ICryptographyProvider cryptographyProvider, SaveFilter saveFilter)
{
if (cryptographyProvider == null)
throw new ArgumentNullException(nameof(cryptographyProvider));
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_cryptographyProvider = cryptographyProvider;
_saveFilter = saveFilter;
}
public XDocument CompileDocument(ConnectionTreeModel connectionTreeModel, bool fullFileEncryption, bool export)
@@ -77,7 +85,7 @@ namespace mRemoteNG.Config.Serializers
private XElement CompileConnectionInfoNode(ConnectionInfo connectionInfo)
{
var connectionSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, _encryptionKey);
var connectionSerializer = new XmlConnectionNodeSerializer(_cryptographyProvider, _encryptionKey, _saveFilter);
return connectionSerializer.SerializeConnectionInfo(connectionInfo);
}
}

View File

@@ -41,7 +41,7 @@ namespace mRemoteNG.Config.Serializers
var xml = "";
try
{
var documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider);
var documentCompiler = new XmlConnectionsDocumentCompiler(_cryptographyProvider, SaveFilter);
var xmlDocument = documentCompiler.CompileDocument(serializationTarget, UseFullEncryption, Export);
xml = WriteXmlToString(xmlDocument);
}

View File

@@ -20,47 +20,59 @@ namespace mRemoteNG.Config.Settings
public void LoadExternalAppsFromXML()
{
var oldPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + GeneralAppInfo.ProductName + "\\" + SettingsFileInfo.ExtAppsFilesName;
var newPath = SettingsFileInfo.SettingsPath + "\\" + SettingsFileInfo.ExtAppsFilesName;
#if !PORTABLE
var oldPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), GeneralAppInfo.ProductName, SettingsFileInfo.ExtAppsFilesName);
#endif
var newPath = Path.Combine(SettingsFileInfo.SettingsPath, SettingsFileInfo.ExtAppsFilesName);
var xDom = new XmlDocument();
if (File.Exists(newPath))
{
Logger.Instance.Info($"Loading External Apps from: {newPath}");
xDom.Load(newPath);
}
#if !PORTABLE
}
else if (File.Exists(oldPath))
{
xDom.Load(oldPath);
Logger.Instance.Info($"Loading External Apps from: {oldPath}");
xDom.Load(oldPath);
}
#endif
}
else
{
Logger.Instance.Warn("Loading External Apps failed: Could not FIND file!");
return;
}
if (xDom.DocumentElement != null)
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
if (xDom.DocumentElement == null)
{
Logger.Instance.Warn("Loading External Apps failed: Could not LOAD file!");
return;
}
foreach (XmlElement xEl in xDom.DocumentElement.ChildNodes)
{
var extA = new ExternalTool
{
var extA = new ExternalTool
{
DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value,
Arguments = xEl.Attributes["Arguments"].Value
};
DisplayName = xEl.Attributes["DisplayName"].Value,
FileName = xEl.Attributes["FileName"].Value,
Arguments = xEl.Attributes["Arguments"].Value
};
if (xEl.HasAttribute("WaitForExit"))
{
extA.WaitForExit = bool.Parse(xEl.Attributes["WaitForExit"].Value);
}
if (xEl.HasAttribute("TryToIntegrate"))
{
extA.TryIntegrate = bool.Parse(xEl.Attributes["TryToIntegrate"].Value);
}
Runtime.ExternalTools.Add(extA);
if (xEl.HasAttribute("WaitForExit"))
{
extA.WaitForExit = bool.Parse(xEl.Attributes["WaitForExit"].Value);
}
if (xEl.HasAttribute("TryToIntegrate"))
{
extA.TryIntegrate = bool.Parse(xEl.Attributes["TryToIntegrate"].Value);
}
Logger.Instance.Info($"Adding External App: {extA.DisplayName} {extA.FileName} {extA.Arguments}");
Runtime.ExternalTools.Add(extA);
}
_MainForm.SwitchToolBarText(Convert.ToBoolean(mRemoteNG.Settings.Default.ExtAppsTBShowText));
frmMain.Default.AddExternalToolsToToolBar();

View File

@@ -48,7 +48,7 @@ namespace mRemoteNG.Config.Settings
}
else
{
Startup.Instance.SetDefaultLayout();
frmMain.Default.SetDefaultLayout();
}
}
catch (Exception ex)

View File

@@ -9,6 +9,7 @@ using mRemoteNG.Themes;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.App.Info;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.UI.Forms;
@@ -137,14 +138,14 @@ namespace mRemoteNG.Config.Settings
private void SetKioskMode()
{
if (!mRemoteNG.Settings.Default.MainFormKiosk) return;
MainForm.Fullscreen.Value = true;
MainForm._fullscreen.Value = true;
MainForm.mMenViewFullscreen.Checked = true;
}
private static void SetShowSystemTrayIcon()
{
if (mRemoteNG.Settings.Default.ShowSystemTrayIcon)
Runtime.NotificationAreaIcon = new Tools.Controls.NotificationAreaIcon();
Runtime.NotificationAreaIcon = new NotificationAreaIcon();
}
private static void SetPuttyPath()

View File

@@ -36,9 +36,9 @@ namespace mRemoteNG.Config.Settings
mRemoteNG.Settings.Default.MainFormState = with1.WindowState;
if (with1.Fullscreen != null)
if (with1._fullscreen != null)
{
mRemoteNG.Settings.Default.MainFormKiosk = with1.Fullscreen.Value;
mRemoteNG.Settings.Default.MainFormKiosk = with1._fullscreen.Value;
}
mRemoteNG.Settings.Default.FirstStart = false;

View File

@@ -30,6 +30,8 @@ namespace mRemoteNG.Connection
private ProtocolICA.EncryptionStrength _icaEncryption;
private bool _useConsoleSession;
private ProtocolRDP.AuthenticationLevel _rdpAuthenticationLevel;
private int _rdpMinutesToIdleTimeout;
private bool _rdpAlertIdleTimeout;
private string _loadBalanceInfo;
private HTTPBase.RenderingEngine _renderingEngine;
private bool _useCredSsp;
@@ -225,6 +227,30 @@ namespace mRemoteNG.Connection
set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); }
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPMinutesToIdleTimeout"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")]
public virtual int RDPMinutesToIdleTimeout
{
get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); }
set {
if(value < 0) {
value = 0;
} else if(value > 240) {
value = 240;
}
SetField(ref _rdpMinutesToIdleTimeout, value, "RDPMinutesToIdleTimeout");
}
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameRDPAlertIdleTimeout"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")]
public bool RDPAlertIdleTimeout
{
get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); }
set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); }
}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
LocalizedAttributes.LocalizedDisplayName("strPropertyNameLoadBalanceInfo"),
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")]

View File

@@ -78,7 +78,6 @@ namespace mRemoteNG.Connection
var newConnectionInfo = new ConnectionInfo();
newConnectionInfo.CopyFrom(this);
newConnectionInfo.ConstantID = MiscTools.CreateConstantID();
newConnectionInfo.SetParent(Parent);
newConnectionInfo.Inheritance = Inheritance.Clone();
return newConnectionInfo;
}
@@ -172,7 +171,7 @@ namespace mRemoteNG.Connection
{
var inheritType = Inheritance.GetType();
var inheritPropertyInfo = inheritType.GetProperty(propertyName);
var inheritPropertyValue = Convert.ToBoolean(inheritPropertyInfo.GetValue(Inheritance, null));
var inheritPropertyValue = inheritPropertyInfo != null && Convert.ToBoolean(inheritPropertyInfo.GetValue(Inheritance, null));
return inheritPropertyValue;
}
@@ -180,15 +179,20 @@ namespace mRemoteNG.Connection
{
var connectionInfoType = Parent.GetType();
var parentPropertyInfo = connectionInfoType.GetProperty(propertyName);
if (parentPropertyInfo == null)
return default(TPropertyType); // shouldn't get here...
var parentPropertyValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
return parentPropertyValue;
}
private static int GetDefaultPort(ProtocolType protocol)
{
try
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (protocol)
{
case ProtocolType.RDP:
@@ -248,6 +252,8 @@ namespace mRemoteNG.Connection
ICAEncryptionStrength = (ProtocolICA.EncryptionStrength) Enum.Parse(typeof(ProtocolICA.EncryptionStrength), Settings.Default.ConDefaultICAEncryptionStrength);
UseConsoleSession = Settings.Default.ConDefaultUseConsoleSession;
RDPAuthenticationLevel = (ProtocolRDP.AuthenticationLevel) Enum.Parse(typeof(ProtocolRDP.AuthenticationLevel), Settings.Default.ConDefaultRDPAuthenticationLevel);
RDPMinutesToIdleTimeout = Settings.Default.ConDefaultRDPMinutesToIdleTimeout;
RDPAlertIdleTimeout = Settings.Default.ConDefaultRDPAlertIdleTimeout;
LoadBalanceInfo = Settings.Default.ConDefaultLoadBalanceInfo;
RenderingEngine = (HTTPBase.RenderingEngine) Enum.Parse(typeof(HTTPBase.RenderingEngine), Settings.Default.ConDefaultRenderingEngine);
UseCredSsp = Settings.Default.ConDefaultUseCredSsp;

View File

@@ -83,9 +83,19 @@ namespace mRemoteNG.Connection
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameAuthenticationLevel"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionAuthenticationLevel"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPAuthenticationLevel {get; set;}
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPAuthenticationLevel {get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPMinutesToIdleTimeout"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPMinutesToIdleTimeout"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool RDPMinutesToIdleTimeout { get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameRDPAlertIdleTimeout"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionRDPAlertIdleTimeout"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))] public bool RDPAlertIdleTimeout { get; set; }
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 4),
LocalizedAttributes.LocalizedDisplayNameInheritAttribute("strPropertyNameLoadBalanceInfo"),
LocalizedAttributes.LocalizedDescriptionInheritAttribute("strPropertyDescriptionLoadBalanceInfo"),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]public bool LoadBalanceInfo {get; set;}

View File

@@ -12,14 +12,52 @@ using TabPage = Crownwood.Magic.Controls.TabPage;
namespace mRemoteNG.Connection
{
public static class ConnectionInitiator
public class ConnectionInitiator : IConnectionInitiator
{
public static void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
{
OpenConnection(containerInfo, force, null);
}
private static void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm)
public void OpenConnection(ConnectionInfo connectionInfo)
{
try
{
OpenConnection(connectionInfo, ConnectionInfo.Force.None);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
}
}
public void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{
try
{
OpenConnection(connectionInfo, force, null);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
}
}
public bool SwitchToOpenConnection(ConnectionInfo connectionInfo)
{
var interfaceControl = FindConnectionContainer(connectionInfo);
if (interfaceControl == null) return false;
var connectionWindow = (ConnectionWindow)interfaceControl.FindForm();
connectionWindow?.Focus();
var findForm = (ConnectionWindow)interfaceControl.FindForm();
findForm?.Show(frmMain.Default.pnlDock);
var tabPage = (TabPage)interfaceControl.Parent;
tabPage.Selected = true;
return true;
}
#region Private
private void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force, Form conForm)
{
var children = containerInfo.Children;
if (children.Count == 0) return;
@@ -33,31 +71,7 @@ namespace mRemoteNG.Connection
}
}
public static void OpenConnection(ConnectionInfo connectionInfo)
{
try
{
OpenConnection(connectionInfo, ConnectionInfo.Force.None);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message);
}
}
public static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force)
{
try
{
OpenConnection(connectionInfo, force, null);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message);
}
}
private static void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm)
private void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force, Form conForm)
{
try
{
@@ -104,7 +118,7 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionOpenFailed + Environment.NewLine + ex.Message);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionOpenFailed, ex);
}
}
@@ -115,19 +129,6 @@ namespace mRemoteNG.Connection
extA?.Start(connectionInfo);
}
public static bool SwitchToOpenConnection(ConnectionInfo nCi)
{
var IC = FindConnectionContainer(nCi);
if (IC == null) return false;
var connectionWindow = (ConnectionWindow)IC.FindForm();
connectionWindow?.Focus();
var findForm = (ConnectionWindow)IC.FindForm();
findForm?.Show(frmMain.Default.pnlDock);
var tabPage = (TabPage)IC.Parent;
tabPage.Selected = true;
return true;
}
private static InterfaceControl FindConnectionContainer(ConnectionInfo connectionInfo)
{
if (connectionInfo.OpenConnections.Count <= 0) return null;
@@ -185,11 +186,15 @@ namespace mRemoteNG.Connection
{
Control connectionContainer = ((ConnectionWindow)connectionForm).AddConnectionTab(connectionInfo);
if (connectionInfo.Protocol == ProtocolType.IntApp)
{
if (Runtime.GetExtAppByName(connectionInfo.ExtApp).Icon != null)
((TabPage)connectionContainer).Icon = Runtime.GetExtAppByName(connectionInfo.ExtApp).Icon;
}
if (connectionInfo.Protocol != ProtocolType.IntApp) return connectionContainer;
var extT = Runtime.GetExtAppByName(connectionInfo.ExtApp);
if(extT == null) return connectionContainer;
if (extT.Icon != null)
((TabPage)connectionContainer).Icon = extT.Icon;
return connectionContainer;
}
@@ -210,10 +215,9 @@ namespace mRemoteNG.Connection
{
newProtocol.InterfaceControl = new InterfaceControl(connectionContainer, newProtocol, connectionInfo);
}
#endregion
#region Event handlers
private static void Prot_Event_Disconnected(object sender, string disconnectedMessage)
{
try
@@ -230,7 +234,7 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.strProtocolEventDisconnectFailed, ex.Message), true);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strProtocolEventDisconnectFailed, ex);
}
}
@@ -240,7 +244,15 @@ namespace mRemoteNG.Connection
{
var Prot = (ProtocolBase)sender;
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strConnenctionCloseEvent, true);
Runtime.MessageCollector.AddMessage(MessageClass.ReportMsg, string.Format(Language.strConnenctionClosedByUser, Prot.InterfaceControl.Info.Hostname, Prot.InterfaceControl.Info.Protocol.ToString(), Environment.UserName));
string connDetail;
if (Prot.InterfaceControl.Info.Hostname == "" && Prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp)
connDetail = Prot.InterfaceControl.Info.ExtApp;
else if (Prot.InterfaceControl.Info.Hostname != "")
connDetail = Prot.InterfaceControl.Info.Hostname;
else
connDetail = "UNKNOWN";
Runtime.MessageCollector.AddMessage(MessageClass.ReportMsg, string.Format(Language.strConnenctionClosedByUser, connDetail, Prot.InterfaceControl.Info.Protocol, Environment.UserName));
Prot.InterfaceControl.Info.OpenConnections.Remove(Prot);
if (Prot.InterfaceControl.Info.PostExtApp == "") return;
@@ -249,7 +261,7 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnenctionCloseEventFailed + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnenctionCloseEventFailed, ex);
}
}
@@ -273,8 +285,9 @@ namespace mRemoteNG.Connection
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strConnectionEventConnectionFailed + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace(Language.strConnectionEventConnectionFailed, ex);
}
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
using mRemoteNG.App;
namespace mRemoteNG.Connection
@@ -17,11 +18,17 @@ namespace mRemoteNG.Connection
public void LoadFrom<TSource>(TSource sourceInstance, Func<string, string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var connectionProperties = GetProperties(_excludedProperties);
foreach (var property in connectionProperties)
{
var propertyFromSource = typeof(TSource).GetProperty(propertyNameMutator(property.Name));
if (propertyFromSource == null)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInfo-LoadFrom: Could not load {property.Name}", true);
continue;
}
var valueFromSource = propertyFromSource.GetValue(sourceInstance, null);
var descriptor = TypeDescriptor.GetProperties(Instance)[property.Name];
@@ -35,19 +42,27 @@ namespace mRemoteNG.Connection
public void SaveTo<TDestination>(TDestination destinationInstance, Func<string, string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var inheritanceProperties = GetProperties(_excludedProperties);
foreach (var property in inheritanceProperties)
{
var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
var descriptor = TypeDescriptor.GetProperties(Instance)[property.Name];
var converter = descriptor.Converter;
if (converter != null && converter.CanConvertFrom(localValue.GetType()))
propertyFromDestination.SetValue(destinationInstance, converter.ConvertFrom(localValue), null);
else
propertyFromDestination.SetValue(destinationInstance, localValue, null);
try
{
var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
if (propertyFromDestination == null)
{
Runtime.MessageCollector?.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInfo-SaveTo: Could not load {property.Name}", true);
continue;
}
var convertedValue = Convert.ChangeType(localValue, propertyFromDestination.PropertyType);
propertyFromDestination.SetValue(destinationInstance, convertedValue, null);
}
catch (Exception ex)
{
Runtime.MessageCollector?.AddExceptionStackTrace($"Error saving default connectioninfo property {property.Name}", ex);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using mRemoteNG.App;
namespace mRemoteNG.Connection
@@ -17,11 +18,17 @@ namespace mRemoteNG.Connection
public void LoadFrom<TSource>(TSource sourceInstance, Func<string,string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var inheritanceProperties = GetProperties();
foreach (var property in inheritanceProperties)
{
var propertyFromSettings = typeof(TSource).GetProperty(propertyNameMutator(property.Name));
if (propertyFromSettings == null)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInherit-LoadFrom: Could not load {property.Name}", true);
continue;
}
var valueFromSettings = propertyFromSettings.GetValue(sourceInstance, null);
property.SetValue(Instance, valueFromSettings, null);
}
@@ -29,12 +36,18 @@ namespace mRemoteNG.Connection
public void SaveTo<TDestination>(TDestination destinationInstance, Func<string, string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var inheritanceProperties = GetProperties();
foreach (var property in inheritanceProperties)
{
var propertyFromSettings = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
if (propertyFromSettings == null)
{
Runtime.MessageCollector?.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInherit-SaveTo: Could not load {property.Name}", true);
continue;
}
propertyFromSettings.SetValue(destinationInstance, localValue, null);
}
}

View File

@@ -0,0 +1,15 @@
using mRemoteNG.Container;
namespace mRemoteNG.Connection
{
public interface IConnectionInitiator
{
void OpenConnection(ConnectionInfo connectionInfo);
void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None);
void OpenConnection(ConnectionInfo connectionInfo, ConnectionInfo.Force force);
bool SwitchToOpenConnection(ConnectionInfo connectionInfo);
}
}

View File

@@ -172,7 +172,7 @@ namespace mRemoteNG.Connection.Protocol.Http
WebBrowser objWebBrowser = wBrowser as WebBrowser;
if (objWebBrowser == null)
{
return ;
return;
}
// This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise.

View File

@@ -137,7 +137,7 @@ namespace mRemoteNG.Connection.Protocol.ICA
{
if (((int)Force & (int)ConnectionInfo.Force.NoCredentials) == (int)ConnectionInfo.Force.NoCredentials)
{
return ;
return;
}
string _user = _Info.Username;

View File

@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Messages;
namespace mRemoteNG.Connection.Protocol
@@ -20,41 +21,52 @@ namespace mRemoteNG.Connection.Protocol
#region Public Methods
public override bool Initialize()
{
if (InterfaceControl.Info != null)
{
_externalTool = Runtime.GetExtAppByName(Convert.ToString(InterfaceControl.Info.ExtApp));
_externalTool.ConnectionInfo = InterfaceControl.Info;
}
return base.Initialize();
if (InterfaceControl.Info == null) return base.Initialize();
_externalTool = Runtime.GetExtAppByName(InterfaceControl.Info.Name);
_externalTool.ConnectionInfo = InterfaceControl.Info;
return base.Initialize();
}
public override bool Connect()
{
try
{
if (_externalTool.TryIntegrate == false)
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Attempting to start: {_externalTool.DisplayName}", true);
if (_externalTool.TryIntegrate == false)
{
_externalTool.Start(InterfaceControl.Info);
Close();
return false;
/* Don't call close here... There's nothing for the override to do in this case since
* _process is not created in this scenario. When returning false, ProtocolBase.Close()
* will be called - which is just going to call IntegratedProgram.Close() again anyway...
* Close();
*/
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Assuming no other errors/exceptions occurred immediately before this message regarding {_externalTool.DisplayName}, the next \"closed by user\" message can be ignored", true);
return false;
}
ExternalToolArgumentParser argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
_process = new Process();
_process.StartInfo.UseShellExecute = true;
_process.StartInfo.FileName = argParser.ParseArguments(_externalTool.FileName);
_process.StartInfo.Arguments = argParser.ParseArguments(_externalTool.Arguments);
_process.EnableRaisingEvents = true;
_process.Exited += ProcessExited;
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
_process = new Process
{
StartInfo =
{
UseShellExecute = true,
FileName = argParser.ParseArguments(_externalTool.FileName),
Arguments = argParser.ParseArguments(_externalTool.Arguments)
},
EnableRaisingEvents = true
};
_process.Exited += ProcessExited;
_process.Start();
_process.WaitForInputIdle(Convert.ToInt32(Settings.Default.MaxPuttyWaitTime * 1000));
int startTicks = Environment.TickCount;
while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + (Settings.Default.MaxPuttyWaitTime * 1000))
_process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount;
while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
{
_process.Refresh();
if (_process.MainWindowTitle != "Default IME")
@@ -68,10 +80,10 @@ namespace mRemoteNG.Connection.Protocol
}
NativeMethods.SetParent(_handle, InterfaceControl.Handle);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, Language.strIntAppStuff, true);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle.ToString()), true);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true);
Runtime.MessageCollector.AddMessage(Messages.MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle.ToString()), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strIntAppStuff, true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle), true);
Resize(this, new EventArgs());
base.Connect();
@@ -88,15 +100,12 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
if (ConnectionWindow.InTabDrag)
{
return ;
}
if (ConnectionWindow.InTabDrag) return;
NativeMethods.SetForegroundWindow(_handle);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppFocusFailed, ex: ex, logOnly: true);
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppFocusFailed, ex);
}
}
@@ -104,45 +113,49 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
if (InterfaceControl.Size == Size.Empty)
{
return ;
}
NativeMethods.MoveWindow(_handle, Convert.ToInt32(-SystemInformation.FrameBorderSize.Width), Convert.ToInt32(-(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height)), InterfaceControl.Width + (SystemInformation.FrameBorderSize.Width * 2), InterfaceControl.Height + SystemInformation.CaptionHeight + (SystemInformation.FrameBorderSize.Height * 2), true);
if (InterfaceControl.Size == Size.Empty) return;
NativeMethods.MoveWindow(_handle, -SystemInformation.FrameBorderSize.Width, -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, InterfaceControl.Height + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2, true);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppResizeFailed, ex: ex, logOnly: true);
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppResizeFailed, ex);
}
}
public override void Close()
{
try
{
if (!_process.HasExited)
{
_process.Kill();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppKillFailed, ex: ex, logOnly: true);
}
try
{
if (!_process.HasExited)
{
_process.Dispose();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(message: Language.strIntAppDisposeFailed, ex: ex, logOnly: true);
}
base.Close();
/* only attempt this if we have a valid process object
* Non-integated tools will still call base.Close() and don't have a valid process object.
* See Connect() above... This just muddies up the log.
*/
if (_process != null)
{
try
{
if (!_process.HasExited)
{
_process.Kill();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppKillFailed, ex);
}
try
{
if (!_process.HasExited)
{
_process.Dispose();
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppDisposeFailed, ex);
}
}
base.Close();
}
#endregion

View File

@@ -23,12 +23,12 @@ namespace mRemoteNG.Connection.Protocol
#region Public Properties
#region Control
public string Name { get; set; }
private string Name { get; }
protected UI.Window.ConnectionWindow ConnectionWindow
{
get { return _connectionWindow; }
set
private set
{
_connectionWindow = value;
_connectionWindow.ResizeBegin += ResizeBegin;
@@ -61,7 +61,7 @@ namespace mRemoteNG.Connection.Protocol
Name = name;
}
public ProtocolBase()
protected ProtocolBase()
{
}
@@ -78,7 +78,7 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t focus Control (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't focus Control (Connection.Protocol.Base)", ex);
}
}
@@ -112,7 +112,7 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t SetProps (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't SetProps (Connection.Protocol.Base)", ex);
return false;
}
}
@@ -132,7 +132,7 @@ namespace mRemoteNG.Connection.Protocol
public virtual void Close()
{
Thread t = new Thread(CloseBG);
var t = new Thread(CloseBG);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
@@ -153,31 +153,31 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, "Could not dispose control, probably form is already closed (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", ex);
}
}
if (_interfaceControl != null)
{
try
{
if (_interfaceControl.Parent == null) return;
if (_interfaceControl.Parent.Tag != null)
{
SetTagToNothing();
}
if (_interfaceControl == null) return;
try
{
if (_interfaceControl.Parent == null) return;
if (_interfaceControl.Parent.Tag != null)
{
SetTagToNothing();
}
DisposeInterface();
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.WarningMsg, "Could not set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
}
}
DisposeInterface();
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)", ex);
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, "Couldn\'t Close InterfaceControl BG (Connection.Protocol.Base)" + Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex);
}
}
@@ -186,7 +186,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (_interfaceControl.InvokeRequired)
{
DisposeInterfaceCB s = new DisposeInterfaceCB(DisposeInterface);
var s = new DisposeInterfaceCB(DisposeInterface);
_interfaceControl.Invoke(s);
}
else
@@ -200,7 +200,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (_interfaceControl.Parent.InvokeRequired)
{
SetTagToNothingCB s = new SetTagToNothingCB(SetTagToNothing);
var s = new SetTagToNothingCB(SetTagToNothing);
_interfaceControl.Parent.Invoke(s);
}
else
@@ -214,7 +214,7 @@ namespace mRemoteNG.Connection.Protocol
{
if (Control.InvokeRequired)
{
DisposeControlCB s = new DisposeControlCB(DisposeControl);
var s = new DisposeControlCB(DisposeControl);
Control.Invoke(s);
}
else

Some files were not shown because too many files have changed in this diff Show More