Compare commits

..

192 Commits

Author SHA1 Message Date
Faryan Rezagholi
8a5f0f248e open credential manager from connection tree window 2021-09-04 00:52:04 +02:00
Faryan Rezagholi
c1931ff4cd hide password/username/domain fields in connection properties 2021-09-04 00:27:42 +02:00
Faryan Rezagholi
12cb7ad7b0 merged from develop 2021-09-01 01:26:21 +02:00
Faryan Rezagholi
fdea0144b0 removed test output from script 2021-08-29 18:44:08 +02:00
Faryan Rezagholi
7398a373c2 Squashed commit of the following:
commit 84b28316d01d158891d909e90fe428e48d5566e3
Author: Faryan Rezagholi <faryan.rezagholi@siedle.de>
Date:   Sun Aug 29 13:08:31 2021 +0200

    r

commit 7375b4a5456a615b36c4fbf0eda7a8d56762de85
Author: Faryan Rezagholi <faryan.rezagholi@siedle.de>
Date:   Sun Aug 29 12:54:40 2021 +0200

    ...

commit 96aa9d809131c8277bd62cb90fdfa4fd07f1940e
Author: Faryan Rezagholi <faryan.rezagholi@siedle.de>
Date:   Fri Aug 20 15:12:03 2021 +0200

    j
2021-08-29 18:41:50 +02:00
Faryan Rezagholi
74af24c3db appveyor test 2021-08-20 13:14:16 +02:00
Faryan Rezagholi
ac1f32f773 setting workdir for 7z 2021-08-20 13:03:22 +02:00
Faryan Rezagholi
99c7dbb332 trying -sfp2 option on 7z for appveyor 2021-08-20 12:17:14 +02:00
Faryan Rezagholi
b0632b8910 trying to fix appveyor no 7z-ing portable release 2021-08-20 00:36:09 +02:00
Faryan Rezagholi
e5042712b6 nuget update 2021-08-19 23:29:13 +02:00
Faryan Rezagholi
0e74314ddc fixed port scan and external tools window not showing 2021-08-15 21:53:10 +02:00
Faryan Rezagholi
54eabd6a74 some property display names were not showing, fixes #1990 2021-08-15 20:53:52 +02:00
Faryan Rezagholi
2f52473566 Allow setting Port when using MSSQL, fixes #1884 2021-08-15 20:13:59 +02:00
Faryan Rezagholi
98e7250b3c trying to fix 7z creating archives wrong on appveyor 2021-08-15 19:51:25 +02:00
Faryan Rezagholi
882438f5e0 replaced logo in readme 2021-08-15 19:16:17 +02:00
Faryan Rezagholi
59b9f4f15b moved resharper logo 2021-08-15 02:17:40 +02:00
Faryan Rezagholi
7ff0ce5369 tring to fix 7z duplicate file error on appveyor builds 2021-08-15 00:41:59 +02:00
Faryan Rezagholi
93bd278819 removed assembly bindings 2021-08-14 18:30:49 +02:00
Faryan Rezagholi
b97b1f3690 added sigcheck back 2021-08-14 18:24:36 +02:00
Faryan Rezagholi
307f374be1 fixed renaming of installer not working 2021-08-14 18:17:17 +02:00
Faryan Rezagholi
17f701824e encore un test 2021-08-14 17:05:21 +02:00
Faryan Rezagholi
c7b89dcf71 another test 2021-08-14 16:57:42 +02:00
Faryan Rezagholi
fc527a947f appveyor build script fixes 2021-08-14 16:49:23 +02:00
Faryan Rezagholi
d0520690a2 appveyor build script fixes 2021-08-14 16:45:06 +02:00
Faryan Rezagholi
315d020b6f appveyor build script fixes 2021-08-14 13:55:42 +02:00
Faryan Rezagholi
8a4bcdef52 appveyor build script fixes 2021-08-14 13:48:38 +02:00
Faryan Rezagholi
727ef34c6d appveyor build script fixes 2021-08-14 13:46:43 +02:00
Faryan Rezagholi
d8bc06d05d ? 2021-08-14 13:41:09 +02:00
Faryan Rezagholi
def214dde2 maybe this time 2021-08-14 13:39:10 +02:00
Faryan Rezagholi
219f948c4a again... 2021-08-14 13:35:13 +02:00
Faryan Rezagholi
72193eccf0 appveyor fix 2021-08-14 13:30:54 +02:00
Faryan Rezagholi
7eb85c6a3d trying to fix appveyor not zipping 2021-08-14 13:26:35 +02:00
Faryan Rezagholi
954c667173 cleanup 2021-08-14 13:16:09 +02:00
Faryan Rezagholi
33c738df5f unified/simplified/accelerated zip file creation 2021-08-14 13:07:14 +02:00
Faryan Rezagholi
2141fe298f let appveyor use project scripts 2021-08-14 12:15:13 +02:00
Faryan Rezagholi
8e73f512b4 moved puttyng.exe to project root 2021-08-14 01:55:51 +02:00
Faryan Rezagholi
92dddb8fd8 removed unused scripts 2021-08-13 02:20:34 +02:00
Faryan Rezagholi
e9869f4c88 cleaned up resource structure 2021-08-13 02:06:21 +02:00
Faryan Rezagholi
52597d4dcb removed 7zip binarys from project 2021-08-13 01:44:26 +02:00
Faryan Rezagholi
dc7ce27b81 fixed designer error 2021-08-13 01:17:27 +02:00
Faryan Rezagholi
4242595a66 Merge branch 'develop' of https://github.com/mRemoteNG/mRemoteNG into develop 2021-08-13 01:12:45 +02:00
Faryan Rezagholi
50b9a11503 change searchbar placement default property 2021-08-13 01:12:20 +02:00
Faryan Rezagholi
621a723602 Merge pull request #2022 from mRemoteNG/webview2
Replace CefSharp with Webview2
2021-08-12 23:46:04 +02:00
Faryan Rezagholi
6260cc3655 fixed tests 2021-08-12 23:35:19 +02:00
Faryan Rezagholi
300e668327 updated wix file fragments 2021-08-12 23:26:18 +02:00
Faryan Rezagholi
3cf274c37a updated changelog 2021-08-12 23:11:55 +02:00
Faryan Rezagholi
2ca356ee5c removed CefSharp from credits 2021-08-12 22:55:40 +02:00
Faryan Rezagholi
ca8751c40c little code cleanup 2021-08-12 22:54:20 +02:00
Faryan Rezagholi
3c7e97d2d9 replaced CefSharp with WebView2 2021-08-12 22:46:07 +02:00
Faryan Rezagholi
dbe2d690da removed majority of cefsharp related code 2021-08-12 21:00:26 +02:00
Faryan Rezagholi
949410e2cc unified release channel names across program 2021-08-11 03:21:16 +02:00
Faryan Rezagholi
100f856b5f cleaned up view menu and made all properties saveable 2021-08-11 03:08:20 +02:00
Faryan Rezagholi
d7bee01454 removed orphaned templates dir 2021-08-10 01:17:15 +02:00
Faryan Rezagholi
5566081986 update nuget packages 2021-08-10 00:59:27 +02:00
Faryan Rezagholi
29f7dd93f3 optimized form closing event 2021-08-10 00:56:14 +02:00
Faryan Rezagholi
3dd8db5728 updated icons in connection tree 2021-08-08 22:30:55 +02:00
Dimitrij
17e70d11f5 Merge pull request #2016 from xjoker/develop
Cannot connect to the database when the password has special characters
2021-08-06 14:59:15 +01:00
wuwenjing
f8afd439b2 When the password contains special characters, it will be unable to connect to the database. Using "SqlConnectionStringBuilder" to construct "ConnectionString" can solve the problem 2021-08-06 16:35:01 +08:00
Faryan Rezagholi
0dc61b1c26 Merge pull request #2014 from mRemoteNG/revised_icons
Revised icons
2021-08-04 02:39:03 +02:00
Faryan Rezagholi
de6c4fcb17 updated readme 2021-08-04 02:18:53 +02:00
Faryan Rezagholi
57f5c854ff moved logo 2021-08-04 02:13:17 +02:00
Faryan Rezagholi
4f4523ab77 removed old form icons 2021-08-04 02:11:29 +02:00
Faryan Rezagholi
e34e632519 removed ICOs from project 2021-08-04 01:49:06 +02:00
Faryan Rezagholi
f810b902a6 added image converter class to get ico from resources (get rid of redundant image resources) 2021-08-04 01:48:08 +02:00
Faryan Rezagholi
fd5bdc1484 replaced remaining icons 2021-08-04 01:11:34 +02:00
Faryan Rezagholi
e3a12ae6c5 you guessed it... ICONS! 2021-08-04 00:51:54 +02:00
Faryan Rezagholi
c9c5664ec6 icons icons icons 2021-08-04 00:39:33 +02:00
Faryan Rezagholi
75cff549ce more icons changed 2021-08-03 23:53:08 +02:00
Faryan Rezagholi
885cb6915d Merge branch 'develop' into revised_icons 2021-08-03 23:13:27 +02:00
Faryan Rezagholi
f9396a4ecf moved photoshop image templates out of project folder 2021-08-03 22:43:57 +02:00
Faryan Rezagholi
f1a03329e5 removed ultravnc icon 2021-08-03 22:38:15 +02:00
Faryan Rezagholi
f65be671a3 moved icons that will stay the same 2021-08-03 22:36:34 +02:00
Faryan Rezagholi
fa9e8f6cba merged develop 2021-08-03 22:27:51 +02:00
Faryan Rezagholi
67a3e76cfe removed icons that are obsolete since #2011 and #2013 2021-08-03 22:16:53 +02:00
Faryan Rezagholi
e4569c0bb8 Merge pull request #2013 from mRemoteNG/remove_components_check
Remove components check
2021-08-03 22:11:10 +02:00
Faryan Rezagholi
6f1a62e917 Merge branch 'develop' into remove_components_check 2021-08-03 21:57:06 +02:00
Faryan Rezagholi
3f6e21f15a Merge pull request #2011 from mRemoteNG/remove_screenshot_manager
removed screenshot manager
2021-08-03 21:54:52 +02:00
Faryan Rezagholi
46c4287c67 updated changelog 2021-08-03 21:51:09 +02:00
Faryan Rezagholi
1ea1826a27 removed leftovers from components check 2021-08-03 21:46:00 +02:00
Faryan Rezagholi
151457daf0 removed components check options page 2021-08-03 21:39:07 +02:00
Faryan Rezagholi
38cc21fa3a first wave of icons changed 2021-08-03 21:36:03 +02:00
Faryan Rezagholi
77f759f258 more icons cleaned up 2021-08-03 18:50:47 +02:00
Faryan Rezagholi
07c04061c2 more unused icons removed 2021-08-03 01:30:06 +02:00
Faryan Rezagholi
d4bf6ed0c8 added icons that were no part of the resource file 2021-08-03 01:21:11 +02:00
Faryan Rezagholi
ebd46efe81 Merge branch 'develop' into remove_screenshot_manager 2021-08-03 01:11:28 +02:00
Faryan Rezagholi
24d193efb0 revised host status icons 2021-08-03 00:59:59 +02:00
Faryan Rezagholi
3b2a63178f removed unused images/duplicate resources 2021-08-03 00:52:28 +02:00
Faryan Rezagholi
78f60afb85 Removed famfamfam folder and obsolete icons from images folder 2021-08-03 00:49:11 +02:00
Faryan Rezagholi
52a7957789 Update README.MD
Embedded new logo
2021-08-02 12:56:04 +02:00
Faryan Rezagholi
6870583b1c new logo 2021-08-02 12:50:00 +02:00
Faryan Rezagholi
9ffe514350 fixed error from previous merge 2021-08-02 00:29:15 +02:00
Faryan Rezagholi
fc6e04497a updated changelog 2021-08-02 00:16:14 +02:00
Faryan Rezagholi
cfb3f9a3ca merged from develop 2021-08-02 00:13:33 +02:00
Faryan Rezagholi
d47fac791e removed unused language strings 2021-08-02 00:05:10 +02:00
Faryan Rezagholi
490b70c2d3 removed cef scheme handler for obsolete in-app documentation 2021-08-02 00:01:48 +02:00
Faryan Rezagholi
3eecdd9ada Merge pull request #2010 from mRemoteNG/redesign_menus
Redesigned Menus
2021-08-01 23:51:22 +02:00
Faryan Rezagholi
7bdbc5417c update changelog 2021-08-01 23:28:32 +02:00
Faryan Rezagholi
2cd07dcb72 Merge branch 'develop' into redesign_menus 2021-08-01 23:01:53 +02:00
Faryan Rezagholi
adb83ade67 Merge pull request #2005 from mRemoteNG/remove_in_app_documentation
Remove in-app documentation
2021-08-01 23:00:21 +02:00
Faryan Rezagholi
a90f5da8b0 updated changelog 2021-08-01 22:45:39 +02:00
Faryan Rezagholi
38937a4f83 more rearrangements 2021-08-01 22:43:59 +02:00
Faryan Rezagholi
31f35a23ee removed some icons from file menu 2021-08-01 22:39:16 +02:00
Faryan Rezagholi
74de010d3c cleaned up icons in view menu 2021-08-01 22:32:27 +02:00
Faryan Rezagholi
a9e4c880df redesigned help menu 2021-08-01 22:29:04 +02:00
Faryan Rezagholi
b7fe265604 rearranged view menu 2021-08-01 21:45:15 +02:00
Faryan Rezagholi
25c4af5a9f cleaned up file menu 2021-08-01 21:40:14 +02:00
Faryan Rezagholi
b3ecf702e1 removed developer notice 2021-07-28 21:31:59 +02:00
Faryan Rezagholi
c34a3cc7e7 Added back sphinx documentation files 2021-07-26 01:22:31 +02:00
Faryan Rezagholi
158783f2d1 removed screenshot manager 2021-07-26 01:11:01 +02:00
Faryan Rezagholi
e9be139ed0 removed HelpWindows from code 2021-07-24 19:40:52 +02:00
Faryan Rezagholi
2b9195ed9c fixed typo 2021-07-24 19:38:09 +02:00
Faryan Rezagholi
dfdfecba57 open help in external browsr instead of in-app 2021-07-24 19:37:38 +02:00
Faryan Rezagholi
2d6fec13fb added url to documentation 2021-07-24 19:37:22 +02:00
Faryan Rezagholi
216f340468 removed sphinx documentation files 2021-07-24 19:35:00 +02:00
Faryan Rezagholi
a4211a7e55 removed postbuild sphinx script 2021-07-24 19:34:04 +02:00
David Sparer
4349b1b65b dont save settings on individual settings pages 2019-05-19 16:23:00 -05:00
David Sparer
bb04605dc3 Merge branch 'develop' into reapply_credential_manager
# Conflicts:
#	mRemoteNGTests/Connection/DefaultConnectionInheritanceTests.cs
#	mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableSerializer.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs
#	mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs
#	mRemoteV1/Connection/AbstractConnectionRecord.cs
#	mRemoteV1/Connection/ConnectionInitiator.cs
#	mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs
#	mRemoteV1/Resources/Help/ui_external_tools.htm
#	mRemoteV1/Resources/Language/Language.resx
#	mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs
#	mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.Designer.cs
#	mRemoteV1/UI/Window/ConfigWindow.cs
#	mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs
#	mRemoteV1/mRemoteV1.csproj
2019-05-19 16:19:18 -05:00
David Sparer
294bd2f7a4 fixed event invocator warnings 2019-03-19 20:25:59 -05:00
David Sparer
a3aa323cce updated html documentation for #680 2019-03-19 20:15:16 -05:00
David Sparer
355cd63acb Merge branch 'develop' into reapply_credential_manager 2019-03-19 18:01:37 -05:00
David Sparer
93d50b0818 Merge branch 'develop' into reapply_credential_manager
# Conflicts:
#	mRemoteNGTests/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManager27DeserializerTests.cs
#	mRemoteNGTests/packages.config
#	mRemoteV1/Config/Connections/SqlConnectionsSaver.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs
#	mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs
#	mRemoteV1/Connection/AbstractConnectionRecord.cs
#	mRemoteV1/Connection/ConnectionInfoInheritance.cs
#	mRemoteV1/Connection/ConnectionsService.cs
#	mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs
#	mRemoteV1/Properties/Settings.settings
#	mRemoteV1/Resources/Language/Language.de.resx
#	mRemoteV1/Resources/Language/Language.resx
#	mRemoteV1/Resources/Language/Language.ru.resx
#	mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs
#	mRemoteV1/mRemoteV1.csproj
2019-03-09 13:49:23 -06:00
Faryan Rezagholi
8779776ad5 removed minimize button from credentials manager 2019-02-20 19:45:18 +01:00
Faryan Rezagholi
3bb285d180 removed unused form 2019-02-20 19:42:30 +01:00
Faryan Rezagholi
052796c794 adjusted text box positioning 2019-02-20 19:08:25 +01:00
Faryan Rezagholi
33a6dbb4c3 made more hardcoded strings translateable 2019-02-20 18:32:35 +01:00
Faryan Rezagholi
953ddaa292 merged develop 2019-02-19 22:39:58 +01:00
Faryan Rezagholi
c065b86dbd revised credential manager forms design 2019-02-19 22:38:12 +01:00
David Sparer
95859b96ff Merge branch 'develop' into reapply_credential_manager
# Conflicts:
#	mRemoteV1/App/Export.cs
#	mRemoteV1/App/Initialization/CredsAndConsSetup.cs
#	mRemoteV1/App/Runtime.cs
#	mRemoteV1/Config/Connections/ConnectionsLoadedEventArgs.cs
#	mRemoteV1/Config/Connections/ConnectionsSavedEventArgs.cs
#	mRemoteV1/Config/Connections/CsvConnectionsSaver.cs
#	mRemoteV1/Config/Connections/SaveConnectionsOnEdit.cs
#	mRemoteV1/Config/CredentialHarvester.cs
#	mRemoteV1/Config/CredentialRepositoryListLoader.cs
#	mRemoteV1/Config/CredentialRepositoryListSaver.cs
#	mRemoteV1/Config/DataProviders/FileDataProvider.cs
#	mRemoteV1/Config/Import/MRemoteNGCsvImporter.cs
#	mRemoteV1/Config/Import/MRemoteNGXmlImporter.cs
#	mRemoteV1/Config/Import/RemoteDesktopConnectionImporter.cs
#	mRemoteV1/Config/Putty/PuttySessionsRegistryProvider.cs
#	mRemoteV1/Config/Putty/PuttySessionsXmingProvider.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsDeserializerMremotengFormat.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Csv/CsvConnectionsSerializerMremotengFormat.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableDeserializer.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/MsSql/DataTableSerializer.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionNodeSerializer27.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsSerializer.cs
#	mRemoteV1/Config/Serializers/CredentialProviderSerializer/CredentialRepositoryListDeserializer.cs
#	mRemoteV1/Config/Serializers/MiscSerializers/PuttyConnectionManagerDeserializer.cs
#	mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionDeserializer.cs
#	mRemoteV1/Config/Serializers/MiscSerializers/RemoteDesktopConnectionManagerDeserializer.cs
#	mRemoteV1/Connection/AbstractConnectionRecord.cs
#	mRemoteV1/Connection/ConnectionInfo.cs
#	mRemoteV1/Connection/ConnectionInfoInheritance.cs
#	mRemoteV1/Connection/ConnectionInitiator.cs
#	mRemoteV1/Connection/ConnectionsService.cs
#	mRemoteV1/Connection/DefaultConnectionInfo.cs
#	mRemoteV1/Connection/Protocol/Http/Connection.Protocol.HTTPBase.cs
#	mRemoteV1/Connection/Protocol/ICA/IcaProtocol.cs
#	mRemoteV1/Connection/Protocol/IntegratedProgram.cs
#	mRemoteV1/Connection/Protocol/ProtocolBase.cs
#	mRemoteV1/Connection/Protocol/PuttyBase.cs
#	mRemoteV1/Connection/Protocol/RDP/RdpProtocol.cs
#	mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs
#	mRemoteV1/Connection/PuttySessionInfo.cs
#	mRemoteV1/Credential/CredentialRecordTypeConverter.cs
#	mRemoteV1/Credential/CredentialServiceFacade.cs
#	mRemoteV1/Credential/CredentialServiceFactory.cs
#	mRemoteV1/Credential/Records/UnavailableCredentialRecord.cs
#	mRemoteV1/Credential/Repositories/XmlCredentialRepository.cs
#	mRemoteV1/Credential/Repositories/XmlCredentialRepositoryFactory.cs
#	mRemoteV1/Properties/Settings.settings
#	mRemoteV1/Schemas/mremoteng_confcons_v2_7.xsd
#	mRemoteV1/Tools/CustomCollections/FullyObservableCollection.cs
#	mRemoteV1/Tools/Extensions.cs
#	mRemoteV1/Tools/ExternalTool.cs
#	mRemoteV1/Tools/ExternalToolArgumentParser.cs
#	mRemoteV1/UI/Controls/Base/NGComboBox.cs
#	mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs
#	mRemoteV1/UI/Controls/CredentialRecordListBox.cs
#	mRemoteV1/UI/Controls/QuickConnectToolStrip.cs
#	mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.cs
#	mRemoteV1/UI/Forms/OptionsPages/SqlServerPage.cs
#	mRemoteV1/UI/Forms/frmMain.cs
#	mRemoteV1/UI/Forms/frmOptions.cs
#	mRemoteV1/UI/Menu/ToolsMenu.cs
#	mRemoteV1/UI/Window/ConfigWindow.cs
#	mRemoteV1/UI/Window/ConnectionTreeWindow.Designer.cs
#	mRemoteV1/UI/Window/ConnectionTreeWindow.cs
#	mRemoteV1/UI/Window/ConnectionWindow.cs
#	mRemoteV1/app.config
2019-02-17 11:21:22 -06:00
David Sparer
ba62c17ea2 added some interface documentation 2019-01-27 18:01:34 -06:00
David Sparer
1f296f2f72 slight fix to the optional<T> tests 2019-01-27 16:59:02 -06:00
David Sparer
89bb4d45b3 minor tweaks to the import form 2019-01-27 16:58:39 -06:00
David Sparer
6e417ed47e ensure specified creds can be parsed even if no connectioninfo is selected 2019-01-27 12:33:14 -06:00
David Sparer
f3a7d97016 allow specifying specific credential record in external tool arguments
related to #680
2019-01-27 11:31:41 -06:00
David Sparer
530a4e165d extracted interface from credential service to make testing easier 2019-01-27 09:58:28 -06:00
David Sparer
9e217dba79 began creating cred import form 2019-01-23 22:16:08 -06:00
David Sparer
d524df6315 minor efficiency gain 2019-01-22 13:04:58 -06:00
David Sparer
5e224f5b5b ensure assigned cred id property cannot be null 2019-01-22 12:51:41 -06:00
David Sparer
3649927618 fixed bug with connection tree not appearing 2019-01-22 12:48:12 -06:00
David Sparer
4b736176bf request iconnectiontree interface in more places 2019-01-22 06:01:33 -06:00
David Sparer
f78ca1e9fd some more deserialization refactoring 2019-01-21 17:52:18 -06:00
David Sparer
739112a3ff added tests for SaveConnectionsOnEdit
had to create some new interfaces and refactor a bit to make it testable
2019-01-20 15:45:09 -06:00
David Sparer
923b9efd40 began converting the database serializers to work with cred manager 2019-01-20 14:51:09 -06:00
David Sparer
f0d0b5ae21 reduced duplication in rdcm tests 2019-01-20 13:46:34 -06:00
David Sparer
8906e08704 made the rdcm 2.7 importer compatible with credential management 2019-01-20 12:38:39 -06:00
David Sparer
9ead7e8e16 fixed an issue with putty session importing
cred id was not being set. also added a test for it
2019-01-20 11:18:40 -06:00
David Sparer
788ca79ece fixed rdp file importer to support cred manager 2019-01-20 11:15:33 -06:00
David Sparer
88558a353c fixed putty connection manager credential serialization 2019-01-19 14:22:04 -06:00
David Sparer
7fd9abbbc8 resolved csv deserializer test 2019-01-19 13:19:06 -06:00
David Sparer
b029b35df7 Merge remote-tracking branch 'origin/develop' into reapply_credential_manager
# Conflicts:
#	mRemoteV1/Properties/Settings.Designer.cs
#	mRemoteV1/Properties/Settings.settings
#	mRemoteV1/app.config
2019-01-19 12:51:43 -06:00
David Sparer
187ca5e55b started to redo how cred harvesting works in order to apply it to all importers/deserializers 2019-01-14 16:32:51 -06:00
David Sparer
53c26d8a91 updated tests and references to using cred records rather than user/domain/pass of the connection 2019-01-14 14:02:41 -06:00
David Sparer
159f25b8a1 fixed exttools arg parser tests 2019-01-14 09:54:19 -06:00
David Sparer
f4904f350e minor cleanup 2019-01-14 07:59:09 -06:00
David Sparer
ea59f6ad9d centralized credential lookup logic 2019-01-14 07:56:31 -06:00
David Sparer
4bba05f737 minor cleanup of cred harvester, slightly more efficient 2019-01-14 07:35:37 -06:00
David Sparer
569cf38f24 fixed a cred harvester test 2019-01-14 07:35:13 -06:00
David Sparer
6f8cde4d8e added a method comment 2019-01-13 14:45:07 -06:00
David Sparer
753ea9b421 connections now correctly use default cred if no credential is supplied 2019-01-13 14:42:24 -06:00
David Sparer
a5ea867b6d began hooking up the default credential to the manager 2019-01-13 12:14:28 -06:00
David Sparer
80228966f9 double clicking cred repo tree item opens editor page 2019-01-13 11:27:42 -06:00
David Sparer
b8298ecb14 minor display changes of the repo manager 2019-01-13 11:19:03 -06:00
David Sparer
ee1db6ff8b refactored some methods/fields to be more descriptive 2019-01-13 11:07:58 -06:00
David Sparer
aab1fb1dd2 minor cleanup 2019-01-13 11:05:45 -06:00
David Sparer
fbea9d1ede hooked up remaining cred repo management buttons 2019-01-13 10:57:33 -06:00
David Sparer
75cfc9c75c Merge branch 'develop' into reapply_credential_manager
# Conflicts:
#	mRemoteV1/Properties/Settings.Designer.cs
#	mRemoteV1/Properties/Settings.settings
#	mRemoteV1/UI/Forms/frmMain.cs
#	mRemoteV1/app.config
2019-01-13 08:52:51 -06:00
David Sparer
f60a481902 Merge branch 'develop' into reapply_credential_manager 2019-01-09 10:27:26 -06:00
David Sparer
e89c77a1bc fixed mis-merge 2019-01-09 10:26:40 -06:00
David Sparer
45766b8c12 Merge branch 'develop' into reapply_credential_manager
# Conflicts:
#	mRemoteV1/UI/Forms/OptionsPages/CredentialsPage.Designer.cs
2019-01-09 07:32:09 -06:00
David Sparer
1c44fcb070 Merge branch 'develop' into reapply_credential_manager
# Conflicts:
#	mRemoteV1/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs
#	mRemoteV1/UI/Controls/Base/NGComboBox.cs
#	mRemoteV1/UI/Controls/NewPasswordWithVerification.Designer.cs
#	mRemoteV1/mRemoteV1.csproj
2019-01-05 07:48:43 -06:00
David Sparer
25aa815a82 began reworking the repo list management screen 2018-12-31 14:17:31 -06:00
David Sparer
a2542f1b18 rearranged some cred manager UI files 2018-12-31 11:13:48 -06:00
David Sparer
2e0979dc5a simplified screens for creating and editing creds 2018-12-31 11:05:36 -06:00
David Sparer
e2ebf25b7b Merge branch 'develop' into reapply_credential_manager 2018-12-31 09:32:47 -06:00
David Sparer
cc44b830a2 scaled images in the unlocker form 2018-12-30 15:28:47 -06:00
David Sparer
687cb6c7bc cred unlocker wont appear if there are no repos to unlock 2018-12-30 14:42:37 -06:00
David Sparer
15f028157e inserted a new page in the upgrade process to view harvested credentials 2018-12-30 14:33:42 -06:00
David Sparer
63ebef56b0 updated cred manager upgrade text with correct version 2018-12-30 11:32:24 -06:00
David Sparer
258093e52a when harvesting creds, consider Password when determining if a credential set is a duplicate
This prevents issues when the username and domain are the same but passwords are different (such as for local admin accounts)
2018-12-28 16:25:33 -06:00
David Sparer
b09fdcd5f5 credential objects now used when establishing connections 2018-12-28 16:25:33 -06:00
David Sparer
2277e95dd2 fixed tests 2018-12-28 16:25:33 -06:00
David Sparer
e0486bec7d simplified some of the credential management classes 2018-12-28 16:25:33 -06:00
David Sparer
29d44d103d fixed bug preventing FullyObservableCollection from generating events 2018-12-28 16:25:32 -06:00
David Sparer
44aa100566 minor change to chkbox location 2018-12-28 16:25:32 -06:00
David Sparer
23eb9cc44b added option to auto close the cred unlocker form when all repos are unlocked 2018-12-28 16:25:32 -06:00
David Sparer
f1797282d9 readded option to unlock cred repos on startup 2018-12-28 16:25:32 -06:00
David Sparer
0c0740d488 cred upgrade form now only lets you upgrade if all required fields are filled in 2018-12-28 16:25:32 -06:00
David Sparer
a4faaa20c3 cred manager upgrader now correctly uses custom password provided during upgrade 2018-12-28 16:25:29 -06:00
David Sparer
ce03b74d48 serialization is now working as expected 2018-12-28 16:25:29 -06:00
David Sparer
ce8ada05f5 hooked up the credential manager upgrader 2018-12-28 16:25:29 -06:00
David Sparer
b4dfe5beb6 hooked up tools menu button for cred manager 2018-12-28 16:25:29 -06:00
David Sparer
22ecf0d06f readded forms and controls for the credential manager 2018-12-28 16:25:29 -06:00
David Sparer
1e66787422 readded the credential record property to the connection info class 2018-12-28 16:25:28 -06:00
745 changed files with 18989 additions and 12455 deletions

