Compare commits

...

439 Commits

Author SHA1 Message Date
Dimitrij
b5c156e0b1 Merge pull request #3013 from Neptunium931/patch-1
fix(doc): the list format in the command_line_switches.rst is incorrect.
2025-11-13 10:56:52 +00:00
Neptunium93
a7e8d8523a fix(doc): the list format in the command_line_switches.rst is incorrect. 2025-11-13 09:50:59 +01:00
Dimitrij
2ead94a740 Merge pull request #2691 from Nizhal/v1.77.3-dev
தமிழ்(ta) Proof reading update
2025-05-06 10:30:44 +01:00
தமிழ் நேரம்
737df595df Merge branch 'mRemoteNG:v1.77.3-dev' into v1.77.3-dev 2025-05-02 18:03:38 +05:30
தமிழ் நேரம்
e1023a6aed done 2025-05-02 17:59:46 +05:30
தமிழ் நேரம்
0eedfab5b1 1448 2025-05-01 22:29:54 +05:30
தமிழ் நேரம்
c682b603e7 1868 2025-05-01 15:52:06 +05:30
Dimitrij
fe063a98cd Merge pull request #2690 from Nizhal/v1.77.3-dev
தமிழ் (ta) Translation update
2025-05-01 11:07:35 +01:00
தமிழ் நேரம்
c90beb66a0 updated
2120
2025-05-01 14:19:57 +05:30
தமிழ் நேரம்
f38dc86551 2371- Backwards 2025-05-01 12:07:17 +05:30
தமிழ் நேரம்
389776ae64 updated 2025-05-01 12:04:56 +05:30
தமிழ் நேரம்
ebe782e5a4 1128 lines updated
updated till 1785 lines

1906 lines updated

1945

1966

2417
2025-04-13 22:16:31 +05:30
தமிழ் நேரம்
d3f497bfbc templated added 2025-04-05 03:44:03 +05:30
Dimitrij
e89b1f4139 Update to PuTTYNG 83.0.1 #2670 2025-02-11 11:18:10 +00:00
Dimitrij
b5c431b8e7 fix ssh quickconnect exception #2668 2025-02-05 14:24:53 +00:00
Dimitrij
3746ba1819 fix year 2025-02-01 17:21:19 +00:00
Dimitrij
945bff3c17 Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2025-02-01 17:01:13 +00:00
Dimitrij
d7e318b1f8 lib update 2025-02-01 16:59:53 +00:00
Dimitrij
eb3db198a1 Update build-x86_64.yml
update vs to 17.12.4
2025-02-01 16:34:00 +00:00
Dimitrij
a908a783be lib update 2025-01-24 13:25:58 +00:00
Dimitrij
1ae9960e82 lib update 2025-01-14 14:54:54 +00:00
Dimitrij
5aa8425209 Lib updates 2024-12-23 14:27:58 +00:00
Dimitrij
b794aa8089 update puttyng to ver. 0.82 2024-12-23 14:09:07 +00:00
Dimitrij
e8bb0bffaa lib upgrade + update
Some version should be not upgraded due .net limitation, what will be done once .net will be upgraded
2024-11-23 15:51:32 +00:00
Dimitrij
e1e0661f25 lib upgrade 2024-11-23 13:12:36 +00:00
Dimitrij
7848c83c72 lib updates 2024-11-23 12:50:16 +00:00
Dimitrij
2de37ed9c7 Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2024-11-21 11:17:24 +00:00
Dimitrij
425b433cd2 lib updates 2024-11-21 11:17:15 +00:00
Dimitrij
44e07e3cdb Merge pull request #2652 from kursataktas/mremoteng-guru
Introducing mRemoteNG Guru on Gurubase.io
2024-11-12 21:46:23 +00:00
Kursat Aktas
689f882104 Introducing mRemoteNG Guru on Gurubase.io
Signed-off-by: Kursat Aktas <kursat.ce@gmail.com>
2024-11-13 00:17:19 +03:00
Dimitrij
207beaee12 Lib updates + small changes 2024-11-12 11:47:47 +00:00
Dimitrij
bd21b85de7 Lib update 2024-11-01 11:17:54 +00:00
Dimitrij
2e7579cac5 Moved all language files into Language folder. To keep root folder clean
On language change new language will not apply, need more work on that later
2024-10-18 15:40:50 +01:00
Dimitrij
ec63812af0 lib update 2024-10-18 11:02:27 +01:00
Dimitrij
8dfe1a22c9 Moved packages dll's into Assembly folder to keep root folder cleaner 2024-10-18 10:58:49 +01:00
Dimitrij
c0e3f547ec Introducing Local settings manager class and example of default settings json schema
Idea to create json file with defaults settings, what will be automatically loaded into new local settings db at creating process.
Group 'default' means its comes from json file and if user change it later - we will have user id there, that allow us to have different settings for different users but at same time keeping "original" ones in case user decide to reset.

What one of the basic steps of transition all settings into local db. Once application is running - will be possible to import already existing settings into local db, as well as switch where to have save them: to windows registery or to local db.

Settings file also could be encrypted, and file will be locked on current machine, that allow all users to use it, but not allow to transfer it to another machine. (If they do it will not work)
mR don't use any hard-coded passwords for such, only hdd id + machine name (what is hashed by SHA256) so couldn't be traceable from memory dump. Later will be possible to lock by user with own password, but that will required to enter on every start as mR will not save it.
2024-10-16 11:37:31 +01:00
Dimitrij
dafb1b364c lib updates 2024-10-15 13:41:41 +01:00
Dimitrij
7d1b9d8635 Merge pull request #2643 from xRushG/asyncRegSetting
Registry Settings: enhancements and new settings implementation
2024-10-01 22:51:52 +01:00
xRushG
8041f58ffd feat: Add registry settings for Security Page and encryption key generator
- Added new registry settings for managing security-related configurations on the Security Page.
- Implemented an encryption key generator to securely generate a password for store in the registry.
- Passwords are placed encrypted on the clipboard for 30 seconds.
- Update documents and finalize comments
2024-10-01 16:02:59 +02:00
xRushG
d018fdbace feat: Add registry settings for Connections and SQL Server settings
- Added registry settings for the Connection Page.
- Added registry settings for the SQL Serverl Page.
- All settings implemented with async registry logic
- Comment unused settings for Connection Page
- Update documents
2024-10-01 12:35:34 +02:00
xRushG
489602ffb3 feat: Add registry settings forTabs and Panel settings
- Added registry settings for the Tabs and Panel Page.
- All settings implemented with async registry logic
- Comment unused settings
- Update documents
2024-10-01 12:32:16 +02:00
xRushG
600ba73f5f Removed the deprecated SaveConnectionsOnExit option from the registry settings related to startup and exit. 2024-10-01 12:29:01 +02:00
xRushG
88600ae6df feat: Add registry settings for Notification Page, Appearance Page, and Startup and Exit Page with async logic
- Added registry settings for the Notification Page.
- Added registry settings for the Appearance Page.
- Added registry settings for the Startup and Exit Page.
- All settings implemented with async registry logic
2024-10-01 12:27:33 +02:00
xRushG
5e3bce9a92 refactor: Apply the async logic for Credentials and Updates registry settings, remove obsolete code
- Moved async registry loading logic to OptRegistryCredentialsPage and OptRegistryUpdatesPage to improve structure and maintainability.
- Removed obsolete logic and redundant code that is no longer needed due to the new asynchronous architecture.
- Enhanced settings management to take advantage of the just-in-time loading mechanism.
- Improved performance by ensuring registry settings are loaded asynchronously right before they are needed by the UI or application logic, minimizing unnecessary loads.
- Update documents
2024-10-01 12:19:41 +02:00
xRushG
9b28b7057d feat: Introduce RegistryLoader class with Lazy<T> and async registry settings loading
- Added the RegistryLoader class to handle loading of registry settings.
- Implemented Lazy<T> for singleton pattern to ensure only one instance of RegistryLoader is created.
- Added support for asynchronous loading of registry settings to improve performance in async workflows.
- Designed the class with thread safety in mind, leveraging ConcurrentDictionary for storage.
- Included logging of debug messages to track the load process and timing.
2024-10-01 12:08:52 +02:00
Dimitrij
0a17220446 lib updates 2024-09-29 17:05:51 +01:00
Dimitrij
7684b19d13 lib updates 2024-09-18 10:32:34 +01:00
Dimitrij
47baf3b662 fix case 2024-08-28 11:35:56 +01:00
Dimitrij
bc5e2b9437 add project line name 2024-08-28 11:29:40 +01:00
Dimitrij
cf0ef6d9d0 remove older schemes from distribution 2024-08-28 09:54:49 +01:00
Dimitrij
b6f3047f82 lib updates 2024-08-28 09:39:02 +01:00
Dimitrij
0a418561d7 Merge pull request #2629 from ianselmi/v1.77.3-dev
Made the specflow compatible with net6
2024-08-27 11:29:10 +01:00
ianselmi
6da79a41df made the specflow compatible with net6 2024-08-18 10:12:16 +02:00
Dimitrij
3ddeac6c74 lib update 2024-08-05 13:35:58 +01:00
Dimitrij
98f97c442d fix build number calculation 2024-08-05 13:33:50 +01:00
Dimitrij
472d33ba12 Merge pull request #2550 from Risae/v1.77.3-dev
CI: Add GitHub Actions workflow
2024-08-01 16:08:44 +01:00
Dimitrij
d906cfcc1e lib updates 2024-07-31 10:24:44 +01:00
Dimitrij
0f0d8bdcdb Merge pull request #2623 from magriggs/issue-2622
issue-2622: mRemoteNGInstaller - remove explicit PuTTyNG fragment, as…
2024-07-30 13:09:31 +01:00
23439176+magriggs@users.noreply.github.com
005b2485f6 issue-2622: mRemoteNGInstaller - remove explicit PuTTyNG fragment, as PuttyNG is copied implicitly by FilesFragment. Fixes #2622. 2024-07-30 09:07:55 +08:00
Dimitrij
ffd90bed70 Merge pull request #2621 from magriggs/issue-726
Issue 726 - SecureString for ConnectionInfo.Password
2024-07-29 09:05:05 +01:00
23439176+magriggs@users.noreply.github.com
70264a24ab Fix null password handling 2024-07-28 21:30:10 +08:00
23439176+magriggs@users.noreply.github.com
ad3a37fde3 Move ConnectionInfo.Password to use SecureString. Only decrypt when required for connecting. Update tests to skip tests of password values where necessary. 2024-07-28 19:56:36 +08:00
Dimitrij
9dac0eeaac Updating due https://github.com/mRemoteNG/mRemoteNG/issues/243 2024-07-16 20:55:18 +01:00
Dimitrij
8dac393bb4 libs update 2024-07-10 10:26:50 +01:00
Dimitrij
287d1a5575 Merge pull request #2611 from Wolvverine/v1.77.3-dev
correct registry path
2024-07-05 22:31:42 +01:00
Michał Panasiewicz
20278e0e53 correct registry path 2024-07-05 20:50:41 +02:00
Dimitrij
a3c3ec8c5c lib updates 2024-06-20 10:22:13 +01:00
Dimitrij
3039b25a66 versioning fix 2024-06-11 14:11:52 +01:00
Dimitrij
0b7ce92af8 libs update 2024-06-11 11:36:17 +01:00
Dimitrij
e3ec521a1d Merge pull request #2601 from xRushG/RegSettings
Enhancement of Registry Settings capabilities
2024-06-11 11:21:39 +01:00
xRushG
88999263a7 Finalize Update Options Page
This commit finalizes the Update Options Page with the following changes:
- Removed unnecessary methods due to new features of the registry handler class.
- Updated and added comments to improve code readability and understanding.
- Implemented UI optimizations such as disabling the frequency control and showing "Never" in the combobox.
- Enabled the password storing ability, making it functional but not yet usable.
- Applied some code optimizations for improved efficiency.
2024-06-11 10:07:33 +02:00
xRushG
9687ccd01d Finalize Credentials Options Page
This commit finalizes the Credentials Options Page with the following changes:
- Updated and added comments to improve code readability and understanding.
- Enabled the password storing ability, making it functional but not yet usable.
- Applied some code optimizations for improved efficiency.
2024-06-11 09:44:20 +02:00
xRushG
ca62502499 Update dependent registry options settings to use new WindowsRegistryEntry class. 2024-06-11 09:08:37 +02:00
xRushG
8b3a68f58e Removing all unnecessary old files 2024-06-11 09:07:04 +02:00
xRushG
08eb35a360 Refactor registry settings interaction classes.
This commit refactors the registry settings interaction classes by consolidating the multiple entry classes for int, string, bool, etc., into a single class that supports multiple data types. This change simplifies the code and enhances readability.

