mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-19 15:19:20 +08:00
Compare commits
222 Commits
v1.76Alpha
...
release/v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8077149b9 | ||
|
|
51514d78e6 | ||
|
|
42f60b0db3 | ||
|
|
5aec72f164 | ||
|
|
068f5942e7 | ||
|
|
703cefaf19 | ||
|
|
ea1f72b8b7 | ||
|
|
993b6759cc | ||
|
|
15f23769d6 | ||
|
|
2d175fd575 | ||
|
|
bdeb4b4dcc | ||
|
|
bdfbb57504 | ||
|
|
6c89913bc6 | ||
|
|
efa72cb697 | ||
|
|
a31fec5fb9 | ||
|
|
ed81030976 | ||
|
|
54322ca949 | ||
|
|
738b159e95 | ||
|
|
e8f2e4f50c | ||
|
|
5cd201440e | ||
|
|
5c6c76b898 | ||
|
|
4847ce054b | ||
|
|
ec42fe7d7d | ||
|
|
07a20ed5ad | ||
|
|
08201b0f00 | ||
|
|
92416b4661 | ||
|
|
75e0b8f4c2 | ||
|
|
8d29ff2d61 | ||
|
|
eea79da1ae | ||
|
|
cb5447f86e | ||
|
|
8cb31ad524 | ||
|
|
6ca52a0db1 | ||
|
|
25e30672c8 | ||
|
|
abcab2aadf | ||
|
|
19bb8f7595 | ||
|
|
0427956e8b | ||
|
|
78bf40282a | ||
|
|
6c6a82f8e6 | ||
|
|
4b9cc7be08 | ||
|
|
dc2d6b8160 | ||
|
|
083456e33a | ||
|
|
80e43e8634 | ||
|
|
e99b8ed453 | ||
|
|
4aba36b756 | ||
|
|
2ebf654973 | ||
|
|
f560fb86d8 | ||
|
|
21e51c8455 | ||
|
|
3234896caf | ||
|
|
b00dd1c5f5 | ||
|
|
992a3f9d1c | ||
|
|
1c12b52ada | ||
|
|
722fe40899 | ||
|
|
b2e7ebf43d | ||
|
|
3ed8e768aa | ||
|
|
d362691389 | ||
|
|
4b7c54d5b5 | ||
|
|
ec80a5aa70 | ||
|
|
0c95f178ca | ||
|
|
e0405b15df | ||
|
|
e029f30acf | ||
|
|
44ed836b7c | ||
|
|
00401201d1 | ||
|
|
20f46bea61 | ||
|
|
a5d22d287c | ||
|
|
793095900b | ||
|
|
f10e54e47b | ||
|
|
704e0c1dc1 | ||
|
|
0c79a9acde | ||
|
|
ebfc2715e7 | ||
|
|
b0dbc9dc18 | ||
|
|
507cdf75a5 | ||
|
|
8f8492b0be | ||
|
|
457e715188 | ||
|
|
1724521ebf | ||
|
|
b0fb3596aa | ||
|
|
fb228d72b1 | ||
|
|
916361a3be | ||
|
|
408c40f699 | ||
|
|
4173f6d775 | ||
|
|
e6f3c22064 | ||
|
|
a013518eac | ||
|
|
9c88cacb3d | ||
|
|
d49bf04b15 | ||
|
|
1dbd5dc5bc | ||
|
|
c103706a54 | ||
|
|
b0a027df52 | ||
|
|
868641378a | ||
|
|
11baae3107 | ||
|
|
ed8125042e | ||
|
|
25b2655d0f | ||
|
|
145a264154 | ||
|
|
3e33170ae0 | ||
|
|
d18bf68f0e | ||
|
|
368917e108 | ||
|
|
cdea4c3911 | ||
|
|
b4b9b55bbf | ||
|
|
6092c63df4 | ||
|
|
fda5132184 | ||
|
|
6a9fb25a18 | ||
|
|
18d7344690 | ||
|
|
ba50cf20a0 | ||
|
|
7bd6e126e2 | ||
|
|
f7521c81d5 | ||
|
|
f483a2dc2f | ||
|
|
9769d5af06 | ||
|
|
0a2dc3563e | ||
|
|
e9f0157b2b | ||
|
|
e8e566fcdd | ||
|
|
72b7d22cef | ||
|
|
f79da476fd | ||
|
|
ef31b7844c | ||
|
|
f1ed1bf115 | ||
|
|
23ea028965 | ||
|
|
42046a614f | ||
|
|
36055f56e6 | ||
|
|
b693cb30fc | ||
|
|
20377d4ff5 | ||
|
|
570d732b0e | ||
|
|
d9d2b1de70 | ||
|
|
0a7eaaf36f | ||
|
|
36dd3e496d | ||
|
|
83fd914d7b | ||
|
|
281c6b13fa | ||
|
|
00b7b1221c | ||
|
|
56cbf0ff3f | ||
|
|
f852a4d341 | ||
|
|
7c8c7d482a | ||
|
|
9e95ae2cb0 | ||
|
|
0d2d935f17 | ||
|
|
eeb320a825 | ||
|
|
9452d4dbe3 | ||
|
|
03d2387cdd | ||
|
|
61b325ccb9 | ||
|
|
e57de9a4de | ||
|
|
96946f3a1e | ||
|
|
8cd6fb7ae2 | ||
|
|
a5afa90790 | ||
|
|
f634eb8d37 | ||
|
|
694b61a67b | ||
|
|
88f0d00a15 | ||
|
|
e31088fd2e | ||
|
|
1d7bb63710 | ||
|
|
af1ed5349f | ||
|
|
9dcf71dc31 | ||
|
|
8bf9af0ed8 | ||
|
|
aecfad5871 | ||
|
|
3edd155898 | ||
|
|
2c419c0b2e | ||
|
|
2fb67e7042 | ||
|
|
29483b2625 | ||
|
|
7fc59e79f3 | ||
|
|
79b3e21148 | ||
|
|
ee91117010 | ||
|
|
0548037ff3 | ||
|
|
46002632bb | ||
|
|
9659ac1611 | ||
|
|
bbc497e68d | ||
|
|
d7ec7574ad | ||
|
|
2f476d9e61 | ||
|
|
c74f37f0de | ||
|
|
d27a62cbfc | ||
|
|
8029e491a3 | ||
|
|
fe56268421 | ||
|
|
2db6fabbe9 | ||
|
|
035e89801a | ||
|
|
3bdcf655fd | ||
|
|
284755f298 | ||
|
|
ad5eed96e7 | ||
|
|
431c830ea0 | ||
|
|
da047427a5 | ||
|
|
69da1dca5f | ||
|
|
cc61501f63 | ||
|
|
4ced2d3392 | ||
|
|
7c72bfdf6b | ||
|
|
b8878e1458 | ||
|
|
abd40cec1b | ||
|
|
cc18da4f28 | ||
|
|
1a39039162 | ||
|
|
cf9dd72ea5 | ||
|
|
b7cdf81665 | ||
|
|
8497a05fd1 | ||
|
|
7db4eec45c | ||
|
|
cd822b545a | ||
|
|
e872581d3c | ||
|
|
defe9e094c | ||
|
|
5662735cb8 | ||
|
|
8646dce21b | ||
|
|
99a3eabbaf | ||
|
|
c57bd386f2 | ||
|
|
f2a52b03df | ||
|
|
860e1ccfaa | ||
|
|
49967b38d4 | ||
|
|
36038fff6d | ||
|
|
c5958954b0 | ||
|
|
d0d63016ca | ||
|
|
35f2484adf | ||
|
|
c2cf496ded | ||
|
|
8a172f02a9 | ||
|
|
f27935ea61 | ||
|
|
043df0aec3 | ||
|
|
63a2e18760 | ||
|
|
c3ced7ed03 | ||
|
|
f597e14b3d | ||
|
|
aff4ba9115 | ||
|
|
554e0805e3 | ||
|
|
f4efa74a23 | ||
|
|
ddc19587fa | ||
|
|
5f1232727e | ||
|
|
9c373e8f0a | ||
|
|
83942d788f | ||
|
|
73d6fec6f3 | ||
|
|
a37b5deaa1 | ||
|
|
3b9de847e7 | ||
|
|
924f1f1e48 | ||
|
|
7bdebbe25b | ||
|
|
8f46c25dc9 | ||
|
|
8bb4a03639 | ||
|
|
7b5bc5e057 | ||
|
|
35582a5e6a | ||
|
|
20340fd31f | ||
|
|
d6d7664b48 | ||
|
|
e5a34388ae |
38
.github/ISSUE_TEMPLATE.md
vendored
38
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,16 +1,30 @@
|
||||
<!--
|
||||
Only file GitHub issues for bugs and feature requests. All other topics will be closed.
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
Before opening an issue, please search for a duplicate or closed issue.
|
||||
Please provide as much detail as possible for us to fix your issue.
|
||||
-->
|
||||
## Expected Behavior
|
||||
<!--- If you're describing a bug, tell us what should happen -->
|
||||
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||
|
||||
<!-- Bug -->
|
||||
|Detail|Value|
|
||||
|--:|---|
|
||||
|Operating system | Windows 10 x64 |
|
||||
|mRemoteNG version| 1.75.7008 |
|
||||
## Current Behavior
|
||||
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||
|
||||
## Possible Solution
|
||||
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||
<!--- or ideas how to implement the addition or change -->
|
||||
|
||||
<!-- Feature Request -->
|
||||
<!-- If you file a feature request, please delete the bug section -->
|
||||
## Steps to Reproduce (for bugs)
|
||||
<!--- Provide an unambiguous set of steps to reproduce -->
|
||||
<!--- this bug. Include code to reproduce, if relevant -->
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many relevant details about the environment you experienced the bug in -->
|
||||
* Version used:
|
||||
* Operating System and version (e.g. Windows 10 1709 x64):
|
||||
|
||||
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
33
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,4 +1,29 @@
|
||||
<!--
|
||||
Please provide as much detail as possible with what your pull request does.
|
||||
Include a reference to a filed issue if it exists.
|
||||
-->
|
||||
<!--- Provide a general summary of your changes in the Title above -->
|
||||
|
||||
## Description
|
||||
<!--- Describe your changes in detail -->
|
||||
|
||||
## Motivation and Context
|
||||
<!--- Why is this change required? What problem does it solve? -->
|
||||
<!--- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
## How Has This Been Tested?
|
||||
<!--- Please describe in detail how you tested your changes. -->
|
||||
<!--- Include details of your testing environment, and the tests you ran to -->
|
||||
<!--- see how your change affects other areas of the code, etc. -->
|
||||
|
||||
## Screenshots (if appropriate):
|
||||
|
||||
## Types of changes
|
||||
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
|
||||
|
||||
## Checklist:
|
||||
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
|
||||
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
|
||||
- [ ] My code follows the code style of this project.
|
||||
- [ ] My change requires a change to the documentation.
|
||||
- [ ] I have updated the documentation accordingly.
|
||||
- [ ] I have read the **CONTRIBUTING** document.
|
||||
|
||||
172
CHANGELOG.TXT
172
CHANGELOG.TXT
@@ -1,3 +1,175 @@
|
||||
1.76.20 (2019-04-12):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1401: Connections corrupted when importing RDC Manager files that are missing certain fields
|
||||
|
||||
|
||||
1.76.19 (2019-04-04):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1374: Vertical Scroll Bar missing in PuTTYNG after 0.70.0.1 & 0.71 updates
|
||||
|
||||
|
||||
1.76.18 (2019-03-20):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1365: PuTTY window not centered after 0.71 update
|
||||
|
||||
|
||||
1.76.17 (2019-03-20):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1362: Updated PuTTYNG to 0.71
|
||||
|
||||
|
||||
1.76.16 (2019-03-14):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1347: Remote Desktop Gateway username field encrypted instead of password
|
||||
|
||||
|
||||
1.76.15 (2019-03-09):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1303: Exception on first connection with new SQL server database
|
||||
#1304: Resolved several issues with importing multiple RDP Manager v2.7 files
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
Importing multiple files now only causes 1 save event, rather than 1 per file imported.
|
||||
|
||||
|
||||
1.76.14 (2019-02-08):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#222: Allow FIPS to be enabled
|
||||
|
||||
|
||||
1.76.13 (2018-12-22):
|
||||
|
||||
Changes:
|
||||
--------
|
||||
#222: Pre-Release Test build for running on systems with FIPS Enabled
|
||||
|
||||
|
||||
1.76.12 (2018-11-08):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#1180: Allow saving certain connection properties locally when using database
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1181: Connections sometimes dont immediately load when switching to sql feature
|
||||
#1173: Fixed memory leak when loading connections multiple times
|
||||
#1168: Autohide Connection and Config tab won't open when ssh connection active
|
||||
#1134: Fixed issue where opening a connection opens same connection on other clients when using database feature
|
||||
#449: Encrypt passwords saved to database
|
||||
|
||||
|
||||
1.76.11 (2018-10-18):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1139: Feature "Reconnect to previously opened sessions" not working
|
||||
#1136: Putty window not maximized
|
||||
|
||||
|
||||
1.76.10 (2018-10-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1124: Enabling themes causes an exception
|
||||
|
||||
|
||||
1.76.9 (2018-10-07):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1117: Duplicate panel created when "Reconnect on Startup" and "Create Empty Panel" settings enabled
|
||||
#1115: Exception when changing from xml data storage to SQL
|
||||
#1110: Pressing Delete button during connection rename attempts to delete the connection instead of the text
|
||||
#1106: Inheritance does not work when parent has C# default type set
|
||||
#1092: Invalid Cast Exceptions loading default connectioninfo
|
||||
#1091: Minor themeing issues
|
||||
#853: Added some additional safety checks and logging to help address RDP crashes
|
||||
|
||||
|
||||
1.76.8 (2018-08-25):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1088: Delete and Launch buttons are not disabled when last external tool deleted
|
||||
#1087: 'Save connections after every edit' setting not honored
|
||||
#1082: Connections not given GUID if Id is empty in connection xml
|
||||
|
||||
|
||||
1.76.7 (2018-08-22):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1076: Wrong object selected when duplicating connection then switching between properties and inheritance in config window
|
||||
#1068: Fixed some toolbar positioning bugs
|
||||
|
||||
|
||||
1.76.6 (2018-08-03):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1062: Entering correct password when starting app does not load connections file
|
||||
|
||||
1.76.5 (2018-08-02):
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#1057: Hitting F2 with no connection node selected caused unhandled exception
|
||||
#1052: 'Switch to notification panel' feature does not always switch
|
||||
#1051: Tooltips always displayed regardless of 'Show description tooltips in connection tree' setting
|
||||
#1050: Config window retains access to previously selected node after loading new connections file
|
||||
#1045: Config window shows several incorrect properties for HTTPS connections
|
||||
#1040: Canceling "select panel" form does not cancel
|
||||
#1039: Set default theme when themes disabled
|
||||
#1038: Unable to add connection with active filter
|
||||
#1036: Exception when themes are active and options page closed on Connections then reopened
|
||||
#1034: Connection context menu not being translated
|
||||
#1030: Exception thrown if importing from port scan and no tree node is selected
|
||||
#1020: BackupFileKeepCount setting not limiting backup file count
|
||||
#1004: Duplicating root or PuTTy node through hotkey causes unhandled exception
|
||||
#1002: Disabling filtering without clearing keyword leaves filtered state
|
||||
#1001: Connection tree context menu hotkeys stop working and disappear in some cases
|
||||
#999: Some hotkeys stop working if File menu was called when PuTTy Saved Sessions was selected
|
||||
#998: Can sometimes add connection under PuTTY Sessions node
|
||||
#991: Error when deleting host in filtered view
|
||||
#971: Portable Settings now apply to any machine they are used on
|
||||
#961: Connections file overwritten if correct decryption password not provided
|
||||
#893: Removed unneeded files from build/package
|
||||
#868: if statement returned the same value
|
||||
#762: Increased button size to fit locaized text
|
||||
|
||||
|
||||
1.76.4 Alpha 6 (2018-06-03):
|
||||
|
||||
Features/Enhancements:
|
||||
----------------------
|
||||
#948: Fixed issue where many menu item translations were not being used
|
||||
#942: Improved Russian translation of several items
|
||||
#924: Notification for "No Host Specified" when clicking folders in quick-connect menu
|
||||
#902: Menu bar can once again be moved. View -> "Lock toolbar positions" now also locks the menu position
|
||||
Added option for creating an empty panel on startup
|
||||
|
||||
Fixes:
|
||||
------
|
||||
#938: Minor layout improvements on the Port Scan screen
|
||||
#916: Default properties were not being saved
|
||||
|
||||
|
||||
1.76.3 Alpha 5 (2018-03-14):
|
||||
|
||||
Fixes:
|
||||
|
||||
@@ -23,6 +23,8 @@ github.com/DamianBis
|
||||
github.com/pfjason
|
||||
github.com/sirLoaf
|
||||
github.com/Fyers
|
||||
Vladimir Semenov (github.com/sli-pro)
|
||||
Stephan (github.com/st-schuler)
|
||||
|
||||
|
||||
Past Contributors
|
||||
@@ -59,6 +61,8 @@ Lukas Plachy (github.com/rheingold)
|
||||
Gyuha Shin
|
||||
Stefan (github.com/polluks)
|
||||
github.com/emazv72
|
||||
Vladimir Semenov (github.com/sli-pro)
|
||||
Marco Sousa (github.com/marcomsousa)
|
||||
|
||||
|
||||
Included Source Code
|
||||
|
||||
8
Jenkinsfile
vendored
8
Jenkinsfile
vendored
@@ -1,8 +1,8 @@
|
||||
#!groovy
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
|
||||
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def reportGeneratorPath = "${jobDir}\\packages\\ReportGenerator.3.0.2\\tools\\ReportGenerator.exe"
|
||||
@@ -24,11 +24,11 @@ node('windows') {
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Normal)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
bat "\"${msBuild}\" /nologo /p:Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
bat "\"${msBuild}\" /nologo /p:Configuration=\"Debug Portable\";Platform=x86 \"${jobDir}\\mRemoteV1.sln\""
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Normal, w/coverage)') {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
node('windows') {
|
||||
def jobDir = pwd()
|
||||
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
|
||||
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
|
||||
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
|
||||
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions"
|
||||
def msBuild = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\MSBuild\\15.0\\Bin\\msbuild.exe"
|
||||
def nunitConsolePath = "${jobDir}\\packages\\NUnit.ConsoleRunner.3.7.0\\tools\\nunit3-console.exe"
|
||||
def openCoverPath = "${jobDir}\\packages\\OpenCover.4.6.519\\tools\\OpenCover.Console.exe"
|
||||
def testResultFilePrefix = "TestResult"
|
||||
def testResultFileNormal = "${testResultFilePrefix}_UnitTests_normal.xml"
|
||||
def testResultFilePortable = "${testResultFilePrefix}_UnitTests_portable.xml"
|
||||
def coverageReport = "code_coverage_report.xml"
|
||||
|
||||
|
||||
stage ('Clean output dir') {
|
||||
@@ -32,24 +36,24 @@ node('windows') {
|
||||
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) {
|
||||
withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
|
||||
stage ('Build mRemoteNG (Normal - MSI)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
|
||||
stage ('Build mRemoteNG (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
bat "\"${msBuild}\" /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
|
||||
archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Normal - MSI)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\""
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\""
|
||||
}
|
||||
stage ('Run Unit Tests (Normal - MSI)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release\\mRemoteNGTests.dll\" --result=${testResultFileNormal} --x86"
|
||||
}
|
||||
|
||||
stage ('Run Unit Tests (Portable)') {
|
||||
bat "\"${nunitConsolePath}\" \"${jobDir}\\mRemoteNGTests\\bin\\release portable\\mRemoteNGTests.dll\" --result=${testResultFilePortable} --x86"
|
||||
}
|
||||
|
||||
stage ('Generate UpdateCheck Files') {
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\""
|
||||
@@ -58,11 +62,10 @@ node('windows') {
|
||||
|
||||
stage ('Publish to GitHub') {
|
||||
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
|
||||
def zipPath = "${jobDir}\\Release\\*.zip"
|
||||
def msiPath = "${jobDir}\\Release\\*.msi"
|
||||
def releaseFolder = "${jobDir}\\Release"
|
||||
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell
|
||||
def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString()
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ZipFilePath \"${zipPath}\" -MsiFilePath \"${msiPath}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ReleaseFolderPath \"${releaseFolder}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
| ---------------|--------------|-----------|
|
||||
| Stable | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/master) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7012) |
|
||||
| Beta | | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75.7012) |
|
||||
| Development | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76Alpha4) |
|
||||
| Development | [](https://ci.appveyor.com/project/mremoteng/mremoteng/branch/develop) | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76Alpha5) |
|
||||
|
||||
mRemoteNG is the next generation of mRemote, a full-featured, multi-tab remote connections manager.
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (C) 1999-2016 Igor Pavlov.
|
||||
Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
7-Zip Extra files are under the GNU LGPL license.
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
7-Zip Extra history
|
||||
-------------------
|
||||
|
||||
This file contains only information about changes related to that package exclusively.
|
||||
The full history of changes is listed in history.txt in main 7-Zip program.
|
||||
|
||||
|
||||
18.05 2018-04-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased
|
||||
by 8% for fastest/fast compression levels and
|
||||
by 3% for normal/maximum compression levels.
|
||||
|
||||
|
||||
18.03 beta 2018-03-04
|
||||
-------------------------
|
||||
- The speed for single-thread LZMA/LZMA2 decoding
|
||||
was increased by 30% in x64 version and by 3% in x86 version.
|
||||
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
|
||||
if there are multiple independent data chunks in LZMA2 stream.
|
||||
|
||||
|
||||
9.35 beta 2014-12-07
|
||||
------------------------------
|
||||
- SFX modules were moved to LZMA SDK package.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
7-Zip Extra 16.02
|
||||
7-Zip Extra 18.05
|
||||
-----------------
|
||||
|
||||
7-Zip Extra is package of extra modules of 7-Zip.
|
||||
|
||||
7-Zip Copyright (C) 1999-2016 Igor Pavlov.
|
||||
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
||||
|
||||
7-Zip is free software. Read License.txt for more information about license.
|
||||
|
||||
|
||||
@@ -17,5 +17,7 @@ if (!(Test-Path -Path $DestinationDir))
|
||||
$sourceFiles = Get-ChildItem -Path $SourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
|
||||
foreach ($item in $sourceFiles)
|
||||
{
|
||||
$item.Name
|
||||
(Get-FileHash -Path $item.fullName -Algorithm SHA512).Hash
|
||||
Copy-Item -Path $item.FullName -Destination $DestinationDir -Force
|
||||
}
|
||||
@@ -171,13 +171,27 @@ function Upload-GitHubReleaseAsset {
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# The OAuth2 token to use for authentication.
|
||||
$AuthToken
|
||||
$AuthToken,
|
||||
|
||||
[string]
|
||||
# A short description label for the asset
|
||||
$Label = ""
|
||||
)
|
||||
|
||||
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$"
|
||||
$file = Get-Item -Path $FilePath
|
||||
$files = Get-Item -Path $FilePath
|
||||
|
||||
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
|
||||
$labelParam = ""
|
||||
if ($Label -ne "") {
|
||||
$labelParam = "&label=$Label"
|
||||
}
|
||||
|
||||
# Get-Item could produce an array of files if a wildcard is provided. (C:\*.txt)
|
||||
# Upload each matching item individually
|
||||
foreach ($file in $files) {
|
||||
Write-Output "Uploading asset to GitHub release: '$($file.FullName)'"
|
||||
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)$labelParam" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -46,4 +46,5 @@ Format-Table -AutoSize -Wrap -InputObject @{
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath
|
||||
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
@@ -43,13 +43,8 @@ param (
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
# Path to the zip file to upload with the release
|
||||
$ZipFilePath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
#Path to the msi file to upload with the release
|
||||
$MsiFilePath,
|
||||
# Path to the folder which contains release assets to upload
|
||||
$ReleaseFolderPath,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
@@ -70,7 +65,17 @@ if ($DescriptionIsBase64Encoded) {
|
||||
. "$PSScriptRoot\github_functions.ps1"
|
||||
|
||||
|
||||
$releaseFolderItems = Get-ChildItem -Path $ReleaseFolderPath
|
||||
$mrngPortablePath = ($releaseFolderItems | ?{$_.Name -match "portable-[\d\.]+\.zip"}).FullName
|
||||
$mrngNormalPath = ($releaseFolderItems | ?{$_.Name -match "installer-[\d\.]+\.msi"}).FullName
|
||||
$mrngPortableSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-portable-symbols-[\d\.]+\.zip"}).FullName
|
||||
$mrngNormalSymbolsPath = ($releaseFolderItems | ?{$_.Name -match "mremoteng-symbols-[\d\.]+\.zip"}).FullName
|
||||
|
||||
|
||||
$release = Publish-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken
|
||||
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken
|
||||
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken
|
||||
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortablePath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition (zip)"
|
||||
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalPath -ContentType "application/octet-stream" -AuthToken $AuthToken -Label "Normal Edition (msi)"
|
||||
|
||||
$portableEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngPortableSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Portable Edition Debug Symbols"
|
||||
$normalEditionSymbols = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $mrngNormalSymbolsPath -ContentType "application/zip" -AuthToken $AuthToken -Label "Normal Edition Debug Symbols"
|
||||
Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken)
|
||||
@@ -15,7 +15,6 @@ if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Removing unnecessary files from Release versions"
|
||||
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
|
||||
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
|
||||
"*.pdb",
|
||||
"*.publish",
|
||||
"*.xml",
|
||||
"*.backup",
|
||||
|
||||
@@ -13,13 +13,51 @@ param (
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
$path_packageZipScript = Join-Path -Path $SolutionDir -ChildPath "Tools\build-relport.cmd"
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") {
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
& $path_packageZipScript
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
$tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteV1\bin\package"
|
||||
Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item $tempFolderPath -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination $tempFolderPath
|
||||
|
||||
#Write-Output "$($SolutionDir)mRemoteV1\bin\$ConfigurationName"
|
||||
#Write-Output "$($SolutionDir)mRemoteV1\bin\package"
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force
|
||||
# Delete any PDB files that accidentally get copied into the temp folder
|
||||
Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*")
|
||||
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
|
||||
(Get-FileHash -Path $PortableZip -Algorithm SHA512).Hash
|
||||
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
|
||||
39
Tools/zip_portable_files_appv.ps1
Normal file
39
Tools/zip_portable_files_appv.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "NOT running via Appveyor - Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
$appvDir = $Env:APPVEYOR_BUILD_FOLDER
|
||||
|
||||
Write-Output "Appveyor Build Dir: '$($appvDir)'"
|
||||
$ConfigurationName = $Env:CONFIGURATION.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
Remove-Item -Recurse "$($SolutionDir)mRemoteV1\bin\package" -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item "$($SolutionDir)mRemoteV1\bin\package" -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" -Destination "$($SolutionDir)mRemoteV1\bin\package"
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteV1\bin\$ConfigurationName\*" -Destination "$($SolutionDir)mRemoteV1\bin\package" -Recurse -Force
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination "$($SolutionDir)mRemoteV1\bin\package"
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip "$($SolutionDir)mRemoteV1\bin\package\*.*"
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
56
Tools/zip_symbols.ps1
Normal file
56
Tools/zip_symbols.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Packaging debug symbols"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteV1\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
if ($ConfigurationName -match "Portable") {
|
||||
$zipFilePrefix = "mRemoteNG-Portable-symbols"
|
||||
} else {
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
}
|
||||
|
||||
$outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
|
||||
|
||||
Write-Output "Creating debug symbols ZIP file $($outputZipPath)"
|
||||
Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb")
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not package debug symbols - this isnt a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
12
appveyor.yml
12
appveyor.yml
@@ -1,10 +1,11 @@
|
||||
version: 1.0.{build}
|
||||
version: 1.76.{build}
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
image: Visual Studio 2017
|
||||
configuration:
|
||||
- Release
|
||||
- Release Portable
|
||||
- Release Installer
|
||||
platform: x86
|
||||
clone_depth: 1
|
||||
install:
|
||||
@@ -14,7 +15,14 @@ before_build:
|
||||
build:
|
||||
project: mRemoteV1.sln
|
||||
verbosity: normal
|
||||
after_build:
|
||||
- ps: "if([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {\n Write-Output \"NOT running via Appveyor - Exiting\"\n Exit\n}\n\n$appvDir = $Env:APPVEYOR_BUILD_FOLDER\n\nWrite-Output \"Appveyor Build Dir: '$($appvDir)'\"\n$ConfigurationName = $Env:CONFIGURATION.Trim()\nWrite-Output \"Config Name (tirmmed): '$($ConfigurationName)'\"\n\n\n$SIGCHECK=\"$($SolutionDir)Tools\\exes\\sigcheck.exe\"\n$SEVENZIP=\"$($SolutionDir)Tools\\7zip\\7za.exe\"\n\nif ($ConfigurationName -eq \"Release Portable\") {\n Write-Output \"Packaging Release Portable ZIP\"\n \n $version = & $SIGCHECK /accepteula -q -n \"$($SolutionDir)mRemoteV1\\bin\\$($ConfigurationName)\\mRemoteNG.exe\"\n\n Write-Output \"Version is $($version)\"\n\n $PortableZip=\"$($SolutionDir)Release\\mRemoteNG-Portable-$($version).zip\"\n\n Remove-Item -Recurse \"$($SolutionDir)mRemoteV1\\bin\\package\" -ErrorAction SilentlyContinue | Out-Null\n New-Item \"$($SolutionDir)mRemoteV1\\bin\\package\" -ItemType \"directory\" | Out-Null\n \n Copy-Item \"$($SolutionDir)mRemoteV1\\Resources\\PuTTYNG.exe\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Copy-Item \"$($SolutionDir)mRemoteV1\\bin\\$ConfigurationName\\*\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\" -Recurse -Force \n Copy-Item \"$($SolutionDir)*.txt\" -Destination \"$($SolutionDir)mRemoteV1\\bin\\package\"\n\n Write-Output \"Creating portable ZIP file $($PortableZip)\"\n Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue\n & $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip \"$($SolutionDir)mRemoteV1\\bin\\package\\*.*\"\n}\nelse {\n Write-Output \"We will not zip anything - this isnt a portable release build.\"\n}"
|
||||
test:
|
||||
assemblies:
|
||||
only:
|
||||
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
|
||||
- mRemoteNGTests\bin\$(configuration)\mRemoteNGTests.dll
|
||||
artifacts:
|
||||
- path: Release\*.msi
|
||||
name: mRemoteNG-installer.msi
|
||||
- path: Release\*.zip
|
||||
name: mRemoteNG-portable.zip
|
||||
47
mRemoteNGTests/App/ImportTests.cs
Normal file
47
mRemoteNGTests/App/ImportTests.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.IO;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNGTests.Properties;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.App
|
||||
{
|
||||
public class ImportTests
|
||||
{
|
||||
[Test]
|
||||
public void ErrorHandlerCalledWhenUnsupportedFileExtensionFound()
|
||||
{
|
||||
using (FileTestHelpers.DisposableTempFile(out var file, ".blah"))
|
||||
{
|
||||
var conService = new ConnectionsService(PuttySessionsManager.Instance);
|
||||
var container = new ContainerInfo();
|
||||
var exceptionOccurred = false;
|
||||
|
||||
Import.HeadlessFileImport(new []{file}, container, conService, s => exceptionOccurred = true);
|
||||
|
||||
Assert.That(exceptionOccurred);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AnErrorInOneFileDoNotPreventOtherFilesFromProcessing()
|
||||
{
|
||||
using (FileTestHelpers.DisposableTempFile(out var badFile, ".blah"))
|
||||
using (FileTestHelpers.DisposableTempFile(out var rdpFile, ".rdp"))
|
||||
{
|
||||
File.AppendAllText(rdpFile, Resources.test_remotedesktopconnection_rdp);
|
||||
var conService = new ConnectionsService(PuttySessionsManager.Instance);
|
||||
var container = new ContainerInfo();
|
||||
var exceptionCount = 0;
|
||||
|
||||
Import.HeadlessFileImport(new[] { badFile, rdpFile }, container, conService, s => exceptionCount++);
|
||||
|
||||
Assert.That(exceptionCount, Is.EqualTo(1));
|
||||
Assert.That(container.Children, Has.One.Items);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
@@ -19,7 +18,7 @@ namespace mRemoteNGTests.Config.Serializers.ConnectionSerializers.Xml
|
||||
|
||||
public void Setup(string confCons, string password)
|
||||
{
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(password.ConvertToSecureString);
|
||||
_xmlConnectionsDeserializer = new XmlConnectionsDeserializer(() => password.ConvertToSecureString());
|
||||
_connectionTreeModel = _xmlConnectionsDeserializer.Deserialize(confCons);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
@@ -12,30 +14,37 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public class DataTableDeserializerTests
|
||||
{
|
||||
private DataTableDeserializer _deserializer;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeATree()
|
||||
{
|
||||
var model = CreateConnectionTreeModel();
|
||||
var dataTable = CreateDataTable(model.RootNodes[0]);
|
||||
_deserializer = new DataTableDeserializer();
|
||||
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
|
||||
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(model.GetRecursiveChildList().Count));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WeCanDeserializeASingleEntry()
|
||||
{
|
||||
var dataTable = CreateDataTable(new ConnectionInfo());
|
||||
_deserializer = new DataTableDeserializer();
|
||||
_deserializer = new DataTableDeserializer(_cryptographyProvider, new SecureString());
|
||||
var output = _deserializer.Deserialize(dataTable);
|
||||
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
|
||||
Assert.That(output.GetRecursiveChildList().Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
private DataTable CreateDataTable(ConnectionInfo tableContent)
|
||||
{
|
||||
var serializer = new DataTableSerializer(new SaveFilter());
|
||||
var serializer = new DataTableSerializer(new SaveFilter(), _cryptographyProvider, new SecureString());
|
||||
return serializer.Serialize(tableContent);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers
|
||||
@@ -19,7 +23,10 @@ namespace mRemoteNGTests.Config.Serializers
|
||||
public void Setup()
|
||||
{
|
||||
_saveFilter = new SaveFilter();
|
||||
_dataTableSerializer = new DataTableSerializer(_saveFilter);
|
||||
_dataTableSerializer = new DataTableSerializer(
|
||||
_saveFilter,
|
||||
new LegacyRijndaelCryptographyProvider(),
|
||||
new SecureString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNGTests.Properties;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionManager27DeserializerTests
|
||||
public class RemoteDesktopConnectionManager27DeserializerTests
|
||||
{
|
||||
private string _connectionFileContents;
|
||||
private RemoteDesktopConnectionManagerDeserializer _deserializer;
|
||||
private ConnectionTreeModel _connectionTreeModel;
|
||||
private const string ExpectedName = "server1_displayname";
|
||||
private const string ExpectedHostname = "server1";
|
||||
private const string ExpectedDescription = "Comment text here";
|
||||
@@ -44,265 +45,80 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
{
|
||||
_connectionFileContents = Resources.test_rdcman_v2_7_schema3;
|
||||
_deserializer = new RemoteDesktopConnectionManagerDeserializer();
|
||||
_connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionTreeModelHasARootNode()
|
||||
{
|
||||
var numberOfRootNodes = _connectionTreeModel.RootNodes.Count;
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
var numberOfRootNodes = connectionTreeModel.RootNodes.Count;
|
||||
Assert.That(numberOfRootNodes, Is.GreaterThan(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RootNodeHasContents()
|
||||
{
|
||||
var rootNodeContents = _connectionTreeModel.RootNodes.First().Children;
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
var rootNodeContents = connectionTreeModel.RootNodes.First().Children;
|
||||
Assert.That(rootNodeContents, Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllSubRootFoldersImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
var rootNode = connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var rootNodeContents = importedRdcmanRootNode.Children.Count(node => node.Name == "Group1" || node.Name == "Group2");
|
||||
Assert.That(rootNodeContents, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDisplayNameImported()
|
||||
[TestCaseSource(nameof(ExpectedPropertyValues))]
|
||||
public void PropertiesWithValuesAreCorrectlyImported(Func<ConnectionInfo, object> propSelector, object expectedValue)
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Name, Is.EqualTo(ExpectedName));
|
||||
var connectionTreeModel = _deserializer.Deserialize(_connectionFileContents);
|
||||
|
||||
var connection = connectionTreeModel
|
||||
.GetRecursiveChildList()
|
||||
.OfType<ContainerInfo>()
|
||||
.First(node => node.Name == "Group1")
|
||||
.Children
|
||||
.First();
|
||||
|
||||
Assert.That(propSelector(connection), Is.EqualTo(expectedValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionHostnameImported()
|
||||
[TestCaseSource(nameof(NullPropertyValues))]
|
||||
public void PropertiesWithoutValuesAreIgnored(Func<ConnectionInfo, object> propSelector)
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Hostname, Is.EqualTo(ExpectedHostname));
|
||||
var connectionTreeModel = _deserializer.Deserialize(Resources.test_rdcman_v2_7_schema3_empty_values);
|
||||
|
||||
var importedConnection = connectionTreeModel
|
||||
.GetRecursiveChildList()
|
||||
.OfType<ContainerInfo>()
|
||||
.First(node => node.Name == "Group1")
|
||||
.Children
|
||||
.First();
|
||||
|
||||
Assert.That(propSelector(importedConnection), Is.EqualTo(propSelector(new ConnectionInfo())));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDescriptionImported()
|
||||
[TestCaseSource(nameof(NullPropertyValues))]
|
||||
public void NonExistantPropertiesAreIgnored(Func<ConnectionInfo, object> propSelector)
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Description, Is.EqualTo(ExpectedDescription));
|
||||
var connectionTreeModel = _deserializer.Deserialize(Resources.test_rdcman_v2_7_schema3_null_values);
|
||||
|
||||
var importedConnection = connectionTreeModel
|
||||
.GetRecursiveChildList()
|
||||
.OfType<ContainerInfo>()
|
||||
.First(node => node.Name == "Group1")
|
||||
.Children
|
||||
.First();
|
||||
|
||||
Assert.That(propSelector(importedConnection), Is.EqualTo(propSelector(new ConnectionInfo())));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionUsernameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Username, Is.EqualTo(ExpectedUsername));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDomainImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Domain, Is.EqualTo(ExpectedDomain));
|
||||
}
|
||||
|
||||
// Since password is encrypted with a machine key, cant test decryption on another machine
|
||||
//[Test]
|
||||
//public void ConnectionPasswordImported()
|
||||
//{
|
||||
// var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
// var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
// var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
// var connection = group1.Children.First();
|
||||
// Assert.That(connection.Password, Is.EqualTo(ExpectedPassword));
|
||||
//}
|
||||
|
||||
[Test]
|
||||
public void ConnectionProtocolSetToRdp()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Protocol, Is.EqualTo(ProtocolType.RDP));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionUseConsoleSessionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.UseConsoleSession, Is.EqualTo(ExpectedUseConsoleSession));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionPortImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Port, Is.EqualTo(ExpectedPort));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayUsageMethodImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayUsageMethod, Is.EqualTo(ExpectedGatewayUsageMethod));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayHostnameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayHostname, Is.EqualTo(ExpectedGatewayHostname));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayUsernameImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayUsername, Is.EqualTo(ExpectedGatewayUsername));
|
||||
}
|
||||
|
||||
// Since password is encrypted with a machine key, cant test decryption on another machine
|
||||
//[Test]
|
||||
//public void ConnectionGatewayPasswordImported()
|
||||
//{
|
||||
// var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
// var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
// var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
// var connection = group1.Children.First();
|
||||
// Assert.That(connection.RDGatewayPassword, Is.EqualTo(ExpectedGatewayPassword));
|
||||
//}
|
||||
|
||||
[Test]
|
||||
public void ConnectionGatewayDomainImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDGatewayDomain, Is.EqualTo(ExpectedGatewayDomain));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionResolutionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Resolution, Is.EqualTo(ExpectedRdpResolution));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionColorDepthImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.Colors, Is.EqualTo(ExpectedRdpColorDepth));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionAudioRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectSound, Is.EqualTo(ExpectedAudioRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionKeyRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectKeys, Is.EqualTo(ExpectedKeyRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionDriveRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectDiskDrives, Is.EqualTo(ExpectedDriveRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionPortRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectPorts, Is.EqualTo(ExpectedPortRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionPrinterRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectPrinters, Is.EqualTo(ExpectedPrinterRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionSmartcardRedirectionImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RedirectSmartCards, Is.EqualTo(ExpectedSmartcardRedirection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectionauthenticationLevelImported()
|
||||
{
|
||||
var rootNode = _connectionTreeModel.RootNodes.First();
|
||||
var importedRdcmanRootNode = rootNode.Children.OfType<ContainerInfo>().First();
|
||||
var group1 = importedRdcmanRootNode.Children.OfType<ContainerInfo>().First(node => node.Name == "Group1");
|
||||
var connection = group1.Children.First();
|
||||
Assert.That(connection.RDPAuthenticationLevel, Is.EqualTo(ExpectedAuthLevel));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test]
|
||||
public void ExceptionThrownOnBadSchemaVersion()
|
||||
{
|
||||
var badFileContents = Resources.test_rdcman_v2_2_badschemaversion;
|
||||
@@ -322,5 +138,61 @@ namespace mRemoteNGTests.Config.Serializers.MiscSerializers
|
||||
var badFileContents = Resources.test_rdcman_noversion;
|
||||
Assert.That(() => _deserializer.Deserialize(badFileContents), Throws.TypeOf<FileFormatException>());
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> ExpectedPropertyValues()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Name), ExpectedName).SetName(nameof(ConnectionInfo.Name)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Hostname), ExpectedHostname).SetName(nameof(ConnectionInfo.Hostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Description), ExpectedDescription).SetName(nameof(ConnectionInfo.Description)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Username), ExpectedUsername).SetName(nameof(ConnectionInfo.Username)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Domain), ExpectedDomain).SetName(nameof(ConnectionInfo.Domain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Protocol), ProtocolType.RDP).SetName(nameof(ConnectionInfo.Protocol)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.UseConsoleSession), ExpectedUseConsoleSession).SetName(nameof(ConnectionInfo.UseConsoleSession)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Port), ExpectedPort).SetName(nameof(ConnectionInfo.Port)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsageMethod), ExpectedGatewayUsageMethod).SetName(nameof(ConnectionInfo.RDGatewayUsageMethod)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayHostname), ExpectedGatewayHostname).SetName(nameof(ConnectionInfo.RDGatewayHostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsername), ExpectedGatewayUsername).SetName(nameof(ConnectionInfo.RDGatewayUsername)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayDomain), ExpectedGatewayDomain).SetName(nameof(ConnectionInfo.RDGatewayDomain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Resolution), ExpectedRdpResolution).SetName(nameof(ConnectionInfo.Resolution)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Colors), ExpectedRdpColorDepth).SetName(nameof(ConnectionInfo.Colors)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSound), ExpectedAudioRedirection).SetName(nameof(ConnectionInfo.RedirectSound)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectKeys), ExpectedKeyRedirection).SetName(nameof(ConnectionInfo.RedirectKeys)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDPAuthenticationLevel), ExpectedAuthLevel).SetName(nameof(ConnectionInfo.RDPAuthenticationLevel)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSmartCards), ExpectedSmartcardRedirection).SetName(nameof(ConnectionInfo.RedirectSmartCards)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPrinters), ExpectedPrinterRedirection).SetName(nameof(ConnectionInfo.RedirectPrinters)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPorts), ExpectedPortRedirection).SetName(nameof(ConnectionInfo.RedirectPorts)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectDiskDrives), ExpectedDriveRedirection).SetName(nameof(ConnectionInfo.RedirectDiskDrives)),
|
||||
};
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> NullPropertyValues()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Name)).SetName(nameof(ConnectionInfo.Name)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Hostname)).SetName(nameof(ConnectionInfo.Hostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Description)).SetName(nameof(ConnectionInfo.Description)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Username)).SetName(nameof(ConnectionInfo.Username)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Domain)).SetName(nameof(ConnectionInfo.Domain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Protocol)).SetName(nameof(ConnectionInfo.Protocol)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.UseConsoleSession)).SetName(nameof(ConnectionInfo.UseConsoleSession)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Port)).SetName(nameof(ConnectionInfo.Port)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsageMethod)).SetName(nameof(ConnectionInfo.RDGatewayUsageMethod)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayHostname)).SetName(nameof(ConnectionInfo.RDGatewayHostname)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayUsername)).SetName(nameof(ConnectionInfo.RDGatewayUsername)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDGatewayDomain)).SetName(nameof(ConnectionInfo.RDGatewayDomain)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Resolution)).SetName(nameof(ConnectionInfo.Resolution)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.Colors)).SetName(nameof(ConnectionInfo.Colors)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSound)).SetName(nameof(ConnectionInfo.RedirectSound)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectKeys)).SetName(nameof(ConnectionInfo.RedirectKeys)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RDPAuthenticationLevel)).SetName(nameof(ConnectionInfo.RDPAuthenticationLevel)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectSmartCards)).SetName(nameof(ConnectionInfo.RedirectSmartCards)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPrinters)).SetName(nameof(ConnectionInfo.RedirectPrinters)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectPorts)).SetName(nameof(ConnectionInfo.RedirectPorts)),
|
||||
new TestCaseData((Func<ConnectionInfo,object>)(con => con.RedirectDiskDrives)).SetName(nameof(ConnectionInfo.RedirectDiskDrives)),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using NUnit.Framework;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
@@ -74,6 +75,22 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(hasEverythingInheritedProperty, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AlwaysReturnInheritedValueIfRequested()
|
||||
{
|
||||
var expectedSetting = false;
|
||||
|
||||
var container = new ContainerInfo { AutomaticResize = expectedSetting };
|
||||
var con1 = new ConnectionInfo
|
||||
{
|
||||
AutomaticResize = true,
|
||||
Inheritance = {AutomaticResize = true}
|
||||
};
|
||||
container.AddChild(con1);
|
||||
|
||||
Assert.That(con1.AutomaticResize, Is.EqualTo(expectedSetting));
|
||||
}
|
||||
|
||||
private bool AllInheritancePropertiesAreTrue()
|
||||
{
|
||||
var allPropertiesTrue = true;
|
||||
|
||||
@@ -43,6 +43,20 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(clonedConnection.Parent, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CloneAlsoCopiesInheritanceObject()
|
||||
{
|
||||
var clonedConnection = _connectionInfo.Clone();
|
||||
Assert.That(clonedConnection.Inheritance, Is.Not.EqualTo(_connectionInfo.Inheritance));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CloneCorrectlySetsParentOfInheritanceObject()
|
||||
{
|
||||
var clonedConnection = _connectionInfo.Clone();
|
||||
Assert.That(clonedConnection.Inheritance.Parent, Is.EqualTo(clonedConnection));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CopyFromCopiesProperties()
|
||||
{
|
||||
|
||||
@@ -1,73 +1,62 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNGTests.TestHelpers;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
public class DefaultConnectionInfoTests
|
||||
{
|
||||
private string _testDomain = "somedomain";
|
||||
public class DefaultConnectionInfoTests
|
||||
{
|
||||
private ConnectionInfo _randomizedConnectionInfo;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
DefaultConnectionInfo.Instance.Domain = "";
|
||||
_randomizedConnectionInfo = ConnectionInfoHelpers.GetRandomizedConnectionInfo();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadingDefaultInfoUpdatesAllProperties()
|
||||
[TestCaseSource(nameof(GetConnectionInfoProperties))]
|
||||
public void LoadingDefaultInfoUpdatesAllProperties(PropertyInfo property)
|
||||
{
|
||||
var connectionInfoSource = new ConnectionInfo { Domain = _testDomain };
|
||||
DefaultConnectionInfo.Instance.LoadFrom(connectionInfoSource);
|
||||
Assert.That(DefaultConnectionInfo.Instance.Domain, Is.EqualTo(_testDomain));
|
||||
DefaultConnectionInfo.Instance.LoadFrom(_randomizedConnectionInfo);
|
||||
var valueInDestination = property.GetValue(DefaultConnectionInfo.Instance);
|
||||
var valueInSource = property.GetValue(_randomizedConnectionInfo);
|
||||
Assert.That(valueInDestination, Is.EqualTo(valueInSource));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SavingDefaultConnectionInfoExportsAllProperties()
|
||||
[TestCaseSource(nameof(GetConnectionInfoProperties))]
|
||||
public void SavingDefaultConnectionInfoExportsAllProperties(PropertyInfo property)
|
||||
{
|
||||
var saveTarget = new ConnectionInfo();
|
||||
DefaultConnectionInfo.Instance.Domain = _testDomain;
|
||||
var randomizedValue = property.GetValue(_randomizedConnectionInfo);
|
||||
property.SetValue(DefaultConnectionInfo.Instance, randomizedValue);
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.Domain, Is.EqualTo(_testDomain));
|
||||
var valueInDestination = property.GetValue(saveTarget);
|
||||
var valueInSource = property.GetValue(DefaultConnectionInfo.Instance);
|
||||
Assert.That(valueInDestination, Is.EqualTo(valueInSource));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSaveEnumValuesToString()
|
||||
{
|
||||
const ProtocolType targetProtocol = ProtocolType.RAW;
|
||||
var saveTarget = new AllStringPropertySaveTarget();
|
||||
DefaultConnectionInfo.Instance.Protocol = targetProtocol;
|
||||
[TestCaseSource(nameof(GetConnectionInfoProperties))]
|
||||
public void CanSaveDefaultConnectionToModelWithAllStringProperties(PropertyInfo property)
|
||||
{
|
||||
var saveTarget = new SerializableConnectionInfoAllPropertiesOfType<string>();
|
||||
|
||||
// randomize default connnection values to ensure we dont get false passing tests
|
||||
var randomizedValue = property.GetValue(_randomizedConnectionInfo);
|
||||
property.SetValue(DefaultConnectionInfo.Instance, randomizedValue);
|
||||
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.Protocol, Is.EqualTo(targetProtocol.ToString()));
|
||||
|
||||
var valueInSource = property.GetValue(DefaultConnectionInfo.Instance).ToString();
|
||||
var valueInDestination = saveTarget.GetType().GetProperty(property.Name).GetValue(saveTarget).ToString();
|
||||
Assert.That(valueInDestination, Is.EqualTo(valueInSource));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSaveIntegerValuesToString()
|
||||
{
|
||||
const int targetValue = 123;
|
||||
var saveTarget = new AllStringPropertySaveTarget();
|
||||
DefaultConnectionInfo.Instance.RDPMinutesToIdleTimeout = targetValue;
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.RDPMinutesToIdleTimeout, Is.EqualTo(targetValue.ToString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSaveStringValuesToString()
|
||||
{
|
||||
const string targetName = "hello";
|
||||
var saveTarget = new AllStringPropertySaveTarget();
|
||||
DefaultConnectionInfo.Instance.Username = targetName;
|
||||
DefaultConnectionInfo.Instance.SaveTo(saveTarget);
|
||||
Assert.That(saveTarget.Username, Is.EqualTo(targetName));
|
||||
}
|
||||
|
||||
|
||||
private class AllStringPropertySaveTarget
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public string Protocol { get; set; }
|
||||
public string RDPMinutesToIdleTimeout { get; set; }
|
||||
}
|
||||
private static IEnumerable<PropertyInfo> GetConnectionInfoProperties()
|
||||
{
|
||||
return new ConnectionInfo().GetSerializableProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,40 @@
|
||||
using mRemoteNG.Connection;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.Connection;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
namespace mRemoteNGTests.Connection
|
||||
{
|
||||
public class DefaultConnectionInheritanceTests
|
||||
public class DefaultConnectionInheritanceTests
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
[TestCaseSource(nameof(GetInheritanceProperties))]
|
||||
public void LoadingDefaultInheritanceUpdatesAllProperties(PropertyInfo property)
|
||||
{
|
||||
DefaultConnectionInheritance.Instance.TurnOffInheritanceCompletely();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LoadingDefaultInheritanceUpdatesAllProperties()
|
||||
{
|
||||
var inheritanceSource = new ConnectionInfoInheritance(new object(), true);
|
||||
var inheritanceSource = new ConnectionInfoInheritance(new object(), true);
|
||||
inheritanceSource.TurnOnInheritanceCompletely();
|
||||
DefaultConnectionInheritance.Instance.LoadFrom(inheritanceSource);
|
||||
Assert.That(DefaultConnectionInheritance.Instance.EverythingInherited, Is.True);
|
||||
}
|
||||
DefaultConnectionInheritance.Instance.TurnOffInheritanceCompletely();
|
||||
|
||||
[Test]
|
||||
public void SavingDefaultInheritanceExportsAllProperties()
|
||||
DefaultConnectionInheritance.Instance.LoadFrom(inheritanceSource);
|
||||
|
||||
var valueInDestination = property.GetValue(DefaultConnectionInheritance.Instance);
|
||||
var valueInSource = property.GetValue(inheritanceSource);
|
||||
Assert.That(valueInDestination, Is.EqualTo(valueInSource));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(GetInheritanceProperties))]
|
||||
public void SavingDefaultInheritanceExportsAllProperties(PropertyInfo property)
|
||||
{
|
||||
var inheritanceDestination = new ConnectionInfoInheritance(new object(), true);
|
||||
DefaultConnectionInheritance.Instance.AutomaticResize = true;
|
||||
DefaultConnectionInheritance.Instance.SaveTo(inheritanceDestination);
|
||||
Assert.That(inheritanceDestination.AutomaticResize, Is.True);
|
||||
}
|
||||
var saveTarget = new ConnectionInfoInheritance(new object(), true);
|
||||
saveTarget.TurnOffInheritanceCompletely();
|
||||
DefaultConnectionInheritance.Instance.TurnOnInheritanceCompletely();
|
||||
|
||||
DefaultConnectionInheritance.Instance.SaveTo(saveTarget);
|
||||
|
||||
var valueInDestination = property.GetValue(saveTarget);
|
||||
var valueInSource = property.GetValue(DefaultConnectionInheritance.Instance);
|
||||
Assert.That(valueInDestination, Is.EqualTo(valueInSource));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NewInheritanceInstancesCreatedWithDefaultInheritanceValues()
|
||||
@@ -38,12 +44,20 @@ namespace mRemoteNGTests.Connection
|
||||
Assert.That(inheritanceInstance.Domain, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NewInheritanceInstancesCreatedWithAllDefaultInheritanceValues()
|
||||
[TestCaseSource(nameof(GetInheritanceProperties))]
|
||||
public void NewInheritanceInstancesCreatedWithAllDefaultInheritanceValues(PropertyInfo property)
|
||||
{
|
||||
DefaultConnectionInheritance.Instance.TurnOnInheritanceCompletely();
|
||||
var inheritanceInstance = new ConnectionInfoInheritance(new object());
|
||||
Assert.That(inheritanceInstance.EverythingInherited, Is.True);
|
||||
}
|
||||
}
|
||||
|
||||
var valueInDestination = property.GetValue(inheritanceInstance);
|
||||
var valueInSource = property.GetValue(DefaultConnectionInheritance.Instance);
|
||||
Assert.That(valueInDestination, Is.EqualTo(valueInSource));
|
||||
}
|
||||
|
||||
private static IEnumerable<PropertyInfo> GetInheritanceProperties()
|
||||
{
|
||||
return new ConnectionInfoInheritance(new object(), true).GetProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
@@ -29,20 +31,19 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
_originalModel.RootNodes.OfType<RootNodeInfo>().First().PasswordString.ConvertToSecureString(),
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_serializer = null;
|
||||
_deserializer = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeThenDeserialize()
|
||||
{
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
@@ -54,7 +55,6 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
{
|
||||
_serializer.UseFullEncryption = true;
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
@@ -66,7 +66,6 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
{
|
||||
var originalConnectionInfo = new ConnectionInfo {Name = "con1", Description = "£°úg¶┬ä" };
|
||||
var serializedContent = _serializer.Serialize(originalConnectionInfo);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
|
||||
Assert.That(deserializedConnectionInfo.Description, Is.EqualTo(originalConnectionInfo.Description));
|
||||
@@ -84,13 +83,26 @@ namespace mRemoteNGTests.IntegrationTests
|
||||
new SaveFilter());
|
||||
_serializer = new XmlConnectionsSerializer(cryptoProvider, nodeSerializer);
|
||||
var serializedContent = _serializer.Serialize(_originalModel);
|
||||
_deserializer = new XmlConnectionsDeserializer();
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var nodeNamesFromDeserializedModel = deserializedModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
var nodeNamesFromOriginalModel = _originalModel.GetRecursiveChildList().Select(node => node.Name);
|
||||
Assert.That(nodeNamesFromDeserializedModel, Is.EquivalentTo(nodeNamesFromOriginalModel));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GuidCreatedIfNonExistedInXml()
|
||||
{
|
||||
var originalConnectionInfo = new ConnectionInfo { Name = "con1" };
|
||||
var serializedContent = _serializer.Serialize(originalConnectionInfo);
|
||||
|
||||
// remove GUID from connection xml
|
||||
serializedContent = serializedContent.Replace(originalConnectionInfo.ConstantID, "");
|
||||
|
||||
var deserializedModel = _deserializer.Deserialize(serializedContent);
|
||||
var deserializedConnectionInfo = deserializedModel.GetRecursiveChildList().First(node => node.Name == originalConnectionInfo.Name);
|
||||
Assert.That(Guid.TryParse(deserializedConnectionInfo.ConstantID, out var guid));
|
||||
}
|
||||
|
||||
|
||||
private ConnectionTreeModel SetupConnectionTreeModel()
|
||||
{
|
||||
|
||||
52
mRemoteNGTests/Properties/Resources.Designer.cs
generated
52
mRemoteNGTests/Properties/Resources.Designer.cs
generated
@@ -298,6 +298,58 @@ namespace mRemoteNGTests.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?>
|
||||
///<RDCMan programVersion="2.7" schemaVersion="3">
|
||||
/// <file>
|
||||
/// <credentialsProfiles />
|
||||
/// <properties>
|
||||
/// <expanded>True</expanded>
|
||||
/// <name>test_RDCMan_connections</name>
|
||||
/// </properties>
|
||||
/// <smartGroup>
|
||||
/// <properties>
|
||||
/// <expanded>False</expanded>
|
||||
/// <name>AllServers</name>
|
||||
/// </properties>
|
||||
/// <ruleGroup operator="All">
|
||||
/// <rule>
|
||||
/// <property>DisplayName</property>
|
||||
/// <operator>Matches</operator>
|
||||
/// [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string test_rdcman_v2_7_schema3_empty_values {
|
||||
get {
|
||||
return ResourceManager.GetString("test_rdcman_v2_7_schema3_empty_values", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?>
|
||||
///<RDCMan programVersion="2.7" schemaVersion="3">
|
||||
/// <file>
|
||||
/// <credentialsProfiles />
|
||||
/// <properties>
|
||||
/// <expanded>True</expanded>
|
||||
/// <name>test_RDCMan_connections</name>
|
||||
/// </properties>
|
||||
/// <smartGroup>
|
||||
/// <properties>
|
||||
/// <expanded>False</expanded>
|
||||
/// <name>AllServers</name>
|
||||
/// </properties>
|
||||
/// <ruleGroup operator="All">
|
||||
/// <rule>
|
||||
/// <property>DisplayName</property>
|
||||
/// <operator>Matches</operator>
|
||||
/// [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string test_rdcman_v2_7_schema3_null_values {
|
||||
get {
|
||||
return ResourceManager.GetString("test_rdcman_v2_7_schema3_null_values", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to screen mode id:i:1
|
||||
///use multimon:i:0
|
||||
|
||||
@@ -172,6 +172,12 @@
|
||||
<data name="test_rdcman_v2_7_schema3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\test_RDCMan_v2_7_schema3.rdg;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="test_rdcman_v2_7_schema3_empty_values" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\test_rdcman_v2_7_schema3_empty_values.rdg;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="test_rdcman_v2_7_schema3_null_values" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\test_rdcman_v2_7_schema3_null_values.rdg;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="test_remotedesktopconnection_rdp" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\test_remotedesktopconnection.rdp;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RDCMan programVersion="2.7" schemaVersion="3">
|
||||
<file>
|
||||
<credentialsProfiles />
|
||||
<properties>
|
||||
<expanded>True</expanded>
|
||||
<name>test_RDCMan_connections</name>
|
||||
</properties>
|
||||
<smartGroup>
|
||||
<properties>
|
||||
<expanded>False</expanded>
|
||||
<name>AllServers</name>
|
||||
</properties>
|
||||
<ruleGroup operator="All">
|
||||
<rule>
|
||||
<property>DisplayName</property>
|
||||
<operator>Matches</operator>
|
||||
<value>server</value>
|
||||
</rule>
|
||||
</ruleGroup>
|
||||
</smartGroup>
|
||||
<group>
|
||||
<properties>
|
||||
<expanded>True</expanded>
|
||||
<name>Group1</name>
|
||||
</properties>
|
||||
<server>
|
||||
<properties>
|
||||
<displayName></displayName>
|
||||
<name></name>
|
||||
<comment></comment>
|
||||
</properties>
|
||||
<logonCredentials inherit="None">
|
||||
<profileName scope="Local"></profileName>
|
||||
<userName></userName>
|
||||
<password></password>
|
||||
<domain></domain>
|
||||
</logonCredentials>
|
||||
<connectionSettings inherit="None">
|
||||
<connectToConsole></connectToConsole>
|
||||
<startProgram />
|
||||
<workingDir />
|
||||
<port></port>
|
||||
<loadBalanceInfo />
|
||||
</connectionSettings>
|
||||
<gatewaySettings inherit="None">
|
||||
<enabled></enabled>
|
||||
<hostName></hostName>
|
||||
<logonMethod></logonMethod>
|
||||
<localBypass></localBypass>
|
||||
<credSharing></credSharing>
|
||||
<profileName scope="Local"></profileName>
|
||||
<userName></userName>
|
||||
<password />
|
||||
<domain></domain>
|
||||
</gatewaySettings>
|
||||
<remoteDesktop inherit="None">
|
||||
<sameSizeAsClientArea></sameSizeAsClientArea>
|
||||
<fullScreen></fullScreen>
|
||||
<colorDepth></colorDepth>
|
||||
</remoteDesktop>
|
||||
<localResources inherit="None">
|
||||
<audioRedirection></audioRedirection>
|
||||
<audioRedirectionQuality></audioRedirectionQuality>
|
||||
<audioCaptureRedirection></audioCaptureRedirection>
|
||||
<keyboardHook></keyboardHook>
|
||||
<redirectClipboard></redirectClipboard>
|
||||
<redirectDrives></redirectDrives>
|
||||
<redirectDrivesList>
|
||||
<item></item>
|
||||
<item></item>
|
||||
<item></item>
|
||||
<item></item>
|
||||
<item></item>
|
||||
</redirectDrivesList>
|
||||
<redirectPrinters></redirectPrinters>
|
||||
<redirectPorts></redirectPorts>
|
||||
<redirectSmartCards></redirectSmartCards>
|
||||
<redirectPnpDevices></redirectPnpDevices>
|
||||
</localResources>
|
||||
<displaySettings inherit="None">
|
||||
<thumbnailScale></thumbnailScale>
|
||||
<smartSizeDockedWindows></smartSizeDockedWindows>
|
||||
<smartSizeUndockedWindows></smartSizeUndockedWindows>
|
||||
</displaySettings>
|
||||
<securitySettings inherit="None">
|
||||
<authentication></authentication>
|
||||
</securitySettings>
|
||||
</server>
|
||||
</group>
|
||||
</file>
|
||||
<connected />
|
||||
<favorites />
|
||||
<recentlyUsed />
|
||||
</RDCMan>
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RDCMan programVersion="2.7" schemaVersion="3">
|
||||
<file>
|
||||
<credentialsProfiles />
|
||||
<properties>
|
||||
<expanded>True</expanded>
|
||||
<name>test_RDCMan_connections</name>
|
||||
</properties>
|
||||
<smartGroup>
|
||||
<properties>
|
||||
<expanded>False</expanded>
|
||||
<name>AllServers</name>
|
||||
</properties>
|
||||
<ruleGroup operator="All">
|
||||
<rule>
|
||||
<property>DisplayName</property>
|
||||
<operator>Matches</operator>
|
||||
<value>server</value>
|
||||
</rule>
|
||||
</ruleGroup>
|
||||
</smartGroup>
|
||||
<group>
|
||||
<properties>
|
||||
<expanded>True</expanded>
|
||||
<name>Group1</name>
|
||||
</properties>
|
||||
<server>
|
||||
<properties>
|
||||
</properties>
|
||||
<logonCredentials inherit="None">
|
||||
</logonCredentials>
|
||||
<connectionSettings inherit="None">
|
||||
</connectionSettings>
|
||||
<gatewaySettings inherit="None">
|
||||
</gatewaySettings>
|
||||
<remoteDesktop inherit="None">
|
||||
</remoteDesktop>
|
||||
<localResources inherit="None">
|
||||
</localResources>
|
||||
<displaySettings inherit="None">
|
||||
</displaySettings>
|
||||
<securitySettings inherit="None">
|
||||
</securitySettings>
|
||||
</server>
|
||||
</group>
|
||||
</file>
|
||||
<connected />
|
||||
<favorites />
|
||||
<recentlyUsed />
|
||||
</RDCMan>
|
||||
@@ -2,6 +2,7 @@
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
@@ -9,35 +10,31 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
{
|
||||
public class PasswordAuthenticatorTests
|
||||
{
|
||||
private PasswordAuthenticator _authenticator;
|
||||
private ICryptographyProvider _cryptographyProvider;
|
||||
private string _cipherText;
|
||||
private readonly SecureString _correctPassword = "9theCorrectPass#5".ConvertToSecureString();
|
||||
private readonly SecureString _wrongPassword = "wrongPassword".ConvertToSecureString();
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var cryptoProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
|
||||
const string cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
|
||||
_authenticator = new PasswordAuthenticator(cryptoProvider, cipherText);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Teardown()
|
||||
{
|
||||
_authenticator = null;
|
||||
_cryptographyProvider = new AeadCryptographyProvider {KeyDerivationIterations = 10000};
|
||||
_cipherText = "MPELiwk7+xeNlruIyt5uxTvVB+/RLVoLdUGnwY4CWCqwKe7T2IBwWo4oaKum5hdv7447g5m2nZsYPrfARSlotQB4r1KZQg==";
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatingWithCorrectPasswordReturnsTrue()
|
||||
{
|
||||
var authenticated = _authenticator.Authenticate(_correctPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
|
||||
var authenticated = authenticator.Authenticate(_correctPassword);
|
||||
Assert.That(authenticated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatingWithWrongPasswordReturnsFalse()
|
||||
{
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => Optional<SecureString>.Empty);
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(!authenticated);
|
||||
}
|
||||
|
||||
@@ -45,12 +42,15 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticationRequestorIsCalledWhenInitialPasswordIsWrong()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
wasCalled = true;
|
||||
return _correctPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(wasCalled);
|
||||
}
|
||||
|
||||
@@ -58,28 +58,30 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticationRequestorNotCalledWhenInitialPasswordIsCorrect()
|
||||
{
|
||||
var wasCalled = false;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
wasCalled = true;
|
||||
return _correctPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_correctPassword);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_correctPassword);
|
||||
Assert.That(!wasCalled);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProvidingCorrectPasswordToTheAuthenticationRequestorReturnsTrue()
|
||||
{
|
||||
_authenticator.AuthenticationRequestor = () => _correctPassword;
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => _correctPassword);
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authenticated);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticationFailsWhenAuthenticationRequestorGivenEmptyPassword()
|
||||
{
|
||||
_authenticator.AuthenticationRequestor = () => new SecureString();
|
||||
var authenticated = _authenticator.Authenticate(_wrongPassword);
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, () => new SecureString());
|
||||
var authenticated = authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(!authenticated);
|
||||
}
|
||||
|
||||
@@ -87,27 +89,34 @@ namespace mRemoteNGTests.Security.Authentication
|
||||
public void AuthenticatorRespectsMaxAttempts()
|
||||
{
|
||||
var authAttempts = 0;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
authAttempts++;
|
||||
return _wrongPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == _authenticator.MaxAttempts);
|
||||
}
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor);
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == authenticator.MaxAttempts);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AuthenticatorRespectsMaxAttemptsCustomValue()
|
||||
{
|
||||
const int customMaxAttempts = 5;
|
||||
_authenticator.MaxAttempts = customMaxAttempts;
|
||||
var authAttempts = 0;
|
||||
_authenticator.AuthenticationRequestor = () =>
|
||||
Optional<SecureString> AuthenticationRequestor()
|
||||
{
|
||||
authAttempts++;
|
||||
return _wrongPassword;
|
||||
};
|
||||
_authenticator.Authenticate(_wrongPassword);
|
||||
}
|
||||
|
||||
var authenticator =
|
||||
new PasswordAuthenticator(_cryptographyProvider, _cipherText, AuthenticationRequestor)
|
||||
{
|
||||
MaxAttempts = customMaxAttempts
|
||||
};
|
||||
authenticator.Authenticate(_wrongPassword);
|
||||
Assert.That(authAttempts == customMaxAttempts);
|
||||
}
|
||||
}
|
||||
|
||||
132
mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs
Normal file
132
mRemoteNGTests/TestHelpers/ConnectionInfoHelpers.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.ICA;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
|
||||
namespace mRemoteNGTests.TestHelpers
|
||||
{
|
||||
internal static class ConnectionInfoHelpers
|
||||
{
|
||||
private static readonly Random _random = new Random();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="ConnectionInfo"/> object with randomized
|
||||
/// values in all fields.
|
||||
/// </summary>
|
||||
internal static ConnectionInfo GetRandomizedConnectionInfo(bool randomizeInheritance = false)
|
||||
{
|
||||
var connectionInfo = new ConnectionInfo
|
||||
{
|
||||
// string types
|
||||
Name = RandomString(),
|
||||
Hostname = RandomString(),
|
||||
Description = RandomString(),
|
||||
Domain = RandomString(),
|
||||
ExtApp = RandomString(),
|
||||
Icon = RandomString(),
|
||||
LoadBalanceInfo = RandomString(),
|
||||
MacAddress = RandomString(),
|
||||
Panel = RandomString(),
|
||||
Password = RandomString(),
|
||||
PostExtApp = RandomString(),
|
||||
PreExtApp = RandomString(),
|
||||
PuttySession = RandomString(),
|
||||
RDGatewayHostname = RandomString(),
|
||||
RDGatewayUsername = RandomString(),
|
||||
RDGatewayDomain = RandomString(),
|
||||
RDGatewayPassword = RandomString(),
|
||||
UserField = RandomString(),
|
||||
Username = RandomString(),
|
||||
VNCProxyIP = RandomString(),
|
||||
VNCProxyPassword = RandomString(),
|
||||
VNCProxyUsername = RandomString(),
|
||||
|
||||
// bool types
|
||||
AutomaticResize = RandomBool(),
|
||||
CacheBitmaps = RandomBool(),
|
||||
DisplayThemes = RandomBool(),
|
||||
DisplayWallpaper = RandomBool(),
|
||||
EnableDesktopComposition = RandomBool(),
|
||||
EnableFontSmoothing = RandomBool(),
|
||||
IsContainer = RandomBool(),
|
||||
IsDefault = RandomBool(),
|
||||
IsQuickConnect = RandomBool(),
|
||||
PleaseConnect = RandomBool(),
|
||||
RDPAlertIdleTimeout = RandomBool(),
|
||||
RedirectDiskDrives = RandomBool(),
|
||||
RedirectKeys = RandomBool(),
|
||||
RedirectPorts = RandomBool(),
|
||||
RedirectPrinters = RandomBool(),
|
||||
RedirectSmartCards = RandomBool(),
|
||||
UseConsoleSession = RandomBool(),
|
||||
UseCredSsp = RandomBool(),
|
||||
VNCViewOnly = RandomBool(),
|
||||
|
||||
// ints
|
||||
Port = RandomInt(),
|
||||
RDPMinutesToIdleTimeout = RandomInt(),
|
||||
VNCProxyPort = RandomInt(),
|
||||
|
||||
// enums
|
||||
Colors = RandomEnum<RdpProtocol.RDPColors>(),
|
||||
ICAEncryptionStrength = RandomEnum<IcaProtocol.EncryptionStrength> (),
|
||||
Protocol = RandomEnum<ProtocolType>(),
|
||||
RDGatewayUsageMethod = RandomEnum<RdpProtocol.RDGatewayUsageMethod>(),
|
||||
RDGatewayUseConnectionCredentials = RandomEnum<RdpProtocol.RDGatewayUseConnectionCredentials>(),
|
||||
RDPAuthenticationLevel = RandomEnum<RdpProtocol.AuthenticationLevel>(),
|
||||
RedirectSound = RandomEnum<RdpProtocol.RDPSounds>(),
|
||||
RenderingEngine = RandomEnum<HTTPBase.RenderingEngine>(),
|
||||
Resolution = RandomEnum<RdpProtocol.RDPResolutions>(),
|
||||
SoundQuality = RandomEnum<RdpProtocol.RDPSoundQuality>(),
|
||||
VNCAuthMode = RandomEnum<ProtocolVNC.AuthMode>(),
|
||||
VNCColors = RandomEnum<ProtocolVNC.Colors>(),
|
||||
VNCCompression = RandomEnum<ProtocolVNC.Compression>(),
|
||||
VNCEncoding = RandomEnum<ProtocolVNC.Encoding>(),
|
||||
VNCProxyType = RandomEnum<ProtocolVNC.ProxyType>(),
|
||||
VNCSmartSizeMode = RandomEnum<ProtocolVNC.SmartSizeMode>(),
|
||||
};
|
||||
|
||||
if (randomizeInheritance)
|
||||
connectionInfo.Inheritance = GetRandomizedInheritance(connectionInfo);
|
||||
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
internal static ConnectionInfoInheritance GetRandomizedInheritance(ConnectionInfo parent)
|
||||
{
|
||||
var inheritance = new ConnectionInfoInheritance(parent, true);
|
||||
foreach (var property in inheritance.GetProperties())
|
||||
{
|
||||
property.SetValue(inheritance, RandomBool());
|
||||
}
|
||||
return inheritance;
|
||||
}
|
||||
|
||||
internal static string RandomString()
|
||||
{
|
||||
return Guid.NewGuid().ToString("N");
|
||||
}
|
||||
|
||||
internal static bool RandomBool()
|
||||
{
|
||||
return _random.Next() % 2 == 0;
|
||||
}
|
||||
|
||||
internal static int RandomInt()
|
||||
{
|
||||
return _random.Next();
|
||||
}
|
||||
|
||||
internal static T RandomEnum<T>() where T : struct, IConvertible
|
||||
{
|
||||
if (!typeof(T).IsEnum)
|
||||
throw new ArgumentException("T must be an enum");
|
||||
|
||||
var values = Enum.GetValues(typeof(T));
|
||||
return (T)values.GetValue(_random.Next(values.Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNGTests.TestHelpers
|
||||
{
|
||||
@@ -18,9 +19,17 @@ namespace mRemoteNGTests.TestHelpers
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
public static string NewTempFilePath()
|
||||
public static void DeleteDirectory(string directory)
|
||||
{
|
||||
if (Directory.Exists(directory))
|
||||
Directory.Delete(directory, true);
|
||||
}
|
||||
|
||||
public static string NewTempFilePath(string extension = "")
|
||||
{
|
||||
var newPath = Path.Combine(GetTestSpecificTempDirectory(), Path.GetRandomFileName());
|
||||
if (!string.IsNullOrWhiteSpace(extension))
|
||||
newPath = newPath + extension;
|
||||
var folderPath = Path.GetDirectoryName(newPath);
|
||||
if (!Directory.Exists(folderPath))
|
||||
Directory.CreateDirectory(folderPath);
|
||||
@@ -35,5 +44,15 @@ namespace mRemoteNGTests.TestHelpers
|
||||
{
|
||||
return Path.Combine(Path.GetTempPath(), "mRemoteNGTests", Path.GetRandomFileName());
|
||||
}
|
||||
|
||||
public static DisposableAction DisposableTempFile(out string filePath, string extension = "")
|
||||
{
|
||||
var file = NewTempFilePath(extension);
|
||||
filePath = file;
|
||||
File.AppendAllText(file, "");
|
||||
return new DisposableAction(
|
||||
() => {},
|
||||
() => DeleteDirectory(Path.GetDirectoryName(file)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
namespace mRemoteNGTests.TestHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A ConnectionInfo that has only the serializable properties as string types.
|
||||
/// Only used for testing.
|
||||
/// </summary>
|
||||
internal class SerializableConnectionInfoAllPropertiesOfType<TType>
|
||||
{
|
||||
public TType Description { get; set; }
|
||||
public TType Icon { get; set; }
|
||||
public TType Panel { get; set; }
|
||||
public TType Username { get; set; }
|
||||
public TType Password { get; set; }
|
||||
public TType Domain { get; set; }
|
||||
public TType Protocol { get; set; }
|
||||
public TType ExtApp { get; set; }
|
||||
public TType PuttySession { get; set; }
|
||||
public TType ICAEncryptionStrength { get; set; }
|
||||
public TType UseConsoleSession { get; set; }
|
||||
public TType RDPAuthenticationLevel { get; set; }
|
||||
public TType RDPMinutesToIdleTimeout { get; set; }
|
||||
public TType RDPAlertIdleTimeout { get; set; }
|
||||
public TType LoadBalanceInfo { get; set; }
|
||||
public TType RenderingEngine { get; set; }
|
||||
public TType UseCredSsp { get; set; }
|
||||
public TType RDGatewayUsageMethod { get; set; }
|
||||
public TType RDGatewayHostname { get; set; }
|
||||
public TType RDGatewayUseConnectionCredentials { get; set; }
|
||||
public TType RDGatewayUsername { get; set; }
|
||||
public TType RDGatewayPassword { get; set; }
|
||||
public TType RDGatewayDomain { get; set; }
|
||||
public TType Resolution { get; set; }
|
||||
public TType AutomaticResize { get; set; }
|
||||
public TType Colors { get; set; }
|
||||
public TType CacheBitmaps { get; set; }
|
||||
public TType DisplayWallpaper { get; set; }
|
||||
public TType DisplayThemes { get; set; }
|
||||
public TType EnableFontSmoothing { get; set; }
|
||||
public TType EnableDesktopComposition { get; set; }
|
||||
public TType RedirectKeys { get; set; }
|
||||
public TType RedirectDiskDrives { get; set; }
|
||||
public TType RedirectPrinters { get; set; }
|
||||
public TType RedirectPorts { get; set; }
|
||||
public TType RedirectSmartCards { get; set; }
|
||||
public TType RedirectSound { get; set; }
|
||||
public TType SoundQuality { get; set; }
|
||||
public TType PreExtApp { get; set; }
|
||||
public TType PostExtApp { get; set; }
|
||||
public TType MacAddress { get; set; }
|
||||
public TType UserField { get; set; }
|
||||
public TType VNCCompression { get; set; }
|
||||
public TType VNCEncoding { get; set; }
|
||||
public TType VNCAuthMode { get; set; }
|
||||
public TType VNCProxyType { get; set; }
|
||||
public TType VNCProxyIP { get; set; }
|
||||
public TType VNCProxyPort { get; set; }
|
||||
public TType VNCProxyUsername { get; set; }
|
||||
public TType VNCProxyPassword { get; set; }
|
||||
public TType VNCColors { get; set; }
|
||||
public TType VNCSmartSizeMode { get; set; }
|
||||
public TType VNCViewOnly { get; set; }
|
||||
}
|
||||
}
|
||||
42
mRemoteNGTests/Tools/DisposableActionTests.cs
Normal file
42
mRemoteNGTests/Tools/DisposableActionTests.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using mRemoteNG.Tools;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Tools
|
||||
{
|
||||
public class DisposableActionTests
|
||||
{
|
||||
[Test]
|
||||
public void InitializerActionRunsWhenObjectIsCreated()
|
||||
{
|
||||
var initializerRan = false;
|
||||
new DisposableAction(() => initializerRan = true, () => { });
|
||||
|
||||
Assert.That(initializerRan);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DisposalActionRunsWhenDisposeIsCalled()
|
||||
{
|
||||
var disposeActionRan = false;
|
||||
var action = new DisposableAction(() => {}, () => disposeActionRan = true);
|
||||
|
||||
Assert.That(disposeActionRan, Is.False);
|
||||
action.Dispose();
|
||||
Assert.That(disposeActionRan, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DisposeActionOnlyExecutedOnceWhenCallingDisposeMultipleTimes()
|
||||
{
|
||||
var invokeCount = 0;
|
||||
var action = new DisposableAction(() => { }, () => invokeCount++);
|
||||
|
||||
action.Dispose();
|
||||
action.Dispose();
|
||||
action.Dispose();
|
||||
action.Dispose();
|
||||
action.Dispose();
|
||||
Assert.That(invokeCount, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Tree
|
||||
{
|
||||
public class NodeSearcherTests
|
||||
public class NodeSearcherTests
|
||||
{
|
||||
private NodeSearcher _nodeSearcher;
|
||||
private ContainerInfo _folder1;
|
||||
@@ -104,6 +104,14 @@ namespace mRemoteNGTests.Tree
|
||||
_con4 = new ConnectionInfo { Name = "con4", Description="description6", Hostname="hostname6" };
|
||||
_con5 = new ConnectionInfo { Name = "con5", Description="description7", Hostname="hostname7" };
|
||||
|
||||
_folder1.Inheritance.TurnOffInheritanceCompletely();
|
||||
_con1.Inheritance.TurnOffInheritanceCompletely();
|
||||
_con2.Inheritance.TurnOffInheritanceCompletely();
|
||||
_folder2.Inheritance.TurnOffInheritanceCompletely();
|
||||
_con3.Inheritance.TurnOffInheritanceCompletely();
|
||||
_con4.Inheritance.TurnOffInheritanceCompletely();
|
||||
_con5.Inheritance.TurnOffInheritanceCompletely();
|
||||
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
root.AddChildRange(new [] { _folder1, _folder2, _con5 });
|
||||
_folder1.AddChildRange(new [] { _con1, _con2 });
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
||||
@@ -46,5 +47,13 @@ namespace mRemoteNGTests.Tree
|
||||
_rootNodeInfo.PasswordString = password;
|
||||
Assert.That(_rootNodeInfo.PasswordString, Is.EqualTo(password));
|
||||
}
|
||||
|
||||
[TestCase(RootNodeType.Connection, TreeNodeType.Root)]
|
||||
[TestCase(RootNodeType.PuttySessions, TreeNodeType.PuttyRoot)]
|
||||
public void RootNodeHasCorrectTreeNodeType(RootNodeType rootNodeType, TreeNodeType expectedTreeNodeType)
|
||||
{
|
||||
var rootNode = new RootNodeInfo(rootNodeType);
|
||||
Assert.That(rootNode.GetTreeNodeType(), Is.EqualTo(expectedTreeNodeType));
|
||||
}
|
||||
}
|
||||
}
|
||||
202
mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs
Normal file
202
mRemoteNGTests/UI/Controls/ConnectionTreeTests.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Controls;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Controls
|
||||
{
|
||||
public class ConnectionTreeTests
|
||||
{
|
||||
private ConnectionTreeSearchTextFilter _filter;
|
||||
private ConnectionTree _connectionTree;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_filter = new ConnectionTreeSearchTextFilter();
|
||||
_connectionTree = new ConnectionTree
|
||||
{
|
||||
UseFiltering = true
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void FilteringIsRetainedAndUpdatedWhenNodeDeleted()
|
||||
{
|
||||
// root
|
||||
// |- folder1
|
||||
// | |- con1
|
||||
// | |- dontshowme
|
||||
// |- folder2
|
||||
// |- con2
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var folder1 = new ContainerInfo {Name = "folder1"};
|
||||
var folder2 = new ContainerInfo {Name = "folder2"};
|
||||
var con1 = new ConnectionInfo {Name = "con1"};
|
||||
var con2 = new ConnectionInfo {Name = "con2"};
|
||||
var conDontShow = new ConnectionInfo {Name = "dontshowme" };
|
||||
root.AddChildRange(new []{folder1, folder2});
|
||||
folder1.AddChildRange(new []{con1, conDontShow});
|
||||
folder2.AddChild(con2);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
// ensure all folders expanded
|
||||
_connectionTree.ExpandAll();
|
||||
|
||||
// apply filtering on the tree
|
||||
_filter.FilterText = "con";
|
||||
_connectionTree.ModelFilter = _filter;
|
||||
|
||||
connectionTreeModel.DeleteNode(con1);
|
||||
|
||||
Assert.That(_connectionTree.IsFiltering, Is.True);
|
||||
Assert.That(_connectionTree.FilteredObjects, Does.Not.Contain(con1));
|
||||
Assert.That(_connectionTree.FilteredObjects, Does.Not.Contain(conDontShow));
|
||||
Assert.That(_connectionTree.FilteredObjects, Does.Contain(con2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotAddConnectionToPuttySessionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = puttyRoot;
|
||||
_connectionTree.AddConnection();
|
||||
|
||||
Assert.That(puttyRoot.Children, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotAddFolderToPuttySessionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = puttyRoot;
|
||||
_connectionTree.AddFolder();
|
||||
|
||||
Assert.That(puttyRoot.Children, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotDuplicateRootConnectionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = root;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotDuplicateRootPuttyNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = puttyRoot;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void CannotDuplicatePuttyConnectionNode()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
var puttyConnection = new PuttySessionInfo();
|
||||
puttyRoot.AddChild(puttyConnection);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
_connectionTree.ExpandAll();
|
||||
|
||||
_connectionTree.SelectedObject = puttyConnection;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(puttyRoot.Children, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void DuplicatingWithNoNodeSelectedDoesNothing()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var puttyRoot = new RootNodeInfo(RootNodeType.PuttySessions);
|
||||
connectionTreeModel.AddRootNode(puttyRoot);
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
_connectionTree.SelectedObject = null;
|
||||
_connectionTree.DuplicateSelectedNode();
|
||||
|
||||
Assert.That(connectionTreeModel.RootNodes, Has.One.Items);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void ExpandingAllItemsUpdatesColumnWidthAppropriately()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
ContainerInfo parent = root;
|
||||
foreach (var i in Enumerable.Repeat("", 8))
|
||||
{
|
||||
var newContainer = new ContainerInfo {IsExpanded = false};
|
||||
parent.AddChild(newContainer);
|
||||
parent = newContainer;
|
||||
}
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
|
||||
var widthBefore = _connectionTree.Columns[0].Width;
|
||||
_connectionTree.ExpandAll();
|
||||
var widthAfter = _connectionTree.Columns[0].Width;
|
||||
|
||||
Assert.That(widthAfter, Is.GreaterThan(widthBefore));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Apartment(ApartmentState.STA)]
|
||||
public void RenamingNodeWithNothingSelectedDoesNothing()
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
|
||||
_connectionTree.ConnectionTreeModel = connectionTreeModel;
|
||||
_connectionTree.SelectedObject = null;
|
||||
|
||||
Assert.DoesNotThrow(() => _connectionTree.RenameSelectedNode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Window;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public class ConfigWindowGeneralTests
|
||||
{
|
||||
private ConfigWindow _configWindow;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_configWindow = new ConfigWindow
|
||||
{
|
||||
PropertiesVisible = true
|
||||
};
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(ConnectionInfoGeneralTestCases))]
|
||||
public void PropertyGridShowCorrectPropertiesForConnectionInfo(ConnectionInfo connectionInfo, IEnumerable<string> expectedVisibleProperties)
|
||||
{
|
||||
_configWindow.SelectedTreeNode = connectionInfo;
|
||||
Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PropertyGridShowCorrectPropertiesForRootConnectionInfo()
|
||||
{
|
||||
var expectedVisibleProperties = new[]
|
||||
{
|
||||
nameof(RootNodeInfo.Name),
|
||||
nameof(RootNodeInfo.Password),
|
||||
};
|
||||
|
||||
_configWindow.SelectedTreeNode = new RootNodeInfo(RootNodeType.Connection);
|
||||
Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PropertyGridShowCorrectPropertiesForRootPuttyInfo()
|
||||
{
|
||||
var expectedVisibleProperties = new[]
|
||||
{
|
||||
nameof(RootNodeInfo.Name),
|
||||
};
|
||||
|
||||
_configWindow.SelectedTreeNode = new RootPuttySessionsNodeInfo();
|
||||
Assert.That(_configWindow.VisibleObjectProperties, Is.EquivalentTo(expectedVisibleProperties));
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> ConnectionInfoGeneralTestCases()
|
||||
{
|
||||
var protocolTypes = typeof(ProtocolType).GetEnumValues().OfType<ProtocolType>();
|
||||
var testCases = new List<TestCaseData>();
|
||||
|
||||
foreach (var protocol in protocolTypes)
|
||||
{
|
||||
var expectedPropertyListConnection = BuildExpectedConnectionInfoPropertyList(protocol, false);
|
||||
var connectionInfo = ConstructConnectionInfo(protocol, false);
|
||||
var testCaseConnection = new TestCaseData(connectionInfo, expectedPropertyListConnection)
|
||||
.SetName(protocol + ", ConnectionInfo");
|
||||
testCases.Add(testCaseConnection);
|
||||
|
||||
var expectedPropertyListContainer = BuildExpectedConnectionInfoPropertyList(protocol, true);
|
||||
var containerInfo = ConstructConnectionInfo(protocol, true);
|
||||
var testCaseContainer = new TestCaseData(containerInfo, expectedPropertyListContainer)
|
||||
.SetName(protocol + ", ContainerInfo");
|
||||
testCases.Add(testCaseContainer);
|
||||
}
|
||||
|
||||
return testCases;
|
||||
}
|
||||
|
||||
internal static ConnectionInfo ConstructConnectionInfo(ProtocolType protocol, bool isContainer)
|
||||
{
|
||||
// build connection info. set certain connection properties so
|
||||
// that toggled properties are hidden in the property grid. We
|
||||
// will test those separately in the special protocol tests.
|
||||
var node = isContainer
|
||||
? new ContainerInfo()
|
||||
: new ConnectionInfo();
|
||||
|
||||
node.Protocol = protocol;
|
||||
node.Resolution = RdpProtocol.RDPResolutions.Res800x600;
|
||||
node.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Never;
|
||||
node.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.Yes;
|
||||
node.RedirectSound = RdpProtocol.RDPSounds.DoNotPlay;
|
||||
node.VNCAuthMode = ProtocolVNC.AuthMode.AuthVNC;
|
||||
node.VNCProxyType = ProtocolVNC.ProxyType.ProxyNone;
|
||||
node.Inheritance.TurnOffInheritanceCompletely();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
internal static List<string> BuildExpectedConnectionInfoPropertyList(ProtocolType protocol, bool isContainer)
|
||||
{
|
||||
var expectedProperties = new List<string>
|
||||
{
|
||||
nameof(ConnectionInfo.Name),
|
||||
nameof(ConnectionInfo.Description),
|
||||
nameof(ConnectionInfo.Icon),
|
||||
nameof(ConnectionInfo.Panel),
|
||||
nameof(ConnectionInfo.Protocol),
|
||||
nameof(ConnectionInfo.PreExtApp),
|
||||
nameof(ConnectionInfo.PostExtApp),
|
||||
nameof(ConnectionInfo.MacAddress),
|
||||
nameof(ConnectionInfo.UserField),
|
||||
};
|
||||
|
||||
if (!isContainer)
|
||||
{
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Hostname),
|
||||
});
|
||||
}
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case ProtocolType.RDP:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.UseConsoleSession),
|
||||
nameof(ConnectionInfo.RDPAuthenticationLevel),
|
||||
nameof(ConnectionInfo.RDPMinutesToIdleTimeout),
|
||||
nameof(ConnectionInfo.LoadBalanceInfo),
|
||||
nameof(ConnectionInfo.UseCredSsp),
|
||||
nameof(ConnectionInfo.RDGatewayUsageMethod),
|
||||
nameof(ConnectionInfo.Resolution),
|
||||
nameof(ConnectionInfo.Colors),
|
||||
nameof(ConnectionInfo.CacheBitmaps),
|
||||
nameof(ConnectionInfo.DisplayWallpaper),
|
||||
nameof(ConnectionInfo.DisplayThemes),
|
||||
nameof(ConnectionInfo.EnableFontSmoothing),
|
||||
nameof(ConnectionInfo.EnableDesktopComposition),
|
||||
nameof(ConnectionInfo.RedirectKeys),
|
||||
nameof(ConnectionInfo.RedirectDiskDrives),
|
||||
nameof(ConnectionInfo.RedirectPrinters),
|
||||
nameof(ConnectionInfo.RedirectPorts),
|
||||
nameof(ConnectionInfo.RedirectSmartCards),
|
||||
nameof(ConnectionInfo.RedirectSound),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.VNC:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.VNCSmartSizeMode),
|
||||
nameof(ConnectionInfo.VNCViewOnly),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.SSH1:
|
||||
case ProtocolType.SSH2:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.PuttySession)
|
||||
});
|
||||
break;
|
||||
case ProtocolType.Telnet:
|
||||
case ProtocolType.Rlogin:
|
||||
case ProtocolType.RAW:
|
||||
expectedProperties.AddRange(new[]
|
||||
{
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.PuttySession),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.HTTP:
|
||||
case ProtocolType.HTTPS:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.RenderingEngine),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.ICA:
|
||||
expectedProperties.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
nameof(ConnectionInfo.ICAEncryptionStrength),
|
||||
nameof(ConnectionInfo.Resolution),
|
||||
nameof(ConnectionInfo.Colors),
|
||||
nameof(ConnectionInfo.CacheBitmaps),
|
||||
});
|
||||
break;
|
||||
case ProtocolType.IntApp:
|
||||
expectedProperties.AddRange(new[]
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Password),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
nameof(ConnectionInfo.Port),
|
||||
nameof(ConnectionInfo.ExtApp),
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(protocol), protocol, null);
|
||||
}
|
||||
|
||||
return expectedProperties;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public class ConfigWindowRdpSpecialTests : ConfigWindowSpecialTestsBase
|
||||
{
|
||||
protected override ProtocolType Protocol => ProtocolType.RDP;
|
||||
|
||||
[Test]
|
||||
public void PropertyShownWhenActive_RdpMinutesToIdleTimeout()
|
||||
{
|
||||
ConnectionInfo.RDPMinutesToIdleTimeout = 1;
|
||||
ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.RDPAlertIdleTimeout));
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[TestCase(RdpProtocol.RDGatewayUsageMethod.Always)]
|
||||
[TestCase(RdpProtocol.RDGatewayUsageMethod.Detect)]
|
||||
public void RdGatewayPropertiesShown_WhenRdGatewayUsageMethodIsNotNever(RdpProtocol.RDGatewayUsageMethod gatewayUsageMethod)
|
||||
{
|
||||
ConnectionInfo.RDGatewayUsageMethod = gatewayUsageMethod;
|
||||
ConnectionInfo.RDGatewayUseConnectionCredentials = RdpProtocol.RDGatewayUseConnectionCredentials.Yes;
|
||||
ExpectedPropertyList.AddRange(new []
|
||||
{
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayHostname),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUseConnectionCredentials)
|
||||
});
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[TestCase(RdpProtocol.RDGatewayUseConnectionCredentials.No)]
|
||||
[TestCase(RdpProtocol.RDGatewayUseConnectionCredentials.SmartCard)]
|
||||
public void RdGatewayPropertiesShown_WhenRDGatewayUseConnectionCredentialsIsNotYes(RdpProtocol.RDGatewayUseConnectionCredentials useConnectionCredentials)
|
||||
{
|
||||
ConnectionInfo.RDGatewayUsageMethod = RdpProtocol.RDGatewayUsageMethod.Always;
|
||||
ConnectionInfo.RDGatewayUseConnectionCredentials = useConnectionCredentials;
|
||||
ExpectedPropertyList.AddRange(new []
|
||||
{
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayHostname),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUsername),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayPassword),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayDomain),
|
||||
nameof(mRemoteNG.Connection.ConnectionInfo.RDGatewayUseConnectionCredentials)
|
||||
});
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SoundQualityPropertyShown_WhenRdpSoundsSetToBringToThisComputer()
|
||||
{
|
||||
ConnectionInfo.RedirectSound = RdpProtocol.RDPSounds.BringToThisComputer;
|
||||
ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.SoundQuality));
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
|
||||
[TestCase(RdpProtocol.RDPResolutions.FitToWindow)]
|
||||
[TestCase(RdpProtocol.RDPResolutions.Fullscreen)]
|
||||
public void AutomaticResizePropertyShown_WhenResolutionIsDynamic(RdpProtocol.RDPResolutions resolution)
|
||||
{
|
||||
ConnectionInfo.Resolution = resolution;
|
||||
ExpectedPropertyList.Add(nameof(mRemoteNG.Connection.ConnectionInfo.AutomaticResize));
|
||||
|
||||
RunVerification();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.UI.Window;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public abstract class ConfigWindowSpecialTestsBase
|
||||
{
|
||||
protected abstract ProtocolType Protocol { get; }
|
||||
protected bool TestAgainstContainerInfo { get; set; } = false;
|
||||
protected ConfigWindow ConfigWindow;
|
||||
protected ConnectionInfo ConnectionInfo;
|
||||
protected List<string> ExpectedPropertyList;
|
||||
|
||||
[SetUp]
|
||||
public virtual void Setup()
|
||||
{
|
||||
ConnectionInfo = ConfigWindowGeneralTests.ConstructConnectionInfo(Protocol, TestAgainstContainerInfo);
|
||||
ExpectedPropertyList = ConfigWindowGeneralTests.BuildExpectedConnectionInfoPropertyList(Protocol, TestAgainstContainerInfo);
|
||||
|
||||
ConfigWindow = new ConfigWindow
|
||||
{
|
||||
PropertiesVisible = true,
|
||||
};
|
||||
}
|
||||
|
||||
public void RunVerification()
|
||||
{
|
||||
ConfigWindow.SelectedTreeNode = ConnectionInfo;
|
||||
Assert.That(
|
||||
ConfigWindow.VisibleObjectProperties,
|
||||
Is.EquivalentTo(ExpectedPropertyList));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.UI.Window.ConfigWindowTests
|
||||
{
|
||||
public class ConfigWindowVncSpecialTests : ConfigWindowSpecialTestsBase
|
||||
{
|
||||
protected override ProtocolType Protocol => ProtocolType.VNC;
|
||||
|
||||
[Test]
|
||||
public void UserDomainPropertiesShown_WhenAuthModeIsWindows()
|
||||
{
|
||||
ConnectionInfo.VNCAuthMode = ProtocolVNC.AuthMode.AuthWin;
|
||||
ExpectedPropertyList.AddRange(new []
|
||||
{
|
||||
nameof(ConnectionInfo.Username),
|
||||
nameof(ConnectionInfo.Domain),
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(ProtocolVNC.ProxyType.ProxyHTTP)]
|
||||
[TestCase(ProtocolVNC.ProxyType.ProxySocks5)]
|
||||
[TestCase(ProtocolVNC.ProxyType.ProxyUltra)]
|
||||
public void ProxyPropertiesShown_WhenProxyModeIsNotNone(ProtocolVNC.ProxyType proxyType)
|
||||
{
|
||||
ConnectionInfo.VNCProxyType = proxyType;
|
||||
ExpectedPropertyList.AddRange(new[]
|
||||
{
|
||||
nameof(ConnectionInfo.VNCProxyIP),
|
||||
nameof(ConnectionInfo.VNCProxyPort),
|
||||
nameof(ConnectionInfo.VNCProxyUsername),
|
||||
nameof(ConnectionInfo.VNCProxyPassword),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -108,6 +110,7 @@
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="App\ImportTests.cs" />
|
||||
<Compile Include="App\UpdaterTests.cs" />
|
||||
<Compile Include="BinaryFileTests.cs" />
|
||||
<Compile Include="Config\Connections\Multiuser\ConnectionsUpdateAvailableEventArgsTests.cs" />
|
||||
@@ -170,9 +173,12 @@
|
||||
<Compile Include="Security\PasswordCreation\PasswordLengthConstraintTests.cs" />
|
||||
<Compile Include="Security\RandomGeneratorTests.cs" />
|
||||
<Compile Include="Security\SecureStringExtensionsTests.cs" />
|
||||
<Compile Include="TestHelpers\ConnectionInfoHelpers.cs" />
|
||||
<Compile Include="TestHelpers\ConnectionTreeModelBuilder.cs" />
|
||||
<Compile Include="Security\XmlCryptoProviderBuilderTests.cs" />
|
||||
<Compile Include="TestHelpers\FileTestHelpers.cs" />
|
||||
<Compile Include="TestHelpers\SerializableConnectionInfoAllPropertiesOfType.cs" />
|
||||
<Compile Include="Tools\DisposableActionTests.cs" />
|
||||
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
|
||||
<Compile Include="Tools\FullyObservableCollectionTests.cs" />
|
||||
<Compile Include="Tools\OptionalTests.cs" />
|
||||
@@ -205,6 +211,7 @@
|
||||
<Compile Include="Tree\RootNodeInfoTests.cs" />
|
||||
<Compile Include="Tree\ClickHandlers\SwitchToConnectionClickHandlerTests.cs" />
|
||||
<Compile Include="Tree\SelectedConnectionDeletionConfirmerTests.cs" />
|
||||
<Compile Include="UI\Controls\ConnectionTreeTests.cs" />
|
||||
<Compile Include="UI\Controls\PageSequenceTests.cs" />
|
||||
<Compile Include="UI\Controls\SecureTextBoxTestForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -229,6 +236,10 @@
|
||||
<Compile Include="UI\Forms\OptionsFormSetupAndTeardown.cs" />
|
||||
<Compile Include="UI\Forms\PasswordFormTests.cs" />
|
||||
<Compile Include="UI\WindowListTests.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowGeneralTests.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowRdpSpecialTests.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowSpecialTestsBase.cs" />
|
||||
<Compile Include="UI\Window\ConfigWindowTests\ConfigWindowVncSpecialTests.cs" />
|
||||
<Compile Include="UI\Window\ConnectionTreeWindowTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -258,6 +269,8 @@
|
||||
<None Include="Resources\test_rdcman_v2_2_badschemaversion.rdg" />
|
||||
<None Include="Resources\test_rdcman_v2_2_schema1.rdg" />
|
||||
<None Include="Resources\test_RDCMan_v2_7_schema3.rdg" />
|
||||
<None Include="Resources\test_rdcman_v2_7_schema3_empty_values.rdg" />
|
||||
<None Include="Resources\test_rdcman_v2_7_schema3_null_values.rdg" />
|
||||
<None Include="Resources\test_remotedesktopconnection.rdp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2010
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29613.14
|
||||
MinimumVisualStudioVersion = 14.0.25420.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteV1", "mRemoteV1\mRemoteV1.csproj", "{4934A491-40BC-4E5B-9166-EA1169A220F6}"
|
||||
EndProject
|
||||
@@ -33,16 +33,19 @@ Global
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = Debug Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = Debug|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|Any CPU.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = Release Portable|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
@@ -50,24 +53,25 @@ Global
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.ActiveCfg = Release|x86
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.ActiveCfg = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|Any CPU.Build.0 = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = Debug Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|Any CPU.Build.0 = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = Debug|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|Any CPU.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.ActiveCfg = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = Release Portable|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|Any CPU.Build.0 = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.ActiveCfg = Release|x86
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|Any CPU.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.ActiveCfg = Debug|x86
|
||||
@@ -77,7 +81,6 @@ Global
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|Any CPU.Build.0 = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x86.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|Any CPU.Build.0 = Release|x86
|
||||
@@ -86,8 +89,8 @@ Global
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release Portable|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|Any CPU.Build.0 = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.ActiveCfg = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = Release|x86
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|Any CPU.ActiveCfg = Release Portable|x86
|
||||
@@ -102,7 +105,6 @@ Global
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|Any CPU.Build.0 = Release|Any CPU
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|x86.ActiveCfg = Release|Any CPU
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer|x86.Build.0 = Release|Any CPU
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Portable|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -19,13 +19,29 @@ namespace mRemoteNG.App
|
||||
|
||||
private static void CheckFipsPolicy(MessageCollector messageCollector)
|
||||
{
|
||||
if (Settings.Default.OverrideFIPSCheck)
|
||||
{
|
||||
messageCollector.AddMessage(MessageClass.InformationMsg, "OverrideFIPSCheck is set. Will skip check...", true);
|
||||
return;
|
||||
}
|
||||
|
||||
messageCollector.AddMessage(MessageClass.InformationMsg, "Checking FIPS Policy...", true);
|
||||
if (!FipsPolicyEnabledForServer2003() && !FipsPolicyEnabledForServer2008AndNewer()) return;
|
||||
var errorText = string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName,
|
||||
GeneralAppInfo.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
|
||||
var errorText = string.Format(Language.strErrorFipsPolicyIncompatible, GeneralAppInfo.ProductName);
|
||||
messageCollector.AddMessage(MessageClass.ErrorMsg, errorText, true);
|
||||
MessageBox.Show(FrmMain.Default, errorText);
|
||||
Environment.Exit(1);
|
||||
|
||||
var ShouldIStayOrShouldIGo = CTaskDialog.MessageBox(Application.ProductName, Language.strCompatibilityProblemDetected, errorText, "", "", Language.strCheckboxDoNotShowThisMessageAgain, ETaskDialogButtons.OkCancel, ESysIcons.Warning, ESysIcons.Warning);
|
||||
if (CTaskDialog.VerificationChecked && ShouldIStayOrShouldIGo == DialogResult.OK)
|
||||
{
|
||||
messageCollector.AddMessage(MessageClass.ErrorMsg, "User requests that FIPS check be overridden", true);
|
||||
Settings.Default.OverrideFIPSCheck = true;
|
||||
Settings.Default.Save();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldIStayOrShouldIGo == DialogResult.Cancel)
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
private static bool FipsPolicyEnabledForServer2003()
|
||||
|
||||
@@ -3,13 +3,14 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Config.Import;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
public static class Import
|
||||
public static class Import
|
||||
{
|
||||
public static void ImportFromFile(ContainerInfo importDestinationContainer)
|
||||
{
|
||||
@@ -35,22 +36,12 @@ namespace mRemoteNG.App
|
||||
if (openFileDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
foreach (var fileName in openFileDialog.FileNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
var importer = BuildConnectionImporterFromFileExtension(fileName);
|
||||
importer.Import(fileName, importDestinationContainer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(string.Format(Language.strImportFileFailedContent, fileName), Language.strImportFileFailedMainInstruction,
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
|
||||
Runtime.MessageCollector.AddExceptionMessage("Unable to import file.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Runtime.ConnectionsService.SaveConnectionsAsync();
|
||||
HeadlessFileImport(
|
||||
openFileDialog.FileNames,
|
||||
importDestinationContainer,
|
||||
Runtime.ConnectionsService,
|
||||
fileName => MessageBox.Show(string.Format(Language.strImportFileFailedContent, fileName), Language.strImportFileFailedMainInstruction,
|
||||
MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -59,12 +50,38 @@ namespace mRemoteNG.App
|
||||
}
|
||||
}
|
||||
|
||||
public static void HeadlessFileImport(
|
||||
IEnumerable<string> filePaths,
|
||||
ContainerInfo importDestinationContainer,
|
||||
ConnectionsService connectionsService,
|
||||
Action<string> exceptionAction = null)
|
||||
{
|
||||
using (connectionsService.BatchedSavingContext())
|
||||
{
|
||||
foreach (var fileName in filePaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
var importer = BuildConnectionImporterFromFileExtension(fileName);
|
||||
importer.Import(fileName, importDestinationContainer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
exceptionAction?.Invoke(fileName);
|
||||
Runtime.MessageCollector.AddExceptionMessage($"Error occurred while importing file '{fileName}'.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ImportFromActiveDirectory(string ldapPath, ContainerInfo importDestinationContainer, bool importSubOu)
|
||||
{
|
||||
try
|
||||
{
|
||||
ActiveDirectoryImporter.Import(ldapPath, importDestinationContainer, importSubOu);
|
||||
Runtime.ConnectionsService.SaveConnectionsAsync();
|
||||
using (Runtime.ConnectionsService.BatchedSavingContext())
|
||||
{
|
||||
ActiveDirectoryImporter.Import(ldapPath, importDestinationContainer, importSubOu);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -76,9 +93,11 @@ namespace mRemoteNG.App
|
||||
{
|
||||
try
|
||||
{
|
||||
var importer = new PortScanImporter(protocol);
|
||||
importer.Import(hosts, importDestinationContainer);
|
||||
Runtime.ConnectionsService.SaveConnectionsAsync();
|
||||
using (Runtime.ConnectionsService.BatchedSavingContext())
|
||||
{
|
||||
var importer = new PortScanImporter(protocol);
|
||||
importer.Import(hosts, importDestinationContainer);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Connection;
|
||||
|
||||
namespace mRemoteNG.App.Info
|
||||
{
|
||||
public static class SettingsFileInfo
|
||||
{
|
||||
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
|
||||
|
||||
public static string SettingsPath { get; } = Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
|
||||
public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
|
||||
public static string LayoutFileName { get; } = "pnlLayout.xml";
|
||||
public static string ExtAppsFilesName { get; } = "extApps.xml";
|
||||
public static string ThemesFileName { get; } = "Themes.xml";
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
@@ -17,10 +10,15 @@ using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.TaskDialog;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
public static class Runtime
|
||||
public static class Runtime
|
||||
{
|
||||
public static bool IsPortableEdition
|
||||
{
|
||||
@@ -45,19 +43,23 @@ namespace mRemoteNG.App
|
||||
#region Connections Loading/Saving
|
||||
public static void LoadConnectionsAsync()
|
||||
{
|
||||
_withDialog = false;
|
||||
|
||||
var t = new Thread(LoadConnectionsBGd);
|
||||
t.SetApartmentState(ApartmentState.STA);
|
||||
t.Start();
|
||||
}
|
||||
|
||||
private static bool _withDialog;
|
||||
private static void LoadConnectionsBGd()
|
||||
{
|
||||
LoadConnections(_withDialog);
|
||||
LoadConnections();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="withDialog">
|
||||
/// Should we show the file selection dialog to allow the user to select
|
||||
/// a connection file
|
||||
/// </param>
|
||||
public static void LoadConnections(bool withDialog = false)
|
||||
{
|
||||
var connectionFileName = "";
|
||||
@@ -67,24 +69,19 @@ namespace mRemoteNG.App
|
||||
// disable sql update checking while we are loading updates
|
||||
ConnectionsService.RemoteConnectionsSyncronizer?.Disable();
|
||||
|
||||
if (!Settings.Default.UseSQLServer)
|
||||
if (withDialog)
|
||||
{
|
||||
if (withDialog)
|
||||
{
|
||||
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
|
||||
if (loadDialog.ShowDialog() != DialogResult.OK) return;
|
||||
connectionFileName = loadDialog.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
|
||||
}
|
||||
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
|
||||
if (loadDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var backupFileCreator = new FileBackupCreator();
|
||||
backupFileCreator.CreateBackupFile(connectionFileName);
|
||||
|
||||
var backupPruner = new FileBackupPruner();
|
||||
backupPruner.PruneBackupFiles(connectionFileName);
|
||||
connectionFileName = loadDialog.FileName;
|
||||
Settings.Default.UseSQLServer = false;
|
||||
Settings.Default.Save();
|
||||
}
|
||||
else if (!Settings.Default.UseSQLServer)
|
||||
{
|
||||
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
|
||||
}
|
||||
|
||||
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
|
||||
@@ -93,18 +90,6 @@ namespace mRemoteNG.App
|
||||
{
|
||||
ConnectionsService.LastSqlUpdate = DateTime.Now;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (connectionFileName == ConnectionsService.GetDefaultStartupConnectionFileName())
|
||||
{
|
||||
Settings.Default.LoadConsFromCustomLocation = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Settings.Default.LoadConsFromCustomLocation = true;
|
||||
Settings.Default.CustomConsPath = connectionFileName;
|
||||
}
|
||||
}
|
||||
|
||||
// re-enable sql update checking after updates are loaded
|
||||
ConnectionsService.RemoteConnectionsSyncronizer?.Enable();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Window;
|
||||
using System;
|
||||
using System;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.UI;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Window;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
@@ -15,8 +15,14 @@ namespace mRemoteNG.App
|
||||
private static PortScanWindow _portscanForm;
|
||||
private static UltraVNCWindow _ultravncscForm;
|
||||
private static ComponentsCheckWindow _componentscheckForm;
|
||||
private static ConnectionTreeWindow _treeForm;
|
||||
|
||||
internal static ConnectionTreeWindow TreeForm
|
||||
{
|
||||
get => _treeForm ?? (_treeForm = new ConnectionTreeWindow());
|
||||
set => _treeForm = value;
|
||||
}
|
||||
|
||||
internal static ConnectionTreeWindow TreeForm { get; set; } = new ConnectionTreeWindow();
|
||||
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
|
||||
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
|
||||
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace mRemoteNG.Config.Connections
|
||||
_saveFilter = saveFilter;
|
||||
}
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel)
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
|
||||
var dataProvider = new FileDataProvider(_connectionFileName);
|
||||
|
||||
9
mRemoteV1/Config/Connections/IConnectionsLoader.cs
Normal file
9
mRemoteV1/Config/Connections/IConnectionsLoader.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using mRemoteNG.Tree;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public interface IConnectionsLoader
|
||||
{
|
||||
ConnectionTreeModel Load();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using mRemoteNG.App;
|
||||
using System;
|
||||
using System.Timers;
|
||||
using mRemoteNG.App;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.Config.Connections.Multiuser
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Threading;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
@@ -13,7 +13,7 @@ namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
private readonly SqlDatabaseConnector _sqlConnector;
|
||||
private readonly SqlCommand _sqlQuery;
|
||||
private DateTime _lastUpdateTime;
|
||||
private DateTime LastUpdateTime => Runtime.ConnectionsService.LastSqlUpdate;
|
||||
private DateTime _lastDatabaseUpdateTime;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
_sqlConnector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings();
|
||||
_sqlQuery = new SqlCommand("SELECT * FROM tblUpdate", _sqlConnector.SqlConnection);
|
||||
_lastUpdateTime = default(DateTime);
|
||||
_lastDatabaseUpdateTime = default(DateTime);
|
||||
}
|
||||
|
||||
@@ -58,14 +57,14 @@ namespace mRemoteNG.Config.Connections
|
||||
private bool DatabaseIsMoreUpToDateThanUs()
|
||||
{
|
||||
var lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
|
||||
var IAmTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
|
||||
return (lastUpdateInDb > _lastUpdateTime && !IAmTheLastoneUpdated);
|
||||
var amTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
|
||||
return (lastUpdateInDb > LastUpdateTime && !amTheLastoneUpdated);
|
||||
}
|
||||
|
||||
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
|
||||
{
|
||||
DateTime LastSqlUpdateWithoutMilliseconds = new DateTime(Runtime.ConnectionsService.LastSqlUpdate.Ticks - (Runtime.ConnectionsService.LastSqlUpdate.Ticks % TimeSpan.TicksPerSecond), Runtime.ConnectionsService.LastSqlUpdate.Kind);
|
||||
return lastUpdateInDb == LastSqlUpdateWithoutMilliseconds;
|
||||
DateTime lastSqlUpdateWithoutMilliseconds = new DateTime(LastUpdateTime.Ticks - (LastUpdateTime.Ticks % TimeSpan.TicksPerSecond), LastUpdateTime.Kind);
|
||||
return lastUpdateInDb == lastSqlUpdateWithoutMilliseconds;
|
||||
}
|
||||
|
||||
private DateTime GetLastUpdateTimeFromDbResponse()
|
||||
@@ -104,10 +103,9 @@ namespace mRemoteNG.Config.Connections
|
||||
public event ConnectionsUpdateAvailableEventHandler ConnectionsUpdateAvailable;
|
||||
private void RaiseConnectionsUpdateAvailableEvent()
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Remote connection update is available");
|
||||
var args = new ConnectionsUpdateAvailableEventArgs(_sqlConnector, _lastDatabaseUpdateTime);
|
||||
ConnectionsUpdateAvailable?.Invoke(this, args);
|
||||
if(args.Handled)
|
||||
_lastUpdateTime = _lastDatabaseUpdateTime;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
@@ -20,10 +21,9 @@ namespace mRemoteNG.Config.Connections
|
||||
|
||||
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
|
||||
{
|
||||
|
||||
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
|
||||
|
||||
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
|
||||
{
|
||||
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
|
||||
@@ -33,7 +33,7 @@ namespace mRemoteNG.Config.Connections
|
||||
|
||||
private void ConnectionTreeModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
|
||||
{
|
||||
SaveConnectionOnEdit();
|
||||
SaveConnectionOnEdit(propertyChangedEventArgs.PropertyName);
|
||||
}
|
||||
|
||||
private void ConnectionTreeModelOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
|
||||
@@ -41,11 +41,14 @@ namespace mRemoteNG.Config.Connections
|
||||
SaveConnectionOnEdit();
|
||||
}
|
||||
|
||||
private void SaveConnectionOnEdit()
|
||||
private void SaveConnectionOnEdit(string propertyName = "")
|
||||
{
|
||||
if (!mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit)
|
||||
return;
|
||||
_connectionsService.SaveConnections();
|
||||
if (FrmMain.Default.IsClosing)
|
||||
return;
|
||||
|
||||
_connectionsService.SaveConnectionsAsync(propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,96 @@
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class SqlConnectionsLoader
|
||||
public class SqlConnectionsLoader : IConnectionsLoader
|
||||
{
|
||||
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; } =
|
||||
() => MiscTools.PasswordDialog("", false);
|
||||
|
||||
public SqlConnectionsLoader(
|
||||
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
|
||||
IDataProvider<string> dataProvider)
|
||||
{
|
||||
_localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
|
||||
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Load()
|
||||
{
|
||||
var connector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings();
|
||||
var dataProvider = new SqlDataProvider(connector);
|
||||
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
|
||||
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(connector);
|
||||
databaseVersionVerifier.VerifyDatabaseVersion();
|
||||
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
|
||||
|
||||
var metaData = metaDataRetriever.GetDatabaseMetaData(connector) ??
|
||||
HandleFirstRun(metaDataRetriever, connector);
|
||||
var 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();
|
||||
return deserializer.Deserialize(dataTable);
|
||||
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
|
||||
var 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());
|
||||
|
||||
if (authenticated)
|
||||
return authenticator.LastAuthenticatedPassword;
|
||||
return Optional<SecureString>.Empty;
|
||||
}
|
||||
|
||||
private void ApplyLocalConnectionProperties(ContainerInfo rootNode)
|
||||
{
|
||||
var localPropertiesXml = _dataProvider.Load();
|
||||
var localConnectionProperties = _localConnectionPropertiesDeserializer.Deserialize(localPropertiesXml);
|
||||
|
||||
rootNode
|
||||
.GetRecursiveChildList()
|
||||
.Join(localConnectionProperties,
|
||||
con => con.ConstantID,
|
||||
locals => locals.ConnectionId,
|
||||
(con, locals) => new {Connection = con, LocalProperties = locals})
|
||||
.ForEach(x =>
|
||||
{
|
||||
x.Connection.PleaseConnect = x.LocalProperties.Connected;
|
||||
if (x.Connection is ContainerInfo container)
|
||||
container.IsExpanded = x.LocalProperties.Expanded;
|
||||
});
|
||||
}
|
||||
|
||||
private SqlConnectionListMetaData HandleFirstRun(SqlDatabaseMetaDataRetriever metaDataRetriever, SqlDatabaseConnector connector)
|
||||
{
|
||||
metaDataRetriever.WriteDatabaseMetaData(new RootNodeInfo(RootNodeType.Connection), connector);
|
||||
return metaDataRetriever.GetDatabaseMetaData(connector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Config.Serializers.Versioning;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
@@ -19,44 +21,90 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
|
||||
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
|
||||
{
|
||||
private SecureString _password = Runtime.EncryptionKey;
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer;
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
|
||||
public SqlConnectionsSaver(SaveFilter saveFilter)
|
||||
public SqlConnectionsSaver(
|
||||
SaveFilter saveFilter,
|
||||
ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> localPropertieSerializer,
|
||||
IDataProvider<string> localPropertiesDataProvider)
|
||||
{
|
||||
if (saveFilter == null)
|
||||
throw new ArgumentNullException(nameof(saveFilter));
|
||||
_saveFilter = saveFilter;
|
||||
_localPropertiesSerializer = localPropertieSerializer.ThrowIfNull(nameof(localPropertieSerializer));
|
||||
_dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
|
||||
}
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel)
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
|
||||
|
||||
UpdateLocalConnectionProperties(rootTreeNode);
|
||||
|
||||
if (PropertyIsLocalOnly(propertyNameTrigger))
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
|
||||
$"Property {propertyNameTrigger} is local only. Not saving to database.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SqlUserIsReadOnly())
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Trying to save connection tree but the SQL read only checkbox is checked, aborting!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
using (var sqlConnector = DatabaseConnectorFactory.SqlDatabaseConnectorFromSettings())
|
||||
{
|
||||
sqlConnector.Connect();
|
||||
var databaseVersionVerifier = new SqlDatabaseVersionVerifier(sqlConnector);
|
||||
var metaDataRetriever = new SqlDatabaseMetaDataRetriever();
|
||||
var metaData = metaDataRetriever.GetDatabaseMetaData(sqlConnector);
|
||||
|
||||
if (!databaseVersionVerifier.VerifyDatabaseVersion())
|
||||
if (!databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion))
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strErrorConnectionListSaveFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
|
||||
|
||||
UpdateRootNodeTable(rootTreeNode, sqlConnector);
|
||||
metaDataRetriever.WriteDatabaseMetaData(rootTreeNode, sqlConnector);
|
||||
UpdateConnectionsTable(rootTreeNode, sqlConnector);
|
||||
UpdateUpdatesTable(sqlConnector);
|
||||
}
|
||||
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Saved connections to database");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a given property name should be only saved
|
||||
/// locally.
|
||||
/// </summary>
|
||||
/// <param name="property">
|
||||
/// The name of the property that triggered the save event
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
private bool PropertyIsLocalOnly(string property)
|
||||
{
|
||||
return property == nameof(ConnectionInfo.OpenConnections) ||
|
||||
property == nameof(ContainerInfo.IsExpanded);
|
||||
}
|
||||
|
||||
private void UpdateLocalConnectionProperties(ContainerInfo rootNode)
|
||||
{
|
||||
var a = rootNode.GetRecursiveChildList().Select(info => new LocalConnectionPropertiesModel
|
||||
{
|
||||
ConnectionId = info.ConstantID,
|
||||
Connected = info.OpenConnections.Count > 0,
|
||||
Expanded = info is ContainerInfo c && c.IsExpanded
|
||||
});
|
||||
|
||||
var serializedProperties = _localPropertiesSerializer.Serialize(a);
|
||||
_dataProvider.Save(serializedProperties);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, "Saved local connection properties");
|
||||
}
|
||||
|
||||
private void UpdateRootNodeTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
|
||||
@@ -67,17 +115,17 @@ namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
if (rootTreeNode.Password)
|
||||
{
|
||||
_password = rootTreeNode.PasswordString.ConvertToSecureString();
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", _password);
|
||||
var password = rootTreeNode.PasswordString.ConvertToSecureString();
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", password);
|
||||
}
|
||||
else
|
||||
{
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _password);
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", _password);
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", Runtime.EncryptionKey);
|
||||
}
|
||||
|
||||
var sqlQuery = new SqlCommand("DELETE FROM tblRoot", sqlDatabaseConnector.SqlConnection);
|
||||
@@ -99,13 +147,15 @@ namespace mRemoteNG.Config.Connections
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateConnectionsTable(ContainerInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
|
||||
private void UpdateConnectionsTable(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
|
||||
{
|
||||
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
|
||||
sqlQuery.ExecuteNonQuery();
|
||||
var serializer = new DataTableSerializer(_saveFilter);
|
||||
var cryptoProvider = new LegacyRijndaelCryptographyProvider();
|
||||
var serializer = new DataTableSerializer(_saveFilter, cryptoProvider, rootTreeNode.PasswordString.ConvertToSecureString());
|
||||
var dataTable = serializer.Serialize(rootTreeNode);
|
||||
var dataProvider = new SqlDataProvider(sqlDatabaseConnector);
|
||||
|
||||
var sqlQuery = new SqlCommand("DELETE FROM tblCons", sqlDatabaseConnector.SqlConnection);
|
||||
sqlQuery.ExecuteNonQuery();
|
||||
dataProvider.Save(dataTable);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using System;
|
||||
using System.IO;
|
||||
using mRemoteNG.Config.Serializers.Xml;
|
||||
using System.Security;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class XmlConnectionsLoader
|
||||
public class XmlConnectionsLoader : IConnectionsLoader
|
||||
{
|
||||
private readonly string _connectionFilePath;
|
||||
|
||||
@@ -32,7 +31,7 @@ namespace mRemoteNG.Config.Connections
|
||||
return deserializer.Deserialize(xmlString);
|
||||
}
|
||||
|
||||
private SecureString PromptForPassword()
|
||||
private Optional<SecureString> PromptForPassword()
|
||||
{
|
||||
var password = MiscTools.PasswordDialog("", false);
|
||||
return password;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace mRemoteNG.Config.Connections
|
||||
_saveFilter = saveFilter;
|
||||
}
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel)
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace mRemoteNG.Config
|
||||
_dataProvider = dataProvider;
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<ICredentialRepository> repositories)
|
||||
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
|
||||
{
|
||||
var serializer = new CredentialRepositoryListSerializer();
|
||||
var data = serializer.Serialize(repositories);
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
public class FileBackupPruner
|
||||
{
|
||||
public void PruneBackupFiles(string baseName)
|
||||
public void PruneBackupFiles(string filePath, int maxBackupsToKeep)
|
||||
{
|
||||
var fileName = Path.GetFileName(baseName);
|
||||
var directoryName = Path.GetDirectoryName(baseName);
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
var directoryName = Path.GetDirectoryName(filePath);
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName)) return;
|
||||
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(directoryName))
|
||||
return;
|
||||
|
||||
var searchPattern = string.Format(mRemoteNG.Settings.Default.BackupFileNameFormat, fileName, "*");
|
||||
var files = Directory.GetFiles(directoryName, searchPattern);
|
||||
|
||||
if (files.Length <= mRemoteNG.Settings.Default.BackupFileKeepCount) return;
|
||||
if (files.Length <= maxBackupsToKeep)
|
||||
return;
|
||||
|
||||
Array.Sort(files);
|
||||
Array.Resize(ref files, files.Length - mRemoteNG.Settings.Default.BackupFileKeepCount);
|
||||
var filesToDelete = files
|
||||
.OrderByDescending(s => s)
|
||||
.Skip(maxBackupsToKeep);
|
||||
|
||||
foreach (var file in files)
|
||||
foreach (var file in filesToDelete)
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
{
|
||||
public interface ISaver<in T>
|
||||
{
|
||||
void Save(T model);
|
||||
void Save(T model, string propertyNameTrigger = "");
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using mRemoteNG.Tools;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree.Root;
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
public class PuttySessionsManager
|
||||
public class PuttySessionsManager
|
||||
{
|
||||
public static PuttySessionsManager Instance { get; } = new PuttySessionsManager();
|
||||
|
||||
@@ -35,10 +35,12 @@ namespace mRemoteNG.Config.Putty
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSessionsFromProvider(AbstractPuttySessionsProvider provider)
|
||||
private void AddSessionsFromProvider(AbstractPuttySessionsProvider puttySessionProvider)
|
||||
{
|
||||
var rootTreeNode = provider.RootInfo;
|
||||
provider.GetSessions();
|
||||
puttySessionProvider.ThrowIfNull(nameof(puttySessionProvider));
|
||||
|
||||
var rootTreeNode = puttySessionProvider.RootInfo;
|
||||
puttySessionProvider.GetSessions();
|
||||
|
||||
if (!RootPuttySessionsNodes.Contains(rootTreeNode) && rootTreeNode.HasChildren())
|
||||
RootPuttySessionsNodes.Add(rootTreeNode);
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using Microsoft.Win32;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Microsoft.Win32;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
|
||||
|
||||
namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider
|
||||
public class PuttySessionsRegistryProvider : AbstractPuttySessionsProvider
|
||||
{
|
||||
private const string PuttySessionsKey = "Software\\SimonTatham\\PuTTY\\Sessions";
|
||||
private static ManagementEventWatcher _eventWatcher;
|
||||
@@ -39,7 +39,10 @@ namespace mRemoteNG.Config.Putty
|
||||
}
|
||||
|
||||
public override PuttySessionInfo GetSession(string sessionName)
|
||||
{
|
||||
{
|
||||
if (string.IsNullOrEmpty(sessionName))
|
||||
return null;
|
||||
|
||||
var sessionsKey = Registry.CurrentUser.OpenSubKey(PuttySessionsKey);
|
||||
var sessionKey = sessionsKey?.OpenSubKey(sessionName);
|
||||
if (sessionKey == null) return null;
|
||||
@@ -50,10 +53,15 @@ namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
PuttySession = sessionName,
|
||||
Name = sessionName,
|
||||
Hostname = Convert.ToString(sessionKey.GetValue("HostName")),
|
||||
Username = Convert.ToString(sessionKey.GetValue("UserName"))
|
||||
Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "",
|
||||
Username = sessionKey.GetValue("UserName")?.ToString() ?? ""
|
||||
};
|
||||
var protocol = Convert.ToString(sessionKey.GetValue("Protocol")) ?? "ssh";
|
||||
|
||||
|
||||
var protocol = string.IsNullOrEmpty(sessionKey.GetValue("Protocol")?.ToString())
|
||||
? "ssh"
|
||||
: sessionKey.GetValue("Protocol").ToString();
|
||||
|
||||
switch (protocol.ToLowerInvariant())
|
||||
{
|
||||
case "raw":
|
||||
@@ -65,16 +73,15 @@ namespace mRemoteNG.Config.Putty
|
||||
case "serial":
|
||||
return null;
|
||||
case "ssh":
|
||||
var sshVersionObject = sessionKey.GetValue("SshProt");
|
||||
if (sshVersionObject != null)
|
||||
{
|
||||
var sshVersion = Convert.ToInt32(sshVersionObject);
|
||||
sessionInfo.Protocol = sshVersion >= 2 ? ProtocolType.SSH2 : ProtocolType.SSH1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sessionInfo.Protocol = ProtocolType.SSH2;
|
||||
}
|
||||
int.TryParse(sessionKey.GetValue("SshProt")?.ToString(), out var sshVersion);
|
||||
/* Per PUTTY.H in PuTTYNG & PuTTYNG Upstream (PuTTY proper currently)
|
||||
* expect 0 for SSH1, 3 for SSH2 ONLY
|
||||
* 1 for SSH1 with a 2 fallback
|
||||
* 2 for SSH2 with a 1 fallback
|
||||
*
|
||||
* default to SSH2 if any other value is received
|
||||
*/
|
||||
sessionInfo.Protocol = sshVersion == 1 || sshVersion == 0 ? ProtocolType.SSH1 : ProtocolType.SSH2;
|
||||
break;
|
||||
case "telnet":
|
||||
sessionInfo.Protocol = ProtocolType.Telnet;
|
||||
@@ -82,7 +89,12 @@ namespace mRemoteNG.Config.Putty
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
sessionInfo.Port = Convert.ToInt32(sessionKey.GetValue("PortNumber"));
|
||||
|
||||
int.TryParse(sessionKey.GetValue("PortNumber")?.ToString(), out var portNumber);
|
||||
if (portNumber == default(int))
|
||||
sessionInfo.SetDefaultPort();
|
||||
else
|
||||
sessionInfo.Port = portNumber;
|
||||
|
||||
return sessionInfo;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace mRemoteNG.Config.Putty
|
||||
foreach (var sessionName in Directory.GetFiles(sessionsFolderPath))
|
||||
{
|
||||
var sessionFileName = Path.GetFileName(sessionName);
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
sessionNames.Add(raw ? sessionFileName : System.Web.HttpUtility.UrlDecode(sessionFileName?.Replace("+", "%2B")));
|
||||
}
|
||||
|
||||
@@ -125,9 +126,6 @@ namespace mRemoteNG.Config.Putty
|
||||
|
||||
public override void StartWatcher()
|
||||
{
|
||||
PuttySessionsRegistryProvider.StartWatcher();
|
||||
PuttySessionsRegistryProvider.PuttySessionChanged += OnRegistrySessionChanged;
|
||||
|
||||
if (_eventWatcher != null)
|
||||
{
|
||||
return;
|
||||
@@ -136,18 +134,22 @@ namespace mRemoteNG.Config.Putty
|
||||
try
|
||||
{
|
||||
var sessionsFolderPath = GetSessionsFolderPath();
|
||||
if (Directory.Exists(sessionsFolderPath))
|
||||
{
|
||||
_eventWatcher = new FileSystemWatcher(sessionsFolderPath)
|
||||
{
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
|
||||
};
|
||||
_eventWatcher.Changed += OnFileSystemEventArrived;
|
||||
_eventWatcher.Created += OnFileSystemEventArrived;
|
||||
_eventWatcher.Deleted += OnFileSystemEventArrived;
|
||||
_eventWatcher.Renamed += OnFileSystemEventArrived;
|
||||
_eventWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(sessionsFolderPath))
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"XmingPortablePuttySessions.Watcher.StartWatching() failed: '{sessionsFolderPath}' does not exist.", true);
|
||||
return;
|
||||
}
|
||||
|
||||
_eventWatcher = new FileSystemWatcher(sessionsFolderPath)
|
||||
{
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite
|
||||
};
|
||||
_eventWatcher.Changed += OnFileSystemEventArrived;
|
||||
_eventWatcher.Created += OnFileSystemEventArrived;
|
||||
_eventWatcher.Deleted += OnFileSystemEventArrived;
|
||||
_eventWatcher.Renamed += OnFileSystemEventArrived;
|
||||
_eventWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -173,7 +175,8 @@ namespace mRemoteNG.Config.Putty
|
||||
private static string GetPuttyConfPath()
|
||||
{
|
||||
var puttyPath = mRemoteNG.Settings.Default.UseCustomPuttyPath ? mRemoteNG.Settings.Default.CustomPuttyPath : App.Info.GeneralAppInfo.PuttyPath;
|
||||
return Path.Combine(Path.GetDirectoryName(puttyPath), "putty.conf");
|
||||
puttyPath = Path.GetDirectoryName(puttyPath);
|
||||
return string.IsNullOrEmpty(puttyPath) ? null : Path.Combine(puttyPath, "putty.conf");
|
||||
}
|
||||
|
||||
private static string GetSessionsFolderPath()
|
||||
@@ -200,6 +203,9 @@ namespace mRemoteNG.Config.Putty
|
||||
|
||||
private static PuttySessionInfo ModifyRegistrySessionInfo(PuttySessionInfo sessionInfo)
|
||||
{
|
||||
if (sessionInfo == null)
|
||||
return null;
|
||||
|
||||
sessionInfo.Name = string.Format(RegistrySessionNameFormat, sessionInfo.Name);
|
||||
sessionInfo.PuttySession = string.Format(RegistrySessionNameFormat, sessionInfo.PuttySession);
|
||||
return sessionInfo;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
@@ -12,11 +8,28 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
|
||||
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _decryptionKey;
|
||||
|
||||
public DataTableDeserializer(ICryptographyProvider cryptographyProvider, SecureString decryptionKey)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Deserialize(DataTable table)
|
||||
{
|
||||
var connectionList = CreateNodesFromTable(table);
|
||||
@@ -34,10 +47,10 @@ namespace mRemoteNG.Config.Serializers
|
||||
switch ((string)row["Type"])
|
||||
{
|
||||
case "Connection":
|
||||
nodeList.Add(DeserializeConnectionInfo(row));
|
||||
nodeList.Add(DeserializeConnectionInfo(row));
|
||||
break;
|
||||
case "Container":
|
||||
nodeList.Add(DeserializeContainerInfo(row));
|
||||
nodeList.Add(DeserializeContainerInfo(row));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -68,16 +81,12 @@ namespace mRemoteNG.Config.Serializers
|
||||
// The Parent object is linked properly later in CreateNodeHierarchy()
|
||||
//connectionInfo.Parent.ConstantID = (string)dataRow["ParentID"];
|
||||
|
||||
var info = connectionInfo as ContainerInfo;
|
||||
if(info != null)
|
||||
info.IsExpanded = (bool)dataRow["Expanded"];
|
||||
|
||||
connectionInfo.Description = (string)dataRow["Description"];
|
||||
connectionInfo.Icon = (string)dataRow["Icon"];
|
||||
connectionInfo.Panel = (string)dataRow["Panel"];
|
||||
connectionInfo.Username = (string)dataRow["Username"];
|
||||
connectionInfo.Domain = (string)dataRow["DomainName"];
|
||||
connectionInfo.Password = (string)dataRow["Password"];
|
||||
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
|
||||
connectionInfo.Hostname = (string)dataRow["Hostname"];
|
||||
connectionInfo.Protocol = (ProtocolType)Enum.Parse(typeof(ProtocolType), (string)dataRow["Protocol"]);
|
||||
connectionInfo.PuttySession = (string)dataRow["PuttySession"];
|
||||
@@ -105,7 +114,6 @@ namespace mRemoteNG.Config.Serializers
|
||||
connectionInfo.RedirectSound = (RdpProtocol.RDPSounds)Enum.Parse(typeof(RdpProtocol.RDPSounds), (string)dataRow["RedirectSound"]);
|
||||
connectionInfo.SoundQuality = (RdpProtocol.RDPSoundQuality)Enum.Parse(typeof(RdpProtocol.RDPSoundQuality), (string)dataRow["SoundQuality"]);
|
||||
connectionInfo.RedirectKeys = (bool)dataRow["RedirectKeys"];
|
||||
connectionInfo.PleaseConnect = (bool)dataRow["Connected"];
|
||||
connectionInfo.PreExtApp = (string)dataRow["PreExtApp"];
|
||||
connectionInfo.PostExtApp = (string)dataRow["PostExtApp"];
|
||||
connectionInfo.MacAddress = (string)dataRow["MacAddress"];
|
||||
@@ -118,7 +126,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
connectionInfo.VNCProxyIP = (string)dataRow["VNCProxyIP"];
|
||||
connectionInfo.VNCProxyPort = (int)dataRow["VNCProxyPort"];
|
||||
connectionInfo.VNCProxyUsername = (string)dataRow["VNCProxyUsername"];
|
||||
connectionInfo.VNCProxyPassword = (string)dataRow["VNCProxyPassword"];
|
||||
connectionInfo.VNCProxyPassword = DecryptValue((string)dataRow["VNCProxyPassword"]);
|
||||
connectionInfo.VNCColors = (ProtocolVNC.Colors)Enum.Parse(typeof(ProtocolVNC.Colors), (string)dataRow["VNCColors"]);
|
||||
connectionInfo.VNCSmartSizeMode = (ProtocolVNC.SmartSizeMode)Enum.Parse(typeof(ProtocolVNC.SmartSizeMode), (string)dataRow["VNCSmartSizeMode"]);
|
||||
connectionInfo.VNCViewOnly = (bool)dataRow["VNCViewOnly"];
|
||||
@@ -126,7 +134,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
connectionInfo.RDGatewayHostname = (string)dataRow["RDGatewayHostname"];
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = (RdpProtocol.RDGatewayUseConnectionCredentials)Enum.Parse(typeof(RdpProtocol.RDGatewayUseConnectionCredentials), (string)dataRow["RDGatewayUseConnectionCredentials"]);
|
||||
connectionInfo.RDGatewayUsername = (string)dataRow["RDGatewayUsername"];
|
||||
connectionInfo.RDGatewayPassword = (string)dataRow["RDGatewayPassword"];
|
||||
connectionInfo.RDGatewayPassword = DecryptValue((string)dataRow["RDGatewayPassword"]);
|
||||
connectionInfo.RDGatewayDomain = (string)dataRow["RDGatewayDomain"];
|
||||
|
||||
connectionInfo.Inheritance.CacheBitmaps = (bool)dataRow["InheritCacheBitmaps"];
|
||||
@@ -185,10 +193,26 @@ namespace mRemoteNG.Config.Serializers
|
||||
connectionInfo.Inheritance.RDGatewayDomain = (bool)dataRow["InheritRDGatewayDomain"];
|
||||
}
|
||||
|
||||
private string DecryptValue(string cipherText)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _cryptographyProvider.Decrypt(cipherText, _decryptionKey);
|
||||
}
|
||||
catch (EncryptionException)
|
||||
{
|
||||
// value may not be encrypted
|
||||
return cipherText;
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectionTreeModel CreateNodeHierarchy(List<ConnectionInfo> connectionList, DataTable dataTable)
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0");
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0")
|
||||
{
|
||||
PasswordString = _decryptionKey.ConvertToUnsecureString()
|
||||
};
|
||||
connectionTreeModel.AddRootNode(rootNode);
|
||||
|
||||
foreach (DataRow row in dataTable.Rows)
|
||||
@@ -1,25 +1,31 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class DataTableSerializer : ISerializer<ConnectionInfo,DataTable>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _encryptionKey;
|
||||
private DataTable _dataTable;
|
||||
private const string TableName = "tblCons";
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private int _currentNodeIndex;
|
||||
|
||||
public DataTableSerializer(SaveFilter saveFilter)
|
||||
public DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey)
|
||||
{
|
||||
_saveFilter = saveFilter;
|
||||
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_encryptionKey = encryptionKey.ThrowIfNull(nameof(encryptionKey));
|
||||
}
|
||||
|
||||
|
||||
@@ -204,14 +210,15 @@ namespace mRemoteNG.Config.Serializers
|
||||
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
|
||||
dataRow["PositionID"] = _currentNodeIndex;
|
||||
dataRow["LastChange"] = (SqlDateTime)DateTime.Now;
|
||||
var info = connectionInfo as ContainerInfo;
|
||||
dataRow["Expanded"] = info != null && info.IsExpanded;
|
||||
dataRow["Expanded"] = false; // TODO: this column can eventually be removed. we now save this property locally
|
||||
dataRow["Description"] = connectionInfo.Description;
|
||||
dataRow["Icon"] = connectionInfo.Icon;
|
||||
dataRow["Panel"] = connectionInfo.Panel;
|
||||
dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : "";
|
||||
dataRow["DomainName"] = _saveFilter.SaveDomain ? connectionInfo.Domain : "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword ? connectionInfo.Password : "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword
|
||||
? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)
|
||||
: "";
|
||||
dataRow["Hostname"] = connectionInfo.Hostname;
|
||||
dataRow["Protocol"] = connectionInfo.Protocol;
|
||||
dataRow["PuttySession"] = connectionInfo.PuttySession;
|
||||
@@ -239,7 +246,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
dataRow["RedirectSound"] = connectionInfo.RedirectSound;
|
||||
dataRow["SoundQuality"] = connectionInfo.SoundQuality;
|
||||
dataRow["RedirectKeys"] = connectionInfo.RedirectKeys;
|
||||
dataRow["Connected"] = connectionInfo.OpenConnections.Count > 0;
|
||||
dataRow["Connected"] = false; // TODO: this column can eventually be removed. we now save this property locally
|
||||
dataRow["PreExtApp"] = connectionInfo.PreExtApp;
|
||||
dataRow["PostExtApp"] = connectionInfo.PostExtApp;
|
||||
dataRow["MacAddress"] = connectionInfo.MacAddress;
|
||||
@@ -252,7 +259,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
dataRow["VNCProxyIP"] = connectionInfo.VNCProxyIP;
|
||||
dataRow["VNCProxyPort"] = connectionInfo.VNCProxyPort;
|
||||
dataRow["VNCProxyUsername"] = connectionInfo.VNCProxyUsername;
|
||||
dataRow["VNCProxyPassword"] = connectionInfo.VNCProxyPassword;
|
||||
dataRow["VNCProxyPassword"] = _cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey);
|
||||
dataRow["VNCColors"] = connectionInfo.VNCColors;
|
||||
dataRow["VNCSmartSizeMode"] = connectionInfo.VNCSmartSizeMode;
|
||||
dataRow["VNCViewOnly"] = connectionInfo.VNCViewOnly;
|
||||
@@ -260,7 +267,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
dataRow["RDGatewayHostname"] = connectionInfo.RDGatewayHostname;
|
||||
dataRow["RDGatewayUseConnectionCredentials"] = connectionInfo.RDGatewayUseConnectionCredentials;
|
||||
dataRow["RDGatewayUsername"] = connectionInfo.RDGatewayUsername;
|
||||
dataRow["RDGatewayPassword"] = connectionInfo.RDGatewayPassword;
|
||||
dataRow["RDGatewayPassword"] = _cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey);
|
||||
dataRow["RDGatewayDomain"] = connectionInfo.RDGatewayDomain;
|
||||
if (_saveFilter.SaveInheritance)
|
||||
{
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class LocalConnectionPropertiesModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique Id of this tree node
|
||||
/// </summary>
|
||||
public string ConnectionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this connection is connected
|
||||
/// </summary>
|
||||
public bool Connected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this container is expanded in the tree
|
||||
/// </summary>
|
||||
public bool Expanded { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class LocalConnectionPropertiesXmlSerializer :
|
||||
ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string>,
|
||||
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>>
|
||||
{
|
||||
public string Serialize(IEnumerable<LocalConnectionPropertiesModel> models)
|
||||
{
|
||||
var localConnections = models
|
||||
.Select(m => new XElement("Node",
|
||||
new XAttribute("ConnectionId", m.ConnectionId),
|
||||
new XAttribute("Connected", m.Connected),
|
||||
new XAttribute("Expanded", m.Expanded)));
|
||||
|
||||
var root = new XElement("LocalConnections", localConnections);
|
||||
var xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), root);
|
||||
return WriteXmlToString(xdoc);
|
||||
}
|
||||
|
||||
public IEnumerable<LocalConnectionPropertiesModel> Deserialize(string serializedData)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(serializedData))
|
||||
return Enumerable.Empty<LocalConnectionPropertiesModel>();
|
||||
|
||||
var xdoc = XDocument.Parse(serializedData);
|
||||
return xdoc
|
||||
.Descendants("Node")
|
||||
.Where(e => e.Attribute("ConnectionId") != null)
|
||||
.Select(e => new LocalConnectionPropertiesModel
|
||||
{
|
||||
ConnectionId = e.Attribute("ConnectionId")?.Value,
|
||||
Connected = bool.Parse(e.Attribute("Connected")?.Value ?? "False"),
|
||||
Expanded = bool.Parse(e.Attribute("Expanded")?.Value ?? "False")
|
||||
});
|
||||
}
|
||||
|
||||
private static string WriteXmlToString(XNode xmlDocument)
|
||||
{
|
||||
string xmlString;
|
||||
var xmlWriterSettings = new XmlWriterSettings { Indent = true, IndentChars = " ", Encoding = Encoding.UTF8 };
|
||||
var memoryStream = new MemoryStream();
|
||||
using (var xmlTextWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
|
||||
{
|
||||
xmlDocument.WriteTo(xmlTextWriter);
|
||||
xmlTextWriter.Flush();
|
||||
var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true);
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
xmlString = streamReader.ReadToEnd();
|
||||
}
|
||||
return xmlString;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class SqlConnectionListMetaData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Protected { get; set; }
|
||||
public bool Export { get; set; }
|
||||
public Version ConfVersion { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MsSql
|
||||
{
|
||||
public class SqlDatabaseMetaDataRetriever
|
||||
{
|
||||
public SqlConnectionListMetaData GetDatabaseMetaData(SqlDatabaseConnector sqlDatabaseConnector)
|
||||
{
|
||||
SqlConnectionListMetaData metaData;
|
||||
SqlDataReader sqlDataReader = null;
|
||||
try
|
||||
{
|
||||
var sqlCommand = new SqlCommand("SELECT * FROM tblRoot", sqlDatabaseConnector.SqlConnection);
|
||||
if (!sqlDatabaseConnector.IsConnected)
|
||||
sqlDatabaseConnector.Connect();
|
||||
sqlDataReader = sqlCommand.ExecuteReader();
|
||||
if (!sqlDataReader.HasRows)
|
||||
return null; // assume new empty database
|
||||
else
|
||||
sqlDataReader.Read();
|
||||
|
||||
metaData = new SqlConnectionListMetaData
|
||||
{
|
||||
Name = sqlDataReader["Name"] as string ?? "",
|
||||
Protected = sqlDataReader["Protected"] as string ?? "",
|
||||
Export = (bool)sqlDataReader["Export"],
|
||||
ConfVersion = new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture))
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Retrieving database version failed. {ex}");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (sqlDataReader != null && !sqlDataReader.IsClosed)
|
||||
sqlDataReader.Close();
|
||||
}
|
||||
return metaData;
|
||||
}
|
||||
|
||||
public void WriteDatabaseMetaData(RootNodeInfo rootTreeNode, SqlDatabaseConnector sqlDatabaseConnector)
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
string strProtected;
|
||||
if (rootTreeNode != null)
|
||||
{
|
||||
if (rootTreeNode.Password)
|
||||
{
|
||||
var password = rootTreeNode.PasswordString.ConvertToSecureString();
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsProtected", password);
|
||||
}
|
||||
else
|
||||
{
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strProtected = cryptographyProvider.Encrypt("ThisIsNotProtected", Runtime.EncryptionKey);
|
||||
}
|
||||
|
||||
var sqlQuery = new SqlCommand("DELETE FROM tblRoot", sqlDatabaseConnector.SqlConnection);
|
||||
sqlQuery.ExecuteNonQuery();
|
||||
|
||||
if (rootTreeNode != null)
|
||||
{
|
||||
sqlQuery =
|
||||
new SqlCommand(
|
||||
"INSERT INTO tblRoot (Name, Export, Protected, ConfVersion) VALUES(\'" +
|
||||
MiscTools.PrepareValueForDB(rootTreeNode.Name) + "\', 0, \'" + strProtected + "\'," +
|
||||
ConnectionsFileInfo.ConnectionFileVersion.ToString(CultureInfo.InvariantCulture) + ")",
|
||||
sqlDatabaseConnector.SqlConnection);
|
||||
sqlQuery.ExecuteNonQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"UpdateRootNodeTable: rootTreeNode was null. Could not insert!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Forms;
|
||||
@@ -20,7 +21,7 @@ using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
{
|
||||
private XmlDocument _xmlDocument;
|
||||
private double _confVersion;
|
||||
@@ -29,9 +30,9 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
private const double MaxSupportedConfVersion = 2.8;
|
||||
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
public XmlConnectionsDeserializer(Func<SecureString> authenticationRequestor = null)
|
||||
public XmlConnectionsDeserializer(Func<Optional<SecureString>> authenticationRequestor = null)
|
||||
{
|
||||
AuthenticationRequestor = authenticationRequestor;
|
||||
}
|
||||
@@ -47,8 +48,6 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
LoadXmlConnectionData(xml);
|
||||
ValidateConnectionFileVersion();
|
||||
if (!import)
|
||||
Runtime.ConnectionsService.IsConnectionsFileLoaded = false;
|
||||
|
||||
var rootXmlElement = _xmlDocument.DocumentElement;
|
||||
InitializeRootNode(rootXmlElement);
|
||||
@@ -62,8 +61,6 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
|
||||
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, _rootNodeInfo.PasswordString.ConvertToSecureString()))
|
||||
{
|
||||
mRemoteNG.Settings.Default.LoadConsFromCustomLocation = false;
|
||||
mRemoteNG.Settings.Default.CustomConsPath = "";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -208,7 +205,9 @@ namespace mRemoteNG.Config.Serializers.Xml
|
||||
{
|
||||
if (xmlnode.Attributes == null) return null;
|
||||
|
||||
var connectionId = xmlnode.Attributes["Id"]?.Value ?? Guid.NewGuid().ToString();
|
||||
var connectionId = xmlnode.Attributes["Id"]?.Value;
|
||||
if (string.IsNullOrWhiteSpace(connectionId))
|
||||
connectionId = Guid.NewGuid().ToString();
|
||||
var connectionInfo = new ConnectionInfo(connectionId);
|
||||
|
||||
try
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
@@ -7,13 +9,11 @@ using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
{
|
||||
public class RemoteDesktopConnectionManagerDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class RemoteDesktopConnectionManagerDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
{
|
||||
private static int _schemaVersion; /* 1 = RDCMan v2.2
|
||||
3 = RDCMan v2.7 */
|
||||
@@ -40,11 +40,15 @@ namespace mRemoteNG.Config.Serializers
|
||||
|
||||
private static void VerifySchemaVersion(XmlNode rdcManNode)
|
||||
{
|
||||
_schemaVersion = Convert.ToInt32(rdcManNode?.Attributes?["schemaVersion"].Value);
|
||||
if (_schemaVersion != 1 && _schemaVersion != 3)
|
||||
if (!int.TryParse(rdcManNode?.Attributes?["schemaVersion"]?.Value, out var version))
|
||||
throw new FileFormatException("Could not find schema version attribute.");
|
||||
|
||||
if (version != 1 && version != 3)
|
||||
{
|
||||
throw (new FileFormatException($"Unsupported schema version ({_schemaVersion})."));
|
||||
throw new FileFormatException($"Unsupported schema version ({version}).");
|
||||
}
|
||||
|
||||
_schemaVersion = version;
|
||||
}
|
||||
|
||||
private static void VerifyFileVersion(XmlNode rdcManNode)
|
||||
@@ -60,7 +64,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
else
|
||||
{
|
||||
var versionNode = rdcManNode.SelectSingleNode("./version")?.InnerText;
|
||||
var versionNode = rdcManNode?.SelectSingleNode("./version")?.InnerText;
|
||||
if (versionNode != null)
|
||||
{
|
||||
var version = new Version(versionNode);
|
||||
@@ -101,19 +105,21 @@ namespace mRemoteNG.Config.Serializers
|
||||
{
|
||||
if (_schemaVersion == 1)
|
||||
{
|
||||
// Program Verison 2.2 wraps all setting inside the Properties tags
|
||||
// Program Version 2.2 wraps all setting inside the Properties tags
|
||||
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
|
||||
}
|
||||
var newContainer = new ContainerInfo();
|
||||
var connectionInfo = ConnectionInfoFromXml(containerPropertiesNode);
|
||||
newContainer.CopyFrom(connectionInfo);
|
||||
|
||||
if (_schemaVersion == 3)
|
||||
{
|
||||
// Program Verison 2.7 wraps these properties
|
||||
// Program Version 2.7 wraps these properties
|
||||
containerPropertiesNode = containerPropertiesNode.SelectSingleNode("./properties");
|
||||
}
|
||||
newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.strNewFolder;
|
||||
newContainer.IsExpanded = bool.Parse(containerPropertiesNode?.SelectSingleNode("./expanded")?.InnerText ?? "false");
|
||||
if (bool.TryParse(containerPropertiesNode?.SelectSingleNode("./expanded")?.InnerText, out var expanded))
|
||||
newContainer.IsExpanded = expanded;
|
||||
parentContainer.AddChild(newContainer);
|
||||
return newContainer;
|
||||
}
|
||||
@@ -128,29 +134,39 @@ namespace mRemoteNG.Config.Serializers
|
||||
{
|
||||
var connectionInfo = new ConnectionInfo {Protocol = ProtocolType.RDP};
|
||||
|
||||
|
||||
var propertiesNode = xmlNode.SelectSingleNode("./properties");
|
||||
if (_schemaVersion == 1) propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
|
||||
connectionInfo.Hostname = propertiesNode.SelectSingleNode("./name")?.InnerText;
|
||||
connectionInfo.Name = propertiesNode.SelectSingleNode("./displayName")?.InnerText ?? connectionInfo.Hostname;
|
||||
connectionInfo.Description = propertiesNode.SelectSingleNode("./comment")?.InnerText ?? String.Empty;
|
||||
if (_schemaVersion == 1)
|
||||
propertiesNode = xmlNode; // Version 2.2 defines the container name at the root instead
|
||||
|
||||
connectionInfo.Hostname = propertiesNode?.SelectSingleNode("./name")?.InnerText ?? "";
|
||||
|
||||
var connectionDisplayName = propertiesNode?.SelectSingleNode("./displayName")?.InnerText;
|
||||
connectionInfo.Name = !string.IsNullOrWhiteSpace(connectionDisplayName)
|
||||
? connectionDisplayName
|
||||
: string.IsNullOrWhiteSpace(connectionInfo.Hostname)
|
||||
? connectionInfo.Name
|
||||
: connectionInfo.Hostname;
|
||||
|
||||
connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty;
|
||||
|
||||
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
|
||||
if (logonCredentialsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (logonCredentialsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText;
|
||||
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText ?? string.Empty;
|
||||
|
||||
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
|
||||
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords
|
||||
{
|
||||
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"].Value == "True" ? passwordNode.InnerText : DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionInfo.Password = DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
|
||||
connectionInfo.Domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText;
|
||||
connectionInfo.Domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -160,12 +176,14 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var connectionSettingsNode = xmlNode.SelectSingleNode("./connectionSettings");
|
||||
if (connectionSettingsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (connectionSettingsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.UseConsoleSession = bool.Parse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText ?? "false");
|
||||
if (bool.TryParse(connectionSettingsNode.SelectSingleNode("./connectToConsole")?.InnerText, out var useConsole))
|
||||
connectionInfo.UseConsoleSession = useConsole;
|
||||
// ./startProgram
|
||||
// ./workingDir
|
||||
connectionInfo.Port = Convert.ToInt32(connectionSettingsNode.SelectSingleNode("./port")?.InnerText);
|
||||
if (int.TryParse(connectionSettingsNode.SelectSingleNode("./port")?.InnerText, out var port))
|
||||
connectionInfo.Port = port;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -174,16 +192,20 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var gatewaySettingsNode = xmlNode.SelectSingleNode("./gatewaySettings");
|
||||
if (gatewaySettingsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (gatewaySettingsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.RDGatewayUsageMethod = gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True" ? RdpProtocol.RDGatewayUsageMethod.Always : RdpProtocol.RDGatewayUsageMethod.Never;
|
||||
connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText;
|
||||
connectionInfo.RDGatewayUsername = gatewaySettingsNode.SelectSingleNode("./userName")?.InnerText;
|
||||
connectionInfo.RDGatewayUsageMethod = gatewaySettingsNode.SelectSingleNode("./enabled")?.InnerText == "True"
|
||||
? RdpProtocol.RDGatewayUsageMethod.Always
|
||||
: RdpProtocol.RDGatewayUsageMethod.Never;
|
||||
connectionInfo.RDGatewayHostname = gatewaySettingsNode.SelectSingleNode("./hostName")?.InnerText ?? string.Empty;
|
||||
connectionInfo.RDGatewayUsername = gatewaySettingsNode.SelectSingleNode("./userName")?.InnerText ?? string.Empty;
|
||||
|
||||
var passwordNode = gatewaySettingsNode.SelectSingleNode("./password");
|
||||
connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True" ? passwordNode.InnerText : DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
|
||||
connectionInfo.RDGatewayDomain = gatewaySettingsNode.SelectSingleNode("./domain")?.InnerText;
|
||||
connectionInfo.RDGatewayDomain = gatewaySettingsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
|
||||
// ./logonMethod
|
||||
// ./localBypass
|
||||
// ./credSharing
|
||||
@@ -198,17 +220,12 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var remoteDesktopNode = xmlNode.SelectSingleNode("./remoteDesktop");
|
||||
if (remoteDesktopNode?.Attributes?["inherit"].Value == "None")
|
||||
if (remoteDesktopNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
var resolutionString = remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", "");
|
||||
try
|
||||
{
|
||||
connectionInfo.Resolution = (RdpProtocol.RDPResolutions)Enum.Parse(typeof(RdpProtocol.RDPResolutions), "Res" + resolutionString);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
connectionInfo.Resolution = RdpProtocol.RDPResolutions.FitToWindow;
|
||||
}
|
||||
connectionInfo.Resolution =
|
||||
Enum.TryParse<RdpProtocol.RDPResolutions>(remoteDesktopNode.SelectSingleNode("./size")?.InnerText.Replace(" ", ""), true, out var rdpResolution)
|
||||
? rdpResolution
|
||||
: RdpProtocol.RDPResolutions.FitToWindow;
|
||||
|
||||
if (remoteDesktopNode.SelectSingleNode("./sameSizeAsClientArea")?.InnerText == "True")
|
||||
{
|
||||
@@ -220,9 +237,8 @@ namespace mRemoteNG.Config.Serializers
|
||||
connectionInfo.Resolution = RdpProtocol.RDPResolutions.Fullscreen;
|
||||
}
|
||||
|
||||
var colorDepth = remoteDesktopNode.SelectSingleNode("./colorDepth")?.InnerText;
|
||||
if (colorDepth != null)
|
||||
connectionInfo.Colors = (RdpProtocol.RDPColors)Enum.Parse(typeof(RdpProtocol.RDPColors), colorDepth);
|
||||
if (Enum.TryParse<RdpProtocol.RDPColors>(remoteDesktopNode.SelectSingleNode("./colorDepth")?.InnerText, true, out var rdpColors))
|
||||
connectionInfo.Colors = rdpColors;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -231,7 +247,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var localResourcesNode = xmlNode.SelectSingleNode("./localResources");
|
||||
if (localResourcesNode?.Attributes?["inherit"].Value == "None")
|
||||
if (localResourcesNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (localResourcesNode.SelectSingleNode("./audioRedirection")?.InnerText)
|
||||
@@ -271,10 +287,17 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
// ./redirectClipboard
|
||||
connectionInfo.RedirectDiskDrives = bool.Parse(localResourcesNode.SelectSingleNode("./redirectDrives")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectPorts = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPorts")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectPrinters = bool.Parse(localResourcesNode.SelectSingleNode("./redirectPrinters")?.InnerText ?? "false");
|
||||
connectionInfo.RedirectSmartCards = bool.Parse(localResourcesNode.SelectSingleNode("./redirectSmartCards")?.InnerText ?? "false");
|
||||
if (bool.TryParse(localResourcesNode?.SelectSingleNode("./redirectDrives")?.InnerText, out var redirectDisks))
|
||||
connectionInfo.RedirectDiskDrives = redirectDisks;
|
||||
|
||||
if (bool.TryParse(localResourcesNode?.SelectSingleNode("./redirectPorts")?.InnerText, out var redirectPorts))
|
||||
connectionInfo.RedirectPorts = redirectPorts;
|
||||
|
||||
if (bool.TryParse(localResourcesNode?.SelectSingleNode("./redirectPrinters")?.InnerText, out var redirectPrinters))
|
||||
connectionInfo.RedirectPrinters = redirectPrinters;
|
||||
|
||||
if (bool.TryParse(localResourcesNode?.SelectSingleNode("./redirectSmartCards")?.InnerText, out var redirectSmartCards))
|
||||
connectionInfo.RedirectSmartCards = redirectSmartCards;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -287,7 +310,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
}
|
||||
|
||||
var securitySettingsNode = xmlNode.SelectSingleNode("./securitySettings");
|
||||
if (securitySettingsNode?.Attributes?["inherit"].Value == "None")
|
||||
if (securitySettingsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (securitySettingsNode.SelectSingleNode("./authentication")?.InnerText)
|
||||
@@ -321,7 +344,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
private static string DecryptRdcManPassword(string ciphertext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ciphertext))
|
||||
return null;
|
||||
return string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -332,7 +355,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
catch (Exception /*ex*/)
|
||||
{
|
||||
//Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true);
|
||||
return null;
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using System.Globalization;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
public class SqlDatabaseVersionRetriever
|
||||
{
|
||||
public Version GetDatabaseVersion(SqlDatabaseConnector sqlDatabaseConnector)
|
||||
{
|
||||
Version databaseVersion;
|
||||
SqlDataReader sqlDataReader = null;
|
||||
try
|
||||
{
|
||||
var sqlCommand = new SqlCommand("SELECT * FROM tblRoot", sqlDatabaseConnector.SqlConnection);
|
||||
if (!sqlDatabaseConnector.IsConnected)
|
||||
sqlDatabaseConnector.Connect();
|
||||
sqlDataReader = sqlCommand.ExecuteReader();
|
||||
if (!sqlDataReader.HasRows)
|
||||
return new Version(); // assume new empty database
|
||||
else
|
||||
sqlDataReader.Read();
|
||||
databaseVersion = new Version(Convert.ToString(sqlDataReader["confVersion"], CultureInfo.InvariantCulture));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, $"Retrieving database version failed. {ex}");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (sqlDataReader != null && !sqlDataReader.IsClosed)
|
||||
sqlDataReader.Close();
|
||||
}
|
||||
return databaseVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ namespace mRemoteNG.Config.Serializers.Versioning
|
||||
public class SqlDatabaseVersionVerifier
|
||||
{
|
||||
private readonly SqlDatabaseConnector _sqlDatabaseConnector;
|
||||
private readonly SqlDatabaseVersionRetriever _versionRetriever;
|
||||
|
||||
public SqlDatabaseVersionVerifier(SqlDatabaseConnector sqlDatabaseConnector)
|
||||
{
|
||||
@@ -17,15 +16,14 @@ namespace mRemoteNG.Config.Serializers.Versioning
|
||||
throw new ArgumentNullException(nameof(sqlDatabaseConnector));
|
||||
|
||||
_sqlDatabaseConnector = sqlDatabaseConnector;
|
||||
_versionRetriever = new SqlDatabaseVersionRetriever();
|
||||
}
|
||||
|
||||
public bool VerifyDatabaseVersion()
|
||||
public bool VerifyDatabaseVersion(Version dbVersion)
|
||||
{
|
||||
var isVerified = false;
|
||||
try
|
||||
{
|
||||
var databaseVersion = _versionRetriever.GetDatabaseVersion(_sqlDatabaseConnector);
|
||||
var databaseVersion = dbVersion;
|
||||
|
||||
if (databaseVersion.Equals(new Version()))
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
@@ -13,7 +14,7 @@ namespace mRemoteNG.Config.Serializers
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly RootNodeInfo _rootNodeInfo;
|
||||
|
||||
public Func<SecureString> AuthenticationRequestor { get; set; }
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
public int KeyDerivationIterations
|
||||
{
|
||||
@@ -91,16 +92,14 @@ namespace mRemoteNG.Config.Serializers
|
||||
|
||||
private bool Authenticate(string cipherText, SecureString password)
|
||||
{
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText)
|
||||
{
|
||||
AuthenticationRequestor = AuthenticationRequestor
|
||||
};
|
||||
|
||||
var authenticator = new PasswordAuthenticator(_cryptographyProvider, cipherText, AuthenticationRequestor);
|
||||
var authenticated = authenticator.Authenticate(password);
|
||||
|
||||
if (!authenticated) return authenticated;
|
||||
if (!authenticated)
|
||||
return false;
|
||||
|
||||
_rootNodeInfo.PasswordString = authenticator.LastAuthenticatedPassword.ConvertToUnsecureString();
|
||||
return authenticated;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Configuration;
|
||||
#if !PORTABLE
|
||||
using System.Configuration;
|
||||
#endif
|
||||
|
||||
namespace mRemoteNG.Config.Settings.Providers
|
||||
{
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
/// The MIT License (MIT)
|
||||
///
|
||||
/// Copyright(c) crdx
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining
|
||||
/// a copy of this software and associated documentation files (the
|
||||
/// "Software"), to deal in the Software without restriction, including
|
||||
/// without limitation the rights to use, copy, modify, merge, publish,
|
||||
/// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
/// permit persons to whom the Software is furnished to do so, subject to
|
||||
/// the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be
|
||||
/// included in all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
/// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
/// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
/// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
/// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
/// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
///
|
||||
/// https://raw.githubusercontent.com/crdx/PortableSettingsProvider
|
||||
///
|
||||
using System.Linq;
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright(c) crdx
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// https://raw.githubusercontent.com/crdx/PortableSettingsProvider
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Windows.Forms;
|
||||
using System.Collections.Specialized;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
//using mRemoteNG.App;
|
||||
|
||||
namespace mRemoteNG.Config.Settings.Providers
|
||||
{
|
||||
@@ -43,63 +43,34 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
private const string _className = "PortableSettingsProvider";
|
||||
private XmlDocument _xmlDocument;
|
||||
|
||||
private string _filePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),
|
||||
string.Format("{0}.settings", ApplicationName));
|
||||
}
|
||||
}
|
||||
private string _filePath => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? throw new InvalidOperationException(), $"{ApplicationName}.settings");
|
||||
|
||||
private XmlNode _localSettingsNode
|
||||
{
|
||||
get
|
||||
{
|
||||
XmlNode settingsNode = GetSettingsNode(_localSettingsNodeName);
|
||||
XmlNode machineNode = settingsNode.SelectSingleNode(Environment.MachineName.ToLowerInvariant());
|
||||
private XmlNode _localSettingsNode => GetSettingsNode(_localSettingsNodeName);
|
||||
|
||||
if (machineNode == null)
|
||||
{
|
||||
machineNode = _rootDocument.CreateElement(Environment.MachineName.ToLowerInvariant());
|
||||
settingsNode.AppendChild(machineNode);
|
||||
}
|
||||
private XmlNode _globalSettingsNode => GetSettingsNode(_globalSettingsNodeName);
|
||||
|
||||
return machineNode;
|
||||
}
|
||||
}
|
||||
|
||||
private XmlNode _globalSettingsNode
|
||||
{
|
||||
get { return GetSettingsNode(_globalSettingsNodeName); }
|
||||
}
|
||||
|
||||
private XmlNode _rootNode
|
||||
{
|
||||
get { return _rootDocument.SelectSingleNode(_rootNodeName); }
|
||||
}
|
||||
private XmlNode _rootNode => _rootDocument.SelectSingleNode(_rootNodeName);
|
||||
|
||||
private XmlDocument _rootDocument
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_xmlDocument == null)
|
||||
if (_xmlDocument != null) return _xmlDocument;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
_xmlDocument = new XmlDocument();
|
||||
_xmlDocument.Load(_filePath);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (_xmlDocument.SelectSingleNode(_rootNodeName) != null)
|
||||
return _xmlDocument;
|
||||
|
||||
_xmlDocument = GetBlankXmlDocument();
|
||||
_xmlDocument = new XmlDocument();
|
||||
_xmlDocument.Load(_filePath);
|
||||
}
|
||||
catch (Exception /*ex*/)
|
||||
{
|
||||
// This casues hundreds of unit tests to fail for some reason...
|
||||
//Runtime.MessageCollector.AddExceptionStackTrace("PortableSettingsProvider: Error getting XML", ex);
|
||||
}
|
||||
|
||||
if (_xmlDocument?.SelectSingleNode(_rootNodeName) != null)
|
||||
return _xmlDocument;
|
||||
|
||||
_xmlDocument = GetBlankXmlDocument();
|
||||
|
||||
return _xmlDocument;
|
||||
}
|
||||
@@ -107,14 +78,11 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
public override string ApplicationName
|
||||
{
|
||||
get { return Path.GetFileNameWithoutExtension(Application.ExecutablePath); }
|
||||
get => Path.GetFileNameWithoutExtension(Application.ExecutablePath);
|
||||
set { }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return _className; }
|
||||
}
|
||||
public override string Name => _className;
|
||||
|
||||
public override void Initialize(string name, NameValueCollection config)
|
||||
{
|
||||
@@ -143,7 +111,7 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
|
||||
{
|
||||
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
|
||||
var values = new SettingsPropertyValueCollection();
|
||||
|
||||
foreach (SettingsProperty property in collection)
|
||||
{
|
||||
@@ -158,11 +126,9 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
private void SetValue(SettingsPropertyValue propertyValue)
|
||||
{
|
||||
XmlNode targetNode = IsGlobal(propertyValue.Property)
|
||||
? _globalSettingsNode
|
||||
: _localSettingsNode;
|
||||
var targetNode = IsGlobal(propertyValue.Property) ? _globalSettingsNode : _localSettingsNode;
|
||||
|
||||
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", propertyValue.Name));
|
||||
var settingNode = targetNode.SelectSingleNode($"setting[@name='{propertyValue.Name}']");
|
||||
|
||||
if (settingNode != null)
|
||||
settingNode.InnerText = propertyValue.SerializedValue.ToString();
|
||||
@@ -170,10 +136,10 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
{
|
||||
settingNode = _rootDocument.CreateElement("setting");
|
||||
|
||||
XmlAttribute nameAttribute = _rootDocument.CreateAttribute("name");
|
||||
var nameAttribute = _rootDocument.CreateAttribute("name");
|
||||
nameAttribute.Value = propertyValue.Name;
|
||||
|
||||
settingNode.Attributes.Append(nameAttribute);
|
||||
settingNode.Attributes?.Append(nameAttribute);
|
||||
settingNode.InnerText = propertyValue.SerializedValue.ToString();
|
||||
|
||||
targetNode.AppendChild(settingNode);
|
||||
@@ -182,8 +148,8 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
private string GetValue(SettingsProperty property)
|
||||
{
|
||||
XmlNode targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
|
||||
XmlNode settingNode = targetNode.SelectSingleNode(string.Format("setting[@name='{0}']", property.Name));
|
||||
var targetNode = IsGlobal(property) ? _globalSettingsNode : _localSettingsNode;
|
||||
var settingNode = targetNode.SelectSingleNode($"setting[@name='{property.Name}']");
|
||||
|
||||
if (settingNode == null)
|
||||
return property.DefaultValue != null ? property.DefaultValue.ToString() : string.Empty;
|
||||
@@ -191,7 +157,7 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
return settingNode.InnerText;
|
||||
}
|
||||
|
||||
private bool IsGlobal(SettingsProperty property)
|
||||
private static bool IsGlobal(SettingsProperty property)
|
||||
{
|
||||
foreach (DictionaryEntry attribute in property.Attributes)
|
||||
{
|
||||
@@ -204,20 +170,18 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
|
||||
private XmlNode GetSettingsNode(string name)
|
||||
{
|
||||
XmlNode settingsNode = _rootNode.SelectSingleNode(name);
|
||||
var settingsNode = _rootNode.SelectSingleNode(name);
|
||||
|
||||
if (settingsNode == null)
|
||||
{
|
||||
settingsNode = _rootDocument.CreateElement(name);
|
||||
_rootNode.AppendChild(settingsNode);
|
||||
}
|
||||
if (settingsNode != null) return settingsNode;
|
||||
settingsNode = _rootDocument.CreateElement(name);
|
||||
_rootNode.AppendChild(settingsNode);
|
||||
|
||||
return settingsNode;
|
||||
}
|
||||
|
||||
public XmlDocument GetBlankXmlDocument()
|
||||
private static XmlDocument GetBlankXmlDocument()
|
||||
{
|
||||
XmlDocument blankXmlDocument = new XmlDocument();
|
||||
var blankXmlDocument = new XmlDocument();
|
||||
blankXmlDocument.AppendChild(blankXmlDocument.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
|
||||
blankXmlDocument.AppendChild(blankXmlDocument.CreateElement(_rootNodeName));
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace mRemoteNG.Config.Settings
|
||||
{
|
||||
private readonly ExternalAppsLoader _externalAppsLoader;
|
||||
private readonly MessageCollector _messageCollector;
|
||||
private readonly MenuStrip _mainMenu;
|
||||
private readonly QuickConnectToolStrip _quickConnectToolStrip;
|
||||
private readonly ExternalToolsToolStrip _externalToolsToolStrip;
|
||||
private readonly MultiSshToolStrip _multiSshToolStrip;
|
||||
@@ -31,7 +32,8 @@ namespace mRemoteNG.Config.Settings
|
||||
MessageCollector messageCollector,
|
||||
QuickConnectToolStrip quickConnectToolStrip,
|
||||
ExternalToolsToolStrip externalToolsToolStrip,
|
||||
MultiSshToolStrip multiSshToolStrip)
|
||||
MultiSshToolStrip multiSshToolStrip,
|
||||
MenuStrip mainMenu)
|
||||
{
|
||||
if (mainForm == null)
|
||||
throw new ArgumentNullException(nameof(mainForm));
|
||||
@@ -43,13 +45,16 @@ namespace mRemoteNG.Config.Settings
|
||||
throw new ArgumentNullException(nameof(externalToolsToolStrip));
|
||||
if (multiSshToolStrip == null)
|
||||
throw new ArgumentNullException(nameof(multiSshToolStrip));
|
||||
if (mainMenu == null)
|
||||
throw new ArgumentNullException(nameof(mainMenu));
|
||||
|
||||
MainForm = mainForm;
|
||||
_messageCollector = messageCollector;
|
||||
_quickConnectToolStrip = quickConnectToolStrip;
|
||||
_externalToolsToolStrip = externalToolsToolStrip;
|
||||
_multiSshToolStrip = multiSshToolStrip;
|
||||
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
|
||||
_mainMenu = mainMenu;
|
||||
_externalAppsLoader = new ExternalAppsLoader(MainForm, messageCollector, _externalToolsToolStrip);
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
@@ -197,6 +202,7 @@ namespace mRemoteNG.Config.Settings
|
||||
private void LoadToolbarsFromSettings()
|
||||
{
|
||||
ResetAllToolbarLocations();
|
||||
AddMainMenuPanel();
|
||||
AddExternalAppsPanel();
|
||||
AddQuickConnectPanel();
|
||||
AddMultiSshPanel();
|
||||
@@ -210,31 +216,49 @@ namespace mRemoteNG.Config.Settings
|
||||
private void ResetAllToolbarLocations()
|
||||
{
|
||||
var tempToolStrip = new ToolStripPanel();
|
||||
tempToolStrip.Join(_mainMenu);
|
||||
tempToolStrip.Join(_quickConnectToolStrip);
|
||||
tempToolStrip.Join(_externalToolsToolStrip);
|
||||
tempToolStrip.Join(_multiSshToolStrip);
|
||||
}
|
||||
|
||||
private void AddMainMenuPanel()
|
||||
{
|
||||
SetToolstripGripStyle(_mainMenu);
|
||||
var toolStripPanel = ToolStripPanelFromString("top");
|
||||
toolStripPanel.Join(_mainMenu, new Point(3, 0));
|
||||
}
|
||||
|
||||
private void AddQuickConnectPanel()
|
||||
{
|
||||
SetToolstripGripStyle(_quickConnectToolStrip);
|
||||
_quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible;
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.QuickyTBParentDock);
|
||||
toolStripPanel.Join(_quickConnectToolStrip, mRemoteNG.Settings.Default.QuickyTBLocation);
|
||||
_quickConnectToolStrip.Visible = mRemoteNG.Settings.Default.QuickyTBVisible;
|
||||
}
|
||||
|
||||
private void AddExternalAppsPanel()
|
||||
{
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
|
||||
toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation);
|
||||
SetToolstripGripStyle(_externalToolsToolStrip);
|
||||
_externalToolsToolStrip.Visible = mRemoteNG.Settings.Default.ExtAppsTBVisible;
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
|
||||
toolStripPanel.Join(_externalToolsToolStrip, mRemoteNG.Settings.Default.ExtAppsTBLocation);
|
||||
}
|
||||
|
||||
private void AddMultiSshPanel()
|
||||
{
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.ExtAppsTBParentDock);
|
||||
toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation);
|
||||
SetToolstripGripStyle(_multiSshToolStrip);
|
||||
_multiSshToolStrip.Visible = mRemoteNG.Settings.Default.MultiSshToolbarVisible;
|
||||
var toolStripPanel = ToolStripPanelFromString(mRemoteNG.Settings.Default.MultiSshToolbarParentDock);
|
||||
toolStripPanel.Join(_multiSshToolStrip, mRemoteNG.Settings.Default.MultiSshToolbarLocation);
|
||||
}
|
||||
|
||||
private void SetToolstripGripStyle(ToolStrip toolbar)
|
||||
{
|
||||
toolbar.GripStyle = mRemoteNG.Settings.Default.LockToolbars
|
||||
? ToolStripGripStyle.Hidden
|
||||
: ToolStripGripStyle.Visible;
|
||||
}
|
||||
|
||||
private ToolStripPanel ToolStripPanelFromString(string panel)
|
||||
{
|
||||
|
||||
@@ -87,8 +87,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionName")]
|
||||
public virtual string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetField(ref _name, value, "Name"); }
|
||||
get => _name;
|
||||
set => SetField(ref _name, value, "Name");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
|
||||
@@ -96,8 +96,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDescription")]
|
||||
public virtual string Description
|
||||
{
|
||||
get { return GetPropertyValue("Description", _description); }
|
||||
set { SetField(ref _description, value, "Description"); }
|
||||
get => GetPropertyValue("Description", _description);
|
||||
set => SetField(ref _description, value, "Description");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
|
||||
@@ -106,8 +106,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionIcon")]
|
||||
public virtual string Icon
|
||||
{
|
||||
get { return GetPropertyValue("Icon", _icon); }
|
||||
set { SetField(ref _icon, value, "Icon"); }
|
||||
get => GetPropertyValue("Icon", _icon);
|
||||
set => SetField(ref _icon, value, "Icon");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryDisplay"),
|
||||
@@ -115,8 +115,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPanel")]
|
||||
public virtual string Panel
|
||||
{
|
||||
get { return GetPropertyValue("Panel", _panel); }
|
||||
set { SetField(ref _panel, value, "Panel"); }
|
||||
get => GetPropertyValue("Panel", _panel);
|
||||
set => SetField(ref _panel, value, "Panel");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -126,8 +126,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionAddress")]
|
||||
public virtual string Hostname
|
||||
{
|
||||
get { return _hostname.Trim(); }
|
||||
set { SetField(ref _hostname, value?.Trim(), "Hostname"); }
|
||||
get => _hostname.Trim();
|
||||
set => SetField(ref _hostname, value?.Trim(), "Hostname");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -135,8 +135,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUsername")]
|
||||
public virtual string Username
|
||||
{
|
||||
get { return GetPropertyValue("Username", _username); }
|
||||
set { SetField(ref _username, value?.Trim(), "Username"); }
|
||||
get => GetPropertyValue("Username", _username);
|
||||
set => SetField(ref _username, value?.Trim(), "Username");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -145,8 +145,8 @@ namespace mRemoteNG.Connection
|
||||
PasswordPropertyText(true)]
|
||||
public virtual string Password
|
||||
{
|
||||
get { return GetPropertyValue("Password", _password); }
|
||||
set { SetField(ref _password, value, "Password"); }
|
||||
get => GetPropertyValue("Password", _password);
|
||||
set => SetField(ref _password, value, "Password");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -154,8 +154,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionDomain")]
|
||||
public string Domain
|
||||
{
|
||||
get { return GetPropertyValue("Domain", _domain).Trim(); }
|
||||
set { SetField(ref _domain, value?.Trim(), "Domain"); }
|
||||
get => GetPropertyValue("Domain", _domain).Trim();
|
||||
set => SetField(ref _domain, value?.Trim(), "Domain");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -166,8 +166,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public virtual ProtocolType Protocol
|
||||
{
|
||||
get { return GetPropertyValue("Protocol", _protocol); }
|
||||
set { SetField(ref _protocol, value, "Protocol"); }
|
||||
get => GetPropertyValue("Protocol", _protocol);
|
||||
set => SetField(ref _protocol, value, "Protocol");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -176,8 +176,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(ExternalToolsTypeConverter))]
|
||||
public string ExtApp
|
||||
{
|
||||
get { return GetPropertyValue("ExtApp", _extApp); }
|
||||
set { SetField(ref _extApp, value, "ExtApp"); }
|
||||
get => GetPropertyValue("ExtApp", _extApp);
|
||||
set => SetField(ref _extApp, value, "ExtApp");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -185,8 +185,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionPort")]
|
||||
public virtual int Port
|
||||
{
|
||||
get { return GetPropertyValue("Port", _port); }
|
||||
set { SetField(ref _port, value, "Port"); }
|
||||
get => GetPropertyValue("Port", _port);
|
||||
set => SetField(ref _port, value, "Port");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -195,8 +195,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(Config.Putty.PuttySessionsManager.SessionList))]
|
||||
public virtual string PuttySession
|
||||
{
|
||||
get { return GetPropertyValue("PuttySession", _puttySession); }
|
||||
set { SetField(ref _puttySession, value, "PuttySession"); }
|
||||
get => GetPropertyValue("PuttySession", _puttySession);
|
||||
set => SetField(ref _puttySession, value, "PuttySession");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -205,8 +205,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public IcaProtocol.EncryptionStrength ICAEncryptionStrength
|
||||
{
|
||||
get { return GetPropertyValue("ICAEncryptionStrength", _icaEncryption); }
|
||||
set { SetField(ref _icaEncryption, value, "ICAEncryptionStrength"); }
|
||||
get => GetPropertyValue("ICAEncryptionStrength", _icaEncryption);
|
||||
set => SetField(ref _icaEncryption, value, "ICAEncryptionStrength");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -215,8 +215,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool UseConsoleSession
|
||||
{
|
||||
get { return GetPropertyValue("UseConsoleSession", _useConsoleSession); }
|
||||
set { SetField(ref _useConsoleSession, value, "UseConsoleSession"); }
|
||||
get => GetPropertyValue("UseConsoleSession", _useConsoleSession);
|
||||
set => SetField(ref _useConsoleSession, value, "UseConsoleSession");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -225,8 +225,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.AuthenticationLevel RDPAuthenticationLevel
|
||||
{
|
||||
get { return GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel); }
|
||||
set { SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel"); }
|
||||
get => GetPropertyValue("RDPAuthenticationLevel", _rdpAuthenticationLevel);
|
||||
set => SetField(ref _rdpAuthenticationLevel, value, "RDPAuthenticationLevel");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -234,7 +234,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPMinutesToIdleTimeout")]
|
||||
public virtual int RDPMinutesToIdleTimeout
|
||||
{
|
||||
get { return GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout); }
|
||||
get => GetPropertyValue("RDPMinutesToIdleTimeout", _rdpMinutesToIdleTimeout);
|
||||
set {
|
||||
if(value < 0)
|
||||
value = 0;
|
||||
@@ -249,8 +249,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDPAlertIdleTimeout")]
|
||||
public bool RDPAlertIdleTimeout
|
||||
{
|
||||
get { return GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout); }
|
||||
set { SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout"); }
|
||||
get => GetPropertyValue("RDPAlertIdleTimeout", _rdpAlertIdleTimeout);
|
||||
set => SetField(ref _rdpAlertIdleTimeout, value, "RDPAlertIdleTimeout");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -258,8 +258,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionLoadBalanceInfo")]
|
||||
public string LoadBalanceInfo
|
||||
{
|
||||
get { return GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim(); }
|
||||
set { SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo"); }
|
||||
get => GetPropertyValue("LoadBalanceInfo", _loadBalanceInfo).Trim();
|
||||
set => SetField(ref _loadBalanceInfo, value?.Trim(), "LoadBalanceInfo");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -268,8 +268,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public HTTPBase.RenderingEngine RenderingEngine
|
||||
{
|
||||
get { return GetPropertyValue("RenderingEngine", _renderingEngine); }
|
||||
set { SetField(ref _renderingEngine, value, "RenderingEngine"); }
|
||||
get => GetPropertyValue("RenderingEngine", _renderingEngine);
|
||||
set => SetField(ref _renderingEngine, value, "RenderingEngine");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryProtocol", 3),
|
||||
@@ -278,8 +278,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool UseCredSsp
|
||||
{
|
||||
get { return GetPropertyValue("UseCredSsp", _useCredSsp); }
|
||||
set { SetField(ref _useCredSsp, value, "UseCredSsp"); }
|
||||
get => GetPropertyValue("UseCredSsp", _useCredSsp);
|
||||
set => SetField(ref _useCredSsp, value, "UseCredSsp");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -290,8 +290,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDGatewayUsageMethod RDGatewayUsageMethod
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod); }
|
||||
set { SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod"); }
|
||||
get => GetPropertyValue("RDGatewayUsageMethod", _rdGatewayUsageMethod);
|
||||
set => SetField(ref _rdGatewayUsageMethod, value, "RDGatewayUsageMethod");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -299,8 +299,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayHostname")]
|
||||
public string RDGatewayHostname
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim(); }
|
||||
set { SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname"); }
|
||||
get => GetPropertyValue("RDGatewayHostname", _rdGatewayHostname).Trim();
|
||||
set => SetField(ref _rdGatewayHostname, value?.Trim(), "RDGatewayHostname");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -309,8 +309,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDGatewayUseConnectionCredentials RDGatewayUseConnectionCredentials
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials); }
|
||||
set { SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials"); }
|
||||
get => GetPropertyValue("RDGatewayUseConnectionCredentials", _rdGatewayUseConnectionCredentials);
|
||||
set => SetField(ref _rdGatewayUseConnectionCredentials, value, "RDGatewayUseConnectionCredentials");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -318,8 +318,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayUsername")]
|
||||
public string RDGatewayUsername
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim(); }
|
||||
set { SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername"); }
|
||||
get => GetPropertyValue("RDGatewayUsername", _rdGatewayUsername).Trim();
|
||||
set => SetField(ref _rdGatewayUsername, value?.Trim(), "RDGatewayUsername");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -328,8 +328,8 @@ namespace mRemoteNG.Connection
|
||||
PasswordPropertyText(true)]
|
||||
public string RDGatewayPassword
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayPassword", _rdGatewayPassword); }
|
||||
set { SetField(ref _rdGatewayPassword, value, "RDGatewayPassword"); }
|
||||
get => GetPropertyValue("RDGatewayPassword", _rdGatewayPassword);
|
||||
set => SetField(ref _rdGatewayPassword, value, "RDGatewayPassword");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryGateway", 4),
|
||||
@@ -337,8 +337,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionRDGatewayDomain")]
|
||||
public string RDGatewayDomain
|
||||
{
|
||||
get { return GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim(); }
|
||||
set { SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain"); }
|
||||
get => GetPropertyValue("RDGatewayDomain", _rdGatewayDomain).Trim();
|
||||
set => SetField(ref _rdGatewayDomain, value?.Trim(), "RDGatewayDomain");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -349,8 +349,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPResolutions Resolution
|
||||
{
|
||||
get { return GetPropertyValue("Resolution", _resolution); }
|
||||
set { SetField(ref _resolution, value, "Resolution"); }
|
||||
get => GetPropertyValue("Resolution", _resolution);
|
||||
set => SetField(ref _resolution, value, "Resolution");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -359,8 +359,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool AutomaticResize
|
||||
{
|
||||
get { return GetPropertyValue("AutomaticResize", _automaticResize); }
|
||||
set { SetField(ref _automaticResize, value, "AutomaticResize"); }
|
||||
get => GetPropertyValue("AutomaticResize", _automaticResize);
|
||||
set => SetField(ref _automaticResize, value, "AutomaticResize");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -369,8 +369,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPColors Colors
|
||||
{
|
||||
get { return GetPropertyValue("Colors", _colors); }
|
||||
set { SetField(ref _colors, value, "Colors"); }
|
||||
get => GetPropertyValue("Colors", _colors);
|
||||
set => SetField(ref _colors, value, "Colors");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -379,8 +379,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool CacheBitmaps
|
||||
{
|
||||
get { return GetPropertyValue("CacheBitmaps", _cacheBitmaps); }
|
||||
set { SetField(ref _cacheBitmaps, value, "CacheBitmaps"); }
|
||||
get => GetPropertyValue("CacheBitmaps", _cacheBitmaps);
|
||||
set => SetField(ref _cacheBitmaps, value, "CacheBitmaps");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -389,8 +389,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool DisplayWallpaper
|
||||
{
|
||||
get { return GetPropertyValue("DisplayWallpaper", _displayWallpaper); }
|
||||
set { SetField(ref _displayWallpaper, value, "DisplayWallpaper"); }
|
||||
get => GetPropertyValue("DisplayWallpaper", _displayWallpaper);
|
||||
set => SetField(ref _displayWallpaper, value, "DisplayWallpaper");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -399,8 +399,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool DisplayThemes
|
||||
{
|
||||
get { return GetPropertyValue("DisplayThemes", _displayThemes); }
|
||||
set { SetField(ref _displayThemes, value, "DisplayThemes"); }
|
||||
get => GetPropertyValue("DisplayThemes", _displayThemes);
|
||||
set => SetField(ref _displayThemes, value, "DisplayThemes");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -409,8 +409,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool EnableFontSmoothing
|
||||
{
|
||||
get { return GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing); }
|
||||
set { SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing"); }
|
||||
get => GetPropertyValue("EnableFontSmoothing", _enableFontSmoothing);
|
||||
set => SetField(ref _enableFontSmoothing, value, "EnableFontSmoothing");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -419,8 +419,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool EnableDesktopComposition
|
||||
{
|
||||
get { return GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition); }
|
||||
set { SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition"); }
|
||||
get => GetPropertyValue("EnableDesktopComposition", _enableDesktopComposition);
|
||||
set => SetField(ref _enableDesktopComposition, value, "EnableDesktopComposition");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -431,8 +431,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectKeys
|
||||
{
|
||||
get { return GetPropertyValue("RedirectKeys", _redirectKeys); }
|
||||
set { SetField(ref _redirectKeys, value, "RedirectKeys"); }
|
||||
get => GetPropertyValue("RedirectKeys", _redirectKeys);
|
||||
set => SetField(ref _redirectKeys, value, "RedirectKeys");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -441,8 +441,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectDiskDrives
|
||||
{
|
||||
get { return GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives); }
|
||||
set { SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives"); }
|
||||
get => GetPropertyValue("RedirectDiskDrives", _redirectDiskDrives);
|
||||
set => SetField(ref _redirectDiskDrives, value, "RedirectDiskDrives");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -451,8 +451,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectPrinters
|
||||
{
|
||||
get { return GetPropertyValue("RedirectPrinters", _redirectPrinters); }
|
||||
set { SetField(ref _redirectPrinters, value, "RedirectPrinters"); }
|
||||
get => GetPropertyValue("RedirectPrinters", _redirectPrinters);
|
||||
set => SetField(ref _redirectPrinters, value, "RedirectPrinters");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -461,8 +461,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectPorts
|
||||
{
|
||||
get { return GetPropertyValue("RedirectPorts", _redirectPorts); }
|
||||
set { SetField(ref _redirectPorts, value, "RedirectPorts"); }
|
||||
get => GetPropertyValue("RedirectPorts", _redirectPorts);
|
||||
set => SetField(ref _redirectPorts, value, "RedirectPorts");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -471,8 +471,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool RedirectSmartCards
|
||||
{
|
||||
get { return GetPropertyValue("RedirectSmartCards", _redirectSmartCards); }
|
||||
set { SetField(ref _redirectSmartCards, value, "RedirectSmartCards"); }
|
||||
get => GetPropertyValue("RedirectSmartCards", _redirectSmartCards);
|
||||
set => SetField(ref _redirectSmartCards, value, "RedirectSmartCards");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -481,8 +481,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPSounds RedirectSound
|
||||
{
|
||||
get { return GetPropertyValue("RedirectSound", _redirectSound); }
|
||||
set { SetField(ref _redirectSound, value, "RedirectSound"); }
|
||||
get => GetPropertyValue("RedirectSound", _redirectSound);
|
||||
set => SetField(ref _redirectSound, value, "RedirectSound");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryRedirect", 6),
|
||||
@@ -491,8 +491,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public RdpProtocol.RDPSoundQuality SoundQuality
|
||||
{
|
||||
get { return GetPropertyValue("SoundQuality", _soundQuality); }
|
||||
set { SetField(ref _soundQuality, value, "SoundQuality"); }
|
||||
get => GetPropertyValue("SoundQuality", _soundQuality);
|
||||
set => SetField(ref _soundQuality, value, "SoundQuality");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -506,8 +506,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(ExternalToolsTypeConverter))]
|
||||
public virtual string PreExtApp
|
||||
{
|
||||
get { return GetPropertyValue("PreExtApp", _preExtApp); }
|
||||
set { SetField(ref _preExtApp, value, "PreExtApp"); }
|
||||
get => GetPropertyValue("PreExtApp", _preExtApp);
|
||||
set => SetField(ref _preExtApp, value, "PreExtApp");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -516,8 +516,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(ExternalToolsTypeConverter))]
|
||||
public virtual string PostExtApp
|
||||
{
|
||||
get { return GetPropertyValue("PostExtApp", _postExtApp); }
|
||||
set { SetField(ref _postExtApp, value, "PostExtApp"); }
|
||||
get => GetPropertyValue("PostExtApp", _postExtApp);
|
||||
set => SetField(ref _postExtApp, value, "PostExtApp");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -525,8 +525,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionMACAddress")]
|
||||
public virtual string MacAddress
|
||||
{
|
||||
get { return GetPropertyValue("MacAddress", _macAddress); }
|
||||
set { SetField(ref _macAddress, value, "MacAddress"); }
|
||||
get => GetPropertyValue("MacAddress", _macAddress);
|
||||
set => SetField(ref _macAddress, value, "MacAddress");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -534,8 +534,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionUser1")]
|
||||
public virtual string UserField
|
||||
{
|
||||
get { return GetPropertyValue("UserField", _userField); }
|
||||
set { SetField(ref _userField, value, "UserField"); }
|
||||
get => GetPropertyValue("UserField", _userField);
|
||||
set => SetField(ref _userField, value, "UserField");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -547,8 +547,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.Compression VNCCompression
|
||||
{
|
||||
get { return GetPropertyValue("VNCCompression", _vncCompression); }
|
||||
set { SetField(ref _vncCompression, value, "VNCCompression"); }
|
||||
get => GetPropertyValue("VNCCompression", _vncCompression);
|
||||
set => SetField(ref _vncCompression, value, "VNCCompression");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -558,8 +558,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.Encoding VNCEncoding
|
||||
{
|
||||
get { return GetPropertyValue("VNCEncoding", _vncEncoding); }
|
||||
set { SetField(ref _vncEncoding, value, "VNCEncoding"); }
|
||||
get => GetPropertyValue("VNCEncoding", _vncEncoding);
|
||||
set => SetField(ref _vncEncoding, value, "VNCEncoding");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryConnection", 2),
|
||||
@@ -569,8 +569,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.AuthMode VNCAuthMode
|
||||
{
|
||||
get { return GetPropertyValue("VNCAuthMode", _vncAuthMode); }
|
||||
set { SetField(ref _vncAuthMode, value, "VNCAuthMode"); }
|
||||
get => GetPropertyValue("VNCAuthMode", _vncAuthMode);
|
||||
set => SetField(ref _vncAuthMode, value, "VNCAuthMode");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -580,8 +580,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.ProxyType VNCProxyType
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyType", _vncProxyType); }
|
||||
set { SetField(ref _vncProxyType, value, "VNCProxyType"); }
|
||||
get => GetPropertyValue("VNCProxyType", _vncProxyType);
|
||||
set => SetField(ref _vncProxyType, value, "VNCProxyType");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -590,8 +590,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyAddress")]
|
||||
public string VNCProxyIP
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyIP", _vncProxyIp); }
|
||||
set { SetField(ref _vncProxyIp, value, "VNCProxyIP"); }
|
||||
get => GetPropertyValue("VNCProxyIP", _vncProxyIp);
|
||||
set => SetField(ref _vncProxyIp, value, "VNCProxyIP");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -600,8 +600,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyPort")]
|
||||
public int VNCProxyPort
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyPort", _vncProxyPort); }
|
||||
set { SetField(ref _vncProxyPort, value, "VNCProxyPort"); }
|
||||
get => GetPropertyValue("VNCProxyPort", _vncProxyPort);
|
||||
set => SetField(ref _vncProxyPort, value, "VNCProxyPort");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -610,8 +610,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription("strPropertyDescriptionVNCProxyUsername")]
|
||||
public string VNCProxyUsername
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyUsername", _vncProxyUsername); }
|
||||
set { SetField(ref _vncProxyUsername, value, "VNCProxyUsername"); }
|
||||
get => GetPropertyValue("VNCProxyUsername", _vncProxyUsername);
|
||||
set => SetField(ref _vncProxyUsername, value, "VNCProxyUsername");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryMiscellaneous", 7),
|
||||
@@ -621,8 +621,8 @@ namespace mRemoteNG.Connection
|
||||
PasswordPropertyText(true)]
|
||||
public string VNCProxyPassword
|
||||
{
|
||||
get { return GetPropertyValue("VNCProxyPassword", _vncProxyPassword); }
|
||||
set { SetField(ref _vncProxyPassword, value, "VNCProxyPassword"); }
|
||||
get => GetPropertyValue("VNCProxyPassword", _vncProxyPassword);
|
||||
set => SetField(ref _vncProxyPassword, value, "VNCProxyPassword");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -632,8 +632,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.Colors VNCColors
|
||||
{
|
||||
get { return GetPropertyValue("VNCColors", _vncColors); }
|
||||
set { SetField(ref _vncColors, value, "VNCColors"); }
|
||||
get => GetPropertyValue("VNCColors", _vncColors);
|
||||
set => SetField(ref _vncColors, value, "VNCColors");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -642,8 +642,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter))]
|
||||
public ProtocolVNC.SmartSizeMode VNCSmartSizeMode
|
||||
{
|
||||
get { return GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode); }
|
||||
set { SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode"); }
|
||||
get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode);
|
||||
set => SetField(ref _vncSmartSizeMode, value, "VNCSmartSizeMode");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory("strCategoryAppearance", 5),
|
||||
@@ -652,8 +652,8 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool VNCViewOnly
|
||||
{
|
||||
get { return GetPropertyValue("VNCViewOnly", _vncViewOnly); }
|
||||
set { SetField(ref _vncViewOnly, value, "VNCViewOnly"); }
|
||||
get => GetPropertyValue("VNCViewOnly", _vncViewOnly);
|
||||
set => SetField(ref _vncViewOnly, value, "VNCViewOnly");
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
@@ -665,7 +665,7 @@ namespace mRemoteNG.Connection
|
||||
|
||||
protected virtual TPropertyType GetPropertyValue<TPropertyType>(string propertyName, TPropertyType value)
|
||||
{
|
||||
return (TPropertyType)GetType().GetProperty(propertyName).GetValue(this, null);
|
||||
return (TPropertyType)GetType().GetProperty(propertyName)?.GetValue(this, null);
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@@ -674,12 +674,11 @@ namespace mRemoteNG.Connection
|
||||
PropertyChanged?.Invoke(sender, new PropertyChangedEventArgs(args.PropertyName));
|
||||
}
|
||||
|
||||
protected bool SetField<T>(ref T field, T value, string propertyName = null)
|
||||
protected void SetField<T>(ref T field, T value, string propertyName = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) return;
|
||||
field = value;
|
||||
RaisePropertyChangedEvent(this, new PropertyChangedEventArgs(propertyName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
@@ -15,12 +10,16 @@ using mRemoteNG.Connection.Protocol.Telnet;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
[DefaultProperty("Name")]
|
||||
[DefaultProperty("Name")]
|
||||
public class ConnectionInfo : AbstractConnectionRecord, IHasParent, IInheritable
|
||||
{
|
||||
#region Public Properties
|
||||
@@ -79,7 +78,8 @@ namespace mRemoteNG.Connection
|
||||
var newConnectionInfo = new ConnectionInfo();
|
||||
newConnectionInfo.CopyFrom(this);
|
||||
newConnectionInfo.Inheritance = Inheritance.Clone();
|
||||
return newConnectionInfo;
|
||||
newConnectionInfo.Inheritance.Parent = newConnectionInfo;
|
||||
return newConnectionInfo;
|
||||
}
|
||||
|
||||
public void CopyFrom(ConnectionInfo sourceConnectionInfo)
|
||||
@@ -127,6 +127,14 @@ namespace mRemoteNG.Connection
|
||||
return filteredProperties;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<PropertyInfo> GetSerializableProperties()
|
||||
{
|
||||
var excludedProperties = new[] { "Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections",
|
||||
"IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" };
|
||||
|
||||
return GetProperties(excludedProperties);
|
||||
}
|
||||
|
||||
public virtual void SetParent(ContainerInfo newParent)
|
||||
{
|
||||
RemoveParent();
|
||||
@@ -165,10 +173,11 @@ namespace mRemoteNG.Connection
|
||||
if (!ShouldThisPropertyBeInherited(propertyName))
|
||||
return value;
|
||||
|
||||
var inheritedValue = GetInheritedPropertyValue<TPropertyType>(propertyName);
|
||||
if (inheritedValue.Equals(default(TPropertyType)))
|
||||
return value;
|
||||
return inheritedValue;
|
||||
var couldGetInheritedValue = TryGetInheritedPropertyValue<TPropertyType>(propertyName, out var inheritedValue);
|
||||
|
||||
return couldGetInheritedValue
|
||||
? inheritedValue
|
||||
: value;
|
||||
}
|
||||
|
||||
private bool ShouldThisPropertyBeInherited(string propertyName)
|
||||
@@ -189,22 +198,23 @@ namespace mRemoteNG.Connection
|
||||
return inheritPropertyValue;
|
||||
}
|
||||
|
||||
private TPropertyType GetInheritedPropertyValue<TPropertyType>(string propertyName)
|
||||
private bool TryGetInheritedPropertyValue<TPropertyType>(string propertyName, out TPropertyType inheritedValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
var connectionInfoType = Parent.GetType();
|
||||
var parentPropertyInfo = connectionInfoType.GetProperty(propertyName);
|
||||
if (parentPropertyInfo == null)
|
||||
return default(TPropertyType); // shouldn't get here...
|
||||
var parentPropertyValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
|
||||
throw new NullReferenceException($"Could not retrieve property data for property '{propertyName}' on parent node '{Parent?.Name}'");
|
||||
|
||||
return parentPropertyValue;
|
||||
inheritedValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionStackTrace($"Error retrieving inherited property '{propertyName}'", e);
|
||||
return default(TPropertyType);
|
||||
inheritedValue = default(TPropertyType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
@@ -8,14 +6,23 @@ using mRemoteNG.Messages;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Panels;
|
||||
using mRemoteNG.UI.Window;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using TabPage = Crownwood.Magic.Controls.TabPage;
|
||||
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public class ConnectionInitiator : IConnectionInitiator
|
||||
public class ConnectionInitiator : IConnectionInitiator
|
||||
{
|
||||
private readonly PanelAdder _panelAdder = new PanelAdder();
|
||||
private readonly List<string> _activeConnections = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// List of unique IDs of the currently active connections
|
||||
/// </summary>
|
||||
public IEnumerable<string> ActiveConnections => _activeConnections;
|
||||
|
||||
public void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None)
|
||||
{
|
||||
@@ -96,6 +103,7 @@ namespace mRemoteNG.Connection
|
||||
var newProtocol = protocolFactory.CreateProtocol(connectionInfo);
|
||||
|
||||
var connectionPanel = SetConnectionPanel(connectionInfo, force);
|
||||
if (string.IsNullOrEmpty(connectionPanel)) return;
|
||||
var connectionForm = SetConnectionForm(conForm, connectionPanel);
|
||||
var connectionContainer = SetConnectionContainer(connectionInfo, connectionForm);
|
||||
SetConnectionFormEventHandlers(newProtocol, connectionForm);
|
||||
@@ -117,6 +125,7 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
|
||||
connectionInfo.OpenConnections.Add(newProtocol);
|
||||
_activeConnections.Add(connectionInfo.ConstantID);
|
||||
FrmMain.Default.SelectedConnection = connectionInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -163,6 +172,10 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
connectionPanel = frmPnl.Panel;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -205,7 +218,7 @@ namespace mRemoteNG.Connection
|
||||
newProtocol.Closed += ((ConnectionWindow)connectionForm).Prot_Event_Closed;
|
||||
}
|
||||
|
||||
private static void SetConnectionEventHandlers(ProtocolBase newProtocol)
|
||||
private void SetConnectionEventHandlers(ProtocolBase newProtocol)
|
||||
{
|
||||
newProtocol.Disconnected += Prot_Event_Disconnected;
|
||||
newProtocol.Connected += Prot_Event_Connected;
|
||||
@@ -246,7 +259,7 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
}
|
||||
|
||||
private static void Prot_Event_Closed(object sender)
|
||||
private void Prot_Event_Closed(object sender)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -262,6 +275,8 @@ namespace mRemoteNG.Connection
|
||||
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strConnenctionClosedByUser, connDetail, prot.InterfaceControl.Info.Protocol, Environment.UserName));
|
||||
prot.InterfaceControl.Info.OpenConnections.Remove(prot);
|
||||
if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID))
|
||||
_activeConnections.Remove(prot.InterfaceControl.Info.ConstantID);
|
||||
|
||||
if (prot.InterfaceControl.Info.PostExtApp == "") return;
|
||||
var extA = Runtime.ExternalToolsService.GetExtAppByName(prot.InterfaceControl.Info.PostExtApp);
|
||||
|
||||
@@ -4,21 +4,31 @@ using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config;
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Config.Connections.Multiuser;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Config.Serializers.MsSql;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public class ConnectionsService
|
||||
public class ConnectionsService
|
||||
{
|
||||
private static readonly object SaveLock = new object();
|
||||
private readonly PuttySessionsManager _puttySessionsManager;
|
||||
private readonly IDataProvider<string> _localConnectionPropertiesDataProvider;
|
||||
private readonly LocalConnectionPropertiesXmlSerializer _localConnectionPropertiesSerializer;
|
||||
private bool _batchingSaves = false;
|
||||
private bool _saveRequested = false;
|
||||
private bool _saveAsyncRequested = false;
|
||||
|
||||
public bool IsConnectionsFileLoaded { get; set; }
|
||||
public bool UsingDatabase { get; private set; }
|
||||
@@ -27,11 +37,6 @@ namespace mRemoteNG.Connection
|
||||
public DateTime LastSqlUpdate { get; set; }
|
||||
|
||||
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
|
||||
//public ConnectionTreeModel ConnectionTreeModel
|
||||
//{
|
||||
// get { return Windows.TreeForm.ConnectionTree.ConnectionTreeModel; }
|
||||
// set { Windows.TreeForm.ConnectionTree.ConnectionTreeModel = value; }
|
||||
//}
|
||||
|
||||
public ConnectionsService(PuttySessionsManager puttySessionsManager)
|
||||
{
|
||||
@@ -39,17 +44,20 @@ namespace mRemoteNG.Connection
|
||||
throw new ArgumentNullException(nameof(puttySessionsManager));
|
||||
|
||||
_puttySessionsManager = puttySessionsManager;
|
||||
var path = SettingsFileInfo.SettingsPath;
|
||||
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
|
||||
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
|
||||
}
|
||||
|
||||
public void NewConnectionsFile(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
filename.ThrowIfNullOrEmpty(nameof(filename));
|
||||
var newConnectionsModel = new ConnectionTreeModel();
|
||||
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename);
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
|
||||
LoadConnections(false, false, filename);
|
||||
UpdateCustomConsPathSetting(filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -79,6 +87,10 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
newConnectionInfo.Port = uri.Port;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(newConnectionInfo.Panel))
|
||||
newConnectionInfo.Panel = Language.strGeneral;
|
||||
|
||||
newConnectionInfo.IsQuickConnect = true;
|
||||
|
||||
return newConnectionInfo;
|
||||
@@ -97,16 +109,29 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="import"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public ConnectionTreeModel LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
{
|
||||
var oldConnectionTreeModel = ConnectionTreeModel;
|
||||
var oldIsUsingDatabaseValue = UsingDatabase;
|
||||
|
||||
var newConnectionTreeModel =
|
||||
(useDatabase
|
||||
? new SqlConnectionsLoader().Load()
|
||||
: new XmlConnectionsLoader(connectionFileName).Load())
|
||||
?? new ConnectionTreeModel();
|
||||
var connectionLoader = useDatabase
|
||||
? (IConnectionsLoader)new SqlConnectionsLoader(_localConnectionPropertiesSerializer, _localConnectionPropertiesDataProvider)
|
||||
: new XmlConnectionsLoader(connectionFileName);
|
||||
|
||||
var newConnectionTreeModel = connectionLoader.Load();
|
||||
|
||||
if (useDatabase)
|
||||
LastSqlUpdate = DateTime.Now;
|
||||
|
||||
if (newConnectionTreeModel == null)
|
||||
{
|
||||
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed", IsConnectionsFileLoaded);
|
||||
return;
|
||||
}
|
||||
|
||||
IsConnectionsFileLoaded = true;
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
|
||||
if (!import)
|
||||
{
|
||||
@@ -114,12 +139,49 @@ namespace mRemoteNG.Connection
|
||||
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
|
||||
}
|
||||
|
||||
IsConnectionsFileLoaded = true;
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
ConnectionTreeModel = newConnectionTreeModel;
|
||||
UpdateCustomConsPathSetting(connectionFileName);
|
||||
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue, useDatabase, connectionFileName);
|
||||
return newConnectionTreeModel;
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Connections loaded using {connectionLoader.GetType().Name}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When turned on, calls to <see cref="SaveConnections()"/> or
|
||||
/// <see cref="SaveConnectionsAsync"/> will not immediately execute.
|
||||
/// Instead, they will be deferred until <see cref="EndBatchingSaves"/>
|
||||
/// is called.
|
||||
/// </summary>
|
||||
public void BeginBatchingSaves()
|
||||
{
|
||||
_batchingSaves = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately executes a single <see cref="SaveConnections()"/> or
|
||||
/// <see cref="SaveConnectionsAsync"/> if one has been requested
|
||||
/// since calling <see cref="BeginBatchingSaves"/>.
|
||||
/// </summary>
|
||||
public void EndBatchingSaves()
|
||||
{
|
||||
_batchingSaves = false;
|
||||
|
||||
if (_saveAsyncRequested)
|
||||
SaveConnectionsAsync();
|
||||
else if(_saveRequested)
|
||||
SaveConnections();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All calls to <see cref="SaveConnections()"/> or <see cref="SaveConnectionsAsync"/>
|
||||
/// will be deferred until the returned <see cref="DisposableAction"/> is disposed.
|
||||
/// Once disposed, this will immediately executes a single <see cref="SaveConnections()"/>
|
||||
/// or <see cref="SaveConnectionsAsync"/> if one has been requested.
|
||||
/// Place this call in a 'using' block to represent a batched saving context.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public DisposableAction BatchedSavingContext()
|
||||
{
|
||||
return new DisposableAction(BeginBatchingSaves, EndBatchingSaves);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -128,8 +190,6 @@ namespace mRemoteNG.Connection
|
||||
/// </summary>
|
||||
public void SaveConnections()
|
||||
{
|
||||
if (!IsConnectionsFileLoaded)
|
||||
return;
|
||||
SaveConnections(ConnectionTreeModel, UsingDatabase, new SaveFilter(), ConnectionFileName);
|
||||
}
|
||||
|
||||
@@ -141,19 +201,44 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="saveFilter"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public void SaveConnections(ConnectionTreeModel connectionTreeModel, bool useDatabase, SaveFilter saveFilter, string connectionFileName)
|
||||
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
|
||||
/// <param name="propertyNameTrigger">
|
||||
/// Optional. The name of the property that triggered
|
||||
/// this save.
|
||||
/// </param>
|
||||
public void SaveConnections(
|
||||
ConnectionTreeModel connectionTreeModel,
|
||||
bool useDatabase,
|
||||
SaveFilter saveFilter,
|
||||
string connectionFileName,
|
||||
bool forceSave = false,
|
||||
string propertyNameTrigger = "")
|
||||
{
|
||||
if (connectionTreeModel == null) return;
|
||||
if (connectionTreeModel == null)
|
||||
return;
|
||||
|
||||
if (!forceSave && !IsConnectionsFileLoaded)
|
||||
return;
|
||||
|
||||
if (_batchingSaves)
|
||||
{
|
||||
_saveRequested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Saving connections...");
|
||||
RemoteConnectionsSyncronizer?.Disable();
|
||||
|
||||
var previouslyUsingDatabase = UsingDatabase;
|
||||
if (useDatabase)
|
||||
new SqlConnectionsSaver(saveFilter).Save(connectionTreeModel);
|
||||
else
|
||||
new XmlConnectionsSaver(connectionFileName, saveFilter).Save(connectionTreeModel);
|
||||
|
||||
var saver = useDatabase
|
||||
? (ISaver<ConnectionTreeModel>)new SqlConnectionsSaver(saveFilter, _localConnectionPropertiesSerializer,
|
||||
_localConnectionPropertiesDataProvider)
|
||||
: new XmlConnectionsSaver(connectionFileName, saveFilter);
|
||||
|
||||
saver.Save(connectionTreeModel, propertyNameTrigger);
|
||||
|
||||
if (UsingDatabase)
|
||||
LastSqlUpdate = DateTime.Now;
|
||||
@@ -161,6 +246,7 @@ namespace mRemoteNG.Connection
|
||||
UsingDatabase = useDatabase;
|
||||
ConnectionFileName = connectionFileName;
|
||||
RaiseConnectionsSavedEvent(connectionTreeModel, previouslyUsingDatabase, UsingDatabase, connectionFileName);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Successfully saved connections");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -172,28 +258,49 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveConnectionsAsync()
|
||||
/// <summary>
|
||||
/// Save the currently loaded connections asynchronously
|
||||
/// </summary>
|
||||
/// <param name="propertyNameTrigger">
|
||||
/// Optional. The name of the property that triggered
|
||||
/// this save.
|
||||
/// </param>
|
||||
public void SaveConnectionsAsync(string propertyNameTrigger = "")
|
||||
{
|
||||
var t = new Thread(SaveConnectionsBGd);
|
||||
if (_batchingSaves)
|
||||
{
|
||||
_saveAsyncRequested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
lock (SaveLock)
|
||||
{
|
||||
SaveConnections(
|
||||
ConnectionTreeModel,
|
||||
UsingDatabase,
|
||||
new SaveFilter(),
|
||||
ConnectionFileName,
|
||||
propertyNameTrigger: propertyNameTrigger);
|
||||
}
|
||||
});
|
||||
t.SetApartmentState(ApartmentState.STA);
|
||||
t.Start();
|
||||
}
|
||||
|
||||
private void SaveConnectionsBGd()
|
||||
{
|
||||
Monitor.Enter(SaveLock);
|
||||
SaveConnections();
|
||||
Monitor.Exit(SaveLock);
|
||||
}
|
||||
|
||||
public string GetStartupConnectionFileName()
|
||||
{
|
||||
return Settings.Default.LoadConsFromCustomLocation == false ? GetDefaultStartupConnectionFileName() : Settings.Default.CustomConsPath;
|
||||
return Settings.Default.LoadConsFromCustomLocation == false
|
||||
? GetDefaultStartupConnectionFileName()
|
||||
: Settings.Default.CustomConsPath;
|
||||
}
|
||||
|
||||
public string GetDefaultStartupConnectionFileName()
|
||||
{
|
||||
return Runtime.IsPortableEdition ? GetDefaultStartupConnectionFileNamePortableEdition() : GetDefaultStartupConnectionFileNameNormalEdition();
|
||||
return Runtime.IsPortableEdition
|
||||
? GetDefaultStartupConnectionFileNamePortableEdition()
|
||||
: GetDefaultStartupConnectionFileNameNormalEdition();
|
||||
}
|
||||
|
||||
private void UpdateCustomConsPathSetting(string filename)
|
||||
|
||||
@@ -1,35 +1,44 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration;
|
||||
using mRemoteNG.App;
|
||||
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public class DefaultConnectionInfo : ConnectionInfo
|
||||
public class DefaultConnectionInfo : ConnectionInfo
|
||||
{
|
||||
public static DefaultConnectionInfo Instance { get; } = new DefaultConnectionInfo();
|
||||
private readonly string[] _excludedProperties = { "Parent", "Name", "Hostname", "Port", "Inheritance",
|
||||
"OpenConnections", "IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect" };
|
||||
|
||||
private DefaultConnectionInfo()
|
||||
{
|
||||
IsDefault = true;
|
||||
Inheritance = DefaultConnectionInheritance.Instance;
|
||||
}
|
||||
|
||||
public void LoadFrom<TSource>(TSource sourceInstance, Func<string, string> propertyNameMutator = null)
|
||||
{
|
||||
if (propertyNameMutator == null) propertyNameMutator = a => a;
|
||||
var connectionProperties = GetProperties(_excludedProperties);
|
||||
if (propertyNameMutator == null)
|
||||
propertyNameMutator = a => a;
|
||||
|
||||
var connectionProperties = GetSerializableProperties();
|
||||
foreach (var property in connectionProperties)
|
||||
{
|
||||
try
|
||||
{
|
||||
var propertyFromSource = typeof(TSource).GetProperty(propertyNameMutator(property.Name));
|
||||
if (propertyFromSource == null) continue;
|
||||
var valueFromSource = propertyFromSource.GetValue(sourceInstance, null);
|
||||
var typeConverter = TypeDescriptor.GetConverter(property.PropertyType);
|
||||
if (typeConverter.CanConvertFrom(valueFromSource.GetType()))
|
||||
property.SetValue(Instance, typeConverter.ConvertFrom(valueFromSource), null);
|
||||
var expectedPropertyName = propertyNameMutator(property.Name);
|
||||
var propertyFromSource = typeof(TSource).GetProperty(expectedPropertyName);
|
||||
if (propertyFromSource == null)
|
||||
throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found.");
|
||||
|
||||
var valueFromSource = propertyFromSource.GetValue(sourceInstance, null);
|
||||
|
||||
if (property.PropertyType.IsEnum)
|
||||
{
|
||||
property.SetValue(Instance, Enum.Parse(property.PropertyType, valueFromSource.ToString()), null);
|
||||
continue;
|
||||
}
|
||||
|
||||
property.SetValue(Instance, Convert.ChangeType(valueFromSource, property.PropertyType), null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -40,19 +49,25 @@ namespace mRemoteNG.Connection
|
||||
|
||||
public void SaveTo<TDestination>(TDestination destinationInstance, Func<string, string> propertyNameMutator = null)
|
||||
{
|
||||
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
|
||||
var inheritanceProperties = GetProperties(_excludedProperties);
|
||||
foreach (var property in inheritanceProperties)
|
||||
if (propertyNameMutator == null)
|
||||
propertyNameMutator = (a) => a;
|
||||
|
||||
var connectionProperties = GetSerializableProperties();
|
||||
|
||||
foreach (var property in connectionProperties)
|
||||
{
|
||||
try
|
||||
{
|
||||
var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
|
||||
var localValue = property.GetValue(Instance, null);
|
||||
var typeConverter = TypeDescriptor.GetConverter(property.PropertyType);
|
||||
if (propertyFromDestination != null && !typeConverter.CanConvertTo(propertyFromDestination.PropertyType)) continue;
|
||||
if (propertyFromDestination == null) continue;
|
||||
var convertedValue = typeConverter.ConvertTo(localValue, propertyFromDestination.PropertyType);
|
||||
propertyFromDestination.SetValue(destinationInstance, convertedValue, null);
|
||||
var expectedPropertyName = propertyNameMutator(property.Name);
|
||||
var propertyFromDestination = typeof(TDestination).GetProperty(expectedPropertyName);
|
||||
|
||||
if (propertyFromDestination == null)
|
||||
throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found.");
|
||||
|
||||
// ensure value is of correct type
|
||||
var value = Convert.ChangeType(property.GetValue(Instance, null), propertyFromDestination.PropertyType);
|
||||
|
||||
propertyFromDestination.SetValue(destinationInstance, value, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using mRemoteNG.Container;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public interface IConnectionInitiator
|
||||
{
|
||||
IEnumerable<string> ActiveConnections { get; }
|
||||
|
||||
void OpenConnection(ConnectionInfo connectionInfo);
|
||||
|
||||
void OpenConnection(ContainerInfo containerInfo, ConnectionInfo.Force force = ConnectionInfo.Force.None);
|
||||
|
||||
@@ -117,57 +117,55 @@ namespace mRemoteNG.Connection.Protocol.ICA
|
||||
return;
|
||||
}
|
||||
|
||||
var user = _info?.Username ?? "";
|
||||
var pass = _info?.Password ?? "";
|
||||
var dom = _info?.Domain ?? "";
|
||||
var user = _info?.Username ?? "";
|
||||
var pass = _info?.Password ?? "";
|
||||
var dom = _info?.Domain ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(user))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
_icaClient.Username = Environment.UserName;
|
||||
user = Environment.UserName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom")
|
||||
else if (Settings.Default.EmptyCredentials == "custom" || Settings.Default.EmptyCredentials == "admpwd")
|
||||
{
|
||||
_icaClient.Username = Settings.Default.DefaultUsername;
|
||||
user = Settings.Default.DefaultUsername;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (string.IsNullOrEmpty(dom))
|
||||
{
|
||||
_icaClient.Username = user;
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
dom = Environment.UserDomainName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom" || Settings.Default.EmptyCredentials == "admpwd")
|
||||
{
|
||||
dom = Settings.Default.DefaultDomain;
|
||||
}
|
||||
}
|
||||
|
||||
_icaClient.Username = user;
|
||||
_icaClient.Domain = dom;
|
||||
|
||||
if (string.IsNullOrEmpty(pass))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
if (Settings.Default.DefaultPassword != "")
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
_icaClient.SetProp("ClearPassword", cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey));
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
pass = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_icaClient.SetProp("ClearPassword", pass);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(dom))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
if (Settings.Default.EmptyCredentials == "admpwd")
|
||||
{
|
||||
_icaClient.Domain = Environment.UserDomainName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
_icaClient.Domain = Settings.Default.DefaultDomain;
|
||||
if (dom == ".")
|
||||
pass = AdmPwd.PDSUtils.PdsWrapper.GetPassword(null, _info.Hostname, AdmPwd.Types.IdentityType.LocalComputerAdmin, false, false).Password;
|
||||
else
|
||||
pass = AdmPwd.PDSUtils.PdsWrapper.GetPassword(dom, user, AdmPwd.Types.IdentityType.ManagedDomainAccount, false, false).Password;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_icaClient.Domain = dom;
|
||||
}
|
||||
|
||||
_icaClient.SetProp("ClearPassword", pass);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@ using mRemoteNG.Tools.Cmdline;
|
||||
namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
public class PuttyBase : ProtocolBase
|
||||
{
|
||||
{
|
||||
private const int IDM_RECONF = 0x50; // PuTTY Settings Menu ID
|
||||
private bool _isPuttyNg;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
Event_Closed(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Methods
|
||||
public override bool Connect()
|
||||
{
|
||||
@@ -62,11 +62,11 @@ namespace mRemoteNG.Connection.Protocol
|
||||
var arguments = new CommandLineArguments {EscapeForShell = false};
|
||||
|
||||
arguments.Add("-load", InterfaceControl.Info.PuttySession);
|
||||
|
||||
|
||||
if (!(InterfaceControl.Info is PuttySessionInfo))
|
||||
{
|
||||
arguments.Add("-" + PuttyProtocol);
|
||||
|
||||
|
||||
if (PuttyProtocol == Putty_Protocol.ssh)
|
||||
{
|
||||
var username = "";
|
||||
@@ -89,7 +89,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password))
|
||||
{
|
||||
password = InterfaceControl.Info.Password;
|
||||
@@ -102,9 +102,9 @@ namespace mRemoteNG.Connection.Protocol
|
||||
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
arguments.Add("-" + (int)PuttySSHVersion);
|
||||
|
||||
|
||||
if (((int)Force & (int)ConnectionInfo.Force.NoCredentials) != (int)ConnectionInfo.Force.NoCredentials)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(username))
|
||||
@@ -117,24 +117,24 @@ namespace mRemoteNG.Connection.Protocol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
arguments.Add("-P", InterfaceControl.Info.Port.ToString());
|
||||
arguments.Add(InterfaceControl.Info.Hostname);
|
||||
}
|
||||
|
||||
|
||||
if (_isPuttyNg)
|
||||
{
|
||||
arguments.Add("-hwndparent", InterfaceControl.Handle.ToString());
|
||||
}
|
||||
|
||||
|
||||
PuttyProcess.StartInfo.Arguments = arguments.ToString();
|
||||
|
||||
|
||||
PuttyProcess.EnableRaisingEvents = true;
|
||||
PuttyProcess.Exited += ProcessExited;
|
||||
|
||||
|
||||
PuttyProcess.Start();
|
||||
PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
|
||||
|
||||
|
||||
var startTicks = Environment.TickCount;
|
||||
while (PuttyHandle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
|
||||
{
|
||||
@@ -153,17 +153,17 @@ namespace mRemoteNG.Connection.Protocol
|
||||
Thread.Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!_isPuttyNg)
|
||||
{
|
||||
NativeMethods.SetParent(PuttyHandle, InterfaceControl.Handle);
|
||||
}
|
||||
|
||||
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strPuttyStuff, true);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyHandle, PuttyHandle), true);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyTitle, PuttyProcess.MainWindowTitle), true);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strPuttyParentHandle, InterfaceControl.Parent.Handle), true);
|
||||
|
||||
|
||||
Resize(this, new EventArgs());
|
||||
base.Connect();
|
||||
return true;
|
||||
@@ -174,7 +174,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Focus()
|
||||
{
|
||||
try
|
||||
@@ -190,7 +190,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyFocusFailed + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Resize(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -199,14 +199,29 @@ namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
return;
|
||||
}
|
||||
NativeMethods.MoveWindow(PuttyHandle, -SystemInformation.FrameBorderSize.Width, -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height), InterfaceControl.Width + SystemInformation.FrameBorderSize.Width * 2, InterfaceControl.Height + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2, true);
|
||||
}
|
||||
|
||||
if (_isPuttyNg)
|
||||
{
|
||||
// PuTTYNG 0.70.0.1 and later doesn't have any window borders
|
||||
NativeMethods.MoveWindow(PuttyHandle, 0, 0, InterfaceControl.Width, InterfaceControl.Height, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var left = -(SystemInformation.FrameBorderSize.Width + SystemInformation.HorizontalResizeBorderThickness);
|
||||
var top = -(SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height + SystemInformation.VerticalResizeBorderThickness);
|
||||
var width = InterfaceControl.Width + (SystemInformation.FrameBorderSize.Width + SystemInformation.HorizontalResizeBorderThickness) * 2;
|
||||
var height = InterfaceControl.Height + SystemInformation.CaptionHeight + (SystemInformation.FrameBorderSize.Height +
|
||||
SystemInformation.VerticalResizeBorderThickness) * 2;
|
||||
|
||||
NativeMethods.MoveWindow(PuttyHandle, left, top, width, height, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyResizeFailed + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
try
|
||||
@@ -220,7 +235,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyKillFailed + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
PuttyProcess.Dispose();
|
||||
@@ -229,10 +244,10 @@ namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, Language.strPuttyDisposeFailed + Environment.NewLine + ex.Message, true);
|
||||
}
|
||||
|
||||
|
||||
base.Close();
|
||||
}
|
||||
|
||||
|
||||
public void ShowSettingsDialog()
|
||||
{
|
||||
try
|
||||
@@ -246,7 +261,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Enums
|
||||
|
||||
protected enum Putty_Protocol
|
||||
|
||||
@@ -316,10 +316,19 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
return;
|
||||
}
|
||||
|
||||
var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size;
|
||||
try
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Resizing RDP connection to host '{_connectionInfo.Hostname}'");
|
||||
var size = !Fullscreen ? Control.Size : Screen.FromControl(Control).Bounds.Size;
|
||||
|
||||
IMsRdpClient8 msRdpClient8 = _rdpClient;
|
||||
msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height);
|
||||
IMsRdpClient8 msRdpClient8 = _rdpClient;
|
||||
msRdpClient8.Reconnect((uint)size.Width, (uint)size.Height);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.ChangeConnectionResolutionError, _connectionInfo.Hostname),
|
||||
ex, MessageClass.WarningMsg, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRdGateway()
|
||||
@@ -346,9 +355,12 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
if (_connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes)
|
||||
{
|
||||
_rdpClient.TransportSettings2.GatewayUsername = _connectionInfo.Username;
|
||||
_rdpClient.TransportSettings2.GatewayPassword = _connectionInfo.Password;
|
||||
_rdpClient.TransportSettings2.GatewayDomain = _connectionInfo?.Domain;
|
||||
var userName = GetUserName(_connectionInfo?.Username ?? "");
|
||||
var domain = GetDomain(_connectionInfo?.Domain ?? "");
|
||||
|
||||
_rdpClient.TransportSettings2.GatewayUsername = userName;
|
||||
_rdpClient.TransportSettings2.GatewayDomain = domain;
|
||||
_rdpClient.TransportSettings2.GatewayPassword = GetPassword((_connectionInfo?.Password ?? ""), userName, domain, _connectionInfo.Hostname);
|
||||
}
|
||||
else if (_connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard)
|
||||
{
|
||||
@@ -356,11 +368,14 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.TransportSettings2.GatewayUsername = _connectionInfo.RDGatewayUsername;
|
||||
_rdpClient.TransportSettings2.GatewayPassword = _connectionInfo.RDGatewayPassword;
|
||||
_rdpClient.TransportSettings2.GatewayDomain = _connectionInfo.RDGatewayDomain;
|
||||
_rdpClient.TransportSettings2.GatewayCredSharing = 0;
|
||||
}
|
||||
var userName = GetUserName(_connectionInfo.RDGatewayUsername);
|
||||
var domain = GetDomain(_connectionInfo.RDGatewayDomain);
|
||||
|
||||
_rdpClient.TransportSettings2.GatewayUsername = userName;
|
||||
_rdpClient.TransportSettings2.GatewayDomain = domain;
|
||||
_rdpClient.TransportSettings2.GatewayPassword = GetPassword(_connectionInfo.RDGatewayPassword, userName, domain, _connectionInfo.Hostname);
|
||||
_rdpClient.TransportSettings2.GatewayCredSharing = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -407,7 +422,60 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
Runtime.MessageCollector.AddExceptionStackTrace(Language.strRdpSetConsoleSessionFailed, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string GetUserName(string userName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userName))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
userName = Environment.UserName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom" || Settings.Default.EmptyCredentials == "admpwd")
|
||||
{
|
||||
userName = Settings.Default.DefaultUsername;
|
||||
}
|
||||
}
|
||||
return userName;
|
||||
}
|
||||
private string GetDomain(string domain)
|
||||
{
|
||||
if (string.IsNullOrEmpty(domain))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
domain = Environment.UserDomainName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom" || Settings.Default.EmptyCredentials == "admpwd")
|
||||
{
|
||||
domain = Settings.Default.DefaultDomain;
|
||||
}
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
private string GetPassword(string password, string userName, string domain, string host)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
if (Settings.Default.DefaultPassword != "")
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
if (Settings.Default.EmptyCredentials == "admpwd")
|
||||
{
|
||||
if (domain == ".")
|
||||
password = AdmPwd.PDSUtils.PdsWrapper.GetPassword(null, host, AdmPwd.Types.IdentityType.LocalComputerAdmin, false, false).Password;
|
||||
else
|
||||
password = AdmPwd.PDSUtils.PdsWrapper.GetPassword(domain, userName, AdmPwd.Types.IdentityType.ManagedDomainAccount, false, false).Password;
|
||||
}
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
private void SetCredentials()
|
||||
{
|
||||
try
|
||||
@@ -417,57 +485,13 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
return;
|
||||
}
|
||||
|
||||
var userName = _connectionInfo?.Username ?? "";
|
||||
var password = _connectionInfo?.Password ?? "";
|
||||
var domain = _connectionInfo?.Domain ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(userName))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
_rdpClient.UserName = Environment.UserName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
_rdpClient.UserName = Settings.Default.DefaultUsername;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.UserName = userName;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
if (Settings.Default.DefaultPassword != "")
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
_rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.AdvancedSettings2.ClearTextPassword = password;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(domain))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
_rdpClient.Domain = Environment.UserDomainName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
_rdpClient.Domain = Settings.Default.DefaultDomain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.Domain = domain;
|
||||
}
|
||||
var userName = GetUserName(_connectionInfo?.Username ?? "");
|
||||
var domain = GetDomain(_connectionInfo?.Domain ?? "");
|
||||
|
||||
_rdpClient.Domain = domain;
|
||||
_rdpClient.UserName = userName;
|
||||
_rdpClient.AdvancedSettings2.ClearTextPassword = GetPassword((_connectionInfo?.Password ?? ""), userName, domain, _connectionInfo.Hostname);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -916,17 +940,25 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
#region Reconnect Stuff
|
||||
public void tmrReconnect_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port));
|
||||
try
|
||||
{
|
||||
var srvReady = PortScanner.IsPortOpen(_connectionInfo.Hostname, Convert.ToString(_connectionInfo.Port));
|
||||
|
||||
ReconnectGroup.ServerReady = srvReady;
|
||||
ReconnectGroup.ServerReady = srvReady;
|
||||
|
||||
if (ReconnectGroup.ReconnectWhenReady && srvReady)
|
||||
{
|
||||
tmrReconnect.Enabled = false;
|
||||
ReconnectGroup.DisposeReconnectGroup();
|
||||
//SetProps()
|
||||
_rdpClient.Connect();
|
||||
}
|
||||
if (ReconnectGroup.ReconnectWhenReady && srvReady)
|
||||
{
|
||||
tmrReconnect.Enabled = false;
|
||||
ReconnectGroup.DisposeReconnectGroup();
|
||||
//SetProps()
|
||||
_rdpClient.Connect();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionMessage(string.Format(Language.AutomaticReconnectError, _connectionInfo.Hostname),
|
||||
ex, MessageClass.WarningMsg, false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace mRemoteNG.Connection
|
||||
connectionInfo.Hostname = url;
|
||||
connectionInfo.Protocol = url.StartsWith("https:") ? ProtocolType.HTTPS : ProtocolType.HTTP;
|
||||
connectionInfo.SetDefaultPort();
|
||||
if (string.IsNullOrEmpty(connectionInfo.Panel))
|
||||
connectionInfo.Panel = Language.strGeneral;
|
||||
connectionInfo.IsQuickConnect = true;
|
||||
var connectionInitiator = new ConnectionInitiator();
|
||||
connectionInitiator.OpenConnection(connectionInfo, ConnectionInfo.Force.DoNotJump);
|
||||
|
||||
@@ -12,13 +12,19 @@ namespace mRemoteNG.Container
|
||||
[DefaultProperty("Name")]
|
||||
public class ContainerInfo : ConnectionInfo, INotifyCollectionChanged
|
||||
{
|
||||
[Browsable(false)]
|
||||
private bool _isExpanded;
|
||||
|
||||
[Browsable(false)]
|
||||
public List<ConnectionInfo> Children { get; } = new List<ConnectionInfo>();
|
||||
|
||||
[Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)]
|
||||
public bool IsExpanded { get; set; }
|
||||
[Category(""), Browsable(false), ReadOnly(false), Bindable(false), DefaultValue(""), DesignOnly(false)]
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => _isExpanded;
|
||||
set => SetField(ref _isExpanded, value, "IsExpanded");
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
[Browsable(false)]
|
||||
public override bool IsContainer { get { return true; } set {} }
|
||||
|
||||
public ContainerInfo(string uniqueId)
|
||||
|
||||
357
mRemoteV1/Docs/PDSConfigWrapper.xml
Normal file
357
mRemoteV1/Docs/PDSConfigWrapper.xml
Normal file
@@ -0,0 +1,357 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--Management interface-->
|
||||
<PdsConfigWrapper>
|
||||
<GetPds>
|
||||
<summary>
|
||||
Returns list of PDS discovered either form DNS or from GPO
|
||||
</summary>
|
||||
<returns>Returns list of PDS instances discovered</returns>
|
||||
<remarks>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetPds>
|
||||
<GetSupportedForest>
|
||||
<summary>
|
||||
Calls PDS to get list of supported forests as configured in PDS configuration file.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to query list of supported forests.
|
||||
</param>
|
||||
<returns>List of names of AD forests as known by given PDS instance (optionaly with connection credentials and id of enryption key that is used to protect them is configuration file), or null if no specific AD forests are configured and PDS just covers local AD forest.</returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</GetSupportedForest>
|
||||
<AddSupportedForest>
|
||||
<summary>
|
||||
Calls PDS to add new AD forest to list of supported forests.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance that will be target of the operation. If operating more intances of PDS, supported AD forest must be added to each of them, so as PDS configuration is consistent across all instances.
|
||||
</param>
|
||||
<param name="Forest">
|
||||
Specifies parameters of the newly supported forest
|
||||
</param>
|
||||
<returns>Newly added supported forest.</returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</AddSupportedForest>
|
||||
<SetSupportedForest>
|
||||
<summary>
|
||||
Calls PDS to update supported forest parameters (typically connection credentials).
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to perform the operation on. If operating more intances of PDS, update must be performed on each of them to ensure consistency of configuration across all instances of PDS.
|
||||
</param>
|
||||
<param name="Forest">
|
||||
Specifies parameters to be updated on the forest
|
||||
</param>
|
||||
<returns>Updated supported forest.</returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</SetSupportedForest>
|
||||
<RemoveSupportedForest>
|
||||
<summary>
|
||||
Calls PDS to add remove AD forest from list of supported forests.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to remove the forest from list of supported forests. If operating more intances of PDS, supported AD forest must be removed from each of them.
|
||||
</param>
|
||||
<param name="Forest">
|
||||
Specifies parameters of the removed forest. Only DNS name of Forest is used to identify forest to be removed.
|
||||
</param>
|
||||
<returns>Removed forest.</returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</RemoveSupportedForest>
|
||||
<AddSidMapping>
|
||||
<summary>
|
||||
Calls PDS to add maping of security principal from untrusted forest to security principal from trusted forest.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with. If operating more intances of PDS, SID mapping must be added to each of them to ensure configuration consistency.
|
||||
</param>
|
||||
<param name="Mapping">
|
||||
Specifies parameters of the SID mapping.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</AddSidMapping>
|
||||
<UpdateSidMapping>
|
||||
<summary>
|
||||
Calls PDS to modify maping of security principal from untrusted forest to security principal from trusted forest.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with. If operating more intances of PDS, SID mapping must be updated on each of them to ensure configuration consistency.
|
||||
</param>
|
||||
<param name="Mapping">
|
||||
Specifies parameters of the SID mapping.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</UpdateSidMapping>
|
||||
<GetSidMapping>
|
||||
<summary>
|
||||
Calls PDS to get configured mapings of security principal from untrusted forest to security principal from trusted forest.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<returns>List of configured SID mappings</returns>
|
||||
<remarks>
|
||||
<para>Can be called by any authenticated user</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetSidMapping>
|
||||
<RemoveSidMapping>
|
||||
<summary>
|
||||
Calls PDS to add remove SID mappings from list of mappings.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to remove the mapping from. If operating more intances of PDS, mapping must be removed from each of them.
|
||||
</param>
|
||||
<param name="PrimarySid">
|
||||
Specifies Primary SID of mapping to be removed.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</RemoveSidMapping>
|
||||
<AddManagedAccountsContainer>
|
||||
<summary>
|
||||
Calls PDS to add AD container with accounts with automatically managed password.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with. If operating more intances of PDS, container must be added to configuration of each of them to ensure configuration consistency.
|
||||
</param>
|
||||
<param name="Container">
|
||||
Specifies parameters of password for accounts located in AD container.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</AddManagedAccountsContainer>
|
||||
<GetManagedAccountsContainer>
|
||||
<summary>
|
||||
Calls PDS to retrieve configuration of AD containers with accounts with automatically managed password.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<returns>List of managed domain acocunts containers as defined in PDS configuration file.</returns>
|
||||
<remarks>
|
||||
<para>Can be called by any authenticated user</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetManagedAccountsContainer>
|
||||
<SetManagedAccountsContainer>
|
||||
<summary>
|
||||
Calls PDS to update configuration of AD container with accounts with automatically managed password.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with. If operating more intances of PDS, container must be updated on each of them to ensure configuration consistency.
|
||||
</param>
|
||||
<param name="Container">
|
||||
Specifies parameters of password for accounts located in given AD container.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</SetManagedAccountsContainer>
|
||||
<RemoveManagedAccountsContainer>
|
||||
<summary>
|
||||
Calls PDS to remove AD container with accounts with automatically managed password from PDS configuration.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with. If operating more intances of PDS, container must be removed from each of them to ensure configuration consistency.
|
||||
</param>
|
||||
<param name="DN">
|
||||
Specifies distinguishedName of container to be removed from configuration.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</RemoveManagedAccountsContainer>
|
||||
<TransferPdsAdminRole>
|
||||
<summary>
|
||||
Transfers PDS Admin role to security principal (user or group)
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
<para>Identifies PDS instance to work with.</para>
|
||||
<para>Important: If operating more intances of PDS, configuration change must be performed on each of them to ensure configuration consistency.</para>
|
||||
</param>
|
||||
<param name="NewRoleHolder">
|
||||
Name of new holder of PDS Admin role. Should include domain name.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</TransferPdsAdminRole>
|
||||
<UpdateManagedAccountsParameters>
|
||||
<summary>
|
||||
Updates global configuration of managed domain accounts processing.<br/>
|
||||
Note: Currently, only global parameter supported is interval of scanning of managed domain accounts for password expiration.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
<para>Identifies PDS instance to work with.</para>
|
||||
<para>Important: If operating more intances of PDS, configuration change must be performed on each of them to ensure configuration consistency.</para>
|
||||
</param>
|
||||
<param name="ManagementInterval">
|
||||
Interval of scanning of managed domain accounts for password expiration.
|
||||
</param>
|
||||
<returns></returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</UpdateManagedAccountsParameters>
|
||||
<GetManagedAccountsParameters>
|
||||
<summary>
|
||||
Returns global configuration of managed domain accounts processing.<br/>
|
||||
Note: Currently, only global parameter supported is interval of scanning of managed domain accounts for password expiration.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<returns>Global configuration of managed domain accounts processing.</returns>
|
||||
<remarks>
|
||||
</remarks>
|
||||
</GetManagedAccountsParameters>
|
||||
<GetDnsParameters>
|
||||
<summary>
|
||||
Returns parameters of DNS registration for PDS autodiscover SRV records.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<returns>
|
||||
<see cref="DnsParameters"/> object.
|
||||
</returns>
|
||||
<remarks>
|
||||
</remarks>
|
||||
</GetDnsParameters>
|
||||
<UpdateDnsParameters>
|
||||
<summary>
|
||||
Updates parameters of DNS registration for PDS autodiscover SRV records.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
<para>Identifies PDS instance to work with.</para>
|
||||
<para>Important: If operating more intances of PDS, configuration change must be performed on each of them to ensure configuration consistency.</para>
|
||||
</param>
|
||||
<param name="Priority">Priority of SRV record. Null means default, which is 100.</param>
|
||||
<param name="RegistrationInterval">How often PDS service re-registers autodiscover record to prevent its expiration. Null means default, which is 86400 seconds (1 day).</param>
|
||||
<param name="Ttl">Time-to-live for registered SRV record. Null means default, which is 1200 seconds (20 minutes)</param>
|
||||
<param name="UnregisterOnShutdown">Whether or not the SRV record shall be unregistered then services stops, to prevent autodiscover records pointing to non-operating PDS instance. Null means default, which is 'true'</param>
|
||||
<param name="Weight">Weight of registered SRV record.<br/>
|
||||
Note: Weight is not used by the solution.
|
||||
</param>
|
||||
<returns>
|
||||
</returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</UpdateDnsParameters>
|
||||
<UpdateAccessControlParameters>
|
||||
<summary>
|
||||
Updates parameters of access control process for password reads and resets.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
<para>Identifies PDS instance to work with.</para>
|
||||
<para>Important: If operating more intances of PDS, configuration change must be performed on each of them to ensure configuration consistency.</para>
|
||||
</param>
|
||||
<param name="HonorAllExtendedRightsPermission">Whether 'All extended rights' permission also includes 'Read password' and 'Reset password' permission.Null means default, which is 'false'.</param>
|
||||
<param name="HonorFullControlPermission">Whether 'Full control' permission also includes 'Read password' and 'Reset password' permission.Null means default, which is 'false'.</param>
|
||||
<param name="HonorLocalGroupsFromRemoteComputerDomain">
|
||||
<para>
|
||||
Whether PDS also evaluates membership in local groups from remote domain.
|
||||
</para>
|
||||
<para>
|
||||
Consider the following scenario:
|
||||
<list>
|
||||
<item>PDS is installed in forest domain A</item>
|
||||
<item>Computer account X we want know admin password for is in forest domain B</item>
|
||||
<item>User U who wants to know admin password for computer X is also in forest domain B</item>
|
||||
<item>User U is member of Domain local group DLG</item>
|
||||
<item>Permission to read the admin password for computer X is delegated to group DLG</item>
|
||||
</list>
|
||||
In this case, when PDS is performing access check, it normally does NOT see user U being member of group DLG (because membership in Domain Local groups is not propagated to other domains in forest), and because of that, it replies with AccessDenied error. Setting this parameter to true makes PDS to perform direct lookup for local group membership of user in his home domain to make sure that complete membership is evaluated.
|
||||
This additional lookup consumes PDS service resources and requires direct connection between PDS and domain controller of user's domain, so delegation using domain Local groups in multi-forest domains should be avoided.
|
||||
</para>
|
||||
</param>
|
||||
<param name="MandatoryGroupSids">List of Security Identifiers (SIDs) that caller additionally must be member of for calls to password reads/resets to succeed. Membership in such groups is then additional gate that allows to perform active operations. If multiple groups specified, user must be member of at least 1 of them. This helps implement additional levels of access control, such as JIT of Authentication Mechanism Assurance (AMA)</param>
|
||||
<returns>
|
||||
</returns>
|
||||
<remarks>
|
||||
<para>PDS Admin role is required to successfully call this method</para>
|
||||
<para>Call is audited</para>
|
||||
</remarks>
|
||||
</UpdateAccessControlParameters>
|
||||
<GetAccessControlsParameters>
|
||||
<summary>
|
||||
Returns parameters of access control process for password reads and resets.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<returns>
|
||||
<see cref="AccessControlParameters"/> object.
|
||||
</returns>
|
||||
<remarks>
|
||||
</remarks>
|
||||
</GetAccessControlsParameters>
|
||||
<GetLicenseParameters>
|
||||
<summary>
|
||||
Returns parameters of current license, including path to license file.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<returns>
|
||||
<see cref="LicenseParameters"/> object.
|
||||
</returns>
|
||||
<remarks>
|
||||
</remarks>
|
||||
</GetLicenseParameters>
|
||||
<UpdateLicenseFilePath>
|
||||
<summary>
|
||||
Updates path to license file.
|
||||
</summary>
|
||||
<param name="Pds">
|
||||
Identifies PDS instance to work with.
|
||||
</param>
|
||||
<param name="FilePath">
|
||||
Absolute or relative path to license file that Pds instance shall use.
|
||||
</param>
|
||||
<returns>
|
||||
<see cref="LicenseParameters"/> object.
|
||||
</returns>
|
||||
<remarks>
|
||||
</remarks>
|
||||
</UpdateLicenseFilePath>
|
||||
|
||||
</PdsConfigWrapper>
|
||||
374
mRemoteV1/Docs/PdsWrapper.xml
Normal file
374
mRemoteV1/Docs/PdsWrapper.xml
Normal file
@@ -0,0 +1,374 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<PdsWrapper>
|
||||
<UpsertSupportedForest>
|
||||
<summary>
|
||||
Calls PDS to request add or update supported forest to configuration file in PDS.
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of new or update supported forest.
|
||||
</param>
|
||||
<param name="User">
|
||||
Name of account which use for ldap connection to supported forest.
|
||||
Account name can be passed as one of the following:
|
||||
<list type="bullet">
|
||||
<item>sAMAccountName (with domain)</item>
|
||||
<item>userPrincipalName</item>
|
||||
</list>
|
||||
<para>Together with parameter "User" must set parameters "Password" and "KeyId".</para>
|
||||
</param>
|
||||
<param name="Password">
|
||||
Password for account which use for ldap connection to supported forest.
|
||||
<para>Together with parameter "Password" must set parameters "User" and "KeyId".</para>
|
||||
</param>
|
||||
<param name="KeyId">
|
||||
Identifies key pair to which the password is encrypted.
|
||||
<para>Together with parameter "KeyId" must set parameters "User" and "Password".</para>
|
||||
</param>
|
||||
<returns>List of PDS instances where added or updated supported forest.</returns>
|
||||
<para>When parameter User, Password and KeyID are not set, use default PDS credentials</para>
|
||||
<para>
|
||||
Caller must have PDS Admin role. For callers without role, AccessDenied exception is thrown. To find out, if caller has PDS Admin role, call method <see cref="IsPDSAdmin"/>.
|
||||
</para>
|
||||
<para>By default, PDS Admin role is assigned to Enterprise Admins group and can be changed via PDS configuration file.</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</UpsertSupportedForest>
|
||||
<ResetManagedAccountPassword>
|
||||
<summary>
|
||||
Calls PDS to request reset of managed account password in given AD forest.
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
<para>
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest (forest where PDS is installed), you can pass null as parameter value
|
||||
</para>
|
||||
</param>
|
||||
<param name="AccountName">
|
||||
Name of account where password shall be reset.
|
||||
Account name can be passed as one of the following:
|
||||
* sAMAccountName (without domain)
|
||||
* userPrincipalName
|
||||
* distinguishedName
|
||||
</param>
|
||||
<param name="WhenEffective">When password reset shall occur. Password will be reset during next PDS management cycle - see passwordManagementInterval in PDS config file.</param>
|
||||
<returns>Information about result of operation along with account name and DN</returns>
|
||||
<remarks>
|
||||
<para>
|
||||
PDS does not try to guess domain or forest name from account name - it searches against Global Catalog interface of AD forest passed in <paramref name="ForestName"/> parameter
|
||||
</para>
|
||||
<para>Caller must have Reset Local Admin Passsword permission on given managed account object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</ResetManagedAccountPassword>
|
||||
<GetEnvironmentStats>
|
||||
<summary>
|
||||
Calls PDs to retrieve environment status for managed environment:
|
||||
* List of domains in each managed forest, along with number of managed machines and domain accounts in each domain
|
||||
* Overall status for each AD forest, including license expiration and consumption
|
||||
</summary>
|
||||
<returns>Environment status for the solution</returns>
|
||||
<remarks>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetEnvironmentStats>
|
||||
<GetUserPermissions>
|
||||
<summary>
|
||||
Calls PDS to retrieve information about AdmPwd.E permissions that given user has on computer object, as seen by PDS
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest, pass null as parameter value
|
||||
</param>
|
||||
<param name="ComputerName">Name of computer where password of local admin account shall be reset</param>
|
||||
<param name="UserUpn">UserPrincipalName of user in question.</param>
|
||||
<returns>List of solution specific permissions PDS finds for given user for given computer object </returns>
|
||||
<remarks>
|
||||
<para>This method uses Kerberos S2U4Self logon to obtain user's Kerberos ticket with security group membership of user account in question</para>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetUserPermissions>
|
||||
<GetKeyAdminsRoleName>
|
||||
<summary>
|
||||
Calls PDS to retrieve name of AD group that implements Key Admin role. Members of the group hold Key Admin role on PDS
|
||||
</summary>
|
||||
<returns>Returns name of AD group that is configured on PDS as Key Admin role group</returns>
|
||||
<remarks>
|
||||
<para>By default, this role is held by Enterprise Admins group. Role assignment can be changed in PDS configuration file.</para>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetKeyAdminsRoleName>
|
||||
<GetSupportedKeySizes>
|
||||
<summary>
|
||||
Calls PDS to retrieve key sizes supported by PDS.
|
||||
</summary>
|
||||
<returns>List of supported key sizes, in bits</returns>
|
||||
<remarks>
|
||||
<para>
|
||||
PDS only creates key pairs of supported sizes; however it can decrypt passwords encrypted by any valid RSA key - see <see cref="GenerateKeyPair"/> method to see how to generate new key pair
|
||||
</para>
|
||||
<para>Supported key sizes are configured in PDS configuration file.</para>
|
||||
<para>RSA CSP used by solution supports key sizes up to 16384 bits in 8-bit increments on Windows OS.</para>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetSupportedKeySizes>
|
||||
<IsPDSAdmin>
|
||||
<summary>
|
||||
Calls PDS to return information whether or not the caller is in Key Admin role on PDS
|
||||
</summary>
|
||||
<returns>True if caller is in Key Admin role on PDS. Otherwise returns false.</returns>
|
||||
<remarks>
|
||||
<para>Can be used by various client tools to properly render UI and allow users in KeyAdmin role to see key pair management UI</para>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</IsPDSAdmin>
|
||||
<GetManagedAccountPassword>
|
||||
<summary>
|
||||
Retrieves password of managed account in given AD forest.
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
<para>
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest (forest where PDS is installed), you can pass null as parameter value
|
||||
</para>
|
||||
</param>
|
||||
<param name="AccountName">
|
||||
Name of account where password shall be read.
|
||||
Account name can be passed as one of the following:
|
||||
* sAMAccountName (without domain)
|
||||
* userPrincipalName
|
||||
* distinguishedName
|
||||
</param>
|
||||
<param name="IncludePasswordHistory">Whether or not to include password history</param>
|
||||
<returns>Password, current password expiration time and optional password history</returns>
|
||||
<remarks>
|
||||
<para>
|
||||
PDS does not try to guess domain or forest name from account name - it searches against Global Catalog interface of AD forest passed in <paramref name="ForestName"/> parameter for account as specified in <paramRef name="AccountName"/>
|
||||
</para>
|
||||
<para>Caller must have Read Local Admin Passsword permission on given managed account object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</GetManagedAccountPassword>
|
||||
<GetPassword>
|
||||
<summary>
|
||||
Calls PDS to retrieve password of managed account in given AD forest.
|
||||
Managed account can be either:
|
||||
* Domain computer local admin account
|
||||
* Managed domain account
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest, pass null as parameter value
|
||||
</param>
|
||||
<param name="Identity">
|
||||
When retrieving password of computer local admin account, pass name of computer where password of local admin account shall be retrieved. Name of the computer can be passed as one of the following:
|
||||
* Hostname, such as MyComputer
|
||||
* FQDN, such as mycomputer.mydomain.com
|
||||
* Distinguished name, such as cn=MyComputer,ou=MyComputers,dc=mydomain,dc=com
|
||||
<para/>
|
||||
When retrieving password of managed domain account, pas the name of domain account. Account name can be passed as one of the following:
|
||||
* sAMAccountName (without domain)
|
||||
* userPrincipalName
|
||||
* distinguishedName
|
||||
</param>
|
||||
<param name="Type">
|
||||
Type of the account to retrieve password for. Can be one of the supported account types:
|
||||
* LocalComputerAdmin
|
||||
* ManagedDomainAccount
|
||||
</param>
|
||||
<param name="IncludePasswordHistory">Whether or not to include password history</param>
|
||||
<param name="IsDeleted">
|
||||
Whether computer account or managed domain account is deleted or not.
|
||||
Note: there may be multiple deleted objects with the same name. In such case, password for most recently deleted object is returned
|
||||
</param>
|
||||
<returns>Password, current password expiration time and optional password history. Passwords returned are plain text</returns>
|
||||
<remarks>
|
||||
<para>Name of local admin account is not stored by solution. Caller is expected to know name of local managed account</para>
|
||||
<para>
|
||||
PDS does not try to guess domain or forest name from computer name - it searches against Global Catalog interface of AD forest passed in <paramref name="ForestName"/> parameter
|
||||
</para>
|
||||
<para>Caller must have Read Admin Passsword permission on given computer or user object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</GetPassword>
|
||||
<GetSecurePassword>
|
||||
<summary>
|
||||
Calls PDS to retrieve password of managed account in given AD forest.
|
||||
Managed account can be either:
|
||||
* Domain computer local admin account
|
||||
* Managed domain account
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest, pass null as parameter value
|
||||
</param>
|
||||
<param name="Identity">
|
||||
When retrieving password of computer local admin account, pass name of computer where password of local admin account shall be retrieved. Name of the computer can be passed as one of the following:
|
||||
* Hostname, such as MyComputer
|
||||
* FQDN, such as mycomputer.mydomain.com
|
||||
* Distinguished name, such as cn=MyComputer,ou=MyComputers,dc=mydomain,dc=com
|
||||
<para/>
|
||||
When retrieving password of managed domain account, pas the name of domain account. Account name can be passed as one of the following:
|
||||
* sAMAccountName (without domain)
|
||||
* userPrincipalName
|
||||
* distinguishedName
|
||||
</param>
|
||||
<param name="Type">
|
||||
Type of the account to retrieve password for. Can be one of the supported account types:
|
||||
* LocalComputerAdmin
|
||||
* ManagedDomainAccount
|
||||
</param>
|
||||
<param name="IncludePasswordHistory">Whether or not to include password history</param>
|
||||
<param name="IsDeleted">
|
||||
Whether computer account or managed domain account is deleted or not.
|
||||
Note: there may be multiple deleted objects with the same name. In such case, password for most recently deleted object is returned
|
||||
</param>
|
||||
<returns>Password, current password expiration time and optional password history. Passwords returned as secure strings</returns>
|
||||
<remarks>
|
||||
<para>Name of local admin account is not stored by solution. Caller is expected to know name of local managed account</para>
|
||||
<para>
|
||||
PDS does not try to guess domain or forest name from computer name - it searches against Global Catalog interface of AD forest passed in <paramref name="ForestName"/> parameter
|
||||
</para>
|
||||
<para>Caller must have Read Admin Passsword permission on given computer or user object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</GetSecurePassword>
|
||||
<ResetPassword>
|
||||
<summary>
|
||||
Calls PDS to request reset of for given managed account in given AD forest.
|
||||
Managed account can be either:
|
||||
* Domain computer local admin account
|
||||
* Managed domain account
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest, pass null as parameter value
|
||||
</param>
|
||||
<param name="Identity">Name of computer where password of local admin account shall be reset</param>
|
||||
<param name="Type">
|
||||
Type of the managed account to reset password for. Can be one of the supported account types:
|
||||
* LocalComputerAdmin
|
||||
* ManagedDomainAccount
|
||||
</param>
|
||||
<param name="WhenEffective">When password reset shall occur.
|
||||
If type of account is local computer admin account, then password will be reset during next GPO update cycle on given computer after this time.
|
||||
If type of account is managed domain account, and WhenEffective is in the past, then password is reset immediately. If WhenEffective is in the future, then password will be scheduled for reset according to WhenEffective parameter.
|
||||
</param>
|
||||
<returns>Information about result of operation along with computer name and computer DN</returns>
|
||||
<remarks>
|
||||
<para>Caller must have Reset Admin Passsword permission on given computer or user object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</ResetPassword>
|
||||
<GetLocalAdminPassword>
|
||||
<summary>
|
||||
Calls PDS to retrieve password of managed local admin account of given computer in given AD forest
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest, pass null as parameter value
|
||||
</param>
|
||||
<param name="ComputerName">
|
||||
Name of computer where password of local admin account shall be reset. Name of the computer can be passed as one of the following:
|
||||
* Hostname, such as MyComputer
|
||||
* FQDN, such as mycomputer.mydomain.com
|
||||
* Distinguished name, such as cn=MyComputer,ou=MyComputers,dc=mydomain,dc=com
|
||||
</param>
|
||||
<param name="IncludePasswordHistory">Whether or not to include password history</param>
|
||||
<param name="ComputerIsDeleted">
|
||||
Whether computer is deleted or not.
|
||||
Note: there may be multiple deleted computer objects with the same name. In such case, password for most recently deleted computer is returned
|
||||
</param>
|
||||
<returns>Password, current password expiration time and optional password history</returns>
|
||||
<remarks>
|
||||
<para>Name of local admin account is not stored by solution. Caller is expected to know name of local managed account</para>
|
||||
<para>
|
||||
PDS does not try to guess domain or forest name from computer name - it searches against Global Catalog interface of AD forest passed in <paramref name="ForestName"/> parameter
|
||||
</para>
|
||||
<para>Caller must have Read Local Admin Passsword permission on given computer object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</GetLocalAdminPassword>
|
||||
<ResetLocalAdminPassword>
|
||||
<summary>
|
||||
Calls PDS to request reset of managed local admin password for given computer in given AD forest.
|
||||
</summary>
|
||||
<param name="ForestName">
|
||||
Name of AD forest.
|
||||
Forest must be marked as supported in PDS configuration.
|
||||
For local forest, pass null as parameter value
|
||||
</param>
|
||||
<param name="ComputerName">Name of computer where password of local admin account shall be reset</param>
|
||||
<param name="WhenEffective">When password reset shall occur. Password will be reset during next GPO update cycle on given computer after this time </param>
|
||||
<returns>Information about result of operation along with computer name and computer DN</returns>
|
||||
<remarks>
|
||||
<para>Caller must have Reset Local Admin Passsword permission on given computer object</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</ResetLocalAdminPassword>
|
||||
<GetPublicKeys>
|
||||
<summary>
|
||||
Asks PDS to return public keys for all available key pairs.
|
||||
</summary>
|
||||
<returns>Returns list of all public keys managed by PDS, along with type of the key, size in bits, and key ID</returns>
|
||||
<remarks>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetPublicKeys>
|
||||
<GetSupportedForestNames>
|
||||
<summary>
|
||||
Asks PDS to return list of all supported AD forests.
|
||||
</summary>
|
||||
<returns>
|
||||
Returns list of names of all supported AD forests.
|
||||
<para>In single forest deployments, list is empty, meaning that only supported forest is the forest where solution is deployed.</para>
|
||||
</returns>
|
||||
<remarks>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetSupportedForestNames>
|
||||
|
||||
<GetPublicKey>
|
||||
<summary>
|
||||
Asks PDS to return public key with specified key ID
|
||||
</summary>
|
||||
<param name="KeyId">Identifies key pair for which public key is returned</param>
|
||||
<returns>Returns public key of key pair with given KeyID, along with key ID</returns>
|
||||
<remarks>
|
||||
<para>No specific permissions required</para>
|
||||
<para>Call is not audited</para>
|
||||
</remarks>
|
||||
</GetPublicKey>
|
||||
<GenerateKeyPair>
|
||||
<summary>
|
||||
<para>Calls PDS to generate new RSA key pair.</para>
|
||||
<para>
|
||||
PDS keeps private key of key pair in own storage and uses it for password decryption.
|
||||
Public key is put to GPO by an administrator and managed machines use it to encrypt the password of managed local admin account when reporting it to AD.
|
||||
</para>
|
||||
<para>PDS also uses public key to encrypt password of managed domain account - ID of key to use is specified in PDS configuration file.</para>
|
||||
</summary>
|
||||
<param name="KeySize">
|
||||
Specifies desired RSA key size<br/>
|
||||
Key size must be one of those allowed by PDS - see <see cref="GetSupportedKeySizes"/> method
|
||||
</param>
|
||||
<returns>Return public key of newly generated key pair, along with key ID assigned to newly generated key pair</returns>
|
||||
<remarks>
|
||||
<para>Caller must have Key Admin role. For callers without role, AccessDenied exception is thrown. To find out, if caller has Key Admin role, call method <see cref="IsPDSAdmin"/>.</para>
|
||||
<para>By default, Key Admin role is assigned to Enterprise Admins group and can be changed via PDS configuration file.</para>
|
||||
<para>Call is audited on PDS</para>
|
||||
</remarks>
|
||||
</GenerateKeyPair>
|
||||
</PdsWrapper>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user