14
.readthedocs.yaml Normal file
View File

@@ -0,0 +1,14 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: mRemoteNGDocumentation/conf.py
# Optionally build your docs in additional formats such as PDF
formats:
- pdf

View File

@@ -14,12 +14,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- #283: Support for native PowerShell remoting as new protocol
- #1850: Minify config xml
### Changed
- #2022: Replaced CefSharp with WebView2
- #2014: Revised icons
- #2013: Removed components check
- #2011: Removed screenshot manager
- #2010: Redesigned menus
- #2005: Removed in-app documentation
- #1777: Cleaned up VisualStudio project structure
- #1767: Turned about window into a simple popup form
- #1766: Converted components check page into options page
- #1690: Replaced GeckoFX (Firefox) with CefSharp (Chromium)
- #1325: Language resource files cleanup
### Fixed
- #1884: Allow setting Port when using MSSQL
- #1783: Added missing inheritance properties to SQL scripts
- #1773: Connection issue with mysql - Missing fields in
- #1756: Cannot type any character on MultiSSH toolbar

View File

@@ -90,10 +90,6 @@ Copyright © 2004 Marc Merritt © 2008 Felix Deimel
# Included Components
**[CefSharp](https://github.com/cefsharp/CefSharp)**
Copyright © The CefSharp Authors
MIT License
**[DockPanel Suite](https://github.com/dockpanelsuite/dockpanelsuite)**
Copyright © 2018 @roken and @lextm (formerly Weifen Luo)
MIT License

View File

@@ -2,7 +2,7 @@
<br/><br/>
<p align="center">
<img width="500" src="https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/Tools/img/logo.png">
<img width="500" src="https://github.com/mRemoteNG/mRemoteNG/blob/develop/mRemoteNGProjectFiles/Header_dark.png">
</p>
<p align="center">
@@ -177,5 +177,5 @@ Check out the [Wiki page](https://github.com/mRemoteNG/mRemoteNG/wiki) on how to
</br>
<p align="center">
<img alt="Developed with ReSharper" src="https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/Tools/img/icon_ReSharper.png">
<img alt="Developed with ReSharper" src="https://github.com/mRemoteNG/mRemoteNG/blob/develop/mRemoteNGProjectFiles/icon_ReSharper.png">
</p>

View File

@@ -1,331 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
//
// Hotkey selection control, written by serenity@exscape.org, 2006-08-03
// Please mail me if you find a bug.
//
namespace SharedLibraryNG
{
/// <summary>
/// A simple control that allows the user to select pretty much any valid hotkey combination
/// </summary>
public class HotkeyControl : TextBox
{
private const string KeySeparator = " + ";
// These variables store the current hotkey and modifier(s)
private Keys _keyCode = Keys.None;
private Keys _modifiers = Keys.None;
// ArrayLists used to enforce the use of proper modifiers.
// Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing.
private readonly ArrayList _needNonShiftModifier;
private readonly ArrayList _needNonAltGrModifier;
private readonly ContextMenu _emptyContextMenu = new ContextMenu();
/// <summary>
/// Used to make sure that there is no right-click menu available
/// </summary>
public override ContextMenu ContextMenu
{
get
{
return _emptyContextMenu;
}
// ReSharper disable once ValueParameterNotUsed
set
{
base.ContextMenu = _emptyContextMenu;
}
}
/// <summary>
/// Forces the control to be non-multiline
/// </summary>
public override bool Multiline
{
get
{
return base.Multiline;
}
// ReSharper disable once ValueParameterNotUsed
set
{
// Ignore what the user wants; force Multiline to false
base.Multiline = false;
}
}
/// <summary>
/// Creates a new HotkeyControl
/// </summary>
public HotkeyControl()
{
// Handle events that occurs when keys are pressed
KeyUp += HotkeyControl_KeyUp;
// Fill the ArrayLists that contain all invalid hotkey combinations
_needNonShiftModifier = new ArrayList();
_needNonAltGrModifier = new ArrayList();
PopulateModifierLists();
}
protected override void OnCreateControl()
{
base.OnCreateControl();
ContextMenu = _emptyContextMenu; // Disable right-clicking
Multiline = false;
Text = "None";
}
/// <summary>
/// Populates the ArrayLists specifying disallowed hotkeys
/// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc
/// </summary>
private void PopulateModifierLists()
{
// Shift + 0 - 9, A - Z
for (var k = Keys.D0; k <= Keys.Z; k++)
_needNonShiftModifier.Add((int)k);
// Shift + Numpad keys
for (var k = Keys.NumPad0; k <= Keys.NumPad9; k++)
_needNonShiftModifier.Add((int)k);
// Shift + Misc (,;<./ etc)
for (var k = Keys.Oem1; k <= Keys.OemBackslash; k++)
_needNonShiftModifier.Add((int)k);
// Misc keys that we can't loop through
_needNonShiftModifier.Add((int)Keys.Insert);
_needNonShiftModifier.Add((int)Keys.Help);
_needNonShiftModifier.Add((int)Keys.Multiply);
_needNonShiftModifier.Add((int)Keys.Add);
_needNonShiftModifier.Add((int)Keys.Subtract);
_needNonShiftModifier.Add((int)Keys.Divide);
_needNonShiftModifier.Add((int)Keys.Decimal);
_needNonShiftModifier.Add((int)Keys.Return);
_needNonShiftModifier.Add((int)Keys.Escape);
_needNonShiftModifier.Add((int)Keys.NumLock);
_needNonShiftModifier.Add((int)Keys.Scroll);
_needNonShiftModifier.Add((int)Keys.Pause);
// Ctrl+Alt + 0 - 9
for (var k = Keys.D0; k <= Keys.D9; k++)
_needNonAltGrModifier.Add((int)k);
}
/// <summary>
/// Fires when all keys are released. If the current hotkey isn't valid, reset it.
/// Otherwise, do nothing and keep the text and hotkey as it was.
/// </summary>
void HotkeyControl_KeyUp(object sender, KeyEventArgs e)
{
if (_keyCode == Keys.None && ModifierKeys == Keys.None) ResetHotkey();
}
/// <summary>
/// Handles some misc keys, such as Ctrl+Delete and Shift+Insert
/// </summary>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
var keyCode = keyData & Keys.KeyCode;
var modifiers = keyData & Keys.Modifiers;
if (keyData == Keys.Back || keyData == Keys.Delete)
{
ResetHotkey();
return true;
}
_keyCode = keyCode;
_modifiers = modifiers;
Redraw();
return true;
}
/// <summary>
/// Clears the current hotkey and resets the TextBox
/// </summary>
public void ResetHotkey()
{
_keyCode = Keys.None;
_modifiers = Keys.None;
Text = "None";
}
/// <summary>
/// Used to get/set the hotkey (e.g. Keys.A)
/// </summary>
public Keys KeyCode
{
get
{
return _keyCode;
}
set
{
_keyCode = value;
Redraw(false);
}
}
/// <summary>
/// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control)
/// </summary>
public Keys HotkeyModifiers
{
get
{
return _modifiers;
}
set
{
_modifiers = value;
Redraw(false);
}
}
/// <summary>
/// Redraws the TextBox when necessary.
/// </summary>
/// <param name="validate">Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user.</param>
private void Redraw(bool validate = true)
{
// Only validate input if it comes from the user
if (validate)
{
// No modifier or shift only, AND a hotkey that needs another modifier
if ((_modifiers == Keys.Shift || _modifiers == Keys.None) &&
_needNonShiftModifier.Contains((int) _keyCode))
{
if (_modifiers == Keys.None)
{
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work...
if (_needNonAltGrModifier.Contains((int) _keyCode) == false)
_modifiers = Keys.Alt | Keys.Control;
else // ... in that case, use Shift+Alt instead.
_modifiers = Keys.Alt | Keys.Shift;
}
else
{
// User pressed Shift and an invalid key (e.g. a letter or a number),
// that needs another set of modifier keys
_keyCode = Keys.None;
Text = _modifiers + " + Invalid Key";
return;
}
}
// Check all Ctrl+Alt keys
if ((_modifiers == (Keys.Alt | Keys.Control)) &&
_needNonAltGrModifier.Contains((int) _keyCode))
{
// Ctrl+Alt+4 etc won't work; reset hotkey and tell the user
_keyCode = Keys.None;
Text = _modifiers + " + Invalid Key";
return;
}
}
// Don't allow modifiers keys for _keyCode
if (_keyCode == Keys.ShiftKey ||
_keyCode == Keys.LShiftKey ||
_keyCode == Keys.RShiftKey ||
_keyCode == Keys.ControlKey ||
_keyCode == Keys.LControlKey ||
_keyCode == Keys.RControlKey ||
_keyCode == Keys.Menu ||
_keyCode == Keys.LMenu ||
_keyCode == Keys.RMenu ||
_keyCode == Keys.LWin ||
_keyCode == Keys.RWin)
_keyCode = Keys.None;
if (_modifiers == Keys.None)
{
if (_keyCode == Keys.None)
{
ResetHotkey();
return;
}
// We get here if we've got a hotkey that is valid without a modifier,
// like F1-F12, Media-keys etc.
Text = _keyCode.ToString();
return;
}
Text = string.Join(KeySeparator, new[] { KeysToString(_modifiers), KeysToString(_keyCode) });
}
public static string KeysToString(Keys keys)
{
if (keys == Keys.None) return "None";
var modifiers = (keys & Keys.Modifiers);
var keyCode = (keys & Keys.KeyCode);
var strings = new List<string>();
if (modifiers != 0)
{
var modifierStrings = new List<string>(modifiers.ToString().Replace(", ", ",").Split(','));
modifierStrings.Sort(new KeyModifierComparer());
strings.AddRange(modifierStrings);
}
if (keyCode != 0)
{
var keyString = keyCode.ToString();
var keyHashtable = new Dictionary<string, string>
{
{"Next", "PageDown"},
{"Oemcomma", ","},
{"OemMinus", "-"},
{"OemOpenBrackets", "["},
{"OemPeriod", "."},
{"Oemplus", "="},
{"OemQuestion", "/"},
{"Oemtilde", "`"},
{"D0", "0"},
{"D1", "1"},
{"D2", "2"},
{"D3", "3"},
{"D4", "4"},
{"D5", "5"},
{"D6", "6"},
{"D7", "7"},
{"D8", "8"},
{"D9", "9"},
};
if (keyHashtable.ContainsKey(keyString)) keyString = keyHashtable[keyString];
strings.Add(keyString);
}
return string.Join(KeySeparator, strings.ToArray());
}
private class KeyModifierComparer : IComparer<string>
{
private static readonly List<string> ModifierOrder = new List<string>
{
"control",
"alt",
"shift",
};
public int Compare(string x, string y)
{
var xIndex = ModifierOrder.IndexOf(x.ToLowerInvariant());
var yIndex = ModifierOrder.IndexOf(y.ToLowerInvariant());
return xIndex - yIndex;
}
}
}
}

View File

@@ -1,258 +0,0 @@
//
// Based on code from Stephen Toub's MSDN blog at
// http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
//
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace SharedLibraryNG
{
public class KeyboardHook
{
// ReSharper disable InconsistentNaming
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PostMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, HookKeyMsgData lParam);
// ReSharper restore InconsistentNaming
[Flags]
public enum ModifierKeys
{
None = 0x0000,
Shift = 0x0001,
LeftShift = 0x002,
RightShift = 0x004,
Control = 0x0008,
LeftControl = 0x010,
RightControl = 0x20,
Alt = 0x0040,
LeftAlt = 0x0080,
RightAlt = 0x0100,
Win = 0x0200,
LeftWin = 0x0400,
RightWin = 0x0800,
}
protected class KeyNotificationEntry
: IEquatable<KeyNotificationEntry>
{
public IntPtr WindowHandle;
public Int32 KeyCode;
public ModifierKeys ModifierKeys;
public Boolean Block;
public bool Equals(KeyNotificationEntry obj)
{
return (WindowHandle == obj.WindowHandle &&
KeyCode == obj.KeyCode &&
ModifierKeys == obj.ModifierKeys &&
Block == obj.Block);
}
}
public const string HookKeyMsgName = "HOOKKEYMSG-{56BE0940-34DA-11E1-B308-C6714824019B}";
private static Int32 _hookKeyMsg;
public static Int32 HookKeyMsg
{
get
{
if (_hookKeyMsg == 0)
{
_hookKeyMsg = Win32.RegisterWindowMessage(HookKeyMsgName).ToInt32();
if (_hookKeyMsg == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return _hookKeyMsg;
}
}
// this is a custom structure that will be passed to
// the requested hWnd via a WM_APP_HOOKKEYMSG message
[StructLayout(LayoutKind.Sequential)]
public class HookKeyMsgData
{
public Int32 KeyCode;
public ModifierKeys ModifierKeys;
public Boolean WasBlocked;
}
private static int _referenceCount;
private static IntPtr _hook;
private static readonly Win32.LowLevelKeyboardProcDelegate LowLevelKeyboardProcStaticDelegate = LowLevelKeyboardProc;
private static readonly List<KeyNotificationEntry> NotificationEntries = new List<KeyNotificationEntry>();
public KeyboardHook()
{
_referenceCount++;
SetHook();
}
~KeyboardHook()
{
_referenceCount--;
if (_referenceCount < 1) UnsetHook();
}
private static void SetHook()
{
if (_hook != IntPtr.Zero) return;
var curProcess = Process.GetCurrentProcess();
var curModule = curProcess.MainModule;
var hook = Win32.SetWindowsHookEx(Win32.WH_KEYBOARD_LL, LowLevelKeyboardProcStaticDelegate, Win32.GetModuleHandle(curModule.ModuleName), 0);
if (hook == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
_hook = hook;
}
private static void UnsetHook()
{
if (_hook == IntPtr.Zero) return;
Win32.UnhookWindowsHookEx(_hook);
_hook = IntPtr.Zero;
}
private static IntPtr LowLevelKeyboardProc(Int32 nCode, IntPtr wParam, Win32.KBDLLHOOKSTRUCT lParam)
{
var wParamInt = wParam.ToInt32();
var result = 0;
if (nCode == Win32.HC_ACTION)
{
switch (wParamInt)
{
case Win32.WM_KEYDOWN:
case Win32.WM_SYSKEYDOWN:
case Win32.WM_KEYUP:
case Win32.WM_SYSKEYUP:
result = OnKey(wParamInt, lParam);
break;
}
}
if (result != 0) return new IntPtr(result);
return Win32.CallNextHookEx(_hook, nCode, wParam, lParam);
}
private static int OnKey(Int32 msg, Win32.KBDLLHOOKSTRUCT key)
{
var result = 0;
foreach (var notificationEntry in NotificationEntries)
if (GetFocusWindow() == notificationEntry.WindowHandle && notificationEntry.KeyCode == key.vkCode)
{
var modifierKeys = GetModifierKeyState();
if (!ModifierKeysMatch(notificationEntry.ModifierKeys, modifierKeys)) continue;
var wParam = new IntPtr(msg);
var lParam = new HookKeyMsgData
{
KeyCode = key.vkCode,
ModifierKeys = modifierKeys,
WasBlocked = notificationEntry.Block,
};
if (!PostMessage(notificationEntry.WindowHandle, HookKeyMsg, wParam, lParam))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (notificationEntry.Block) result = 1;
}
return result;
}
private static IntPtr GetFocusWindow()
{
var guiThreadInfo = new Win32.GUITHREADINFO();
if (!Win32.GetGUIThreadInfo(0, guiThreadInfo))
throw new Win32Exception(Marshal.GetLastWin32Error());
return Win32.GetAncestor(guiThreadInfo.hwndFocus, Win32.GA_ROOT);
}
protected static Dictionary<Int32, ModifierKeys> ModifierKeyTable = new Dictionary<Int32, ModifierKeys>
{
{ Win32.VK_SHIFT, ModifierKeys.Shift },
{ Win32.VK_LSHIFT, ModifierKeys.LeftShift },
{ Win32.VK_RSHIFT, ModifierKeys.RightShift },
{ Win32.VK_CONTROL, ModifierKeys.Control },
{ Win32.VK_LCONTROL, ModifierKeys.LeftControl },
{ Win32.VK_RCONTROL, ModifierKeys.RightControl },
{ Win32.VK_MENU, ModifierKeys.Alt },
{ Win32.VK_LMENU, ModifierKeys.LeftAlt },
{ Win32.VK_RMENU, ModifierKeys.RightAlt },
{ Win32.VK_LWIN, ModifierKeys.LeftWin },
{ Win32.VK_RWIN, ModifierKeys.RightWin },
};
public static ModifierKeys GetModifierKeyState()
{
var modifierKeyState = ModifierKeys.None;
foreach (KeyValuePair<Int32, ModifierKeys> pair in ModifierKeyTable)
{
if ((Win32.GetAsyncKeyState(pair.Key) & Win32.KEYSTATE_PRESSED) != 0) modifierKeyState |= pair.Value;
}
if ((modifierKeyState & ModifierKeys.LeftWin) != 0) modifierKeyState |= ModifierKeys.Win;
if ((modifierKeyState & ModifierKeys.RightWin) != 0) modifierKeyState |= ModifierKeys.Win;
return modifierKeyState;
}
public static Boolean ModifierKeysMatch(ModifierKeys requestedKeys, ModifierKeys pressedKeys)
{
if ((requestedKeys & ModifierKeys.Shift) != 0) pressedKeys &= ~(ModifierKeys.LeftShift | ModifierKeys.RightShift);
if ((requestedKeys & ModifierKeys.Control) != 0) pressedKeys &= ~(ModifierKeys.LeftControl | ModifierKeys.RightControl);
if ((requestedKeys & ModifierKeys.Alt) != 0) pressedKeys &= ~(ModifierKeys.LeftAlt | ModifierKeys.RightAlt);
if ((requestedKeys & ModifierKeys.Win) != 0) pressedKeys &= ~(ModifierKeys.LeftWin | ModifierKeys.RightWin);
return requestedKeys == pressedKeys;
}
public static void RequestKeyNotification(IntPtr windowHandle, Int32 keyCode, Boolean block)
{
RequestKeyNotification(windowHandle, keyCode, ModifierKeys.None, block);
}
public static void RequestKeyNotification(IntPtr windowHandle, Int32 keyCode, ModifierKeys modifierKeys = ModifierKeys.None, Boolean block = false)
{
var newNotificationEntry = new KeyNotificationEntry
{
WindowHandle = windowHandle,
KeyCode = keyCode,
ModifierKeys = modifierKeys,
Block = block,
};
foreach (var notificationEntry in NotificationEntries)
if (notificationEntry == newNotificationEntry) return;
NotificationEntries.Add(newNotificationEntry);
}
public static void CancelKeyNotification(IntPtr windowHandle, Int32 keyCode, Boolean block)
{
CancelKeyNotification(windowHandle, keyCode, ModifierKeys.None, block);
}
public static void CancelKeyNotification(IntPtr windowHandle, Int32 keyCode, ModifierKeys modifierKeys = ModifierKeys.None, Boolean block = false)
{
var notificationEntry = new KeyNotificationEntry
{
WindowHandle = windowHandle,
KeyCode = keyCode,
ModifierKeys = modifierKeys,
Block = block,
};
NotificationEntries.Remove(notificationEntry);
}
}
}

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SharedLibraryNG")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SharedLibraryNG")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f4470853-f933-4203-9d2a-b3c731e225c7")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0F615504-5F30-4CF2-8341-1DE7FEC95A23}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SharedLibraryNG</RootNamespace>
<AssemblyName>SharedLibraryNG</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="HotkeyControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="KeyboardHook.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Win32.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,171 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace SharedLibraryNG
{
// ReSharper disable InconsistentNaming
public static class Win32
{
#region Functions
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, IntPtr hMod, Int32 dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr RegisterWindowMessage(string lpString);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetGUIThreadInfo(Int32 idThread, GUITHREADINFO lpgui);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetAncestor(IntPtr hwnd, UInt32 gaFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Int16 GetAsyncKeyState(Int32 vKey);
#endregion
#region Delegates
public delegate IntPtr LowLevelKeyboardProcDelegate(Int32 nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam);
#endregion
#region Structures
[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT
{
public Int32 vkCode;
public Int32 scanCode;
public Int32 flags;
public Int32 time;
public IntPtr dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential)]
public class GUITHREADINFO
{
public GUITHREADINFO()
{
cbSize = Convert.ToInt32(Marshal.SizeOf(this));
}
public Int32 cbSize;
public Int32 flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rcCaret;
}
#endregion
#region Constants
// GetAncestor
public const int GA_ROOT = 2;
// SetWindowsHookEx
public const int WH_KEYBOARD_LL = 13;
// LowLevelKeyboardProcDelegate
public const int HC_ACTION = 0;
// SendMessage
public const int WM_KEYDOWN = 0x0100;
public const int WM_KEYUP = 0x0101;
public const int WM_SYSKEYDOWN = 0x0104;
public const int WM_SYSKEYUP = 0x0105;
// GetAsyncKeyState
public const int KEYSTATE_PRESSED = 0x8000;
#region Virtual Keys
public const int VK_CANCEL = 0x0003;
public const int VK_BACK = 0x0008;
public const int VK_TAB = 0x0009;
public const int VK_CLEAR = 0x000C;
public const int VK_RETURN = 0x000D;
public const int VK_PAUSE = 0x0013;
public const int VK_ESCAPE = 0x001B;
public const int VK_SNAPSHOT = 0x002C;
public const int VK_INSERT = 0x002D;
public const int VK_DELETE = 0x002E;
public const int VK_HOME = 0x0024;
public const int VK_END = 0x0023;
public const int VK_PRIOR = 0x0021;
public const int VK_NEXT = 0x0022;
public const int VK_LEFT = 0x0025;
public const int VK_UP = 0x0026;
public const int VK_RIGHT = 0x0027;
public const int VK_DOWN = 0x0028;
public const int VK_SELECT = 0x0029;
public const int VK_PRINT = 0x002A;
public const int VK_EXECUTE = 0x002B;
public const int VK_HELP = 0x002F;
public const int VK_LWIN = 0x005B;
public const int VK_RWIN = 0x005C;
public const int VK_APPS = 0x005D;
public const int VK_F1 = 0x0070;
public const int VK_F2 = 0x0071;
public const int VK_F3 = 0x0072;
public const int VK_F4 = 0x0073;
public const int VK_F5 = 0x0074;
public const int VK_F6 = 0x0075;
public const int VK_F7 = 0x0076;
public const int VK_F8 = 0x0077;
public const int VK_F9 = 0x0078;
public const int VK_F10 = 0x0079;
public const int VK_F11 = 0x007A;
public const int VK_F12 = 0x007B;
public const int VK_SHIFT = 0x0010;
public const int VK_LSHIFT = 0x00A0;
public const int VK_RSHIFT = 0x00A1;
public const int VK_CONTROL = 0x0011;
public const int VK_LCONTROL = 0x00A2;
public const int VK_RCONTROL = 0x00A3;
public const int VK_MENU = 0x0012;
public const int VK_LMENU = 0x00A4;
public const int VK_RMENU = 0x00A5;
public const int VK_OEM_1 = 0x00BA;
public const int VK_OEM_2 = 0x00BF;
public const int VK_OEM_3 = 0x00C0;
public const int VK_OEM_4 = 0x00DB;
public const int VK_OEM_5 = 0x00DC;
public const int VK_OEM_6 = 0x00DD;
public const int VK_OEM_7 = 0x00DE;
public const int VK_OEM_8 = 0x00DF;
public const int VK_OEM_102 = 0x00E2;
#endregion
#endregion
// ReSharper restore InconsistentNaming
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,31 +0,0 @@
7-Zip Extra
~~~~~~~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright (C) 1999-2019 Igor Pavlov.
7-Zip Extra files are under the GNU LGPL license.
Notes:
You can use 7-Zip Extra on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
GNU LGPL information
--------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/

View File

@@ -1,111 +0,0 @@
7-Zip Extra history
-------------------
This file contains only information about changes related to that package exclusively.
The full history of changes is listed in history.txt in main 7-Zip program.
19.00 2019-02-21
-------------------------
- Encryption strength for 7z archives was increased:
the size of random initialization vector was increased from 64-bit to 128-bit,
and the pseudo-random number generator was improved.
- Some bugs were fixed.
18.06 2018-12-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
and there are minor changes in compression ratio.
- Some bugs were fixed.
18.05 2018-04-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased
by 8% for fastest/fast compression levels and
by 3% for normal/maximum compression levels.
18.03 beta 2018-03-04
-------------------------
- The speed for single-thread LZMA/LZMA2 decoding
was increased by 30% in x64 version and by 3% in x86 version.
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
if there are multiple independent data chunks in LZMA2 stream.
9.35 beta 2014-12-07
------------------------------
- SFX modules were moved to LZMA SDK package.
9.34 alpha 2014-06-22
------------------------------
- Minimum supported system now is Windows 2000 for EXE and DLL files.
- all EXE and DLL files use msvcrt.dll.
- 7zr.exe now support AES encryption.
9.18 2010-11-02
------------------------------
- New small SFX module for installers.
9.17 2010-10-04
------------------------------
- New 7-Zip plugin for FAR Manager x64.
9.10 2009-12-30
------------------------------
- 7-Zip for installers now supports LZMA2.
9.09 2009-12-12
------------------------------
- LZMA2 compression method support.
- Some bugs were fixed.
4.65 2009-02-03
------------------------------
- Some bugs were fixed.
4.38 beta 2006-04-13
------------------------------
- SFX for installers now supports new properties in config file:
Progress, Directory, ExecuteFile, ExecuteParameters.
4.34 beta 2006-02-27
------------------------------
- ISetProperties::SetProperties:
it's possible to specify desirable number of CPU threads:
PROPVARIANT: name=L"mt", vt = VT_UI4, ulVal = NumberOfThreads
If "mt" is not defined, 7za.dll will check number of processors in system to set
number of desirable threads.
Now 7za.dll can use:
2 threads for LZMA compressing
N threads for BZip2 compressing
4 threads for BZip2 decompressing
Other codecs use only one thread.
Note: 7za.dll can use additional "small" threads with low CPU load.
- It's possible to call ISetProperties::SetProperties to specify "mt" property for decoder.
4.33 beta 2006-02-05
------------------------------
- Compressing speed and Memory requirements were increased.
Default dictionary size was increased: Fastest: 64 KB, Fast: 1 MB,
Normal: 4 MB, Max: 16 MB, Ultra: 64 MB.
- 7z/LZMA now can use only these match finders: HC4, BT2, BT3, BT4
4.27 2005-09-21
------------------------------
- Some GUIDs/interfaces were changed.
IStream.h:
ISequentialInStream::Read now works as old ReadPart
ISequentialOutStream::Write now works as old WritePart

View File

@@ -1,124 +0,0 @@
7-Zip Extra 19.00
-----------------
7-Zip Extra is package of extra modules of 7-Zip.
7-Zip Copyright (C) 1999-2019 Igor Pavlov.
7-Zip is free software. Read License.txt for more information about license.
Source code of binaries can be found at:
http://www.7-zip.org/
This package contains the following files:
7za.exe - standalone console version of 7-Zip with reduced formats support.
7za.dll - library for working with 7z archives
7zxa.dll - library for extracting from 7z archives
License.txt - license information
readme.txt - this file
Far\ - plugin for Far Manager
x64\ - binaries for x64
All 32-bit binaries can work in:
Windows 2000 / 2003 / 2008 / XP / Vista / 7 / 8 / 10
and in any Windows x64 version with WoW64 support.
All x64 binaries can work in any Windows x64 version.
All binaries use msvcrt.dll.
7za.exe
-------
7za.exe - is a standalone console version of 7-Zip with reduced formats support.
Extra: 7za.exe : support for only some formats of 7-Zip.
7-Zip: 7z.exe with 7z.dll : support for all formats of 7-Zip.
7za.exe and 7z.exe from 7-Zip have same command line interface.
7za.exe doesn't use external DLL files.
You can read Help File (7-zip.chm) from 7-Zip package for description
of all commands and switches for 7za.exe and 7z.exe.
7za.exe features:
- High compression ratio in 7z format
- Supported formats:
- Packing / unpacking: 7z, xz, ZIP, GZIP, BZIP2 and TAR
- Unpacking only: Z, lzma, CAB.
- Highest compression ratio for ZIP and GZIP formats.
- Fast compression and decompression
- Strong AES-256 encryption in 7z and ZIP formats.
Note: LZMA SDK contains 7zr.exe - more reduced version of 7za.exe.
But you can use 7zr.exe as "public domain" code.
DLL files
---------
7za.dll and 7zxa.dll are reduced versions of 7z.dll from 7-Zip.
7za.dll and 7zxa.dll support only 7z format.
Note: 7z.dll is main DLL file that works with all archive types in 7-Zip.
7za.dll and 7zxa.dll support the following decoding methods:
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES, BZip2, Deflate.
7za.dll also supports 7z encoding with the following encoding methods:
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES.
7za.dll and 7zxa.dll work via COM interfaces.
But these DLLs don't use standard COM interfaces for objects creating.
Look also example code that calls DLL functions (in source code of 7-Zip):
7zip\UI\Client7z
Another example of binary that uses these interface is 7-Zip itself.
The following binaries from 7-Zip use 7z.dll:
- 7z.exe (console version)
- 7zG.exe (GUI version)
- 7zFM.exe (7-Zip File Manager)
Note: The source code of LZMA SDK also contains the code for similar DLLs
(DLLs without BZip2, Deflate support). And these files from LZMA SDK can be
used as "public domain" code. If you use LZMA SDK files, you don't need to
follow GNU LGPL rules, if you want to change the code.
License FAQ
-----------
Can I use the EXE or DLL files from 7-Zip in a commercial application?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Yes, but you are required to specify in documentation for your application:
(1) that you used parts of the 7-Zip program,
(2) that 7-Zip is licensed under the GNU LGPL license and
(3) you must give a link to www.7-zip.org, where the source code can be found.
Can I use the source code of 7-Zip in a commercial application?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Since 7-Zip is licensed under the GNU LGPL you must follow the rules of that license.
In brief, it means that any LGPL'ed code must remain licensed under the LGPL.
For instance, you can change the code from 7-Zip or write a wrapper for some
code from 7-Zip and compile it into a DLL; but, the source code of that DLL
(including your modifications / additions / wrapper) must be licensed under
the LGPL or GPL.
Any other code in your application can be licensed as you wish. This scheme allows
users and developers to change LGPL'ed code and recompile that DLL. That is the
idea of free software. Read more here: http://www.gnu.org/.
Note: You can look also LZMA SDK, which is available under a more liberal license.
---
End of document

View File

@@ -1,15 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "Copying PUTTYNG to correct directory"
Copy-Item -Path (Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\Resources\PuTTYNG.exe") -Destination $TargetDir -Force
Write-Output ""

View File

@@ -1,19 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "Copying THEMES folder to output"
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteNG\Resources\Themes' )
$DestinationDir = [io.path]::combine($TargetDir , 'Themes')
robocopy $sourceFiles $DestinationDir *.vstheme /s
Write-Output ""

View File

@@ -1,17 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "Copying TILES folder to output"
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteNG\Resources\Tiles' )
robocopy $sourceFiles $TargetDir *.*
Write-Output ""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -37,16 +37,9 @@ Format-Table -AutoSize -Wrap -InputObject @{
"ExcludeFromSigning" = $ExcludeFromSigning
}
& "$PSScriptRoot\copy_puttyng.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
& "$PSScriptRoot\copy_themes.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
& "$PSScriptRoot\copy_tiles.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
& "$PSScriptRoot\sphinx_docs.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
& "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\zip_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName

View File

@@ -3,7 +3,7 @@
$SolutionDir
)
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
$renameTarget = $SolutionDir + "mRemoteNGInstaller\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
Write-Host $SolutionDir
Write-Host $renameTarget

View File

@@ -1,33 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "Building HTML-Documentation with Sphinx"
$path_HelpFilesDir = Join-Path -Path $TargetDir -ChildPath "Help"
$path_SphinxSourceDir = Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\Documentation"
# Remove stale Help files, if they exist
if (Test-Path -Path $path_HelpFilesDir) {
Remove-Item -Path $path_HelpFilesDir -Recurse -Force
}
# Build docs
sphinx-build $path_SphinxSourceDir $path_HelpFilesDir
# Place dummy html file if build failed
if (-Not (Test-Path $path_HelpFilesDir\index.html -PathType Leaf)) {
New-Item -Path $path_HelpFilesDir -ItemType "directory"
New-Item $path_HelpFilesDir\index.html
Set-Content $path_HelpFilesDir\index.html 'Welcome to mRemoteNG!'
}
Write-Output ""

72
Tools/zip_files.ps1 Normal file
View File

@@ -0,0 +1,72 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
$ConfigurationName = $ConfigurationName.Trim()
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
$exe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
$Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($exe).FileVersion
Write-Output "Version is $($version)"
# Fix for AppVeyor
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
if(!(test-path "Release")) {
New-Item -ItemType Directory -Force -Path "Release" | Out-Null
}
}
# Package debug symbols zip file
if ($ConfigurationName -match "Release") {
Write-Output "Packaging debug symbols"
if ($ConfigurationName -match "Portable") {
$zipFilePrefix = "mRemoteNG-Portable-symbols"
} else {
$zipFilePrefix = "mRemoteNG-symbols"
}
$debugFile = Join-Path -Path $TargetDir -ChildPath "mRemoteNG.pdb"
# AppVeyor build
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\$zipFilePrefix-$($version).zip"
7z a $outputZipPath $debugFile
}
# Local build
else {
$outputZipPath = "$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
Compress-Archive $debugFile $outputZipPath -Force
}
Remove-Item $debugFile
}
# Package portable release zip file
if ($ConfigurationName -eq "Release Portable") {
Write-Output "Packaging portable ZIP file"
# AppVeyor build
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\mRemoteNG-Portable-$($version).zip"
7z a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath $TargetDir\*
}
# Local build
else {
$outputZipPath="$($SolutionDir)\Release\mRemoteNG-Portable-$($version).zip"
Compress-Archive $Source $outputZipPath -Force
}
}
Write-Output ""

View File

@@ -1,64 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
Exit
}
Write-Output "Solution Dir: '$($SolutionDir)'"
Write-Output "Target Dir: '$($TargetDir)'"
$ConfigurationName = $ConfigurationName.Trim()
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
# Package Zip
if ($ConfigurationName -eq "Release Portable") {
Write-Output "Packaging Release Portable ZIP"
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteNG\bin\$($ConfigurationName)\mRemoteNG.exe"
Write-Output "Version is $($version)"
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
$tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\bin\package"
Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null
New-Item $tempFolderPath -ItemType "directory" | Out-Null
Copy-Item "$($SolutionDir)mRemoteNG\Resources\PuTTYNG.exe" -Destination $tempFolderPath
#Write-Output "$($SolutionDir)mRemoteNG\bin\$ConfigurationName"
#Write-Output "$($SolutionDir)mRemoteNG\bin\package"
Copy-Item "$($SolutionDir)mRemoteNG\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force
# Delete any PDB files that accidentally get copied into the temp folder
Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item
Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath
Write-Output "Creating portable ZIP file $($PortableZip)"
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*")
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
}
else {
Write-Output "We will not zip anything - this isnt a portable release build."
}
Write-Output ""

View File

@@ -1,56 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
Exit
}
Write-Output "Solution Dir: '$($SolutionDir)'"
Write-Output "Target Dir: '$($TargetDir)'"
$ConfigurationName = $ConfigurationName.Trim()
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
# Package Zip
if ($ConfigurationName -match "Release") {
Write-Output "Packaging debug symbols"
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteNG\bin\$($ConfigurationName)\mRemoteNG.exe"
Write-Output "Version is $($version)"
if ($ConfigurationName -match "Portable") {
$zipFilePrefix = "mRemoteNG-Portable-symbols"
} else {
$zipFilePrefix = "mRemoteNG-symbols"
}
$outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
Write-Output "Creating debug symbols ZIP file $($outputZipPath)"
Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb")
}
else {
Write-Output "We will not package debug symbols - this isnt a release build."
}
Write-Output ""

View File

@@ -18,8 +18,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "mRemoteNGInsta
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedLibraryNG", "SharedLibraryNG\SharedLibraryNG.csproj", "{0F615504-5F30-4CF2-8341-1DE7FEC95A23}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug Portable|Any CPU = Debug Portable|Any CPU
@@ -120,26 +118,6 @@ Global
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|Any CPU.ActiveCfg = Release|x86
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.ActiveCfg = Release|x86
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.Build.0 = Release|x86
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|Any CPU.ActiveCfg = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|Any CPU.Build.0 = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|x86.ActiveCfg = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|x86.Build.0 = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|x86.ActiveCfg = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|x86.Build.0 = Debug|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|Any CPU.ActiveCfg = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|Any CPU.Build.0 = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|x86.ActiveCfg = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|x86.Build.0 = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|Any CPU.ActiveCfg = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|Any CPU.Build.0 = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|x86.ActiveCfg = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|x86.Build.0 = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|Any CPU.Build.0 = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|x86.ActiveCfg = Release|Any CPU
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -5,7 +5,6 @@ using Microsoft.Win32;
using mRemoteNG.App.Info;
using mRemoteNG.Messages;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.TaskDialog;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.Windows.Forms;
using mRemoteNG.Config.Connections;
@@ -19,7 +19,7 @@ namespace mRemoteNG.App
{
public static class Export
{
public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel)
public static void ExportToFile(ConnectionInfo selectedNode, IConnectionTreeModel connectionTreeModel)
{
try
{
@@ -93,8 +93,7 @@ namespace mRemoteNG.App
serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer);
break;
case SaveFormat.mRCSV:
serializer =
new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialProviderCatalog);
serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialService.RepositoryList);
break;
default:
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);