- Consolidate multiple entry classes (int, string, bool, etc.) into a single class
- Introduce WindowsRegistryEntry<T> to support multiple data types
2024-06-11 09:03:34 +02:00
Dimitrij
dec82b41f2 lib update 2024-06-10 21:14:52 +01:00
Dimitrij
b9ab5c76f7 Merge pull request #2597 from CodeCasterNL/v1.77.3-dev
Remember the opened connection file on relaunch
2024-06-07 13:33:53 +01:00
Dimitrij
6de0c536e8 Merge pull request #2591 from tecxx/develop-orig
add Clickstudios Passwordstate API connector
2024-06-07 13:32:56 +01:00
tecxx
3f0aca97bf Merge branch 'mRemoteNG:v1.77.3-dev' into develop-orig 2024-06-06 09:17:37 +02:00
Dimitrij
ccb51a2603 Merge pull request #2599 from xRushG/fix2592
Fix for #2592 compiler issue
2024-05-30 10:03:35 +01:00
xRushG
99d9e70921 Fix #2592: Prevent GeneralAppInfo.ApplicationVersion from being set in Unit Tests. Not needed for tests. 2024-05-29 15:20:56 +02:00
CodeCasterNL
b8b54271dd Save ConnectionFilePath, fix typo in identifier 2024-05-25 17:13:11 +02:00
Dimitrij
49a1549e5a Merge pull request #2596 from xRushG/OpenLogBug
Log File Opening Fails on Notification Settings Page
2024-05-24 09:12:38 +01:00
xRushG
b3f936c194 - Added my missed comment for outlined LocalSettingsManager
- Fixed a bug that occurred when trying to open the log file on the Notification settings page.
- Removed unnecessary file association when user tries to open the log file on the Notification page. The "choose file" dialog handles the extension as it is fixed on .log
- Implemented fallback to open file explorer to the specified file location if mRem fails to open the log file.
2024-05-23 21:29:35 +02:00
Robert Rostek
f3b10d4c20 update credential vault documentation 2024-05-04 18:05:28 +02:00
Robert Rostek
94b17037d0 add Clickstudios Passwordstate API connector 2024-05-04 13:49:17 +02:00
Dimitrij
83f3846ce6 lib updates
correct build number calculations - now its days from last release + hour + minute of build
some changes to migrate to json schema + preparation of using db to save settings
2024-05-03 14:40:52 +01:00
Dimitrij
711a751117 Merge pull request #2589 from xRushG/Fix-2540
LocalSettingsManager class implementation is missing (#2540)
2024-04-29 13:56:53 +01:00
xRushG
e013e32792 Fix #2540
LocalSettingsManager class implementation is missing
2024-04-29 14:34:36 +02:00
Dimitrij
6e64b09256 Merge pull request #2571 from mRemoteNG/dependabot/nuget/mRemoteNG/System.Data.SqlClient-4.8.6
Bump System.Data.SqlClient from 4.8.5 to 4.8.6 in /mRemoteNG
2024-03-11 14:31:41 +00:00
dependabot[bot]
e32d268587 Bump System.Data.SqlClient from 4.8.5 to 4.8.6 in /mRemoteNG
Bumps [System.Data.SqlClient](https://github.com/dotnet/corefx) from 4.8.5 to 4.8.6.
- [Release notes](https://github.com/dotnet/corefx/releases)
- [Commits](https://github.com/dotnet/corefx/commits)

---
updated-dependencies:
- dependency-name: System.Data.SqlClient
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 14:30:32 +00:00
Dimitrij
05635dec93 Merge pull request #2559 from xRushG/v1.77.3-dev
Configuration via windows registry (updates and credentials)
2024-02-19 18:20:44 +00:00
Schmitti91
e694923d33 Merge branch 'v1.77.3-dev' of https://github.com/xRushG/mRemoteNG into v1.77.3-dev 2024-01-28 10:16:30 +01:00
Schmitti91
7322683465 Fix AppVeyor CA2200 and optimize CreateOrSetRegistryValue method 2024-01-28 10:15:34 +01:00
Schmitti91
64688f3512 Add documentation page for registry settings (credentials) 2024-01-27 21:01:38 +01:00
Schmitti91
762760af2f Adding the configuration capability for the Credentials page through the Windows Registry. 2024-01-27 20:55:12 +01:00
Schmitti91
48e6881401 Merge branch 'v1.77.3-dev' of https://github.com/xRushG/mRemoteNG into v1.77.3-dev 2024-01-26 21:13:22 +01:00
Schmitti91
95c958136f Add Dokupage for registry settings (update) 2024-01-26 21:12:24 +01:00
Schmitti91
53a6be0f82 remove placeholder code by commenting it out in its current state. (needed for later commit) 2024-01-26 21:07:04 +01:00
Schmitti91
0b4d95be1c Renameing the common setting name "CheckForUpdate Asked" to "AllowPromptForUpdates Preference" for consistency in naming conventions. 2024-01-23 21:43:29 +01:00
Schmitti91
aad3948475 make ProxyAuthPass not usable, placeholder code 2024-01-23 16:24:28 +01:00
Schmitti91
093370081e Add capability to set Update Settings via Registry
This commit enhances the functionality of the WindowsRegistryAdvanced class to provide the capability to set up Update Settings through the Windows Registry. The changes include the addition of methods or modifications that allow users to configure update-related settings using the Registry.
2024-01-23 16:14:36 +01:00
Schmitti91
33426ceee9 Add GetDwordValue method to WindowsRegistryAdvanced
This commit introduces the GetDwordValue method in the WindowsRegistryAdvanced class, allowing the retrieval of DWORD values from the Windows Registry. The implementation uses int.TryParse for efficient parsing and handles default values gracefully.
2024-01-23 14:29:07 +01:00
Schmitti91
5f5700b948 extend Registry handling capabilities in preparation for Registry settings
Enhanced the functionality of Registry handling in preparation for managing Registry settings
2024-01-23 12:54:43 +01:00
Risae
802e9abfef CI: Create build-x86_64.yml 2024-01-11 17:46:08 +01:00
Dimitrij
45149d6547 Merge pull request #2549 from magriggs/issue-2487
Issue 2487
2024-01-05 12:07:05 +00:00
23439176+magriggs@users.noreply.github.com
595681a982 Remove boilerplate code 2024-01-05 14:28:33 +08:00
23439176+magriggs@users.noreply.github.com
e1cac723d6 First commit of SecureCRT import functionality. 2024-01-05 13:59:36 +08:00
Dimitrij
683f84f053 Merge pull request #2545 from magriggs/issue-1308
Some fixes for issue mRemoteNG#1308. Inspired by dockpanelsuite/dockp…
2024-01-03 13:15:15 +00:00
23439176+magriggs@users.noreply.github.com
b6d882a06f Some fixes for issue mRemoteNG#1308. Inspired by dockpanelsuite/dockpanelsuite#526 (comment). Main change is to enable minimize and close buttons 2024-01-03 20:39:36 +08:00
Dimitrij
9d4bfbcb1c lib updates 2023-12-13 21:56:25 +00:00
Dimitrij
b563747046 Merge pull request #2534 from jcefoli/v1.77.3-dev
Handle case where COM object becomes separated from RCW
2023-12-13 21:47:47 +00:00
Joe Cefoli
1ebd0a430f Remove unnecessary line break 2023-12-13 14:42:13 -05:00
Joe Cefoli
ef4366be4d Handle case where COM object becomes sepatated from Runtime Callable Wrapper (resizing main window after disconnecting from fit to panel session) 2023-12-13 14:34:33 -05:00
Dimitrij
484283fef8 Merge pull request #2533 from tommwq/v1.77.3-dev
support local PowerShell connection
2023-12-13 11:02:10 +00:00
tommwq
b546a48a5f support local PowerShell connection 2023-12-12 23:26:58 +08:00
Dimitrij
51bd64d005 Merge pull request #2530 from BestiaPL/v1.77.3-dev
Update Language.pl.resx
2023-12-11 10:32:02 +00:00
Andrzej Rudnik
2c65d12b92 Update Language.pl.resx 2023-12-05 21:17:59 +01:00
Dimitrij
c43a3b5115 Merge pull request #2529 from xRushG/v1.77.3-dev
Pre-build event powershell code update #2524
2023-12-04 17:47:04 +00:00
Schmitti91
515778b13d Pre-build event powershell code update/fix 2023-12-02 21:59:56 +01:00
Dimitrij
bb4b9ce9e7 Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2023-11-29 09:42:06 +00:00
Dimitrij
1d6707fecd #2528
fix typo
2023-11-29 09:41:56 +00:00
Dimitrij
5b2a46ed91 Merge pull request #2523 from zeze0556/v1.77.3-dev
fixed mysql error
2023-11-20 09:27:46 +00:00
unknown
24fa97da4c fixed mysql error 2023-11-20 10:21:59 +08:00
Dimitrij
b0109c2581 lib update 2023-11-10 11:29:18 +00:00
Dimitrij
20f237ec4c Merge pull request #2519 from BestiaPL/v1.77.3-dev
Update Language.pl.resx
2023-11-04 23:38:09 +00:00
Andrzej Rudnik
6ea535ae29 Update Language.pl.resx 2023-11-04 16:59:46 +01:00
Dimitrij
57ca8a3eee Merge pull request #2514 from Schmitti91/v1.77.3-dev
Update Registry interaction capabilities.
2023-10-24 13:33:12 +01:00
Schmitti91
307ea42a0f Cleanup of references and correction of comments. 2023-10-23 07:58:13 +02:00
Schmitti91
ac41c04f67 mRemoteNG tools WindowsRegistry has been revised and the Windows Registry reading capabilities have been expanded in preparation for working with Registry Keys options. The "RegistryHive" enum was deleted because it is contained in "Microsoft.Win32". 2023-10-22 12:18:42 +02:00
Dimitrij
b3496e79de lib update 2023-10-17 16:05:09 +01:00
Dimitrij
4f7aa755e3 Merge pull request #2508 from RFC1920/v1.77.3-dev-putty
bugfix for Putty import
2023-10-17 09:30:56 +01:00
Dimitrij
d3af50f009 lib updates 2023-10-16 13:59:04 +01:00
RFC1920
ba77a7b7c0 Update Putty registry import to fix connection name, username, and port setting 2023-10-16 05:32:34 -05:00
Dimitrij
666a0e1537 Merge pull request #2507 from RFC1920/v1.77.3-dev-putty
Add Putty registry import
2023-10-16 11:32:21 +01:00
RFC1920
96f4307910 Add Putty registry import 2023-10-16 04:50:35 -05:00
Dimitrij
81e997eb60 Merge pull request #2506 from Schmitti91/v1.77.3-dev
Enhancing the PowerShell Connection.
2023-10-16 09:56:50 +01:00
Schmitti91
7132c6e7c2 Removing the "-NoProfile" option from PowerShell.exe parameters. 2023-10-15 21:48:01 +02:00
Schmitti91
cb01e92fe2 Enhancing the PowerShell Connection. The PowerShell script is designed to simplify multiple login attempts to a remote host using user-provided credentials, or not. In addition, granular error handling has been added to prevent errors, such as the conversion of empty or null strings to SecureString. Furthermore, hostname, username, and password are now passed as parameters in the PowerShell script block (#2195). 2023-10-15 21:13:36 +02:00
Dimitrij
2c9c512d74 Merge pull request #2503 from WojciechNagorski/new-sshnet
Update SSH.NET to 2023.0.0
2023-10-11 13:55:07 +01:00
Wojciech Nagórski
8d05c9040b Update SSH.NET to 2023.0.0 2023-10-11 14:45:01 +02:00
Dimitrij
4e994fb202 Merge pull request #2502 from BestiaPL/v1.77.3-dev
Updated Polish translation
2023-10-09 16:45:55 +01:00
Dimitrij
ab2a778694 Merge pull request #2496 from tecxx/develop-orig
use pwfile instead of cleartext password for putty connections
2023-10-09 09:27:00 +01:00
Andrzej Rudnik
115375820d Update Language.pl.resx 2023-10-08 20:51:22 +02:00
Andrzej Rudnik
8cb753916b Update Language.pl.resx 2023-10-05 23:36:45 +02:00
Robert Rostek
ec3a0cee9b remove unnecessary usings 2023-10-03 10:55:27 +02:00
Robert Rostek
13f8f82537 update changelog 2023-10-03 10:53:34 +02:00
Robert Rostek
54544dd2aa use pwfile instead of pw for puttyng 2023-10-03 10:52:41 +02:00
Dimitrij
ac99115424 Merge pull request #2482 from simonai1254/fix-2195
Fix 2195
2023-08-31 16:37:41 +01:00
Simon Monai
d6c6038193 Update CHANGELOG.md 2023-08-30 23:55:40 +02:00
Simon Monai
c97b84e4a2 Quote variable for #2195
In order to interpret variable as string and not arbitrary code
2023-08-30 23:46:42 +02:00
Dimitrij
6698ec0b06 Update README.md 2023-08-02 13:14:28 +01:00
Dimitrij
290b1c4de5 Update README.md 2023-08-02 13:14:02 +01:00
Dimitrij
d497a50727 Update README.md 2023-08-02 13:13:23 +01:00
Dimitrij
2837c91f5e Update README.md 2023-08-02 13:12:34 +01:00
Dimitrij
9a717f28c6 upd 2023-08-02 13:03:14 +01:00
Dimitrij
e416c2c9c9 upd 2023-08-02 13:01:21 +01:00
Dimitrij
331cdaa6ce upd 2023-08-02 12:54:27 +01:00
Dimitrij
aa329b1a9a upd 2023-08-02 12:51:30 +01:00
Dimitrij
16c080942d upd table 2023-08-02 12:47:15 +01:00
Dimitrij
4acc111b3d upd 2023-08-02 12:39:29 +01:00
Dimitrij
afe453d371 upd 2023-08-02 12:37:25 +01:00
Dimitrij
e93c120dac update table 2023-08-02 12:34:16 +01:00
Dimitrij
2f701458f4 mistype fix 2023-08-02 12:27:30 +01:00
Dimitrij
6a35961dfb Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2023-08-02 12:24:16 +01:00
Dimitrij
1a90095ba3 add add-ons list 2023-08-02 12:24:05 +01:00
Dimitrij
5dc87213b5 Merge pull request #2462 from jurepurgar/rdgw-access-token
Support for gatewayaccesstoken
2023-07-18 16:24:49 +01:00
Jure Purgar
ff8044b09b Delete resx 2023-07-18 16:23:48 +02:00
Jure Purgar
f1fa40f6fd Initial implementation of gatewayaccesstoken support 2023-07-18 16:07:06 +02:00
Dimitrij
9bc5b62828 enable signing 2023-07-15 22:44:26 +01:00
Dimitrij
5aae586812 lib update 2023-07-15 22:11:03 +01:00
Dimitrij
bc5e5be42e update cert 2023-07-15 22:06:47 +01:00
Dimitrij
be68573378 lib updates 2023-07-05 14:33:39 +01:00
Dimitrij
cf0bc3d270 fix links 2023-07-05 12:00:14 +01:00
Dimitrij
d5773eb2e9 doc update
adding image, fix link
2023-07-05 09:29:19 +01:00
Dimitrij
50523e5b67 update docs 2023-07-04 15:59:48 +01:00
Dimitrij
feeca86c6a small fix 2023-06-21 21:03:57 +01:00
Dimitrij
a2e2671483 update links 2023-06-21 20:55:35 +01:00
Dimitrij
0b4d6ef8ef update index 2023-06-21 20:48:23 +01:00
Dimitrij
bdf0e532a5 #2447
add screenshots for themes
2023-06-21 20:46:37 +01:00
Dimitrij
d8cf72d09b Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2023-06-21 12:08:25 +01:00
Dimitrij
6c3ec8f058 update puttyng to actual version 2023-06-21 12:08:07 +01:00
Dimitrij
fbd9b76a09 Merge pull request #2449 from simonai1254/update_documentation
Improve PuttyNG Issue Description
2023-06-21 09:41:55 +01:00
Simon Monai
bee216220a Improve PuttyNG Issue Description
Update PuttyNG Documentation
Do not recommend insecure changes
2023-06-21 09:29:05 +02:00
Dimitrij
4ca7f34989 code corrections 2023-06-16 19:24:33 +01:00
Dimitrij
51015e6b51 lib update 2023-06-16 19:24:00 +01:00
Dimitrij
46100d6d94 lib update 2023-06-08 10:58:05 +01:00
Dimitrij
c94eac3863 Merge pull request #2416 from BlueBlock/streamline_build_scripts_for_appveyor
modify build scripts for appveyor
2023-04-07 15:19:44 +01:00
BlueBlock
965b0e5b6d Update update_and_upload_assemblyinfocs.ps1
enable assemblyinfo.cs update when not (CI)
2023-03-31 11:27:49 -04:00
BlueBlock
000cea1dda test repo name 2023-03-31 11:16:40 -04:00
BlueBlock
6d4d60e3b1 Update postbuild.ps1
fix if matching
2023-03-31 11:02:49 -04:00
BlueBlock
9957282bfa Update postbuild_installer.ps1
disable assemblyinfo.cs update temporarily
2023-03-31 11:01:48 -04:00
BlueBlock
9b603dd956 Update postbuild.ps1
check variables
2023-03-31 10:10:10 -04:00
BlueBlock
759ee55780 modify build scripts for appveyor 2023-03-31 09:14:35 -04:00
Dimitrij
93b2edb5a5 Merge pull request #2415 from BlueBlock/fix_window_restore_resize
Update RdpProtocol8.cs
2023-03-28 14:59:36 +01:00
BlueBlock
4d49c14bb9 Update RdpProtocol8.cs
resize when restored from minimize
2023-03-28 08:49:52 -04:00
Dimitrij
6398808a0a corrected slashes 2023-03-25 22:29:53 +00:00
Dimitrij
64e20f3665 update 2023-03-25 21:45:22 +00:00
Dimitrij
3b542d8868 excluding AssemblyInfo from accidental update in repo 2023-03-25 21:40:42 +00:00
Dimitrij
d5af0e43a5 add condition 2023-03-25 18:44:40 +00:00
Dimitrij
7a8ef87dc7 run string as a command 2023-03-25 18:33:50 +00:00
Dimitrij
7a5293cde3 add wrapping ' 2023-03-25 18:24:08 +00:00
Dimitrij
26400631a0 replace " by ' to avoid path brake 2023-03-25 18:20:46 +00:00
Dimitrij
97a5c584be increase build number only then release in appveyor 2023-03-25 18:16:03 +00:00
Dimitrij
0700b6573c Merge pull request #2413 from BlueBlock/fix_running_of_unit_tests
Fix running of unit tests
2023-03-25 17:17:32 +00:00
Dimitrij
d8f66a4188 Merge pull request #2412 from BlueBlock/update_build_script
Update find_vstool.ps1
2023-03-25 16:39:49 +00:00
BlueBlock
c22971cf54 add unit test references
unit tests were not able to run since the refs were missing
2023-03-25 12:08:52 -04:00
BlueBlock
9d2dd5dd93 remove variable not used 2023-03-25 12:08:02 -04:00
BlueBlock
c19d512631 Update Logger.cs
code formatting and using adjustment
2023-03-25 12:07:28 -04:00
BlueBlock
9efda5fef3 lib update 2023-03-25 12:06:53 -04:00
BlueBlock
a27cdcfdb5 Update find_vstool.ps1
Do not attempt to verify the fingerprint since it changes often. It seems to be overkill to check it.
2023-03-25 12:03:37 -04:00
Dimitrij
5667a07b25 Merge pull request #2411 from BlueBlock/fix_log4net_logging
fix log4net logging
2023-03-25 07:04:21 +00:00
BlueBlock
7d0bd85466 fix log4net logging 2023-03-24 14:49:27 -04:00
Dimitrij
4f269442a6 Merge pull request #2410 from BlueBlock/fix_notificiation_bug_introduced
Fix notification bug introduced
2023-03-24 18:09:14 +00:00
BlueBlock
16d182fca2 Update NotificationPanelMessageWriter.cs
fix notification bug, text not displaying
2023-03-24 11:53:05 -04:00
BlueBlock
6d1a206cc9 code formatting 2023-03-24 11:51:33 -04:00
Dimitrij
d8a7fdbf4f lib update 2023-03-24 15:22:10 +00:00
Dimitrij
516b365ebc Merge pull request #2401 from BlueBlock/fix_options_ui_sizing
options pages size and position fixes
2023-03-24 07:16:15 +00:00
BlueBlock
6da6a5ede9 options pages size and position fixes
- options page was too small
- some tabs needed adjustment for spacing
2023-03-24 03:02:27 -04:00
Dimitrij
67244f1957 Merge pull request #2400 from BlueBlock/fix_database_columns_and_some_tests
Fix database columns and some tests
2023-03-24 06:08:48 +00:00
BlueBlock
0a304e9a03 add missing objects needed in tests 2023-03-24 01:35:37 -04:00
BlueBlock
05154af606 code formatting 2023-03-24 01:34:51 -04:00
BlueBlock
7454b15ec9 adjust app to use 2.8 xsd schema 2023-03-24 01:33:30 -04:00
BlueBlock
38f435f639 Update RemoteDesktopConnectionDeserializer.cs
add missing serializer
2023-03-24 01:32:21 -04:00
BlueBlock
5f38ec7210 Update SqlVersion29To30Upgrader.cs
add missing DB column UserViaAPI
2023-03-24 01:31:41 -04:00
BlueBlock
ca143bf969 Update mremoteng_confcons_v2_8.xsd
inherit should be boolean
2023-03-24 01:29:39 -04:00
BlueBlock
402e5c3665 Create mRemoteNG.lutconfig
live test runner config file
2023-03-24 01:27:52 -04:00
BlueBlock
290dbcc3ed Update SqlDatabaseMetaDataRetriever.cs
- add missing db column UserViaAPI
- formatting and remove commented code
2023-03-24 01:26:44 -04:00
Dimitrij
a7749c70e7 Merge pull request #2399 from BlueBlock/fix_database_use
Fix database use
2023-03-23 22:01:40 +00:00
BlueBlock
9f0cfd5f22 Update CsvConnectionsDeserializerMremotengFormatTests.cs
fix test
2023-03-23 17:47:27 -04:00
BlueBlock
f47434c09e Merge remote-tracking branch 'upstream/v1.77.3-dev' into fix_database_use 2023-03-23 17:44:39 -04:00
BlueBlock
795a4b571e Update AbstractConnectionRecord.cs
defaults set not needed
2023-03-23 17:26:11 -04:00
BlueBlock
f71727e05e Update SqlConnectionsUpdateChecker.cs
code formatting
2023-03-23 16:34:37 -04:00
BlueBlock
d2fa8e86b1 Update DatabaseConnectorFactory.cs
add TODO
2023-03-23 16:34:15 -04:00
BlueBlock
23dcd9d30f Update MySqlDatabaseConnector.cs
add TODO
2023-03-23 16:33:55 -04:00
BlueBlock
d6890c6ecd refactor to newer c# code statements 2023-03-23 16:32:14 -04:00
BlueBlock
b1a6ba78d4 fix database upgrades
- fix tested db upgrading for each version
- fix version check for 3.0
2023-03-23 16:31:28 -04:00
BlueBlock
e6abe3f3a1 simple code reformatting 2023-03-23 16:30:04 -04:00
BlueBlock
6c32540ecb refactor class mssql to sql
refactor class mssql to sql
code formatting
refactor null check
use db TRUNCATE instead of DELETE (mysql warns about mass DELETE)
2023-03-23 16:27:17 -04:00
BlueBlock
951ad5cd0a Update ConnectionsService.cs
use universal time for db time
2023-03-23 16:23:45 -04:00
BlueBlock
5f56477123 Update MiscTools.cs
- add GetBooleanValue method for getting bool from databases
- use universal time for db time
2023-03-23 16:22:38 -04:00
BlueBlock
3180f38a1d Update AbstractConnectionRecord.cs
fix to add redirectdiskdrives default value
2023-03-23 16:21:34 -04:00
BlueBlock
07f15993e5 Update SettingsLoader.cs
refactor null check
2023-03-23 16:20:55 -04:00
BlueBlock
fc8e9c7689 rename class from mssql to sql
This class is not dedicated to mssql but is used by all sql databases. Rename to reflect this.
2023-03-23 16:20:01 -04:00
BlueBlock
7cb20b9e28 Update Runtime.cs
use universal time for stored DB time since users can span time zones
2023-03-23 15:16:28 -04:00
BlueBlock
ffc2351d64 Update ConnectionsFileInfo.cs
latest db version should be 3.0
2023-03-23 15:15:36 -04:00
Dimitrij
f10fec61ac Merge pull request #2398 from BlueBlock/fix_deserializer_test
Update CsvConnectionsDeserializerMremotengFormatTests.cs
2023-03-23 16:39:01 +00:00
BlueBlock
e41200067c Update CsvConnectionsDeserializerMremotengFormatTests.cs
fix test, missing changes needed for RedirectDrives PR
2023-03-23 12:18:28 -04:00
Dimitrij
30f6d3dde7 Merge pull request #2397 from BlueBlock/fix_remove_exception_test
Update ProgramRoot.cs
2023-03-21 20:59:32 +00:00
BlueBlock
7f9dcb11f0 Update ProgramRoot.cs
remove exception test
2023-03-21 16:49:59 -04:00
Dimitrij
d5fa2f62c0 Merge pull request #2396 from BlueBlock/fix_load_misssing_localconnectionproperties_xml_file
Fix load misssing localconnectionproperties xml file
2023-03-21 20:44:59 +00:00
Dimitrij
fa7967190d Merge pull request #2395 from integratorbit/v1.77.3-dev
Improve Disk Drive Redirection
2023-03-21 20:33:33 +00:00
BlueBlock
20e04c0d75 resolve conflicts 2023-03-21 16:04:32 -04:00
BlueBlock
d5eea9db20 Merge remote-tracking branch 'upstream/v1.77.3-dev' into pr/2395 2023-03-21 16:00:50 -04:00
BlueBlock
8cb598ce25 Update FileDataProvider.cs
fix creation of file LocalConnectionProperties.xml if it does not exist
2023-03-21 15:26:01 -04:00
BlueBlock
f3a57d7f23 move filename value LocalConnectionProperties.xml into settings file 2023-03-21 15:25:32 -04:00
BlueBlock
14e47def9d Update SqlDatabaseMetaDataRetriever.cs
fix exception casting int64 to int32, unbox and cast to int
2023-03-21 15:24:49 -04:00
Dimitrij
7573081d7a Merge pull request #2394 from BlueBlock/fix_rdp_operation
Fix RDP operation
2023-03-21 18:48:56 +00:00
Dimitrij
aaca581324 Merge pull request #2393 from BlueBlock/do_not_display_splash_on_taskbar
Do not show splash on taskbar
2023-03-21 18:06:52 +00:00
BlueBlock
43c2797a51 Update ProgramRoot.cs
do not show splash on taskbar
2023-03-21 13:56:55 -04:00
integratorbit
da6bbf65f0 Improve Disk Drive Redirection 2023-03-21 14:31:15 -03:00
BlueBlock
7d0cbf423e add resize fallback
Add resize fallback if the target OS fails to resize using the most current method. (for example, this occurs with Server2008R2)
2023-03-21 13:03:21 -04:00
BlueBlock
d94eab71da Update RdpProtocol8.cs
remove test code
2023-03-21 12:58:58 -04:00
BlueBlock
b0a8ccc5b6 multiple RDP issues fixed
- fix scale of RDP session when moving between 4k and 1080 monitors etc.
- fix inefficient continuous RDP screen resizing while the window size is changed
- add a RDP version check before attempting to use each RDP version and properties
2023-03-21 12:23:59 -04:00
BlueBlock
5cbf1f1568 adjust method access level of common protocol methods 2023-03-21 12:22:20 -04:00
BlueBlock
22cde74db2 Delete RdpProtocol6.cs
class renamed to RdpProtocol
2023-03-21 12:07:18 -04:00
BlueBlock
cdc3759c04 Update Optional.cs
- use more efficient empty assignments
- use string interpolation
- adjust method access to minimal needed
2023-03-21 12:06:38 -04:00
BlueBlock
38abc8a167 Update NotificationPanelMessageWriter.cs
check for object _messageWindow before using it to avoid an exception
2023-03-21 12:04:52 -04:00
BlueBlock
7c7c7086ce Update RdpProtocolFactory.cs
class RdpProtocol6 renamed to RdpProtocol
2023-03-21 12:04:03 -04:00
BlueBlock
50daf64025 Update ProtocolBase.cs
- add check for object _interfaceControl before using it
- adjust methods to protected where appropriate
- remove unused using
2023-03-21 12:03:28 -04:00
BlueBlock
dc38df5389 Update ConnectionsService.cs
use object initializer and remove unused using
2023-03-21 12:00:54 -04:00
BlueBlock
a46b2c9d98 Update ProtocolFactory.cs
remove unused usings
2023-03-21 11:57:34 -04:00
BlueBlock
200756361c rename base class of RDP
So it is consistent with other protocols, rename the RDP base class to not reflect a version.
2023-03-21 11:55:17 -04:00
Dimitrij
877a1e4cd0 Merge pull request #2391 from BlueBlock/add_set_devenvdir_to_prebuild
Update mRemoteNG.csproj
2023-03-20 21:16:18 +00:00
BlueBlock
a382206f5a Update mRemoteNG.csproj
add setting of DevEnvDir in prebuild
2023-03-20 16:31:22 -04:00
Dimitrij
1af7a622a6 Merge pull request #2388 from BlueBlock/fix_remove_unsused_class
Delete RDPVersions.cs
2023-03-17 17:54:50 +00:00
Dimitrij
3f95b2aa7e Merge pull request #2387 from BlueBlock/fix_exception_in_disposeinterface
Update ProtocolBase.cs
2023-03-17 17:48:43 +00:00
BlueBlock
b7871e2e04 Delete RDPVersions.cs
Class is unused and not needed.
2023-03-17 13:18:14 -04:00
BlueBlock
6b6ceda497 Update ProtocolBase.cs
check if object is disposed before working with it
2023-03-17 13:07:58 -04:00
Dimitrij
b01b8e4bc8 adjust installer script 2023-03-17 00:42:46 +00:00
Dimitrij
20f7cb1cd0 update move installer 2023-03-17 00:17:52 +00:00
Dimitrij
3e1ee0056d small amendments 2023-03-16 23:01:06 +00:00
Dimitrij
a3a851e57f Merge pull request #2383 from BlueBlock/fix_null_check_not_needed
Update PuttySessionsRegistryProvider.cs
2023-03-16 20:10:57 +00:00
BlueBlock
cf650d4318 use more efficient array 2023-03-16 16:10:01 -04:00
Dimitrij
58e7420f04 Merge pull request #2386 from BlueBlock/fix_suppress_com_warnings_on_release_build
Update mRemoteNG.csproj
2023-03-16 19:24:18 +00:00
Dimitrij
aedaf084d9 Merge pull request #2382 from BlueBlock/fix_more_CA1416_warnings
fix more CA1416 warnings
2023-03-16 19:04:47 +00:00
BlueBlock
c18f638989 Update mRemoteNG.csproj
suppress com warnings on release build, but display warnings on debug builds
2023-03-16 15:00:46 -04:00
BlueBlock
fb50cdc058 Update PuttySessionsRegistryProvider.cs
remove unreachable code
- no need to test for null, PuttySessionsKey is a const with a value set on instantiation
2023-03-16 14:35:39 -04:00
BlueBlock
68e702c344 fix more CA1416 warnings 2023-03-16 14:15:44 -04:00
Dimitrij
651b18a8b3 Merge pull request #2381 from BlueBlock/fix_obsolete_SHA1CryptoServiceProvider
Update PuttyKeyFileGenerator.cs
2023-03-16 17:11:53 +00:00
BlueBlock
2174e56407 Update PuttyKeyFileGenerator.cs
Replace use of obsolete SHA1CryptoServiceProvider with replacement call.
2023-03-16 12:59:28 -04:00
Dimitrij
ea27a4da02 Merge pull request #2380 from BlueBlock/fix_appveyor_bulk_of_changes
appveyor build automation
2023-03-16 16:50:53 +00:00
BlueBlock
321fd1162b appveyor build automation
bulk of the changes for appveyor automation
2023-03-16 11:08:27 -04:00
Dimitrij
c51f38ddc7 Merge pull request #2379 from BlueBlock/fix_appveyor
additional appveyor change
2023-03-15 19:05:36 +00:00
BlueBlock
b34cd1acc5 additional appveyor change 2023-03-15 14:51:04 -04:00
Dimitrij
43f20bb83a Merge pull request #2378 from BlueBlock/fix_adj_appveyor_build
appveyor build adjustment
2023-03-15 16:57:16 +00:00
Dimitrij
79b8ddef15 Merge pull request #2377 from BlueBlock/fix_putty_registry_watcher
Fix putty registry watcher
2023-03-15 16:49:29 +00:00
BlueBlock
2642ea0601 appveyor build adjustment
Further work to test appveyor builds
2023-03-15 12:46:37 -04:00
Dimitrij
7a2f934f6a Merge pull request #2376 from BlueBlock/add_rdp_protocol_rdc11
add rdp protocol rdc11
2023-03-15 12:49:03 +00:00
BlueBlock
f299fefcdc Update PuttySessionsRegistryProvider.cs
Remove previous fixes return statement
2023-03-15 08:22:29 -04:00
BlueBlock
209319f460 Update PuttySessionsRegistryProvider.cs
Update the latest fix for the putty registry watcher, to create the registry path if it does not exist, so the watcher is able to always run.
2023-03-15 08:14:52 -04:00
BlueBlock
5ec4f4dcea add rdp rdc11 2023-03-15 08:04:01 -04:00
Dimitrij
16f67d58d1 Merge pull request #2372 from BlueBlock/fix_exception_when_no_putty_sessions_exist
fix exception when no putty sessions exist
2023-03-14 19:32:10 +00:00
Dimitrij
542d794ab4 Merge pull request #2373 from BlueBlock/fix_exception_with_notification_on_app_closing
Update MessageFocusDecorator.cs
2023-03-14 17:03:33 +00:00
Dimitrij
ede1573b56 Merge pull request #2375 from BlueBlock/fix_exception_for_protocolbase_when_closing_app
Update ProtocolBase.cs
2023-03-14 16:24:43 +00:00
Dimitrij
bc8eec8887 Merge pull request #2374 from BlueBlock/add_rdp_protocol_rdc10
add rdc10 protocol
2023-03-14 15:35:38 +00:00
Dimitrij
59b0654b95 Merge pull request #2371 from BlueBlock/fix_installer_build_order
Update mRemoteNG.sln
2023-03-14 15:24:05 +00:00
Dimitrij
cae3477591 Merge pull request #2370 from BlueBlock/fix_file_fragments
Update FilesFragment.wxs
2023-03-14 15:22:30 +00:00
BlueBlock
6a3115b80a Update ProtocolBase.cs
Do not attempt to dispose the control if the control is already closed, closing or disposed.
2023-03-14 04:44:42 -04:00
BlueBlock
1232d7c288 add rdc10 protocol 2023-03-13 22:38:13 -04:00
BlueBlock
8e1b4c9271 Update MessageFocusDecorator.cs
do not attempt to focus the notification panel if the application is closing, otherwise exceptions will occur since _frmMain is closing
2023-03-13 20:08:48 -04:00
BlueBlock
0f8810e22a fix exception when no putty sessions exist
When putty is not installed or no sessions exist in the registry, an exception is thrown when starting the eventwatcher. Only start the eventwatcher if sessions registry path exists.
2023-03-13 18:53:00 -04:00
BlueBlock
7bbff38b6b Update mRemoteNG.sln
fix install build order by also including building mremoteng
2023-03-13 18:47:14 -04:00
BlueBlock
4a7b8fa250 Update FilesFragment.wxs
fix some dll paths and remove unused dll
2023-03-13 18:44:26 -04:00
Dimitrij
53acc94976 Merge pull request #2369 from BlueBlock/fix_find_vstool.ps1
Update find_vstool.ps1
2023-03-13 14:11:00 +00:00
BlueBlock
ab8d83b12d Update find_vstool.ps1
add vs2022 cert thunbprint
fix function which tests if a file is executable
2023-03-13 09:46:27 -04:00
Dimitrij
713a0a6174 more fixes for CA1416 2023-03-11 13:13:19 +00:00
Dimitrij
a3b9695b81 lib replace 2023-03-11 12:38:53 +00:00
Dimitrij
85dd381bd9 lib update 2023-03-11 12:21:17 +00:00
Dimitrij
05b418e9b6 more fix for Warning CA1416 2023-03-11 12:20:19 +00:00
Dimitrij
40af584afe fix for Warning CA1416 2023-03-11 01:46:11 +00:00
Dimitrij
93fe32491b couple of fixes 2023-03-10 23:00:05 +00:00
Dimitrij
4b67fcb0d4 fix splash screen version logo 2023-03-09 09:12:40 +00:00
Dimitrij
0b0c92717d fix format to avoid error on file name 2023-03-08 22:15:25 +00:00
Dimitrij
4564cafa85 more fixes for CA1416 2023-03-08 21:50:23 +00:00
Dimitrij
2e21f8d03a add form 2023-03-08 20:51:58 +00:00
Dimitrij
4336254d56 fix naming after rename 2023-03-08 20:36:00 +00:00
Dimitrij
bc5e9279a5 fix naming to be inline with Others 2023-03-08 20:28:31 +00:00
Dimitrij
1bfbb956c2 fix CA1416: Validate platform compatibility
https://learn.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/quality-rules/ca1416
2023-03-08 20:23:38 +00:00
Dimitrij
b336db773c Merge pull request #2367 from BlueBlock/update_build_scripts
Update build scripts
2023-03-08 19:32:06 +00:00
BlueBlock
30e7d2424c Merge remote-tracking branch 'upstream/v1.77.3-dev' into update_build_scripts 2023-03-08 14:08:46 -05:00
kmscode
cbb8c0234d fixed a few warnings 2023-03-05 20:10:32 -05:00
kmscode
95469107fd don't need to manually editbin for large address aware on x64 targets 2023-03-05 15:37:49 -05:00
Dimitrij
ba0058c0b9 fix installer paths 2023-03-04 22:49:23 +00:00
Dimitrij
8f35afe353 fix for portable version 2023-03-04 21:02:19 +00:00
Dimitrij
aaf219eb90 revert check due set variable explicitly in appveyor 2023-03-04 20:32:22 +00:00
Dimitrij
1167794d58 fix condition to work in appveyor env. 2023-03-04 18:38:12 +00:00
Dimitrij
929babd69a Update change log 2023-03-04 00:35:35 +00:00
Dimitrij
870b7c1ffd update links 2023-03-04 00:07:19 +00:00
Dimitrij
9ed9d835b9 file harvester update 2023-03-04 00:06:55 +00:00
Dimitrij
985feb4b91 name space sync 2023-03-03 23:25:18 +00:00
Dimitrij
c43c85bb21 lib Update
correction for update window
2023-03-03 22:19:38 +00:00
Dimitrij
038074131c add template for build versioning 2023-03-03 20:45:40 +00:00
Dimitrij
ab9156a7d3 Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2023-03-03 15:44:34 +00:00
Dimitrij
f4b76818e8 lib update 2023-03-03 15:42:33 +00:00
Dimitrij
12a399a354 Merge pull request #2364 from BlueBlock/update_sql_usage_instructions
update sql usage doc
2023-03-02 13:55:24 +00:00
BlueBlock
dfdbbea85c sql usage doc updated 2023-03-02 08:32:07 -05:00
BlueBlock
5fad5ec4c7 Merge remote-tracking branch 'upstream/v1.77.3-dev' into update_build_scripts 2023-03-02 08:28:10 -05:00
Dimitrij
fe94da4727 lib update 2023-03-02 09:42:43 +00:00
Dimitrij
361ae3af50 Merge pull request #2362 from BlueBlock/fix_use_of_sql_database
Fix use of sql database
2023-03-02 09:34:06 +00:00
BlueBlock
a2e302ebfa add check for appveyor only actions in scripts 2023-03-01 15:31:54 -05:00
BlueBlock
186ab9c00e Merge remote-tracking branch 'upstream/v1.77.3-dev' into update_build_scripts 2023-03-01 14:50:49 -05:00
BlueBlock
9a2453524a update db to 2.9 2023-03-01 14:19:41 -05:00
BlueBlock
3a2e128e98 add missing columns to serializer 2023-03-01 11:22:18 -05:00
BlueBlock
1bd2dbf9f0 modify schema to be consistent 2023-03-01 11:21:55 -05:00
BlueBlock
b7f880e7f8 modify sql bit columns to be consistent 2023-03-01 11:21:26 -05:00
BlueBlock
13cd926b4f add missing columns 2023-03-01 09:37:10 -05:00
BlueBlock
6fb7b1c6e4 update docs to reflect auto-schema generation 2023-03-01 07:29:31 -05:00
BlueBlock
8f35015a6c fix db upgrade
fix db upgrade 2.8->2.9
2023-03-01 07:11:45 -05:00
BlueBlock
a926bccb97 fix db upgrade
fix db upgrade 2.7->2.8
2023-03-01 07:11:30 -05:00
BlueBlock
b9f2abf5eb add db schema initialization on a new empty database 2023-03-01 07:10:29 -05:00
BlueBlock
8dc5bda171 Update SqlDatabaseVersionVerifier.cs
fix CRLF of file
2023-03-01 07:09:33 -05:00
Dimitrij
d24bdb543b lib update 2023-02-26 21:40:14 +00:00
BlueBlock
dc921161e4 Merge remote-tracking branch 'upstream/v1.77.3-dev' into update_build_scripts 2023-02-25 17:37:58 -05:00
Dimitrij
8e248cb545 lib update 2023-02-21 21:48:20 +00:00
BlueBlock
ae93be4cfb make website update optional 2023-02-20 12:39:29 -05:00
BlueBlock
42949fbe91 update build scripts to create update files 2023-02-20 05:21:11 -05:00
Dimitrij
21dd175456 lib update 2023-02-17 19:49:47 +00:00
BlueBlock
a3df0da26b widen the version label further 2023-02-16 16:55:40 -05:00
BlueBlock
6b9d4fd107 increase label width for version on splashscreen
Widen to support longer version numbers such as 1.77.3.1234
2023-02-16 16:27:17 -05:00
BlueBlock
fac2ae6399 Merge remote-tracking branch 'upstream/v1.77.3-dev' into update_build_scripts 2023-02-16 15:47:57 -05:00
Dimitrij
46732803c3 Merge pull request #2356 from BlueBlock/improve_options_page_speed
improve speed for the display of the options page
2023-02-16 20:16:47 +00:00
BlueBlock
39d205bd4d improve speed for the display of the options page
rather than create the options page on demand, instantiate the options page immediately upon app start though in the background using idle time.
2023-02-16 14:57:11 -05:00
Dimitrij
8e2bd7997e update "Known Issues" regarding how-to update PuttyNG to latest 2023-02-16 11:12:44 +00:00
Dimitrij
76db9a6c62 Merge pull request #2352 from pakass/SSH.NET-update
SSH.NET Update
2023-02-16 09:45:30 +00:00
pakass
c03d5e891d update Changelog 2023-02-15 15:15:55 +01:00
pakass
b21f6e8ce7 update SSH.NET 2023-02-15 15:11:22 +01:00
BlueBlock
4b916f1888 update build scripts 2023-02-14 19:38:08 -05:00
Dimitrij
1f80e5339b Merge pull request #2348 from BlueBlock/remove_mat_kit
Remove mat kit included unintentionally
2023-02-13 09:30:48 +00:00
BlueBlock
dc616f8ea1 remove mat kit included unintentionally
It appears the mat kit config was included along with some .xlf definitions on the csproj

Remove th mat kit and references
2023-02-12 16:39:30 -05:00
Dimitrij
dc6588243f libs update 2023-02-11 21:31:12 +00:00
Dimitrij
690d3b0d4e Merge pull request #2347 from savornicesei/simo/gh-2344-docs-log4net-patching
Documented manual patching of  log4net CVE-2018-1285 vulnerability #2344
2023-02-11 12:41:09 +00:00
Dimitrij
4bc5dffabb Merge pull request #2346 from BlueBlock/add_feature_to_auto_reconnect_without_clicking_check
Modify "auto reconnect" to have the ability to really auto-reconnect
2023-02-11 12:35:02 +00:00
Simona Avornicesei
55a1e4a544 Documented manual patching of log4net CVE-2018-1285 vulnerability #2344 2023-02-10 21:17:26 +02:00
BlueBlock
5cb32dd75a change reconnect timer from 2s to 5s
Change and increase the reconnect timer to avoid too frequent connection attempts.
2023-02-10 04:40:55 -05:00
BlueBlock
f858c9fe48 fix checkbox state 2023-02-10 04:39:13 -05:00
BlueBlock
0ac39af404 modify "auto reconnect" to really auto-reconnect
The auto-reconnect does not automatically reconnect but instead displays a reconnect dialog. A second Options checkbox is added to allow true auto-reconnect.
2023-02-09 13:41:31 -05:00
Dimitrij
fc757b236f lib update 2023-02-04 16:42:12 +00:00
Dimitrij
a921e6e3d4 Merge pull request #2340 from BlueBlock/set_default_theme_on_first_run
set the default theme setting
2023-02-04 16:28:34 +00:00
Dimitrij
8cf0f50565 Merge pull request #2341 from BlueBlock/fix_broken_tests
Fix broken tests
2023-02-04 16:26:34 +00:00
Dimitrij
575ad7664f Merge pull request #2343 from savornicesei/simo/gh-2342-installer-in-debug-mode
Build installer in Debug mode #2342
2023-02-04 16:23:51 +00:00
Dimitrij
be17488070 Merge pull request #2339 from BlueBlock/add_missing_settings
Add 2 missing settings
2023-02-04 16:23:07 +00:00
Simona Avornicesei
f504107928 Build installer in Debug mode #2342 2023-02-04 10:10:51 +02:00
BlueBlock
0113f549c5 fix remaining unit tests 2023-02-03 17:35:09 -05:00
BlueBlock
9ff831faab fix additional tests 2023-02-03 17:05:36 -05:00
BlueBlock
a9ca243c0b fix protocol config unit tests 2023-02-03 16:53:29 -05:00
BlueBlock
553bbef45f set the default theme setting
On the initial start of a fresh install, if the options are opened the theme is then set from an empty string to the default. This causes the user to see the "must restart app" dialog when closing the options.

This only occurs on the initial run of the app. If the app is closed and run again, the theme will have been set.
2023-02-03 14:34:38 -05:00
BlueBlock
8f713f861b Add 2 missing settings
Two settings are missing in the settings but do exist in the Designer class.  These settings are used in code so they do need to exist.
ConDefaultRDGatewayUserViaAPI
ConDefaultRDGatewayExternalCredentialProvider
2023-02-03 14:12:02 -05:00
Dimitrij
324054b9d7 Merge pull request #2337 from BlueBlock/set_language_resx_to_autogen_language_class
set language.resx to auto generate the designer class
2023-02-03 10:10:20 +00:00
BlueBlock
d3fc9404ee set language.resx to auto generate the designer class
This avoids the need to manually regenerate the Language.Designer.cs file.

Note that in VS the file Language.Designer.cs will appear under Language.resx but the actual file locations have not changed.
2023-02-02 10:25:27 -05:00
Dimitrij
5bb780439b add autodate as was suggested by @savornicese 2023-02-01 12:56:43 +00:00
Dimitrij
f0e6008441 lib update 2023-02-01 12:44:37 +00:00
Dimitrij
39dd69f15e Merge pull request #2334 from BlueBlock/fix_build_order
Fix the dependencies for the Installer project build
2023-02-01 12:37:47 +00:00
Dimitrij
7b2e89df26 Merge pull request #2335 from BlueBlock/update_packages
Update project packages
2023-02-01 12:36:14 +00:00
BlueBlock
aa853f8481 Update project packages 2023-01-31 14:44:37 -05:00
BlueBlock
83bba75af6 Fix the dependencies for the Installer project build
The Installer project fails to build without also specifying the ExternalConnectors and mRemoteNG projects as dependencies.
2023-01-31 10:46:51 -05:00
Dimitrij
23889aa5b1 lib update 2023-01-08 11:57:03 +00:00
Dimitrij
5e6094fc42 lib update 2022-11-15 15:16:03 +00:00
Dimitrij
a4181cb6d6 Merge pull request #2301 from bartuszekj/splash_screen_fix
Fix for splash screen to appear on the primary screen.
2022-11-14 09:29:06 +00:00
Jerzy Bartuszek
88c49f0722 Fix for splash screen to appear on the primary screen. 2022-11-11 17:06:50 -06:00
Dimitrij
513d9e199c lib update 2022-11-09 14:34:02 +00:00
Dimitrij
e80975c56e lib update 2022-10-20 11:53:32 +01:00
Dimitrij
9051ac102c Merge pull request #2298 from SOlangsam/patch-2
Update mysql_db_setup.sql
2022-10-19 19:13:44 +01:00
SOlangsam
39a9b2e619 Update mysql_db_setup.sql
Added missing fields
Fix Issue for mysql #2292
2022-10-11 16:40:08 +02:00
Dimitrij
dbc55d248f add version color overwrite 2022-10-06 18:58:52 +01:00
Dimitrij
2b46180bfb clear inherited max-width 2022-10-06 18:41:31 +01:00
Dimitrij
5abe6c7e27 empty css 2022-10-06 18:30:31 +01:00
Dimitrij
4595ebeb9a next try to fix theme 2022-10-06 17:36:45 +01:00
Dimitrij
815c08e6d4 fix colors of sidebar 2022-10-05 21:31:30 +01:00
Dimitrij
a72ad218a0 fix for menu links color 2022-10-05 21:14:46 +01:00
Dimitrij
944ad1f769 Merge pull request #2295 from CrunchyBlue/v1.77.3-dev
*Updates hyperlink style to make links more visible to end users
2022-10-05 19:40:07 +01:00
PRINTABLE\dgagliardi
e17a68f61c *Updates hyperlink style to make links more visible to end users 2022-10-05 11:40:30 -05:00
Dimitrij
0b8196be68 Merge pull request #2285 from tecxx/develop-orig
support extraction of SSH private keys from external cred prov
2022-09-07 13:59:21 +01:00
tecxx
d9c01148b7 support extraction of SSH private keys from external credential provider (DSS)
supported formats: rsa, rsa with passphrase, putty private key
2022-09-07 14:08:29 +02:00
Dimitrij
2b3cfd992f Merge pull request #2275 from tecxx/develop-orig
external connectors improvement
2022-08-25 21:36:27 +01:00
tecxx
7e4bd7a6f3 add UI property selectors for external connectors
add support for external credential provider in remote desktop gateway
rename TSS to DSS
fix tests and property naming issues
2022-08-25 21:58:16 +02:00
Dimitrij
161e0ed637 fix for #2208 2022-08-22 10:31:54 +01:00
Dimitrij
1ee03e863c Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2022-07-29 23:26:59 +01:00
Dimitrij
2411481d8b lib upd 2022-07-29 23:26:14 +01:00
Dimitrij
0314a627ed Merge pull request #2259 from luciusagarthy/patch-1
Update Language.cs-CZ.resx
2022-07-27 23:39:09 +01:00
Dimitrij
4d339a0b09 Merge pull request #2261 from maxshlain/v1.77.3-hide-filemenu
Implement Show/Hide file menu in view menu
2022-07-27 23:38:37 +01:00
Dimitrij
c171e7f94b Merge branch 'v1.77.3-dev' of https://github.com/mRemoteNG/mRemoteNG into v1.77.3-dev 2022-07-17 23:14:21 +01:00
Dimitrij
eac4d966d9 remove not needed reference to old ObjectListView 2.7 2022-07-17 23:11:36 +01:00
Dimitrij
c20868c20c lib update 2022-07-17 22:42:17 +01:00
maxim-shlain
bb74d46f1f Implement Show/Hide file menu in view menu 2022-07-08 19:34:42 +03:00
luciusagarthy
152d48c583 Update Language.cs-CZ.resx
Thank you for a great app. I will contribute more. Here is some translation.
2022-07-07 16:19:48 +02:00
Dimitrij
b7a0155ba4 lib update 2022-06-25 06:39:19 +01:00
Dimitrij
0414724b21 update 2022-06-13 13:34:21 +01:00
Dimitrij
469f21db8d lib update 2022-06-13 10:35:41 +01:00
594 changed files with 35518 additions and 15325 deletions

130
.github/workflows/build-x86_64.yml vendored Normal file
View File

@@ -0,0 +1,130 @@
name: Build x86_64
on:
push:
branches:
- v1.77.3-dev
jobs:
Build-Debug-MSI:
runs-on: windows-2022
steps:
- name: 01. Copy repository
uses: actions/checkout@v4
- name: 02. Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
with:
vs-version: '17.12.4'
- name: 03. Restore nuget packages for solution
shell: pwsh
run: |
dotnet restore
- name: 04. Compile mRemoteNG
shell: pwsh
run: |
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Debug Installer" -p:Platform=x64 /verbosity:normal
- name: 05. Publish MSI as Artifact
uses: actions/upload-artifact@v4
with:
name: debug-msi-x86_64
path: ${{ github.workspace }}\mRemoteNGInstaller\Installer\bin\x64\Debug\en-US\
if-no-files-found: error
Build-Debug-Portable:
runs-on: windows-2022
steps:
- name: 01. Copy repository
uses: actions/checkout@v4
- name: 02. Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
with:
vs-version: '17.8.3'
- name: 03. Restore nuget packages for solution
shell: pwsh
run: |
dotnet restore
- name: 04. Compile mRemoteNG
shell: pwsh
run: |
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Debug Portable" -p:Platform=x64 /verbosity:normal
- name: 05. Publish Portable Binary as Artifact
uses: actions/upload-artifact@v4
with:
name: debug-portable-x86_64
path: ${{ github.workspace }}\mRemoteNG\bin\x64\Debug Portable\
if-no-files-found: error
Build-Release:
runs-on: windows-2022
steps:
- name: 01. Copy repository
uses: actions/checkout@v4
- name: 02. Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
with:
vs-version: '17.12.4'
- name: 03. Restore nuget packages for solution
shell: pwsh
run: |
dotnet restore
- name: 04. Compile mRemoteNG
shell: pwsh
run: |
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Release Installer and Portable" -p:Platform=x64 /verbosity:normal
- name: 05. Publish MSI Binary as Artifact
uses: actions/upload-artifact@v4
with:
name: release-msi-x86_64
path: ${{ github.workspace }}\mRemoteNGInstaller\Installer\bin\x64\Release\en-US\
if-no-files-found: error
- name: 06. Publish Portable Binary as Artifact
uses: actions/upload-artifact@v4
with:
name: release-portable-x86_64
path: ${{ github.workspace }}\mRemoteNG\bin\x64\Release
if-no-files-found: error
Create-Release:
needs: [Build-Debug-MSI, Build-Debug-Portable, Build-Release]
runs-on: ubuntu-22.04
steps:
- name: 01. Copy repository
uses: actions/checkout@v4
- name: 02. Download Artifacts
uses: actions/download-artifact@v4
- name: 03. Create compressed archives # Needs to be done because "actions/download-artifact@v4" is extracting the zipped Artifacts
shell: bash
run: |
zip -r debug-msi-x86_64.zip debug-msi-x86_64/
zip -r debug-portable-x86_64.zip debug-portable-x86_64/
zip -r release-msi-x86_64.zip release-msi-x86_64/
zip -r release-portable-x86_64.zip release-portable-x86_64/
- name: 04. Create Release
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "v1.77.3-dev-${GITHUB_RUN_NUMBER}" \
--title "v1.77.3-dev-${GITHUB_RUN_NUMBER}" \
--prerelease \
--generate-notes \
$GITHUB_WORKSPACE/debug-msi-x86_64.zip \
$GITHUB_WORKSPACE/debug-portable-x86_64.zip \
$GITHUB_WORKSPACE/release-msi-x86_64.zip \
$GITHUB_WORKSPACE/release-portable-x86_64.zip

6
.gitignore vendored
View File

@@ -283,6 +283,6 @@ Installer Projects/Installer/Fragments/HelpFilesFragment.wxs
InstallerProjects/Installer/Fragments/FilesFragment.wxs
InstallerProjects/Installer/Resources/License.rtf
# gh-pages info
runlocal.bat
/_site
# mRemoteNG
**/mRemoteNG/Properties/AssemblyInfo.tt
**/mRemoteNG/Properties/AssemblyInfo.cs

11
Add-ons/README.md Normal file
View File

@@ -0,0 +1,11 @@
## Add-ons library by 3rd party
This is a list of add-ons, plugins and extentions what could be used with mRemoteNG, if you wish to add yours to this list - just drop me a line: <a href="mailto:support@mremoteng.org">support@mremoteng.org</a>
<br>
| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Date&nbsp;added</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Author</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | <b>Type</b> | <b>Name</b> | <b>Description</b> | <b>Repository</b> |
| :---------------------------------------------------------:|:-------------------------------------------------:| :---------: |-------------|--------------------|:-----------------:|
| 02-08-2022 | <a href="https://github.com/JustBeta"><img align="left" src="https://avatars.githubusercontent.com/u/25150896?v=4" alt="JustBeta" width="30px"/>JustBeta</a> | script | Export-MobaXterm2mRemoteNG | Conversion of MobaXterm's ini file to mRemoteNG format. | [GITHUB Repository](https://github.com/JustBeta/Export-MobaXtern2mRemoteNG/tree/main) |
<br>
For a detailed usage examples and documentation please reach out authors.

View File

@@ -2,9 +2,30 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.77.3.1784]
### Fixed
- #2362: Fix use of sql database
- #2356: Improve speed for the display of the options page
- #2352: SSH.NET Update
- #2346: Modify "auto reconnect" to have the ability to really auto-reconnect
- #2340: Set the default theme setting
- #2339: Add 2 missing settings
- #2261: Implement Show/Hide file menu in view menu
- #2244: Save RCG and RestrictedAdmin fields correctly in connections file
- #2195: Fix crafted XML File Code Execution vulnerability
- #304: use pwfile instead of cleartext password for puttyng
### Added
- #2285: Support extraction of SSH private keys from external cred prov
- #2268: Postregsql database support
### Updated
- #2295: Updates hyperlink style to make links more visible to end users
- #2337: Set language.resx to auto generate the designer class
## [1.77.3]
### Added
- #1736: Update of SSH.NET to 2020.0.2 to allow File Transfer again
- #2138: Improve compatibility with Remote Desktop Connection Manager v2.83
- #2123: Thycotic Secret Server - Added 2FA OTP support
### Changed

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,241 @@
namespace ExternalConnectors.CPS
{
partial class CPSConnectionForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CPSConnectionForm));
tbServerURL = new TextBox();
label3 = new Label();
tbAPIKey = new TextBox();
btnOK = new Button();
btnCancel = new Button();
tableLayoutPanel1 = new TableLayoutPanel();
label1 = new Label();
label6 = new Label();
tbOTP = new TextBox();
cbUseSSO = new CheckBox();
tableLayoutPanel2 = new TableLayoutPanel();
label4 = new Label();
tableLayoutPanel1.SuspendLayout();
tableLayoutPanel2.SuspendLayout();
SuspendLayout();
//
// tbServerURL
//
tbServerURL.Dock = DockStyle.Fill;
tbServerURL.Location = new Point(298, 5);
tbServerURL.Margin = new Padding(5);
tbServerURL.Name = "tbServerURL";
tbServerURL.Size = new Size(611, 27);
tbServerURL.TabIndex = 0;
//
// label3
//
label3.AutoSize = true;
label3.Dock = DockStyle.Fill;
label3.Location = new Point(5, 84);
label3.Margin = new Padding(5, 0, 5, 0);
label3.Name = "label3";
label3.Size = new Size(283, 42);
label3.TabIndex = 5;
label3.Text = "API Key";
label3.TextAlign = ContentAlignment.MiddleLeft;
//
// tbAPIKey
//
tbAPIKey.Dock = DockStyle.Fill;
tbAPIKey.Location = new Point(298, 89);
tbAPIKey.Margin = new Padding(5);
tbAPIKey.Name = "tbAPIKey";
tbAPIKey.Size = new Size(611, 27);
tbAPIKey.TabIndex = 4;
tbAPIKey.UseSystemPasswordChar = true;
//
// btnOK
//
btnOK.Anchor = AnchorStyles.Right;
btnOK.DialogResult = DialogResult.OK;
btnOK.Location = new Point(337, 16);
btnOK.Margin = new Padding(5);
btnOK.Name = "btnOK";
btnOK.Size = new Size(101, 35);
btnOK.TabIndex = 6;
btnOK.Text = "OK";
btnOK.UseVisualStyleBackColor = true;
//
// btnCancel
//
btnCancel.Anchor = AnchorStyles.Left;
btnCancel.DialogResult = DialogResult.Cancel;
btnCancel.Location = new Point(474, 16);
btnCancel.Margin = new Padding(5);
btnCancel.Name = "btnCancel";
btnCancel.Size = new Size(101, 35);
btnCancel.TabIndex = 11;
btnCancel.Text = "Cancel";
btnCancel.UseVisualStyleBackColor = true;
//
// tableLayoutPanel1
//
tableLayoutPanel1.ColumnCount = 2;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 32.06997F));
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 67.93003F));
tableLayoutPanel1.Controls.Add(label1, 0, 0);
tableLayoutPanel1.Controls.Add(label3, 0, 2);
tableLayoutPanel1.Controls.Add(tbServerURL, 1, 0);
tableLayoutPanel1.Controls.Add(tbAPIKey, 1, 2);
tableLayoutPanel1.Controls.Add(label6, 0, 3);
tableLayoutPanel1.Controls.Add(tbOTP, 1, 3);
tableLayoutPanel1.Controls.Add(cbUseSSO, 0, 1);
tableLayoutPanel1.Dock = DockStyle.Top;
tableLayoutPanel1.Location = new Point(0, 0);
tableLayoutPanel1.Margin = new Padding(5);
tableLayoutPanel1.Name = "tableLayoutPanel1";
tableLayoutPanel1.RowCount = 5;
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 20F));
tableLayoutPanel1.Size = new Size(914, 212);
tableLayoutPanel1.TabIndex = 12;
//
// label1
//
label1.AutoSize = true;
label1.Dock = DockStyle.Fill;
label1.Location = new Point(5, 0);
label1.Margin = new Padding(5, 0, 5, 0);
label1.Name = "label1";
label1.Size = new Size(283, 42);
label1.TabIndex = 2;
label1.Text = "Passwordstate URL";
label1.TextAlign = ContentAlignment.MiddleLeft;
//
// label6
//
label6.AutoSize = true;
label6.Dock = DockStyle.Fill;
label6.Location = new Point(3, 126);
label6.Name = "label6";
label6.Size = new Size(287, 42);
label6.TabIndex = 15;
label6.Text = "2FA OTP (Optional)";
//
// tbOTP
//
tbOTP.Dock = DockStyle.Fill;
tbOTP.Location = new Point(298, 131);
tbOTP.Margin = new Padding(5);
tbOTP.Name = "tbOTP";
tbOTP.Size = new Size(611, 27);
tbOTP.TabIndex = 5;
//
// cbUseSSO
//
cbUseSSO.Anchor = AnchorStyles.Left;
cbUseSSO.AutoSize = true;
cbUseSSO.Location = new Point(5, 53);
cbUseSSO.Margin = new Padding(5, 5, 5, 0);
cbUseSSO.Name = "cbUseSSO";
cbUseSSO.Size = new Size(157, 24);
cbUseSSO.TabIndex = 14;
cbUseSSO.Text = "Use SSO / WinAuth";
cbUseSSO.UseVisualStyleBackColor = true;
cbUseSSO.CheckedChanged += cbUseSSO_CheckedChanged;
//
// tableLayoutPanel2
//
tableLayoutPanel2.ColumnCount = 5;
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 106F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 26F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 107F));
tableLayoutPanel2.Controls.Add(btnOK, 1, 0);
tableLayoutPanel2.Controls.Add(btnCancel, 3, 0);
tableLayoutPanel2.Dock = DockStyle.Bottom;
tableLayoutPanel2.Location = new Point(0, 300);
tableLayoutPanel2.Margin = new Padding(5);
tableLayoutPanel2.Name = "tableLayoutPanel2";
tableLayoutPanel2.RowCount = 1;
tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
tableLayoutPanel2.Size = new Size(914, 67);
tableLayoutPanel2.TabIndex = 13;
//
// label4
//
label4.AutoSize = true;
label4.Dock = DockStyle.Fill;
label4.Location = new Point(0, 212);
label4.Margin = new Padding(5, 0, 5, 0);
label4.Name = "label4";
label4.Size = new Size(345, 20);
label4.TabIndex = 14;
label4.Text = "URL is the base URL, like https://pass.domain.local/";
label4.TextAlign = ContentAlignment.MiddleLeft;
//
// CPSConnectionForm
//
AcceptButton = btnOK;
AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(914, 367);
Controls.Add(label4);
Controls.Add(tableLayoutPanel2);
Controls.Add(tableLayoutPanel1);
Icon = (Icon)resources.GetObject("$this.Icon");
Margin = new Padding(5);
Name = "CPSConnectionForm";
Text = "Passwordstate API Login Data";
Activated += CPSConnectionForm_Activated;
tableLayoutPanel1.ResumeLayout(false);
tableLayoutPanel1.PerformLayout();
tableLayoutPanel2.ResumeLayout(false);
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label label3;
public System.Windows.Forms.TextBox tbServerURL;
//public System.Windows.Forms.TextBox tbUsername;
public System.Windows.Forms.TextBox tbAPIKey;
private System.Windows.Forms.Button btnOK;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
public System.Windows.Forms.CheckBox cbUseSSO;
private System.Windows.Forms.Label label4;
private Label label6;
public TextBox tbOTP;
}
}