View File

@@ -6,12 +6,11 @@ using mRemoteNG.Config.Import;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
namespace mRemoteNG.App
{
public static class Import
public static class Import
{
public static void ImportFromFile(ContainerInfo importDestinationContainer)
{

View File

@@ -15,6 +15,7 @@ namespace mRemoteNG.App.Info
public const string UrlDonate = "https://mremoteng.org/contribute";
public const string UrlForum = "https://www.reddit.com/r/mRemoteNG";
public const string UrlBugs = "https://bugs.mremoteng.org";
public const string UrlDocumentation = "https://mremoteng.readthedocs.io/en/latest/";
public static string ApplicationVersion = Application.ProductVersion;
public static readonly string ProductName = Application.ProductName;

View File

@@ -8,17 +8,16 @@ namespace mRemoteNG.App.Info
public static class UpdateChannelInfo
{
public const string STABLE = "Stable";
public const string BETA = "Beta";
public const string DEV = "Development";
public const string PREVIEW = "Preview";
public const string NIGHTLY = "Nightly";
/* no #if here since they are used for unit tests as well */
public const string STABLE_PORTABLE = "update-portable.txt";
public const string BETA_PORTABLE = "beta-update-portable.txt";
public const string DEV_PORTABLE = "dev-update-portable.txt";
public const string PREVIEW_PORTABLE = "preview-update-portable.txt";
public const string NIGHTLY_PORTABLE = "nightly-update-portable.txt";
public const string STABLE_MSI = "update.txt";
public const string BETA_MSI = "beta-update.txt";
public const string DEV_MSI = "dev-update.txt";
public const string PREVIEW_MSI = "preview-update.txt";
public const string NIGHTLY_MSI = "nightly-update.txt";
public static Uri GetUpdateChannelInfo()
@@ -40,10 +39,10 @@ namespace mRemoteNG.App.Info
{
case STABLE:
return STABLE_MSI;
case BETA:
return BETA_MSI;
case DEV:
return DEV_MSI;
case PREVIEW:
return PREVIEW_MSI;
case NIGHTLY:
return NIGHTLY_MSI;
default:
return STABLE_MSI;
}
@@ -55,10 +54,10 @@ namespace mRemoteNG.App.Info
{
case STABLE:
return STABLE_PORTABLE;
case BETA:
return BETA_PORTABLE;
case DEV:
return DEV_PORTABLE;
case PREVIEW:
return PREVIEW_PORTABLE;
case NIGHTLY:
return NIGHTLY_PORTABLE;
default:
return STABLE_PORTABLE;
}
@@ -72,7 +71,7 @@ namespace mRemoteNG.App.Info
private static bool IsValidChannel(string s)
{
return s.Equals(STABLE) || s.Equals(BETA) || s.Equals(DEV);
return s.Equals(STABLE) || s.Equals(PREVIEW) || s.Equals(NIGHTLY);
}
}
}

View File

@@ -1,21 +1,38 @@
using System.IO;
using System;
using System.IO;
using System.Linq;
using mRemoteNG.Config.Connections;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Tools;
using mRemoteNG.Properties;
namespace mRemoteNG.App.Initialization
{
public class CredsAndConsSetup
{
public void LoadCredsAndCons()
public void LoadCredsAndCons(ConnectionsService connectionsService, CredentialService credentialService, SaveConnectionsOnEdit connectionsOnEdit)
{
new SaveConnectionsOnEdit(Runtime.ConnectionsService);
connectionsOnEdit.Subscribe(connectionsService);
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation &&
!File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService
.GetStartupConnectionFileName());
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation &&
!File.Exists(connectionsService.GetStartupConnectionFileName()))
connectionsService.NewConnectionsFile(connectionsService.GetStartupConnectionFileName());
credentialService.LoadRepositoryList();
LoadDefaultConnectionCredentials(credentialService);
Runtime.LoadConnections();
}
private void LoadDefaultConnectionCredentials(CredentialService credentialService)
{
var defaultCredId = Settings.Default.ConDefaultCredentialRecord;
var matchedCredentials = credentialService
.GetCredentialRecords()
.Where(record => record.Id.Equals(defaultCredId))
.ToArray();
DefaultConnectionInfo.Instance.CredentialRecordId = Optional<Guid>.FromNullable(matchedCredentials.FirstOrDefault()?.Id);
}
}
}

View File

@@ -3,7 +3,6 @@ using System.Management;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.App.Initialization
{

View File

@@ -2,7 +2,6 @@
using mRemoteNG.Config.Putty;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Messages;
using mRemoteNG.Security;
using mRemoteNG.Tools;
@@ -16,7 +15,6 @@ using System.Security;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.App
{
@@ -37,7 +35,7 @@ namespace mRemoteNG.App
/// <summary>
/// Feature flag to enable the credential manager feature
/// </summary>
public static bool UseCredentialManager => false;
public static bool UseCredentialManager => true;
public static WindowList WindowList { get; set; }
public static MessageCollector MessageCollector { get; } = new MessageCollector();
@@ -47,10 +45,9 @@ namespace mRemoteNG.App
public static SecureString EncryptionKey { get; set; } =
new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
public static CredentialService CredentialService { get; } = new CredentialServiceFactory().Build();
public static ConnectionsService ConnectionsService { get; } =
new ConnectionsService(PuttySessionsManager.Instance);
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance, CredentialService);
#region Connections Loading/Saving
@@ -97,7 +94,7 @@ namespace mRemoteNG.App
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
}
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, connectionFileName);
if (Settings.Default.UseSQLServer)
{

View File

@@ -4,7 +4,6 @@ using System.Diagnostics;
using System.Windows.Forms;
using mRemoteNG.Config.Putty;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Forms;

View File

@@ -8,10 +8,8 @@ namespace mRemoteNG.App
public static class Windows
{
private static ActiveDirectoryImportWindow _adimportForm;
private static HelpWindow _helpForm;
private static ExternalToolsWindow _externalappsForm;
private static PortScanWindow _portscanForm;
private static ScreenshotManagerWindow _screenshotmanagerForm;
private static UltraVNCWindow _ultravncscForm;
private static ConnectionTreeWindow _treeForm;
@@ -23,7 +21,6 @@ namespace mRemoteNG.App
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
@@ -58,11 +55,6 @@ namespace mRemoteNG.App
UpdateForm = new UpdateWindow();
UpdateForm.Show(dockPanel);
break;
case WindowType.Help:
if (_helpForm == null || _helpForm.IsDisposed)
_helpForm = new HelpWindow();
_helpForm.Show(dockPanel);
break;
case WindowType.ExternalApps:
if (_externalappsForm == null || _externalappsForm.IsDisposed)
_externalappsForm = new ExternalToolsWindow();
@@ -72,10 +64,6 @@ namespace mRemoteNG.App
_portscanForm = new PortScanWindow();
_portscanForm.Show(dockPanel);
break;
case WindowType.ScreenshotManager:
_screenshotmanagerForm = new ScreenshotManagerWindow();
_screenshotmanagerForm.Show(dockPanel);
break;
case WindowType.UltraVNCSC:
if (_ultravncscForm == null || _ultravncscForm.IsDisposed)
_ultravncscForm = new UltraVNCWindow();

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using mRemoteNG.Credential;
namespace mRemoteNG.Config
{
public class ConnectionToCredentialMap : Dictionary<Guid, ICredentialRecord>
{
private readonly IEqualityComparer<ICredentialRecord> _credentialComparer = new CredentialDomainUserPasswordComparer();
public IEnumerable<ICredentialRecord> DistinctCredentialRecords => Values.Distinct(_credentialComparer);
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
@@ -10,7 +12,7 @@ namespace mRemoteNG.Config.Connections
/// The previous <see cref="ConnectionTreeModel"/> that is being
/// unloaded.
/// </summary>
public Optional<ConnectionTreeModel> PreviousConnectionTreeModel { get; }
public List<ConnectionInfo> RemovedConnections { get; }
/// <summary>
/// True if the previous <see cref="ConnectionTreeModel"/> was loaded from
@@ -21,7 +23,7 @@ namespace mRemoteNG.Config.Connections
/// <summary>
/// The new <see cref="ConnectionTreeModel"/> that is being loaded.
/// </summary>
public ConnectionTreeModel NewConnectionTreeModel { get; }
public List<ConnectionInfo> AddedConnections { get; }
/// <summary>
/// True if the new <see cref="ConnectionTreeModel"/> was loaded from
@@ -36,24 +38,18 @@ namespace mRemoteNG.Config.Connections
/// </summary>
public string NewSourcePath { get; }
public ConnectionsLoadedEventArgs(Optional<ConnectionTreeModel> previousTreeModelModel,
ConnectionTreeModel newTreeModelModel,
bool previousSourceWasDatabase,
bool newSourceIsDatabase,
string newSourcePath)
{
if (previousTreeModelModel == null)
throw new ArgumentNullException(nameof(previousTreeModelModel));
if (newTreeModelModel == null)
throw new ArgumentNullException(nameof(newTreeModelModel));
if (newSourcePath == null)
throw new ArgumentNullException(nameof(newSourcePath));
public IConnectionTreeModel NewConnectionTreeModel { get; set; } = new ConnectionTreeModel();
PreviousConnectionTreeModel = previousTreeModelModel;
public ConnectionsLoadedEventArgs(
List<ConnectionInfo> removedConnections, List<ConnectionInfo> addedConnections,
bool previousSourceWasDatabase, bool newSourceIsDatabase,
string newSourcePath)
{
RemovedConnections = removedConnections.ThrowIfNull(nameof(removedConnections));
PreviousSourceWasDatabase = previousSourceWasDatabase;
NewConnectionTreeModel = newTreeModelModel;
AddedConnections = addedConnections.ThrowIfNull(nameof(addedConnections));
NewSourceIsDatabase = newSourceIsDatabase;
NewSourcePath = newSourcePath;
NewSourcePath = newSourcePath.ThrowIfNull(nameof(newSourcePath));
}
}
}
}

View File

@@ -5,12 +5,12 @@ namespace mRemoteNG.Config.Connections
{
public class ConnectionsSavedEventArgs
{
public ConnectionTreeModel ModelThatWasSaved { get; }
public IConnectionTreeModel ModelThatWasSaved { get; }
public bool PreviouslyUsingDatabase { get; }
public bool UsingDatabase { get; }
public string ConnectionFileName { get; }
public ConnectionsSavedEventArgs(ConnectionTreeModel modelThatWasSaved,
public ConnectionsSavedEventArgs(IConnectionTreeModel modelThatWasSaved,
bool previouslyUsingDatabase,
bool usingDatabase,
string connectionFileName)
@@ -24,4 +24,4 @@ namespace mRemoteNG.Config.Connections
ConnectionFileName = connectionFileName;
}
}
}
}

View File

@@ -25,11 +25,10 @@ namespace mRemoteNG.Config.Connections
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
var csvConnectionsSerializer =
new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialService.RepositoryList);
var dataProvider = new FileDataProvider(_connectionFileName);
var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
dataProvider.Save(csvContent);
}
}
}
}

View File

@@ -1,9 +1,9 @@
using mRemoteNG.Tree;
using mRemoteNG.Config.Serializers;
namespace mRemoteNG.Config.Connections
{
public interface IConnectionsLoader
{
ConnectionTreeModel Load();
SerializationResult Load();
}
}

View File

@@ -35,7 +35,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
private void Load(object sender, ConnectionsUpdateAvailableEventArgs args)
{
Runtime.ConnectionsService.LoadConnections(true, false, "");
Runtime.ConnectionsService.LoadConnections(true, "");
args.Handled = true;
}

View File

@@ -1,36 +1,26 @@
using System;
using System.Collections.Specialized;
using System.Collections.Specialized;
using System.ComponentModel;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Connections
{
public class SaveConnectionsOnEdit
{
private readonly ConnectionsService _connectionsService;
private IConnectionsService _connectionsService;
public SaveConnectionsOnEdit(ConnectionsService connectionsService)
public void Subscribe(IConnectionsService connectionsService)
{
if (connectionsService == null)
throw new ArgumentNullException(nameof(connectionsService));
_connectionsService = connectionsService;
connectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded;
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
connectionsService.ConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
connectionsService.ConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
}
private void ConnectionsServiceOnConnectionsLoaded(object sender,
ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
public void Unsubscribe()
{
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged +=
ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
{
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
oldTree.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;
}
_connectionsService.ConnectionTreeModel.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
_connectionsService.ConnectionTreeModel.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;
_connectionsService = null;
}
private void ConnectionTreeModelOnPropertyChanged(object sender,
@@ -50,10 +40,8 @@ namespace mRemoteNG.Config.Connections
{
if (!Properties.Settings.Default.SaveConnectionsAfterEveryEdit)
return;
if (FrmMain.Default.IsClosing)
return;
_connectionsService.SaveConnectionsAsync(propertyName);
_connectionsService?.SaveConnectionsAsync(propertyName);
}
}
}
}

View File

@@ -12,7 +12,6 @@ using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Connections
@@ -36,7 +35,7 @@ namespace mRemoteNG.Config.Connections
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
}
public ConnectionTreeModel Load()
public SerializationResult Load()
{
var connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
var dataProvider = new SqlDataProvider(connector);
@@ -54,9 +53,9 @@ namespace mRemoteNG.Config.Connections
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
var dataTable = dataProvider.Load();
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
var connectionTree = deserializer.Deserialize(dataTable);
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
return connectionTree;
var serializationResult = deserializer.Deserialize(dataTable);
ApplyLocalConnectionProperties(serializationResult.ConnectionRecords.OfType<RootNodeInfo>().First());
return serializationResult;
}
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)

View File