View File

@@ -0,0 +1,41 @@
namespace ExternalConnectors.CPS
{
public partial class CPSConnectionForm : Form
{
public CPSConnectionForm()
{
InitializeComponent();
}
private void CPSConnectionForm_Activated(object sender, EventArgs e)
{
SetVisibility();
if (cbUseSSO.Checked)
btnOK.Focus();
else
{
if (tbAPIKey.Text.Length == 0)
tbAPIKey.Focus();
else
tbOTP.Focus();
}
tbAPIKey.Focus();
if (!string.IsNullOrEmpty(tbAPIKey.Text) || cbUseSSO.Checked == true)
tbOTP.Focus();
}
private void cbUseSSO_CheckedChanged(object sender, EventArgs e)
{
SetVisibility();
}
private void SetVisibility()
{
bool ch = cbUseSSO.Checked;
tbAPIKey.Enabled = !ch;
//tbUsername.Enabled = !ch;
}
}
}

View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAA
AAAtLDAA+PDaAP///wD79ugA/PrzAPf39wBGRUkA7NacAM2WAAA3z6kA+Pz/AIKBgwD+//4A4sNtAHXe
xAD8+vIAjuTOANOjHgDV6/4AJZf3APn5+QDw37IAIB8jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAgICAgICCQ4CAgIWAgIUAgICAgICAgkJAgICFhYWAAIIDwICAgICCQwCAhYWFgYCCAgIBwIC
AgkJAgsWFhYWBQICCAgIAwIJCQIWFhYWAgICAgINCAgCAgICFhYCAgICAgICAgIRAgICAgICAgICAgIC
AgICEwICAgICEhMTExMCAgITExMCAgICAgITExMTAhMTExMCAgICAgICAgICAhMTEwICAgIICAIJCQIC
AgIKAgICAgIICAQCAgkJAgICAgICAgICCAgCAgICCQkCAgICAgICFQgBAgICAgwJAgICAgICAggIAgIC
AgICEAkCAgICAgIIAgICAgICAgICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
</value>
</data>
</root>

View File