@@ -12,7 +12,6 @@ using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
using mRemoteNG.Security;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
@@ -21,7 +20,7 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Connections
{
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
public class SqlConnectionsSaver : ISaver<IConnectionTreeModel>
{
private readonly SaveFilter _saveFilter;
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer;
@@ -39,7 +38,7 @@ namespace mRemoteNG.Config.Connections
_dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
public void Save(IConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();

View File

@@ -1,18 +1,25 @@
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using System;
using System.IO;
using System.Security;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
using mRemoteNG.App.Info;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.Config.Connections
{
public class XmlConnectionsLoader : IConnectionsLoader
{
private readonly string _credentialFilePath = Path.Combine(CredentialsFileInfo.CredentialsPath, CredentialsFileInfo.CredentialsFile);
private readonly string _connectionFilePath;
private readonly ConnectionsService _connectionsService;
private readonly ICredentialService _credentialService;
public XmlConnectionsLoader(string connectionFilePath)
public XmlConnectionsLoader(string connectionFilePath, ICredentialService credentialService, ConnectionsService connectionsService)
{
if (string.IsNullOrEmpty(connectionFilePath))
throw new ArgumentException($"{nameof(connectionFilePath)} cannot be null or empty");
@@ -21,14 +28,26 @@ namespace mRemoteNG.Config.Connections
throw new FileNotFoundException($"{connectionFilePath} does not exist");
_connectionFilePath = connectionFilePath;
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));
}
public ConnectionTreeModel Load()
public SerializationResult Load()
{
var dataProvider = new FileDataProvider(_connectionFilePath);
var xmlString = dataProvider.Load();
var deserializer = new XmlConnectionsDeserializer(PromptForPassword);
return deserializer.Deserialize(xmlString);
var deserializer = new CredentialManagerUpgradeForm
{
ConnectionFilePath = _connectionFilePath,
NewCredentialRepoPath = _credentialFilePath,
ConnectionsService = _connectionsService,
CredentialService = _credentialService,
ConnectionDeserializer = new XmlConnectionsDeserializer(PromptForPassword)
};
var serializationResult = deserializer.Deserialize(xmlString);
return serializationResult;
}
private Optional<SecureString> PromptForPassword()

View File

@@ -10,7 +10,7 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Connections
{
public class XmlConnectionsSaver : ISaver<ConnectionTreeModel>
public class XmlConnectionsSaver : ISaver<IConnectionTreeModel>
{
private readonly string _connectionFileName;
private readonly SaveFilter _saveFilter;
@@ -26,7 +26,7 @@ namespace mRemoteNG.Config.Connections
_saveFilter = saveFilter;
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
public void Save(IConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
try
{

View File

@@ -0,0 +1,39 @@
using System.Collections.Generic;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Credential;
using mRemoteNG.Credential.Repositories;
using mRemoteNG.Tools;
namespace mRemoteNG.Config
{
public class CredentialRepositoryListPersistor : ISaver<IEnumerable<ICredentialRepository>>, ILoader<IEnumerable<ICredentialRepository>>
{
private readonly IReadOnlyCollection<ICredentialRepositoryFactory> _repositoryFactories;
private readonly IDataProvider<string> _dataProvider;
private readonly CredentialRepositoryListDeserializer _deserializer;
private readonly CredentialRepositoryListSerializer _serializer;
public CredentialRepositoryListPersistor(
IDataProvider<string> dataProvider,
IReadOnlyCollection<ICredentialRepositoryFactory> repositoryFactories)
{
_repositoryFactories = repositoryFactories.ThrowIfNull(nameof(repositoryFactories));
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
_deserializer = new CredentialRepositoryListDeserializer();
_serializer = new CredentialRepositoryListSerializer();
}
public IEnumerable<ICredentialRepository> Load()
{
var data = _dataProvider.Load();
return _deserializer.Deserialize(data, _repositoryFactories);
}
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
{
var data = _serializer.Serialize(repositories);
_dataProvider.Save(data);
}
}
}

View File

@@ -2,7 +2,6 @@
using System.IO;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.Config.DataProviders
{

View File

@@ -53,12 +53,26 @@ namespace mRemoteNG.Config.DatabaseConnectors
private void BuildDbConnectionStringWithCustomCredentials()
{
_dbConnectionString = $"Data Source={_dbHost};Initial Catalog={_dbCatalog};User Id={_dbUsername};Password={_dbPassword}";
string[] hostParts = _dbHost.Split(new char[] { ':' }, 2);
var _dbPort = (hostParts.Length == 2) ? hostParts[1] : "1433";
_dbConnectionString = new SqlConnectionStringBuilder
{
DataSource = $"{hostParts[0]},{_dbPort}",
InitialCatalog = _dbCatalog,
UserID = _dbUsername,
Password = _dbPassword,
}.ToString();
}
private void BuildDbConnectionStringWithDefaultCredentials()
{
_dbConnectionString = $"Data Source={_dbHost};Initial Catalog={_dbCatalog};Integrated Security=True";
_dbConnectionString = new SqlConnectionStringBuilder
{
DataSource = _dbHost,
InitialCatalog = _dbCatalog,
IntegratedSecurity = true
}.ToString();
}
public void Connect()

View File

@@ -1,10 +1,11 @@
using System.IO;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Csv;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using System.IO;
using System.Linq;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.Config.Import
{
@@ -25,11 +26,18 @@ namespace mRemoteNG.Config.Import
var dataProvider = new FileDataProvider(filePath);
var xmlString = dataProvider.Load();
var xmlConnectionsDeserializer = new CsvConnectionsDeserializerMremotengFormat();
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString);
var serializationResult = xmlConnectionsDeserializer.Deserialize(xmlString);
var credentialImportForm = new CredentialImportForm
{
ImportedCredentialRecords = serializationResult.ConnectionToCredentialMap.DistinctCredentialRecords.ToList(),
CredentialService = Runtime.CredentialService
};
credentialImportForm.ShowDialog();
var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(filePath)};
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
rootImportContainer.AddChildRange(serializationResult.ConnectionRecords);
destinationContainer.AddChild(rootImportContainer);
}
}
}
}

View File

@@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
@@ -27,10 +26,10 @@ namespace mRemoteNG.Config.Import
var dataProvider = new FileDataProvider(fileName);
var xmlString = dataProvider.Load();
var xmlConnectionsDeserializer = new XmlConnectionsDeserializer();
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true);
var serializationResult = xmlConnectionsDeserializer.Deserialize(xmlString, true);
var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(fileName)};
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
rootImportContainer.AddChildRange(serializationResult.ConnectionRecords);
destinationContainer.AddChild(rootImportContainer);
}
}

View File

@@ -1,5 +1,4 @@
using System.Linq;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Container;
@@ -14,12 +13,9 @@ namespace mRemoteNG.Config.Import
var xmlContent = dataProvider.Load();
var deserializer = new PuttyConnectionManagerDeserializer();
var connectionTreeModel = deserializer.Deserialize(xmlContent);
var serializationResult = deserializer.Deserialize(xmlContent);
var importedRootNode = connectionTreeModel.RootNodes.First();
if (importedRootNode == null) return;
var childrenToAdd = importedRootNode.Children.ToArray();
destinationContainer.AddChildRange(childrenToAdd);
destinationContainer.AddChildRange(serializationResult.ConnectionRecords);
}
}
}

View File

@@ -15,9 +15,9 @@ namespace mRemoteNG.Config.Import
var content = dataProvider.Load();
var deserializer = new RemoteDesktopConnectionDeserializer();
var connectionTreeModel = deserializer.Deserialize(content);
var serializationResult = deserializer.Deserialize(content);
var importedConnection = connectionTreeModel.RootNodes.First().Children.First();
var importedConnection = serializationResult.ConnectionRecords.FirstOrDefault();
if (importedConnection == null) return;
importedConnection.Name = Path.GetFileNameWithoutExtension(fileName);

View File

@@ -1,5 +1,4 @@
using System.Linq;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Container;
@@ -14,12 +13,9 @@ namespace mRemoteNG.Config.Import
var fileContent = dataProvider.Load();
var deserializer = new RemoteDesktopConnectionManagerDeserializer();
var connectionTreeModel = deserializer.Deserialize(fileContent);
var serializationResult = deserializer.Deserialize(fileContent);
var importedRootNode = connectionTreeModel.RootNodes.First();
if (importedRootNode == null) return;
var childrenToAdd = importedRootNode.Children.ToArray();
destinationContainer.AddChildRange(childrenToAdd);
destinationContainer.AddChildRange(serializationResult.ConnectionRecords);
}
}
}

View File

@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Management;
using System.Net;
using System.Security.Principal;
using Microsoft.Win32;
using Microsoft.Win32;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Messages;
using System;
using System.Collections.Generic;
using System.Management;
using System.Net;
using System.Security.Principal;
namespace mRemoteNG.Config.Putty
@@ -55,6 +55,7 @@ namespace mRemoteNG.Config.Putty
PuttySession = sessionName,
Name = sessionName,
Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "",
// TODO: this should create a temp putty credential
Username = sessionKey.GetValue("UserName")?.ToString() ?? ""
};

View File

@@ -1,20 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using mRemoteNG.Config.Serializers.CredentialSerializer;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.Http;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
{
public class CsvConnectionsDeserializerMremotengFormat : IDeserializer<string, ConnectionTreeModel>
public class CsvConnectionsDeserializerMremotengFormat
{
public ConnectionTreeModel Deserialize(string serializedData)
public SerializationResult Deserialize(string serializedData)
{
var lines = serializedData.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries);
var csvHeaders = new List<string>();
@@ -29,26 +32,39 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
else
{
var connectionInfo = ParseConnectionInfo(csvHeaders, line);
parentMapping.Add(connectionInfo, line[csvHeaders.IndexOf("Parent")]);
var parentFieldIndex = csvHeaders.IndexOf("Parent");
if (parentFieldIndex > 0)
parentMapping.Add(connectionInfo, line[parentFieldIndex]);
}
}
var root = CreateTreeStructure(parentMapping);
var connectionTreeModel = new ConnectionTreeModel();
connectionTreeModel.AddRootNode(root);
return connectionTreeModel;
var harvestedCredentials = new CredentialHarvester()
.Harvest(new HarvestConfig<string[]>
{
ItemEnumerator = () => lines.Skip(1).Select(s => s.Split(';')),
ConnectionGuidSelector = line => csvHeaders.Contains("Id") ? Guid.Parse(line[csvHeaders.IndexOf("Id")]) : Guid.NewGuid(),
TitleSelector = line => "",
UsernameSelector = line => csvHeaders.Contains("Username") ? line[csvHeaders.IndexOf("Username")] : "",
DomainSelector = line => csvHeaders.Contains("Domain") ? line[csvHeaders.IndexOf("Domain")] : "",
PasswordSelector = line => csvHeaders.Contains("Password") ? line[csvHeaders.IndexOf("Password")].ConvertToSecureString() : new SecureString()
});
var result = new SerializationResult(root, harvestedCredentials);
return result;
}
private RootNodeInfo CreateTreeStructure(Dictionary<ConnectionInfo, string> parentMapping)
private List<ConnectionInfo> CreateTreeStructure(Dictionary<ConnectionInfo, string> parentMapping)
{
var root = new RootNodeInfo(RootNodeType.Connection);
var root = new List<ConnectionInfo>();
foreach (var node in parentMapping)
{
// no parent mapped, add to root
if (string.IsNullOrEmpty(node.Value))
{
root.AddChild(node.Key);
root.Add(node.Key);
continue;
}
@@ -64,7 +80,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
}
else
{
root.AddChild(node.Key);
root.Add(node.Key);
}
}
@@ -85,53 +101,25 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
? new ConnectionInfo(nodeId)
: new ContainerInfo(nodeId);
connectionRecord.Name = headers.Contains("Name")
? connectionCsv[headers.IndexOf("Name")]
: "";
connectionRecord.Name = headers.Contains("Name") ? connectionCsv[headers.IndexOf("Name")] : "";
connectionRecord.Description =
headers.Contains("Description") ? connectionCsv[headers.IndexOf("Description")] : "";
connectionRecord.Icon = headers.Contains("Icon") ? connectionCsv[headers.IndexOf("Icon")] : "";
connectionRecord.Panel = headers.Contains("Panel") ? connectionCsv[headers.IndexOf("Panel")] : "";
connectionRecord.Description = headers.Contains("Description")
? connectionCsv[headers.IndexOf("Description")]
: "";
var hasCredRecordId = Guid.TryParse(
headers.Contains("CredentialRecordId") ? connectionCsv[headers.IndexOf("CredentialRecordId")] : "",
out var credRecordId);
connectionRecord.CredentialRecordId = hasCredRecordId ? credRecordId : Optional<Guid>.Empty;
connectionRecord.Icon = headers.Contains("Icon")
? connectionCsv[headers.IndexOf("Icon")]
: "";
connectionRecord.Panel = headers.Contains("Panel")
? connectionCsv[headers.IndexOf("Panel")]
: "";
connectionRecord.Username = headers.Contains("Username")
? connectionCsv[headers.IndexOf("Username")]
: "";
connectionRecord.Password = headers.Contains("Password")
? connectionCsv[headers.IndexOf("Password")]
: "";
connectionRecord.Domain = headers.Contains("Domain")
? connectionCsv[headers.IndexOf("Domain")]
: "";
connectionRecord.Hostname = headers.Contains("Hostname")
? connectionCsv[headers.IndexOf("Hostname")]
: "";
connectionRecord.VmId = headers.Contains("VmId")
? connectionCsv[headers.IndexOf("VmId")] : "";
connectionRecord.SSHOptions =headers.Contains("SSHOptions")
? connectionCsv[headers.IndexOf("SSHOptions")]
: "";
connectionRecord.SSHTunnelConnectionName = headers.Contains("SSHTunnelConnectionName")
? connectionCsv[headers.IndexOf("SSHTunnelConnectionName")]
: "";
connectionRecord.PuttySession = headers.Contains("PuttySession")
? connectionCsv[headers.IndexOf("PuttySession")]
: "";
// TODO: harvest
connectionRecord.Username = headers.Contains("Username") ? connectionCsv[headers.IndexOf("Username")] : "";
connectionRecord.Password = headers.Contains("Password") ? connectionCsv[headers.IndexOf("Password")] : "";
connectionRecord.Domain = headers.Contains("Domain") ? connectionCsv[headers.IndexOf("Domain")] : "";
connectionRecord.Hostname = headers.Contains("Hostname") ? connectionCsv[headers.IndexOf("Hostname")] : "";
connectionRecord.PuttySession =
headers.Contains("PuttySession") ? connectionCsv[headers.IndexOf("PuttySession")] : "";
connectionRecord.LoadBalanceInfo = headers.Contains("LoadBalanceInfo")
? connectionCsv[headers.IndexOf("LoadBalanceInfo")]
: "";
@@ -186,6 +174,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
? connectionCsv[headers.IndexOf("RDGatewayHostname")]
: "";
if (headers.Contains("CredentialId"))
{
if (Guid.TryParse(connectionCsv[headers.IndexOf("CredentialId")], out var credId))
connectionRecord.CredentialRecordId = credId;
}
if (headers.Contains("Protocol"))
{
if (Enum.TryParse(connectionCsv[headers.IndexOf("Protocol")], out ProtocolType protocolType))
@@ -825,9 +819,16 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
connectionRecord.Inheritance.RdpVersion = value;
}
if (headers.Contains("InheritCredentialRecord"))
{
if (bool.TryParse(connectionCsv[headers.IndexOf("InheritCredentialRecord")], out bool value))
connectionRecord.Inheritance.CredentialId = value;
}
#endregion
return connectionRecord;
}
}
}
}

View File

@@ -61,7 +61,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
"CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;" +
"PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;Favorite;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;" +
"VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;" +
"RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;RedirectAudioCapture;RdpVersion;");
"RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;RedirectAudioCapture;RdpVersion;CredentialId");
if (_saveFilter.SaveInheritance)
sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;" +
@@ -74,7 +74,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
"InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;" +
"InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;" +
"InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality;" +
"InheritRedirectAudioCapture;InheritRdpVersion");
"InheritRedirectAudioCapture;InheritRdpVersion;InheritCredentialRecord");
}
private void SerializeNodesRecursive(ConnectionInfo node, StringBuilder sb)
@@ -104,18 +104,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
.Append(FormatForCsv(con.GetTreeNodeType()))
.Append(FormatForCsv(con.Description))
.Append(FormatForCsv(con.Icon))
.Append(FormatForCsv(con.Panel));
if (_saveFilter.SaveUsername)
sb.Append(FormatForCsv(con.Username));
if (_saveFilter.SavePassword)
sb.Append(FormatForCsv(con.Password));
if (_saveFilter.SaveDomain)
sb.Append(FormatForCsv(con.Domain));
sb.Append(FormatForCsv(con.Hostname))
.Append(FormatForCsv(con.Panel))
.Append(FormatForCsv(con.Hostname))
.Append(FormatForCsv(con.Port))
.Append(FormatForCsv(con.VmId))
.Append(FormatForCsv(con.Protocol))
@@ -172,7 +162,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
.Append(FormatForCsv(con.RDGatewayPassword))
.Append(FormatForCsv(con.RDGatewayDomain))
.Append(FormatForCsv(con.RedirectAudioCapture))
.Append(FormatForCsv(con.RdpVersion));
.Append(FormatForCsv(con.RdpVersion))
.Append(FormatForCsv(con.CredentialRecordId));
if (!_saveFilter.SaveInheritance)
@@ -243,7 +234,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
.Append(FormatForCsv(con.Inheritance.RDPMinutesToIdleTimeout))
.Append(FormatForCsv(con.Inheritance.SoundQuality))
.Append(FormatForCsv(con.Inheritance.RedirectAudioCapture))
.Append(FormatForCsv(con.Inheritance.RdpVersion));
.Append(FormatForCsv(con.Inheritance.RdpVersion))
.Append(FormatForCsv(con.Inheritance.CredentialId));
}
private string FormatForCsv(object value)

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.Http;
@@ -12,12 +11,10 @@ using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
{
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
public class DataTableDeserializer
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly SecureString _decryptionKey;
@@ -28,12 +25,13 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
}
public ConnectionTreeModel Deserialize(DataTable table)
public SerializationResult Deserialize(DataTable table)
{
var connectionList = CreateNodesFromTable(table);
var connectionTreeModel = CreateNodeHierarchy(connectionList, table);
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel;
var rootNodes = CreateNodeHierarchy(connectionList, table);
var serializationResult = new SerializationResult(rootNodes, new ConnectionToCredentialMap());
return serializationResult;
}
private List<ConnectionInfo> CreateNodesFromTable(DataTable table)
@@ -60,7 +58,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
{
var connectionId = row["ConstantID"] as string ?? Guid.NewGuid().ToString();
var connectionInfo = new ConnectionInfo(connectionId);
PopulateConnectionInfoFromDatarow(row, connectionInfo);
PopulateConnectionInfoFromDataRow(row, connectionInfo);
return connectionInfo;
}
@@ -68,11 +66,11 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
{
var containerId = row["ConstantID"] as string ?? Guid.NewGuid().ToString();
var containerInfo = new ContainerInfo(containerId);
PopulateConnectionInfoFromDatarow(row, containerInfo);
PopulateConnectionInfoFromDataRow(row, containerInfo);
return containerInfo;
}
private void PopulateConnectionInfoFromDatarow(DataRow dataRow, ConnectionInfo connectionInfo)
private void PopulateConnectionInfoFromDataRow(DataRow dataRow, ConnectionInfo connectionInfo)
{
connectionInfo.Name = (string)dataRow["Name"];
@@ -83,9 +81,15 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
connectionInfo.Description = (string)dataRow["Description"];
connectionInfo.Icon = (string)dataRow["Icon"];
connectionInfo.Panel = (string)dataRow["Panel"];
connectionInfo.Username = (string)dataRow["Username"];
connectionInfo.Domain = (string)dataRow["Domain"];
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
// TODO: harvest
if (dataRow.Table.Columns.Contains("Username"))
connectionInfo.Username = (string)dataRow["Username"];
if (dataRow.Table.Columns.Contains("DomainName"))
connectionInfo.Domain = (string)dataRow["DomainName"];
if (dataRow.Table.Columns.Contains("Password"))
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
connectionInfo.Hostname = (string)dataRow["Hostname"];
connectionInfo.VmId = (string)dataRow["VmId"];
connectionInfo.UseEnhancedMode = (bool)dataRow["UseEnhancedMode"];
@@ -184,7 +188,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
connectionInfo.Inheritance.Domain = (bool)dataRow["InheritDomain"];
connectionInfo.Inheritance.Icon = (bool)dataRow["InheritIcon"];
connectionInfo.Inheritance.Panel = (bool)dataRow["InheritPanel"];
connectionInfo.Inheritance.Password = (bool)dataRow["InheritPassword"];
connectionInfo.Inheritance.Port = (bool)dataRow["InheritPort"];
connectionInfo.Inheritance.Protocol = (bool)dataRow["InheritProtocol"];
connectionInfo.Inheritance.SSHTunnelConnectionName = (bool)dataRow["InheritSSHTunnelConnectionName"];
@@ -251,28 +254,21 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
}
}
private ConnectionTreeModel CreateNodeHierarchy(List<ConnectionInfo> connectionList, DataTable dataTable)
private List<ConnectionInfo> CreateNodeHierarchy(IReadOnlyCollection<ConnectionInfo> connectionList, DataTable dataTable)
{
var connectionTreeModel = new ConnectionTreeModel();
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0")
{
PasswordString = _decryptionKey.ConvertToUnsecureString()
};
connectionTreeModel.AddRootNode(rootNode);
var rootNodes = new List<ConnectionInfo>();
foreach (DataRow row in dataTable.Rows)
{
var id = (string)row["ConstantID"];
var id = (string) row["ConstantID"];
var connectionInfo = connectionList.First(node => node.ConstantID == id);
var parentId = (string)row["ParentID"];
var parentId = (string) row["ParentID"];
if (parentId == "0" || connectionList.All(node => node.ConstantID != parentId))
rootNode.AddChild(connectionInfo);
rootNodes.Add(connectionInfo);
else
(connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(
connectionInfo);
(connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(connectionInfo);
}
return connectionTreeModel;
return rootNodes;
}
}
}

View File

@@ -105,9 +105,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
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("Domain", typeof(string));
dataTable.Columns.Add("Password", typeof(string));
dataTable.Columns.Add("Hostname", typeof(string));
dataTable.Columns.Add("Port", typeof(int));
dataTable.Columns.Add("Protocol", typeof(string));
@@ -502,16 +499,10 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
dataRow["PositionID"] = _currentNodeIndex;
dataRow["LastChange"] = MiscTools.DBTimeStampNow();
dataRow["Expanded"] =
false; // TODO: this column can eventually be removed. we now save this property locally
dataRow["Description"] = connectionInfo.Description;
dataRow["Icon"] = connectionInfo.Icon;
dataRow["Panel"] = connectionInfo.Panel;
dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : "";
dataRow["Domain"] = _saveFilter.SaveDomain ? connectionInfo.Domain : "";
dataRow["Password"] = _saveFilter.SavePassword
? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)
: "";
dataRow["Hostname"] = connectionInfo.Hostname;
dataRow["VmId"] = connectionInfo.VmId;
dataRow["Protocol"] = connectionInfo.Protocol;
@@ -549,7 +540,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
dataRow["SoundQuality"] = connectionInfo.SoundQuality;
dataRow["RedirectAudioCapture"] = connectionInfo.RedirectAudioCapture;
dataRow["RedirectKeys"] = connectionInfo.RedirectKeys;
dataRow["Connected"] = false; // TODO: this column can eventually be removed. we now save this property locally
dataRow["PreExtApp"] = connectionInfo.PreExtApp;
dataRow["PostExtApp"] = connectionInfo.PostExtApp;
dataRow["MacAddress"] = connectionInfo.MacAddress;
@@ -592,7 +582,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
dataRow["InheritDomain"] = connectionInfo.Inheritance.Domain;
dataRow["InheritIcon"] = connectionInfo.Inheritance.Icon;
dataRow["InheritPanel"] = connectionInfo.Inheritance.Panel;
dataRow["InheritPassword"] = connectionInfo.Inheritance.Password;
dataRow["InheritPort"] = connectionInfo.Inheritance.Port;
dataRow["InheritProtocol"] = connectionInfo.Inheritance.Protocol;
dataRow["InheritSSHTunnelConnectionName"] = connectionInfo.Inheritance.SSHTunnelConnectionName;
@@ -660,7 +649,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
dataRow["InheritDomain"] = false;
dataRow["InheritIcon"] = false;
dataRow["InheritPanel"] = false;
dataRow["InheritPassword"] = false;
dataRow["InheritPort"] = false;
dataRow["InheritProtocol"] = false;
dataRow["InheritSSHTunnelConnectionName"] = false;

View File

@@ -10,7 +10,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
{
public ISerializer<ConnectionInfo, string> Build(
ICryptographyProvider cryptographyProvider,
ConnectionTreeModel connectionTreeModel,
IConnectionTreeModel connectionTreeModel,
SaveFilter saveFilter = null,
bool useFullEncryption = false)
{

View File

@@ -11,24 +11,25 @@ using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.TaskDialog;
using System.Collections.Generic;
using mRemoteNG.Credential;
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
{
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
public class XmlConnectionsDeserializer
{
private XmlDocument _xmlDocument;
private double _confVersion;
private XmlConnectionsDecryptor _decryptor;
private string ConnectionFileName = "";
private const double MaxSupportedConfVersion = 2.8;
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
private const double MaxSupportedConfVersion = 2.7;
private readonly CredentialDomainUserPasswordComparer _credentialComparer = new CredentialDomainUserPasswordComparer();
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
@@ -37,12 +38,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
AuthenticationRequestor = authenticationRequestor;
}
public ConnectionTreeModel Deserialize(string xml)
public SerializationResult Deserialize(string xml)
{
return Deserialize(xml, false);
}
public ConnectionTreeModel Deserialize(string xml, bool import)
public SerializationResult Deserialize(string xml, bool import)
{
try
{
@@ -50,17 +51,13 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
ValidateConnectionFileVersion();
var rootXmlElement = _xmlDocument.DocumentElement;
InitializeRootNode(rootXmlElement);
CreateDecryptor(_rootNodeInfo, rootXmlElement);
var connectionTreeModel = new ConnectionTreeModel();
connectionTreeModel.AddRootNode(_rootNodeInfo);
var rootNodeInfo = InitializeRootNode(rootXmlElement);
_decryptor = CreateDecryptor(rootNodeInfo, rootXmlElement);
if (_confVersion > 1.3)
{
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString,
_rootNodeInfo.PasswordString.ConvertToSecureString()))
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, rootNodeInfo.PasswordString.ConvertToSecureString()))
{
return null;
}
@@ -76,12 +73,11 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
}
}
AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, _rootNodeInfo);
var credentialMap = new ConnectionToCredentialMap();
var rootNodes = AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, credentialMap);
var serializationResult = new SerializationResult(rootNodes, credentialMap);
if (!import)
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
return connectionTreeModel;
return serializationResult;
}
catch (Exception ex)
{
@@ -93,8 +89,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
private void LoadXmlConnectionData(string connections)
{
CreateDecryptor(new RootNodeInfo(RootNodeType.Connection));
connections = _decryptor.LegacyFullFileDecrypt(connections);
var legacyDecryptor = CreateDecryptor(new RootNodeInfo(RootNodeType.Connection));
connections = legacyDecryptor.LegacyFullFileDecrypt(connections);
_xmlDocument = new XmlDocument();
if (connections != "")
_xmlDocument.LoadXml(connections);
@@ -135,13 +131,16 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
);
}
private void InitializeRootNode(XmlElement connectionsRootElement)
private RootNodeInfo InitializeRootNode(XmlElement connectionsRootElement)
{
var rootNodeName = connectionsRootElement?.Attributes["Name"].Value.Trim();
_rootNodeInfo.Name = rootNodeName;
return new RootNodeInfo(RootNodeType.Connection)
{
Name = rootNodeName
};
}
private void CreateDecryptor(RootNodeInfo rootNodeInfo, XmlElement connectionsRootElement = null)
private XmlConnectionsDecryptor CreateDecryptor(RootNodeInfo rootNodeInfo, XmlElement connectionsRootElement = null)
{
if (_confVersion >= 2.6)
{
@@ -149,24 +148,27 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
var mode = connectionsRootElement.GetAttributeAsEnum<BlockCipherModes>("BlockCipherMode");
var keyDerivationIterations = connectionsRootElement.GetAttributeAsInt("KdfIterations");
_decryptor = new XmlConnectionsDecryptor(engine, mode, rootNodeInfo)
return new XmlConnectionsDecryptor(engine, mode, rootNodeInfo)
{
AuthenticationRequestor = AuthenticationRequestor,
KeyDerivationIterations = keyDerivationIterations
};
}
else
return new XmlConnectionsDecryptor(rootNodeInfo)
{
_decryptor = new XmlConnectionsDecryptor(_rootNodeInfo)
{AuthenticationRequestor = AuthenticationRequestor};
}
AuthenticationRequestor = AuthenticationRequestor
};
}
private void AddNodesFromXmlRecursive(XmlNode parentXmlNode, ContainerInfo parentContainer)
private List<ConnectionInfo> AddNodesFromXmlRecursive(XmlNode parentXmlNode, ConnectionToCredentialMap credentialMap)
{
try
{
if (!parentXmlNode.HasChildNodes) return;
if (!parentXmlNode.HasChildNodes)
return new List<ConnectionInfo>();
var children = new List<ConnectionInfo>();
foreach (XmlNode xmlNode in parentXmlNode.ChildNodes)
{
var nodeType = xmlNode.GetAttributeAsEnum("Type", TreeNodeType.Connection);
@@ -175,24 +177,27 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
switch (nodeType)
{
case TreeNodeType.Connection:
var connectionInfo = GetConnectionInfoFromXml(xmlNode);
parentContainer.AddChild(connectionInfo);
var connectionInfo = GetConnectionInfoFromXml(xmlNode, credentialMap);
children.Add(connectionInfo);
break;
case TreeNodeType.Container:
var containerInfo = new ContainerInfo();
if (_confVersion >= 0.9)
containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode));
containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode, credentialMap));
if (_confVersion >= 0.8)
{
containerInfo.IsExpanded = xmlNode.GetAttributeAsBool("Expanded");
}
parentContainer.AddChild(containerInfo);
AddNodesFromXmlRecursive(xmlNode, containerInfo);
var subChildren = AddNodesFromXmlRecursive(xmlNode, credentialMap);
subChildren.ForEach(info => containerInfo.AddChild(info));
children.Add(containerInfo);
break;
}
}
return children;
}
catch (Exception ex)
{
@@ -201,7 +206,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
}
}
private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode)
private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode, ConnectionToCredentialMap credentialMap)
{
if (xmlnode?.Attributes == null)
return null;
@@ -229,13 +234,21 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
: RDPResolutions.FitToWindow;
}
if (!Runtime.UseCredentialManager || _confVersion <= 2.6) // 0.2 - 2.6
if (_confVersion <= 2.6) // 0.2 - 2.6
{
#pragma warning disable 618
connectionInfo.Username = xmlnode.GetAttributeAsString("Username");
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
connectionInfo.Domain = xmlnode.GetAttributeAsString("Domain");
#pragma warning restore 618
var username = xmlnode.GetAttributeAsString("Username");
var domain = xmlnode.GetAttributeAsString("Domain");
var cred = new CredentialRecord
{
Title = domain.Length > 0 ? $"{domain}\\{username}" : username,
Username = username,
Domain = domain,
Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password")).ConvertToSecureString()
};
if (!_credentialComparer.Equals(cred, new NullCredentialRecord()))
connectionInfo.CredentialRecordId = cred.Id;
}
}
@@ -557,6 +570,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
connectionInfo.Inheritance.DisableMenuAnimations = xmlnode.GetAttributeAsBool("InheritDisableMenuAnimations");
connectionInfo.Inheritance.DisableCursorShadow = xmlnode.GetAttributeAsBool("InheritDisableCursorShadow");
connectionInfo.Inheritance.DisableCursorBlinking = xmlnode.GetAttributeAsBool("InheritDisableCursorBlinking");
connectionInfo.CredentialRecordId = Guid.TryParse(xmlnode.Attributes?["CredentialId"]?.Value, out var credId)
? credId
: Optional<Guid>.Empty;
connectionInfo.Inheritance.CredentialId = xmlnode.GetAttributeAsBool("InheritCredentialId");
}
}
catch (Exception ex)

View File