@@ -0,0 +1,301 @@
using Microsoft.Win32;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using System.Security.Cryptography;
using System.Text.Json;
using System.Text.Json.Nodes;
namespace ExternalConnectors.CPS;
public class PasswordstateInterface
{
private static class CPSConnectionData
{
public static string ssUsername = "";
public static string ssPassword = "";
public static string ssUrl = "";
public static string ssOTP = "";
public static DateTime ssOTPTimeStampExpiration;
public static bool ssSSO = false;
public static bool initdone = false;
//token
//public static string ssTokenBearer = "";
//public static DateTime ssTokenExpiresOn = DateTime.UtcNow;
//public static string ssTokenRefresh = "";
public static void Init()
{
// 2024-05-04 passwordstate currently does not support auth tokens, so we need to re-enter otp codes frequently
if (!string.IsNullOrEmpty(ssOTP) && DateTime.Now > ssOTPTimeStampExpiration)
{
ssOTP = "";
initdone = false;
}
if (initdone == true)
return;
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteCPSInterface");
try
{
// display gui and ask for data
CPSConnectionForm f = new CPSConnectionForm();
//string? un = key.GetValue("Username") as string;
//f.tbUsername.Text = un ?? "";
f.tbAPIKey.Text = CPSConnectionData.ssPassword; // in OTP refresh cases, this value might already be filled
string? url = key.GetValue("URL") as string;
if (url == null || !url.Contains("://"))
url = "https://cred.domain.local/SecretServer";
f.tbServerURL.Text = url;
var b = key.GetValue("SSO");
if (b == null || (string)b != "True")
ssSSO = false;
else
ssSSO = true;
f.cbUseSSO.Checked = ssSSO;
// show dialog
while (true)
{
_ = f.ShowDialog();
if (f.DialogResult != DialogResult.OK)
return;
// store values to memory
//ssUsername = f.tbUsername.Text;
ssPassword = f.tbAPIKey.Text;
ssUrl = f.tbServerURL.Text;
ssSSO = f.cbUseSSO.Checked;
ssOTP = f.tbOTP.Text;
ssOTPTimeStampExpiration = DateTime.Now.AddSeconds(30);
// check connection first
try
{
if (TestCredentials() == true)
{
initdone = true;
break;
}
}
catch (Exception)
{
MessageBox.Show("Test Credentials failed - please check your credentials");
}
}
// write values to registry
//key.SetValue("Username", ssUsername);
key.SetValue("URL", ssUrl);
key.SetValue("SSO", ssSSO);
}
catch (Exception)
{
throw;
}
finally
{
key.Close();
}
}
}
private static bool TestCredentials()
{
return ConnectionTest();
}
private static bool ConnectionTest()
{
if (CPSConnectionData.ssSSO)
{
string url = $"{CPSConnectionData.ssUrl}/winapi/passwordlists/";
using HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
var json = client.GetStringAsync(url).Result;
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
if (data == null)
return false;
return true;
}
else
{
string url = $"{CPSConnectionData.ssUrl}/api/passwordlists/";
using HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
client.DefaultRequestHeaders.Add("APIKey", CPSConnectionData.ssPassword);
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
var json = client.GetStringAsync(url).Result;
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
if (data == null)
return false;
return true;
}
}
private static JsonNode? FetchDataWinAuth(int secretID)
{
string url = $"{CPSConnectionData.ssUrl}/winapi/passwords/{secretID}";
using HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
var json = client.GetStringAsync(url).Result;
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
if (data == null)
return null;
JsonNode? element = data[0];
return element;
}
private static JsonNode? FetchDataAPIKeyAuth(int secretID)
{
string url = $"{CPSConnectionData.ssUrl}/api/passwords/{secretID}";
using HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("User-Agent", "mRemote");
client.DefaultRequestHeaders.Add("APIKey", CPSConnectionData.ssPassword);
client.DefaultRequestHeaders.Add("OTP", CPSConnectionData.ssOTP);
var json = client.GetStringAsync(url).Result;
JsonNode? data = JsonSerializer.Deserialize<JsonNode>(json);
if (data == null)
return null;
JsonNode? element = data[0];
return element;
}
private static void FetchSecret(int secretID, out string secretUsername, out string secretPassword, out string secretDomain, out string privatekey)
{
// clear return variables
secretDomain = "";
secretUsername = "";
secretPassword = "";
privatekey = "";
string privatekeypassphrase = "";
JsonNode? element = null;
if (CPSConnectionData.ssSSO)
element = FetchDataWinAuth(secretID);
else
element = FetchDataAPIKeyAuth(secretID);
if (element == null)
return;
var dom = element["Domain"];
if (dom != null) secretDomain = dom.ToString();
var user = element["UserName"];
if (user != null) secretUsername = user.ToString();
var pw = element["Password"];
if (pw != null) secretPassword = pw.ToString();
var privkey = element["GenericField1"];
if (privkey != null) privatekey = privkey.ToString();
var phrase = element["GenericField3"];
if (phrase != null) privatekeypassphrase = phrase.ToString();
// need to decode the private key?
if (!string.IsNullOrEmpty(privatekeypassphrase))
{
try
{
var key = DecodePrivateKey(privatekey, privatekeypassphrase);
privatekey = key;
}
catch(Exception)
{
}
}
// conversion to putty format necessary?
if (!string.IsNullOrEmpty(privatekey) && !privatekey.StartsWith("PuTTY-User-Key-File-2"))
{
try
{
RSACryptoServiceProvider key = ImportPrivateKey(privatekey);
privatekey = PuttyKeyFileGenerator.ToPuttyPrivateKey(key);
}
catch (Exception)
{
}
}
}
#region PUTTY KEY HANDLING
// decode rsa private key with encryption password
private static string DecodePrivateKey(string encryptedPrivateKey, string password)
{
TextReader textReader = new StringReader(encryptedPrivateKey);
PemReader pemReader = new PemReader(textReader, new PasswordFinder(password));
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
TextWriter textWriter = new StringWriter();
var pemWriter = new PemWriter(textWriter);
pemWriter.WriteObject(keyPair.Private);
pemWriter.Writer.Flush();
return ""+textWriter.ToString();
}
private class PasswordFinder : IPasswordFinder
{
private string password;
public PasswordFinder(string password)
{
this.password = password;
}
public char[] GetPassword()
{
return password.ToCharArray();
}
}
// read private key pem string to rsacryptoserviceprovider
public static RSACryptoServiceProvider ImportPrivateKey(string pem)
{
PemReader pr = new PemReader(new StringReader(pem));
AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private);
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParams);
return rsa;
}
#endregion
// input: must be the secret id to fetch
public static void FetchSecretFromServer(string secretID, out string username, out string password, out string domain, out string privatekey)
{
// get secret id
int sid = Int32.Parse(secretID);
// init connection credentials, display popup if necessary
CPSConnectionData.Init();
// get the secret
FetchSecret(sid, out username, out password, out domain, out privatekey);
}
}

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -1,4 +1,4 @@
namespace ExternalConnectors.TSS
namespace ExternalConnectors.DSS
{
partial class SSConnectionForm
{
@@ -51,29 +51,29 @@
// tbSSURL
//
this.tbSSURL.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbSSURL.Location = new System.Drawing.Point(260, 4);
this.tbSSURL.Margin = new System.Windows.Forms.Padding(4);
this.tbSSURL.Location = new System.Drawing.Point(298, 5);
this.tbSSURL.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.tbSSURL.Name = "tbSSURL";
this.tbSSURL.Size = new System.Drawing.Size(536, 23);
this.tbSSURL.Size = new System.Drawing.Size(611, 27);
this.tbSSURL.TabIndex = 0;
//
// tbUsername
//
this.tbUsername.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbUsername.Location = new System.Drawing.Point(260, 35);
this.tbUsername.Margin = new System.Windows.Forms.Padding(4);
this.tbUsername.Location = new System.Drawing.Point(298, 47);
this.tbUsername.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.tbUsername.Name = "tbUsername";
this.tbUsername.Size = new System.Drawing.Size(536, 23);
this.tbUsername.Size = new System.Drawing.Size(611, 27);
this.tbUsername.TabIndex = 2;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Dock = System.Windows.Forms.DockStyle.Fill;
this.label3.Location = new System.Drawing.Point(4, 62);
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label3.Location = new System.Drawing.Point(5, 84);
this.label3.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(248, 31);
this.label3.Size = new System.Drawing.Size(283, 42);
this.label3.TabIndex = 5;
this.label3.Text = "Password";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@@ -81,10 +81,10 @@
// tbPassword
//
this.tbPassword.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbPassword.Location = new System.Drawing.Point(260, 66);
this.tbPassword.Margin = new System.Windows.Forms.Padding(4);
this.tbPassword.Location = new System.Drawing.Point(298, 89);
this.tbPassword.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.tbPassword.Name = "tbPassword";
this.tbPassword.Size = new System.Drawing.Size(536, 23);
this.tbPassword.Size = new System.Drawing.Size(611, 27);
this.tbPassword.TabIndex = 4;
this.tbPassword.UseSystemPasswordChar = true;
//
@@ -92,10 +92,10 @@
//
this.btnOK.Anchor = System.Windows.Forms.AnchorStyles.Right;
this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnOK.Location = new System.Drawing.Point(296, 12);
this.btnOK.Margin = new System.Windows.Forms.Padding(4);
this.btnOK.Location = new System.Drawing.Point(337, 16);
this.btnOK.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.btnOK.Name = "btnOK";
this.btnOK.Size = new System.Drawing.Size(88, 26);
this.btnOK.Size = new System.Drawing.Size(101, 35);
this.btnOK.TabIndex = 6;
this.btnOK.Text = "OK";
this.btnOK.UseVisualStyleBackColor = true;
@@ -104,10 +104,10 @@
//
this.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(415, 12);
this.btnCancel.Margin = new System.Windows.Forms.Padding(4);
this.btnCancel.Location = new System.Drawing.Point(474, 16);
this.btnCancel.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(88, 26);
this.btnCancel.Size = new System.Drawing.Size(101, 35);
this.btnCancel.TabIndex = 11;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
@@ -129,7 +129,7 @@
this.tableLayoutPanel1.Controls.Add(this.tbOTP, 1, 3);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 5;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
@@ -137,17 +137,17 @@
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(800, 159);
this.tableLayoutPanel1.Size = new System.Drawing.Size(914, 212);
this.tableLayoutPanel1.TabIndex = 12;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Dock = System.Windows.Forms.DockStyle.Fill;
this.label5.Location = new System.Drawing.Point(260, 124);
this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label5.Location = new System.Drawing.Point(298, 168);
this.label5.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(536, 35);
this.label5.Size = new System.Drawing.Size(611, 44);
this.label5.TabIndex = 15;
this.label5.Text = "For SSO to work, additional IIS configuration is required!";
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@@ -156,10 +156,10 @@
//
this.label1.AutoSize = true;
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(4, 0);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Location = new System.Drawing.Point(5, 0);
this.label1.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(248, 31);
this.label1.Size = new System.Drawing.Size(283, 42);
this.label1.TabIndex = 2;
this.label1.Text = "Secret Server URL";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@@ -168,10 +168,10 @@
//
this.label2.AutoSize = true;
this.label2.Dock = System.Windows.Forms.DockStyle.Fill;
this.label2.Location = new System.Drawing.Point(4, 31);
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label2.Location = new System.Drawing.Point(5, 42);
this.label2.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(248, 31);
this.label2.Size = new System.Drawing.Size(283, 42);
this.label2.TabIndex = 4;
this.label2.Text = "DOMAIN\\Username";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@@ -179,10 +179,10 @@
// cbUseSSO
//
this.cbUseSSO.AutoSize = true;
this.cbUseSSO.Location = new System.Drawing.Point(4, 128);
this.cbUseSSO.Margin = new System.Windows.Forms.Padding(4, 4, 4, 0);
this.cbUseSSO.Location = new System.Drawing.Point(5, 173);
this.cbUseSSO.Margin = new System.Windows.Forms.Padding(5, 5, 5, 0);
this.cbUseSSO.Name = "cbUseSSO";
this.cbUseSSO.Size = new System.Drawing.Size(69, 19);
this.cbUseSSO.Size = new System.Drawing.Size(86, 24);
this.cbUseSSO.TabIndex = 14;
this.cbUseSSO.Text = "Use SSO";
this.cbUseSSO.UseVisualStyleBackColor = true;
@@ -192,47 +192,48 @@
//
this.label6.AutoSize = true;
this.label6.Dock = System.Windows.Forms.DockStyle.Fill;
this.label6.Location = new System.Drawing.Point(3, 93);
this.label6.Location = new System.Drawing.Point(3, 126);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(250, 31);
this.label6.Size = new System.Drawing.Size(287, 42);
this.label6.TabIndex = 15;
this.label6.Text = "2FA OTP (Optional)";
//
// tbOTP
//
this.tbOTP.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbOTP.Location = new System.Drawing.Point(259, 96);
this.tbOTP.Location = new System.Drawing.Point(296, 130);
this.tbOTP.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
this.tbOTP.Name = "tbOTP";
this.tbOTP.Size = new System.Drawing.Size(538, 23);
this.tbOTP.Size = new System.Drawing.Size(615, 27);
this.tbOTP.TabIndex = 5;
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 5;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 93F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 106F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 23F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 26F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 93F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 107F));
this.tableLayoutPanel2.Controls.Add(this.btnOK, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.btnCancel, 3, 0);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Bottom;
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 225);
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(4);
this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 300);
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 1;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(800, 50);
this.tableLayoutPanel2.Size = new System.Drawing.Size(914, 67);
this.tableLayoutPanel2.TabIndex = 13;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Dock = System.Windows.Forms.DockStyle.Fill;
this.label4.Location = new System.Drawing.Point(0, 159);
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label4.Location = new System.Drawing.Point(0, 212);
this.label4.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(341, 15);
this.label4.Size = new System.Drawing.Size(427, 20);
this.label4.TabIndex = 14;
this.label4.Text = "URL is the base URL, like https://cred.domain.local/SecretServer";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
@@ -240,14 +241,14 @@
// SSConnectionForm
//
this.AcceptButton = this.btnOK;
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 275);
this.ClientSize = new System.Drawing.Size(914, 367);
this.Controls.Add(this.label4);
this.Controls.Add(this.tableLayoutPanel2);
this.Controls.Add(this.tableLayoutPanel1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(4);
this.Margin = new System.Windows.Forms.Padding(5, 5, 5, 5);
this.Name = "SSConnectionForm";
this.Text = "Secret Server API Login Data";
this.Activated += new System.EventHandler(this.SSConnectionForm_Activated);

View File

@@ -1,4 +1,4 @@
namespace ExternalConnectors.TSS
namespace ExternalConnectors.DSS
{
public partial class SSConnectionForm : Form
{

View File

@@ -12,7 +12,7 @@
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
namespace SecretServerAuthentication.TSS
namespace SecretServerAuthentication.DSS
{
using System = global::System;

View File

@@ -0,0 +1,341 @@
using Microsoft.Win32;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using SecretServerAuthentication.DSS;
using SecretServerRestClient.DSS;
using System.Security.Cryptography;
namespace ExternalConnectors.DSS;
public class SecretServerInterface
{
private static class SSConnectionData
{
public static string ssUsername = "";
public static string ssPassword = "";
public static string ssUrl = "";
public static string ssOTP = "";
public static bool ssSSO = false;
public static bool initdone = false;
//token
public static string ssTokenBearer = "";
public static DateTime ssTokenExpiresOn = DateTime.UtcNow;
public static string ssTokenRefresh = "";
public static void Init()
{
if (initdone == true)
return;
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteSSInterface");
try
{
// display gui and ask for data
SSConnectionForm f = new();
string? un = key.GetValue("Username") as string;
f.tbUsername.Text = un ?? "";
f.tbPassword.Text = SSConnectionData.ssPassword; // in OTP refresh cases, this value might already be filled
string? url = key.GetValue("URL") as string;
if (url == null || !url.Contains("://"))
url = "https://cred.domain.local/SecretServer";
f.tbSSURL.Text = url;
var b = key.GetValue("SSO");
if (b == null || (string)b != "True")
ssSSO = false;
else
ssSSO = true;
f.cbUseSSO.Checked = ssSSO;
// show dialog
while (true)
{
_ = f.ShowDialog();
if (f.DialogResult != DialogResult.OK)
return;
// store values to memory
ssUsername = f.tbUsername.Text;
ssPassword = f.tbPassword.Text;
ssUrl = f.tbSSURL.Text;
ssSSO = f.cbUseSSO.Checked;
ssOTP = f.tbOTP.Text;
// check connection first
try
{
if (TestCredentials() == true)
{
initdone = true;
break;
}
}
catch (Exception)
{
MessageBox.Show("Test Credentials failed - please check your credentials");
}
}
// write values to registry
key.SetValue("Username", ssUsername);
key.SetValue("URL", ssUrl);
key.SetValue("SSO", ssSSO);
}
catch (Exception)
{
throw;
}
finally
{
key.Close();
}
}
}
private static bool TestCredentials()
{
if (SSConnectionData.ssSSO)
{
// checking creds doesn't really make sense here, as we can't modify them anyway if something is wrong
return true;
}
else
{
if (!String.IsNullOrEmpty(GetToken()))
{
return true;
}
else
{
return false;
}
}
}
private static SecretsServiceClient ConstructSecretsServiceClient()
{
string baseURL = SSConnectionData.ssUrl;
if (SSConnectionData.ssSSO)
{
// REQUIRES IIS CONFIG! https://docs.thycotic.com/ss/11.0.0/api-scripting/webservice-iwa-powershell
var handler = new HttpClientHandler() { UseDefaultCredentials = true };
var httpClient = new HttpClient(handler);
{
// Call REST API:
return new SecretsServiceClient($"{baseURL}/winauthwebservices/api", httpClient);
}
}
else
{
var httpClient = new HttpClient();
{
var token = GetToken();
// Set credentials (token):
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// Call REST API:
return new SecretsServiceClient($"{baseURL}/api", httpClient);
}
}
}
private static void FetchSecret(int secretID, out string secretUsername, out string secretPassword, out string secretDomain, out string privatekey)
{
var client = ConstructSecretsServiceClient();
SecretModel secret = client.GetSecretAsync(false, true, secretID, null).Result;
// clear return variables
secretDomain = "";
secretUsername = "";
secretPassword = "";
privatekey = "";
string privatekeypassphrase = "";
// parse data and extract what we need
foreach (var item in secret.Items)
{
if (item.FieldName.ToLower().Equals("domain"))
secretDomain = item.ItemValue;
else if (item.FieldName.ToLower().Equals("username"))
secretUsername = item.ItemValue;
else if (item.FieldName.ToLower().Equals("password"))
secretPassword = item.ItemValue;
else if (item.FieldName.ToLower().Equals("private key"))
{
client.ReadResponseNoJSONConvert = true;
privatekey = client.GetFieldAsync(false, false, secretID, "private-key").Result;
client.ReadResponseNoJSONConvert = false;
}
else if (item.FieldName.ToLower().Equals("private key passphrase"))
privatekeypassphrase = item.ItemValue;
}
// need to decode the private key?
if (!string.IsNullOrEmpty(privatekeypassphrase))
{
try
{
var key = DecodePrivateKey(privatekey, privatekeypassphrase);
privatekey = key;
}
catch(Exception)
{
}
}
// conversion to putty format necessary?
if (!string.IsNullOrEmpty(privatekey) && !privatekey.StartsWith("PuTTY-User-Key-File-2"))
{
try
{
RSACryptoServiceProvider key = ImportPrivateKey(privatekey);
privatekey = PuttyKeyFileGenerator.ToPuttyPrivateKey(key);
}
catch (Exception)
{
}
}
}
#region PUTTY KEY HANDLING
// decode rsa private key with encryption password
private static string DecodePrivateKey(string encryptedPrivateKey, string password)
{
TextReader textReader = new StringReader(encryptedPrivateKey);
PemReader pemReader = new(textReader, new PasswordFinder(password));
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
TextWriter textWriter = new StringWriter();
var pemWriter = new PemWriter(textWriter);
pemWriter.WriteObject(keyPair.Private);
pemWriter.Writer.Flush();
return ""+textWriter.ToString();
}
private class PasswordFinder : IPasswordFinder
{
private string password;
public PasswordFinder(string password)
{
this.password = password;
}
public char[] GetPassword()
{
return password.ToCharArray();
}
}
// read private key pem string to rsacryptoserviceprovider
public static RSACryptoServiceProvider ImportPrivateKey(string pem)
{
PemReader pr = new(new StringReader(pem));
AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private);
RSACryptoServiceProvider rsa = new();
rsa.ImportParameters(rsaParams);
return rsa;
}
#endregion
#region TOKEN
private static string GetToken()
{
// if there is no token, fetch a fresh one
if (String.IsNullOrEmpty(SSConnectionData.ssTokenBearer))
{
return GetTokenFresh();
}
// if there is a token, check if it is valid
if (SSConnectionData.ssTokenExpiresOn >= DateTime.UtcNow)
{
return SSConnectionData.ssTokenBearer;
}
else
{
// try using refresh token
using (var httpClient = new HttpClient())
{
var tokenClient = new OAuth2ServiceClient(SSConnectionData.ssUrl, httpClient);
TokenResponse token = new();
try
{
token = tokenClient.AuthorizeAsync(Grant_type.Refresh_token, null, null, SSConnectionData.ssTokenRefresh, null).Result;
var tokenResult = token.Access_token;
SSConnectionData.ssTokenBearer = tokenResult;
SSConnectionData.ssTokenRefresh = token.Refresh_token;
SSConnectionData.ssTokenExpiresOn = token.Expires_on;
return tokenResult;
}
catch (Exception)
{
// refresh token failed. clean memory and start fresh
SSConnectionData.ssTokenBearer = "";
SSConnectionData.ssTokenRefresh = "";
SSConnectionData.ssTokenExpiresOn = DateTime.Now;
// if OTP is required we need to ask user for a new OTP
if (!String.IsNullOrEmpty(SSConnectionData.ssOTP))
{
SSConnectionData.initdone = false;
// the call below executes a connection test, which fetches a valid token
SSConnectionData.Init();
// we now have a fresh token in memory. return it to caller
return SSConnectionData.ssTokenBearer;
}
else
{
// no user interaction required. get a fresh token and return it to caller
return GetTokenFresh();
}
}
}
}
}
static string GetTokenFresh()
{
using (var httpClient = new HttpClient())
{
// Authenticate:
var tokenClient = new OAuth2ServiceClient(SSConnectionData.ssUrl, httpClient);
// call below will throw an exception if the creds are invalid
var token = tokenClient.AuthorizeAsync(Grant_type.Password, SSConnectionData.ssUsername, SSConnectionData.ssPassword, null, SSConnectionData.ssOTP).Result;
// here we can be sure the creds are ok - return success state
var tokenResult = token.Access_token;
SSConnectionData.ssTokenBearer = tokenResult;
SSConnectionData.ssTokenRefresh = token.Refresh_token;
SSConnectionData.ssTokenExpiresOn = token.Expires_on;
return tokenResult;
}
}
#endregion
// input must be the secret id to fetch
public static void FetchSecretFromServer(string input, out string username, out string password, out string domain, out string privatekey)
{
// get secret id
int secretID = Int32.Parse(input);
// init connection credentials, display popup if necessary
SSConnectionData.Init();
// get the secret
FetchSecret(secretID, out username, out password, out domain, out privatekey);
}
}

View File

@@ -12,7 +12,7 @@
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
namespace SecretServerRestClient.TSS
namespace SecretServerRestClient.DSS
{
using System = global::System;
@@ -72886,6 +72886,9 @@ namespace SecretServerRestClient.TSS
}
public bool ReadResponseAsString { get; set; }
// RR 2022-09-97
public bool ReadResponseNoJSONConvert { get; set; }
// RR END
protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>> ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IEnumerable<string>> headers, System.Threading.CancellationToken cancellationToken)
{
@@ -72894,6 +72897,14 @@ namespace SecretServerRestClient.TSS
return new ObjectResponseResult<T>(default(T), string.Empty);
}
// RR 2022-09-97
if (ReadResponseNoJSONConvert)
{
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return new ObjectResponseResult<T>((T)(object)responseText, responseText); // not sure if this is best practice, but it works.
}
// RR END
if (ReadResponseAsString)
{
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

View File

@@ -7,22 +7,24 @@
<OutputType>Library</OutputType>
<UseWindowsForms>True</UseWindowsForms>
<Platforms>x64</Platforms>
<Configurations>Debug;Release;Debug Portable;Release Portable</Configurations>
<Configurations>Debug;Release;Debug Portable;Release Portable;Deploy to github</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Portable|x64'">
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.Core" Version="3.7.11.2" />
<PackageReference Include="AWSSDK.EC2" Version="3.7.72" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="AWSSDK.Core" Version="3.7.401.6" />
<PackageReference Include="AWSSDK.EC2" Version="3.7.429.1" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Compile Update="AWS\AWSConnectionForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="TSS\SSConnectionForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="AWS\AWSConnectionForm.cs" />
<Compile Update="CPS\CPSConnectionForm.cs" />
<Compile Update="DSS\SSConnectionForm.cs" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,111 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace ExternalConnectors;
public class PuttyKeyFileGenerator
{
private const int prefixSize = 4;
private const int paddedPrefixSize = prefixSize + 1;
private const int lineLength = 64;
private const string keyType = "ssh-rsa";
private const string encryptionType = "none";
public static string ToPuttyPrivateKey(RSACryptoServiceProvider cryptoServiceProvider, string Comment = "imported-openssh-key")
{
var publicParameters = cryptoServiceProvider.ExportParameters(false);
byte[] publicBuffer = new byte[3 + keyType.Length + GetPrefixSize(publicParameters.Exponent) + publicParameters.Exponent!.Length + GetPrefixSize(publicParameters.Modulus) + publicParameters.Modulus!.Length + 1];
using (var bw = new BinaryWriter(new MemoryStream(publicBuffer)))
{
bw.Write(new byte[] { 0x00, 0x00, 0x00 });
bw.Write(Encoding.ASCII.GetBytes(keyType));
PutPrefixed(bw, publicParameters.Exponent, CheckIsNeddPadding(publicParameters.Exponent));
PutPrefixed(bw, publicParameters.Modulus, CheckIsNeddPadding(publicParameters.Modulus));
}
var publicBlob = System.Convert.ToBase64String(publicBuffer);
var privateParameters = cryptoServiceProvider.ExportParameters(true);
byte[] privateBuffer = new byte[paddedPrefixSize + privateParameters.D!.Length + paddedPrefixSize + privateParameters.P!.Length + paddedPrefixSize + privateParameters.Q!.Length + paddedPrefixSize + privateParameters.InverseQ!.Length];
using (var bw = new BinaryWriter(new MemoryStream(privateBuffer)))
{
PutPrefixed(bw, privateParameters.D, true);
PutPrefixed(bw, privateParameters.P, true);
PutPrefixed(bw, privateParameters.Q, true);
PutPrefixed(bw, privateParameters.InverseQ, true);
}
var privateBlob = System.Convert.ToBase64String(privateBuffer);
HMACSHA1 hmacSha1 = new(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes("putty-private-key-file-mac-key")));
byte[] bytesToHash = new byte[prefixSize + keyType.Length + prefixSize + encryptionType.Length + prefixSize + Comment.Length + prefixSize + publicBuffer.Length + prefixSize + privateBuffer.Length];
using (var bw = new BinaryWriter(new MemoryStream(bytesToHash)))
{
PutPrefixed(bw, Encoding.ASCII.GetBytes(keyType));
PutPrefixed(bw, Encoding.ASCII.GetBytes(encryptionType));
PutPrefixed(bw, Encoding.ASCII.GetBytes(Comment));
PutPrefixed(bw, publicBuffer);
PutPrefixed(bw, privateBuffer);
}
var hash = string.Join("", hmacSha1.ComputeHash(bytesToHash).Select(x => $"{x:x2}"));
var sb = new StringBuilder();
sb.AppendLine("PuTTY-User-Key-File-2: " + keyType);
sb.AppendLine("Encryption: " + encryptionType);
sb.AppendLine("Comment: " + Comment);
var publicLines = SpliceText(publicBlob, lineLength);
sb.AppendLine("Public-Lines: " + publicLines.Length);
foreach (var line in publicLines)
{
sb.AppendLine(line);
}
var privateLines = SpliceText(privateBlob, lineLength);
sb.AppendLine("Private-Lines: " + privateLines.Length);
foreach (var line in privateLines)
{
sb.AppendLine(line);
}
sb.AppendLine("Private-MAC: " + hash);
return sb.ToString();
}
private static void PutPrefixed(BinaryWriter bw, byte[] bytes, bool addLeadingNull = false)
{
bw.Write(BitConverter.GetBytes(bytes.Length + (addLeadingNull ? 1 : 0)).Reverse().ToArray());
if (addLeadingNull)
bw.Write(new byte[] { 0x00 });
bw.Write(bytes);
}
private static string[] SpliceText(string text, int lineLength)
{
return Regex.Matches(text, ".{1," + lineLength + "}").Cast<Match>().Select(m => m.Value).ToArray();
}
private static int GetPrefixSize(byte[]? bytes)
{
if (bytes is null)
return 0;
return CheckIsNeddPadding(bytes) ? paddedPrefixSize : prefixSize;
}
private static bool CheckIsNeddPadding(byte[] bytes)
{
if (bytes is null || bytes.Length == 0)
return false;
// 128 == 10000000
// This means that the number of bits can be divided by 8.
// According to the algorithm in putty, you need to add a padding.
return bytes[0] >= 128;
}
}

View File

@@ -1,254 +0,0 @@
using Microsoft.Win32;
using SecretServerAuthentication.TSS;
using SecretServerRestClient.TSS;
namespace ExternalConnectors.TSS
{
public class SecretServerInterface
{
private static class SSConnectionData
{
public static string ssUsername = "";
public static string ssPassword = "";
public static string ssUrl = "";
public static string ssOTP = "";
public static bool ssSSO = false;
public static bool initdone = false;
//token
public static string ssTokenBearer = "";
public static DateTime ssTokenExpiresOn = DateTime.UtcNow;
public static string ssTokenRefresh = "";
public static void Init()
{
if (initdone == true)
return;
RegistryKey key = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\mRemoteSSInterface");
try
{
// display gui and ask for data
SSConnectionForm f = new SSConnectionForm();
string? un = key.GetValue("Username") as string;
f.tbUsername.Text = un ?? "";
f.tbPassword.Text = SSConnectionData.ssPassword; // in OTP refresh cases, this value might already be filled
string? url = key.GetValue("URL") as string;
if (url == null || !url.Contains("://"))
url = "https://cred.domain.local/SecretServer";
f.tbSSURL.Text = url;
var b = key.GetValue("SSO");
if (b == null || (string)b != "True")
ssSSO = false;
else
ssSSO = true;
f.cbUseSSO.Checked = ssSSO;
// show dialog
while (true)
{
_ = f.ShowDialog();
if (f.DialogResult != DialogResult.OK)
return;
// store values to memory
ssUsername = f.tbUsername.Text;
ssPassword = f.tbPassword.Text;
ssUrl = f.tbSSURL.Text;
ssSSO = f.cbUseSSO.Checked;
ssOTP = f.tbOTP.Text;
// check connection first
try
{
if (TestCredentials() == true)
{
initdone = true;
break;
}
}
catch (Exception)
{
MessageBox.Show("Test Credentials failed - please check your credentials");
}
}
// write values to registry
key.SetValue("Username", ssUsername);
key.SetValue("URL", ssUrl);
key.SetValue("SSO", ssSSO);
}
catch (Exception)
{
throw;
}
finally
{
key.Close();
}
}
}
private static bool TestCredentials()
{
if (SSConnectionData.ssSSO)
{
// checking creds doesn't really make sense here, as we can't modify them anyway if something is wrong
return true;
}
else
{
if (!String.IsNullOrEmpty(GetToken()))
{
return true;
}
else
{
return false;
}
}
}
private static void FetchSecret(int secretID, out string secretUsername, out string secretPassword, out string secretDomain)
{
string baseURL = SSConnectionData.ssUrl;
SecretModel secret;
if (SSConnectionData.ssSSO)
{
// REQUIRES IIS CONFIG! https://docs.thycotic.com/ss/11.0.0/api-scripting/webservice-iwa-powershell
var handler = new HttpClientHandler() { UseDefaultCredentials = true };
using (var httpClient = new HttpClient(handler))
{
// Call REST API:
var client = new SecretsServiceClient($"{baseURL}/winauthwebservices/api", httpClient);
secret = client.GetSecretAsync(false, true, secretID, null).Result;
}
}
else
{
using (var httpClient = new HttpClient())
{
var token = GetToken();
// Set credentials (token):
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// Call REST API:
var client = new SecretsServiceClient($"{baseURL}/api", httpClient);
secret = client.GetSecretAsync(false, true, secretID, null).Result;
}
}
// clear return variables
secretDomain = "";
secretUsername = "";
secretPassword = "";
// parse data and extract what we need
foreach (var item in secret.Items)
{
if (item.FieldName.ToLower().Equals("domain"))
secretDomain = item.ItemValue;
else if (item.FieldName.ToLower().Equals("username"))
secretUsername = item.ItemValue;
else if (item.FieldName.ToLower().Equals("password"))
secretPassword = item.ItemValue;
}
}
private static string GetToken()
{
// if there is no token, fetch a fresh one
if (String.IsNullOrEmpty(SSConnectionData.ssTokenBearer))
{
return GetTokenFresh();
}
// if there is a token, check if it is valid
if (SSConnectionData.ssTokenExpiresOn >= DateTime.UtcNow)
{
return SSConnectionData.ssTokenBearer;
}
else
{
// try using refresh token
using (var httpClient = new HttpClient())
{
var tokenClient = new OAuth2ServiceClient(SSConnectionData.ssUrl, httpClient);
TokenResponse token = new();
try
{
token = tokenClient.AuthorizeAsync(Grant_type.Refresh_token, null, null, SSConnectionData.ssTokenRefresh, null).Result;
var tokenResult = token.Access_token;
SSConnectionData.ssTokenBearer = tokenResult;
SSConnectionData.ssTokenRefresh = token.Refresh_token;
SSConnectionData.ssTokenExpiresOn = token.Expires_on;
return tokenResult;
}
catch (Exception)
{
// refresh token failed. clean memory and start fresh
SSConnectionData.ssTokenBearer = "";
SSConnectionData.ssTokenRefresh = "";
SSConnectionData.ssTokenExpiresOn = DateTime.Now;
// if OTP is required we need to ask user for a new OTP
if (!String.IsNullOrEmpty(SSConnectionData.ssOTP))
{
SSConnectionData.initdone = false;
// the call below executes a connection test, which fetches a valid token
SSConnectionData.Init();
// we now have a fresh token in memory. return it to caller
return SSConnectionData.ssTokenBearer;
}
else
{
// no user interaction required. get a fresh token and return it to caller
return GetTokenFresh();
}
}
}
}
}
static string GetTokenFresh()
{
using (var httpClient = new HttpClient())
{
// Authenticate:
var tokenClient = new OAuth2ServiceClient(SSConnectionData.ssUrl, httpClient);
// call below will throw an exception if the creds are invalid
var token = tokenClient.AuthorizeAsync(Grant_type.Password, SSConnectionData.ssUsername, SSConnectionData.ssPassword, null, SSConnectionData.ssOTP).Result;
// here we can be sure the creds are ok - return success state
var tokenResult = token.Access_token;
SSConnectionData.ssTokenBearer = tokenResult;
SSConnectionData.ssTokenRefresh = token.Refresh_token;
SSConnectionData.ssTokenExpiresOn = token.Expires_on;
return tokenResult;
}
}
// input must be in form "SSAPI:xxxx" where xxx is the secret id to fetch
public static void FetchSecretFromServer(string input, out string username, out string password, out string domain)
{
// get secret id
if (!input.StartsWith("SSAPI:"))
throw new Exception("calling this function requires SSAPI: input");
int secretID = Int32.Parse(input.Substring(6));
// init connection credentials, display popup if necessary
SSConnectionData.Init();
// get the secret
FetchSecret(secretID, out username, out password, out domain);
}
}
}

View File

@@ -20,8 +20,8 @@
<a href="https://twitter.com/mremoteng">
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/mremoteng?color=%231DA1F2&label=Twitter&logo=Twitter&style=flat-square">
</a>
<a href="https://gitter.im/mRemoteNG/PublicChat">
<img alt="Gitter" src="https://img.shields.io/gitter/room/mRemoteNG/PublicChat?label=Join%20the%20Chat&logo=Gitter&style=flat-square">
<a href="https://app.element.io/#/room/#mremoteng:matrix.org">
<img alt="Element" src="https://img.shields.io/matrix/mremoteng:matrix.org?label=Join%20to%20chat%20about%20mRemoteNG&logo=element&style=social&link=https://app.element.io/#/room/#mremoteng:matrix.org">
</a>
</p>
<p align="center">
@@ -43,6 +43,9 @@
<a href='https://mremoteng.readthedocs.io/en/latest/?badge=latest'>
<img src='https://readthedocs.org/projects/mremoteng/badge/?version=latest' alt='Documentation Status' />
</a>
<a href="https://gurubase.io/g/mremoteng">
<img alt="Gurubase" src="https://img.shields.io/badge/Gurubase-Ask%20mRemoteNG%20Guru-006BFF?style=flat-square">
</a>
</p>
---
@@ -51,7 +54,7 @@
| ---------------|--------------|-----------|
| Stable | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.76.20/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76.20) |
| Preview | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf/branch/preview?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.77.1/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.77.1) |
| Nightly | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf/branch/develop?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/2022.01.07-1.77.2-nb/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/2022.01.07-1.77.2-nb) |
| Nightly | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf/branch/develop?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/2023.03.03-v1.77.3-nb/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/2023.03.03-v1.77.3-nb) |
## Features

View File

@@ -0,0 +1,38 @@
U2FsdGVkX1/uEeToOEIrunpoPNl7NUYNQfI+ixMzGgKX0DlHZxa/PonAVd9NoAE+
dqWegkN8fa/M2HcW8moN5sN0yS88amG8cfwRZNRSgRB4IxDdYPjM/iX7y8FjUh9R
OZnGhq1rAkqcf7ASAdZfQDSFOAEDPQgByN4IB2j/G3ueqV3jf5sWWiM0ielcorWX
jXuEL7uIk9diI3Qh3BVqmrotzErzqTTLB4DWoL1aWqRRYH+exKahfcMT3C9r+tul
ETH6o1im3kdYzFgHl58FmihbHa+h1+c+DWVGGXRxJPw1DZfg8/+ldIy8J75aWimz
2MX+PiBVQj+wYlSSkQLj2EdbpSERlinE1O55ldwpbnMPAlYCgFRdO3/hiB6LiLLt
n9s8f32HLNG20Mk1oxXdN9VPOw+RwQpUf6Zfcyps6e/9EFKBLnwq4cYwM/dHRuez
w48EJX5wKzpukHn2UFg5aCRGYU/4NyUn+AlIjjCMBWY1R0uBhC340cl6YqoPFN12
clzbS6JdQS+ktusCeaKcsj2iknVqQrGY81LKrTaQZdfehGwAn9pMWE3iWRX80yzO
s08lpmHfPK4uhtlyIbdReLn4n7hvB8KRVa7Foms+4wpEwKrL8KF/8CYc89Tm3PSD
LCrLr7rzCHh51ncJXHAwZqY2ZRLnQBVwhIRsFYyZ595b89tuDY00sYpWnTKzWubK
UD993CmYKg1cA+mj6NR6iSmecawsUz68nI/nmHM2APE5cCCHSK3lz40e9Z9Hmy5Y
kVS6c86a+gwNyn4F9t3iISdj2vIOwGMVWQLeY+nwpiKnnOuI0XPtIMjNbhoaDToT
kph2ZVjqbpmYHgTSX71v8Y16Stl+p/dZn0dE2d4JhxOJxDN//H6y7mOwg8DYX9GP
rFBMIEWyEQyEFYTmWgztQ5KU89w0lV1qiWpaiWR/IDkGbUzHR8ELp4NHYPbZnuYa
FFXooJGPsQ02ioXPm18Lkhloo63lANgyBE0jc1x9hPrI0oVn1wTkKdeW13IbHzrn
VsGXeZz06bB46QChXUPmQ49sNkAXcMDnfNFM9ayUa8eVmNx9fWabtBy8qs7rpdv0
1y/2ud4Da9t7SAUvxwI65+b2Ytk05pLFLmQYb01g4BpBDxbJW3yw3CqKgMnLoZ3t
s2kiUpn7FEQU8jbpbFV+UB4DdJgm8S7o1gbTEWYTscZ7l+oLCmQgMYoi/EJDDIa2
cCSdGy4p7kLlLUoO438Mz36+FDf6qX2B86ezVdNnXQb3UPljjDxiOFM6NkI3HTpl
RqxjBg8JdrwoQ1UMha6ucDKhPXq1xkg0dpO9QyjxywssG3krgQ5Py64s5Xu7IgQm
AzmwGTZ6gFZlDTr9SpJkiucF9vexCo6JHHkF8OjhS49FanqB8otJvg5JclVugP51
LcqqvuMkAsFago261SNcOhgtR6nV5B9QgHyr66c6YnTlwt07T1Qq3S1lw2x0Eccs
PKbJDVU5rAHiM71QYmwsuoC8qkYPTtVPIoUTs+5u5aLywVoLejr1dE5twNXy5PYY
fDwubg0YG3kchvv85N3epZ1h50ADq3W3msU9bWDKWwdwIbpGq+dwjkLssBQmjVtI
R8rGbt1DgL7xtRNF9ESnWVkfHJvJu/5oD6wGAU/oIfBxVON0VYb1evc8wRdQTbDH
Dnt+aKwcSPYdyGVRKfRtBGvEZ8rB5hzCXQnS795L0imdfXjBSJn7Pnl9VwpcB3Pr
aZ6s0GcB8kYDEXzjv+o7JF6k5i2I+sVGwvFVGIoVd/Igq2ysrk/GfWVov0SUu78A
JeHYdtRuKwXOdZw2cjZQ72bvFaHOuoXrQnyKyZDWRyu0NB5HLW75v/YEbr4msIm9
E+3HFwRvKSTfUx/M4NgVKrgsHDeBRD4tLNx/SerQvqaplunM7OfAtULucveUhwSo
vT6uNK3URe1qDgX554cz8c6+KrkglTLFMuKfNWj3q/uSM0BxTTD9QgorNdlMmErH
TfV/ZpZACpuMFRbC5xQRkCG1x4U12pdPbtIkGtVBJROEXhP1aw3BDWwrIN7zSgfj
8I4OF4fbj/rSuvI4klzi1zlUMQQnenlRURE+7DKRxtWipJhW9vtDI0LXN7gGfmbR
73uR3YUny6zUJ0svqaWj4Eo6t3g99nmk4D2hm/622dRksv2HqEQiq29jJxlcbdZB
PU96wOp54s/BzgodyI5dh+xL06Obr9AltLV9vw3iK0VBZqquj9FuhvWC1tYlZQJF
AOgVDOGUZzmAJXftI7gaohFBwsT5tAHQtBuY7tB3b1hrnfrFb9FTNxGZJKcIH3p4
dOAvedsfuq+2/lU9iM4tX9fjSzfnGRZRuKCGDSdhE6EDik9/f2kSCoY9z0zJwdZH
324TpGbZNbgcwgHDL9i5Nsnaua5yxtr0/Fr1We1tvn0=

View File

@@ -1,17 +1,27 @@
#Requires -Version 4.0
param (
[string]
[Parameter(Mandatory=$true)]
$WebsiteTargetOwner,
[string]
[Parameter(Mandatory=$true)]
$WebsiteTargetRepository,
[string]
[Parameter(Mandatory=$false)]
$PreTagName = "",
[string]
[Parameter(Mandatory=$true)]
$TagName,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Stable","Beta","Development")]
$UpdateChannel
$ProjectName
)
function New-MsiUpdateFileContent {
param (
[System.IO.FileInfo]
@@ -25,7 +35,7 @@ function New-MsiUpdateFileContent {
$version = $MsiFile.BaseName -replace "[a-zA-Z-]*"
$certThumbprint = (Get-AuthenticodeSignature -FilePath $MsiFile).SignerCertificate.Thumbprint
$hash = Get-FileHash -Algorithm SHA512 $MsiFile | % { $_.Hash }
$hash = Get-FileHash -Algorithm SHA512 $MsiFile | ForEach-Object { $_.Hash }
$fileContents = `
"Version: $version
@@ -49,7 +59,7 @@ function New-ZipUpdateFileContent {
)
$version = $ZipFile.BaseName -replace "[a-zA-Z-]*"
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | % { $_.Hash }
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | ForEach-Object { $_.Hash }
$fileContents = `
"Version: $version
@@ -64,7 +74,7 @@ function Resolve-UpdateCheckFileName {
param (
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Stable","Beta","Development")]
[ValidateSet("Stable","Preview","Nightly")]
$UpdateChannel,
[string]
@@ -75,8 +85,8 @@ function Resolve-UpdateCheckFileName {
$fileName = ""
if ($UpdateChannel -eq "Beta") { $fileName += "beta-" }
elseif ($UpdateChannel -eq "Development") { $fileName += "dev-" }
if ($UpdateChannel -eq "Preview") { $fileName += "preview-" }
elseif ($UpdateChannel -eq "Nightly") { $fileName += "nightly-" }
$fileName += "update"
@@ -87,23 +97,72 @@ function Resolve-UpdateCheckFileName {
Write-Output $fileName
}
Write-Output ""
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
# determine update channel
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
Write-Output "UpdateChannel = Nightly"
$UpdateChannel = "Nightly"
$ModifiedTagName = "$PreTagName-$TagName-NB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
Write-Output "UpdateChannel = Preview"
$UpdateChannel = "Preview"
$ModifiedTagName = "v$TagName-PB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
Write-Output "UpdateChannel = Stable"
$UpdateChannel = "Stable"
$ModifiedTagName = "v" + $TagName.Split("-")[0]
} else {
$UpdateChannel = ""
}
#$buildFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\mRemoteNG\bin\x64\Release" -Resolve -ErrorAction Ignore
$ReleaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
if ($UpdateChannel -ne "" -and $ReleaseFolder -ne "" -and $WebsiteTargetOwner -and $WebsiteTargetRepository) {
$releaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
$msiFile = Get-ChildItem -Path "$ReleaseFolder\*.msi" -Exclude "*-symbols-*.zip" | Sort-Object LastWriteTime | Select-Object -last 1
if (![string]::IsNullOrEmpty($msiFile)) {
$msiUpdateContents = New-MsiUpdateFileContent -MsiFile $msiFile -TagName $ModifiedTagName
$msiUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Normal
Write-Output "`n`nMSI Update Check File Contents ($msiUpdateFileName)`n------------------------------"
Tee-Object -InputObject $msiUpdateContents -FilePath "$ReleaseFolder\$msiUpdateFileName"
# commit msi update txt file
if ($env:WEBSITE_UPDATE_ENABLED.ToLower() -eq "true") {
if ((Test-Path -Path "$ReleaseFolder\$msiUpdateFileName") -and (-not [string]::IsNullOrEmpty($WebsiteTargetRepository))) {
Write-Output "Publish Update File $msiUpdateFileName to $WebsiteTargetRepository"
$update_file_content_string = Get-Content "$ReleaseFolder\$msiUpdateFileName" | Out-String
Set-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path $msiUpdateFileName -CommitMessage "Build $ModifiedTagName" -Content $update_file_content_string -BranchName main
} else {
Write-Warning "WARNING: Update file does not exist: $ReleaseFolder\$msiUpdateFileName"
}
}
}
# build msi update file
$msiFile = Get-ChildItem -Path "$releaseFolder\*.msi" | sort LastWriteTime | select -last 1
$msiUpdateContents = New-MsiUpdateFileContent -MsiFile $msiFile -TagName $TagName
$msiUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Normal
Write-Output "`n`nMSI Update Check File Contents ($msiUpdateFileName)`n------------------------------"
Tee-Object -InputObject $msiUpdateContents -FilePath "$releaseFolder\$msiUpdateFileName"
# build zip update file
$zipFile = Get-ChildItem -Path "$ReleaseFolder\*.zip" -Exclude "*-symbols-*.zip" | Sort-Object LastWriteTime | Select-Object -last 1
if (![string]::IsNullOrEmpty($zipFile)) {
$zipUpdateContents = New-ZipUpdateFileContent -ZipFile $zipFile -TagName $ModifiedTagName
$zipUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Portable
Write-Output "`n`nZip Update Check File Contents ($zipUpdateFileName)`n------------------------------"
Tee-Object -InputObject $zipUpdateContents -FilePath "$ReleaseFolder\$zipUpdateFileName"
# commit zip update txt file
if ($env:WEBSITE_UPDATE_ENABLED.ToLower() -eq "true") {
if ((Test-Path -Path "$ReleaseFolder\$zipUpdateFileName") -and (-not [string]::IsNullOrEmpty($WebsiteTargetRepository))) {
Write-Output "Publish Update File $zipUpdateFileName to $WebsiteTargetRepository"
$update_file_content_string = Get-Content "$ReleaseFolder\$zipUpdateFileName" | Out-String
Set-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path $zipUpdateFileName -CommitMessage "Build $ModifiedTagName" -Content $update_file_content_string -BranchName main
} else {
Write-Warning "WARNING: Update file does not exist: $ReleaseFolder\$zipUpdateFileName"
}
}
}
} else {
Write-Output "ReleaseFolder not found"
}
# build zip update file
$zipFile = Get-ChildItem -Path "$releaseFolder\*.zip" | sort LastWriteTime | select -last 1
$zipUpdateContents = New-ZipUpdateFileContent -ZipFile $zipFile -TagName $TagName
$zipUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Portable
Write-Output "`n`nZip Update Check File Contents ($zipUpdateFileName)`n------------------------------"
Tee-Object -InputObject $zipUpdateContents -FilePath "$releaseFolder\$zipUpdateFileName"
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

2
Tools/decrypt.bat Normal file
View File

@@ -0,0 +1,2 @@
openssl enc -base64 -aes-256-cbc -md sha512 -pbkdf2 -iter 100000 -d -in cert/CodeSigning_Cert_mRemoteNG_Certum.enc -out cert/CodeSigning_Cert_mRemoteNG_Certum.cer
pause

2
Tools/encrypt.bat Normal file
View File

@@ -0,0 +1,2 @@
openssl enc -base64 -aes-256-cbc -md sha512 -pbkdf2 -iter 100000 -e -in cert/CodeSigning_Cert_mRemoteNG_Certum.cer -out cert/CodeSigning_Cert_mRemoteNG_Certum.enc
pause

View File

@@ -19,27 +19,28 @@ function EditBinCertificateIsValid() {
"3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC",
"98ED99A67886D020C564923B7DF25E9AC019DF26",
"108E2BA23632620C427C570B6D9DB51AC31387FE",
"5EAD300DC7E4D637948ECB0ED829A072BD152E17"
"5EAD300DC7E4D637948ECB0ED829A072BD152E17",
"97221B97098F37A135DCC212E2B41E452BCE51F2"
)
$file_signature = Get-AuthenticodeSignature -FilePath $Path
if (($file_signature.Status -ne "Valid") -or ($valid_microsoft_cert_thumbprints -notcontains $file_signature.SignerCertificate.Thumbprint)) {
Write-Warning "Could not validate the signature of $Path"
Write-Warning "Could not validate the signature of $Path $($file_signature.SignerCertificate.Thumbprint)"
Write-Output "file_signature.SignerCertificate.Thumbprint: $($file_signature.SignerCertificate.Thumbprint)"
return $false
} else {
return $true
}
}
function ToolCanBeExecuted {
param (
[string]
$Path
)
$null = & $Path
Write-Output ($LASTEXITCODE -gt 0)
$env:PATHEXT.Contains((Get-Item $Path).Extension.ToUpper())
}
$rootSearchPaths = @(
[System.IO.Directory]::EnumerateFileSystemEntries("C:\Program Files", "*Visual Studio*", [System.IO.SearchOption]::TopDirectoryOnly),
[System.IO.Directory]::EnumerateFileSystemEntries("C:\Program Files (x86)", "*Visual Studio*", [System.IO.SearchOption]::TopDirectoryOnly)
@@ -51,7 +52,8 @@ foreach ($searchPath in $rootSearchPaths) {
Write-Verbose "Searching in folder '$visualStudioFolder'"
$matchingExes = [System.IO.Directory]::EnumerateFileSystemEntries($visualStudioFolder, $FileName, [System.IO.SearchOption]::AllDirectories)
foreach ($matchingExe in $matchingExes) {
if ((EditBinCertificateIsValid -Path $matchingExe) -and (ToolCanBeExecuted -Path $matchingExe)) {
#if ((EditBinCertificateIsValid -Path $matchingExe) -and (ToolCanBeExecuted -Path $matchingExe)) {
if (ToolCanBeExecuted -Path $matchingExe) {
return $matchingExe
}
}

View File

@@ -2,6 +2,32 @@ $githubUrl = 'https://api.github.com'
# GitHub doesn't support the default powershell protocol (TLS 1.0)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
if ($IsAppVeyor) {
#$CURRENT_GITHUB_USER = $env:APPVEYOR_REPO_NAME.Split("/")[0]
Install-Module -Name PowerShellForGitHub -Scope CurrentUser
Set-GitHubConfiguration -DisableTelemetry
$PSDefaultParameterValues["*-GitHub*:AccessToken"] = "$env:ACCESS_TOKEN"
#New-Item -Path "$Env:APPVEYOR_BUILD_FOLDER\Release" -ItemType Directory -Force
}
function New-TemporaryDirectory {
$parent = [System.IO.Path]::GetTempPath()
[string] $name = [System.Guid]::NewGuid()
$fullTempPath = (Join-Path $parent $name)
New-Item -ItemType Directory -Path $fullTempPath
return $fullTempPath
}
Function ConvertFrom-Base64($base64) {
return [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64))
}
Function ConvertTo-Base64($plain) {
return [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($plain))
}
function Publish-GitHubRelease {
param (
[string]
@@ -232,4 +258,4 @@ function New-GitHubReleaseRequestBody {
$json_body = ConvertTo-Json -InputObject $body_params -Compress
Write-Output $json_body
}
}

76
Tools/postbuild.ps1 Normal file
View File

@@ -0,0 +1,76 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
$CertificatePath,
[string]
$CertificatePassword,
[string[]]
$ExcludeFromSigning
)
. "$PSScriptRoot\github_functions.ps1"
Write-Output ""
Write-Output "+============================================================+"
Write-Output "| Beginning mRemoteNG Post Build |"
Write-Output "+============================================================+"
Format-Table -AutoSize -Wrap -InputObject @{
"SolutionDir" = $SolutionDir
"TargetDir" = $TargetDir
"TargetFileName" = $TargetFileName
"ConfigurationName" = $ConfigurationName
"CertificatePath" = $CertificatePath
"ExcludeFromSigning" = $ExcludeFromSigning
}
if ( $ConfigurationName -match "Debug" -and ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) { return; } #skip when Debug local developer build
if ( $env:APPVEYOR_PROJECT_NAME -match "(CI)" -and -not ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) { return; } #skip when AppVeyor (CI) build
$dstPath = "$($SolutionDir)Release"
New-Item -Path $dstPath -ItemType Directory -Force
# $RunInstaller = $TargetDir -match "\\mRemoteNGInstaller\\Installer\\bin\\"
# $RunPortable = ( ($Targetdir -match "\\mRemoteNG\\bin\\") -and -not ($TargetDir -match "\\mRemoteNGInstaller\\Installer\\bin\\") )
if ( ($ConfigurationName -match "Release") -and ($env:APPVEYOR_PROJECT_NAME -notmatch "(CI)") -and -not ([string]::IsNullOrEmpty($env:WEBSITE_TARGET_OWNER)) -and -not ([string]::IsNullOrEmpty($env:WEBSITE_TARGET_REPOSITORY)) ) {
Write-Output "-Begin Release Portable"
& "$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_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\create_upg_chk_files.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
& "$PSScriptRoot\update_and_upload_website_release_json_file.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
Write-Output "-End Release Portable"
}
Write-Output "End mRemoteNG Post Build"
Write-Output ""

View File

@@ -25,6 +25,9 @@ param (
$ExcludeFromSigning
)
. "$PSScriptRoot\github_functions.ps1"
Write-Output ""
Write-Output "+===========================================================================================+"
Write-Output "| Beginning mRemoteNG Installer Post Build |"
Write-Output "+===========================================================================================+"
@@ -37,7 +40,24 @@ Format-Table -AutoSize -Wrap -InputObject @{
"ExcludeFromSigning" = $ExcludeFromSigning
}
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
& "$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\rename_and_copy_installer.ps1" -SolutionDir $SolutionDir
if ( $IsAppVeyor -and ($ConfigurationName.ToUpper() -match "RELEASE") -and (($env:APPVEYOR_PROJECT_NAME).ToUpper() -notmatch "(CI)") ) {
& "$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\rename_and_copy_installer.ps1" -SolutionDir $SolutionDir -BuildConfiguration $ConfigurationName.Trim()
& "$PSScriptRoot\create_upg_chk_files.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
& "$PSScriptRoot\update_and_upload_website_release_json_file.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
& "$PSScriptRoot\update_and_upload_assemblyinfocs.ps1"
}
Write-Output "End mRemoteNG Installer Post Build"
Write-Output ""

View File

@@ -1,61 +0,0 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
$CertificatePath,
[string]
$CertificatePassword,
[string[]]
$ExcludeFromSigning
)
Write-Output "+===========================================================================================+"
Write-Output "| Beginning mRemoteNG Post Build |"
Write-Output "+===========================================================================================+"
Format-Table -AutoSize -Wrap -InputObject @{
"SolutionDir" = $SolutionDir
"TargetDir" = $TargetDir
"TargetFileName" = $TargetFileName
"ConfigurationName" = $ConfigurationName
"CertificatePath" = $CertificatePath
"ExcludeFromSigning" = $ExcludeFromSigning
}
# Move dlls resurses into folder
#Remove-Item -Path "$TargetDir\libs" -Recurse -ErrorAction Ignore
#New-Item -ItemType "directory" -Force -Path $TargetDir -Name "libs"
#Move-Item -Path "$TargetDir\*.dll" -Destination "$TargetDir\libs" -force
###
# Move lang resurses into folder
#Remove-Item -Path "$TargetDir\languages" -Recurse -ErrorAction Ignore
#New-Item -ItemType "directory" -Force -Path $TargetDir -Name "languages"
#"cs-CZ,de,el,en-US,es-AR,es,fr,hu,it,lt,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW,fi-FI".Split(",") | ForEach {
# Move-Item -Path "$TargetDir\$_" -Destination "$TargetDir\languages" -force
# }
###
& "$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_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName

View File

@@ -0,0 +1,91 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
$CertificatePath,
[string]
$CertificatePassword,
[string[]]
$ExcludeFromSigning
)
. "$PSScriptRoot\github_functions.ps1"
Write-Output ""
Write-Output "+===========================================================================================+"
Write-Output "| Beginning mRemoteNG Portable Post Build |"
Write-Output "+===========================================================================================+"
Format-Table -AutoSize -Wrap -InputObject @{
"SolutionDir" = $SolutionDir
"TargetDir" = $TargetDir
"TargetFileName" = $TargetFileName
"ConfigurationName" = $ConfigurationName
"CertificatePath" = $CertificatePath
"ExcludeFromSigning" = $ExcludeFromSigning
}
# Move dlls resurses into folder
#Remove-Item -Path "$TargetDir\libs" -Recurse -ErrorAction Ignore
#New-Item -ItemType "directory" -Force -Path $TargetDir -Name "libs"
#Move-Item -Path "$TargetDir\*.dll" -Destination "$TargetDir\libs" -force
###
# Move lang resurses into folder
#Remove-Item -Path "$TargetDir\languages" -Recurse -ErrorAction Ignore
#New-Item -ItemType "directory" -Force -Path $TargetDir -Name "languages"
#"cs-CZ,de,el,en-US,es-AR,es,fr,hu,it,lt,ja-JP,ko-KR,nb-NO,nl,pt,pt-BR,pl,ru,uk,tr-TR,zh-CN,zh-TW,fi-FI".Split(",") | ForEach {
# Move-Item -Path "$TargetDir\$_" -Destination "$TargetDir\languages" -force
# }
###
# Currently targeting x64, shouldn't need to manually set LargeAddressAware...
#& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
#& "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
if (!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
$postbuild_installer_executed = Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\AppVeyor_mRemoteNG' -Name postbuild_installer_executed
} else {
$postbuild_installer_executed = ""
}
write-host "-SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName "
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
if ($postbuild_installer_executed -ne "true" -or $env:postbuild_installer_executed -ne "true") {
& "$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_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
if ( ![string]::IsNullOrEmpty($env:WEBSITE_TARGET_OWNER) -and ![string]::IsNullOrEmpty($env:WEBSITE_TARGET_REPOSITORY) ) {
& "$PSScriptRoot\create_upg_chk_files.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
& "$PSScriptRoot\update_and_upload_website_release_json_file.ps1" -WebsiteTargetOwner $env:WEBSITE_TARGET_OWNER -WebsiteTargetRepository $env:WEBSITE_TARGET_REPOSITORY -PreTagName $env:NightlyBuildTagName -TagName $env:APPVEYOR_BUILD_VERSION -ProjectName $env:APPVEYOR_PROJECT_NAME
}
Write-Output "End mRemoteNG Portable Post Build"
Write-Output ""

View File

@@ -1,13 +1,61 @@
param (
[string]
$SolutionDir
$SolutionDir,
[string]
$BuildConfiguration
)
$ErrorActionPreference = "Stop"
$targetVersionedFile = "$SolutionDir\mRemoteNG\bin\x64\Release\mRemoteNG.exe"
$version = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile
$src = $SolutionDir + "mRemoteNGInstaller\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
$dst = $SolutionDir + "mRemoteNG\bin\x64\Release\mRemoteNG-Installer-" + $version + ".msi"
Write-Output ""
Write-Output " /===== Begin rename_and_copy_installer =====/"
$targetVersionedFile = "$SolutionDir\mRemoteNG\bin\x64\$BuildConfiguration\mRemoteNG.exe"
#$fileversion = &"$SolutionDir\Tools\exes\sigcheck.exe" /accepteula -q -n $targetVersionedFile
#$prodversion = ((Get-Item -Path $targetVersionedFile).VersionInfo | Select-Object -Property ProductVersion)."ProductVersion"
$fileversion = ((Get-Item -Path $targetVersionedFile).VersionInfo | Select-Object -Property FileVersion)."FileVersion"
Write-Output "fileversion: $fileversion"
$msiversion = $fileversion
# determine update channel
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
Write-Output " UpdateChannel = Nightly"
$msiversion = "$msiversion-NB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
Write-Output " UpdateChannel = Preview"
$msiversion = "$msiversion-PB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
Write-Output " UpdateChannel = Stable"
} else {
}
$dstPath = "$($SolutionDir)Release"
New-Item -Path $dstPath -ItemType Directory -Force
$srcMsi = $SolutionDir + "mRemoteNGInstaller\Installer\bin\x64\$BuildConfiguration\en-US\mRemoteNG-Installer.msi"
$dstMsi = $dstPath + "\mRemoteNG-Installer-" + $msiversion + ".msi"
#$srcSymbols = $SolutionDir + "mRemoteNGInstaller\Installer\bin\x64\$BuildConfiguration\en-US\mRemoteNG-Installer-Symbols*.zip"
#$dstSymbols = $SolutionDir + "Release\mRemoteNG-Installer-Symbols-" + $msiversion + ".zip"
Write-Output " Copy Installer file:"
Write-Output " From: $srcMsi"
Write-Output " To: $dstMsi"
Write-Output ""
# Copy file
Copy-Item $src -Destination $dst -Force
try
{
Copy-Item $srcMsi -Destination $dstMsi -Force -ErrorAction Stop
#Copy-Item $srcSymbols -Destination $dstSymbols -Force -ErrorAction Stop
Write-Host " [Success!]" -ForegroundColor green
}
catch
{
Write-Host " [Failure!]" -ForegroundColor red
Write-Output $Error[0]
$PSCmdlet.ThrowTerminatingError()
}
Write-Output ""
Write-Output " /===== End rename_and_copy_installer.ps1 =====/"
Write-Output ""

View File

@@ -24,65 +24,80 @@ param (
$SolutionDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output ""
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
# validate release versions and if the certificate value was passed
if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
try {
# validate release versions and if the certificate value was passed
if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
if(-Not ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) {
$CertificatePath = Join-Path -Path $SolutionDir -ChildPath $CertificatePath
if($IsAppVeyor) {
$CertificatePath = Join-Path -Path $SolutionDir -ChildPath $CertificatePath
Write-Output "Decrypt Cert"
& appveyor-tools\secure-file -decrypt "$($Env:cert_path).enc" -secret "$Env:cert_decrypt_pwd"
if(-Not (Test-Path $Env:cert_path)) {
Write-Output "decrypt cert does not exist..."
Throw "Could not decrypt cert"
}
Write-Output "Restoring NuGets"
}
# make sure the cert is actually available
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
{
Write-Output "Certificate is not present - we won't sign files."
return
}
if ($CertificatePassword -eq "") {
Write-Output "No certificate password was provided - we won't sign files."
return
}
try {
$certKeyStore = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword, $certKeyStore) -ErrorAction Stop
} catch {
Write-Output "Error loading certificate file - we won't sign files."
Write-Output $Error[0]
return
}
# Sign MSI if we are building a release version and the certificate is available
Write-Output "Signing Binaries"
Write-Output "Getting files from path: $TargetDir"
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
$excluded_files = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -contains $_.Name}
$excluded_files | ForEach-Object `
-Begin { Write-Output "The following files were excluded from signing due to being on the exclusion list:" } `
-Process { Write-Output "-- $($_.FullName)" }
Write-Output "Signable files count: $($signableFiles.Count)"
foreach ($file in $signableFiles) {
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
}
# Release certificate
if ($null -ne $cert) {
$cert.Dispose()
}
} else {
Write-Output "This is not a release build or CertificatePath wasn't provided - we won't sign files."
Write-Output "Config: $($ConfigurationName)`tCertPath: $($CertificatePath)"
}
# make sure the cert is actually available
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
{
Write-Output "Certificate is not present - we won't sign files."
return
}
if ($CertificatePassword -eq "") {
Write-Output "No certificate password was provided - we won't sign files."
return
}
try {
$certKeyStore = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword, $certKeyStore) -ErrorAction Stop
} catch {
Write-Output "Error loading certificate file - we won't sign files."
Write-Output $Error[0]
return
}
# Sign MSI if we are building a release version and the certificate is available
Write-Output "Signing Binaries"
Write-Output "Getting files from path: $TargetDir"
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
$excluded_files = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -contains $_.Name}
$excluded_files | ForEach-Object `
-Begin { Write-Output "The following files were excluded from signing due to being on the exclusion list:" } `
-Process { Write-Output "-- $($_.FullName)" }
Write-Output "Signable files count: $($signableFiles.Count)"
foreach ($file in $signableFiles) {
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
}
# Release certificate
if ($cert -ne $null) {
$cert.Dispose()
}
} else {
Write-Output "This is not a release build or CertificatePath wasn't provided - we won't sign files."
Write-Output "Config: $($ConfigurationName)`tCertPath: $($CertificatePath)"
}
catch {
Write-Output $Error[0]
}
Write-Output ""
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

View File

@@ -28,4 +28,6 @@ Write-Output "Signable files count: $($signableFiles.Count)"
foreach ($file in $signableFiles) {
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
}
}
Write-Output ""

View File