@@ -12,8 +12,7 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
{
public class XmlConnectionsSerializer : ISerializer<ConnectionTreeModel, string>,
ISerializer<ConnectionInfo, string>
public class XmlConnectionsSerializer : ISerializer<IConnectionTreeModel,string>, ISerializer<ConnectionInfo, string>
{
private readonly ICryptographyProvider _cryptographyProvider;
private readonly ISerializer<ConnectionInfo, XElement> _connectionNodeSerializer;
@@ -28,7 +27,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
_connectionNodeSerializer = connectionNodeSerializer;
}
public string Serialize(ConnectionTreeModel connectionTreeModel)
public string Serialize(IConnectionTreeModel connectionTreeModel)
{
var rootNode = (RootNodeInfo)connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
return SerializeConnectionsData(rootNode);

View File

@@ -9,29 +9,38 @@ namespace mRemoteNG.Config.Serializers.CredentialProviderSerializer
{
public class CredentialRepositoryListDeserializer
{
private readonly ISecureSerializer<IEnumerable<ICredentialRecord>, string> _serializer;
private readonly ISecureDeserializer<string, IEnumerable<ICredentialRecord>> _deserializer;
public CredentialRepositoryListDeserializer(
ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer,
ISecureDeserializer<string, IEnumerable<ICredentialRecord>> deserializer)
public IEnumerable<ICredentialRepository> Deserialize(string xml, IEnumerable<ICredentialRepositoryFactory> factories)
{
if (serializer == null)
throw new ArgumentNullException(nameof(serializer));
if (deserializer == null)
throw new ArgumentNullException(nameof(deserializer));
if (string.IsNullOrEmpty(xml))
return new ICredentialRepository[0];
_serializer = serializer;
_deserializer = deserializer;
}
public IEnumerable<ICredentialRepository> Deserialize(string xml)
{
if (string.IsNullOrEmpty(xml)) return new ICredentialRepository[0];
var xdoc = XDocument.Parse(xml);
var repoEntries = xdoc.Descendants("CredentialRepository");
var xmlRepoFactory = new XmlCredentialRepositoryFactory(_serializer, _deserializer);
return repoEntries.Select(xmlRepoFactory.Build);
return repoEntries
.Select(ParseConfigEntries)
.Select(config =>
factories
.FirstOrDefault(f => string.Equals(f.SupportsConfigType, config.TypeName))?
.Build(config));
}
public ICredentialRepositoryConfig ParseConfigEntries(XElement repositoryXElement)
{
var stringId = repositoryXElement.Attribute("Id")?.Value;
Guid.TryParse(stringId, out var id);
if (id.Equals(Guid.Empty))
id = Guid.NewGuid();
var config = new CredentialRepositoryConfig(id)
{
TypeName = repositoryXElement.Attribute("TypeName")?.Value,
Title = repositoryXElement.Attribute("Title")?.Value,
Source = repositoryXElement.Attribute("Source")?.Value
};
return config;
}
}
}

View File

@@ -0,0 +1,51 @@
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using System;
using System.Collections.Generic;
using System.Linq;
namespace mRemoteNG.Config.Serializers.CredentialSerializer
{
public class CredentialHarvester
{
private readonly IEqualityComparer<ICredentialRecord> _credentialComparer = new CredentialDomainUserPasswordComparer();
/// <summary>
/// Maps a <see cref="ConnectionInfo"/> (by its id) to the <see cref="ICredentialRecord"/>
/// object that was harvested
/// </summary>
/// <param name="harvestConfig"></param>
public ConnectionToCredentialMap Harvest<T>(HarvestConfig<T> harvestConfig)
{
if (harvestConfig == null)
throw new ArgumentNullException(nameof(harvestConfig));
var credentialMap = new ConnectionToCredentialMap();
foreach (var element in harvestConfig.ItemEnumerator())
{
var newCredential = new CredentialRecord
{
Title = harvestConfig.TitleSelector(element),
Username = harvestConfig.UsernameSelector(element),
Domain = harvestConfig.DomainSelector(element),
Password = harvestConfig.PasswordSelector(element)
};
if (!EntryHasSomeCredentialData(newCredential))
continue;
var connectionId = harvestConfig.ConnectionGuidSelector(element);
var existingCredential = credentialMap.Values.FirstOrDefault(record => _credentialComparer.Equals(newCredential, record));
credentialMap.Add(connectionId, existingCredential ?? newCredential);
}
return credentialMap;
}
private bool EntryHasSomeCredentialData(ICredentialRecord e)
{
return !_credentialComparer.Equals(e, new NullCredentialRecord());
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Security;
namespace mRemoteNG.Config.Serializers.CredentialSerializer
{
/// <summary>
/// Configuration for the <see cref="CredentialHarvester"/> to allow it to
/// iterate over and select values from any arbitrary data type. Each element
/// of type <see cref="T"/> represents an object that contains intermixed
/// connection and credential data.
/// </summary>
/// <typeparam name="T"></typeparam>
public class HarvestConfig<T>
{
/// <summary>
/// This will be called to produce a list of all objects
/// that should be iterated over.
/// </summary>
public Func<IEnumerable<T>> ItemEnumerator { get; set; }
/// <summary>
/// Given an item of type <see cref="T"/>, return
/// the <see cref="Guid"/> that represents the connection's unique ID
/// within mRemoteNG.
/// </summary>
public Func<T, Guid> ConnectionGuidSelector { get; set; }
/// <summary>
/// Given an item of type <see cref="T"/>, return a <see cref="string"/>
/// that represents what the associated credential's title should be.
/// </summary>
public Func<T, string> TitleSelector { get; set; }
/// <summary>
/// Given an item of type <see cref="T"/>, return a <see cref="string"/>
/// that represents what the associated credential's username should be.
/// </summary>
public Func<T, string> UsernameSelector { get; set; }
/// <summary>
/// Given an item of type <see cref="T"/>, return a <see cref="string"/>
/// that represents what the associated credential's domain should be.
/// </summary>
public Func<T, string> DomainSelector { get; set; }
/// <summary>
/// Given an item of type <see cref="T"/>, return a <see cref="SecureString"/>
/// that represents what the associated credential's password should be.
/// </summary>
public Func<T, SecureString> PasswordSelector { get; set; }
}
}

View File

@@ -6,7 +6,6 @@ using mRemoteNG.Config.Import;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;

View File

@@ -1,59 +1,68 @@
using System;
using System.IO;
using System.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security;
using System.Xml;
using mRemoteNG.Credential;
using mRemoteNG.Security;
namespace mRemoteNG.Config.Serializers.MiscSerializers
{
public class PuttyConnectionManagerDeserializer : IDeserializer<string, ConnectionTreeModel>
public class PuttyConnectionManagerDeserializer
{
public ConnectionTreeModel Deserialize(string puttycmConnectionsXml)
public SerializationResult Deserialize(string puttycmConnectionsXml)
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
connectionTreeModel.AddRootNode(root);
var result = new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(puttycmConnectionsXml);
var configurationNode = xmlDocument.SelectSingleNode("/configuration");
var rootNodes = configurationNode?.SelectNodes("./root");
if (rootNodes == null) return connectionTreeModel;
foreach (XmlNode rootNode in rootNodes)
var rootXmlNode = configurationNode?.SelectSingleNode("./root");
if (rootXmlNode == null)
return result;
var rootContainer = ReadContainerProperties(rootXmlNode);
result.ConnectionRecords.Add(rootContainer);
foreach (XmlNode node in rootXmlNode.ChildNodes)
{
ImportRootOrContainer(rootNode, root);
rootContainer.AddChild(ImportRecursive(node, result.ConnectionToCredentialMap));
}
return connectionTreeModel;
return result;
}
private void ImportRootOrContainer(XmlNode xmlNode, ContainerInfo parentContainer)
private ContainerInfo ImportRecursive(XmlNode xmlNode, ConnectionToCredentialMap credentialMap)
{
VerifyNodeType(xmlNode);
var newContainer = ImportContainer(xmlNode, parentContainer);
var newContainer = ReadContainerProperties(xmlNode);
var childNodes = xmlNode.SelectNodes("./*");
if (childNodes == null) return;
if (childNodes == null)
return newContainer;
foreach (XmlNode childNode in childNodes)
{
switch (childNode.Name)
{
case "container":
ImportRootOrContainer(childNode, newContainer);
newContainer.AddChild(ImportRecursive(childNode, credentialMap));
break;
case "connection":
ImportConnection(childNode, newContainer);
newContainer.AddChild(ImportConnection(childNode, credentialMap));
break;
default:
throw (new FileFormatException($"Unrecognized child node ({childNode.Name})."));
throw new FileFormatException($"Unrecognized child node ({childNode.Name}).");
}
}
return newContainer;
}
private void VerifyNodeType(XmlNode xmlNode)
@@ -82,25 +91,28 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
}
}
private ContainerInfo ImportContainer(XmlNode containerNode, ContainerInfo parentContainer)
private ContainerInfo ReadContainerProperties(XmlNode containerNode)
{
var containerInfo = new ContainerInfo
{
Name = containerNode.Attributes?["name"].Value,
IsExpanded = bool.Parse(containerNode.Attributes?["expanded"].InnerText ?? "false")
};
parentContainer.AddChild(containerInfo);
return containerInfo;
}
private void ImportConnection(XmlNode connectionNode, ContainerInfo parentContainer)
private ConnectionInfo ImportConnection(XmlNode connectionNode, ConnectionToCredentialMap credentialMap)
{
var connectionNodeType = connectionNode.Attributes?["type"].Value;
if (string.Compare(connectionNodeType, "PuTTY", StringComparison.OrdinalIgnoreCase) != 0)
throw (new FileFormatException($"Unrecognized connection node type ({connectionNodeType})."));
var connectionInfo = ConnectionInfoFromXml(connectionNode);
parentContainer.AddChild(connectionInfo);
var cred = CredentialFromXml(connectionNode);
connectionInfo.CredentialRecordId = cred.Id;
credentialMap.Add(Guid.Parse(connectionInfo.ConstantID), cred);
return connectionInfo;
}
private ConnectionInfo ConnectionInfoFromXml(XmlNode xmlNode)
@@ -129,9 +141,6 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
// ./commandline
connectionInfo.Description = connectionInfoNode.SelectSingleNode("./description")?.InnerText;
var loginNode = xmlNode.SelectSingleNode("./login");
connectionInfo.Username = loginNode?.SelectSingleNode("login")?.InnerText;
connectionInfo.Password = loginNode?.SelectSingleNode("password")?.InnerText;
// ./prompt
// ./timeout/connectiontimeout
@@ -151,5 +160,19 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
return connectionInfo;
}
private ICredentialRecord CredentialFromXml(XmlNode xmlNode)
{
var loginNode = xmlNode.SelectSingleNode("./login");
var username = loginNode?.SelectSingleNode("login")?.InnerText ?? "";
return new CredentialRecord
{
Title = username,
Username = username,
Domain = "",
Password = loginNode?.SelectSingleNode("password")?.InnerText.ConvertToSecureString() ?? new SecureString()
};
}
}
}

View File

@@ -1,21 +1,21 @@
using System;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using System.Collections.Generic;
using mRemoteNG.Credential;
namespace mRemoteNG.Config.Serializers.MiscSerializers
{
public class RemoteDesktopConnectionDeserializer : IDeserializer<string, ConnectionTreeModel>
public class RemoteDesktopConnectionDeserializer
{
// .rdp file schema: https://technet.microsoft.com/en-us/library/ff393699(v=ws.10).aspx
public ConnectionTreeModel Deserialize(string rdcFileContent)
public SerializationResult Deserialize(string rdcFileContent)
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
connectionTreeModel.AddRootNode(root);
var connectionInfo = new ConnectionInfo();
var username = "";
var domain = "";
foreach (var line in rdcFileContent.Split(Environment.NewLine.ToCharArray()))
{
var parts = line.Split(new[] { ':' }, 3);
@@ -24,21 +24,42 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
continue;
}
var key = parts[0].Trim();
var propertyName = parts[0].Trim().ToLowerInvariant();
var value = parts[2].Trim();
SetConnectionInfoParameter(connectionInfo, key, value);
SetConnectionInfoParameter(connectionInfo, propertyName, value);
if (propertyName.Equals("username"))
username = value;
if (propertyName.Equals("domain"))
domain = value;
}
root.AddChild(connectionInfo);
var serializationResult = new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
serializationResult.ConnectionRecords.Add(connectionInfo);
return connectionTreeModel;
if (username.Length > 0 || domain.Length > 0)
{
var cred = new CredentialRecord
{
Title = domain.Length > 0 ? $"{domain}\\" : "" + username,
Domain = domain,
Username = username
};
serializationResult.ConnectionToCredentialMap.Add(Guid.Parse(connectionInfo.ConstantID), cred);
connectionInfo.CredentialRecordId = cred.Id;
}
return serializationResult;
}
private void SetConnectionInfoParameter(ConnectionInfo connectionInfo, string key, string value)
{
switch (key.ToLower())
switch (key)
{
case "full address":
var uri = new Uri("dummyscheme" + Uri.SchemeDelimiter + value);
@@ -50,12 +71,6 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
case "server port":
connectionInfo.Port = Convert.ToInt32(value);
break;
case "username":
connectionInfo.Username = value;
break;
case "domain":
connectionInfo.Domain = value;
break;
case "session bpp":
switch (value)
{

View File

@@ -1,41 +1,44 @@
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Container;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Container;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.Credential;
using mRemoteNG.Security;
using mRemoteNG.Tools;
namespace mRemoteNG.Config.Serializers.MiscSerializers
{
public class RemoteDesktopConnectionManagerDeserializer : IDeserializer<string, ConnectionTreeModel>
public class RemoteDesktopConnectionManagerDeserializer
{
private static int _schemaVersion; /* 1 = RDCMan v2.2
3 = RDCMan v2.7 */
// 1 = RDCMan v2.2
// 3 = RDCMan v2.7
private static int _schemaVersion;
public ConnectionTreeModel Deserialize(string rdcmConnectionsXml)
public SerializationResult Deserialize(string rdcmConnectionsXml)
{
var connectionTreeModel = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var serializationResult = new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(rdcmConnectionsXml);
var rdcManNode = xmlDocument.SelectSingleNode("/RDCMan");
VerifySchemaVersion(rdcManNode);
VerifyFileVersion(rdcManNode);
var fileNode = rdcManNode?.SelectSingleNode("./file");
ImportFileOrGroup(fileNode, root);
var importedItem = ImportFileOrGroup(fileNode, serializationResult.ConnectionToCredentialMap);
connectionTreeModel.AddRootNode(root);
return connectionTreeModel;
serializationResult.ConnectionRecords.Add(importedItem);
return serializationResult;
}
private static void VerifySchemaVersion(XmlNode rdcManNode)
@@ -80,28 +83,46 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
}
}
private static void ImportFileOrGroup(XmlNode xmlNode, ContainerInfo parentContainer)
private static ContainerInfo ImportFileOrGroup(XmlNode xmlNode, ConnectionToCredentialMap credentialMap)
{
var newContainer = ImportContainer(xmlNode, parentContainer);
var newContainer = ImportContainer(xmlNode);
var childNodes = xmlNode.SelectNodes("./group|./server");
if (childNodes == null) return;
if (childNodes == null)
return newContainer;
foreach (XmlNode childNode in childNodes)
{
ConnectionInfo newChild = null;
// ReSharper disable once SwitchStatementMissingSomeCases
switch (childNode.Name)
{
case "group":
ImportFileOrGroup(childNode, newContainer);
newChild = ImportFileOrGroup(childNode, credentialMap);
break;
case "server":
ImportServer(childNode, newContainer);
newChild = ConnectionInfoFromXml(childNode);
break;
}
if (newChild == null)
return newContainer;
newContainer.AddChild(newChild);
var cred = ParseCredentials(childNode);
if (!cred.Any())
continue;
newChild.CredentialRecordId = cred.First().Id;
credentialMap.Add(Guid.Parse(newChild.ConstantID), cred.First());
}
return newContainer;
}
private static ContainerInfo ImportContainer(XmlNode containerPropertiesNode, ContainerInfo parentContainer)
private static ContainerInfo ImportContainer(XmlNode containerPropertiesNode)
{
if (_schemaVersion == 1)
{
@@ -121,16 +142,9 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.NewFolder;
if (bool.TryParse(containerPropertiesNode?.SelectSingleNode("./expanded")?.InnerText, out var expanded))
newContainer.IsExpanded = expanded;
parentContainer.AddChild(newContainer);
return newContainer;
}
private static void ImportServer(XmlNode serverNode, ContainerInfo parentContainer)
{
var newConnectionInfo = ConnectionInfoFromXml(serverNode);
parentContainer.AddChild(newConnectionInfo);
}
private static ConnectionInfo ConnectionInfoFromXml(XmlNode xmlNode)
{
var connectionInfo = new ConnectionInfo {Protocol = ProtocolType.RDP};
@@ -153,25 +167,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty;
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
if (logonCredentialsNode?.Attributes?["inherit"]?.Value == "None")
{
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText ?? string.Empty;
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords
{
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
? passwordNode.InnerText
: DecryptRdcManPassword(passwordNode?.InnerText);
}
else
{
connectionInfo.Password = DecryptRdcManPassword(passwordNode?.InnerText);
}
connectionInfo.Domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
}
else
if (logonCredentialsNode?.Attributes?["inherit"]?.Value != "None")
{
connectionInfo.Inheritance.Username = true;
connectionInfo.Inheritance.Password = true;
@@ -205,9 +201,9 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
connectionInfo.RDGatewayUsername = gatewaySettingsNode.SelectSingleNode("./userName")?.InnerText ?? string.Empty;
var passwordNode = gatewaySettingsNode.SelectSingleNode("./password");
connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
? passwordNode.InnerText
: DecryptRdcManPassword(passwordNode?.InnerText);
connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
? passwordNode.InnerText
: DecryptRdcManPassword(passwordNode?.InnerText).ConvertToUnsecureString();
connectionInfo.RDGatewayDomain = gatewaySettingsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
// ./logonMethod
@@ -349,22 +345,45 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
return connectionInfo;
}
private static string DecryptRdcManPassword(string ciphertext)
private static Optional<ICredentialRecord> ParseCredentials(XmlNode xmlNode)
{
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
if (logonCredentialsNode?.Attributes?["inherit"]?.Value != "None")
return Optional<ICredentialRecord>.Empty;
var username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText ?? "";
var domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText ?? "";
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
var creds = new CredentialRecord
{
Title = domain.Length > 0 ? $"{domain}\\{username}" : $"{username}",
Username = username,
Domain = domain,
Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
? passwordNode.InnerText.ConvertToSecureString()
: DecryptRdcManPassword(passwordNode?.InnerText)
};
return creds;
}
private static SecureString DecryptRdcManPassword(string ciphertext)
{
if (string.IsNullOrEmpty(ciphertext))
return string.Empty;
return new SecureString();
try
{
var plaintextData = ProtectedData.Unprotect(Convert.FromBase64String(ciphertext), new byte[] { },
DataProtectionScope.LocalMachine);
var charArray = Encoding.Unicode.GetChars(plaintextData);
return new string(charArray);
return Encoding.Unicode.GetString(plaintextData).ConvertToSecureString();
}
catch (Exception /*ex*/)
{
//Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true);
return string.Empty;
return new SecureString();
}
}
}

View File

@@ -0,0 +1,23 @@
using mRemoteNG.Connection;
using mRemoteNG.Tools;
using System.Collections.Generic;
namespace mRemoteNG.Config.Serializers
{
/// <summary>
/// Represents the connections and credentials found during a deserialization.
/// </summary>
public class SerializationResult
{
public List<ConnectionInfo> ConnectionRecords { get; }
public ConnectionToCredentialMap ConnectionToCredentialMap { get; }
public SerializationResult(
List<ConnectionInfo> connectionRecords,
ConnectionToCredentialMap connectionToCredentialMap)
{
ConnectionRecords = connectionRecords.ThrowIfNull(nameof(connectionRecords));
ConnectionToCredentialMap = connectionToCredentialMap.ThrowIfNull(nameof(connectionToCredentialMap));
}
}
}

View File

@@ -3,7 +3,6 @@ using mRemoteNG.App.Info;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Messages;
using System;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.Config.Serializers.Versioning
{

View File

@@ -0,0 +1,109 @@
using mRemoteNG.App;
using mRemoteNG.Config.Serializers.CredentialSerializer;
using mRemoteNG.Connection;
using mRemoteNG.Credential;
using mRemoteNG.Security;
using mRemoteNG.Security.Authentication;
using mRemoteNG.Security.Factories;
using mRemoteNG.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
namespace mRemoteNG.Config.Serializers.Versioning
{
public class XmlCredentialManagerUpgrader
{
private readonly XmlConnectionsDeserializer _deserializer;
public XmlCredentialManagerUpgrader(XmlConnectionsDeserializer decoratedDeserializer)
{
_deserializer = decoratedDeserializer.ThrowIfNull(nameof(decoratedDeserializer));
}
public SerializationResult Deserialize(string serializedData, ConnectionToCredentialMap upgradeMap)
{
var serializedDataAsXDoc = EnsureConnectionXmlElementsHaveIds(serializedData);
var serializedDataWithIds = $"{serializedDataAsXDoc.Declaration}{serializedDataAsXDoc}";
var serializationResult = _deserializer.Deserialize(serializedDataWithIds);
if (upgradeMap != null)
ApplyCredentialMapping(upgradeMap, serializationResult.ConnectionRecords.FlattenConnectionTree());
return serializationResult;
}
private XDocument EnsureConnectionXmlElementsHaveIds(string serializedData)
{
var xdoc = XDocument.Parse(serializedData);
xdoc.Declaration = new XDeclaration("1.0", "utf-8", null);
var adapter = new ConfConsEnsureConnectionsHaveIds();
adapter.EnsureElementsHaveIds(xdoc);
return xdoc;
}
public ConnectionToCredentialMap UpgradeUserFilesForCredentialManager(XDocument xdoc)
{
if (!CredentialManagerUpgradeNeeded(xdoc))
{
return null;
}
var cryptoProvider = new CryptoProviderFactoryFromXml(xdoc.Root).Build();
var encryptedValue = xdoc.Root?.Attribute("Protected")?.Value;
var auth = new PasswordAuthenticator(cryptoProvider, encryptedValue, () => MiscTools.PasswordDialog("", false));
if (!auth.Authenticate(Runtime.EncryptionKey))
throw new Exception("Could not authenticate");
var keyForOldConnectionFile = auth.LastAuthenticatedPassword;
var preCredManagerXmlHarvestConfig = new HarvestConfig<XElement>
{
ItemEnumerator = () => xdoc.Descendants("Node"),
ConnectionGuidSelector = e =>
{
Guid.TryParse(e.Attribute("Id")?.Value, out var connectionId);
return connectionId;
},
UsernameSelector = e => e.Attribute("Username")?.Value,
DomainSelector = e => e.Attribute("Domain")?.Value,
PasswordSelector = e => cryptoProvider.Decrypt(e.Attribute("Password")?.Value, keyForOldConnectionFile).ConvertToSecureString(),
TitleSelector = e => $"{e.Attribute("Domain")?.Value}{(string.IsNullOrEmpty(e.Attribute("Domain")?.Value) ? "" : "\\")}{e.Attribute("Username")?.Value}"
};
var credentialHarvester = new CredentialHarvester();
var harvestedCredentials = credentialHarvester.Harvest(preCredManagerXmlHarvestConfig);
return harvestedCredentials;
}
/// <summary>
/// If any connections in the xml contain a Username/Domain/Password field, we need to upgrade
/// it to be compatible with the credential manager.
/// </summary>
/// <param name="xdoc"></param>
public static bool CredentialManagerUpgradeNeeded(XContainer xdoc)
{
return xdoc
.Descendants("Node")
.Any(n =>
n.Attribute("Username") != null ||
n.Attribute("Domain") != null ||
n.Attribute("Password") != null);
}
private void ApplyCredentialMapping(IDictionary<Guid, ICredentialRecord> map, IEnumerable<AbstractConnectionRecord> connectionRecords)
{
foreach (var connectionInfo in connectionRecords)
{
Guid.TryParse(connectionInfo.ConstantID, out var id);
if (map.ContainsKey(id))
connectionInfo.CredentialRecordId = map[id].Id.ToOptional();
}
}
}
}

View File

@@ -77,9 +77,6 @@ namespace mRemoteNG.Config.Settings
if (persistString == typeof(ErrorAndInfoWindow).ToString())
return Windows.ErrorsForm;
if (persistString == typeof(ScreenshotManagerWindow).ToString())
return Windows.ScreenshotForm;
}
catch (Exception ex)
{

View File

@@ -1,13 +1,18 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Connection.Protocol.Http;
using mRemoteNG.Connection.Protocol.RDP;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Credential;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools.Attributes;
using mRemoteNG.UI.Controls.Adapters;
namespace mRemoteNG.Connection
@@ -22,6 +27,7 @@ namespace mRemoteNG.Connection
private string _panel;
private string _hostname;
private Optional<Guid> _credentialRecordId = new Optional<Guid>();
private string _username = "";
private string _password = "";
private string _domain = "";
@@ -160,6 +166,7 @@ namespace mRemoteNG.Connection
set => SetField(ref _port, value, "Port");
}
[Browsable(false)]
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Username)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionUsername)),
@@ -170,6 +177,7 @@ namespace mRemoteNG.Connection
set => SetField(ref _username, Settings.Default.DoNotTrimUsername ? value : value?.Trim(), "Username");
}
[Browsable(false)]
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Password)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionPassword)),
@@ -181,6 +189,7 @@ namespace mRemoteNG.Connection
set => SetField(ref _password, value, "Password");
}
[Browsable(false)]
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Domain)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionDomain)),
@@ -211,6 +220,26 @@ namespace mRemoteNG.Connection
get => GetPropertyValue("SSHTunnelConnectionName", _sshTunnelConnectionName).Trim();
set => SetField(ref _sshTunnelConnectionName, value?.Trim(), "SSHTunnelConnectionName");
}
[Browsable(false)]
public virtual Optional<Guid> CredentialRecordId
{
get => GetPropertyValue(nameof(CredentialRecordId), _credentialRecordId);
set => SetField(ref _credentialRecordId, value ?? Optional<Guid>.Empty, nameof(CredentialRecordId));
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Credentials)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionCredentials)),
AttributeUsedInAllProtocolsExcept()]
[Editor(typeof(CredentialRecordListAdaptor), typeof(UITypeEditor))]
[TypeConverter(typeof(ExpandableObjectConverter))]
public virtual ICredentialRecord CredentialRecord
{
// TODO: this static ref to the cred service makes testing difficult. refactor it to allow easy mocking
get => Runtime.CredentialService.GetEffectiveCredentialRecord(CredentialRecordId, false).FirstOrDefault();
set => CredentialRecordId = Optional<Guid>.FromNullable(value?.Id);
}
#endregion
#region Protocol
@@ -589,7 +618,7 @@ namespace mRemoteNG.Connection
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Redirect)),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.DiskDrives)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectDrives)),
TypeConverter(typeof(MiscTools.YesNoTypeConverter)),
AttributeUsedInProtocol(ProtocolType.RDP)]
@@ -634,7 +663,7 @@ namespace mRemoteNG.Connection
}
[LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Redirect)),
LocalizedAttributes.LocalizedDisplayName(nameof(Language.SmartCard)),
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectSmartCards)),
TypeConverter(typeof(MiscTools.YesNoTypeConverter)),
AttributeUsedInProtocol(ProtocolType.RDP)]

View File

@@ -15,7 +15,6 @@ using mRemoteNG.Connection.Protocol.Telnet;
using mRemoteNG.Connection.Protocol.VNC;
using mRemoteNG.Container;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tree;
@@ -136,22 +135,24 @@ namespace mRemoteNG.Connection
return filteredProperties;
}
public virtual IEnumerable<PropertyInfo> GetSerializableProperties()
{
var excludedProperties = new[]
{
"Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections",
"IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect"
};
public virtual IEnumerable<PropertyInfo> GetSerializableProperties()
{
var excludedProperties = new[] {
nameof(Parent), nameof(Name), nameof(Hostname), nameof(Port),
nameof(Username), nameof(Domain), nameof(Password),
nameof(Inheritance), nameof(OpenConnections),
nameof(IsContainer), nameof(IsDefault), nameof(ConstantID),
nameof(IsQuickConnect), nameof(PleaseConnect), nameof(CredentialRecord)
};
return GetProperties(excludedProperties);
}
return GetProperties(excludedProperties);
}
public virtual void SetParent(ContainerInfo newParent)
{
public virtual void SetParent(ContainerInfo newParent)
{
RemoveParent();
newParent?.AddChild(this);
}
newParent?.AddChild(this);
}
public void RemoveParent()
{

View File

@@ -2,7 +2,6 @@
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection
@@ -49,7 +48,13 @@ namespace mRemoteNG.Connection
#endregion
#region Connection
#region
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 3),
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.Credentials)),
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionCredentials)),
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
public bool CredentialId { get; set; }
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 3),
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.Username)),

View File

@@ -6,9 +6,9 @@ using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Panels;
using mRemoteNG.Credential;
using mRemoteNG.UI.Tabs;
using mRemoteNG.UI.Window;
using WeifenLuo.WinFormsUI.Docking;
@@ -20,6 +20,12 @@ namespace mRemoteNG.Connection
{
private readonly PanelAdder _panelAdder = new PanelAdder();
private readonly List<string> _activeConnections = new List<string>();
private readonly CredentialService _credentialService;
public ConnectionInitiator(CredentialService credentialService)
{
_credentialService = credentialService;
}
public IEnumerable<string> ActiveConnections => _activeConnections;

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App;
@@ -11,9 +13,9 @@ using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Putty;
using mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Credential;
using mRemoteNG.Messages;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.Security;
using mRemoteNG.Tools;
using mRemoteNG.Tree;
@@ -22,7 +24,7 @@ using mRemoteNG.UI;
namespace mRemoteNG.Connection
{
public class ConnectionsService
public class ConnectionsService : IConnectionsService
{
private static readonly object SaveLock = new object();
private readonly PuttySessionsManager _puttySessionsManager;
@@ -31,6 +33,7 @@ namespace mRemoteNG.Connection
private bool _batchingSaves = false;
private bool _saveRequested = false;
private bool _saveAsyncRequested = false;
private readonly ICredentialService _credentialService;
public bool IsConnectionsFileLoaded { get; set; }
public bool UsingDatabase { get; private set; }
@@ -38,18 +41,18 @@ namespace mRemoteNG.Connection
public RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
public DateTime LastSqlUpdate { get; set; }
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
public IConnectionTreeModel ConnectionTreeModel { get; private set; } = new ConnectionTreeModel();
public ConnectionsService(PuttySessionsManager puttySessionsManager)
public ConnectionsService(PuttySessionsManager puttySessionsManager, ICredentialService credentialService)
{
if (puttySessionsManager == null)
throw new ArgumentNullException(nameof(puttySessionsManager));
_puttySessionsManager = puttySessionsManager;
_puttySessionsManager = puttySessionsManager.ThrowIfNull(nameof(puttySessionsManager));
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));
var path = SettingsFileInfo.SettingsPath;
_localConnectionPropertiesDataProvider =
new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
_puttySessionsManager.RootPuttySessionsNodes.ForEach(node => ConnectionTreeModel.AddRootNode(node));
}
public void NewConnectionsFile(string filename)
@@ -57,10 +60,9 @@ namespace mRemoteNG.Connection
try
{
filename.ThrowIfNullOrEmpty(nameof(filename));
var newConnectionsModel = new ConnectionTreeModel();
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
LoadConnections(false, false, filename);
ConnectionTreeModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
SaveConnections(ConnectionTreeModel, false, new SaveFilter(), filename, true);
LoadConnections(false, filename);
}
catch (Exception ex)
{
@@ -124,22 +126,21 @@ namespace mRemoteNG.Connection
/// <param name="useDatabase"></param>
/// <param name="import"></param>
/// <param name="connectionFileName"></param>
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
public void LoadConnections(bool useDatabase, string connectionFileName)
{
var oldConnectionTreeModel = ConnectionTreeModel;
var oldIsUsingDatabaseValue = UsingDatabase;
var connectionLoader = useDatabase
? (IConnectionsLoader)new SqlConnectionsLoader(_localConnectionPropertiesSerializer,
_localConnectionPropertiesDataProvider)
: new XmlConnectionsLoader(connectionFileName);
: new XmlConnectionsLoader(connectionFileName, _credentialService, this);
var newConnectionTreeModel = connectionLoader.Load();
var serializationResult = connectionLoader.Load();
if (useDatabase)
LastSqlUpdate = DateTime.Now;
if (newConnectionTreeModel == null)
if (serializationResult == null)
{
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed",
IsConnectionsFileLoaded);
@@ -150,16 +151,17 @@ namespace mRemoteNG.Connection
ConnectionFileName = connectionFileName;
UsingDatabase = useDatabase;
if (!import)
{
_puttySessionsManager.AddSessions();
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
}
if (ConnectionTreeModel.RootNodes.Any())
ConnectionTreeModel.RemoveRootNode(ConnectionTreeModel.RootNodes.First());
var rootNode = new RootNodeInfo(RootNodeType.Connection);
rootNode.AddChildRange(serializationResult.ConnectionRecords);
ConnectionTreeModel.AddRootNode(rootNode);
ConnectionTreeModel = newConnectionTreeModel;
UpdateCustomConsPathSetting(connectionFileName);
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue,
useDatabase, connectionFileName);
// TODO: fix this call
RaiseConnectionsLoadedEvent(new List<ConnectionInfo>(), new List<ConnectionInfo>(),
oldIsUsingDatabaseValue, useDatabase, connectionFileName);
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
$"Connections loaded using {connectionLoader.GetType().Name}");
}
@@ -225,12 +227,13 @@ namespace mRemoteNG.Connection
/// Optional. The name of the property that triggered
/// this save.
/// </param>
public void SaveConnections(ConnectionTreeModel connectionTreeModel,
bool useDatabase,
SaveFilter saveFilter,
string connectionFileName,
bool forceSave = false,
string propertyNameTrigger = "")
public void SaveConnections(
IConnectionTreeModel connectionTreeModel,
bool useDatabase,
SaveFilter saveFilter,
string connectionFileName,
bool forceSave = false,
string propertyNameTrigger = "")
{
if (connectionTreeModel == null)
return;
@@ -252,9 +255,8 @@ namespace mRemoteNG.Connection
var previouslyUsingDatabase = UsingDatabase;
var saver = useDatabase
? (ISaver<ConnectionTreeModel>)new SqlConnectionsSaver(saveFilter,
_localConnectionPropertiesSerializer,
_localConnectionPropertiesDataProvider)
? (ISaver<IConnectionTreeModel>)new SqlConnectionsSaver(saveFilter, _localConnectionPropertiesSerializer,
_localConnectionPropertiesDataProvider)
: new XmlConnectionsSaver(connectionFileName, saveFilter);
saver.Save(connectionTreeModel, propertyNameTrigger);
@@ -357,31 +359,22 @@ namespace mRemoteNG.Connection
public event EventHandler<ConnectionsLoadedEventArgs> ConnectionsLoaded;
public event EventHandler<ConnectionsSavedEventArgs> ConnectionsSaved;
private void RaiseConnectionsLoadedEvent(Optional<ConnectionTreeModel> previousTreeModel,
ConnectionTreeModel newTreeModel,
bool previousSourceWasDatabase,
bool newSourceIsDatabase,
string newSourcePath)
private void RaiseConnectionsLoadedEvent(List<ConnectionInfo> removedConnections, List<ConnectionInfo> addedConnections,
bool previousSourceWasDatabase, bool newSourceIsDatabase,
string newSourcePath)
{
ConnectionsLoaded?.Invoke(this, new ConnectionsLoadedEventArgs(
previousTreeModel,
newTreeModel,
removedConnections,
addedConnections,
previousSourceWasDatabase,
newSourceIsDatabase,
newSourcePath));
}
private void RaiseConnectionsSavedEvent(ConnectionTreeModel modelThatWasSaved,
bool previouslyUsingDatabase,
bool usingDatabase,
string connectionFileName)
private void RaiseConnectionsSavedEvent(IConnectionTreeModel modelThatWasSaved, bool previouslyUsingDatabase, bool usingDatabase, string connectionFileName)
{
ConnectionsSaved?.Invoke(this,
new ConnectionsSavedEventArgs(modelThatWasSaved, previouslyUsingDatabase,
usingDatabase,
connectionFileName));
ConnectionsSaved?.Invoke(this, new ConnectionsSavedEventArgs(modelThatWasSaved, previouslyUsingDatabase, usingDatabase, connectionFileName));
}
#endregion
}
}