@@ -7,12 +7,12 @@ param (
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output ""
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
# Remove unnecessary files from Release versions
if ($ConfigurationName -match "Release")
{
if ($ConfigurationName -match "Release") {
$test = Join-Path -Path $TargetDir -ChildPath "app.publish"
if (Test-Path $test -PathType Container)
{
@@ -29,19 +29,18 @@ if ($ConfigurationName -match "Release")
) -Exclude @(
"mRemoteNG.VisualElementsManifest.xml"
)
if ($filesToDelete)
{
Write-Output "Unnecessary files are detected and will be removed"
Remove-Item -Path $filesToDelete.FullName
Write-Output $filesToDelete.FullName
} else
{
} else {
Write-Output " No unnecessary files are detected"
}
}
else
{
} else {
Write-Output "We will not remove anything - this is not a release build."
}
Write-Output ""
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

View File

@@ -0,0 +1,53 @@
#Requires -Version 4.0
Write-Output ""
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
$MainRepository = $Env:APPVEYOR_REPO_NAME.Split("/\")[1]
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
Write-Output "MainRepository: $MainRepository"
if ($IsAppVeyor) {
# determine update channel
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
Write-Output "UpdateChannel = Nightly"
$UpdateChannel = "Nightly"
$ModifiedTagName = "$PreTagName-$TagName-NB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
Write-Output "UpdateChannel = Preview"
$UpdateChannel = "Preview"
$ModifiedTagName = "v$TagName-PB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
Write-Output "UpdateChannel = Stable"
$UpdateChannel = "Stable"
$ModifiedTagName = "v" + $TagName.Split("-")[0]
} else {
$UpdateChannel = ""
}
if ($UpdateChannel -ne "" -and $MainRepository -ne "" ) {
# commit AssemblyInfo.cs change
Write-Output "publish AssemblyInfo.cs"
$buildFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\" -Resolve -ErrorAction Ignore
if (Test-Path -Path "$buildFolder\mRemoteNG\Properties\AssemblyInfo.cs") {
$assemblyinfocs_content = [System.String]::Join("`r`n", (Get-Content "$buildFolder\mRemoteNG\Properties\AssemblyInfo.cs"))
Set-GitHubContent -OwnerName $MainRepository -RepositoryName $MainRepository -Path "mRemoteNG\Properties\AssemblyInfo.cs" -CommitMessage "AssemblyInfo.cs updated for $UpdateChannel $ModifiedTagName" -Content $assemblyinfocs_content -BranchName main
Write-Output "publish completed"
}
} else {
Write-Output "Source folder not found"
}
}
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

View File

@@ -0,0 +1,178 @@
#Requires -Version 4.0
param (
[string]
[Parameter(Mandatory=$true)]
$WebsiteTargetOwner,
[string]
[Parameter(Mandatory=$true)]
$WebsiteTargetRepository,
[string]
[Parameter(Mandatory=$false)]
$PreTagName = "",
[string]
[Parameter(Mandatory=$true)]
$TagName,
[string]
[Parameter(Mandatory=$true)]
$ProjectName
)
Write-Output ""
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
$MainRepository = $Env:APPVEYOR_REPO_NAME.Split("/\")[1]
# determine update channel
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
Write-Output "UpdateChannel = Nightly"
$UpdateChannel = "Nightly"
$ModifiedTagName = "$PreTagName-$TagName-NB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
Write-Output "UpdateChannel = Preview"
$UpdateChannel = "Preview"
$ModifiedTagName = "v$TagName-PB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
Write-Output "UpdateChannel = Stable"
$UpdateChannel = "Stable"
$ModifiedTagName = "v" + $TagName.Split("-")[0]
} else {
$UpdateChannel = ""
}
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
if ($IsAppVeyor) {
#$buildFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\mRemoteNG\bin\x64\Release" -Resolve -ErrorAction Ignore
$ReleaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
if ($UpdateChannel -ne "" -and $ReleaseFolder -ne "" -and $MainRepository -ne "" -and $WebsiteTargetOwner -ne "" -and $WebsiteTargetRepository -ne "" ) {
$published_at = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
# get releases.json from github
$releases_json = Get-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path _data\releases.json
ConvertFrom-Base64($releases_json.content) | Out-File -FilePath "$ReleaseFolder\releases.json"
$websiteJsonReleaseFile = Get-ChildItem -Path "$ReleaseFolder\releases.json"
# installer
$msiFile = Get-ChildItem -Path "$ReleaseFolder\*.msi" | Sort-Object LastWriteTime | Select-Object -last 1
if (![string]::IsNullOrEmpty($msiFile)) {
Write-Output "UpdateChannel: $UpdateChannel"
Write-Output "msiFile: $msiFile"
$checksum = (Get-FileHash $msiFile -Algorithm SHA512).Hash
$file_size = (Get-ChildItem $msiFile).Length
$a = Get-Content $websiteJsonReleaseFile | ConvertFrom-Json
switch ($UpdateChannel) {
"Nightly" {
$GithubTag = "$((Get-Date).ToUniversalTime().ToString("yyyyMMdd"))-$TagName-NB"
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($msiFile.Name)"
$a.nightlybuild.name = "v$TagName-NB"
$a.nightlybuild.published_at = $published_at
$a.nightlybuild.html_url = $html_url
$a.nightlybuild.assets.installer.browser_download_url = $browser_download_url
$a.nightlybuild.assets.installer.checksum = $checksum
$a.nightlybuild.assets.installer.size = $file_size
break
}
"Preview" {
$GithubTag = "$TagName-PB"
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($msiFile.Name)"
$a.prerelease.name = "v$TagName-PB"
$a.prerelease.published_at = $published_at
$a.prerelease.html_url = $html_url
$a.prerelease.assets.installer.browser_download_url = $browser_download_url
$a.prerelease.assets.installer.checksum = $checksum
$a.prerelease.assets.installer.size = $file_size
break
}
"Stable" {
$GithubTag = "$TagName"
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($msiFile.Name)"
$a.stable.name = "v$TagName"
$a.stable.published_at = $published_at
$a.stable.html_url = $html_url
$a.stable.assets.installer.browser_download_url = $browser_download_url
$a.stable.assets.installer.checksum = $checksum
$a.stable.assets.installer.size = $file_size
break
}
}
}
# portable
$zipFile = Get-ChildItem -Path "$ReleaseFolder\*.zip" -Exclude "*-symbols-*.zip" | Sort-Object LastWriteTime | Select-Object -last 1
if (![string]::IsNullOrEmpty($zipFile)) {
Write-Output "UpdateChannel: $UpdateChannel"
Write-Output "zipFile: $zipFile"
$checksum = (Get-FileHash $zipFile -Algorithm SHA512).Hash
$file_size = (Get-ChildItem $zipFile).Length
$a = Get-Content $websiteJsonReleaseFile | ConvertFrom-Json
switch ($UpdateChannel) {
"Nightly" {
$GithubTag = "$((Get-Date).ToUniversalTime().ToString("yyyyMMdd"))-$TagName-NB"
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($zipFile.Name)"
$a.nightlybuild.name = "v$TagName-NB"
$a.nightlybuild.published_at = $published_at
$a.nightlybuild.html_url = $html_url
$a.nightlybuild.assets.portable.browser_download_url = $browser_download_url
$a.nightlybuild.assets.portable.checksum = $checksum
$a.nightlybuild.assets.portable.size = $file_size
break
}
"Preview" {
$GithubTag = "$TagName-PB"
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($zipFile.Name)"
$a.prerelease.name = "v$TagName-PB"
$a.prerelease.published_at = $published_at
$a.prerelease.html_url = $html_url
$a.prerelease.assets.portable.browser_download_url = $browser_download_url
$a.prerelease.assets.portable.checksum = $checksum
$a.prerelease.assets.portable.size = $file_size
break
}
"Stable" {
$GithubTag = "$TagName"
$html_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/tag/$GithubTag"
$browser_download_url = "https://github.com/$WebsiteTargetOwner/$MainRepository/releases/download/$GithubTag/$($zipFile.Name)"
$a.stable.name = "v$TagName"
$a.stable.published_at = $published_at
$a.stable.html_url = $html_url
$a.stable.assets.portable.browser_download_url = $browser_download_url
$a.stable.assets.portable.checksum = $checksum
$a.stable.assets.portable.size = $file_size
break
}
}
}
$a | ConvertTo-Json -Depth 10 | Set-Content $websiteJsonReleaseFile
# commit releases.json change
if ($env:WEBSITE_UPDATE_ENABLED.ToLower() -eq "true") {
Write-Output "publish releases.json"
if (Test-Path -Path "$ReleaseFolder\releases.json") {
$releases_json_string = Get-Content "$ReleaseFolder\releases.json" | Out-String
Set-GitHubContent -OwnerName $WebsiteTargetOwner -RepositoryName $WebsiteTargetRepository -Path _data\releases.json -CommitMessage "Updated for $UpdateChannel $ModifiedTagName" -Content $releases_json_string -BranchName main
Write-Output "publish completed"
}
}
} else {
Write-Output "ReleaseFolder not found"
}
}
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

View File

@@ -5,7 +5,13 @@ param (
$FullPath
)
$validMSCertThumbprints = @("3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC", "108E2BA23632620C427C570B6D9DB51AC31387FE", "98ED99A67886D020C564923B7DF25E9AC019DF26", "5EAD300DC7E4D637948ECB0ED829A072BD152E17")
$validMSCertThumbprints = @(
"3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC",
"108E2BA23632620C427C570B6D9DB51AC31387FE",
"98ED99A67886D020C564923B7DF25E9AC019DF26",
"5EAD300DC7E4D637948ECB0ED829A072BD152E17",
"97221B97098F37A135DCC212E2B41E452BCE51F2"
)
$exeSignature = Get-AuthenticodeSignature -FilePath $FullPath
$baseErrorMsg = "Could not validate the certificate of $FullPath. "
@@ -14,4 +20,4 @@ if ($exeSignature.Status -ne "Valid") {
}
elseif ($validMSCertThumbprints -notcontains $exeSignature.SignerCertificate.Thumbprint) {
Write-Error -Message ($baseErrorMsg+"The certificate thumbprint ($($exeSignature.SignerCertificate.Thumbprint)) is not trusted.") -ErrorAction Stop
}
}

View File

@@ -10,7 +10,8 @@ param (
$TargetFileName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output ""
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
$path_dumpBin = Join-Path -Path $PSScriptRoot -ChildPath "exes\dumpbin.exe"
$path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
@@ -18,7 +19,7 @@ $path_outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
# Dump exe header
$output = & "$path_dumpBin" /NOLOGO /HEADERS "$path_outputExe" | Select-String large
if ($output -eq $null)
if ($null -eq $output)
{
Write-Warning "Could not validate LargeAddressAware"
}
@@ -27,4 +28,5 @@ else
Write-Output $output.ToString().TrimStart(" ")
}
Write-Output ""
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

View File

@@ -18,13 +18,15 @@ param (
$SolutionDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output ""
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
# validate release versions and if the certificate value was passed
if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
if(-Not ([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) ) {
if($IsAppVeyor) {
$CertificatePath = Join-Path -Path $SolutionDir -ChildPath $CertificatePath
}
@@ -37,9 +39,10 @@ if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
Write-Output "Verifying signature of binaries"
Write-Output "Getting files from path: $TargetDir"
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"}
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | Where-Object {$_.Extension -match "dll|exe|msi"}
Write-Output "Signable files count: $($signableFiles.Count)"
$badSignatureFound = $false
foreach ($file in $signableFiles) {
$signature = Get-AuthenticodeSignature -FilePath $file.FullName
if ($signature.Status -ne "Valid") {
@@ -47,6 +50,7 @@ if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
$badSignatureFound = $true
}
}
if ($badSignatureFound) {
Write-Output "One or more files were improperly signed."
} else {
@@ -57,4 +61,5 @@ if ($ConfigurationName -match "Release" -And ($CertificatePath)) {
Write-Output "Config: $($ConfigurationName)`tCertPath: $($CertificatePath)"
}
Write-Output ""
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

View File

@@ -13,71 +13,81 @@
)
Write-Output ""
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "===== Begin $($PSCmdlet.MyInvocation.MyCommand) ====="
$IsAppVeyor = !([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))
$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)"
#$version = ((Get-Item -Path $exe).VersionInfo | Select-Object -Property ProductVersion)."ProductVersion"
$version = $(Get-Item -Path $exe).VersionInfo.FileVersion
Write-Output "FileVersion: $version"
# determine update channel
if ($env:APPVEYOR_PROJECT_NAME -match "(Nightly)") {
Write-Output "UpdateChannel = Nightly"
$ModifiedVersion = "$version-NB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Preview)") {
Write-Output "UpdateChannel = Preview"
$ModifiedVersion = "$version-PB"
} elseif ($env:APPVEYOR_PROJECT_NAME -match "(Stable)") {
Write-Output "UpdateChannel = Stable"
$ModifiedVersion = $version
} else {
}
# Fix for AppVeyor
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
if(!(test-path "Release")) {
if($IsAppVeyor) {
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"
Write-Output "Packaging debug symbols"
$zipFilePrefix = "mRemoteNG-symbols"
$pdbFiles = Get-ChildItem -Path $SolutionDir -Filter *.pdb -Recurse
$tempPdbPath = (New-TemporaryDirectory)[0]
foreach ($pdbFile in $pdbFiles) {
if (($pdbFile.FullName).Contains("\$ConfigurationName\")) {
Copy-Item $pdbFile.FullName -Destination $tempPdbPath -Force
}
$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 {
if (!(Test-Path -Path $debugFile -PathType Leaf))
{
$outputZipPath = "$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
Compress-Archive $debugFile $outputZipPath -Force
} else {
write-host "File do not exist:" $debugFile", nothing to compress"
}
}
Remove-Item $debugFile
}
if ($IsAppVeyor) {
# AppVeyor build
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\$zipFilePrefix-$($ModifiedVersion).zip"
Write-Output "outputZipPath: $outputZipPath"
7z a $outputZipPath "$tempPdbPath\*.pdb"
}
# else {
# # Local build
# $outputZipPath = "$($SolutionDir)Release\$zipFilePrefix-$($ModifiedVersion).zip"
# Write-Output "outputZipPath: $outputZipPath"
# Compress-Archive -Path $tempPdbPath -DestinationPath $outputZipPath -Force
# }
# 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 {
if ($Source)
{
$outputZipPath="$($SolutionDir)\Release\mRemoteNG-Portable-$($version).zip"
Compress-Archive $Source $outputZipPath -Force
} else {
write-host "File do not exist:" $Source", nothing to compress"
}
Write-Output "Packaging portable ZIP file"
# AppVeyor build
if ($IsAppVeyor) {
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\mRemoteNG-Portable-$($ModifiedVersion).zip"
7z a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath $TargetDir\*
Write-Output "Portable ZIP: $outputZipPath"
}
# Local build
else {
if ($Source)
{
$outputZipPath="$($SolutionDir)\Release\mRemoteNG-Portable-$($ModifiedVersion).zip"
Compress-Archive $Source $outputZipPath -Force
} else {
Write-Output "Files do not exist:" $Source", nothing to compress"
}
}
Write-Output ""
Write-Output "End $($PSCmdlet.MyInvocation.MyCommand)"
Write-Output ""

6
mRemoteNG.lutconfig Normal file
View File

@@ -0,0 +1,6 @@
<LUTConfig Version="1.0">
<Repository />
<ParallelBuilds>true</ParallelBuilds>
<ParallelTestRuns>true</ParallelTestRuns>
<TestCaseTimeout>180000</TestCaseTimeout>
</LUTConfig>

View File

@@ -13,7 +13,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomActions", "mRemoteNGI
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "mRemoteNGInstaller\Installer\Installer.wixproj", "{F0168B9F-6815-40DF-BA53-46CEE7683B68}"
ProjectSection(ProjectDependencies) = postProject
{4934A491-40BC-4E5B-9166-EA1169A220F6} = {4934A491-40BC-4E5B-9166-EA1169A220F6}
{5423D985-CB48-4344-B47F-E8C6D60C8B04} = {5423D985-CB48-4344-B47F-E8C6D60C8B04}
{A56A2029-79B8-492A-ABE5-D2BFE05801BD} = {A56A2029-79B8-492A-ABE5-D2BFE05801BD}
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
@@ -22,55 +24,39 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalConnectors", "Exter
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug Portable|x64 = Debug Portable|x64
Debug|x64 = Debug|x64
Release Installer|x64 = Release Installer|x64
Release Portable|x64 = Release Portable|x64
Release Installer and Portable|x64 = Release Installer and Portable|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x64.ActiveCfg = Debug Portable|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x64.Build.0 = Debug Portable|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x64.ActiveCfg = Debug|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x64.Build.0 = Debug|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x64.ActiveCfg = Release|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x64.Build.0 = Release|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x64.ActiveCfg = Release Portable|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x64.Build.0 = Release Portable|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|x64.ActiveCfg = Release|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|x64.Build.0 = Release|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x64.ActiveCfg = Release|x64
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x64.Build.0 = Release|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x64.ActiveCfg = Debug Portable|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x64.ActiveCfg = Debug|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x64.ActiveCfg = Release|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x64.ActiveCfg = Release Portable|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x64.Build.0 = Release Portable|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x64.Build.0 = Debug|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer and Portable|x64.ActiveCfg = Release|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x64.ActiveCfg = Release|x64
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x64.Build.0 = Release|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x64.ActiveCfg = Debug Portable|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x64.ActiveCfg = Debug|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x64.ActiveCfg = Release|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x64.Build.0 = Release|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x64.ActiveCfg = Release Portable|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x64.Build.0 = Debug|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer and Portable|x64.ActiveCfg = Release|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer and Portable|x64.Build.0 = Release|x64
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x64.ActiveCfg = Release|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x64.ActiveCfg = Debug Portable|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x64.ActiveCfg = Debug|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x64.ActiveCfg = Release|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x64.Build.0 = Release|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|x64.ActiveCfg = Release Portable|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x64.Build.0 = Debug|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer and Portable|x64.ActiveCfg = Release|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer and Portable|x64.Build.0 = Release|x64
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|x64.ActiveCfg = Release|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug Portable|x64.ActiveCfg = Debug Portable|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x64.ActiveCfg = Debug|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|x64.ActiveCfg = Release|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Portable|x64.ActiveCfg = Release Portable|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x64.ActiveCfg = Release|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug Portable|x64.ActiveCfg = Debug Portable|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug Portable|x64.Build.0 = Debug Portable|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x64.Build.0 = Debug|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer and Portable|x64.ActiveCfg = Release|x64
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x64.ActiveCfg = Release Installer|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|x64.ActiveCfg = Debug|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|x64.Build.0 = Debug|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer|x64.ActiveCfg = Release|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer|x64.Build.0 = Release|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Portable|x64.ActiveCfg = Release Portable|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Portable|x64.Build.0 = Release Portable|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|x64.ActiveCfg = Release|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|x64.Build.0 = Release|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|x64.ActiveCfg = Release|x64
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|x64.Build.0 = Release|x64
EndGlobalSection

11
mRemoteNG/App.config Normal file
View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="LanguageFolder" value="Language"/>
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="Languages"/>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -8,9 +8,11 @@ using mRemoteNG.Properties;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.TaskDialog;
using mRemoteNG.Resources.Language;
using System.Runtime.Versioning;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class CompatibilityChecker
{
public static void CheckCompatibility(MessageCollector messageCollector)
@@ -33,13 +35,13 @@ namespace mRemoteNG.App
if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return;
var errorText = string.Format(Language.ErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName);
string errorText = string.Format(Language.ErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName);
messageCollector.AddMessage(MessageClass.ErrorMsg, errorText, true);
//About to pop up a message, let's not block it...
FrmSplashScreenNew.GetInstance().Close();
var ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, Language.CompatibilityProblemDetected, errorText, "", "", Language.CheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.OkCancel, ESysIcons.Warning, ESysIcons.Warning);
DialogResult ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, Language.CompatibilityProblemDetected, errorText, "", "", Language.CheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.OkCancel, ESysIcons.Warning, ESysIcons.Warning);
if (CTaskDialog.VerificationChecked && ShouldIStayOrShouldIGo == DialogResult.OK)
{
messageCollector.AddMessage(MessageClass.ErrorMsg, "User requests that FIPS check be overridden", true);
@@ -54,7 +56,7 @@ namespace mRemoteNG.App
private static bool FipsPolicyEnabledForServer2003()
{
var regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa");
RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa");
if (!(regKey?.GetValue("FIPSAlgorithmPolicy") is int fipsPolicy))
return false;
return fipsPolicy != 0;
@@ -62,7 +64,7 @@ namespace mRemoteNG.App
private static bool FipsPolicyEnabledForServer2008AndNewer()
{
var regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy");
RegistryKey regKey = Registry.LocalMachine.OpenSubKey(@"System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy");
if (!(regKey?.GetValue("Enabled") is int fipsPolicy))
return false;
return fipsPolicy != 0;
@@ -75,7 +77,7 @@ namespace mRemoteNG.App
if (!Settings.Default.CompatibilityWarnLenovoAutoScrollUtility)
return;
var proccesses = new Process[] { };
Process[] proccesses = new Process[] { };
try
{
proccesses = Process.GetProcessesByName("virtscrl");

View File

@@ -1,5 +1,6 @@
using System;
using System;
using System.Linq;
using System.Runtime.Versioning;
using System.Windows.Forms;
using mRemoteNG.Config.Connections;
using mRemoteNG.Config.DataProviders;
@@ -17,15 +18,16 @@ using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class Export
{
public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel)
{
try
{
var saveFilter = new SaveFilter();
SaveFilter saveFilter = new();
using (var exportForm = new FrmExport())
using (FrmExport exportForm = new())
{
if (selectedNode?.GetTreeNodeType() == TreeNodeType.Container)
exportForm.SelectedFolder = selectedNode as ContainerInfo;
@@ -79,9 +81,9 @@ namespace mRemoteNG.App
switch (saveFormat)
{
case SaveFormat.mRXML:
var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
var rootNode = exportTarget.GetRootParent() as RootNodeInfo;
var connectionNodeSerializer = new XmlConnectionNodeSerializer27(
ICryptographyProvider cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
RootNodeInfo rootNode = exportTarget.GetRootParent() as RootNodeInfo;
XmlConnectionNodeSerializer28 connectionNodeSerializer = new(
cryptographyProvider,
rootNode?.PasswordString
.ConvertToSecureString() ??
@@ -100,8 +102,8 @@ namespace mRemoteNG.App
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);
}
var serializedData = serializer.Serialize(exportTarget);
var fileDataProvider = new FileDataProvider(fileName);
string serializedData = serializer.Serialize(exportTarget);
FileDataProvider fileDataProvider = new(fileName);
fileDataProvider.Save(serializedData);
}
catch (Exception ex)

View File

@@ -8,22 +8,24 @@ using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
using mRemoteNG.Tools;
using mRemoteNG.Resources.Language;
using System.Runtime.Versioning;
namespace mRemoteNG.App
{
public static class Import
[SupportedOSPlatform("windows")]
public static class Import
{
public static void ImportFromFile(ContainerInfo importDestinationContainer)
{
try
{
using (var openFileDialog = new OpenFileDialog())
using (OpenFileDialog openFileDialog = new())
{
openFileDialog.CheckFileExists = true;
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
openFileDialog.Multiselect = true;
var fileTypes = new List<string>();
List<string> fileTypes = new();
fileTypes.AddRange(new[] {Language.FilterAllImportable, "*.xml;*.rdp;*.rdg;*.dat;*.csv"});
fileTypes.AddRange(new[] {Language.FiltermRemoteXML, "*.xml"});
fileTypes.AddRange(new[] {Language.FiltermRemoteCSV, "*.csv"});
@@ -31,6 +33,7 @@ namespace mRemoteNG.App
fileTypes.AddRange(new[] {Language.FilterRdgFiles, "*.rdg"});
fileTypes.AddRange(new[] {Language.FilterPuttyConnectionManager, "*.dat"});
fileTypes.AddRange(new[] {Language.FilterAll, "*.*"});
fileTypes.AddRange(new[] { Language.FilterSecureCRT, "*.crt" });
openFileDialog.Filter = string.Join("|", fileTypes.ToArray());
@@ -57,13 +60,13 @@ namespace mRemoteNG.App
{
using (Runtime.ConnectionsService.BatchedSavingContext())
{
using (var openFileDialog = new OpenFileDialog())
using (OpenFileDialog openFileDialog = new())
{
openFileDialog.CheckFileExists = true;
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
openFileDialog.Multiselect = false;
var fileTypes = new List<string>();
List<string> fileTypes = new();
fileTypes.AddRange(new[] {Language.FiltermRemoteRemoteDesktopManagerCSV, "*.csv"});
openFileDialog.Filter = string.Join("|", fileTypes.ToArray());
@@ -71,7 +74,7 @@ namespace mRemoteNG.App
if (openFileDialog.ShowDialog() != DialogResult.OK)
return;
var importer = new RemoteDesktopManagerImporter();
RemoteDesktopManagerImporter importer = new();
importer.Import(openFileDialog.FileName, importDestinationContainer);
}
}
@@ -90,11 +93,11 @@ namespace mRemoteNG.App
{
using (connectionsService.BatchedSavingContext())
{
foreach (var fileName in filePaths)
foreach (string fileName in filePaths)
{
try
{
var importer = BuildConnectionImporterFromFileExtension(fileName);
IConnectionImporter<string> importer = BuildConnectionImporterFromFileExtension(fileName);
importer.Import(fileName, importDestinationContainer);
}
catch (Exception ex)
@@ -131,7 +134,7 @@ namespace mRemoteNG.App
{
using (Runtime.ConnectionsService.BatchedSavingContext())
{
var importer = new PortScanImporter(protocol);
PortScanImporter importer = new(protocol);
importer.Import(hosts, importDestinationContainer);
}
}
@@ -141,10 +144,25 @@ namespace mRemoteNG.App
}
}
internal static void ImportFromPutty(ContainerInfo selectedNodeAsContainer)
{
try
{
using (Runtime.ConnectionsService.BatchedSavingContext())
{
RegistryImporter.Import("Software\\SimonTatham\\PuTTY\\Sessions", selectedNodeAsContainer);
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("App.Import.ImportFromPutty() failed.", ex);
}
}
private static IConnectionImporter<string> BuildConnectionImporterFromFileExtension(string fileName)
{
// TODO: Use the file contents to determine the file type instead of trusting the extension
var extension = Path.GetExtension(fileName) ?? "";
string extension = Path.GetExtension(fileName) ?? "";
switch (extension.ToLowerInvariant())
{
case ".xml":
@@ -157,6 +175,8 @@ namespace mRemoteNG.App
return new RemoteDesktopConnectionManagerImporter();
case ".dat":
return new PuttyConnectionManagerImporter();
case ".crt":
return new SecureCRTImporter();
default:
throw new FileFormatException("Unrecognized file format.");
}

View File

@@ -1,12 +1,14 @@
using System;
using System.Runtime.Versioning;
namespace mRemoteNG.App.Info
{
public static class ConnectionsFileInfo
{
public static readonly string DefaultConnectionsPath = SettingsFileInfo.SettingsPath;
public static readonly string DefaultConnectionsFile = "confCons.xml";
public static readonly string DefaultConnectionsFileNew = "confConsNew.xml";
public static readonly Version ConnectionFileVersion = new Version(2, 9);
}
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public static class ConnectionsFileInfo
{
public static readonly string DefaultConnectionsPath = SettingsFileInfo.SettingsPath;
public static readonly string DefaultConnectionsFile = "confCons.xml";
public static readonly string DefaultConnectionsFileNew = "confConsNew.xml";
public static readonly Version ConnectionFileVersion = new(3, 0);
}
}

View File

@@ -1,5 +1,8 @@
namespace mRemoteNG.App.Info
using System.Runtime.Versioning;
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public class CredentialsFileInfo
{
public static readonly string CredentialsPath = SettingsFileInfo.SettingsPath;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using System.Threading;
using System.Windows.Forms;
using static System.Environment;
@@ -9,37 +10,33 @@ using static System.Environment;
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public static class GeneralAppInfo
{
public const string UrlHome = "https://www.mremoteng.org";
public const string UrlHome = "https://mremoteng.org";
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 ApplicationVersion = Application.ProductVersion;
public static readonly string ProductName = Application.ProductName;
public static readonly string Copyright =
((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
typeof(AssemblyCopyrightAttribute), false))
.Copyright;
public static readonly string Copyright = ((AssemblyCopyrightAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCopyrightAttribute), false))?.Copyright;
public static readonly string HomePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
//public static string ReportingFilePath = "";
public static readonly string PuttyPath = HomePath + "\\PuTTYNG.exe";
private static readonly string puttyPath = HomePath + "\\PuTTYNG.exe";
public static string UserAgent
{
get
{
var details = new List<string>
{
List<string> details =
[
"compatible",
OSVersion.Platform == PlatformID.Win32NT
? $"Windows NT {OSVersion.Version.Major}.{OSVersion.Version.Minor}"
: OSVersion.VersionString
};
];
if (Is64BitProcess)
{
details.Add("WOW64");
@@ -47,15 +44,17 @@ namespace mRemoteNG.App.Info
details.Add(Thread.CurrentThread.CurrentUICulture.Name);
details.Add($".NET CLR {Environment.Version}");
var detailsString = string.Join("; ", details.ToArray());
string detailsString = string.Join("; ", [.. details]);
return $"Mozilla/5.0 ({detailsString}) {ProductName}/{ApplicationVersion}";
}
}
public static string PuttyPath => puttyPath;
public static Version GetApplicationVersion()
{
System.Version.TryParse(ApplicationVersion, out var v);
_ = System.Version.TryParse(ApplicationVersion, out Version v);
return v;
}
}

View File

@@ -1,11 +1,13 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using System.Windows.Forms;
using mRemoteNG.Connection;
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public static class SettingsFileInfo
{
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
@@ -15,6 +17,7 @@ namespace mRemoteNG.App.Info
public static string LayoutFileName { get; } = "pnlLayout.xml";
public static string ExtAppsFilesName { get; } = "extApps.xml";
public static string ThemesFileName { get; } = "Themes.xml";
public static string LocalConnectionProperties { get; } = "LocalConnectionProperties.xml";
public static string ThemeFolder { get; } =
SettingsPath != null ? Path.Combine(SettingsPath, "Themes") : String.Empty;

View File

@@ -1,10 +1,12 @@
using System;
using System.Runtime.Versioning;
using mRemoteNG.Properties;
// ReSharper disable InconsistentNaming
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public static class UpdateChannelInfo
{
public const string STABLE = "Stable";
@@ -22,7 +24,7 @@ namespace mRemoteNG.App.Info
public static Uri GetUpdateChannelInfo()
{
var channel = IsValidChannel(Properties.OptionsUpdatesPage.Default.UpdateChannel) ? Properties.OptionsUpdatesPage.Default.UpdateChannel : STABLE;
string channel = IsValidChannel(Properties.OptionsUpdatesPage.Default.UpdateChannel) ? Properties.OptionsUpdatesPage.Default.UpdateChannel : STABLE;
return GetUpdateTxtUri(channel);
}

View File

@@ -0,0 +1,87 @@
using Microsoft.Win32;
using System.Runtime.Versioning;
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public static class WindowsRegistryInfo
{
#region General Parameters
public const RegistryHive Hive = RegistryHive.LocalMachine;
public const string RootKey = "SOFTWARE\\mRemoteNG";
private const string OptionsSubKey = "Options";
#endregion
#region Key Locations
// StartupExit
// Registry subkey for general application startup and exit settings
// Registry subkey for startup and exit options page settings
public const string StartupExit = RootKey + "\\StartupExit";
public const string StartupExitOptions = StartupExit + "\\" + OptionsSubKey;
// Appearance
// Registry subkey for general application appearance settings
// Registry subkey for appearance options page settings
public const string Appearance = RootKey + "\\Appearance";
public const string AppearanceOptions = Appearance + "\\" + OptionsSubKey;
// Connections
// Registry subkey for general application connection settings
// Registry subkey for connections options page settings
public const string Connection = RootKey + "\\Connections";
public const string ConnectionOptions = Connection + "\\" + OptionsSubKey;
// Tabs & Panels
// Registry subkey for general application tabs and panels settings
// Registry subkey for tabs and panels options page settings
public const string TabsAndPanels = RootKey + "\\TabsAndPanels";
public const string TabsAndPanelsOptions = TabsAndPanels + "\\" + OptionsSubKey;
// Notifications
// Registry subkey for general application notifications settings
// Registry subkey for notifications options page settings
public const string Notification = RootKey + "\\Notifications";
public const string NotificationOptions = Notification + "\\" + OptionsSubKey;
// Credential
// Registry subkey for general application credentials settings
// Registry subkey for credentials options page settings
public const string Credential = RootKey + "\\Credentials";
public const string CredentialOptions = Credential + "\\" + OptionsSubKey;
// SQL Server
// Registry subkey for general application SQL server settings
// Registry subkey for SQL server options page settings
public const string SQLServer = RootKey + "\\SQLServer";
public const string SQLServerOptions = SQLServer + "\\" + OptionsSubKey;
// Updates
// Registry subkey for general application update settings
// Registry subkey for updates options page settings
public const string Update = RootKey + "\\Updates";
public const string UpdateOptions = Update + "\\" + OptionsSubKey;
// Security
// Registry subkey for general application security settings
// Registry subkey for security options page settings
public const string Security = RootKey + "\\Security";
public const string SecurityOptions = Security + "\\" + OptionsSubKey;
// Advanced
// Registry subkey for general application advanced settings
// Registry subkey for advanced options page settings
public const string Advanced = RootKey + "\\Advanced";
public const string AdvancedOptions = Advanced + "\\" + OptionsSubKey;
// Backup
// Registry subkey for general application backup settings
// Registry subkey for backup options page settings
public const string Backup = RootKey + "\\Backup";
public const string BackupOptions = Backup + "\\" + OptionsSubKey;
#endregion
}
}

View File

@@ -1,10 +1,12 @@
using System;
using System.IO;
using System.Runtime.Versioning;
using mRemoteNG.Connection;
namespace mRemoteNG.App.Initialization
{
[SupportedOSPlatform("windows")]
public class ConnectionIconLoader
{
private readonly string _path;
@@ -22,9 +24,9 @@ namespace mRemoteNG.App.Initialization
if (Directory.Exists(_path) == false)
return;
foreach (var f in Directory.GetFiles(_path, "*.ico", SearchOption.AllDirectories))
foreach (string f in Directory.GetFiles(_path, "*.ico", SearchOption.AllDirectories))
{
var fInfo = new FileInfo(f);
FileInfo fInfo = new(f);
Array.Resize(ref ConnectionIcon.Icons, ConnectionIcon.Icons.Length + 1);
ConnectionIcon.Icons.SetValue(fInfo.Name.Replace(".ico", ""), ConnectionIcon.Icons.Length - 1);
}

View File

@@ -1,9 +1,11 @@
using System.IO;
using System.Runtime.Versioning;
using mRemoteNG.Config.Connections;
using mRemoteNG.Properties;
namespace mRemoteNG.App.Initialization
{
[SupportedOSPlatform("windows")]
public class CredsAndConsSetup
{
public void LoadCredsAndCons()

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.Messages;
using mRemoteNG.Messages.MessageFilteringOptions;
using mRemoteNG.Messages.MessageWriters;
@@ -7,17 +8,24 @@ using mRemoteNG.Messages.WriterDecorators;
namespace mRemoteNG.App.Initialization
{
[SupportedOSPlatform("windows")]
public class MessageCollectorSetup
{
public static void SetupMessageCollector(MessageCollector messageCollector,
IList<IMessageWriter> messageWriterList)
public static void SetupMessageCollector(MessageCollector messageCollector, IList<IMessageWriter> messageWriterList)
{
messageCollector.CollectionChanged += (o, args) =>
{
var messages = args.NewItems.Cast<IMessage>().ToArray();
foreach (var printer in messageWriterList)
foreach (var message in messages)
if (args.NewItems == null) return;
IMessage[] messages = args.NewItems.Cast<IMessage>().ToArray();
foreach (IMessageWriter printer in messageWriterList)
{
foreach (IMessage message in messages)
{
printer.Write(message);
}
}
};
}
@@ -39,37 +47,30 @@ namespace mRemoteNG.App.Initialization
private static IMessageWriter BuildTextLogMessageWriter()
{
return new MessageTypeFilterDecorator(
new LogMessageTypeFilteringOptions(),
new TextLogMessageWriter(Logger.Instance)
);
new LogMessageTypeFilteringOptions(),
new TextLogMessageWriter(Logger.Instance)
);
}
private static IMessageWriter BuildNotificationPanelMessageWriter()
{
return new OnlyLogMessageFilter(
new MessageTypeFilterDecorator(
new
NotificationPanelMessageFilteringOptions(),
new MessageFocusDecorator(
Windows.ErrorsForm,
new
NotificationPanelSwitchOnMessageFilteringOptions(),
new
NotificationPanelMessageWriter(Windows
.ErrorsForm)
)
)
);
new MessageTypeFilterDecorator(
new NotificationPanelMessageFilteringOptions(),
new MessageFocusDecorator(Windows.ErrorsForm,
new NotificationPanelSwitchOnMessageFilteringOptions(),
new NotificationPanelMessageWriter(Windows.ErrorsForm))
)
);
}
private static IMessageWriter BuildPopupMessageWriter()
{
return new OnlyLogMessageFilter(
new MessageTypeFilterDecorator(
new PopupMessageFilteringOptions(),
new PopupMessageWriter()
)
);
new MessageTypeFilterDecorator(
new PopupMessageFilteringOptions(),
new PopupMessageWriter())
);
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Management;
using System.Runtime.Versioning;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Messages;
@@ -7,16 +8,14 @@ using mRemoteNG.Resources.Language;
namespace mRemoteNG.App.Initialization
{
[SupportedOSPlatform("windows")]
public class StartupDataLogger
{
private readonly MessageCollector _messageCollector;
public StartupDataLogger(MessageCollector messageCollector)
{
if (messageCollector == null)
throw new ArgumentNullException(nameof(messageCollector));
_messageCollector = messageCollector;
_messageCollector = messageCollector ?? throw new ArgumentNullException(nameof(messageCollector));
}
public void LogStartupData()
@@ -30,25 +29,25 @@ namespace mRemoteNG.App.Initialization
private void LogSystemData()
{
var osData = GetOperatingSystemData();
var architecture = GetArchitectureData();
var nonEmptyData = Array.FindAll(new[] {osData, architecture}, s => !string.IsNullOrEmpty(s));
var data = string.Join(" ", nonEmptyData);
string osData = GetOperatingSystemData();
string architecture = GetArchitectureData();
string[] nonEmptyData = Array.FindAll(new[] {osData, architecture}, s => !string.IsNullOrEmpty(s));
string data = string.Join(" ", nonEmptyData);
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
}
private string GetOperatingSystemData()
{
var osVersion = string.Empty;
var servicePack = string.Empty;
string osVersion = string.Empty;
string servicePack = string.Empty;
try
{
foreach (var o in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True")
foreach (ManagementBaseObject o in new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem WHERE Primary=True")
.Get())
{
var managementObject = (ManagementObject)o;
osVersion = Convert.ToString(managementObject.GetPropertyValue("Caption")).Trim();
ManagementObject managementObject = (ManagementObject)o;
osVersion = Convert.ToString(managementObject.GetPropertyValue("Caption"))?.Trim();
servicePack = GetOSServicePack(servicePack, managementObject);
}
}
@@ -57,13 +56,13 @@ namespace mRemoteNG.App.Initialization
_messageCollector.AddExceptionMessage("Error retrieving operating system information from WMI.", ex);
}
var osData = string.Join(" ", osVersion, servicePack);
string osData = string.Join(" ", osVersion, servicePack);
return osData;
}
private string GetOSServicePack(string servicePack, ManagementObject managementObject)
{
var servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
int servicePackNumber = Convert.ToInt32(managementObject.GetPropertyValue("ServicePackMajorVersion"));
if (servicePackNumber != 0)
{
servicePack = $"Service Pack {servicePackNumber}";
@@ -74,14 +73,13 @@ namespace mRemoteNG.App.Initialization
private string GetArchitectureData()
{
var architecture = string.Empty;
string architecture = string.Empty;
try
{
foreach (var o in new ManagementObjectSearcher("SELECT AddressWidth FROM Win32_Processor WHERE DeviceID=\'CPU0\'")
.Get())
foreach (ManagementBaseObject o in new ManagementObjectSearcher("SELECT AddressWidth FROM Win32_Processor WHERE DeviceID=\'CPU0\'").Get())
{
var managementObject = (ManagementObject)o;
var addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
ManagementObject managementObject = (ManagementObject)o;
int addressWidth = Convert.ToInt32(managementObject.GetPropertyValue("AddressWidth"));
architecture = $"{addressWidth}-bit";
}
}
@@ -95,7 +93,7 @@ namespace mRemoteNG.App.Initialization
private void LogApplicationData()
{
var data = $"{Application.ProductName} {Application.ProductVersion}";
string data = $"{Application.ProductName} {Application.ProductVersion}";
if (Runtime.IsPortableEdition)
data += $" {Language.PortableEdition}";
data += " starting.";
@@ -104,20 +102,19 @@ namespace mRemoteNG.App.Initialization
private void LogCmdLineArgs()
{
var data = $"Command Line: {string.Join(" ", Environment.GetCommandLineArgs())}";
string data = $"Command Line: {string.Join(" ", Environment.GetCommandLineArgs())}";
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
}
private void LogClrData()
{
var data = $"Microsoft .NET CLR {Environment.Version}";
string data = $"Microsoft .NET CLR {Environment.Version}";
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
}
private void LogCultureData()
{
var data =
$"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}";
string data = $"System Culture: {Thread.CurrentThread.CurrentUICulture.Name}/{Thread.CurrentThread.CurrentUICulture.NativeName}";
_messageCollector.AddMessage(MessageClass.InformationMsg, data, true);
}
}

View File

@@ -1,19 +1,18 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using System.Windows.Forms;
using log4net;
using log4net.Appender;
using log4net.Config;
using mRemoteNG.Properties;
// ReSharper disable ArrangeAccessorOwnerBody
using log4net.Repository;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public class Logger
{
public static readonly Logger Instance = new Logger();
public static readonly Logger Instance = new();
public ILog Log { get; private set; }
@@ -27,22 +26,27 @@ namespace mRemoteNG.App
private void Initialize()
{
XmlConfigurator.Configure(LogManager.CreateRepository("mRemoteNG"));
if (string.IsNullOrEmpty(Properties.OptionsNotificationsPage.Default.LogFilePath))
{
Properties.OptionsNotificationsPage.Default.LogFilePath = BuildLogFilePath();
}
SetLogPath(Properties.OptionsNotificationsPage.Default.LogToApplicationDirectory ? DefaultLogPath : Properties.OptionsNotificationsPage.Default.LogFilePath);
}
public void SetLogPath(string path)
{
var repository = LogManager.GetRepository("mRemoteNG");
XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));
var appenders = repository.GetAppenders();
ILoggerRepository repository = LogManager.GetRepository("mRemoteNG");
foreach (var appender in appenders)
XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));
IAppender[] appenders = repository.GetAppenders();
foreach (IAppender appender in appenders)
{
var fileAppender = (RollingFileAppender)appender;
if (fileAppender == null || fileAppender.Name != "LogFileAppender") continue;
RollingFileAppender fileAppender = (RollingFileAppender)appender;
if (fileAppender is not { Name: "LogFileAppender" }) continue;
fileAppender.File = path;
fileAppender.ActivateOptions();
}
@@ -52,22 +56,26 @@ namespace mRemoteNG.App
private static string BuildLogFilePath()
{
var logFilePath = Runtime.IsPortableEdition ? GetLogPathPortableEdition() : GetLogPathNormalEdition();
var logFileName = Path.ChangeExtension(Application.ProductName, ".log");
string logFilePath = Runtime.IsPortableEdition ? GetLogPathPortableEdition() : GetLogPathNormalEdition();
string logFileName = Path.ChangeExtension(Application.ProductName, ".log");
if (logFileName == null) return "mRemoteNG.log";
var logFile = Path.Combine(logFilePath, logFileName);
string logFile = Path.Combine(logFilePath, logFileName);
return logFile;
}
private static string GetLogPathNormalEdition()
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
Application.ProductName);
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Application.ProductName);
}
private static string GetLogPathPortableEdition()
{
return Application.StartupPath;
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Drawing;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
#pragma warning disable 649
@@ -9,6 +10,7 @@ using System.Text;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class NativeMethods
{
#region Functions

View File

@@ -1,17 +1,22 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using mRemoteNG.Properties;
using mRemoteNG.Config.Settings;
using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class ProgramRoot
{
private static Mutex _mutex;
private static FrmSplashScreenNew _frmSplashScreen = null;
private static string customResourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Languages");
/// <summary>
/// The main entry point for the application.
@@ -19,32 +24,80 @@ namespace mRemoteNG.App
[STAThread]
public static void Main(string[] args)
{
if (Properties.OptionsStartupExitPage.Default.SingleInstance)
Trace.WriteLine("!!!!!!=============== TEST ==================!!!!!!!!!!!!!");
// Forcing to load System.Configuration.ConfigurationManager before any other assembly to be able to check settings
try
{
string assemblyFile = "System.Configuration.ConfigurationManager" + ".dll";
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
if (File.Exists(assemblyPath))
{
Assembly.LoadFrom(assemblyPath);
}
}
catch (FileNotFoundException ex)
{
Trace.WriteLine("Error occured: " + ex.Message);
}
//Subscribe to AssemblyResolve event
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
//Check if local settings DB exist or accessible
CheckLockalDB();
Lazy<bool> singleInstanceOption = new Lazy<bool>(() => Properties.OptionsStartupExitPage.Default.SingleInstance);
if (singleInstanceOption.Value)
{
StartApplicationAsSingleInstance();
}
else
{
StartApplication();
}
}
private static void CheckLockalDB()
{
LocalSettingsDBManager settingsManager = new LocalSettingsDBManager(dbPath: "mRemoteNG.appSettings", useEncryption: false, schemaFilePath: "");
}
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs resolveArgs)
{
string assemblyName = new AssemblyName(resolveArgs.Name).Name.Replace(".resources", string.Empty);
string assemblyFile = assemblyName + ".dll";
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
if (File.Exists(assemblyPath))
{
return Assembly.LoadFrom(assemblyPath);
}
return null;
}
private static void StartApplication()
{
CatchAllUnhandledExceptions();
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var frmSplashScreen = FrmSplashScreenNew.GetInstance();
_frmSplashScreen = FrmSplashScreenNew.GetInstance();
Screen targetScreen = (Screen.AllScreens.Length > 1) ? Screen.AllScreens[1] : Screen.AllScreens[0];
Screen targetScreen = Screen.PrimaryScreen;
Rectangle viewport = targetScreen.WorkingArea;
frmSplashScreen.Top = viewport.Top;
frmSplashScreen.Left = viewport.Left;
// normaly it should be screens[1] however due DPI apply 1 size "same" as default with 100%
frmSplashScreen.Left = viewport.Left + (targetScreen.Bounds.Size.Width / 2) - (frmSplashScreen.Width / 2);
frmSplashScreen.Top = viewport.Top + (targetScreen.Bounds.Size.Height / 2) - (frmSplashScreen.Height / 2);
frmSplashScreen.Show();
System.Windows.Forms.Application.Run(FrmMain.Default);
_frmSplashScreen.Top = viewport.Top;
_frmSplashScreen.Left = viewport.Left;
// normally it should be screens[1] however due DPI apply 1 size "same" as default with 100%
_frmSplashScreen.Left = viewport.Left + (targetScreen.Bounds.Size.Width - _frmSplashScreen.Width) / 2;
_frmSplashScreen.Top = viewport.Top + (targetScreen.Bounds.Size.Height - _frmSplashScreen.Height) / 2;
_frmSplashScreen.ShowInTaskbar = false;
_frmSplashScreen.Show();
Application.Run(FrmMain.Default);
}
public static void CloseSingletonInstanceMutex()
@@ -55,7 +108,7 @@ namespace mRemoteNG.App
private static void StartApplicationAsSingleInstance()
{
const string mutexID = "mRemoteNG_SingleInstanceMutex";
_mutex = new Mutex(false, mutexID, out var newInstanceCreated);
_mutex = new Mutex(false, mutexID, out bool newInstanceCreated);
if (!newInstanceCreated)
{
SwitchToCurrentInstance();
@@ -68,18 +121,18 @@ namespace mRemoteNG.App
private static void SwitchToCurrentInstance()
{
var singletonInstanceWindowHandle = GetRunningSingletonInstanceWindowHandle();
IntPtr singletonInstanceWindowHandle = GetRunningSingletonInstanceWindowHandle();
if (singletonInstanceWindowHandle == IntPtr.Zero) return;
if (NativeMethods.IsIconic(singletonInstanceWindowHandle) != 0)
NativeMethods.ShowWindow(singletonInstanceWindowHandle, (int)NativeMethods.SW_RESTORE);
_ = NativeMethods.ShowWindow(singletonInstanceWindowHandle, (int)NativeMethods.SW_RESTORE);
NativeMethods.SetForegroundWindow(singletonInstanceWindowHandle);
}
private static IntPtr GetRunningSingletonInstanceWindowHandle()
{
var windowHandle = IntPtr.Zero;
var currentProcess = Process.GetCurrentProcess();
foreach (var enumeratedProcess in Process.GetProcessesByName(currentProcess.ProcessName))
IntPtr windowHandle = IntPtr.Zero;
Process currentProcess = Process.GetCurrentProcess();
foreach (Process enumeratedProcess in Process.GetProcessesByName(currentProcess.ProcessName))
{
if (enumeratedProcess.Id != currentProcess.Id &&
enumeratedProcess.MainModule.FileName == currentProcess.MainModule.FileName &&
@@ -99,14 +152,13 @@ namespace mRemoteNG.App
private static void ApplicationOnThreadException(object sender, ThreadExceptionEventArgs e)
{
// if (PresentationSource.FromVisual(FrmSplashScreenNew))
FrmSplashScreenNew.GetInstance().Close();
// if (PresentationSource.FromVisual(FrmSplashScreenNew))
FrmSplashScreenNew.GetInstance().Close();
if (FrmMain.Default.IsDisposed) return;
var window = new FrmUnhandledException(e.Exception, false);
FrmUnhandledException window = new(e.Exception, false);
window.ShowDialog(FrmMain.Default);
}
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
@@ -115,8 +167,9 @@ namespace mRemoteNG.App
//if (!FrmSplashScreenNew.GetInstance().IsDisposed)
// FrmSplashScreenNew.GetInstance().Close();
var window = new FrmUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
FrmUnhandledException window = new(e.ExceptionObject as Exception, e.IsTerminating);
window.ShowDialog(FrmMain.Default);
}
}
}

View File

@@ -17,9 +17,11 @@ using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using System.Runtime.Versioning;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class Runtime
{
public static bool IsPortableEdition
@@ -44,21 +46,19 @@ namespace mRemoteNG.App
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
public static ExternalToolsService ExternalToolsService { get; } = new ExternalToolsService();
public static SecureString EncryptionKey { get; set; } =
new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
public static ConnectionInitiator ConnectionInitiator { get; set; } = new ConnectionInitiator();
public static ConnectionsService ConnectionsService { get; } =
new ConnectionsService(PuttySessionsManager.Instance);
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance);
#region Connections Loading/Saving
public static void LoadConnectionsAsync()
{
var t = new Thread(LoadConnectionsBGd);
Thread t = new(LoadConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
@@ -77,7 +77,7 @@ namespace mRemoteNG.App
/// </param>
public static void LoadConnections(bool withDialog = false)
{
var connectionFileName = "";
string connectionFileName = "";
try
{
@@ -86,7 +86,7 @@ namespace mRemoteNG.App
if (withDialog)
{
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
OpenFileDialog loadDialog = DialogFactory.BuildLoadConnectionsDialog();
if (loadDialog.ShowDialog() != DialogResult.OK)
return;
@@ -103,7 +103,7 @@ namespace mRemoteNG.App
if (Properties.OptionsDBsPage.Default.UseSQLServer)
{
ConnectionsService.LastSqlUpdate = DateTime.Now;
ConnectionsService.LastSqlUpdate = DateTime.Now.ToUniversalTime();
}
else
{
@@ -120,7 +120,7 @@ namespace mRemoteNG.App
if (Properties.OptionsDBsPage.Default.UseSQLServer)
{
MessageCollector.AddExceptionMessage(Language.LoadFromSqlFailed, ex);
var commandButtons = string.Join("|", Language._TryAgain, Language.CommandOpenConnectionFile, string.Format(Language.CommandExitProgram, Application.ProductName));
string commandButtons = string.Join("|", Language._TryAgain, Language.CommandOpenConnectionFile, string.Format(Language.CommandExitProgram, Application.ProductName));
CTaskDialog.ShowCommandBox(Application.ProductName, Language.LoadFromSqlFailed, Language.LoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error);
switch (CTaskDialog.CommandButtonResult)
{
@@ -152,7 +152,7 @@ namespace mRemoteNG.App
Language.Exit
};
var answered = false;
bool answered = false;
while (!answered)
{
try

View File

@@ -1,4 +1,5 @@
using System.Windows.Forms;
using System.Runtime.Versioning;
using System.Windows.Forms;
using mRemoteNG.UI.Forms;
using WeifenLuo.WinFormsUI.Docking;
@@ -6,10 +7,11 @@ namespace mRemoteNG.App
{
public static class Screens
{
[SupportedOSPlatform("windows")]
public static void SendFormToScreen(Screen screen)
{
var frmMain = FrmMain.Default;
var wasMax = false;
FrmMain frmMain = FrmMain.Default;
bool wasMax = false;
if (frmMain.WindowState == FormWindowState.Maximized)
{

View File

@@ -8,11 +8,13 @@ using mRemoteNG.Properties;
using mRemoteNG.UI.Controls;
using mRemoteNG.UI.Forms;
using mRemoteNG.Resources.Language;
using System.Runtime.Versioning;
// ReSharper disable ArrangeAccessorOwnerBody
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class Shutdown
{
private static string _updateFilePath;
@@ -65,8 +67,7 @@ namespace mRemoteNG.App
DateTime updateDate;
DateTime currentDate = DateTime.Now;
//OBSOLETE: Settings.Default.SaveConsOnExit is obsolete and should be removed in a future release
if (Properties.OptionsStartupExitPage.Default.SaveConnectionsOnExit || (Properties.OptionsBackupPage.Default.SaveConnectionsFrequency == (int)ConnectionsBackupFrequencyEnum.OnExit))
if ((Properties.OptionsBackupPage.Default.SaveConnectionsFrequency == (int)ConnectionsBackupFrequencyEnum.OnExit))
{
Runtime.ConnectionsService.SaveConnections();
return;

View File

@@ -1,12 +1,13 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using mRemoteNG.App.Info;
using mRemoteNG.App.Initialization;
using mRemoteNG.App.Update;
using mRemoteNG.Config.Connections.Multiuser;
using mRemoteNG.Config.Settings.Registry;
using mRemoteNG.Connection;
using mRemoteNG.Messages;
using mRemoteNG.Properties;
@@ -18,8 +19,10 @@ using mRemoteNG.UI.Forms;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public class Startup
{
private RegistryLoader _RegistryLoader;
private AppUpdater _appUpdate;
private readonly ConnectionIconLoader _connectionIconLoader;
private readonly FrmMain _frmMain = FrmMain.Default;
@@ -28,18 +31,15 @@ namespace mRemoteNG.App
private Startup()
{
_appUpdate = new AppUpdater();
_RegistryLoader = RegistryLoader.Instance; //created instance
_appUpdate = new AppUpdater();
_connectionIconLoader = new ConnectionIconLoader(GeneralAppInfo.HomePath + "\\Icons\\");
}
static Startup()
{
}
public void InitializeProgram(MessageCollector messageCollector)
{
Debug.Print("---------------------------" + Environment.NewLine + "[START] - " + Convert.ToString(DateTime.Now, CultureInfo.InvariantCulture));
var startupLogger = new StartupDataLogger(messageCollector);
StartupDataLogger startupLogger = new(messageCollector);
startupLogger.LogStartupData();
CompatibilityChecker.CheckCompatibility(messageCollector);
ParseCommandLineArgs(messageCollector);
@@ -51,7 +51,7 @@ namespace mRemoteNG.App
private static void ParseCommandLineArgs(MessageCollector messageCollector)
{
var interpreter = new StartupArgumentsInterpreter(messageCollector);
StartupArgumentsInterpreter interpreter = new(messageCollector);
interpreter.ParseArguments(Environment.GetCommandLineArgs());
}
@@ -75,8 +75,7 @@ namespace mRemoteNG.App
return;
}
var nextUpdateCheck =
Convert.ToDateTime(Properties.OptionsUpdatesPage.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Properties.OptionsUpdatesPage.Default.CheckForUpdatesFrequencyDays))));
DateTime nextUpdateCheck = Convert.ToDateTime(Properties.OptionsUpdatesPage.Default.CheckForUpdatesLastCheck.Add(TimeSpan.FromDays(Convert.ToDouble(Properties.OptionsUpdatesPage.Default.CheckForUpdatesFrequencyDays))));
if (!Properties.OptionsUpdatesPage.Default.UpdatePending && DateTime.UtcNow < nextUpdateCheck)
{
return;

View File

@@ -3,12 +3,14 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using mRemoteNG.Properties;
// ReSharper disable ArrangeAccessorOwnerBody
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
[Serializable]
public sealed class SupportedCultures : Dictionary<string, string>
{
@@ -22,11 +24,11 @@ namespace mRemoteNG.App
private SupportedCultures()
{
foreach (var CultureName in Properties.AppUI.Default.SupportedUICultures.Split(','))
foreach (string CultureName in Properties.AppUI.Default.SupportedUICultures.Split(','))
{
try
{
var CultureInfo = new CultureInfo(CultureName.Trim());
CultureInfo CultureInfo = new(CultureName.Trim());
Add(CultureInfo.Name, CultureInfo.TextInfo.ToTitleCase(CultureInfo.NativeName));
}
catch (Exception ex)
@@ -55,13 +57,13 @@ namespace mRemoteNG.App
public static string get_CultureName(string CultureNativeName)
{
var Names = new string[SingletonInstance.Count + 1];
var NativeNames = new string[SingletonInstance.Count + 1];
string[] Names = new string[SingletonInstance.Count + 1];
string[] NativeNames = new string[SingletonInstance.Count + 1];
SingletonInstance.Keys.CopyTo(Names, 0);
SingletonInstance.Values.CopyTo(NativeNames, 0);
for (var Index = 0; Index <= SingletonInstance.Count; Index++)
for (int Index = 0; Index <= SingletonInstance.Count; Index++)
{
if (NativeNames[Index] == CultureNativeName)
{
@@ -81,8 +83,8 @@ namespace mRemoteNG.App
{
get
{
var ValueList = new List<string>();
foreach (var Value in SingletonInstance.Values)
List<string> ValueList = new();
foreach (string Value in SingletonInstance.Values)
{
ValueList.Add(Value);
}

View File

@@ -8,6 +8,7 @@ using mRemoteNG.Security.SymmetricEncryption;
using System.Security.Cryptography;
using System.Threading.Tasks;
using mRemoteNG.Properties;
using System.Runtime.Versioning;
#if !PORTABLE
using mRemoteNG.Tools;
@@ -19,6 +20,7 @@ using System.Windows.Forms;
namespace mRemoteNG.App.Update
{
[SupportedOSPlatform("windows")]
public class AppUpdater
{
private const int _bufferLength = 8192;
@@ -58,13 +60,13 @@ namespace mRemoteNG.App.Update
private void SetDefaultProxySettings()
{
var shouldWeUseProxy = Properties.OptionsUpdatesPage.Default.UpdateUseProxy;
var proxyAddress = Properties.OptionsUpdatesPage.Default.UpdateProxyAddress;
var port = Properties.OptionsUpdatesPage.Default.UpdateProxyPort;
var useAuthentication = Properties.OptionsUpdatesPage.Default.UpdateProxyUseAuthentication;
var username = Properties.OptionsUpdatesPage.Default.UpdateProxyAuthUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var password = cryptographyProvider.Decrypt(Properties.OptionsUpdatesPage.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
bool shouldWeUseProxy = Properties.OptionsUpdatesPage.Default.UpdateUseProxy;
string proxyAddress = Properties.OptionsUpdatesPage.Default.UpdateProxyAddress;
int port = Properties.OptionsUpdatesPage.Default.UpdateProxyPort;
bool useAuthentication = Properties.OptionsUpdatesPage.Default.UpdateProxyUseAuthentication;
string username = Properties.OptionsUpdatesPage.Default.UpdateProxyAuthUser;
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
string password = cryptographyProvider.Decrypt(Properties.OptionsUpdatesPage.Default.UpdateProxyAuthPass, Runtime.EncryptionKey);
SetProxySettings(shouldWeUseProxy, proxyAddress, port, useAuthentication, username, password);
}
@@ -130,37 +132,37 @@ namespace mRemoteNG.App.Update
try
{
_getUpdateInfoCancelToken = new CancellationTokenSource();
using var response = await _httpClient.GetAsync(CurrentUpdateInfo.DownloadAddress, HttpCompletionOption.ResponseHeadersRead, _getUpdateInfoCancelToken.Token);
var buffer = new byte[_bufferLength];
var totalBytes = response.Content.Headers.ContentLength ?? 0;
var readBytes = 0L;
using HttpResponseMessage response = await _httpClient.GetAsync(CurrentUpdateInfo.DownloadAddress, HttpCompletionOption.ResponseHeadersRead, _getUpdateInfoCancelToken.Token);
byte[] buffer = new byte[_bufferLength];
long totalBytes = response.Content.Headers.ContentLength ?? 0;
long readBytes = 0L;
await using (var httpStream = await response.Content.ReadAsStreamAsync(_getUpdateInfoCancelToken.Token))
await using (Stream httpStream = await response.Content.ReadAsStreamAsync(_getUpdateInfoCancelToken.Token))
{
await using var fileStream = new FileStream(CurrentUpdateInfo.UpdateFilePath, FileMode.Create,
await using FileStream fileStream = new(CurrentUpdateInfo.UpdateFilePath, FileMode.Create,
FileAccess.Write, FileShare.None, _bufferLength, true);
while (readBytes <= totalBytes || !_getUpdateInfoCancelToken.IsCancellationRequested)
{
var bytesRead =
await httpStream.ReadAsync(buffer, 0, _bufferLength, _getUpdateInfoCancelToken.Token);
int bytesRead =
await httpStream.ReadAsync(buffer.AsMemory(0, _bufferLength), _getUpdateInfoCancelToken.Token);
if (bytesRead == 0)
{
progress.Report(100);
break;
}
await fileStream.WriteAsync(buffer, 0, bytesRead, _getUpdateInfoCancelToken.Token);
await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead), _getUpdateInfoCancelToken.Token);
readBytes += bytesRead;
var percentComplete = (int)(readBytes * 100 / totalBytes);
int percentComplete = (int)(readBytes * 100 / totalBytes);
progress.Report(percentComplete);
}
}
#if !PORTABLE
var updateAuthenticode = new Authenticode(CurrentUpdateInfo.UpdateFilePath)
Authenticode updateAuthenticode = new(CurrentUpdateInfo.UpdateFilePath)
{
RequireThumbprintMatch = true,
ThumbprintToMatch = CurrentUpdateInfo.CertificateThumbprint
@@ -177,10 +179,10 @@ namespace mRemoteNG.App.Update
}
#endif
using var checksum = SHA512.Create();
await using var stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath);
var hash = await checksum.ComputeHashAsync(stream);
var hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
using SHA512 checksum = SHA512.Create();
await using FileStream stream = File.OpenRead(CurrentUpdateInfo.UpdateFilePath);
byte[] hash = await checksum.ComputeHashAsync(stream);
string hashString = BitConverter.ToString(hash).Replace("-", "").ToUpperInvariant();
if (!hashString.Equals(CurrentUpdateInfo.Checksum))
throw new Exception("SHA512 Hashes didn't match!");
} finally{
@@ -200,7 +202,7 @@ namespace mRemoteNG.App.Update
_httpClient.Dispose();
}
var httpClientHandler = new HttpClientHandler();
HttpClientHandler httpClientHandler = new();
if (_webProxy != null)
{
httpClientHandler.UseProxy = true;
@@ -222,7 +224,7 @@ namespace mRemoteNG.App.Update
try
{
_getUpdateInfoCancelToken = new CancellationTokenSource();
var updateInfo = await _httpClient.GetStringAsync(UpdateChannelInfo.GetUpdateChannelInfo(), _getUpdateInfoCancelToken.Token);
string updateInfo = await _httpClient.GetStringAsync(UpdateChannelInfo.GetUpdateChannelInfo(), _getUpdateInfoCancelToken.Token);
CurrentUpdateInfo = UpdateInfo.FromString(updateInfo);
Properties.OptionsUpdatesPage.Default.CheckForUpdatesLastCheck = DateTime.UtcNow;

View File

@@ -34,19 +34,19 @@ namespace mRemoteNG.App.Update
// no separators means no valid update data...
if (content.Trim().IndexOfAny(keyValueSeparators) == -1) return;
using (var sr = new StringReader(content))
using (StringReader sr = new(content))
{
string line;
while ((line = sr.ReadLine()) != null)
{
var trimmedLine = line.Trim();
string trimmedLine = line.Trim();
if (trimmedLine.Length == 0)
continue;
if (trimmedLine.Substring(0, 1).IndexOfAny(commentCharacters) != -1)
continue;
var parts = trimmedLine.Split(keyValueSeparators, 2);
string[] parts = trimmedLine.Split(keyValueSeparators, 2);
if (parts.Length != 2)
continue;
@@ -68,13 +68,13 @@ namespace mRemoteNG.App.Update
public Version GetVersion(string key = "Version")
{
var value = GetString(key);
string value = GetString(key);
return string.IsNullOrEmpty(value) ? null : new Version(value);
}
public Uri GetUri(string key)
{
var value = GetString(key);
string value = GetString(key);
return string.IsNullOrEmpty(value) ? null : new Uri(value);
}
@@ -85,8 +85,8 @@ namespace mRemoteNG.App.Update
public string GetFileName()
{
var value = GetString("dURL");
var sv = value.Split('/');
string value = GetString("dURL");
string[] sv = value.Split('/');
return sv[sv.Length - 1];
}

View File

@@ -22,14 +22,14 @@ namespace mRemoteNG.App.Update
public static UpdateInfo FromString(string input)
{
var newInfo = new UpdateInfo();
UpdateInfo newInfo = new();
if (string.IsNullOrEmpty(input))
{
newInfo.IsValid = false;
}
else
{
var updateFile = new UpdateFile(input);
UpdateFile updateFile = new(input);
newInfo.Version = updateFile.GetVersion();
newInfo.DownloadAddress = updateFile.GetUri("dURL");
newInfo.ChangeLogAddress = updateFile.GetUri("clURL");

View File

@@ -1,10 +1,15 @@
using System;
#region Usings
using System;
using System.Runtime.Versioning;
using mRemoteNG.Resources.Language;
using mRemoteNG.UI;
using mRemoteNG.UI.Forms;
using mRemoteNG.UI.Window;
#endregion
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class Windows
{
private static ActiveDirectoryImportWindow _adimportForm;
@@ -29,7 +34,7 @@ namespace mRemoteNG.App
{
try
{
var dockPanel = FrmMain.Default.pnlDock;
WeifenLuo.WinFormsUI.Docking.DockPanel dockPanel = FrmMain.Default.pnlDock;
// ReSharper disable once SwitchStatementMissingSomeCases
switch (windowType)
{
@@ -39,11 +44,8 @@ namespace mRemoteNG.App
_adimportForm.Show(dockPanel);
break;
case WindowType.Options:
using (var optionsForm = new FrmOptions())
{
optionsForm.ShowDialog(dockPanel);
}
FrmMain.OptionsForm.SetActivatedPage(Language.StartupExit);
FrmMain.OptionsForm.Visible = true;
break;
case WindowType.SSHTransfer:
if (SshtransferForm == null || SshtransferForm.IsDisposed)

View File

@@ -1,4 +1,5 @@
using System;
using System.Runtime.Versioning;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Csv;
@@ -7,6 +8,7 @@ using mRemoteNG.Tree;
namespace mRemoteNG.Config.Connections
{
[SupportedOSPlatform("windows")]
public class CsvConnectionsSaver : ISaver<ConnectionTreeModel>
{
private readonly string _connectionFileName;
@@ -25,10 +27,10 @@ namespace mRemoteNG.Config.Connections
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
var csvConnectionsSerializer =
new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
var dataProvider = new FileDataProvider(_connectionFileName);
var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
CsvConnectionsSerializerMremotengFormat csvConnectionsSerializer =
new(_saveFilter, Runtime.CredentialProviderCatalog);
FileDataProvider dataProvider = new(_connectionFileName);
string csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
dataProvider.Save(csvContent);
}
}

View File

@@ -1,11 +1,13 @@
using mRemoteNG.App;
using System;
using System.Runtime.Versioning;
using System.Timers;
// ReSharper disable ArrangeAccessorOwnerBody
namespace mRemoteNG.Config.Connections.Multiuser
{
[SupportedOSPlatform("windows")]
public class RemoteConnectionsSyncronizer : IConnectionsUpdateChecker
{
private readonly System.Timers.Timer _updateTimer;
@@ -27,8 +29,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
{
_updateChecker.UpdateCheckStarted += OnUpdateCheckStarted;
_updateChecker.UpdateCheckFinished += OnUpdateCheckFinished;
_updateChecker.ConnectionsUpdateAvailable +=
(sender, args) => ConnectionsUpdateAvailable?.Invoke(sender, args);
_updateChecker.ConnectionsUpdateAvailable += (sender, args) => ConnectionsUpdateAvailable?.Invoke(sender, args);
_updateTimer.Elapsed += (sender, args) => _updateChecker.IsUpdateAvailableAsync();
ConnectionsUpdateAvailable += Load;
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Data;
using System.Data.Common;
using System.Runtime.Versioning;
using System.Threading;
using mRemoteNG.App;
using mRemoteNG.Config.DatabaseConnectors;
@@ -8,6 +9,7 @@ using mRemoteNG.Messages;
namespace mRemoteNG.Config.Connections.Multiuser
{
[SupportedOSPlatform("windows")]
public class SqlConnectionsUpdateChecker : IConnectionsUpdateChecker
{
private readonly IDatabaseConnector _dbConnector;
@@ -27,7 +29,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
{
RaiseUpdateCheckStartedEvent();
ConnectToSqlDb();
var updateIsAvailable = DatabaseIsMoreUpToDateThanUs();
bool updateIsAvailable = DatabaseIsMoreUpToDateThanUs();
if (updateIsAvailable)
RaiseConnectionsUpdateAvailableEvent();
RaiseUpdateCheckFinishedEvent(updateIsAvailable);
@@ -36,7 +38,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
public void IsUpdateAvailableAsync()
{
var thread = new Thread(() => IsUpdateAvailable());
Thread thread = new(() => IsUpdateAvailable());
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
@@ -49,46 +51,44 @@ namespace mRemoteNG.Config.Connections.Multiuser
}
catch (Exception e)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
"Unable to connect to Sql DB to check for updates." +
Environment.NewLine + e.Message, true);
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"Unable to connect to SQL DB to check for updates.{Environment.NewLine}{e.Message}", true);
}
}
private bool DatabaseIsMoreUpToDateThanUs()
{
var lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
var amTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
DateTime lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
bool amTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
return (lastUpdateInDb > LastUpdateTime && !amTheLastoneUpdated);
}
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
{
DateTime lastSqlUpdateWithoutMilliseconds =
new DateTime(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond),
LastUpdateTime.Kind);
DateTime lastSqlUpdateWithoutMilliseconds = new(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond), LastUpdateTime.Kind);
return lastUpdateInDb == lastSqlUpdateWithoutMilliseconds;
}
private DateTime GetLastUpdateTimeFromDbResponse()
{
var lastUpdateInDb = default(DateTime);
DateTime lastUpdateInDb = default(DateTime);
try
{
var sqlReader = _dbQuery.ExecuteReader(CommandBehavior.CloseConnection);
DbDataReader sqlReader = _dbQuery.ExecuteReader(CommandBehavior.CloseConnection);
sqlReader.Read();
if (sqlReader.HasRows)
{
lastUpdateInDb = Convert.ToDateTime(sqlReader["LastUpdate"]);
}
sqlReader.Close();
}
catch (Exception ex)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg,
"Error executing Sql query to get updates from the DB." +
Environment.NewLine + ex.Message, true);
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Error executing SQL query to get updates from the DB." + Environment.NewLine + ex.Message, true);
}
_lastDatabaseUpdateTime = lastUpdateInDb;
return lastUpdateInDb;
}
@@ -104,7 +104,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
private void RaiseUpdateCheckFinishedEvent(bool updateAvailable)
{
var args = new ConnectionsUpdateCheckFinishedEventArgs {UpdateAvailable = updateAvailable};
ConnectionsUpdateCheckFinishedEventArgs args = new() { UpdateAvailable = updateAvailable};
UpdateCheckFinished?.Invoke(this, args);
}
@@ -113,7 +113,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
private void RaiseConnectionsUpdateAvailableEvent()
{
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Remote connection update is available");
var args = new ConnectionsUpdateAvailableEventArgs(_dbConnector, _lastDatabaseUpdateTime);
ConnectionsUpdateAvailableEventArgs args = new(_dbConnector, _lastDatabaseUpdateTime);
ConnectionsUpdateAvailable?.Invoke(this, args);
}

View File

@@ -4,9 +4,11 @@ using System.ComponentModel;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms;
using mRemoteNG.Properties;
using System.Runtime.Versioning;
namespace mRemoteNG.Config.Connections
{
[SupportedOSPlatform("windows")]
public class SaveConnectionsOnEdit
{
private readonly ConnectionsService _connectionsService;
@@ -22,11 +24,10 @@ namespace mRemoteNG.Config.Connections
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
{
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged +=
ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
foreach (Tree.ConnectionTreeModel oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
{
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
oldTree.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;

View File

@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using System.Security;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Sql;
using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Container;
using mRemoteNG.Security;
@@ -17,66 +18,58 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.Config.Connections
{
[SupportedOSPlatform("windows")]
public class SqlConnectionsLoader : IConnectionsLoader
{
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>>
_localConnectionPropertiesDeserializer;
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
private readonly IDataProvider<string> _dataProvider;
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; } =
() => MiscTools.PasswordDialog("", false);
private Func<Optional<SecureString>> AuthenticationRequestor { get; set; } = () => MiscTools.PasswordDialog("", false);
public SqlConnectionsLoader(
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
IDataProvider<string> dataProvider)
{
_localConnectionPropertiesDeserializer =
localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
_localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
}
public ConnectionTreeModel Load()
{
var connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
var dataProvider = new SqlDataProvider(connector);
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
var metaData = metaDataRetriever.GetDatabaseMetaData(connector) ??
HandleFirstRun(metaDataRetriever, connector);
var decryptionKey = GetDecryptionKey(metaData);
IDatabaseConnector connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
SqlDataProvider dataProvider = new(connector);
SqlDatabaseMetaDataRetriever metaDataRetriever = new();
SqlDatabaseVersionVerifier databaseVersionVerifier = new(connector);
LegacyRijndaelCryptographyProvider cryptoProvider = new();
SqlConnectionListMetaData metaData = metaDataRetriever.GetDatabaseMetaData(connector) ?? HandleFirstRun(metaDataRetriever, connector);
Optional<SecureString> decryptionKey = GetDecryptionKey(metaData);
if (!decryptionKey.Any())
throw new Exception("Could not load SQL connections");
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
var dataTable = dataProvider.Load();
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
var connectionTree = deserializer.Deserialize(dataTable);
System.Data.DataTable dataTable = dataProvider.Load();
DataTableDeserializer deserializer = new(cryptoProvider, decryptionKey.First());
ConnectionTreeModel connectionTree = deserializer.Deserialize(dataTable);
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
return connectionTree;
}
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var cipherText = metaData.Protected;
var authenticator = new PasswordAuthenticator(cryptographyProvider, cipherText, AuthenticationRequestor);
var authenticated =
authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword
.ConvertToSecureString());
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
string cipherText = metaData.Protected;
PasswordAuthenticator authenticator = new(cryptographyProvider, cipherText, AuthenticationRequestor);
bool authenticated = authenticator.Authenticate(new RootNodeInfo(RootNodeType.Connection).DefaultPassword.ConvertToSecureString());
if (authenticated)
return authenticator.LastAuthenticatedPassword;
return Optional<SecureString>.Empty;
return authenticated ? authenticator.LastAuthenticatedPassword : Optional<SecureString>.Empty;
}
private void ApplyLocalConnectionProperties(ContainerInfo rootNode)
{
var localPropertiesXml = _dataProvider.Load();
var localConnectionProperties = _localConnectionPropertiesDeserializer.Deserialize(localPropertiesXml);
string localPropertiesXml = _dataProvider.Load();
IEnumerable<LocalConnectionPropertiesModel> localConnectionProperties = _localConnectionPropertiesDeserializer.Deserialize(localPropertiesXml);
rootNode
.GetRecursiveChildList()

View File

@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Data;
using System.Linq;
using mRemoteNG.App;
using mRemoteNG.App.Info;
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql;
using mRemoteNG.Config.Serializers.Versioning;
using mRemoteNG.Connection;
using mRemoteNG.Container;
@@ -18,11 +17,13 @@ using mRemoteNG.Tools;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.Resources.Language;
using mRemoteNG.Properties;
using System.Runtime.Versioning;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Sql;
namespace mRemoteNG.Config.Connections
{
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
[SupportedOSPlatform("windows")]
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
{
private readonly SaveFilter _saveFilter;
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer;
@@ -30,16 +31,14 @@ namespace mRemoteNG.Config.Connections
public SqlConnectionsSaver(SaveFilter saveFilter, ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> localPropertieSerializer, IDataProvider<string> localPropertiesDataProvider)
{
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_saveFilter = saveFilter;
_saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
_localPropertiesSerializer = localPropertieSerializer.ThrowIfNull(nameof(localPropertieSerializer));
_dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
RootNodeInfo rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
UpdateLocalConnectionProperties(rootTreeNode);
@@ -55,12 +54,12 @@ namespace mRemoteNG.Config.Connections
return;
}
using (var dbConnector = DatabaseConnectorFactory.DatabaseConnectorFromSettings())
using (IDatabaseConnector dbConnector = DatabaseConnectorFactory.DatabaseConnectorFromSettings())
{
dbConnector.Connect();
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(dbConnector);
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
var metaData = metaDataRetriever.GetDatabaseMetaData(dbConnector);
SqlDatabaseVersionVerifier databaseVersionVerifier = new(dbConnector);
SqlDatabaseMetaDataRetriever metaDataRetriever = new();
SqlConnectionListMetaData metaData = metaDataRetriever.GetDatabaseMetaData(dbConnector);
if (!databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion))
{
@@ -94,7 +93,7 @@ namespace mRemoteNG.Config.Connections
private void UpdateLocalConnectionProperties(ContainerInfo rootNode)
{
var a = rootNode.GetRecursiveChildList().Select(info => new LocalConnectionPropertiesModel
IEnumerable<LocalConnectionPropertiesModel> a = rootNode.GetRecursiveChildList().Select(info => new LocalConnectionPropertiesModel
{
ConnectionId = info.ConstantID,
Connected = info.OpenConnections.Count > 0,
@@ -102,20 +101,21 @@ namespace mRemoteNG.Config.Connections
Favorite = info.Favorite,
});
var serializedProperties = _localPropertiesSerializer.Serialize(a);
string serializedProperties = _localPropertiesSerializer.Serialize(a);
_dataProvider.Save(serializedProperties);
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Saved local connection properties");
}
private void UpdateRootNodeTable(RootNodeInfo rootTreeNode, IDatabaseConnector databaseConnector)
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
// TODO: use transaction, but method not used at all?
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
string strProtected;
if (rootTreeNode != null)
{
if (rootTreeNode.Password)
{
var password = rootTreeNode.PasswordString.ConvertToSecureString();
System.Security.SecureString password = rootTreeNode.PasswordString.ConvertToSecureString();
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", password);
}
else
@@ -128,7 +128,7 @@ namespace mRemoteNG.Config.Connections
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", Runtime.EncryptionKey);
}
var dbQuery = databaseConnector.DbCommand("DELETE FROM tblRoot");
System.Data.Common.DbCommand dbQuery = databaseConnector.DbCommand("TRUNCATE TABLE tblRoot");
dbQuery.ExecuteNonQuery();
if (rootTreeNode != null)
@@ -137,37 +137,35 @@ namespace mRemoteNG.Config.Connections
databaseConnector.DbCommand(
"INSERT INTO tblRoot (Name, Export, Protected, ConfVersion) VALUES('" +
MiscTools.PrepareValueForDB(rootTreeNode.Name) + "', 0, '" + strProtected + "','" +
ConnectionsFileInfo.ConnectionFileVersion.ToString() + "')");
ConnectionsFileInfo.ConnectionFileVersion + "')");
dbQuery.ExecuteNonQuery();
}
else
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
$"UpdateRootNodeTable: rootTreeNode was null. Could not insert!");
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"UpdateRootNodeTable: rootTreeNode was null. Could not insert!");
}
}
private void UpdateConnectionsTable(RootNodeInfo rootTreeNode, IDatabaseConnector databaseConnector)
{
var dataProvider = new SqlDataProvider(databaseConnector);
var currentDataTable = dataProvider.Load();
SqlDataProvider dataProvider = new(databaseConnector);
DataTable currentDataTable = dataProvider.Load();
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
var serializer = new DataTableSerializer(_saveFilter, cryptoProvider,
rootTreeNode.PasswordString.ConvertToSecureString());
LegacyRijndaelCryptographyProvider cryptoProvider = new();
DataTableSerializer serializer = new(_saveFilter, cryptoProvider, rootTreeNode.PasswordString.ConvertToSecureString());
serializer.SetSourceDataTable(currentDataTable);
var dataTable = serializer.Serialize(rootTreeNode);
//var dbQuery = databaseConnector.DbCommand("DELETE FROM tblCons");
//dbQuery.ExecuteNonQuery();
DataTable dataTable = serializer.Serialize(rootTreeNode);
dataProvider.Save(dataTable);
}
private void UpdateUpdatesTable(IDatabaseConnector databaseConnector)
{
var dbQuery = databaseConnector.DbCommand("DELETE FROM tblUpdate");
// TODO: use transaction
System.Data.Common.DbCommand dbQuery = databaseConnector.DbCommand("TRUNCATE TABLE tblUpdate");
dbQuery.ExecuteNonQuery();
dbQuery = databaseConnector.DbCommand("INSERT INTO tblUpdate (LastUpdate) VALUES('" + MiscTools.DBDate(DateTime.Now) + "')");
dbQuery = databaseConnector.DbCommand("INSERT INTO tblUpdate (LastUpdate) VALUES('" + MiscTools.DBDate(DateTime.Now.ToUniversalTime()) + "')");
dbQuery.ExecuteNonQuery();
}

View File

@@ -5,9 +5,11 @@ using System;
using System.IO;
using System.Security;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
using System.Runtime.Versioning;
namespace mRemoteNG.Config.Connections
{
[SupportedOSPlatform("windows")]
public class XmlConnectionsLoader : IConnectionsLoader
{
private readonly string _connectionFilePath;
@@ -25,15 +27,15 @@ namespace mRemoteNG.Config.Connections
public ConnectionTreeModel Load()
{
var dataProvider = new FileDataProvider(_connectionFilePath);
var xmlString = dataProvider.Load();
var deserializer = new XmlConnectionsDeserializer(PromptForPassword);
FileDataProvider dataProvider = new(_connectionFilePath);
string xmlString = dataProvider.Load();
XmlConnectionsDeserializer deserializer = new(PromptForPassword);
return deserializer.Deserialize(xmlString);
}
private Optional<SecureString> PromptForPassword()
{
var password = MiscTools.PasswordDialog(Path.GetFileName(_connectionFilePath), false);
Optional<SecureString> password = MiscTools.PasswordDialog(Path.GetFileName(_connectionFilePath), false);
return password;
}
}

View File

@@ -8,9 +8,11 @@ using mRemoteNG.Security.Factories;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNG.Properties;
using System.Runtime.Versioning;
namespace mRemoteNG.Config.Connections
{
[SupportedOSPlatform("windows")]
public class XmlConnectionsSaver : ISaver<ConnectionTreeModel>
{
private readonly string _connectionFileName;
@@ -20,30 +22,23 @@ namespace mRemoteNG.Config.Connections
{
if (string.IsNullOrEmpty(connectionFileName))
throw new ArgumentException($"Argument '{nameof(connectionFileName)}' cannot be null or empty");
if (saveFilter == null)
throw new ArgumentNullException(nameof(saveFilter));
_connectionFileName = connectionFileName;
_saveFilter = saveFilter;
_saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
}
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
{
try
{
var cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
var serializerFactory = new XmlConnectionSerializerFactory();
var xmlConnectionsSerializer = serializerFactory.Build(
cryptographyProvider,
connectionTreeModel,
_saveFilter,
Properties.OptionsSecurityPage.Default.EncryptCompleteConnectionsFile);
ICryptographyProvider cryptographyProvider = new CryptoProviderFactoryFromSettings().Build();
XmlConnectionSerializerFactory serializerFactory = new();
var rootNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
var xml = xmlConnectionsSerializer.Serialize(rootNode);
Serializers.ISerializer<Connection.ConnectionInfo, string> xmlConnectionsSerializer = serializerFactory.Build(cryptographyProvider, connectionTreeModel, _saveFilter, Properties.OptionsSecurityPage.Default.EncryptCompleteConnectionsFile);
var fileDataProvider = new FileDataProviderWithRollingBackup(_connectionFileName);
RootNodeInfo rootNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
string xml = xmlConnectionsSerializer.Serialize(rootNode);
FileDataProviderWithRollingBackup fileDataProvider = new(_connectionFileName);
fileDataProvider.Save(xml);
}
catch (Exception ex)

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using System.Security;
using System.Xml.Linq;
using mRemoteNG.Credential;
@@ -9,25 +10,26 @@ using mRemoteNG.Security.Factories;
namespace mRemoteNG.Config
{
[SupportedOSPlatform("windows")]
public class CredentialHarvester
{
private readonly IEqualityComparer<ICredentialRecord> _credentialComparer = new CredentialDomainUserComparer();
// maps a connectioninfo (by its id) to the credential object that was harvested
public Dictionary<Guid, ICredentialRecord> ConnectionToCredentialMap { get; } =
new Dictionary<Guid, ICredentialRecord>();
[];
public IEnumerable<ICredentialRecord> Harvest(XDocument xDocument, SecureString decryptionKey)
{
if (xDocument == null)
throw new ArgumentNullException(nameof(xDocument));
var cryptoProvider = new CryptoProviderFactoryFromXml(xDocument.Root).Build();
ICryptographyProvider cryptoProvider = new CryptoProviderFactoryFromXml(xDocument.Root).Build();
foreach (var element in xDocument.Descendants("Node"))
foreach (XElement element in xDocument.Descendants("Node"))
{
if (!EntryHasSomeCredentialData(element)) continue;
var newCredential = BuildCredential(element, cryptoProvider, decryptionKey);
ICredentialRecord newCredential = BuildCredential(element, cryptoProvider, decryptionKey);
Guid connectionId;
Guid.TryParse(element.Attribute("Id")?.Value, out connectionId);
@@ -38,9 +40,7 @@ namespace mRemoteNG.Config
if (ConnectionToCredentialMap.Values.Contains(newCredential, _credentialComparer))
{
var existingCredential =
ConnectionToCredentialMap.Values.First(record =>
_credentialComparer.Equals(newCredential, record));
ICredentialRecord existingCredential = ConnectionToCredentialMap.Values.First(record => _credentialComparer.Equals(newCredential, record));
ConnectionToCredentialMap.Add(connectionId, existingCredential);
}
else
@@ -50,17 +50,14 @@ namespace mRemoteNG.Config
return ConnectionToCredentialMap.Values.Distinct(_credentialComparer);
}
private ICredentialRecord BuildCredential(XElement element,
ICryptographyProvider cryptographyProvider,
SecureString decryptionKey)
private ICredentialRecord BuildCredential(XElement element, ICryptographyProvider cryptographyProvider, SecureString decryptionKey)
{
var credential = new CredentialRecord
CredentialRecord credential = new()
{
Title = $"{element.Attribute("Username")?.Value}\\{element.Attribute("Domain")?.Value}",
Username = element.Attribute("Username")?.Value,
Domain = element.Attribute("Domain")?.Value,
Password = cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey)
.ConvertToSecureString()
Password = cryptographyProvider.Decrypt(element.Attribute("Password")?.Value, decryptionKey).ConvertToSecureString()
};
return credential;
}

View File

@@ -27,7 +27,7 @@ namespace mRemoteNG.Config
public IEnumerable<ICredentialRecord> Load(SecureString key)
{
var serializedCredentials = _dataProvider.Load();
string serializedCredentials = _dataProvider.Load();
return _deserializer.Deserialize(serializedCredentials, key);
}
}

View File

@@ -13,8 +13,7 @@ namespace mRemoteNG.Config
private readonly IDataProvider<string> _dataProvider;
private readonly ISecureSerializer<IEnumerable<ICredentialRecord>, string> _serializer;
public CredentialRecordSaver(IDataProvider<string> dataProvider,
ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer)
public CredentialRecordSaver(IDataProvider<string> dataProvider, ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer)
{
if (dataProvider == null)
throw new ArgumentNullException(nameof(dataProvider));
@@ -27,7 +26,7 @@ namespace mRemoteNG.Config
public void Save(IEnumerable<ICredentialRecord> credentialRecords, SecureString key)
{
var serializedCredentials = _serializer.Serialize(credentialRecords, key);
string serializedCredentials = _serializer.Serialize(credentialRecords, key);
_dataProvider.Save(serializedCredentials);
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
using mRemoteNG.Credential;
@@ -11,8 +12,7 @@ namespace mRemoteNG.Config
private readonly IDataProvider<string> _dataProvider;
private readonly CredentialRepositoryListDeserializer _deserializer;
public CredentialRepositoryListLoader(IDataProvider<string> dataProvider,
CredentialRepositoryListDeserializer deserializer)
public CredentialRepositoryListLoader(IDataProvider<string> dataProvider, CredentialRepositoryListDeserializer deserializer)
{
if (dataProvider == null)
throw new ArgumentNullException(nameof(dataProvider));
@@ -23,9 +23,10 @@ namespace mRemoteNG.Config
_deserializer = deserializer;
}
[SupportedOSPlatform("windows")]
public IEnumerable<ICredentialRepository> Load()
{
var data = _dataProvider.Load();
string data = _dataProvider.Load();
return _deserializer.Deserialize(data);
}
}

View File

@@ -20,8 +20,8 @@ namespace mRemoteNG.Config
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
{
var serializer = new CredentialRepositoryListSerializer();
var data = serializer.Serialize(repositories);
CredentialRepositoryListSerializer serializer = new();
string data = serializer.Serialize(repositories);
_dataProvider.Save(data);
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Runtime.Versioning;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Resources.Language;
@@ -8,6 +9,7 @@ namespace mRemoteNG.Config.DataProviders
{
public class FileBackupCreator
{
[SupportedOSPlatform("windows")]
public void CreateBackupFile(string fileName)
{
try
@@ -15,7 +17,7 @@ namespace mRemoteNG.Config.DataProviders
if (WeDontNeedToBackup(fileName))
return;
var backupFileName =
string backupFileName =
string.Format(Properties.OptionsBackupPage.Default.BackupFileNameFormat, fileName, DateTime.Now);
File.Copy(fileName, backupFileName);
}

View File

@@ -7,23 +7,23 @@ namespace mRemoteNG.Config.DataProviders
{
public void PruneBackupFiles(string filePath, int maxBackupsToKeep)
{
var fileName = Path.GetFileName(filePath);
var directoryName = Path.GetDirectoryName(filePath);
string fileName = Path.GetFileName(filePath);
string directoryName = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName))
return;
var searchPattern = string.Format(Properties.OptionsBackupPage.Default.BackupFileNameFormat, fileName, "*");
var files = Directory.GetFiles(directoryName, searchPattern);
string searchPattern = string.Format(Properties.OptionsBackupPage.Default.BackupFileNameFormat, fileName, "*");
string[] files = Directory.GetFiles(directoryName, searchPattern);
if (files.Length <= maxBackupsToKeep)
return;
var filesToDelete = files
System.Collections.Generic.IEnumerable<string> filesToDelete = files
.OrderByDescending(s => s)
.Skip(maxBackupsToKeep);
foreach (var file in filesToDelete)
foreach (string file in filesToDelete)
{
File.Delete(file);
}

View File

@@ -1,11 +1,14 @@
using System;
using System.IO;
using System.Runtime.Versioning;
using mRemoteNG.App;
namespace mRemoteNG.Config.DataProviders
{
[SupportedOSPlatform("windows")]
public class FileDataProvider : IDataProvider<string>
{
[SupportedOSPlatform("windows")]
public string FilePath { get; set; }
public FileDataProvider(string filePath)
@@ -15,9 +18,14 @@ namespace mRemoteNG.Config.DataProviders
public virtual string Load()
{
var fileContents = "";
string fileContents = "";
try
{
if (!File.Exists(FilePath))
{
CreateMissingDirectories();
File.WriteAllLines(FilePath, new []{ $@"<?xml version=""1.0"" encoding=""UTF-8""?>", $@"<LocalConnections/>" });
}
fileContents = File.ReadAllText(FilePath);
}
catch (FileNotFoundException ex)
@@ -62,7 +70,7 @@ namespace mRemoteNG.Config.DataProviders
private void CreateMissingDirectories()
{
var dirname = Path.GetDirectoryName(FilePath);
string dirname = Path.GetDirectoryName(FilePath);
if (dirname == null) return;
Directory.CreateDirectory(dirname);
}

View File

@@ -1,5 +1,8 @@
namespace mRemoteNG.Config.DataProviders
using System.Runtime.Versioning;
namespace mRemoteNG.Config.DataProviders
{
[SupportedOSPlatform("windows")]
public class FileDataProviderWithRollingBackup : FileDataProvider
{
private readonly FileBackupCreator _fileBackupCreator;

View File

@@ -2,12 +2,13 @@
using mRemoteNG.Config.DatabaseConnectors;
using mRemoteNG.Messages;
using mRemoteNG.App;
using mRemoteNG.Properties;
using MySql.Data.MySqlClient;
using System.Data.SqlClient;
using System.Runtime.Versioning;
namespace mRemoteNG.Config.DataProviders
{
[SupportedOSPlatform("windows")]
public class SqlDataProvider : IDataProvider<DataTable>
{
public IDatabaseConnector DatabaseConnector { get; }
@@ -19,12 +20,12 @@ namespace mRemoteNG.Config.DataProviders
public DataTable Load()
{
var dataTable = new DataTable();
var dbQuery = DatabaseConnector.DbCommand("SELECT * FROM tblCons ORDER BY PositionID ASC");
DataTable dataTable = new();
System.Data.Common.DbCommand dbQuery = DatabaseConnector.DbCommand("SELECT * FROM tblCons ORDER BY PositionID ASC");
DatabaseConnector.AssociateItemToThisConnector(dbQuery);
if (!DatabaseConnector.IsConnected)
OpenConnection();
var dbDataReader = dbQuery.ExecuteReader(CommandBehavior.CloseConnection);
System.Data.Common.DbDataReader dbDataReader = dbQuery.ExecuteReader(CommandBehavior.CloseConnection);
if (dbDataReader.HasRows)
dataTable.Load(dbDataReader);
@@ -36,8 +37,7 @@ namespace mRemoteNG.Config.DataProviders
{
if (DbUserIsReadOnly())
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
"Trying to save connections but the SQL read only checkbox is checked, aborting!");
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to save connections but the SQL read only checkbox is checked, aborting!");
return;
}
@@ -46,54 +46,39 @@ namespace mRemoteNG.Config.DataProviders
if (DatabaseConnector.GetType() == typeof(MSSqlDatabaseConnector))
{
SqlConnection sqlConnection = (SqlConnection)DatabaseConnector.DbConnection();
using (SqlTransaction transaction = sqlConnection.BeginTransaction(System.Data.IsolationLevel.Serializable))
using SqlTransaction transaction = sqlConnection.BeginTransaction(System.Data.IsolationLevel.Serializable);
using SqlCommand sqlCommand = new();
sqlCommand.Connection = sqlConnection;
sqlCommand.Transaction = transaction;
sqlCommand.CommandText = "SELECT * FROM tblCons";
using SqlDataAdapter dataAdapter = new();
dataAdapter.SelectCommand = sqlCommand;
SqlCommandBuilder builder = new(dataAdapter)
{
using (SqlCommand sqlCommand = new SqlCommand())
{
sqlCommand.Connection = sqlConnection;
sqlCommand.Transaction = transaction;
sqlCommand.CommandText = "SELECT * FROM tblCons";
using (SqlDataAdapter dataAdpater = new SqlDataAdapter())
{
dataAdpater.SelectCommand = sqlCommand;
SqlCommandBuilder builder = new SqlCommandBuilder(dataAdpater);
// Avoid optimistic concurrency, check if it is necessary.
builder.ConflictOption = ConflictOption.OverwriteChanges;
dataAdpater.UpdateCommand = builder.GetUpdateCommand();
dataAdpater.DeleteCommand = builder.GetDeleteCommand();
dataAdpater.InsertCommand = builder.GetInsertCommand();
dataAdpater.Update(dataTable);
transaction.Commit();
}
}
}
// Avoid optimistic concurrency, check if it is necessary.
ConflictOption = ConflictOption.OverwriteChanges
};
dataAdapter.UpdateCommand = builder.GetUpdateCommand();
dataAdapter.DeleteCommand = builder.GetDeleteCommand();
dataAdapter.InsertCommand = builder.GetInsertCommand();
dataAdapter.Update(dataTable);
transaction.Commit();
}
else if (DatabaseConnector.GetType() == typeof(MySqlDatabaseConnector))
{
var dbConnection = (MySqlConnection) DatabaseConnector.DbConnection();
using (MySqlTransaction transaction = dbConnection.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
using (MySqlCommand sqlCommand = new MySqlCommand())
{
sqlCommand.Connection = dbConnection;
sqlCommand.Transaction = transaction;
sqlCommand.CommandText = "SELECT * FROM tblCons";
using (MySqlDataAdapter dataAdapter = new MySqlDataAdapter(sqlCommand))
{
dataAdapter.UpdateBatchSize = 1000;
using (MySqlCommandBuilder cb = new MySqlCommandBuilder(dataAdapter))
{
dataAdapter.Update(dataTable);
transaction.Commit();
}
}
}
}
MySqlConnection dbConnection = (MySqlConnection) DatabaseConnector.DbConnection();
using MySqlTransaction transaction = dbConnection.BeginTransaction(System.Data.IsolationLevel.Serializable);
using MySqlCommand sqlCommand = new();
sqlCommand.Connection = dbConnection;
sqlCommand.Transaction = transaction;
sqlCommand.CommandText = "SELECT * FROM tblCons";
using MySqlDataAdapter dataAdapter = new(sqlCommand);
dataAdapter.UpdateBatchSize = 1000;
using MySqlCommandBuilder cb = new(dataAdapter);
dataAdapter.Update(dataTable);
transaction.Commit();
}
}

View File

@@ -1,9 +1,11 @@
using System;
using System.Data.SqlClient;
using System.Runtime.Versioning;
using System.Threading.Tasks;
namespace mRemoteNG.Config.DatabaseConnectors
{
[SupportedOSPlatform("windows")]
/// <summary>
/// A helper class for testing database connectivity
/// </summary>
@@ -15,7 +17,7 @@ namespace mRemoteNG.Config.DatabaseConnectors
string username,
string password)
{
using (var dbConnector = DatabaseConnectorFactory.DatabaseConnector(type, server, database, username, password))
using (IDatabaseConnector dbConnector = DatabaseConnectorFactory.DatabaseConnector(type, server, database, username, password))
{
try
{

View File

@@ -1,19 +1,21 @@
using mRemoteNG.App;
using mRemoteNG.Properties;
using mRemoteNG.Security.SymmetricEncryption;
using System.Runtime.Versioning;
namespace mRemoteNG.Config.DatabaseConnectors
{
public class DatabaseConnectorFactory
[SupportedOSPlatform("windows")]
public static class DatabaseConnectorFactory
{
public static IDatabaseConnector DatabaseConnectorFromSettings()
{
var sqlType = Properties.OptionsDBsPage.Default.SQLServerType;
var sqlHost = Properties.OptionsDBsPage.Default.SQLHost;
var sqlCatalog = Properties.OptionsDBsPage.Default.SQLDatabaseName;
var sqlUsername = Properties.OptionsDBsPage.Default.SQLUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
var sqlPassword = cryptographyProvider.Decrypt(Properties.OptionsDBsPage.Default.SQLPass, Runtime.EncryptionKey);
// TODO: add custom port handling?
string sqlType = Properties.OptionsDBsPage.Default.SQLServerType;
string sqlHost = Properties.OptionsDBsPage.Default.SQLHost;
string sqlCatalog = Properties.OptionsDBsPage.Default.SQLDatabaseName;
string sqlUsername = Properties.OptionsDBsPage.Default.SQLUser;
LegacyRijndaelCryptographyProvider cryptographyProvider = new();
string sqlPassword = cryptographyProvider.Decrypt(Properties.OptionsDBsPage.Default.SQLPass, Runtime.EncryptionKey);
return DatabaseConnector(sqlType, sqlHost, sqlCatalog, sqlUsername, sqlPassword);
}

View File

@@ -54,7 +54,7 @@ namespace mRemoteNG.Config.DatabaseConnectors
private void BuildDbConnectionStringWithCustomCredentials()
{
string[] hostParts = _dbHost.Split(new char[] { ':' }, 2);
var _dbPort = (hostParts.Length == 2) ? hostParts[1] : "1433";
string _dbPort = (hostParts.Length == 2) ? hostParts[1] : "1433";
_dbConnectionString = new SqlConnectionStringBuilder
{

View File

@@ -31,6 +31,7 @@ namespace mRemoteNG.Config.DatabaseConnectors
public MySqlDatabaseConnector(string host, string database, string username, string password)
{
// TODO: add custom port handling?
string[] hostParts = host.Split(new char[]{':'}, 2);
_dbHost = hostParts[0];
_dbPort = (hostParts.Length == 2)?hostParts[1]:"3306";
@@ -48,9 +49,9 @@ namespace mRemoteNG.Config.DatabaseConnectors
private void BuildSqlConnectionString()
{
_dbConnectionString = $"server={_dbHost};user={_dbUsername};database={_dbName};port={_dbPort};password={_dbPassword}";
_dbConnectionString = $"server={_dbHost};user={_dbUsername};database={_dbName};port={_dbPort};password={_dbPassword};";
}
public void Connect()
{
_dbConnection.Open();

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.App;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Container;
@@ -7,6 +8,7 @@ using mRemoteNG.Tools;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
public class ActiveDirectoryImporter : IConnectionImporter<string>
{
public void Import(string ldapPath, ContainerInfo destinationContainer)
@@ -19,11 +21,11 @@ namespace mRemoteNG.Config.Import
try
{
ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath));
var deserializer = new ActiveDirectoryDeserializer(ldapPath, importSubOu);
var connectionTreeModel = deserializer.Deserialize();
var importedRootNode = connectionTreeModel.RootNodes.First();
ActiveDirectoryDeserializer deserializer = new(ldapPath, importSubOu);
Tree.ConnectionTreeModel connectionTreeModel = deserializer.Deserialize();
ContainerInfo importedRootNode = connectionTreeModel.RootNodes.First();
if (importedRootNode == null) return;
var childrenToAdd = importedRootNode.Children.ToArray();
Connection.ConnectionInfo[] childrenToAdd = importedRootNode.Children.ToArray();
destinationContainer.AddChildRange(childrenToAdd);
}
catch (Exception ex)

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Csv;
@@ -8,6 +9,7 @@ using mRemoteNG.Messages;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
public class MRemoteNGCsvImporter : IConnectionImporter<string>
{
public void Import(string filePath, ContainerInfo destinationContainer)
@@ -22,12 +24,12 @@ namespace mRemoteNG.Config.Import
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
$"Unable to import file. File does not exist. Path: {filePath}");
var dataProvider = new FileDataProvider(filePath);
var xmlString = dataProvider.Load();
var xmlConnectionsDeserializer = new CsvConnectionsDeserializerMremotengFormat();
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString);
FileDataProvider dataProvider = new(filePath);
string xmlString = dataProvider.Load();
CsvConnectionsDeserializerMremotengFormat xmlConnectionsDeserializer = new();
Tree.ConnectionTreeModel connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString);
var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(filePath)};
ContainerInfo rootImportContainer = new() { Name = Path.GetFileNameWithoutExtension(filePath)};
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
destinationContainer.AddChild(rootImportContainer);
}

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
@@ -9,6 +10,7 @@ using mRemoteNG.Messages;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
// ReSharper disable once InconsistentNaming
public class MRemoteNGXmlImporter : IConnectionImporter<string>
{
@@ -24,12 +26,12 @@ namespace mRemoteNG.Config.Import
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
$"Unable to import file. File does not exist. Path: {fileName}");
var dataProvider = new FileDataProvider(fileName);
var xmlString = dataProvider.Load();
var xmlConnectionsDeserializer = new XmlConnectionsDeserializer();
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true);
FileDataProvider dataProvider = new(fileName);
string xmlString = dataProvider.Load();
XmlConnectionsDeserializer xmlConnectionsDeserializer = new();
Tree.ConnectionTreeModel connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true);
var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(fileName)};
ContainerInfo rootImportContainer = new() { Name = Path.GetFileNameWithoutExtension(fileName)};
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
destinationContainer.AddChild(rootImportContainer);
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Container;
@@ -8,6 +9,7 @@ using mRemoteNG.Tools;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
public class PortScanImporter : IConnectionImporter<IEnumerable<ScanHost>>
{
private readonly ProtocolType _targetProtocolType;
@@ -19,12 +21,12 @@ namespace mRemoteNG.Config.Import
public void Import(IEnumerable<ScanHost> hosts, ContainerInfo destinationContainer)
{
var deserializer = new PortScanDeserializer(_targetProtocolType);
var connectionTreeModel = deserializer.Deserialize(hosts);
PortScanDeserializer deserializer = new(_targetProtocolType);
Tree.ConnectionTreeModel connectionTreeModel = deserializer.Deserialize(hosts);
var importedRootNode = connectionTreeModel.RootNodes.First();
ContainerInfo importedRootNode = connectionTreeModel.RootNodes.First();
if (importedRootNode == null) return;
var childrenToAdd = importedRootNode.Children.ToArray();
Connection.ConnectionInfo[] childrenToAdd = importedRootNode.Children.ToArray();
destinationContainer.AddChildRange(childrenToAdd);
}
}

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Container;
@@ -6,19 +7,20 @@ using mRemoteNG.Container;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
public class PuttyConnectionManagerImporter : IConnectionImporter<string>
{
public void Import(string filePath, ContainerInfo destinationContainer)
{
var dataProvider = new FileDataProvider(filePath);
var xmlContent = dataProvider.Load();
FileDataProvider dataProvider = new(filePath);
string xmlContent = dataProvider.Load();
var deserializer = new PuttyConnectionManagerDeserializer();
var connectionTreeModel = deserializer.Deserialize(xmlContent);
PuttyConnectionManagerDeserializer deserializer = new();
Tree.ConnectionTreeModel connectionTreeModel = deserializer.Deserialize(xmlContent);
var importedRootNode = connectionTreeModel.RootNodes.First();
ContainerInfo importedRootNode = connectionTreeModel.RootNodes.First();
if (importedRootNode == null) return;
var childrenToAdd = importedRootNode.Children.ToArray();
Connection.ConnectionInfo[] childrenToAdd = importedRootNode.Children.ToArray();
destinationContainer.AddChildRange(childrenToAdd);
}
}

View File

@@ -0,0 +1,83 @@
using System;
using System.Runtime.Versioning;
using Microsoft.Win32;
using mRemoteNG.App;
using mRemoteNG.Container;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
internal class RegistryImporter : IConnectionImporter<string>
{
public void Import(string regPath, ContainerInfo destinationContainer)
{
Import(regPath, destinationContainer, false);
}
public static void Import(string regPath, ContainerInfo destinationContainer, bool noop = false)
{
try
{
ContainerInfo importedNode = new()
{
Name = "Imported from PuTTY",
IsContainer = true
};
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(regPath))
{
if (key != null)
{
foreach (string sub in key.GetSubKeyNames())
{
if (sub.EndsWith("Default%20Settings")) continue;
using RegistryKey subkey = key.OpenSubKey(sub);
string Hostname = subkey.GetValue("HostName") as string;
string connName = subkey.Name[(key.Name.Length + 1)..];
if (!string.IsNullOrEmpty(Hostname))
{
int Port = 22;
string Username = string.Empty;
string ProtocolType = subkey.GetValue("Protocol") as string;
Connection.Protocol.ProtocolType Protocol = Connection.Protocol.ProtocolType.SSH2;
if (ProtocolType == "raw")
{
Protocol = Connection.Protocol.ProtocolType.RAW;
}
try
{
Port = int.Parse(subkey.GetValue("PortNumber") as string);
}
catch { }
try
{
Username = subkey.GetValue("UserName") as string;
}
catch { }
importedNode.AddChild(new Connection.ConnectionInfo()
{
Name = connName,
Hostname = Hostname,
Port = Port == 0 ? 22 : Port,
Protocol = Protocol,
Parent = destinationContainer,
Username = string.IsNullOrEmpty(Username) ? string.Empty : Username
});
}
}
}
}
destinationContainer.AddChild(importedNode);
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("Config.Import.Registry.Import() failed.", ex);
}
}
}
}

View File

@@ -1,5 +1,6 @@
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Container;
@@ -7,17 +8,18 @@ using mRemoteNG.Container;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
public class RemoteDesktopConnectionImporter : IConnectionImporter<string>
{
public void Import(string fileName, ContainerInfo destinationContainer)
{
var dataProvider = new FileDataProvider(fileName);
var content = dataProvider.Load();
FileDataProvider dataProvider = new(fileName);
string content = dataProvider.Load();
var deserializer = new RemoteDesktopConnectionDeserializer();
var connectionTreeModel = deserializer.Deserialize(content);
RemoteDesktopConnectionDeserializer deserializer = new();
Tree.ConnectionTreeModel connectionTreeModel = deserializer.Deserialize(content);
var importedConnection = connectionTreeModel.RootNodes.First().Children.First();
Connection.ConnectionInfo importedConnection = connectionTreeModel.RootNodes.First().Children.First();
if (importedConnection == null) return;
importedConnection.Name = Path.GetFileNameWithoutExtension(fileName);

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System.Runtime.Versioning;
using mRemoteNG.Config.DataProviders;
using mRemoteNG.Config.Serializers.MiscSerializers;
using mRemoteNG.Container;
@@ -6,19 +7,20 @@ using mRemoteNG.Container;
namespace mRemoteNG.Config.Import
{
[SupportedOSPlatform("windows")]
public class RemoteDesktopConnectionManagerImporter : IConnectionImporter<string>
{
public void Import(string filePath, ContainerInfo destinationContainer)
{
var dataProvider = new FileDataProvider(filePath);
var fileContent = dataProvider.Load();
FileDataProvider dataProvider = new(filePath);
string fileContent = dataProvider.Load();
var deserializer = new RemoteDesktopConnectionManagerDeserializer();
var connectionTreeModel = deserializer.Deserialize(fileContent);
RemoteDesktopConnectionManagerDeserializer deserializer = new();
Tree.ConnectionTreeModel connectionTreeModel = deserializer.Deserialize(fileContent);
var importedRootNode = connectionTreeModel.RootNodes.First();
ContainerInfo importedRootNode = connectionTreeModel.RootNodes.First();
if (importedRootNode == null) return;
var childrenToAdd = importedRootNode.Children.ToArray();
Connection.ConnectionInfo[] childrenToAdd = importedRootNode.Children.ToArray();
destinationContainer.AddChildRange(childrenToAdd);
}
}

View File

@@ -1,6 +1,7 @@
#region
using System.IO;
using System.Runtime.Versioning;
using Castle.Core.Internal;
using mRemoteNG.App;
using mRemoteNG.Config.DataProviders;
@@ -10,38 +11,39 @@ using mRemoteNG.Messages;
#endregion
namespace mRemoteNG.Config.Import;
public class RemoteDesktopManagerImporter : IConnectionImporter<string>
namespace mRemoteNG.Config.Import
{
public void Import(string filePath, ContainerInfo destinationContainer)
[SupportedOSPlatform("windows")]
public class RemoteDesktopManagerImporter : IConnectionImporter<string>
{
if (string.IsNullOrEmpty(filePath))
public void Import(string filePath, ContainerInfo destinationContainer)
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Unable to import file. File path is null.");
return;
}
if (string.IsNullOrEmpty(filePath))
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File path is null.");
return;
}
if (!File.Exists(filePath))
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg,
$"Unable to import file. File does not exist. Path: {filePath}");
if (!File.Exists(filePath))
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Unable to import file. File does not exist. Path: {filePath}");
var dataProvider = new FileDataProvider(filePath);
var csvString = dataProvider.Load();
FileDataProvider dataProvider = new(filePath);
string csvString = dataProvider.Load();
if (string.IsNullOrEmpty(csvString))
{
var csvDeserializer = new CsvConnectionsDeserializerRdmFormat();
var connectionTreeModel = csvDeserializer.Deserialize(csvString);
if (!string.IsNullOrEmpty(csvString))
{
CsvConnectionsDeserializerRdmFormat csvDeserializer = new();
Tree.ConnectionTreeModel connectionTreeModel = csvDeserializer.Deserialize(csvString);
var rootContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(filePath) };
rootContainer.AddChildRange(connectionTreeModel.RootNodes);
destinationContainer.AddChild(rootContainer);
}
else
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Unable to import file. File is empty.");
return;
ContainerInfo rootContainer = new() { Name = Path.GetFileNameWithoutExtension(filePath) };
rootContainer.AddChildRange(connectionTreeModel.RootNodes);
destinationContainer.AddChild(rootContainer);
}
else
{
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, "Unable to import file. File is empty.");
return;
}
}
}
}

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