View File

@@ -67,8 +67,11 @@ namespace mRemoteNG.Connection
throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found.");
// ensure value is of correct type
var value = Convert.ChangeType(property.GetValue(Instance, null),
propertyFromDestination.PropertyType);
var value = property.PropertyType == propertyFromDestination.PropertyType
? property.GetValue(Instance, null)
: propertyFromDestination.PropertyType == typeof(string)
? property.GetValue(Instance, null).ToString()
: Convert.ChangeType(property.GetValue(Instance, null), propertyFromDestination.PropertyType);
propertyFromDestination.SetValue(destinationInstance, value, null);
}

View File

@@ -0,0 +1,78 @@
using System;
using mRemoteNG.Config.Connections;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Security;
using mRemoteNG.Tree;
namespace mRemoteNG.Connection
{
public interface IConnectionsService
{
IConnectionTreeModel ConnectionTreeModel { get; }
void NewConnectionsFile(string filename);
ConnectionInfo CreateQuickConnect(string connectionString, ProtocolType protocol);
/// <summary>
/// Load connections from a source. <see cref="connectionFileName"/> is ignored if
/// <see cref="useDatabase"/> is true.
/// </summary>
/// <param name="useDatabase"></param>
/// <param name="import"></param>
/// <param name="connectionFileName"></param>
void LoadConnections(bool useDatabase, string connectionFileName);
/// <summary>
/// When turned on, calls to <see cref="ConnectionsService.SaveConnections()"/> or
/// <see cref="ConnectionsService.SaveConnectionsAsync"/> will not immediately execute.
/// Instead, they will be deferred until <see cref="ConnectionsService.EndBatchingSaves"/>
/// is called.
/// </summary>
void BeginBatchingSaves();
/// <summary>
/// Immediately executes a single <see cref="ConnectionsService.SaveConnections()"/> or
/// <see cref="ConnectionsService.SaveConnectionsAsync"/> if one has been requested
/// since calling <see cref="ConnectionsService.BeginBatchingSaves"/>.
/// </summary>
void EndBatchingSaves();
/// <summary>
/// Saves the currently loaded <see cref="ConnectionsService.ConnectionTreeModel"/> with
/// no <see cref="SaveFilter"/>.
/// </summary>
void SaveConnections();
/// <summary>
/// Saves the given <see cref="ConnectionsService.ConnectionTreeModel"/>.
/// If <see cref="useDatabase"/> is true, <see cref="connectionFileName"/> is ignored
/// </summary>
/// <param name="connectionTreeModel"></param>
/// <param name="useDatabase"></param>
/// <param name="saveFilter"></param>
/// <param name="connectionFileName"></param>
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
/// <param name="propertyNameTrigger">
/// Optional. The name of the property that triggered
/// this save.
/// </param>
void SaveConnections(
IConnectionTreeModel connectionTreeModel,
bool useDatabase,
SaveFilter saveFilter,
string connectionFileName,
bool forceSave = false,
string propertyNameTrigger = "");
/// <summary>
/// Save the currently loaded connections asynchronously
/// </summary>
/// <param name="propertyNameTrigger">
/// Optional. The name of the property that triggered
/// this save.
/// </param>
void SaveConnectionsAsync(string propertyNameTrigger = "");
event EventHandler<ConnectionsLoadedEventArgs> ConnectionsLoaded;
event EventHandler<ConnectionsSavedEventArgs> ConnectionsSaved;
}
}

View File

@@ -1,34 +0,0 @@
// Copyright © 2013 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
using CefSharp;
using System;
namespace mRemoteNG.Connection.Protocol.Http
{
public class DownloadHandler : IDownloadHandler
{
public event EventHandler<DownloadItem> OnBeforeDownloadFired;
public event EventHandler<DownloadItem> OnDownloadUpdatedFired;
public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
OnBeforeDownloadFired?.Invoke(this, downloadItem);
if (!callback.IsDisposed)
{
using (callback)
{
callback.Continue(downloadItem.SuggestedFileName, showDialog: true);
}
}
}
public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
OnDownloadUpdatedFired?.Invoke(this, downloadItem);
}
}
}

View File

@@ -1,68 +0,0 @@
using CefSharp;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
namespace mRemoteNG.Connection.Protocol.Http
{
partial class RequestHandler : IRequestHandler
{
public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
{
return false;
}
public IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
return null;
}
public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
{
if (request.Url.StartsWith(Cef.CefCommitHash))
{
return false;
}
else
{
Process.Start(request.Url);
return true;
}
}
public void OnDocumentAvailableInMainFrame(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
}
public bool OnCertificateError(IWebBrowser chromiumWebBrowser, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback)
{
return false;
}
public bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
{
return false;
}
public void OnPluginCrashed(IWebBrowser chromiumWebBrowser, IBrowser browser, string pluginPath)
{
}
public bool OnQuotaRequest(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, long newSize, IRequestCallback callback)
{
return true;
}
public void OnRenderProcessTerminated(IWebBrowser chromiumWebBrowser, IBrowser browser, CefTerminationStatus status)
{
}
public void OnRenderViewReady(IWebBrowser chromiumWebBrowser, IBrowser browser)
{
}
public bool OnSelectClientCertificate(IWebBrowser chromiumWebBrowser, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
{
return true;
}
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using Microsoft.Web.WebView2.WinForms;
using mRemoteNG.Tools;
using mRemoteNG.App;
using mRemoteNG.Resources.Language;
using mRemoteNG.UI.Tabs;
@@ -14,24 +12,22 @@ namespace mRemoteNG.Connection.Protocol.Http
{
#region Private Properties
private Control wBrowser;
private Control _wBrowser;
private string _tabTitle;
protected string httpOrS;
protected int defaultPort;
private string tabTitle;
private bool browserInitialised = false;
private bool connectCalled = false;
#endregion
#region Public Methods
protected HTTPBase(RenderingEngine RenderingEngine)
protected HTTPBase(RenderingEngine renderingEngine)
{
try
{
if (RenderingEngine == RenderingEngine.CEF)
if (renderingEngine == RenderingEngine.EdgeChromium)
{
Control = new ChromiumWebBrowser("about:blank")
Control = new WebView2()
{
Dock = DockStyle.Fill,
};
@@ -53,33 +49,26 @@ namespace mRemoteNG.Connection.Protocol.Http
try
{
if (InterfaceControl.Parent is ConnectionTab objConnectionTab) tabTitle = objConnectionTab.TabText;
if (InterfaceControl.Parent is ConnectionTab objConnectionTab) _tabTitle = objConnectionTab.TabText;
}
catch (Exception)
{
tabTitle = "";
_tabTitle = "";
}
try
{
wBrowser = Control;
_wBrowser = Control;
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.CEF)
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.EdgeChromium)
{
var CEFBrowser = (ChromiumWebBrowser)wBrowser;
if (CEFBrowser != null)
{
CEFBrowser.LoadingStateChanged += CefBrowser_LoadingStateChanged;
CEFBrowser.TitleChanged += WBrowser_DocumentTitleChanged;
}
else
{
throw new Exception("Failed to initialize CEF Rendering Engine.");
}
var edge = (WebView2)_wBrowser;
edge.CoreWebView2InitializationCompleted += Edge_CoreWebView2InitializationCompleted;
}
else
{
var objWebBrowser = (WebBrowser)wBrowser;
var objWebBrowser = (WebBrowser)_wBrowser;
objWebBrowser.ScrollBarsEnabled = true;
// http://stackoverflow.com/questions/4655662/how-to-ignore-script-errors-in-webbrowser
@@ -87,7 +76,6 @@ namespace mRemoteNG.Connection.Protocol.Http
objWebBrowser.Navigated += WBrowser_Navigated;
objWebBrowser.DocumentTitleChanged += WBrowser_DocumentTitleChanged;
browserInitialised = true;
}
return true;
@@ -103,20 +91,16 @@ namespace mRemoteNG.Connection.Protocol.Http
{
try
{
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.CEF)
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.EdgeChromium)
{
if (browserInitialised)
{
((ChromiumWebBrowser)wBrowser).Load(GetURL());
}
((WebView2)_wBrowser).Source = new Uri(GetUrl());
}
else
{
((WebBrowser)wBrowser).Navigate(GetURL());
((WebBrowser)_wBrowser).Navigate(GetUrl());
}
base.Connect();
connectCalled = true;
return true;
}
catch (Exception ex)
@@ -130,22 +114,12 @@ namespace mRemoteNG.Connection.Protocol.Http
#region Private Methods
private string GetURL()
private string GetUrl()
{
try
{
var strHost = InterfaceControl.Info.Hostname;
/*
* Commenting out since this codes doesn't actually do anything at this time...
* Possibly related to MR-221 and/or MR-533 ????
*
string strAuth = "";
if (((int)Force & (int)ConnectionInfo.Force.NoCredentials) != (int)ConnectionInfo.Force.NoCredentials && !string.IsNullOrEmpty(InterfaceControl.Info.Username) && !string.IsNullOrEmpty(InterfaceControl.Info.Password))
{
strAuth = "Authorization: Basic " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(InterfaceControl.Info.Username + ":" + InterfaceControl.Info.Password)) + Environment.NewLine;
}
*/
if (InterfaceControl.Info.Port != defaultPort)
{
if (strHost.EndsWith("/"))
@@ -161,6 +135,7 @@ namespace mRemoteNG.Connection.Protocol.Http
if (strHost.Contains(httpOrS + "://") == false)
strHost = httpOrS + "://" + strHost;
}
return strHost;
}
catch (Exception ex)
@@ -174,26 +149,17 @@ namespace mRemoteNG.Connection.Protocol.Http
#region Events
private void CefBrowser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
private void Edge_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e)
{
browserInitialised = !e.IsLoading;
if (browserInitialised)
if (!e.IsSuccess)
{
// Unhook the loading state changes now, as navigation is done by the user on links in the control
((ChromiumWebBrowser)wBrowser).LoadingStateChanged -= CefBrowser_LoadingStateChanged;
// If this Connection has already been asked to connect but the browser hadn't finished initalising
// then the connect wouldn't have been allowed to take place, so now we can call it!
if (connectCalled)
{
Connect();
}
Runtime.MessageCollector.AddExceptionStackTrace(Language.HttpFailedUrlBuild, e.InitializationException);
}
}
private void WBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
if (!(wBrowser is WebBrowser objWebBrowser)) return;
if (!(_wBrowser is WebBrowser objWebBrowser)) return;
// This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise.
objWebBrowser.AllowWebBrowserDrop = false;
@@ -207,33 +173,18 @@ namespace mRemoteNG.Connection.Protocol.Http
{
if (!(InterfaceControl.Parent is ConnectionTab tabP)) return;
string shortTitle;
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.CEF)
if (((WebBrowser)_wBrowser).DocumentTitle.Length >= 15)
{
if (((TitleChangedEventArgs)e).Title.Length >= 15)
{
shortTitle = ((TitleChangedEventArgs)e).Title.Substring(0, 10) + "...";
}
else
{
shortTitle = ((CefSharp.TitleChangedEventArgs)e).Title;
}
shortTitle = ((WebBrowser)_wBrowser).DocumentTitle.Substring(0, 10) + "...";
}
else
{
if (((WebBrowser)wBrowser).DocumentTitle.Length >= 15)
{
shortTitle = ((WebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "...";
}
else
{
shortTitle = ((WebBrowser)wBrowser).DocumentTitle;
}
shortTitle = ((WebBrowser)_wBrowser).DocumentTitle;
}
if (!string.IsNullOrEmpty(tabTitle))
if (!string.IsNullOrEmpty(_tabTitle))
{
tabP.TabText = tabTitle + @" - " + shortTitle;
tabP.TabText = _tabTitle + @" - " + shortTitle;
}
else
{
@@ -246,38 +197,6 @@ namespace mRemoteNG.Connection.Protocol.Http
}
}
private void geckoBrowser_DocumentTitleChanged(object sender, EventArgs e)
{
try
{
if (!(InterfaceControl.Parent is ConnectionTab tabP)) return;
string shortTitle;
if (((WebBrowser)wBrowser).DocumentTitle.Length >= 15)
{
shortTitle = ((WebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "...";
}
else
{
shortTitle = ((WebBrowser)wBrowser).DocumentTitle;
}
if (!string.IsNullOrEmpty(tabTitle))
{
tabP.TabText = tabTitle + @" - " + shortTitle;
}
else
{
tabP.TabText = shortTitle;
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace(Language.HttpDocumentTileChangeFailed, ex);
}
}
#endregion
#region Enums
@@ -288,7 +207,7 @@ namespace mRemoteNG.Connection.Protocol.Http
IE = 1,
[LocalizedAttributes.LocalizedDescription(nameof(Language.HttpCEF))]
CEF = 2
EdgeChromium = 2
}
#endregion

View File

@@ -6,7 +6,6 @@ using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol
@@ -64,7 +63,7 @@ namespace mRemoteNG.Connection.Protocol
return false;
}
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo, Runtime.CredentialService);
_process = new Process
{
StartInfo =

View File

@@ -3,7 +3,6 @@ using System.Drawing;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.Connection.Protocol.PowerShell
{

View File

@@ -8,7 +8,6 @@ using mRemoteNG.Connection.Protocol.VNC;
using System;
using mRemoteNG.Connection.Protocol.PowerShell;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.Connection.Protocol
{

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol
{

View File

@@ -1,16 +1,15 @@
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.Tools.Cmdline;
using mRemoteNG.UI;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.Security;
// ReSharper disable ArrangeAccessorOwnerBody
@@ -79,45 +78,20 @@ namespace mRemoteNG.Connection.Protocol
if (PuttyProtocol == Putty_Protocol.ssh)
{
var username = "";
var password = "";
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Username))
{
username = InterfaceControl.Info.Username;
}
else
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (Settings.Default.EmptyCredentials)
{
case "windows":
username = Environment.UserName;
break;
case "custom":
username = Settings.Default.DefaultUsername;
break;
}
}
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password))
{
password = InterfaceControl.Info.Password;
}
else
{
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword,
Runtime.EncryptionKey);
}
}
arguments.Add("-" + (int)PuttySSHVersion);
if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials))
{
var cred = Runtime.CredentialService.GetEffectiveCredentialRecord(InterfaceControl?.Info.CredentialRecordId
.FirstOrDefault()).FirstOrDefault();
var username = cred.Username;
var password = cred.Password.ConvertToUnsecureString();
if (!string.IsNullOrEmpty(username))
{
arguments.Add("-l", username);
@@ -150,11 +124,11 @@ namespace mRemoteNG.Connection.Protocol
PuttyProcess.Exited += ProcessExited;
PuttyProcess.Start();
PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
PuttyProcess.WaitForInputIdle(Properties.Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount;
while (PuttyHandle.ToInt32() == 0 &
Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
Environment.TickCount < startTicks + Properties.Settings.Default.MaxPuttyWaitTime * 1000)
{
if (_isPuttyNg)
{

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -1,5 +1,4 @@
using System.ComponentModel;
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -1,5 +1,4 @@
using mRemoteNG.Resources.Language;
using mRemoteNG.Tools;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections;
using mRemoteNG.App;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -8,13 +8,13 @@ using AxMSTSCLib;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.Tools;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Tabs;
using MSTSCLib;
using System.Linq;
using mRemoteNG.Security;
namespace mRemoteNG.Connection.Protocol.RDP
{
@@ -379,9 +379,9 @@ namespace mRemoteNG.Connection.Protocol.RDP
{
if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes)
{
_rdpClient.TransportSettings2.GatewayUsername = connectionInfo.Username;
_rdpClient.TransportSettings2.GatewayPassword = connectionInfo.Password;
_rdpClient.TransportSettings2.GatewayDomain = connectionInfo?.Domain;
_rdpClient.TransportSettings2.GatewayUsername = connectionInfo.CredentialRecord.Username;
_rdpClient.TransportSettings2.GatewayPassword = connectionInfo.CredentialRecord.Password.ConvertToUnsecureString();
_rdpClient.TransportSettings2.GatewayDomain = connectionInfo.CredentialRecord.Domain;
}
else if (connectionInfo.RDGatewayUseConnectionCredentials ==
RDGatewayUseConnectionCredentials.SmartCard)
@@ -457,58 +457,15 @@ namespace mRemoteNG.Connection.Protocol.RDP
return;
}
var userName = connectionInfo?.Username ?? "";
var password = connectionInfo?.Password ?? "";
var domain = connectionInfo?.Domain ?? "";
var cred = Runtime.CredentialService.GetEffectiveCredentialRecord(connectionInfo.CredentialRecordId
.FirstOrDefault()).FirstOrDefault();
if (string.IsNullOrEmpty(userName))
{
if (Settings.Default.EmptyCredentials == "windows")
{
_rdpClient.UserName = Environment.UserName;
}
else if (Settings.Default.EmptyCredentials == "custom")
{
_rdpClient.UserName = Settings.Default.DefaultUsername;
}
}
else
{
_rdpClient.UserName = userName;
}
if (string.IsNullOrEmpty(password))
{
if (Settings.Default.EmptyCredentials == "custom")
{
if (Settings.Default.DefaultPassword != "")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
_rdpClient.AdvancedSettings2.ClearTextPassword =
cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
}
}
}
else
{
_rdpClient.AdvancedSettings2.ClearTextPassword = password;
}
if (string.IsNullOrEmpty(domain))
{
if (Settings.Default.EmptyCredentials == "windows")
{
_rdpClient.Domain = Environment.UserDomainName;
}
else if (Settings.Default.EmptyCredentials == "custom")
{
_rdpClient.Domain = Settings.Default.DefaultDomain;
}
}
else
{
_rdpClient.Domain = domain;
}
_rdpClient.UserName = cred.Username ?? "";
_rdpClient.AdvancedSettings2.ClearTextPassword = cred.Password?.ConvertToUnsecureString() ?? "";
_rdpClient.Domain = cred.Domain ?? "";
}
catch (Exception ex)
{
@@ -817,4 +774,4 @@ namespace mRemoteNG.Connection.Protocol.RDP
#endregion
}
}
}

View File

@@ -3,7 +3,6 @@ using mRemoteNG.App;
using MSTSCLib;
using System;
using System.Windows.Forms;
using mRemoteNG.Resources.Language;
namespace mRemoteNG.Connection.Protocol.RDP
{

View File

@@ -4,7 +4,6 @@ using System.Windows.Forms;
using AxMSTSCLib;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
using MSTSCLib;
namespace mRemoteNG.Connection.Protocol.RDP

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