mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Compare commits
192 Commits
sharedlibr
...
reapply_cr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a5f0f248e | ||
|
|
c1931ff4cd | ||
|
|
12cb7ad7b0 | ||
|
|
fdea0144b0 | ||
|
|
7398a373c2 | ||
|
|
74af24c3db | ||
|
|
ac1f32f773 | ||
|
|
99c7dbb332 | ||
|
|
b0632b8910 | ||
|
|
e5042712b6 | ||
|
|
0e74314ddc | ||
|
|
54eabd6a74 | ||
|
|
2f52473566 | ||
|
|
98e7250b3c | ||
|
|
882438f5e0 | ||
|
|
59b9f4f15b | ||
|
|
7ff0ce5369 | ||
|
|
93bd278819 | ||
|
|
b97b1f3690 | ||
|
|
307f374be1 | ||
|
|
17f701824e | ||
|
|
c7b89dcf71 | ||
|
|
fc527a947f | ||
|
|
d0520690a2 | ||
|
|
315d020b6f | ||
|
|
8a4bcdef52 | ||
|
|
727ef34c6d | ||
|
|
d8bc06d05d | ||
|
|
def214dde2 | ||
|
|
219f948c4a | ||
|
|
72193eccf0 | ||
|
|
7eb85c6a3d | ||
|
|
954c667173 | ||
|
|
33c738df5f | ||
|
|
2141fe298f | ||
|
|
8e73f512b4 | ||
|
|
92dddb8fd8 | ||
|
|
e9869f4c88 | ||
|
|
52597d4dcb | ||
|
|
dc7ce27b81 | ||
|
|
4242595a66 | ||
|
|
50b9a11503 | ||
|
|
621a723602 | ||
|
|
6260cc3655 | ||
|
|
300e668327 | ||
|
|
3cf274c37a | ||
|
|
2ca356ee5c | ||
|
|
ca8751c40c | ||
|
|
3c7e97d2d9 | ||
|
|
dbe2d690da | ||
|
|
949410e2cc | ||
|
|
100f856b5f | ||
|
|
d7bee01454 | ||
|
|
5566081986 | ||
|
|
29f7dd93f3 | ||
|
|
3dd8db5728 | ||
|
|
17e70d11f5 | ||
|
|
f8afd439b2 | ||
|
|
0dc61b1c26 | ||
|
|
de6c4fcb17 | ||
|
|
57f5c854ff | ||
|
|
4f4523ab77 | ||
|
|
e34e632519 | ||
|
|
f810b902a6 | ||
|
|
fd5bdc1484 | ||
|
|
e3a12ae6c5 | ||
|
|
c9c5664ec6 | ||
|
|
75cff549ce | ||
|
|
885cb6915d | ||
|
|
f9396a4ecf | ||
|
|
f1a03329e5 | ||
|
|
f65be671a3 | ||
|
|
fa9e8f6cba | ||
|
|
67a3e76cfe | ||
|
|
e4569c0bb8 | ||
|
|
6f1a62e917 | ||
|
|
3f6e21f15a | ||
|
|
46c4287c67 | ||
|
|
1ea1826a27 | ||
|
|
151457daf0 | ||
|
|
38cc21fa3a | ||
|
|
77f759f258 | ||
|
|
07c04061c2 | ||
|
|
d4bf6ed0c8 | ||
|
|
ebd46efe81 | ||
|
|
24d193efb0 | ||
|
|
3b2a63178f | ||
|
|
78f60afb85 | ||
|
|
52a7957789 | ||
|
|
6870583b1c | ||
|
|
9ffe514350 | ||
|
|
fc6e04497a | ||
|
|
cfb3f9a3ca | ||
|
|
d47fac791e | ||
|
|
490b70c2d3 | ||
|
|
3eecdd9ada | ||
|
|
7bdbc5417c | ||
|
|
2cd07dcb72 | ||
|
|
adb83ade67 | ||
|
|
a90f5da8b0 | ||
|
|
38937a4f83 | ||
|
|
31f35a23ee | ||
|
|
74de010d3c | ||
|
|
a9e4c880df | ||
|
|
b7fe265604 | ||
|
|
25c4af5a9f | ||
|
|
b3ecf702e1 | ||
|
|
c34a3cc7e7 | ||
|
|
158783f2d1 | ||
|
|
e9be139ed0 | ||
|
|
2b9195ed9c | ||
|
|
dfdfecba57 | ||
|
|
2d6fec13fb | ||
|
|
216f340468 | ||
|
|
a4211a7e55 | ||
|
|
4349b1b65b | ||
|
|
bb04605dc3 | ||
|
|
294bd2f7a4 | ||
|
|
a3aa323cce | ||
|
|
355cd63acb | ||
|
|
93d50b0818 | ||
|
|
8779776ad5 | ||
|
|
3bb285d180 | ||
|
|
052796c794 | ||
|
|
33a6dbb4c3 | ||
|
|
953ddaa292 | ||
|
|
c065b86dbd | ||
|
|
95859b96ff | ||
|
|
ba62c17ea2 | ||
|
|
1f296f2f72 | ||
|
|
89bb4d45b3 | ||
|
|
6e417ed47e | ||
|
|
f3a7d97016 | ||
|
|
530a4e165d | ||
|
|
9e217dba79 | ||
|
|
d524df6315 | ||
|
|
5e224f5b5b | ||
|
|
3649927618 | ||
|
|
4b736176bf | ||
|
|
f78ca1e9fd | ||
|
|
739112a3ff | ||
|
|
923b9efd40 | ||
|
|
f0d0b5ae21 | ||
|
|
8906e08704 | ||
|
|
9ead7e8e16 | ||
|
|
788ca79ece | ||
|
|
88558a353c | ||
|
|
7fd9abbbc8 | ||
|
|
b029b35df7 | ||
|
|
187ca5e55b | ||
|
|
53c26d8a91 | ||
|
|
159f25b8a1 | ||
|
|
f4904f350e | ||
|
|
ea59f6ad9d | ||
|
|
4bba05f737 | ||
|
|
569cf38f24 | ||
|
|
6f8cde4d8e | ||
|
|
753ea9b421 | ||
|
|
a5ea867b6d | ||
|
|
80228966f9 | ||
|
|
b8298ecb14 | ||
|
|
ee1db6ff8b | ||
|
|
aab1fb1dd2 | ||
|
|
fbea9d1ede | ||
|
|
75cfc9c75c | ||
|
|
f60a481902 | ||
|
|
e89c77a1bc | ||
|
|
45766b8c12 | ||
|
|
1c44fcb070 | ||
|
|
25aa815a82 | ||
|
|
a2542f1b18 | ||
|
|
2e0979dc5a | ||
|
|
e2ebf25b7b | ||
|
|
cc44b830a2 | ||
|
|
687cb6c7bc | ||
|
|
15f028157e | ||
|
|
63ebef56b0 | ||
|
|
258093e52a | ||
|
|
b09fdcd5f5 | ||
|
|
2277e95dd2 | ||
|
|
e0486bec7d | ||
|
|
29d44d103d | ||
|
|
44aa100566 | ||
|
|
23eb9cc44b | ||
|
|
f1797282d9 | ||
|
|
0c0740d488 | ||
|
|
a4faaa20c3 | ||
|
|
ce03b74d48 | ||
|
|
ce8ada05f5 | ||
|
|
b4dfe5beb6 | ||
|
|
22ecf0d06f | ||
|
|
1e66787422 |
14
.readthedocs.yaml
Normal file
14
.readthedocs.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
configuration: mRemoteNGDocumentation/conf.py
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF
|
||||
formats:
|
||||
- pdf
|
||||
@@ -14,12 +14,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
- #283: Support for native PowerShell remoting as new protocol
|
||||
- #1850: Minify config xml
|
||||
### Changed
|
||||
- #2022: Replaced CefSharp with WebView2
|
||||
- #2014: Revised icons
|
||||
- #2013: Removed components check
|
||||
- #2011: Removed screenshot manager
|
||||
- #2010: Redesigned menus
|
||||
- #2005: Removed in-app documentation
|
||||
- #1777: Cleaned up VisualStudio project structure
|
||||
- #1767: Turned about window into a simple popup form
|
||||
- #1766: Converted components check page into options page
|
||||
- #1690: Replaced GeckoFX (Firefox) with CefSharp (Chromium)
|
||||
- #1325: Language resource files cleanup
|
||||
### Fixed
|
||||
- #1884: Allow setting Port when using MSSQL
|
||||
- #1783: Added missing inheritance properties to SQL scripts
|
||||
- #1773: Connection issue with mysql - Missing fields in
|
||||
- #1756: Cannot type any character on MultiSSH toolbar
|
||||
|
||||
@@ -90,10 +90,6 @@ Copyright © 2004 Marc Merritt © 2008 Felix Deimel
|
||||
|
||||
# Included Components
|
||||
|
||||
**[CefSharp](https://github.com/cefsharp/CefSharp)**
|
||||
Copyright © The CefSharp Authors
|
||||
MIT License
|
||||
|
||||
**[DockPanel Suite](https://github.com/dockpanelsuite/dockpanelsuite)**
|
||||
Copyright © 2018 @roken and @lextm (formerly Weifen Luo)
|
||||
MIT License
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<br/><br/>
|
||||
<p align="center">
|
||||
<img width="500" src="https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/Tools/img/logo.png">
|
||||
<img width="500" src="https://github.com/mRemoteNG/mRemoteNG/blob/develop/mRemoteNGProjectFiles/Header_dark.png">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -177,5 +177,5 @@ Check out the [Wiki page](https://github.com/mRemoteNG/mRemoteNG/wiki) on how to
|
||||
|
||||
</br>
|
||||
<p align="center">
|
||||
<img alt="Developed with ReSharper" src="https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/develop/Tools/img/icon_ReSharper.png">
|
||||
<img alt="Developed with ReSharper" src="https://github.com/mRemoteNG/mRemoteNG/blob/develop/mRemoteNGProjectFiles/icon_ReSharper.png">
|
||||
</p>
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
//
|
||||
// Hotkey selection control, written by serenity@exscape.org, 2006-08-03
|
||||
// Please mail me if you find a bug.
|
||||
//
|
||||
|
||||
namespace SharedLibraryNG
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple control that allows the user to select pretty much any valid hotkey combination
|
||||
/// </summary>
|
||||
public class HotkeyControl : TextBox
|
||||
{
|
||||
private const string KeySeparator = " + ";
|
||||
|
||||
// These variables store the current hotkey and modifier(s)
|
||||
private Keys _keyCode = Keys.None;
|
||||
private Keys _modifiers = Keys.None;
|
||||
|
||||
// ArrayLists used to enforce the use of proper modifiers.
|
||||
// Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing.
|
||||
private readonly ArrayList _needNonShiftModifier;
|
||||
private readonly ArrayList _needNonAltGrModifier;
|
||||
|
||||
private readonly ContextMenu _emptyContextMenu = new ContextMenu();
|
||||
|
||||
/// <summary>
|
||||
/// Used to make sure that there is no right-click menu available
|
||||
/// </summary>
|
||||
public override ContextMenu ContextMenu
|
||||
{
|
||||
get
|
||||
{
|
||||
return _emptyContextMenu;
|
||||
}
|
||||
// ReSharper disable once ValueParameterNotUsed
|
||||
set
|
||||
{
|
||||
base.ContextMenu = _emptyContextMenu;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the control to be non-multiline
|
||||
/// </summary>
|
||||
public override bool Multiline
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Multiline;
|
||||
}
|
||||
// ReSharper disable once ValueParameterNotUsed
|
||||
set
|
||||
{
|
||||
// Ignore what the user wants; force Multiline to false
|
||||
base.Multiline = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new HotkeyControl
|
||||
/// </summary>
|
||||
public HotkeyControl()
|
||||
{
|
||||
// Handle events that occurs when keys are pressed
|
||||
KeyUp += HotkeyControl_KeyUp;
|
||||
|
||||
// Fill the ArrayLists that contain all invalid hotkey combinations
|
||||
_needNonShiftModifier = new ArrayList();
|
||||
_needNonAltGrModifier = new ArrayList();
|
||||
PopulateModifierLists();
|
||||
}
|
||||
|
||||
protected override void OnCreateControl()
|
||||
{
|
||||
base.OnCreateControl();
|
||||
|
||||
ContextMenu = _emptyContextMenu; // Disable right-clicking
|
||||
Multiline = false;
|
||||
Text = "None";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the ArrayLists specifying disallowed hotkeys
|
||||
/// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc
|
||||
/// </summary>
|
||||
private void PopulateModifierLists()
|
||||
{
|
||||
// Shift + 0 - 9, A - Z
|
||||
for (var k = Keys.D0; k <= Keys.Z; k++)
|
||||
_needNonShiftModifier.Add((int)k);
|
||||
|
||||
// Shift + Numpad keys
|
||||
for (var k = Keys.NumPad0; k <= Keys.NumPad9; k++)
|
||||
_needNonShiftModifier.Add((int)k);
|
||||
|
||||
// Shift + Misc (,;<./ etc)
|
||||
for (var k = Keys.Oem1; k <= Keys.OemBackslash; k++)
|
||||
_needNonShiftModifier.Add((int)k);
|
||||
|
||||
// Misc keys that we can't loop through
|
||||
_needNonShiftModifier.Add((int)Keys.Insert);
|
||||
_needNonShiftModifier.Add((int)Keys.Help);
|
||||
_needNonShiftModifier.Add((int)Keys.Multiply);
|
||||
_needNonShiftModifier.Add((int)Keys.Add);
|
||||
_needNonShiftModifier.Add((int)Keys.Subtract);
|
||||
_needNonShiftModifier.Add((int)Keys.Divide);
|
||||
_needNonShiftModifier.Add((int)Keys.Decimal);
|
||||
_needNonShiftModifier.Add((int)Keys.Return);
|
||||
_needNonShiftModifier.Add((int)Keys.Escape);
|
||||
_needNonShiftModifier.Add((int)Keys.NumLock);
|
||||
_needNonShiftModifier.Add((int)Keys.Scroll);
|
||||
_needNonShiftModifier.Add((int)Keys.Pause);
|
||||
|
||||
// Ctrl+Alt + 0 - 9
|
||||
for (var k = Keys.D0; k <= Keys.D9; k++)
|
||||
_needNonAltGrModifier.Add((int)k);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires when all keys are released. If the current hotkey isn't valid, reset it.
|
||||
/// Otherwise, do nothing and keep the text and hotkey as it was.
|
||||
/// </summary>
|
||||
void HotkeyControl_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (_keyCode == Keys.None && ModifierKeys == Keys.None) ResetHotkey();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles some misc keys, such as Ctrl+Delete and Shift+Insert
|
||||
/// </summary>
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
var keyCode = keyData & Keys.KeyCode;
|
||||
var modifiers = keyData & Keys.Modifiers;
|
||||
|
||||
if (keyData == Keys.Back || keyData == Keys.Delete)
|
||||
{
|
||||
ResetHotkey();
|
||||
return true;
|
||||
}
|
||||
|
||||
_keyCode = keyCode;
|
||||
_modifiers = modifiers;
|
||||
Redraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current hotkey and resets the TextBox
|
||||
/// </summary>
|
||||
public void ResetHotkey()
|
||||
{
|
||||
_keyCode = Keys.None;
|
||||
_modifiers = Keys.None;
|
||||
Text = "None";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to get/set the hotkey (e.g. Keys.A)
|
||||
/// </summary>
|
||||
public Keys KeyCode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _keyCode;
|
||||
}
|
||||
set
|
||||
{
|
||||
_keyCode = value;
|
||||
Redraw(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control)
|
||||
/// </summary>
|
||||
public Keys HotkeyModifiers
|
||||
{
|
||||
get
|
||||
{
|
||||
return _modifiers;
|
||||
}
|
||||
set
|
||||
{
|
||||
_modifiers = value;
|
||||
Redraw(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redraws the TextBox when necessary.
|
||||
/// </summary>
|
||||
/// <param name="validate">Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user.</param>
|
||||
private void Redraw(bool validate = true)
|
||||
{
|
||||
// Only validate input if it comes from the user
|
||||
if (validate)
|
||||
{
|
||||
// No modifier or shift only, AND a hotkey that needs another modifier
|
||||
if ((_modifiers == Keys.Shift || _modifiers == Keys.None) &&
|
||||
_needNonShiftModifier.Contains((int) _keyCode))
|
||||
{
|
||||
if (_modifiers == Keys.None)
|
||||
{
|
||||
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work...
|
||||
if (_needNonAltGrModifier.Contains((int) _keyCode) == false)
|
||||
_modifiers = Keys.Alt | Keys.Control;
|
||||
else // ... in that case, use Shift+Alt instead.
|
||||
_modifiers = Keys.Alt | Keys.Shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
// User pressed Shift and an invalid key (e.g. a letter or a number),
|
||||
// that needs another set of modifier keys
|
||||
_keyCode = Keys.None;
|
||||
Text = _modifiers + " + Invalid Key";
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check all Ctrl+Alt keys
|
||||
if ((_modifiers == (Keys.Alt | Keys.Control)) &&
|
||||
_needNonAltGrModifier.Contains((int) _keyCode))
|
||||
{
|
||||
// Ctrl+Alt+4 etc won't work; reset hotkey and tell the user
|
||||
_keyCode = Keys.None;
|
||||
Text = _modifiers + " + Invalid Key";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't allow modifiers keys for _keyCode
|
||||
if (_keyCode == Keys.ShiftKey ||
|
||||
_keyCode == Keys.LShiftKey ||
|
||||
_keyCode == Keys.RShiftKey ||
|
||||
_keyCode == Keys.ControlKey ||
|
||||
_keyCode == Keys.LControlKey ||
|
||||
_keyCode == Keys.RControlKey ||
|
||||
_keyCode == Keys.Menu ||
|
||||
_keyCode == Keys.LMenu ||
|
||||
_keyCode == Keys.RMenu ||
|
||||
_keyCode == Keys.LWin ||
|
||||
_keyCode == Keys.RWin)
|
||||
_keyCode = Keys.None;
|
||||
|
||||
if (_modifiers == Keys.None)
|
||||
{
|
||||
if (_keyCode == Keys.None)
|
||||
{
|
||||
ResetHotkey();
|
||||
return;
|
||||
}
|
||||
|
||||
// We get here if we've got a hotkey that is valid without a modifier,
|
||||
// like F1-F12, Media-keys etc.
|
||||
Text = _keyCode.ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
Text = string.Join(KeySeparator, new[] { KeysToString(_modifiers), KeysToString(_keyCode) });
|
||||
}
|
||||
|
||||
public static string KeysToString(Keys keys)
|
||||
{
|
||||
if (keys == Keys.None) return "None";
|
||||
|
||||
var modifiers = (keys & Keys.Modifiers);
|
||||
var keyCode = (keys & Keys.KeyCode);
|
||||
|
||||
var strings = new List<string>();
|
||||
|
||||
if (modifiers != 0)
|
||||
{
|
||||
var modifierStrings = new List<string>(modifiers.ToString().Replace(", ", ",").Split(','));
|
||||
modifierStrings.Sort(new KeyModifierComparer());
|
||||
strings.AddRange(modifierStrings);
|
||||
}
|
||||
|
||||
if (keyCode != 0)
|
||||
{
|
||||
var keyString = keyCode.ToString();
|
||||
var keyHashtable = new Dictionary<string, string>
|
||||
{
|
||||
{"Next", "PageDown"},
|
||||
{"Oemcomma", ","},
|
||||
{"OemMinus", "-"},
|
||||
{"OemOpenBrackets", "["},
|
||||
{"OemPeriod", "."},
|
||||
{"Oemplus", "="},
|
||||
{"OemQuestion", "/"},
|
||||
{"Oemtilde", "`"},
|
||||
{"D0", "0"},
|
||||
{"D1", "1"},
|
||||
{"D2", "2"},
|
||||
{"D3", "3"},
|
||||
{"D4", "4"},
|
||||
{"D5", "5"},
|
||||
{"D6", "6"},
|
||||
{"D7", "7"},
|
||||
{"D8", "8"},
|
||||
{"D9", "9"},
|
||||
};
|
||||
if (keyHashtable.ContainsKey(keyString)) keyString = keyHashtable[keyString];
|
||||
strings.Add(keyString);
|
||||
}
|
||||
|
||||
return string.Join(KeySeparator, strings.ToArray());
|
||||
}
|
||||
|
||||
private class KeyModifierComparer : IComparer<string>
|
||||
{
|
||||
private static readonly List<string> ModifierOrder = new List<string>
|
||||
{
|
||||
"control",
|
||||
"alt",
|
||||
"shift",
|
||||
};
|
||||
|
||||
public int Compare(string x, string y)
|
||||
{
|
||||
var xIndex = ModifierOrder.IndexOf(x.ToLowerInvariant());
|
||||
var yIndex = ModifierOrder.IndexOf(y.ToLowerInvariant());
|
||||
return xIndex - yIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
//
|
||||
// Based on code from Stephen Toub's MSDN blog at
|
||||
// http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharedLibraryNG
|
||||
{
|
||||
public class KeyboardHook
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool PostMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, HookKeyMsgData lParam);
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
[Flags]
|
||||
public enum ModifierKeys
|
||||
{
|
||||
None = 0x0000,
|
||||
Shift = 0x0001,
|
||||
LeftShift = 0x002,
|
||||
RightShift = 0x004,
|
||||
Control = 0x0008,
|
||||
LeftControl = 0x010,
|
||||
RightControl = 0x20,
|
||||
Alt = 0x0040,
|
||||
LeftAlt = 0x0080,
|
||||
RightAlt = 0x0100,
|
||||
Win = 0x0200,
|
||||
LeftWin = 0x0400,
|
||||
RightWin = 0x0800,
|
||||
}
|
||||
|
||||
protected class KeyNotificationEntry
|
||||
: IEquatable<KeyNotificationEntry>
|
||||
{
|
||||
public IntPtr WindowHandle;
|
||||
public Int32 KeyCode;
|
||||
public ModifierKeys ModifierKeys;
|
||||
public Boolean Block;
|
||||
|
||||
public bool Equals(KeyNotificationEntry obj)
|
||||
{
|
||||
return (WindowHandle == obj.WindowHandle &&
|
||||
KeyCode == obj.KeyCode &&
|
||||
ModifierKeys == obj.ModifierKeys &&
|
||||
Block == obj.Block);
|
||||
}
|
||||
}
|
||||
|
||||
public const string HookKeyMsgName = "HOOKKEYMSG-{56BE0940-34DA-11E1-B308-C6714824019B}";
|
||||
private static Int32 _hookKeyMsg;
|
||||
public static Int32 HookKeyMsg
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_hookKeyMsg == 0)
|
||||
{
|
||||
_hookKeyMsg = Win32.RegisterWindowMessage(HookKeyMsgName).ToInt32();
|
||||
if (_hookKeyMsg == 0)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
return _hookKeyMsg;
|
||||
}
|
||||
}
|
||||
|
||||
// this is a custom structure that will be passed to
|
||||
// the requested hWnd via a WM_APP_HOOKKEYMSG message
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class HookKeyMsgData
|
||||
{
|
||||
public Int32 KeyCode;
|
||||
public ModifierKeys ModifierKeys;
|
||||
public Boolean WasBlocked;
|
||||
}
|
||||
|
||||
private static int _referenceCount;
|
||||
private static IntPtr _hook;
|
||||
private static readonly Win32.LowLevelKeyboardProcDelegate LowLevelKeyboardProcStaticDelegate = LowLevelKeyboardProc;
|
||||
private static readonly List<KeyNotificationEntry> NotificationEntries = new List<KeyNotificationEntry>();
|
||||
|
||||
public KeyboardHook()
|
||||
{
|
||||
_referenceCount++;
|
||||
SetHook();
|
||||
}
|
||||
|
||||
~KeyboardHook()
|
||||
{
|
||||
_referenceCount--;
|
||||
if (_referenceCount < 1) UnsetHook();
|
||||
}
|
||||
|
||||
private static void SetHook()
|
||||
{
|
||||
if (_hook != IntPtr.Zero) return;
|
||||
|
||||
var curProcess = Process.GetCurrentProcess();
|
||||
var curModule = curProcess.MainModule;
|
||||
|
||||
var hook = Win32.SetWindowsHookEx(Win32.WH_KEYBOARD_LL, LowLevelKeyboardProcStaticDelegate, Win32.GetModuleHandle(curModule.ModuleName), 0);
|
||||
if (hook == IntPtr.Zero)
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
|
||||
_hook = hook;
|
||||
}
|
||||
|
||||
private static void UnsetHook()
|
||||
{
|
||||
if (_hook == IntPtr.Zero) return;
|
||||
|
||||
Win32.UnhookWindowsHookEx(_hook);
|
||||
_hook = IntPtr.Zero;
|
||||
}
|
||||
|
||||
private static IntPtr LowLevelKeyboardProc(Int32 nCode, IntPtr wParam, Win32.KBDLLHOOKSTRUCT lParam)
|
||||
{
|
||||
var wParamInt = wParam.ToInt32();
|
||||
var result = 0;
|
||||
|
||||
if (nCode == Win32.HC_ACTION)
|
||||
{
|
||||
switch (wParamInt)
|
||||
{
|
||||
case Win32.WM_KEYDOWN:
|
||||
case Win32.WM_SYSKEYDOWN:
|
||||
case Win32.WM_KEYUP:
|
||||
case Win32.WM_SYSKEYUP:
|
||||
result = OnKey(wParamInt, lParam);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0) return new IntPtr(result);
|
||||
|
||||
return Win32.CallNextHookEx(_hook, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private static int OnKey(Int32 msg, Win32.KBDLLHOOKSTRUCT key)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
foreach (var notificationEntry in NotificationEntries)
|
||||
if (GetFocusWindow() == notificationEntry.WindowHandle && notificationEntry.KeyCode == key.vkCode)
|
||||
{
|
||||
var modifierKeys = GetModifierKeyState();
|
||||
if (!ModifierKeysMatch(notificationEntry.ModifierKeys, modifierKeys)) continue;
|
||||
|
||||
var wParam = new IntPtr(msg);
|
||||
var lParam = new HookKeyMsgData
|
||||
{
|
||||
KeyCode = key.vkCode,
|
||||
ModifierKeys = modifierKeys,
|
||||
WasBlocked = notificationEntry.Block,
|
||||
};
|
||||
|
||||
if (!PostMessage(notificationEntry.WindowHandle, HookKeyMsg, wParam, lParam))
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
|
||||
if (notificationEntry.Block) result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IntPtr GetFocusWindow()
|
||||
{
|
||||
var guiThreadInfo = new Win32.GUITHREADINFO();
|
||||
if (!Win32.GetGUIThreadInfo(0, guiThreadInfo))
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
return Win32.GetAncestor(guiThreadInfo.hwndFocus, Win32.GA_ROOT);
|
||||
}
|
||||
|
||||
protected static Dictionary<Int32, ModifierKeys> ModifierKeyTable = new Dictionary<Int32, ModifierKeys>
|
||||
{
|
||||
{ Win32.VK_SHIFT, ModifierKeys.Shift },
|
||||
{ Win32.VK_LSHIFT, ModifierKeys.LeftShift },
|
||||
{ Win32.VK_RSHIFT, ModifierKeys.RightShift },
|
||||
{ Win32.VK_CONTROL, ModifierKeys.Control },
|
||||
{ Win32.VK_LCONTROL, ModifierKeys.LeftControl },
|
||||
{ Win32.VK_RCONTROL, ModifierKeys.RightControl },
|
||||
{ Win32.VK_MENU, ModifierKeys.Alt },
|
||||
{ Win32.VK_LMENU, ModifierKeys.LeftAlt },
|
||||
{ Win32.VK_RMENU, ModifierKeys.RightAlt },
|
||||
{ Win32.VK_LWIN, ModifierKeys.LeftWin },
|
||||
{ Win32.VK_RWIN, ModifierKeys.RightWin },
|
||||
};
|
||||
|
||||
public static ModifierKeys GetModifierKeyState()
|
||||
{
|
||||
var modifierKeyState = ModifierKeys.None;
|
||||
|
||||
foreach (KeyValuePair<Int32, ModifierKeys> pair in ModifierKeyTable)
|
||||
{
|
||||
if ((Win32.GetAsyncKeyState(pair.Key) & Win32.KEYSTATE_PRESSED) != 0) modifierKeyState |= pair.Value;
|
||||
}
|
||||
|
||||
if ((modifierKeyState & ModifierKeys.LeftWin) != 0) modifierKeyState |= ModifierKeys.Win;
|
||||
if ((modifierKeyState & ModifierKeys.RightWin) != 0) modifierKeyState |= ModifierKeys.Win;
|
||||
|
||||
return modifierKeyState;
|
||||
}
|
||||
|
||||
public static Boolean ModifierKeysMatch(ModifierKeys requestedKeys, ModifierKeys pressedKeys)
|
||||
{
|
||||
if ((requestedKeys & ModifierKeys.Shift) != 0) pressedKeys &= ~(ModifierKeys.LeftShift | ModifierKeys.RightShift);
|
||||
if ((requestedKeys & ModifierKeys.Control) != 0) pressedKeys &= ~(ModifierKeys.LeftControl | ModifierKeys.RightControl);
|
||||
if ((requestedKeys & ModifierKeys.Alt) != 0) pressedKeys &= ~(ModifierKeys.LeftAlt | ModifierKeys.RightAlt);
|
||||
if ((requestedKeys & ModifierKeys.Win) != 0) pressedKeys &= ~(ModifierKeys.LeftWin | ModifierKeys.RightWin);
|
||||
return requestedKeys == pressedKeys;
|
||||
}
|
||||
|
||||
public static void RequestKeyNotification(IntPtr windowHandle, Int32 keyCode, Boolean block)
|
||||
{
|
||||
RequestKeyNotification(windowHandle, keyCode, ModifierKeys.None, block);
|
||||
}
|
||||
|
||||
public static void RequestKeyNotification(IntPtr windowHandle, Int32 keyCode, ModifierKeys modifierKeys = ModifierKeys.None, Boolean block = false)
|
||||
{
|
||||
var newNotificationEntry = new KeyNotificationEntry
|
||||
{
|
||||
WindowHandle = windowHandle,
|
||||
KeyCode = keyCode,
|
||||
ModifierKeys = modifierKeys,
|
||||
Block = block,
|
||||
};
|
||||
|
||||
foreach (var notificationEntry in NotificationEntries)
|
||||
if (notificationEntry == newNotificationEntry) return;
|
||||
|
||||
NotificationEntries.Add(newNotificationEntry);
|
||||
}
|
||||
|
||||
public static void CancelKeyNotification(IntPtr windowHandle, Int32 keyCode, Boolean block)
|
||||
{
|
||||
CancelKeyNotification(windowHandle, keyCode, ModifierKeys.None, block);
|
||||
}
|
||||
|
||||
public static void CancelKeyNotification(IntPtr windowHandle, Int32 keyCode, ModifierKeys modifierKeys = ModifierKeys.None, Boolean block = false)
|
||||
{
|
||||
var notificationEntry = new KeyNotificationEntry
|
||||
{
|
||||
WindowHandle = windowHandle,
|
||||
KeyCode = keyCode,
|
||||
ModifierKeys = modifierKeys,
|
||||
Block = block,
|
||||
};
|
||||
|
||||
NotificationEntries.Remove(notificationEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SharedLibraryNG")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SharedLibraryNG")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f4470853-f933-4203-9d2a-b3c731e225c7")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,55 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{0F615504-5F30-4CF2-8341-1DE7FEC95A23}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SharedLibraryNG</RootNamespace>
|
||||
<AssemblyName>SharedLibraryNG</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="HotkeyControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="KeyboardHook.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Win32.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,171 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SharedLibraryNG
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
public static class Win32
|
||||
{
|
||||
#region Functions
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, IntPtr hMod, Int32 dwThreadId);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr RegisterWindowMessage(string lpString);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetGUIThreadInfo(Int32 idThread, GUITHREADINFO lpgui);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern IntPtr GetAncestor(IntPtr hwnd, UInt32 gaFlags);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern Int16 GetAsyncKeyState(Int32 vKey);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delegates
|
||||
|
||||
public delegate IntPtr LowLevelKeyboardProcDelegate(Int32 nCode, IntPtr wParam, KBDLLHOOKSTRUCT lParam);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Structures
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class KBDLLHOOKSTRUCT
|
||||
{
|
||||
public Int32 vkCode;
|
||||
public Int32 scanCode;
|
||||
public Int32 flags;
|
||||
public Int32 time;
|
||||
public IntPtr dwExtraInfo;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int left;
|
||||
public int top;
|
||||
public int right;
|
||||
public int bottom;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class GUITHREADINFO
|
||||
{
|
||||
public GUITHREADINFO()
|
||||
{
|
||||
cbSize = Convert.ToInt32(Marshal.SizeOf(this));
|
||||
}
|
||||
|
||||
public Int32 cbSize;
|
||||
public Int32 flags;
|
||||
public IntPtr hwndActive;
|
||||
public IntPtr hwndFocus;
|
||||
public IntPtr hwndCapture;
|
||||
public IntPtr hwndMenuOwner;
|
||||
public IntPtr hwndMoveSize;
|
||||
public IntPtr hwndCaret;
|
||||
public RECT rcCaret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
|
||||
// GetAncestor
|
||||
public const int GA_ROOT = 2;
|
||||
|
||||
// SetWindowsHookEx
|
||||
public const int WH_KEYBOARD_LL = 13;
|
||||
|
||||
// LowLevelKeyboardProcDelegate
|
||||
public const int HC_ACTION = 0;
|
||||
|
||||
// SendMessage
|
||||
public const int WM_KEYDOWN = 0x0100;
|
||||
public const int WM_KEYUP = 0x0101;
|
||||
public const int WM_SYSKEYDOWN = 0x0104;
|
||||
public const int WM_SYSKEYUP = 0x0105;
|
||||
|
||||
// GetAsyncKeyState
|
||||
public const int KEYSTATE_PRESSED = 0x8000;
|
||||
|
||||
#region Virtual Keys
|
||||
public const int VK_CANCEL = 0x0003;
|
||||
public const int VK_BACK = 0x0008;
|
||||
public const int VK_TAB = 0x0009;
|
||||
public const int VK_CLEAR = 0x000C;
|
||||
public const int VK_RETURN = 0x000D;
|
||||
public const int VK_PAUSE = 0x0013;
|
||||
public const int VK_ESCAPE = 0x001B;
|
||||
public const int VK_SNAPSHOT = 0x002C;
|
||||
public const int VK_INSERT = 0x002D;
|
||||
public const int VK_DELETE = 0x002E;
|
||||
public const int VK_HOME = 0x0024;
|
||||
public const int VK_END = 0x0023;
|
||||
public const int VK_PRIOR = 0x0021;
|
||||
public const int VK_NEXT = 0x0022;
|
||||
public const int VK_LEFT = 0x0025;
|
||||
public const int VK_UP = 0x0026;
|
||||
public const int VK_RIGHT = 0x0027;
|
||||
public const int VK_DOWN = 0x0028;
|
||||
public const int VK_SELECT = 0x0029;
|
||||
public const int VK_PRINT = 0x002A;
|
||||
public const int VK_EXECUTE = 0x002B;
|
||||
public const int VK_HELP = 0x002F;
|
||||
public const int VK_LWIN = 0x005B;
|
||||
public const int VK_RWIN = 0x005C;
|
||||
public const int VK_APPS = 0x005D;
|
||||
public const int VK_F1 = 0x0070;
|
||||
public const int VK_F2 = 0x0071;
|
||||
public const int VK_F3 = 0x0072;
|
||||
public const int VK_F4 = 0x0073;
|
||||
public const int VK_F5 = 0x0074;
|
||||
public const int VK_F6 = 0x0075;
|
||||
public const int VK_F7 = 0x0076;
|
||||
public const int VK_F8 = 0x0077;
|
||||
public const int VK_F9 = 0x0078;
|
||||
public const int VK_F10 = 0x0079;
|
||||
public const int VK_F11 = 0x007A;
|
||||
public const int VK_F12 = 0x007B;
|
||||
public const int VK_SHIFT = 0x0010;
|
||||
public const int VK_LSHIFT = 0x00A0;
|
||||
public const int VK_RSHIFT = 0x00A1;
|
||||
public const int VK_CONTROL = 0x0011;
|
||||
public const int VK_LCONTROL = 0x00A2;
|
||||
public const int VK_RCONTROL = 0x00A3;
|
||||
public const int VK_MENU = 0x0012;
|
||||
public const int VK_LMENU = 0x00A4;
|
||||
public const int VK_RMENU = 0x00A5;
|
||||
|
||||
public const int VK_OEM_1 = 0x00BA;
|
||||
public const int VK_OEM_2 = 0x00BF;
|
||||
public const int VK_OEM_3 = 0x00C0;
|
||||
public const int VK_OEM_4 = 0x00DB;
|
||||
public const int VK_OEM_5 = 0x00DC;
|
||||
public const int VK_OEM_6 = 0x00DD;
|
||||
public const int VK_OEM_7 = 0x00DE;
|
||||
public const int VK_OEM_8 = 0x00DF;
|
||||
public const int VK_OEM_102 = 0x00E2;
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,31 +0,0 @@
|
||||
7-Zip Extra
|
||||
~~~~~~~~~~~
|
||||
License for use and distribution
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright (C) 1999-2019 Igor Pavlov.
|
||||
|
||||
7-Zip Extra files are under the GNU LGPL license.
|
||||
|
||||
|
||||
Notes:
|
||||
You can use 7-Zip Extra on any computer, including a computer in a commercial
|
||||
organization. You don't need to register or pay for 7-Zip.
|
||||
|
||||
|
||||
GNU LGPL information
|
||||
--------------------
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You can receive a copy of the GNU Lesser General Public License from
|
||||
http://www.gnu.org/
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
7-Zip Extra history
|
||||
-------------------
|
||||
|
||||
This file contains only information about changes related to that package exclusively.
|
||||
The full history of changes is listed in history.txt in main 7-Zip program.
|
||||
|
||||
|
||||
19.00 2019-02-21
|
||||
-------------------------
|
||||
- Encryption strength for 7z archives was increased:
|
||||
the size of random initialization vector was increased from 64-bit to 128-bit,
|
||||
and the pseudo-random number generator was improved.
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
18.06 2018-12-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
|
||||
and there are minor changes in compression ratio.
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
18.05 2018-04-30
|
||||
-------------------------
|
||||
- The speed for LZMA/LZMA2 compressing was increased
|
||||
by 8% for fastest/fast compression levels and
|
||||
by 3% for normal/maximum compression levels.
|
||||
|
||||
|
||||
18.03 beta 2018-03-04
|
||||
-------------------------
|
||||
- The speed for single-thread LZMA/LZMA2 decoding
|
||||
was increased by 30% in x64 version and by 3% in x86 version.
|
||||
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
|
||||
if there are multiple independent data chunks in LZMA2 stream.
|
||||
|
||||
|
||||
9.35 beta 2014-12-07
|
||||
------------------------------
|
||||
- SFX modules were moved to LZMA SDK package.
|
||||
|
||||
|
||||
9.34 alpha 2014-06-22
|
||||
------------------------------
|
||||
- Minimum supported system now is Windows 2000 for EXE and DLL files.
|
||||
- all EXE and DLL files use msvcrt.dll.
|
||||
- 7zr.exe now support AES encryption.
|
||||
|
||||
|
||||
9.18 2010-11-02
|
||||
------------------------------
|
||||
- New small SFX module for installers.
|
||||
|
||||
|
||||
9.17 2010-10-04
|
||||
------------------------------
|
||||
- New 7-Zip plugin for FAR Manager x64.
|
||||
|
||||
|
||||
9.10 2009-12-30
|
||||
------------------------------
|
||||
- 7-Zip for installers now supports LZMA2.
|
||||
|
||||
|
||||
9.09 2009-12-12
|
||||
------------------------------
|
||||
- LZMA2 compression method support.
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
4.65 2009-02-03
|
||||
------------------------------
|
||||
- Some bugs were fixed.
|
||||
|
||||
|
||||
4.38 beta 2006-04-13
|
||||
------------------------------
|
||||
- SFX for installers now supports new properties in config file:
|
||||
Progress, Directory, ExecuteFile, ExecuteParameters.
|
||||
|
||||
|
||||
4.34 beta 2006-02-27
|
||||
------------------------------
|
||||
- ISetProperties::SetProperties:
|
||||
it's possible to specify desirable number of CPU threads:
|
||||
PROPVARIANT: name=L"mt", vt = VT_UI4, ulVal = NumberOfThreads
|
||||
If "mt" is not defined, 7za.dll will check number of processors in system to set
|
||||
number of desirable threads.
|
||||
Now 7za.dll can use:
|
||||
2 threads for LZMA compressing
|
||||
N threads for BZip2 compressing
|
||||
4 threads for BZip2 decompressing
|
||||
Other codecs use only one thread.
|
||||
Note: 7za.dll can use additional "small" threads with low CPU load.
|
||||
- It's possible to call ISetProperties::SetProperties to specify "mt" property for decoder.
|
||||
|
||||
|
||||
4.33 beta 2006-02-05
|
||||
------------------------------
|
||||
- Compressing speed and Memory requirements were increased.
|
||||
Default dictionary size was increased: Fastest: 64 KB, Fast: 1 MB,
|
||||
Normal: 4 MB, Max: 16 MB, Ultra: 64 MB.
|
||||
- 7z/LZMA now can use only these match finders: HC4, BT2, BT3, BT4
|
||||
|
||||
|
||||
4.27 2005-09-21
|
||||
------------------------------
|
||||
- Some GUIDs/interfaces were changed.
|
||||
IStream.h:
|
||||
ISequentialInStream::Read now works as old ReadPart
|
||||
ISequentialOutStream::Write now works as old WritePart
|
||||
@@ -1,124 +0,0 @@
|
||||
7-Zip Extra 19.00
|
||||
-----------------
|
||||
|
||||
7-Zip Extra is package of extra modules of 7-Zip.
|
||||
|
||||
7-Zip Copyright (C) 1999-2019 Igor Pavlov.
|
||||
|
||||
7-Zip is free software. Read License.txt for more information about license.
|
||||
|
||||
Source code of binaries can be found at:
|
||||
http://www.7-zip.org/
|
||||
|
||||
This package contains the following files:
|
||||
|
||||
7za.exe - standalone console version of 7-Zip with reduced formats support.
|
||||
7za.dll - library for working with 7z archives
|
||||
7zxa.dll - library for extracting from 7z archives
|
||||
License.txt - license information
|
||||
readme.txt - this file
|
||||
|
||||
Far\ - plugin for Far Manager
|
||||
x64\ - binaries for x64
|
||||
|
||||
|
||||
All 32-bit binaries can work in:
|
||||
Windows 2000 / 2003 / 2008 / XP / Vista / 7 / 8 / 10
|
||||
and in any Windows x64 version with WoW64 support.
|
||||
All x64 binaries can work in any Windows x64 version.
|
||||
|
||||
All binaries use msvcrt.dll.
|
||||
|
||||
7za.exe
|
||||
-------
|
||||
|
||||
7za.exe - is a standalone console version of 7-Zip with reduced formats support.
|
||||
|
||||
Extra: 7za.exe : support for only some formats of 7-Zip.
|
||||
7-Zip: 7z.exe with 7z.dll : support for all formats of 7-Zip.
|
||||
|
||||
7za.exe and 7z.exe from 7-Zip have same command line interface.
|
||||
7za.exe doesn't use external DLL files.
|
||||
|
||||
You can read Help File (7-zip.chm) from 7-Zip package for description
|
||||
of all commands and switches for 7za.exe and 7z.exe.
|
||||
|
||||
7za.exe features:
|
||||
|
||||
- High compression ratio in 7z format
|
||||
- Supported formats:
|
||||
- Packing / unpacking: 7z, xz, ZIP, GZIP, BZIP2 and TAR
|
||||
- Unpacking only: Z, lzma, CAB.
|
||||
- Highest compression ratio for ZIP and GZIP formats.
|
||||
- Fast compression and decompression
|
||||
- Strong AES-256 encryption in 7z and ZIP formats.
|
||||
|
||||
Note: LZMA SDK contains 7zr.exe - more reduced version of 7za.exe.
|
||||
But you can use 7zr.exe as "public domain" code.
|
||||
|
||||
|
||||
|
||||
DLL files
|
||||
---------
|
||||
|
||||
7za.dll and 7zxa.dll are reduced versions of 7z.dll from 7-Zip.
|
||||
7za.dll and 7zxa.dll support only 7z format.
|
||||
Note: 7z.dll is main DLL file that works with all archive types in 7-Zip.
|
||||
|
||||
7za.dll and 7zxa.dll support the following decoding methods:
|
||||
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES, BZip2, Deflate.
|
||||
|
||||
7za.dll also supports 7z encoding with the following encoding methods:
|
||||
- LZMA, LZMA2, PPMD, BCJ, BCJ2, COPY, 7zAES.
|
||||
|
||||
7za.dll and 7zxa.dll work via COM interfaces.
|
||||
But these DLLs don't use standard COM interfaces for objects creating.
|
||||
|
||||
Look also example code that calls DLL functions (in source code of 7-Zip):
|
||||
|
||||
7zip\UI\Client7z
|
||||
|
||||
Another example of binary that uses these interface is 7-Zip itself.
|
||||
The following binaries from 7-Zip use 7z.dll:
|
||||
- 7z.exe (console version)
|
||||
- 7zG.exe (GUI version)
|
||||
- 7zFM.exe (7-Zip File Manager)
|
||||
|
||||
Note: The source code of LZMA SDK also contains the code for similar DLLs
|
||||
(DLLs without BZip2, Deflate support). And these files from LZMA SDK can be
|
||||
used as "public domain" code. If you use LZMA SDK files, you don't need to
|
||||
follow GNU LGPL rules, if you want to change the code.
|
||||
|
||||
|
||||
|
||||
|
||||
License FAQ
|
||||
-----------
|
||||
|
||||
Can I use the EXE or DLL files from 7-Zip in a commercial application?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Yes, but you are required to specify in documentation for your application:
|
||||
(1) that you used parts of the 7-Zip program,
|
||||
(2) that 7-Zip is licensed under the GNU LGPL license and
|
||||
(3) you must give a link to www.7-zip.org, where the source code can be found.
|
||||
|
||||
|
||||
Can I use the source code of 7-Zip in a commercial application?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Since 7-Zip is licensed under the GNU LGPL you must follow the rules of that license.
|
||||
In brief, it means that any LGPL'ed code must remain licensed under the LGPL.
|
||||
For instance, you can change the code from 7-Zip or write a wrapper for some
|
||||
code from 7-Zip and compile it into a DLL; but, the source code of that DLL
|
||||
(including your modifications / additions / wrapper) must be licensed under
|
||||
the LGPL or GPL.
|
||||
Any other code in your application can be licensed as you wish. This scheme allows
|
||||
users and developers to change LGPL'ed code and recompile that DLL. That is the
|
||||
idea of free software. Read more here: http://www.gnu.org/.
|
||||
|
||||
|
||||
|
||||
Note: You can look also LZMA SDK, which is available under a more liberal license.
|
||||
|
||||
|
||||
---
|
||||
End of document
|
||||
@@ -1,15 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying PUTTYNG to correct directory"
|
||||
Copy-Item -Path (Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\Resources\PuTTYNG.exe") -Destination $TargetDir -Force
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,19 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying THEMES folder to output"
|
||||
|
||||
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteNG\Resources\Themes' )
|
||||
$DestinationDir = [io.path]::combine($TargetDir , 'Themes')
|
||||
|
||||
robocopy $sourceFiles $DestinationDir *.vstheme /s
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,17 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
Write-Output "Copying TILES folder to output"
|
||||
|
||||
$sourceFiles = [io.path]::combine($SolutionDir , 'mRemoteNG\Resources\Tiles' )
|
||||
robocopy $sourceFiles $TargetDir *.*
|
||||
|
||||
Write-Output ""
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB |
@@ -37,16 +37,9 @@ Format-Table -AutoSize -Wrap -InputObject @{
|
||||
"ExcludeFromSigning" = $ExcludeFromSigning
|
||||
}
|
||||
|
||||
|
||||
|
||||
& "$PSScriptRoot\copy_puttyng.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\copy_themes.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\copy_tiles.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\sphinx_docs.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
|
||||
& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
& "$PSScriptRoot\verify_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
|
||||
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\sign_binaries.ps1" -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath -SolutionDir $SolutionDir
|
||||
& "$PSScriptRoot\zip_symbols.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
& "$PSScriptRoot\zip_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName
|
||||
@@ -3,7 +3,7 @@
|
||||
$SolutionDir
|
||||
)
|
||||
|
||||
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
$renameTarget = $SolutionDir + "mRemoteNGInstaller\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
|
||||
|
||||
Write-Host $SolutionDir
|
||||
Write-Host $renameTarget
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
Write-Output "Building HTML-Documentation with Sphinx"
|
||||
|
||||
$path_HelpFilesDir = Join-Path -Path $TargetDir -ChildPath "Help"
|
||||
$path_SphinxSourceDir = Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\Documentation"
|
||||
|
||||
# Remove stale Help files, if they exist
|
||||
if (Test-Path -Path $path_HelpFilesDir) {
|
||||
Remove-Item -Path $path_HelpFilesDir -Recurse -Force
|
||||
}
|
||||
|
||||
# Build docs
|
||||
sphinx-build $path_SphinxSourceDir $path_HelpFilesDir
|
||||
|
||||
# Place dummy html file if build failed
|
||||
if (-Not (Test-Path $path_HelpFilesDir\index.html -PathType Leaf)) {
|
||||
New-Item -Path $path_HelpFilesDir -ItemType "directory"
|
||||
New-Item $path_HelpFilesDir\index.html
|
||||
Set-Content $path_HelpFilesDir\index.html 'Welcome to mRemoteNG!'
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
72
Tools/zip_files.ps1
Normal file
72
Tools/zip_files.ps1
Normal file
@@ -0,0 +1,72 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
|
||||
$exe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
|
||||
$Version = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($exe).FileVersion
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
# Fix for AppVeyor
|
||||
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
|
||||
if(!(test-path "Release")) {
|
||||
New-Item -ItemType Directory -Force -Path "Release" | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Package debug symbols zip file
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Packaging debug symbols"
|
||||
|
||||
if ($ConfigurationName -match "Portable") {
|
||||
$zipFilePrefix = "mRemoteNG-Portable-symbols"
|
||||
} else {
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
}
|
||||
|
||||
$debugFile = Join-Path -Path $TargetDir -ChildPath "mRemoteNG.pdb"
|
||||
|
||||
# AppVeyor build
|
||||
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
|
||||
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\$zipFilePrefix-$($version).zip"
|
||||
7z a $outputZipPath $debugFile
|
||||
}
|
||||
# Local build
|
||||
else {
|
||||
$outputZipPath = "$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
|
||||
Compress-Archive $debugFile $outputZipPath -Force
|
||||
}
|
||||
|
||||
Remove-Item $debugFile
|
||||
}
|
||||
|
||||
# Package portable release zip file
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging portable ZIP file"
|
||||
|
||||
# AppVeyor build
|
||||
if(!([string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER))) {
|
||||
$outputZipPath = Join-Path -Path $SolutionDir -ChildPath "Release\mRemoteNG-Portable-$($version).zip"
|
||||
7z a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath $TargetDir\*
|
||||
}
|
||||
# Local build
|
||||
else {
|
||||
$outputZipPath="$($SolutionDir)\Release\mRemoteNG-Portable-$($version).zip"
|
||||
Compress-Archive $Source $outputZipPath -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,64 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (tirmmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -eq "Release Portable") {
|
||||
Write-Output "Packaging Release Portable ZIP"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteNG\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
$PortableZip="$($SolutionDir)Release\mRemoteNG-Portable-$($version).zip"
|
||||
|
||||
$tempFolderPath = Join-Path -Path $SolutionDir -ChildPath "mRemoteNG\bin\package"
|
||||
Remove-Item -Recurse $tempFolderPath -ErrorAction SilentlyContinue | Out-Null
|
||||
New-Item $tempFolderPath -ItemType "directory" | Out-Null
|
||||
|
||||
Copy-Item "$($SolutionDir)mRemoteNG\Resources\PuTTYNG.exe" -Destination $tempFolderPath
|
||||
|
||||
#Write-Output "$($SolutionDir)mRemoteNG\bin\$ConfigurationName"
|
||||
#Write-Output "$($SolutionDir)mRemoteNG\bin\package"
|
||||
Copy-Item "$($SolutionDir)mRemoteNG\bin\$ConfigurationName\*" -Destination $tempFolderPath -Recurse -Force
|
||||
# Delete any PDB files that accidentally get copied into the temp folder
|
||||
Get-ChildItem -Path $tempFolderPath -Filter "*.pdb" | Remove-Item
|
||||
Copy-Item "$($SolutionDir)*.txt" -Destination $tempFolderPath
|
||||
|
||||
Write-Output "Creating portable ZIP file $($PortableZip)"
|
||||
Remove-Item -Force $PortableZip -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $PortableZip (Join-Path -Path $tempFolderPath -ChildPath "*.*")
|
||||
#& $SEVENZIP a -bt -mx=9 -tzip -y $PortableZip "$($SolutionDir)*.TXT"
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not zip anything - this isnt a portable release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -1,56 +0,0 @@
|
||||
param (
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$SolutionDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$TargetDir,
|
||||
|
||||
[string]
|
||||
[Parameter(Mandatory=$true)]
|
||||
$ConfigurationName
|
||||
)
|
||||
|
||||
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
|
||||
|
||||
if(-not [string]::IsNullOrEmpty($Env:APPVEYOR_BUILD_FOLDER)) {
|
||||
Write-Output "Too early to run via Appveyor - artifacts don't get generated properly. Exiting"
|
||||
Exit
|
||||
}
|
||||
|
||||
Write-Output "Solution Dir: '$($SolutionDir)'"
|
||||
Write-Output "Target Dir: '$($TargetDir)'"
|
||||
$ConfigurationName = $ConfigurationName.Trim()
|
||||
Write-Output "Config Name (trimmed): '$($ConfigurationName)'"
|
||||
|
||||
|
||||
# Windows Sysinternals Sigcheck from http://technet.microsoft.com/en-us/sysinternals/bb897441
|
||||
$SIGCHECK="$($SolutionDir)Tools\exes\sigcheck.exe"
|
||||
$SEVENZIP="$($SolutionDir)Tools\7zip\7za.exe"
|
||||
|
||||
# Package Zip
|
||||
if ($ConfigurationName -match "Release") {
|
||||
Write-Output "Packaging debug symbols"
|
||||
|
||||
$version = & $SIGCHECK /accepteula -q -n "$($SolutionDir)mRemoteNG\bin\$($ConfigurationName)\mRemoteNG.exe"
|
||||
|
||||
Write-Output "Version is $($version)"
|
||||
|
||||
if ($ConfigurationName -match "Portable") {
|
||||
$zipFilePrefix = "mRemoteNG-Portable-symbols"
|
||||
} else {
|
||||
$zipFilePrefix = "mRemoteNG-symbols"
|
||||
}
|
||||
|
||||
$outputZipPath="$($SolutionDir)Release\$zipFilePrefix-$($version).zip"
|
||||
|
||||
Write-Output "Creating debug symbols ZIP file $($outputZipPath)"
|
||||
Remove-Item -Force $outputZipPath -ErrorAction SilentlyContinue
|
||||
& $SEVENZIP a -bt -bd -bb1 -mx=9 -tzip -y -r $outputZipPath (Join-Path -Path $TargetDir -ChildPath "*.pdb")
|
||||
}
|
||||
else {
|
||||
Write-Output "We will not package debug symbols - this isnt a release build."
|
||||
}
|
||||
|
||||
Write-Output ""
|
||||
@@ -18,8 +18,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "mRemoteNGInsta
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedLibraryNG", "SharedLibraryNG\SharedLibraryNG.csproj", "{0F615504-5F30-4CF2-8341-1DE7FEC95A23}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug Portable|Any CPU = Debug Portable|Any CPU
|
||||
@@ -120,26 +118,6 @@ Global
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.ActiveCfg = Release|x86
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x86.Build.0 = Release|x86
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|x86.ActiveCfg = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug Portable|x86.Build.0 = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|Any CPU.Build.0 = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|x86.ActiveCfg = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Installer|x86.Build.0 = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|Any CPU.Build.0 = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|x86.ActiveCfg = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release Portable|x86.Build.0 = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0F615504-5F30-4CF2-8341-1DE7FEC95A23}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -5,7 +5,6 @@ using Microsoft.Win32;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.TaskDialog;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Config.Connections;
|
||||
@@ -19,7 +19,7 @@ namespace mRemoteNG.App
|
||||
{
|
||||
public static class Export
|
||||
{
|
||||
public static void ExportToFile(ConnectionInfo selectedNode, ConnectionTreeModel connectionTreeModel)
|
||||
public static void ExportToFile(ConnectionInfo selectedNode, IConnectionTreeModel connectionTreeModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -93,8 +93,7 @@ namespace mRemoteNG.App
|
||||
serializer = new XmlConnectionsSerializer(cryptographyProvider, connectionNodeSerializer);
|
||||
break;
|
||||
case SaveFormat.mRCSV:
|
||||
serializer =
|
||||
new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialProviderCatalog);
|
||||
serializer = new CsvConnectionsSerializerMremotengFormat(saveFilter, Runtime.CredentialService.RepositoryList);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(saveFormat), saveFormat, null);
|
||||
|
||||
@@ -6,12 +6,11 @@ using mRemoteNG.Config.Import;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
public static class Import
|
||||
public static class Import
|
||||
{
|
||||
public static void ImportFromFile(ContainerInfo importDestinationContainer)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace mRemoteNG.App.Info
|
||||
public const string UrlDonate = "https://mremoteng.org/contribute";
|
||||
public const string UrlForum = "https://www.reddit.com/r/mRemoteNG";
|
||||
public const string UrlBugs = "https://bugs.mremoteng.org";
|
||||
public const string UrlDocumentation = "https://mremoteng.readthedocs.io/en/latest/";
|
||||
public static string ApplicationVersion = Application.ProductVersion;
|
||||
public static readonly string ProductName = Application.ProductName;
|
||||
|
||||
|
||||
@@ -8,17 +8,16 @@ namespace mRemoteNG.App.Info
|
||||
public static class UpdateChannelInfo
|
||||
{
|
||||
public const string STABLE = "Stable";
|
||||
public const string BETA = "Beta";
|
||||
public const string DEV = "Development";
|
||||
public const string PREVIEW = "Preview";
|
||||
public const string NIGHTLY = "Nightly";
|
||||
|
||||
/* no #if here since they are used for unit tests as well */
|
||||
public const string STABLE_PORTABLE = "update-portable.txt";
|
||||
public const string BETA_PORTABLE = "beta-update-portable.txt";
|
||||
public const string DEV_PORTABLE = "dev-update-portable.txt";
|
||||
public const string PREVIEW_PORTABLE = "preview-update-portable.txt";
|
||||
public const string NIGHTLY_PORTABLE = "nightly-update-portable.txt";
|
||||
|
||||
public const string STABLE_MSI = "update.txt";
|
||||
public const string BETA_MSI = "beta-update.txt";
|
||||
public const string DEV_MSI = "dev-update.txt";
|
||||
public const string PREVIEW_MSI = "preview-update.txt";
|
||||
public const string NIGHTLY_MSI = "nightly-update.txt";
|
||||
|
||||
|
||||
public static Uri GetUpdateChannelInfo()
|
||||
@@ -40,10 +39,10 @@ namespace mRemoteNG.App.Info
|
||||
{
|
||||
case STABLE:
|
||||
return STABLE_MSI;
|
||||
case BETA:
|
||||
return BETA_MSI;
|
||||
case DEV:
|
||||
return DEV_MSI;
|
||||
case PREVIEW:
|
||||
return PREVIEW_MSI;
|
||||
case NIGHTLY:
|
||||
return NIGHTLY_MSI;
|
||||
default:
|
||||
return STABLE_MSI;
|
||||
}
|
||||
@@ -55,10 +54,10 @@ namespace mRemoteNG.App.Info
|
||||
{
|
||||
case STABLE:
|
||||
return STABLE_PORTABLE;
|
||||
case BETA:
|
||||
return BETA_PORTABLE;
|
||||
case DEV:
|
||||
return DEV_PORTABLE;
|
||||
case PREVIEW:
|
||||
return PREVIEW_PORTABLE;
|
||||
case NIGHTLY:
|
||||
return NIGHTLY_PORTABLE;
|
||||
default:
|
||||
return STABLE_PORTABLE;
|
||||
}
|
||||
@@ -72,7 +71,7 @@ namespace mRemoteNG.App.Info
|
||||
|
||||
private static bool IsValidChannel(string s)
|
||||
{
|
||||
return s.Equals(STABLE) || s.Equals(BETA) || s.Equals(DEV);
|
||||
return s.Equals(STABLE) || s.Equals(PREVIEW) || s.Equals(NIGHTLY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,38 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Properties;
|
||||
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
public class CredsAndConsSetup
|
||||
{
|
||||
public void LoadCredsAndCons()
|
||||
public void LoadCredsAndCons(ConnectionsService connectionsService, CredentialService credentialService, SaveConnectionsOnEdit connectionsOnEdit)
|
||||
{
|
||||
new SaveConnectionsOnEdit(Runtime.ConnectionsService);
|
||||
connectionsOnEdit.Subscribe(connectionsService);
|
||||
|
||||
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation &&
|
||||
!File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
|
||||
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService
|
||||
.GetStartupConnectionFileName());
|
||||
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation &&
|
||||
!File.Exists(connectionsService.GetStartupConnectionFileName()))
|
||||
connectionsService.NewConnectionsFile(connectionsService.GetStartupConnectionFileName());
|
||||
|
||||
credentialService.LoadRepositoryList();
|
||||
LoadDefaultConnectionCredentials(credentialService);
|
||||
Runtime.LoadConnections();
|
||||
}
|
||||
|
||||
private void LoadDefaultConnectionCredentials(CredentialService credentialService)
|
||||
{
|
||||
var defaultCredId = Settings.Default.ConDefaultCredentialRecord;
|
||||
var matchedCredentials = credentialService
|
||||
.GetCredentialRecords()
|
||||
.Where(record => record.Id.Equals(defaultCredId))
|
||||
.ToArray();
|
||||
|
||||
DefaultConnectionInfo.Instance.CredentialRecordId = Optional<Guid>.FromNullable(matchedCredentials.FirstOrDefault()?.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using System.Management;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Credential.Repositories;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
@@ -16,7 +15,6 @@ using System.Security;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
@@ -37,7 +35,7 @@ namespace mRemoteNG.App
|
||||
/// <summary>
|
||||
/// Feature flag to enable the credential manager feature
|
||||
/// </summary>
|
||||
public static bool UseCredentialManager => false;
|
||||
public static bool UseCredentialManager => true;
|
||||
|
||||
public static WindowList WindowList { get; set; }
|
||||
public static MessageCollector MessageCollector { get; } = new MessageCollector();
|
||||
@@ -47,10 +45,9 @@ namespace mRemoteNG.App
|
||||
public static SecureString EncryptionKey { get; set; } =
|
||||
new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
|
||||
|
||||
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
|
||||
public static CredentialService CredentialService { get; } = new CredentialServiceFactory().Build();
|
||||
|
||||
public static ConnectionsService ConnectionsService { get; } =
|
||||
new ConnectionsService(PuttySessionsManager.Instance);
|
||||
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance, CredentialService);
|
||||
|
||||
#region Connections Loading/Saving
|
||||
|
||||
@@ -97,7 +94,7 @@ namespace mRemoteNG.App
|
||||
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
|
||||
}
|
||||
|
||||
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
|
||||
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, connectionFileName);
|
||||
|
||||
if (Settings.Default.UseSQLServer)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI.Controls;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ namespace mRemoteNG.App
|
||||
public static class Windows
|
||||
{
|
||||
private static ActiveDirectoryImportWindow _adimportForm;
|
||||
private static HelpWindow _helpForm;
|
||||
private static ExternalToolsWindow _externalappsForm;
|
||||
private static PortScanWindow _portscanForm;
|
||||
private static ScreenshotManagerWindow _screenshotmanagerForm;
|
||||
private static UltraVNCWindow _ultravncscForm;
|
||||
private static ConnectionTreeWindow _treeForm;
|
||||
|
||||
@@ -23,7 +21,6 @@ namespace mRemoteNG.App
|
||||
|
||||
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
|
||||
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
|
||||
internal static ScreenshotManagerWindow ScreenshotForm { get; set; } = new ScreenshotManagerWindow();
|
||||
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
|
||||
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
|
||||
|
||||
@@ -58,11 +55,6 @@ namespace mRemoteNG.App
|
||||
UpdateForm = new UpdateWindow();
|
||||
UpdateForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.Help:
|
||||
if (_helpForm == null || _helpForm.IsDisposed)
|
||||
_helpForm = new HelpWindow();
|
||||
_helpForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.ExternalApps:
|
||||
if (_externalappsForm == null || _externalappsForm.IsDisposed)
|
||||
_externalappsForm = new ExternalToolsWindow();
|
||||
@@ -72,10 +64,6 @@ namespace mRemoteNG.App
|
||||
_portscanForm = new PortScanWindow();
|
||||
_portscanForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.ScreenshotManager:
|
||||
_screenshotmanagerForm = new ScreenshotManagerWindow();
|
||||
_screenshotmanagerForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.UltraVNCSC:
|
||||
if (_ultravncscForm == null || _ultravncscForm.IsDisposed)
|
||||
_ultravncscForm = new UltraVNCWindow();
|
||||
|
||||
14
mRemoteNG/Config/ConnectionToCredentialMap.cs
Normal file
14
mRemoteNG/Config/ConnectionToCredentialMap.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Credential;
|
||||
|
||||
namespace mRemoteNG.Config
|
||||
{
|
||||
public class ConnectionToCredentialMap : Dictionary<Guid, ICredentialRecord>
|
||||
{
|
||||
private readonly IEqualityComparer<ICredentialRecord> _credentialComparer = new CredentialDomainUserPasswordComparer();
|
||||
|
||||
public IEnumerable<ICredentialRecord> DistinctCredentialRecords => Values.Distinct(_credentialComparer);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
|
||||
@@ -10,7 +12,7 @@ namespace mRemoteNG.Config.Connections
|
||||
/// The previous <see cref="ConnectionTreeModel"/> that is being
|
||||
/// unloaded.
|
||||
/// </summary>
|
||||
public Optional<ConnectionTreeModel> PreviousConnectionTreeModel { get; }
|
||||
public List<ConnectionInfo> RemovedConnections { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the previous <see cref="ConnectionTreeModel"/> was loaded from
|
||||
@@ -21,7 +23,7 @@ namespace mRemoteNG.Config.Connections
|
||||
/// <summary>
|
||||
/// The new <see cref="ConnectionTreeModel"/> that is being loaded.
|
||||
/// </summary>
|
||||
public ConnectionTreeModel NewConnectionTreeModel { get; }
|
||||
public List<ConnectionInfo> AddedConnections { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the new <see cref="ConnectionTreeModel"/> was loaded from
|
||||
@@ -36,24 +38,18 @@ namespace mRemoteNG.Config.Connections
|
||||
/// </summary>
|
||||
public string NewSourcePath { get; }
|
||||
|
||||
public ConnectionsLoadedEventArgs(Optional<ConnectionTreeModel> previousTreeModelModel,
|
||||
ConnectionTreeModel newTreeModelModel,
|
||||
bool previousSourceWasDatabase,
|
||||
bool newSourceIsDatabase,
|
||||
string newSourcePath)
|
||||
{
|
||||
if (previousTreeModelModel == null)
|
||||
throw new ArgumentNullException(nameof(previousTreeModelModel));
|
||||
if (newTreeModelModel == null)
|
||||
throw new ArgumentNullException(nameof(newTreeModelModel));
|
||||
if (newSourcePath == null)
|
||||
throw new ArgumentNullException(nameof(newSourcePath));
|
||||
public IConnectionTreeModel NewConnectionTreeModel { get; set; } = new ConnectionTreeModel();
|
||||
|
||||
PreviousConnectionTreeModel = previousTreeModelModel;
|
||||
public ConnectionsLoadedEventArgs(
|
||||
List<ConnectionInfo> removedConnections, List<ConnectionInfo> addedConnections,
|
||||
bool previousSourceWasDatabase, bool newSourceIsDatabase,
|
||||
string newSourcePath)
|
||||
{
|
||||
RemovedConnections = removedConnections.ThrowIfNull(nameof(removedConnections));
|
||||
PreviousSourceWasDatabase = previousSourceWasDatabase;
|
||||
NewConnectionTreeModel = newTreeModelModel;
|
||||
AddedConnections = addedConnections.ThrowIfNull(nameof(addedConnections));
|
||||
NewSourceIsDatabase = newSourceIsDatabase;
|
||||
NewSourcePath = newSourcePath;
|
||||
NewSourcePath = newSourcePath.ThrowIfNull(nameof(newSourcePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class ConnectionsSavedEventArgs
|
||||
{
|
||||
public ConnectionTreeModel ModelThatWasSaved { get; }
|
||||
public IConnectionTreeModel ModelThatWasSaved { get; }
|
||||
public bool PreviouslyUsingDatabase { get; }
|
||||
public bool UsingDatabase { get; }
|
||||
public string ConnectionFileName { get; }
|
||||
|
||||
public ConnectionsSavedEventArgs(ConnectionTreeModel modelThatWasSaved,
|
||||
public ConnectionsSavedEventArgs(IConnectionTreeModel modelThatWasSaved,
|
||||
bool previouslyUsingDatabase,
|
||||
bool usingDatabase,
|
||||
string connectionFileName)
|
||||
@@ -24,4 +24,4 @@ namespace mRemoteNG.Config.Connections
|
||||
ConnectionFileName = connectionFileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,10 @@ namespace mRemoteNG.Config.Connections
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
var csvConnectionsSerializer =
|
||||
new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialProviderCatalog);
|
||||
var csvConnectionsSerializer = new CsvConnectionsSerializerMremotengFormat(_saveFilter, Runtime.CredentialService.RepositoryList);
|
||||
var dataProvider = new FileDataProvider(_connectionFileName);
|
||||
var csvContent = csvConnectionsSerializer.Serialize(connectionTreeModel);
|
||||
dataProvider.Save(csvContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public interface IConnectionsLoader
|
||||
{
|
||||
ConnectionTreeModel Load();
|
||||
SerializationResult Load();
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ namespace mRemoteNG.Config.Connections.Multiuser
|
||||
|
||||
private void Load(object sender, ConnectionsUpdateAvailableEventArgs args)
|
||||
{
|
||||
Runtime.ConnectionsService.LoadConnections(true, false, "");
|
||||
Runtime.ConnectionsService.LoadConnections(true, "");
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class SaveConnectionsOnEdit
|
||||
{
|
||||
private readonly ConnectionsService _connectionsService;
|
||||
private IConnectionsService _connectionsService;
|
||||
|
||||
public SaveConnectionsOnEdit(ConnectionsService connectionsService)
|
||||
public void Subscribe(IConnectionsService connectionsService)
|
||||
{
|
||||
if (connectionsService == null)
|
||||
throw new ArgumentNullException(nameof(connectionsService));
|
||||
|
||||
_connectionsService = connectionsService;
|
||||
connectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded;
|
||||
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
|
||||
connectionsService.ConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
|
||||
connectionsService.ConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
|
||||
}
|
||||
|
||||
private void ConnectionsServiceOnConnectionsLoaded(object sender,
|
||||
ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
|
||||
public void Unsubscribe()
|
||||
{
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged +=
|
||||
ConnectionTreeModelOnCollectionChanged;
|
||||
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
|
||||
|
||||
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
|
||||
{
|
||||
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
|
||||
oldTree.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;
|
||||
}
|
||||
_connectionsService.ConnectionTreeModel.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
|
||||
_connectionsService.ConnectionTreeModel.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;
|
||||
_connectionsService = null;
|
||||
}
|
||||
|
||||
private void ConnectionTreeModelOnPropertyChanged(object sender,
|
||||
@@ -50,10 +40,8 @@ namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
if (!Properties.Settings.Default.SaveConnectionsAfterEveryEdit)
|
||||
return;
|
||||
if (FrmMain.Default.IsClosing)
|
||||
return;
|
||||
|
||||
_connectionsService.SaveConnectionsAsync(propertyName);
|
||||
_connectionsService?.SaveConnectionsAsync(propertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
@@ -36,7 +35,7 @@ namespace mRemoteNG.Config.Connections
|
||||
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Load()
|
||||
public SerializationResult Load()
|
||||
{
|
||||
var connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
|
||||
var dataProvider = new SqlDataProvider(connector);
|
||||
@@ -54,9 +53,9 @@ namespace mRemoteNG.Config.Connections
|
||||
databaseVersionVerifier.VerifyDatabaseVersion(metaData.ConfVersion);
|
||||
var dataTable = dataProvider.Load();
|
||||
var deserializer = new DataTableDeserializer(cryptoProvider, decryptionKey.First());
|
||||
var connectionTree = deserializer.Deserialize(dataTable);
|
||||
ApplyLocalConnectionProperties(connectionTree.RootNodes.First(i => i is RootNodeInfo));
|
||||
return connectionTree;
|
||||
var serializationResult = deserializer.Deserialize(dataTable);
|
||||
ApplyLocalConnectionProperties(serializationResult.ConnectionRecords.OfType<RootNodeInfo>().First());
|
||||
return serializationResult;
|
||||
}
|
||||
|
||||
private Optional<SecureString> GetDecryptionKey(SqlConnectionListMetaData metaData)
|
||||
|
||||
@@ -12,7 +12,6 @@ using mRemoteNG.Config.Serializers.Versioning;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
@@ -21,7 +20,7 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
|
||||
public class SqlConnectionsSaver : ISaver<IConnectionTreeModel>
|
||||
{
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer;
|
||||
@@ -39,7 +38,7 @@ namespace mRemoteNG.Config.Connections
|
||||
_dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
|
||||
}
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
public void Save(IConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
var rootTreeNode = connectionTreeModel.RootNodes.OfType<RootNodeInfo>().First();
|
||||
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.Serializers;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class XmlConnectionsLoader : IConnectionsLoader
|
||||
{
|
||||
private readonly string _credentialFilePath = Path.Combine(CredentialsFileInfo.CredentialsPath, CredentialsFileInfo.CredentialsFile);
|
||||
private readonly string _connectionFilePath;
|
||||
private readonly ConnectionsService _connectionsService;
|
||||
private readonly ICredentialService _credentialService;
|
||||
|
||||
public XmlConnectionsLoader(string connectionFilePath)
|
||||
public XmlConnectionsLoader(string connectionFilePath, ICredentialService credentialService, ConnectionsService connectionsService)
|
||||
{
|
||||
if (string.IsNullOrEmpty(connectionFilePath))
|
||||
throw new ArgumentException($"{nameof(connectionFilePath)} cannot be null or empty");
|
||||
@@ -21,14 +28,26 @@ namespace mRemoteNG.Config.Connections
|
||||
throw new FileNotFoundException($"{connectionFilePath} does not exist");
|
||||
|
||||
_connectionFilePath = connectionFilePath;
|
||||
_connectionsService = connectionsService.ThrowIfNull(nameof(connectionsService));
|
||||
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Load()
|
||||
public SerializationResult Load()
|
||||
{
|
||||
var dataProvider = new FileDataProvider(_connectionFilePath);
|
||||
var xmlString = dataProvider.Load();
|
||||
var deserializer = new XmlConnectionsDeserializer(PromptForPassword);
|
||||
return deserializer.Deserialize(xmlString);
|
||||
var deserializer = new CredentialManagerUpgradeForm
|
||||
{
|
||||
ConnectionFilePath = _connectionFilePath,
|
||||
NewCredentialRepoPath = _credentialFilePath,
|
||||
ConnectionsService = _connectionsService,
|
||||
CredentialService = _credentialService,
|
||||
ConnectionDeserializer = new XmlConnectionsDeserializer(PromptForPassword)
|
||||
};
|
||||
|
||||
var serializationResult = deserializer.Deserialize(xmlString);
|
||||
|
||||
return serializationResult;
|
||||
}
|
||||
|
||||
private Optional<SecureString> PromptForPassword()
|
||||
|
||||
@@ -10,7 +10,7 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
public class XmlConnectionsSaver : ISaver<ConnectionTreeModel>
|
||||
public class XmlConnectionsSaver : ISaver<IConnectionTreeModel>
|
||||
{
|
||||
private readonly string _connectionFileName;
|
||||
private readonly SaveFilter _saveFilter;
|
||||
@@ -26,7 +26,7 @@ namespace mRemoteNG.Config.Connections
|
||||
_saveFilter = saveFilter;
|
||||
}
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
public void Save(IConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
39
mRemoteNG/Config/CredentialRepositoryListPersistor.cs
Normal file
39
mRemoteNG/Config/CredentialRepositoryListPersistor.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.CredentialProviderSerializer;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Credential.Repositories;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config
|
||||
{
|
||||
public class CredentialRepositoryListPersistor : ISaver<IEnumerable<ICredentialRepository>>, ILoader<IEnumerable<ICredentialRepository>>
|
||||
{
|
||||
private readonly IReadOnlyCollection<ICredentialRepositoryFactory> _repositoryFactories;
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
private readonly CredentialRepositoryListDeserializer _deserializer;
|
||||
private readonly CredentialRepositoryListSerializer _serializer;
|
||||
|
||||
public CredentialRepositoryListPersistor(
|
||||
IDataProvider<string> dataProvider,
|
||||
IReadOnlyCollection<ICredentialRepositoryFactory> repositoryFactories)
|
||||
{
|
||||
_repositoryFactories = repositoryFactories.ThrowIfNull(nameof(repositoryFactories));
|
||||
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
|
||||
_deserializer = new CredentialRepositoryListDeserializer();
|
||||
_serializer = new CredentialRepositoryListSerializer();
|
||||
}
|
||||
|
||||
public IEnumerable<ICredentialRepository> Load()
|
||||
{
|
||||
var data = _dataProvider.Load();
|
||||
return _deserializer.Deserialize(data, _repositoryFactories);
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<ICredentialRepository> repositories, string propertyNameTrigger = "")
|
||||
{
|
||||
var data = _serializer.Serialize(repositories);
|
||||
_dataProvider.Save(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.IO;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
|
||||
@@ -53,12 +53,26 @@ namespace mRemoteNG.Config.DatabaseConnectors
|
||||
|
||||
private void BuildDbConnectionStringWithCustomCredentials()
|
||||
{
|
||||
_dbConnectionString = $"Data Source={_dbHost};Initial Catalog={_dbCatalog};User Id={_dbUsername};Password={_dbPassword}";
|
||||
string[] hostParts = _dbHost.Split(new char[] { ':' }, 2);
|
||||
var _dbPort = (hostParts.Length == 2) ? hostParts[1] : "1433";
|
||||
|
||||
_dbConnectionString = new SqlConnectionStringBuilder
|
||||
{
|
||||
DataSource = $"{hostParts[0]},{_dbPort}",
|
||||
InitialCatalog = _dbCatalog,
|
||||
UserID = _dbUsername,
|
||||
Password = _dbPassword,
|
||||
}.ToString();
|
||||
}
|
||||
|
||||
private void BuildDbConnectionStringWithDefaultCredentials()
|
||||
{
|
||||
_dbConnectionString = $"Data Source={_dbHost};Initial Catalog={_dbCatalog};Integrated Security=True";
|
||||
_dbConnectionString = new SqlConnectionStringBuilder
|
||||
{
|
||||
DataSource = _dbHost,
|
||||
InitialCatalog = _dbCatalog,
|
||||
IntegratedSecurity = true
|
||||
}.ToString();
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.Csv;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
namespace mRemoteNG.Config.Import
|
||||
{
|
||||
@@ -25,11 +26,18 @@ namespace mRemoteNG.Config.Import
|
||||
var dataProvider = new FileDataProvider(filePath);
|
||||
var xmlString = dataProvider.Load();
|
||||
var xmlConnectionsDeserializer = new CsvConnectionsDeserializerMremotengFormat();
|
||||
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString);
|
||||
var serializationResult = xmlConnectionsDeserializer.Deserialize(xmlString);
|
||||
|
||||
var credentialImportForm = new CredentialImportForm
|
||||
{
|
||||
ImportedCredentialRecords = serializationResult.ConnectionToCredentialMap.DistinctCredentialRecords.ToList(),
|
||||
CredentialService = Runtime.CredentialService
|
||||
};
|
||||
credentialImportForm.ShowDialog();
|
||||
|
||||
var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(filePath)};
|
||||
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
|
||||
rootImportContainer.AddChildRange(serializationResult.ConnectionRecords);
|
||||
destinationContainer.AddChild(rootImportContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
|
||||
@@ -27,10 +26,10 @@ namespace mRemoteNG.Config.Import
|
||||
var dataProvider = new FileDataProvider(fileName);
|
||||
var xmlString = dataProvider.Load();
|
||||
var xmlConnectionsDeserializer = new XmlConnectionsDeserializer();
|
||||
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(xmlString, true);
|
||||
var serializationResult = xmlConnectionsDeserializer.Deserialize(xmlString, true);
|
||||
|
||||
var rootImportContainer = new ContainerInfo {Name = Path.GetFileNameWithoutExtension(fileName)};
|
||||
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
|
||||
rootImportContainer.AddChildRange(serializationResult.ConnectionRecords);
|
||||
destinationContainer.AddChild(rootImportContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.MiscSerializers;
|
||||
using mRemoteNG.Container;
|
||||
|
||||
@@ -14,12 +13,9 @@ namespace mRemoteNG.Config.Import
|
||||
var xmlContent = dataProvider.Load();
|
||||
|
||||
var deserializer = new PuttyConnectionManagerDeserializer();
|
||||
var connectionTreeModel = deserializer.Deserialize(xmlContent);
|
||||
var serializationResult = deserializer.Deserialize(xmlContent);
|
||||
|
||||
var importedRootNode = connectionTreeModel.RootNodes.First();
|
||||
if (importedRootNode == null) return;
|
||||
var childrenToAdd = importedRootNode.Children.ToArray();
|
||||
destinationContainer.AddChildRange(childrenToAdd);
|
||||
destinationContainer.AddChildRange(serializationResult.ConnectionRecords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,9 @@ namespace mRemoteNG.Config.Import
|
||||
var content = dataProvider.Load();
|
||||
|
||||
var deserializer = new RemoteDesktopConnectionDeserializer();
|
||||
var connectionTreeModel = deserializer.Deserialize(content);
|
||||
var serializationResult = deserializer.Deserialize(content);
|
||||
|
||||
var importedConnection = connectionTreeModel.RootNodes.First().Children.First();
|
||||
var importedConnection = serializationResult.ConnectionRecords.FirstOrDefault();
|
||||
|
||||
if (importedConnection == null) return;
|
||||
importedConnection.Name = Path.GetFileNameWithoutExtension(fileName);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Serializers.MiscSerializers;
|
||||
using mRemoteNG.Container;
|
||||
|
||||
@@ -14,12 +13,9 @@ namespace mRemoteNG.Config.Import
|
||||
var fileContent = dataProvider.Load();
|
||||
|
||||
var deserializer = new RemoteDesktopConnectionManagerDeserializer();
|
||||
var connectionTreeModel = deserializer.Deserialize(fileContent);
|
||||
var serializationResult = deserializer.Deserialize(fileContent);
|
||||
|
||||
var importedRootNode = connectionTreeModel.RootNodes.First();
|
||||
if (importedRootNode == null) return;
|
||||
var childrenToAdd = importedRootNode.Children.ToArray();
|
||||
destinationContainer.AddChildRange(childrenToAdd);
|
||||
destinationContainer.AddChildRange(serializationResult.ConnectionRecords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Security.Principal;
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Security.Principal;
|
||||
|
||||
|
||||
namespace mRemoteNG.Config.Putty
|
||||
@@ -55,6 +55,7 @@ namespace mRemoteNG.Config.Putty
|
||||
PuttySession = sessionName,
|
||||
Name = sessionName,
|
||||
Hostname = sessionKey.GetValue("HostName")?.ToString() ?? "",
|
||||
// TODO: this should create a temp putty credential
|
||||
Username = sessionKey.GetValue("UserName")?.ToString() ?? ""
|
||||
};
|
||||
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
{
|
||||
public class CsvConnectionsDeserializerMremotengFormat : IDeserializer<string, ConnectionTreeModel>
|
||||
public class CsvConnectionsDeserializerMremotengFormat
|
||||
{
|
||||
public ConnectionTreeModel Deserialize(string serializedData)
|
||||
public SerializationResult Deserialize(string serializedData)
|
||||
{
|
||||
var lines = serializedData.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.RemoveEmptyEntries);
|
||||
var csvHeaders = new List<string>();
|
||||
@@ -29,26 +32,39 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
else
|
||||
{
|
||||
var connectionInfo = ParseConnectionInfo(csvHeaders, line);
|
||||
parentMapping.Add(connectionInfo, line[csvHeaders.IndexOf("Parent")]);
|
||||
|
||||
var parentFieldIndex = csvHeaders.IndexOf("Parent");
|
||||
if (parentFieldIndex > 0)
|
||||
parentMapping.Add(connectionInfo, line[parentFieldIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
var root = CreateTreeStructure(parentMapping);
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
return connectionTreeModel;
|
||||
var harvestedCredentials = new CredentialHarvester()
|
||||
.Harvest(new HarvestConfig<string[]>
|
||||
{
|
||||
ItemEnumerator = () => lines.Skip(1).Select(s => s.Split(';')),
|
||||
ConnectionGuidSelector = line => csvHeaders.Contains("Id") ? Guid.Parse(line[csvHeaders.IndexOf("Id")]) : Guid.NewGuid(),
|
||||
TitleSelector = line => "",
|
||||
UsernameSelector = line => csvHeaders.Contains("Username") ? line[csvHeaders.IndexOf("Username")] : "",
|
||||
DomainSelector = line => csvHeaders.Contains("Domain") ? line[csvHeaders.IndexOf("Domain")] : "",
|
||||
PasswordSelector = line => csvHeaders.Contains("Password") ? line[csvHeaders.IndexOf("Password")].ConvertToSecureString() : new SecureString()
|
||||
});
|
||||
|
||||
var result = new SerializationResult(root, harvestedCredentials);
|
||||
return result;
|
||||
}
|
||||
|
||||
private RootNodeInfo CreateTreeStructure(Dictionary<ConnectionInfo, string> parentMapping)
|
||||
private List<ConnectionInfo> CreateTreeStructure(Dictionary<ConnectionInfo, string> parentMapping)
|
||||
{
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var root = new List<ConnectionInfo>();
|
||||
|
||||
foreach (var node in parentMapping)
|
||||
{
|
||||
// no parent mapped, add to root
|
||||
if (string.IsNullOrEmpty(node.Value))
|
||||
{
|
||||
root.AddChild(node.Key);
|
||||
root.Add(node.Key);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -64,7 +80,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
}
|
||||
else
|
||||
{
|
||||
root.AddChild(node.Key);
|
||||
root.Add(node.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,53 +101,25 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
? new ConnectionInfo(nodeId)
|
||||
: new ContainerInfo(nodeId);
|
||||
|
||||
connectionRecord.Name = headers.Contains("Name")
|
||||
? connectionCsv[headers.IndexOf("Name")]
|
||||
: "";
|
||||
connectionRecord.Name = headers.Contains("Name") ? connectionCsv[headers.IndexOf("Name")] : "";
|
||||
connectionRecord.Description =
|
||||
headers.Contains("Description") ? connectionCsv[headers.IndexOf("Description")] : "";
|
||||
connectionRecord.Icon = headers.Contains("Icon") ? connectionCsv[headers.IndexOf("Icon")] : "";
|
||||
connectionRecord.Panel = headers.Contains("Panel") ? connectionCsv[headers.IndexOf("Panel")] : "";
|
||||
|
||||
connectionRecord.Description = headers.Contains("Description")
|
||||
? connectionCsv[headers.IndexOf("Description")]
|
||||
: "";
|
||||
var hasCredRecordId = Guid.TryParse(
|
||||
headers.Contains("CredentialRecordId") ? connectionCsv[headers.IndexOf("CredentialRecordId")] : "",
|
||||
out var credRecordId);
|
||||
connectionRecord.CredentialRecordId = hasCredRecordId ? credRecordId : Optional<Guid>.Empty;
|
||||
|
||||
connectionRecord.Icon = headers.Contains("Icon")
|
||||
? connectionCsv[headers.IndexOf("Icon")]
|
||||
: "";
|
||||
|
||||
connectionRecord.Panel = headers.Contains("Panel")
|
||||
? connectionCsv[headers.IndexOf("Panel")]
|
||||
: "";
|
||||
|
||||
connectionRecord.Username = headers.Contains("Username")
|
||||
? connectionCsv[headers.IndexOf("Username")]
|
||||
: "";
|
||||
|
||||
connectionRecord.Password = headers.Contains("Password")
|
||||
? connectionCsv[headers.IndexOf("Password")]
|
||||
: "";
|
||||
|
||||
connectionRecord.Domain = headers.Contains("Domain")
|
||||
? connectionCsv[headers.IndexOf("Domain")]
|
||||
: "";
|
||||
|
||||
connectionRecord.Hostname = headers.Contains("Hostname")
|
||||
? connectionCsv[headers.IndexOf("Hostname")]
|
||||
: "";
|
||||
|
||||
connectionRecord.VmId = headers.Contains("VmId")
|
||||
? connectionCsv[headers.IndexOf("VmId")] : "";
|
||||
|
||||
connectionRecord.SSHOptions =headers.Contains("SSHOptions")
|
||||
? connectionCsv[headers.IndexOf("SSHOptions")]
|
||||
: "";
|
||||
|
||||
connectionRecord.SSHTunnelConnectionName = headers.Contains("SSHTunnelConnectionName")
|
||||
? connectionCsv[headers.IndexOf("SSHTunnelConnectionName")]
|
||||
: "";
|
||||
|
||||
connectionRecord.PuttySession = headers.Contains("PuttySession")
|
||||
? connectionCsv[headers.IndexOf("PuttySession")]
|
||||
: "";
|
||||
// TODO: harvest
|
||||
connectionRecord.Username = headers.Contains("Username") ? connectionCsv[headers.IndexOf("Username")] : "";
|
||||
connectionRecord.Password = headers.Contains("Password") ? connectionCsv[headers.IndexOf("Password")] : "";
|
||||
connectionRecord.Domain = headers.Contains("Domain") ? connectionCsv[headers.IndexOf("Domain")] : "";
|
||||
|
||||
connectionRecord.Hostname = headers.Contains("Hostname") ? connectionCsv[headers.IndexOf("Hostname")] : "";
|
||||
connectionRecord.PuttySession =
|
||||
headers.Contains("PuttySession") ? connectionCsv[headers.IndexOf("PuttySession")] : "";
|
||||
connectionRecord.LoadBalanceInfo = headers.Contains("LoadBalanceInfo")
|
||||
? connectionCsv[headers.IndexOf("LoadBalanceInfo")]
|
||||
: "";
|
||||
@@ -186,6 +174,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
? connectionCsv[headers.IndexOf("RDGatewayHostname")]
|
||||
: "";
|
||||
|
||||
if (headers.Contains("CredentialId"))
|
||||
{
|
||||
if (Guid.TryParse(connectionCsv[headers.IndexOf("CredentialId")], out var credId))
|
||||
connectionRecord.CredentialRecordId = credId;
|
||||
}
|
||||
|
||||
if (headers.Contains("Protocol"))
|
||||
{
|
||||
if (Enum.TryParse(connectionCsv[headers.IndexOf("Protocol")], out ProtocolType protocolType))
|
||||
@@ -825,9 +819,16 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
connectionRecord.Inheritance.RdpVersion = value;
|
||||
}
|
||||
|
||||
|
||||
if (headers.Contains("InheritCredentialRecord"))
|
||||
{
|
||||
if (bool.TryParse(connectionCsv[headers.IndexOf("InheritCredentialRecord")], out bool value))
|
||||
connectionRecord.Inheritance.CredentialId = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return connectionRecord;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
"CacheBitmaps;RedirectDiskDrives;RedirectPorts;RedirectPrinters;RedirectClipboard;RedirectSmartCards;RedirectSound;RedirectKeys;" +
|
||||
"PreExtApp;PostExtApp;MacAddress;UserField;ExtApp;Favorite;VNCCompression;VNCEncoding;VNCAuthMode;VNCProxyType;VNCProxyIP;" +
|
||||
"VNCProxyPort;VNCProxyUsername;VNCProxyPassword;VNCColors;VNCSmartSizeMode;VNCViewOnly;RDGatewayUsageMethod;RDGatewayHostname;" +
|
||||
"RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;RedirectAudioCapture;RdpVersion;");
|
||||
"RDGatewayUseConnectionCredentials;RDGatewayUsername;RDGatewayPassword;RDGatewayDomain;RedirectAudioCapture;RdpVersion;CredentialId");
|
||||
|
||||
if (_saveFilter.SaveInheritance)
|
||||
sb.Append("InheritCacheBitmaps;InheritColors;InheritDescription;InheritDisplayThemes;InheritDisplayWallpaper;" +
|
||||
@@ -74,7 +74,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
"InheritVNCProxyPort;InheritVNCProxyUsername;InheritVNCProxyPassword;InheritVNCColors;InheritVNCSmartSizeMode;InheritVNCViewOnly;" +
|
||||
"InheritRDGatewayUsageMethod;InheritRDGatewayHostname;InheritRDGatewayUseConnectionCredentials;InheritRDGatewayUsername;" +
|
||||
"InheritRDGatewayPassword;InheritRDGatewayDomain;InheritRDPAlertIdleTimeout;InheritRDPMinutesToIdleTimeout;InheritSoundQuality;" +
|
||||
"InheritRedirectAudioCapture;InheritRdpVersion");
|
||||
"InheritRedirectAudioCapture;InheritRdpVersion;InheritCredentialRecord");
|
||||
}
|
||||
|
||||
private void SerializeNodesRecursive(ConnectionInfo node, StringBuilder sb)
|
||||
@@ -104,18 +104,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
.Append(FormatForCsv(con.GetTreeNodeType()))
|
||||
.Append(FormatForCsv(con.Description))
|
||||
.Append(FormatForCsv(con.Icon))
|
||||
.Append(FormatForCsv(con.Panel));
|
||||
|
||||
if (_saveFilter.SaveUsername)
|
||||
sb.Append(FormatForCsv(con.Username));
|
||||
|
||||
if (_saveFilter.SavePassword)
|
||||
sb.Append(FormatForCsv(con.Password));
|
||||
|
||||
if (_saveFilter.SaveDomain)
|
||||
sb.Append(FormatForCsv(con.Domain));
|
||||
|
||||
sb.Append(FormatForCsv(con.Hostname))
|
||||
.Append(FormatForCsv(con.Panel))
|
||||
.Append(FormatForCsv(con.Hostname))
|
||||
.Append(FormatForCsv(con.Port))
|
||||
.Append(FormatForCsv(con.VmId))
|
||||
.Append(FormatForCsv(con.Protocol))
|
||||
@@ -172,7 +162,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
.Append(FormatForCsv(con.RDGatewayPassword))
|
||||
.Append(FormatForCsv(con.RDGatewayDomain))
|
||||
.Append(FormatForCsv(con.RedirectAudioCapture))
|
||||
.Append(FormatForCsv(con.RdpVersion));
|
||||
.Append(FormatForCsv(con.RdpVersion))
|
||||
.Append(FormatForCsv(con.CredentialRecordId));
|
||||
|
||||
|
||||
if (!_saveFilter.SaveInheritance)
|
||||
@@ -243,7 +234,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
.Append(FormatForCsv(con.Inheritance.RDPMinutesToIdleTimeout))
|
||||
.Append(FormatForCsv(con.Inheritance.SoundQuality))
|
||||
.Append(FormatForCsv(con.Inheritance.RedirectAudioCapture))
|
||||
.Append(FormatForCsv(con.Inheritance.RdpVersion));
|
||||
.Append(FormatForCsv(con.Inheritance.RdpVersion))
|
||||
.Append(FormatForCsv(con.Inheritance.CredentialId));
|
||||
}
|
||||
|
||||
private string FormatForCsv(object value)
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
@@ -12,12 +11,10 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
{
|
||||
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
|
||||
public class DataTableDeserializer
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _decryptionKey;
|
||||
@@ -28,12 +25,13 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Deserialize(DataTable table)
|
||||
public SerializationResult Deserialize(DataTable table)
|
||||
{
|
||||
var connectionList = CreateNodesFromTable(table);
|
||||
var connectionTreeModel = CreateNodeHierarchy(connectionList, table);
|
||||
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
|
||||
return connectionTreeModel;
|
||||
var rootNodes = CreateNodeHierarchy(connectionList, table);
|
||||
|
||||
var serializationResult = new SerializationResult(rootNodes, new ConnectionToCredentialMap());
|
||||
return serializationResult;
|
||||
}
|
||||
|
||||
private List<ConnectionInfo> CreateNodesFromTable(DataTable table)
|
||||
@@ -60,7 +58,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
{
|
||||
var connectionId = row["ConstantID"] as string ?? Guid.NewGuid().ToString();
|
||||
var connectionInfo = new ConnectionInfo(connectionId);
|
||||
PopulateConnectionInfoFromDatarow(row, connectionInfo);
|
||||
PopulateConnectionInfoFromDataRow(row, connectionInfo);
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
@@ -68,11 +66,11 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
{
|
||||
var containerId = row["ConstantID"] as string ?? Guid.NewGuid().ToString();
|
||||
var containerInfo = new ContainerInfo(containerId);
|
||||
PopulateConnectionInfoFromDatarow(row, containerInfo);
|
||||
PopulateConnectionInfoFromDataRow(row, containerInfo);
|
||||
return containerInfo;
|
||||
}
|
||||
|
||||
private void PopulateConnectionInfoFromDatarow(DataRow dataRow, ConnectionInfo connectionInfo)
|
||||
private void PopulateConnectionInfoFromDataRow(DataRow dataRow, ConnectionInfo connectionInfo)
|
||||
{
|
||||
connectionInfo.Name = (string)dataRow["Name"];
|
||||
|
||||
@@ -83,9 +81,15 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
connectionInfo.Description = (string)dataRow["Description"];
|
||||
connectionInfo.Icon = (string)dataRow["Icon"];
|
||||
connectionInfo.Panel = (string)dataRow["Panel"];
|
||||
connectionInfo.Username = (string)dataRow["Username"];
|
||||
connectionInfo.Domain = (string)dataRow["Domain"];
|
||||
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
|
||||
|
||||
// TODO: harvest
|
||||
if (dataRow.Table.Columns.Contains("Username"))
|
||||
connectionInfo.Username = (string)dataRow["Username"];
|
||||
if (dataRow.Table.Columns.Contains("DomainName"))
|
||||
connectionInfo.Domain = (string)dataRow["DomainName"];
|
||||
if (dataRow.Table.Columns.Contains("Password"))
|
||||
connectionInfo.Password = DecryptValue((string)dataRow["Password"]);
|
||||
|
||||
connectionInfo.Hostname = (string)dataRow["Hostname"];
|
||||
connectionInfo.VmId = (string)dataRow["VmId"];
|
||||
connectionInfo.UseEnhancedMode = (bool)dataRow["UseEnhancedMode"];
|
||||
@@ -184,7 +188,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
connectionInfo.Inheritance.Domain = (bool)dataRow["InheritDomain"];
|
||||
connectionInfo.Inheritance.Icon = (bool)dataRow["InheritIcon"];
|
||||
connectionInfo.Inheritance.Panel = (bool)dataRow["InheritPanel"];
|
||||
connectionInfo.Inheritance.Password = (bool)dataRow["InheritPassword"];
|
||||
connectionInfo.Inheritance.Port = (bool)dataRow["InheritPort"];
|
||||
connectionInfo.Inheritance.Protocol = (bool)dataRow["InheritProtocol"];
|
||||
connectionInfo.Inheritance.SSHTunnelConnectionName = (bool)dataRow["InheritSSHTunnelConnectionName"];
|
||||
@@ -251,28 +254,21 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectionTreeModel CreateNodeHierarchy(List<ConnectionInfo> connectionList, DataTable dataTable)
|
||||
private List<ConnectionInfo> CreateNodeHierarchy(IReadOnlyCollection<ConnectionInfo> connectionList, DataTable dataTable)
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection, "0")
|
||||
{
|
||||
PasswordString = _decryptionKey.ConvertToUnsecureString()
|
||||
};
|
||||
connectionTreeModel.AddRootNode(rootNode);
|
||||
var rootNodes = new List<ConnectionInfo>();
|
||||
|
||||
foreach (DataRow row in dataTable.Rows)
|
||||
{
|
||||
var id = (string)row["ConstantID"];
|
||||
var id = (string) row["ConstantID"];
|
||||
var connectionInfo = connectionList.First(node => node.ConstantID == id);
|
||||
var parentId = (string)row["ParentID"];
|
||||
var parentId = (string) row["ParentID"];
|
||||
if (parentId == "0" || connectionList.All(node => node.ConstantID != parentId))
|
||||
rootNode.AddChild(connectionInfo);
|
||||
rootNodes.Add(connectionInfo);
|
||||
else
|
||||
(connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(
|
||||
connectionInfo);
|
||||
(connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(connectionInfo);
|
||||
}
|
||||
|
||||
return connectionTreeModel;
|
||||
return rootNodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,9 +105,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
dataTable.Columns.Add("Description", typeof(string));
|
||||
dataTable.Columns.Add("Icon", typeof(string));
|
||||
dataTable.Columns.Add("Panel", typeof(string));
|
||||
dataTable.Columns.Add("Username", typeof(string));
|
||||
dataTable.Columns.Add("Domain", typeof(string));
|
||||
dataTable.Columns.Add("Password", typeof(string));
|
||||
dataTable.Columns.Add("Hostname", typeof(string));
|
||||
dataTable.Columns.Add("Port", typeof(int));
|
||||
dataTable.Columns.Add("Protocol", typeof(string));
|
||||
@@ -502,16 +499,10 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
|
||||
dataRow["PositionID"] = _currentNodeIndex;
|
||||
dataRow["LastChange"] = MiscTools.DBTimeStampNow();
|
||||
dataRow["Expanded"] =
|
||||
false; // TODO: this column can eventually be removed. we now save this property locally
|
||||
dataRow["Description"] = connectionInfo.Description;
|
||||
dataRow["Icon"] = connectionInfo.Icon;
|
||||
dataRow["Panel"] = connectionInfo.Panel;
|
||||
dataRow["Username"] = _saveFilter.SaveUsername ? connectionInfo.Username : "";
|
||||
dataRow["Domain"] = _saveFilter.SaveDomain ? connectionInfo.Domain : "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword
|
||||
? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)
|
||||
: "";
|
||||
|
||||
dataRow["Hostname"] = connectionInfo.Hostname;
|
||||
dataRow["VmId"] = connectionInfo.VmId;
|
||||
dataRow["Protocol"] = connectionInfo.Protocol;
|
||||
@@ -549,7 +540,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
dataRow["SoundQuality"] = connectionInfo.SoundQuality;
|
||||
dataRow["RedirectAudioCapture"] = connectionInfo.RedirectAudioCapture;
|
||||
dataRow["RedirectKeys"] = connectionInfo.RedirectKeys;
|
||||
dataRow["Connected"] = false; // TODO: this column can eventually be removed. we now save this property locally
|
||||
dataRow["PreExtApp"] = connectionInfo.PreExtApp;
|
||||
dataRow["PostExtApp"] = connectionInfo.PostExtApp;
|
||||
dataRow["MacAddress"] = connectionInfo.MacAddress;
|
||||
@@ -592,7 +582,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
dataRow["InheritDomain"] = connectionInfo.Inheritance.Domain;
|
||||
dataRow["InheritIcon"] = connectionInfo.Inheritance.Icon;
|
||||
dataRow["InheritPanel"] = connectionInfo.Inheritance.Panel;
|
||||
dataRow["InheritPassword"] = connectionInfo.Inheritance.Password;
|
||||
dataRow["InheritPort"] = connectionInfo.Inheritance.Port;
|
||||
dataRow["InheritProtocol"] = connectionInfo.Inheritance.Protocol;
|
||||
dataRow["InheritSSHTunnelConnectionName"] = connectionInfo.Inheritance.SSHTunnelConnectionName;
|
||||
@@ -660,7 +649,6 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql
|
||||
dataRow["InheritDomain"] = false;
|
||||
dataRow["InheritIcon"] = false;
|
||||
dataRow["InheritPanel"] = false;
|
||||
dataRow["InheritPassword"] = false;
|
||||
dataRow["InheritPort"] = false;
|
||||
dataRow["InheritProtocol"] = false;
|
||||
dataRow["InheritSSHTunnelConnectionName"] = false;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
public ISerializer<ConnectionInfo, string> Build(
|
||||
ICryptographyProvider cryptographyProvider,
|
||||
ConnectionTreeModel connectionTreeModel,
|
||||
IConnectionTreeModel connectionTreeModel,
|
||||
SaveFilter saveFilter = null,
|
||||
bool useFullEncryption = false)
|
||||
{
|
||||
|
||||
@@ -11,24 +11,25 @@ using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.TaskDialog;
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Credential;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
public class XmlConnectionsDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class XmlConnectionsDeserializer
|
||||
{
|
||||
private XmlDocument _xmlDocument;
|
||||
private double _confVersion;
|
||||
private XmlConnectionsDecryptor _decryptor;
|
||||
private string ConnectionFileName = "";
|
||||
private const double MaxSupportedConfVersion = 2.8;
|
||||
private readonly RootNodeInfo _rootNodeInfo = new RootNodeInfo(RootNodeType.Connection);
|
||||
private const double MaxSupportedConfVersion = 2.7;
|
||||
private readonly CredentialDomainUserPasswordComparer _credentialComparer = new CredentialDomainUserPasswordComparer();
|
||||
|
||||
public Func<Optional<SecureString>> AuthenticationRequestor { get; set; }
|
||||
|
||||
@@ -37,12 +38,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
AuthenticationRequestor = authenticationRequestor;
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Deserialize(string xml)
|
||||
public SerializationResult Deserialize(string xml)
|
||||
{
|
||||
return Deserialize(xml, false);
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Deserialize(string xml, bool import)
|
||||
public SerializationResult Deserialize(string xml, bool import)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -50,17 +51,13 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
ValidateConnectionFileVersion();
|
||||
|
||||
var rootXmlElement = _xmlDocument.DocumentElement;
|
||||
InitializeRootNode(rootXmlElement);
|
||||
CreateDecryptor(_rootNodeInfo, rootXmlElement);
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
connectionTreeModel.AddRootNode(_rootNodeInfo);
|
||||
|
||||
var rootNodeInfo = InitializeRootNode(rootXmlElement);
|
||||
_decryptor = CreateDecryptor(rootNodeInfo, rootXmlElement);
|
||||
|
||||
if (_confVersion > 1.3)
|
||||
{
|
||||
var protectedString = _xmlDocument.DocumentElement?.Attributes["Protected"].Value;
|
||||
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString,
|
||||
_rootNodeInfo.PasswordString.ConvertToSecureString()))
|
||||
if (!_decryptor.ConnectionsFileIsAuthentic(protectedString, rootNodeInfo.PasswordString.ConvertToSecureString()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -76,12 +73,11 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
}
|
||||
}
|
||||
|
||||
AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, _rootNodeInfo);
|
||||
var credentialMap = new ConnectionToCredentialMap();
|
||||
var rootNodes = AddNodesFromXmlRecursive(_xmlDocument.DocumentElement, credentialMap);
|
||||
var serializationResult = new SerializationResult(rootNodes, credentialMap);
|
||||
|
||||
if (!import)
|
||||
Runtime.ConnectionsService.IsConnectionsFileLoaded = true;
|
||||
|
||||
return connectionTreeModel;
|
||||
return serializationResult;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -93,8 +89,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
|
||||
private void LoadXmlConnectionData(string connections)
|
||||
{
|
||||
CreateDecryptor(new RootNodeInfo(RootNodeType.Connection));
|
||||
connections = _decryptor.LegacyFullFileDecrypt(connections);
|
||||
var legacyDecryptor = CreateDecryptor(new RootNodeInfo(RootNodeType.Connection));
|
||||
connections = legacyDecryptor.LegacyFullFileDecrypt(connections);
|
||||
_xmlDocument = new XmlDocument();
|
||||
if (connections != "")
|
||||
_xmlDocument.LoadXml(connections);
|
||||
@@ -135,13 +131,16 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
);
|
||||
}
|
||||
|
||||
private void InitializeRootNode(XmlElement connectionsRootElement)
|
||||
private RootNodeInfo InitializeRootNode(XmlElement connectionsRootElement)
|
||||
{
|
||||
var rootNodeName = connectionsRootElement?.Attributes["Name"].Value.Trim();
|
||||
_rootNodeInfo.Name = rootNodeName;
|
||||
return new RootNodeInfo(RootNodeType.Connection)
|
||||
{
|
||||
Name = rootNodeName
|
||||
};
|
||||
}
|
||||
|
||||
private void CreateDecryptor(RootNodeInfo rootNodeInfo, XmlElement connectionsRootElement = null)
|
||||
private XmlConnectionsDecryptor CreateDecryptor(RootNodeInfo rootNodeInfo, XmlElement connectionsRootElement = null)
|
||||
{
|
||||
if (_confVersion >= 2.6)
|
||||
{
|
||||
@@ -149,24 +148,27 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
var mode = connectionsRootElement.GetAttributeAsEnum<BlockCipherModes>("BlockCipherMode");
|
||||
var keyDerivationIterations = connectionsRootElement.GetAttributeAsInt("KdfIterations");
|
||||
|
||||
_decryptor = new XmlConnectionsDecryptor(engine, mode, rootNodeInfo)
|
||||
return new XmlConnectionsDecryptor(engine, mode, rootNodeInfo)
|
||||
{
|
||||
AuthenticationRequestor = AuthenticationRequestor,
|
||||
KeyDerivationIterations = keyDerivationIterations
|
||||
};
|
||||
}
|
||||
else
|
||||
|
||||
return new XmlConnectionsDecryptor(rootNodeInfo)
|
||||
{
|
||||
_decryptor = new XmlConnectionsDecryptor(_rootNodeInfo)
|
||||
{AuthenticationRequestor = AuthenticationRequestor};
|
||||
}
|
||||
AuthenticationRequestor = AuthenticationRequestor
|
||||
};
|
||||
}
|
||||
|
||||
private void AddNodesFromXmlRecursive(XmlNode parentXmlNode, ContainerInfo parentContainer)
|
||||
private List<ConnectionInfo> AddNodesFromXmlRecursive(XmlNode parentXmlNode, ConnectionToCredentialMap credentialMap)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!parentXmlNode.HasChildNodes) return;
|
||||
if (!parentXmlNode.HasChildNodes)
|
||||
return new List<ConnectionInfo>();
|
||||
|
||||
var children = new List<ConnectionInfo>();
|
||||
foreach (XmlNode xmlNode in parentXmlNode.ChildNodes)
|
||||
{
|
||||
var nodeType = xmlNode.GetAttributeAsEnum("Type", TreeNodeType.Connection);
|
||||
@@ -175,24 +177,27 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
switch (nodeType)
|
||||
{
|
||||
case TreeNodeType.Connection:
|
||||
var connectionInfo = GetConnectionInfoFromXml(xmlNode);
|
||||
parentContainer.AddChild(connectionInfo);
|
||||
var connectionInfo = GetConnectionInfoFromXml(xmlNode, credentialMap);
|
||||
children.Add(connectionInfo);
|
||||
break;
|
||||
case TreeNodeType.Container:
|
||||
var containerInfo = new ContainerInfo();
|
||||
|
||||
if (_confVersion >= 0.9)
|
||||
containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode));
|
||||
containerInfo.CopyFrom(GetConnectionInfoFromXml(xmlNode, credentialMap));
|
||||
if (_confVersion >= 0.8)
|
||||
{
|
||||
containerInfo.IsExpanded = xmlNode.GetAttributeAsBool("Expanded");
|
||||
}
|
||||
|
||||
parentContainer.AddChild(containerInfo);
|
||||
AddNodesFromXmlRecursive(xmlNode, containerInfo);
|
||||
var subChildren = AddNodesFromXmlRecursive(xmlNode, credentialMap);
|
||||
subChildren.ForEach(info => containerInfo.AddChild(info));
|
||||
children.Add(containerInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -201,7 +206,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode)
|
||||
private ConnectionInfo GetConnectionInfoFromXml(XmlNode xmlnode, ConnectionToCredentialMap credentialMap)
|
||||
{
|
||||
if (xmlnode?.Attributes == null)
|
||||
return null;
|
||||
@@ -229,13 +234,21 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
: RDPResolutions.FitToWindow;
|
||||
}
|
||||
|
||||
if (!Runtime.UseCredentialManager || _confVersion <= 2.6) // 0.2 - 2.6
|
||||
if (_confVersion <= 2.6) // 0.2 - 2.6
|
||||
{
|
||||
#pragma warning disable 618
|
||||
connectionInfo.Username = xmlnode.GetAttributeAsString("Username");
|
||||
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
|
||||
connectionInfo.Domain = xmlnode.GetAttributeAsString("Domain");
|
||||
#pragma warning restore 618
|
||||
var username = xmlnode.GetAttributeAsString("Username");
|
||||
var domain = xmlnode.GetAttributeAsString("Domain");
|
||||
|
||||
var cred = new CredentialRecord
|
||||
{
|
||||
Title = domain.Length > 0 ? $"{domain}\\{username}" : username,
|
||||
Username = username,
|
||||
Domain = domain,
|
||||
Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password")).ConvertToSecureString()
|
||||
};
|
||||
|
||||
if (!_credentialComparer.Equals(cred, new NullCredentialRecord()))
|
||||
connectionInfo.CredentialRecordId = cred.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,6 +570,12 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
connectionInfo.Inheritance.DisableMenuAnimations = xmlnode.GetAttributeAsBool("InheritDisableMenuAnimations");
|
||||
connectionInfo.Inheritance.DisableCursorShadow = xmlnode.GetAttributeAsBool("InheritDisableCursorShadow");
|
||||
connectionInfo.Inheritance.DisableCursorBlinking = xmlnode.GetAttributeAsBool("InheritDisableCursorBlinking");
|
||||
|
||||
connectionInfo.CredentialRecordId = Guid.TryParse(xmlnode.Attributes?["CredentialId"]?.Value, out var credId)
|
||||
? credId
|
||||
: Optional<Guid>.Empty;
|
||||
|
||||
connectionInfo.Inheritance.CredentialId = xmlnode.GetAttributeAsBool("InheritCredentialId");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -12,8 +12,7 @@ using mRemoteNG.Tree.Root;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
public class XmlConnectionsSerializer : ISerializer<ConnectionTreeModel, string>,
|
||||
ISerializer<ConnectionInfo, string>
|
||||
public class XmlConnectionsSerializer : ISerializer<IConnectionTreeModel,string>, ISerializer<ConnectionInfo, string>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly ISerializer<ConnectionInfo, XElement> _connectionNodeSerializer;
|
||||
@@ -28,7 +27,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
_connectionNodeSerializer = connectionNodeSerializer;
|
||||
}
|
||||
|
||||
public string Serialize(ConnectionTreeModel connectionTreeModel)
|
||||
public string Serialize(IConnectionTreeModel connectionTreeModel)
|
||||
{
|
||||
var rootNode = (RootNodeInfo)connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
|
||||
return SerializeConnectionsData(rootNode);
|
||||
|
||||
@@ -9,29 +9,38 @@ namespace mRemoteNG.Config.Serializers.CredentialProviderSerializer
|
||||
{
|
||||
public class CredentialRepositoryListDeserializer
|
||||
{
|
||||
private readonly ISecureSerializer<IEnumerable<ICredentialRecord>, string> _serializer;
|
||||
private readonly ISecureDeserializer<string, IEnumerable<ICredentialRecord>> _deserializer;
|
||||
|
||||
public CredentialRepositoryListDeserializer(
|
||||
ISecureSerializer<IEnumerable<ICredentialRecord>, string> serializer,
|
||||
ISecureDeserializer<string, IEnumerable<ICredentialRecord>> deserializer)
|
||||
public IEnumerable<ICredentialRepository> Deserialize(string xml, IEnumerable<ICredentialRepositoryFactory> factories)
|
||||
{
|
||||
if (serializer == null)
|
||||
throw new ArgumentNullException(nameof(serializer));
|
||||
if (deserializer == null)
|
||||
throw new ArgumentNullException(nameof(deserializer));
|
||||
if (string.IsNullOrEmpty(xml))
|
||||
return new ICredentialRepository[0];
|
||||
|
||||
_serializer = serializer;
|
||||
_deserializer = deserializer;
|
||||
}
|
||||
|
||||
public IEnumerable<ICredentialRepository> Deserialize(string xml)
|
||||
{
|
||||
if (string.IsNullOrEmpty(xml)) return new ICredentialRepository[0];
|
||||
var xdoc = XDocument.Parse(xml);
|
||||
var repoEntries = xdoc.Descendants("CredentialRepository");
|
||||
var xmlRepoFactory = new XmlCredentialRepositoryFactory(_serializer, _deserializer);
|
||||
return repoEntries.Select(xmlRepoFactory.Build);
|
||||
|
||||
return repoEntries
|
||||
.Select(ParseConfigEntries)
|
||||
.Select(config =>
|
||||
factories
|
||||
.FirstOrDefault(f => string.Equals(f.SupportsConfigType, config.TypeName))?
|
||||
.Build(config));
|
||||
}
|
||||
|
||||
public ICredentialRepositoryConfig ParseConfigEntries(XElement repositoryXElement)
|
||||
{
|
||||
var stringId = repositoryXElement.Attribute("Id")?.Value;
|
||||
Guid.TryParse(stringId, out var id);
|
||||
|
||||
if (id.Equals(Guid.Empty))
|
||||
id = Guid.NewGuid();
|
||||
|
||||
var config = new CredentialRepositoryConfig(id)
|
||||
{
|
||||
TypeName = repositoryXElement.Attribute("TypeName")?.Value,
|
||||
Title = repositoryXElement.Attribute("Title")?.Value,
|
||||
Source = repositoryXElement.Attribute("Source")?.Value
|
||||
};
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.CredentialSerializer
|
||||
{
|
||||
public class CredentialHarvester
|
||||
{
|
||||
private readonly IEqualityComparer<ICredentialRecord> _credentialComparer = new CredentialDomainUserPasswordComparer();
|
||||
|
||||
/// <summary>
|
||||
/// Maps a <see cref="ConnectionInfo"/> (by its id) to the <see cref="ICredentialRecord"/>
|
||||
/// object that was harvested
|
||||
/// </summary>
|
||||
/// <param name="harvestConfig"></param>
|
||||
public ConnectionToCredentialMap Harvest<T>(HarvestConfig<T> harvestConfig)
|
||||
{
|
||||
if (harvestConfig == null)
|
||||
throw new ArgumentNullException(nameof(harvestConfig));
|
||||
|
||||
var credentialMap = new ConnectionToCredentialMap();
|
||||
foreach (var element in harvestConfig.ItemEnumerator())
|
||||
{
|
||||
var newCredential = new CredentialRecord
|
||||
{
|
||||
Title = harvestConfig.TitleSelector(element),
|
||||
Username = harvestConfig.UsernameSelector(element),
|
||||
Domain = harvestConfig.DomainSelector(element),
|
||||
Password = harvestConfig.PasswordSelector(element)
|
||||
};
|
||||
|
||||
if (!EntryHasSomeCredentialData(newCredential))
|
||||
continue;
|
||||
|
||||
var connectionId = harvestConfig.ConnectionGuidSelector(element);
|
||||
|
||||
var existingCredential = credentialMap.Values.FirstOrDefault(record => _credentialComparer.Equals(newCredential, record));
|
||||
credentialMap.Add(connectionId, existingCredential ?? newCredential);
|
||||
}
|
||||
|
||||
return credentialMap;
|
||||
}
|
||||
|
||||
private bool EntryHasSomeCredentialData(ICredentialRecord e)
|
||||
{
|
||||
return !_credentialComparer.Equals(e, new NullCredentialRecord());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.CredentialSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration for the <see cref="CredentialHarvester"/> to allow it to
|
||||
/// iterate over and select values from any arbitrary data type. Each element
|
||||
/// of type <see cref="T"/> represents an object that contains intermixed
|
||||
/// connection and credential data.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class HarvestConfig<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// This will be called to produce a list of all objects
|
||||
/// that should be iterated over.
|
||||
/// </summary>
|
||||
public Func<IEnumerable<T>> ItemEnumerator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Given an item of type <see cref="T"/>, return
|
||||
/// the <see cref="Guid"/> that represents the connection's unique ID
|
||||
/// within mRemoteNG.
|
||||
/// </summary>
|
||||
public Func<T, Guid> ConnectionGuidSelector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Given an item of type <see cref="T"/>, return a <see cref="string"/>
|
||||
/// that represents what the associated credential's title should be.
|
||||
/// </summary>
|
||||
public Func<T, string> TitleSelector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Given an item of type <see cref="T"/>, return a <see cref="string"/>
|
||||
/// that represents what the associated credential's username should be.
|
||||
/// </summary>
|
||||
public Func<T, string> UsernameSelector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Given an item of type <see cref="T"/>, return a <see cref="string"/>
|
||||
/// that represents what the associated credential's domain should be.
|
||||
/// </summary>
|
||||
public Func<T, string> DomainSelector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Given an item of type <see cref="T"/>, return a <see cref="SecureString"/>
|
||||
/// that represents what the associated credential's password should be.
|
||||
/// </summary>
|
||||
public Func<T, SecureString> PasswordSelector { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ using mRemoteNG.Config.Import;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
|
||||
@@ -1,59 +1,68 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security;
|
||||
using System.Xml;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class PuttyConnectionManagerDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class PuttyConnectionManagerDeserializer
|
||||
{
|
||||
public ConnectionTreeModel Deserialize(string puttycmConnectionsXml)
|
||||
public SerializationResult Deserialize(string puttycmConnectionsXml)
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
var result = new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
|
||||
|
||||
var xmlDocument = new XmlDocument();
|
||||
xmlDocument.LoadXml(puttycmConnectionsXml);
|
||||
|
||||
var configurationNode = xmlDocument.SelectSingleNode("/configuration");
|
||||
|
||||
var rootNodes = configurationNode?.SelectNodes("./root");
|
||||
if (rootNodes == null) return connectionTreeModel;
|
||||
foreach (XmlNode rootNode in rootNodes)
|
||||
var rootXmlNode = configurationNode?.SelectSingleNode("./root");
|
||||
if (rootXmlNode == null)
|
||||
return result;
|
||||
|
||||
var rootContainer = ReadContainerProperties(rootXmlNode);
|
||||
result.ConnectionRecords.Add(rootContainer);
|
||||
|
||||
foreach (XmlNode node in rootXmlNode.ChildNodes)
|
||||
{
|
||||
ImportRootOrContainer(rootNode, root);
|
||||
rootContainer.AddChild(ImportRecursive(node, result.ConnectionToCredentialMap));
|
||||
}
|
||||
|
||||
return connectionTreeModel;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ImportRootOrContainer(XmlNode xmlNode, ContainerInfo parentContainer)
|
||||
private ContainerInfo ImportRecursive(XmlNode xmlNode, ConnectionToCredentialMap credentialMap)
|
||||
{
|
||||
VerifyNodeType(xmlNode);
|
||||
|
||||
var newContainer = ImportContainer(xmlNode, parentContainer);
|
||||
var newContainer = ReadContainerProperties(xmlNode);
|
||||
|
||||
var childNodes = xmlNode.SelectNodes("./*");
|
||||
if (childNodes == null) return;
|
||||
if (childNodes == null)
|
||||
return newContainer;
|
||||
|
||||
foreach (XmlNode childNode in childNodes)
|
||||
{
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "container":
|
||||
ImportRootOrContainer(childNode, newContainer);
|
||||
newContainer.AddChild(ImportRecursive(childNode, credentialMap));
|
||||
break;
|
||||
case "connection":
|
||||
ImportConnection(childNode, newContainer);
|
||||
newContainer.AddChild(ImportConnection(childNode, credentialMap));
|
||||
break;
|
||||
default:
|
||||
throw (new FileFormatException($"Unrecognized child node ({childNode.Name})."));
|
||||
throw new FileFormatException($"Unrecognized child node ({childNode.Name}).");
|
||||
}
|
||||
}
|
||||
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
private void VerifyNodeType(XmlNode xmlNode)
|
||||
@@ -82,25 +91,28 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
}
|
||||
}
|
||||
|
||||
private ContainerInfo ImportContainer(XmlNode containerNode, ContainerInfo parentContainer)
|
||||
private ContainerInfo ReadContainerProperties(XmlNode containerNode)
|
||||
{
|
||||
var containerInfo = new ContainerInfo
|
||||
{
|
||||
Name = containerNode.Attributes?["name"].Value,
|
||||
IsExpanded = bool.Parse(containerNode.Attributes?["expanded"].InnerText ?? "false")
|
||||
};
|
||||
parentContainer.AddChild(containerInfo);
|
||||
|
||||
return containerInfo;
|
||||
}
|
||||
|
||||
private void ImportConnection(XmlNode connectionNode, ContainerInfo parentContainer)
|
||||
private ConnectionInfo ImportConnection(XmlNode connectionNode, ConnectionToCredentialMap credentialMap)
|
||||
{
|
||||
var connectionNodeType = connectionNode.Attributes?["type"].Value;
|
||||
if (string.Compare(connectionNodeType, "PuTTY", StringComparison.OrdinalIgnoreCase) != 0)
|
||||
throw (new FileFormatException($"Unrecognized connection node type ({connectionNodeType})."));
|
||||
|
||||
var connectionInfo = ConnectionInfoFromXml(connectionNode);
|
||||
parentContainer.AddChild(connectionInfo);
|
||||
var cred = CredentialFromXml(connectionNode);
|
||||
connectionInfo.CredentialRecordId = cred.Id;
|
||||
credentialMap.Add(Guid.Parse(connectionInfo.ConstantID), cred);
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
private ConnectionInfo ConnectionInfoFromXml(XmlNode xmlNode)
|
||||
@@ -129,9 +141,6 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
// ./commandline
|
||||
connectionInfo.Description = connectionInfoNode.SelectSingleNode("./description")?.InnerText;
|
||||
|
||||
var loginNode = xmlNode.SelectSingleNode("./login");
|
||||
connectionInfo.Username = loginNode?.SelectSingleNode("login")?.InnerText;
|
||||
connectionInfo.Password = loginNode?.SelectSingleNode("password")?.InnerText;
|
||||
// ./prompt
|
||||
|
||||
// ./timeout/connectiontimeout
|
||||
@@ -151,5 +160,19 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
private ICredentialRecord CredentialFromXml(XmlNode xmlNode)
|
||||
{
|
||||
var loginNode = xmlNode.SelectSingleNode("./login");
|
||||
var username = loginNode?.SelectSingleNode("login")?.InnerText ?? "";
|
||||
|
||||
return new CredentialRecord
|
||||
{
|
||||
Title = username,
|
||||
Username = username,
|
||||
Domain = "",
|
||||
Password = loginNode?.SelectSingleNode("password")?.InnerText.ConvertToSecureString() ?? new SecureString()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
using System;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System.Collections.Generic;
|
||||
using mRemoteNG.Credential;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class RemoteDesktopConnectionDeserializer
|
||||
{
|
||||
// .rdp file schema: https://technet.microsoft.com/en-us/library/ff393699(v=ws.10).aspx
|
||||
|
||||
public ConnectionTreeModel Deserialize(string rdcFileContent)
|
||||
public SerializationResult Deserialize(string rdcFileContent)
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
var connectionInfo = new ConnectionInfo();
|
||||
var username = "";
|
||||
var domain = "";
|
||||
|
||||
foreach (var line in rdcFileContent.Split(Environment.NewLine.ToCharArray()))
|
||||
{
|
||||
var parts = line.Split(new[] { ':' }, 3);
|
||||
@@ -24,21 +24,42 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = parts[0].Trim();
|
||||
var propertyName = parts[0].Trim().ToLowerInvariant();
|
||||
var value = parts[2].Trim();
|
||||
|
||||
SetConnectionInfoParameter(connectionInfo, key, value);
|
||||
SetConnectionInfoParameter(connectionInfo, propertyName, value);
|
||||
|
||||
|
||||
if (propertyName.Equals("username"))
|
||||
username = value;
|
||||
if (propertyName.Equals("domain"))
|
||||
domain = value;
|
||||
}
|
||||
|
||||
root.AddChild(connectionInfo);
|
||||
var serializationResult = new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
|
||||
serializationResult.ConnectionRecords.Add(connectionInfo);
|
||||
|
||||
return connectionTreeModel;
|
||||
if (username.Length > 0 || domain.Length > 0)
|
||||
{
|
||||
var cred = new CredentialRecord
|
||||
{
|
||||
Title = domain.Length > 0 ? $"{domain}\\" : "" + username,
|
||||
Domain = domain,
|
||||
Username = username
|
||||
};
|
||||
|
||||
serializationResult.ConnectionToCredentialMap.Add(Guid.Parse(connectionInfo.ConstantID), cred);
|
||||
connectionInfo.CredentialRecordId = cred.Id;
|
||||
}
|
||||
|
||||
|
||||
return serializationResult;
|
||||
}
|
||||
|
||||
|
||||
private void SetConnectionInfoParameter(ConnectionInfo connectionInfo, string key, string value)
|
||||
{
|
||||
switch (key.ToLower())
|
||||
switch (key)
|
||||
{
|
||||
case "full address":
|
||||
var uri = new Uri("dummyscheme" + Uri.SchemeDelimiter + value);
|
||||
@@ -50,12 +71,6 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
case "server port":
|
||||
connectionInfo.Port = Convert.ToInt32(value);
|
||||
break;
|
||||
case "username":
|
||||
connectionInfo.Username = value;
|
||||
break;
|
||||
case "domain":
|
||||
connectionInfo.Domain = value;
|
||||
break;
|
||||
case "session bpp":
|
||||
switch (value)
|
||||
{
|
||||
|
||||
@@ -1,41 +1,44 @@
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
{
|
||||
public class RemoteDesktopConnectionManagerDeserializer : IDeserializer<string, ConnectionTreeModel>
|
||||
public class RemoteDesktopConnectionManagerDeserializer
|
||||
{
|
||||
private static int _schemaVersion; /* 1 = RDCMan v2.2
|
||||
3 = RDCMan v2.7 */
|
||||
// 1 = RDCMan v2.2
|
||||
// 3 = RDCMan v2.7
|
||||
private static int _schemaVersion;
|
||||
|
||||
public ConnectionTreeModel Deserialize(string rdcmConnectionsXml)
|
||||
public SerializationResult Deserialize(string rdcmConnectionsXml)
|
||||
{
|
||||
var connectionTreeModel = new ConnectionTreeModel();
|
||||
var root = new RootNodeInfo(RootNodeType.Connection);
|
||||
var serializationResult = new SerializationResult(new List<ConnectionInfo>(), new ConnectionToCredentialMap());
|
||||
|
||||
var xmlDocument = new XmlDocument();
|
||||
xmlDocument.LoadXml(rdcmConnectionsXml);
|
||||
|
||||
|
||||
var rdcManNode = xmlDocument.SelectSingleNode("/RDCMan");
|
||||
VerifySchemaVersion(rdcManNode);
|
||||
VerifyFileVersion(rdcManNode);
|
||||
|
||||
var fileNode = rdcManNode?.SelectSingleNode("./file");
|
||||
ImportFileOrGroup(fileNode, root);
|
||||
var importedItem = ImportFileOrGroup(fileNode, serializationResult.ConnectionToCredentialMap);
|
||||
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
return connectionTreeModel;
|
||||
serializationResult.ConnectionRecords.Add(importedItem);
|
||||
|
||||
return serializationResult;
|
||||
}
|
||||
|
||||
private static void VerifySchemaVersion(XmlNode rdcManNode)
|
||||
@@ -80,28 +83,46 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
}
|
||||
}
|
||||
|
||||
private static void ImportFileOrGroup(XmlNode xmlNode, ContainerInfo parentContainer)
|
||||
private static ContainerInfo ImportFileOrGroup(XmlNode xmlNode, ConnectionToCredentialMap credentialMap)
|
||||
{
|
||||
var newContainer = ImportContainer(xmlNode, parentContainer);
|
||||
var newContainer = ImportContainer(xmlNode);
|
||||
|
||||
var childNodes = xmlNode.SelectNodes("./group|./server");
|
||||
if (childNodes == null) return;
|
||||
if (childNodes == null)
|
||||
return newContainer;
|
||||
|
||||
foreach (XmlNode childNode in childNodes)
|
||||
{
|
||||
ConnectionInfo newChild = null;
|
||||
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (childNode.Name)
|
||||
{
|
||||
case "group":
|
||||
ImportFileOrGroup(childNode, newContainer);
|
||||
newChild = ImportFileOrGroup(childNode, credentialMap);
|
||||
break;
|
||||
case "server":
|
||||
ImportServer(childNode, newContainer);
|
||||
newChild = ConnectionInfoFromXml(childNode);
|
||||
break;
|
||||
}
|
||||
|
||||
if (newChild == null)
|
||||
return newContainer;
|
||||
|
||||
newContainer.AddChild(newChild);
|
||||
|
||||
var cred = ParseCredentials(childNode);
|
||||
if (!cred.Any())
|
||||
continue;
|
||||
|
||||
newChild.CredentialRecordId = cred.First().Id;
|
||||
credentialMap.Add(Guid.Parse(newChild.ConstantID), cred.First());
|
||||
}
|
||||
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
private static ContainerInfo ImportContainer(XmlNode containerPropertiesNode, ContainerInfo parentContainer)
|
||||
private static ContainerInfo ImportContainer(XmlNode containerPropertiesNode)
|
||||
{
|
||||
if (_schemaVersion == 1)
|
||||
{
|
||||
@@ -121,16 +142,9 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
newContainer.Name = containerPropertiesNode?.SelectSingleNode("./name")?.InnerText ?? Language.NewFolder;
|
||||
if (bool.TryParse(containerPropertiesNode?.SelectSingleNode("./expanded")?.InnerText, out var expanded))
|
||||
newContainer.IsExpanded = expanded;
|
||||
parentContainer.AddChild(newContainer);
|
||||
return newContainer;
|
||||
}
|
||||
|
||||
private static void ImportServer(XmlNode serverNode, ContainerInfo parentContainer)
|
||||
{
|
||||
var newConnectionInfo = ConnectionInfoFromXml(serverNode);
|
||||
parentContainer.AddChild(newConnectionInfo);
|
||||
}
|
||||
|
||||
private static ConnectionInfo ConnectionInfoFromXml(XmlNode xmlNode)
|
||||
{
|
||||
var connectionInfo = new ConnectionInfo {Protocol = ProtocolType.RDP};
|
||||
@@ -153,25 +167,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
connectionInfo.Description = propertiesNode?.SelectSingleNode("./comment")?.InnerText ?? string.Empty;
|
||||
|
||||
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
|
||||
if (logonCredentialsNode?.Attributes?["inherit"]?.Value == "None")
|
||||
{
|
||||
connectionInfo.Username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText ?? string.Empty;
|
||||
|
||||
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
|
||||
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords
|
||||
{
|
||||
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionInfo.Password = DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
|
||||
connectionInfo.Domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
|
||||
}
|
||||
else
|
||||
if (logonCredentialsNode?.Attributes?["inherit"]?.Value != "None")
|
||||
{
|
||||
connectionInfo.Inheritance.Username = true;
|
||||
connectionInfo.Inheritance.Password = true;
|
||||
@@ -205,9 +201,9 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
connectionInfo.RDGatewayUsername = gatewaySettingsNode.SelectSingleNode("./userName")?.InnerText ?? string.Empty;
|
||||
|
||||
var passwordNode = gatewaySettingsNode.SelectSingleNode("./password");
|
||||
connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
connectionInfo.RDGatewayPassword = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText).ConvertToUnsecureString();
|
||||
|
||||
connectionInfo.RDGatewayDomain = gatewaySettingsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
|
||||
// ./logonMethod
|
||||
@@ -349,22 +345,45 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
private static string DecryptRdcManPassword(string ciphertext)
|
||||
private static Optional<ICredentialRecord> ParseCredentials(XmlNode xmlNode)
|
||||
{
|
||||
var logonCredentialsNode = xmlNode.SelectSingleNode("./logonCredentials");
|
||||
|
||||
if (logonCredentialsNode?.Attributes?["inherit"]?.Value != "None")
|
||||
return Optional<ICredentialRecord>.Empty;
|
||||
|
||||
var username = logonCredentialsNode.SelectSingleNode("userName")?.InnerText ?? "";
|
||||
var domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText ?? "";
|
||||
var passwordNode = logonCredentialsNode.SelectSingleNode("./password");
|
||||
|
||||
var creds = new CredentialRecord
|
||||
{
|
||||
Title = domain.Length > 0 ? $"{domain}\\{username}" : $"{username}",
|
||||
Username = username,
|
||||
Domain = domain,
|
||||
Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText.ConvertToSecureString()
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText)
|
||||
};
|
||||
|
||||
return creds;
|
||||
}
|
||||
|
||||
private static SecureString DecryptRdcManPassword(string ciphertext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ciphertext))
|
||||
return string.Empty;
|
||||
return new SecureString();
|
||||
|
||||
try
|
||||
{
|
||||
var plaintextData = ProtectedData.Unprotect(Convert.FromBase64String(ciphertext), new byte[] { },
|
||||
DataProtectionScope.LocalMachine);
|
||||
var charArray = Encoding.Unicode.GetChars(plaintextData);
|
||||
return new string(charArray);
|
||||
return Encoding.Unicode.GetString(plaintextData).ConvertToSecureString();
|
||||
}
|
||||
catch (Exception /*ex*/)
|
||||
{
|
||||
//Runtime.MessageCollector.AddExceptionMessage("RemoteDesktopConnectionManager.DecryptPassword() failed.", ex, logOnly: true);
|
||||
return string.Empty;
|
||||
return new SecureString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
mRemoteNG/Config/Serializers/SerializationResult.cs
Normal file
23
mRemoteNG/Config/Serializers/SerializationResult.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Tools;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the connections and credentials found during a deserialization.
|
||||
/// </summary>
|
||||
public class SerializationResult
|
||||
{
|
||||
public List<ConnectionInfo> ConnectionRecords { get; }
|
||||
public ConnectionToCredentialMap ConnectionToCredentialMap { get; }
|
||||
|
||||
public SerializationResult(
|
||||
List<ConnectionInfo> connectionRecords,
|
||||
ConnectionToCredentialMap connectionToCredentialMap)
|
||||
{
|
||||
ConnectionRecords = connectionRecords.ThrowIfNull(nameof(connectionRecords));
|
||||
ConnectionToCredentialMap = connectionToCredentialMap.ThrowIfNull(nameof(connectionToCredentialMap));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Config.Serializers.CredentialSerializer;
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Security.Authentication;
|
||||
using mRemoteNG.Security.Factories;
|
||||
using mRemoteNG.Tools;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.Xml;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
public class XmlCredentialManagerUpgrader
|
||||
{
|
||||
private readonly XmlConnectionsDeserializer _deserializer;
|
||||
|
||||
|
||||
public XmlCredentialManagerUpgrader(XmlConnectionsDeserializer decoratedDeserializer)
|
||||
{
|
||||
_deserializer = decoratedDeserializer.ThrowIfNull(nameof(decoratedDeserializer));
|
||||
}
|
||||
|
||||
public SerializationResult Deserialize(string serializedData, ConnectionToCredentialMap upgradeMap)
|
||||
{
|
||||
var serializedDataAsXDoc = EnsureConnectionXmlElementsHaveIds(serializedData);
|
||||
var serializedDataWithIds = $"{serializedDataAsXDoc.Declaration}{serializedDataAsXDoc}";
|
||||
|
||||
var serializationResult = _deserializer.Deserialize(serializedDataWithIds);
|
||||
|
||||
if (upgradeMap != null)
|
||||
ApplyCredentialMapping(upgradeMap, serializationResult.ConnectionRecords.FlattenConnectionTree());
|
||||
|
||||
return serializationResult;
|
||||
}
|
||||
|
||||
private XDocument EnsureConnectionXmlElementsHaveIds(string serializedData)
|
||||
{
|
||||
var xdoc = XDocument.Parse(serializedData);
|
||||
xdoc.Declaration = new XDeclaration("1.0", "utf-8", null);
|
||||
var adapter = new ConfConsEnsureConnectionsHaveIds();
|
||||
adapter.EnsureElementsHaveIds(xdoc);
|
||||
return xdoc;
|
||||
}
|
||||
|
||||
public ConnectionToCredentialMap UpgradeUserFilesForCredentialManager(XDocument xdoc)
|
||||
{
|
||||
if (!CredentialManagerUpgradeNeeded(xdoc))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cryptoProvider = new CryptoProviderFactoryFromXml(xdoc.Root).Build();
|
||||
var encryptedValue = xdoc.Root?.Attribute("Protected")?.Value;
|
||||
var auth = new PasswordAuthenticator(cryptoProvider, encryptedValue, () => MiscTools.PasswordDialog("", false));
|
||||
if (!auth.Authenticate(Runtime.EncryptionKey))
|
||||
throw new Exception("Could not authenticate");
|
||||
|
||||
var keyForOldConnectionFile = auth.LastAuthenticatedPassword;
|
||||
|
||||
var preCredManagerXmlHarvestConfig = new HarvestConfig<XElement>
|
||||
{
|
||||
ItemEnumerator = () => xdoc.Descendants("Node"),
|
||||
ConnectionGuidSelector = e =>
|
||||
{
|
||||
Guid.TryParse(e.Attribute("Id")?.Value, out var connectionId);
|
||||
return connectionId;
|
||||
},
|
||||
UsernameSelector = e => e.Attribute("Username")?.Value,
|
||||
DomainSelector = e => e.Attribute("Domain")?.Value,
|
||||
PasswordSelector = e => cryptoProvider.Decrypt(e.Attribute("Password")?.Value, keyForOldConnectionFile).ConvertToSecureString(),
|
||||
TitleSelector = e => $"{e.Attribute("Domain")?.Value}{(string.IsNullOrEmpty(e.Attribute("Domain")?.Value) ? "" : "\\")}{e.Attribute("Username")?.Value}"
|
||||
};
|
||||
|
||||
var credentialHarvester = new CredentialHarvester();
|
||||
var harvestedCredentials = credentialHarvester.Harvest(preCredManagerXmlHarvestConfig);
|
||||
|
||||
return harvestedCredentials;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If any connections in the xml contain a Username/Domain/Password field, we need to upgrade
|
||||
/// it to be compatible with the credential manager.
|
||||
/// </summary>
|
||||
/// <param name="xdoc"></param>
|
||||
public static bool CredentialManagerUpgradeNeeded(XContainer xdoc)
|
||||
{
|
||||
return xdoc
|
||||
.Descendants("Node")
|
||||
.Any(n =>
|
||||
n.Attribute("Username") != null ||
|
||||
n.Attribute("Domain") != null ||
|
||||
n.Attribute("Password") != null);
|
||||
}
|
||||
|
||||
private void ApplyCredentialMapping(IDictionary<Guid, ICredentialRecord> map, IEnumerable<AbstractConnectionRecord> connectionRecords)
|
||||
{
|
||||
foreach (var connectionInfo in connectionRecords)
|
||||
{
|
||||
Guid.TryParse(connectionInfo.ConstantID, out var id);
|
||||
if (map.ContainsKey(id))
|
||||
connectionInfo.CredentialRecordId = map[id].Id.ToOptional();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,9 +77,6 @@ namespace mRemoteNG.Config.Settings
|
||||
|
||||
if (persistString == typeof(ErrorAndInfoWindow).ToString())
|
||||
return Windows.ErrorsForm;
|
||||
|
||||
if (persistString == typeof(ScreenshotManagerWindow).ToString())
|
||||
return Windows.ScreenshotForm;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
using System.Linq;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools.Attributes;
|
||||
using mRemoteNG.UI.Controls.Adapters;
|
||||
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
@@ -22,6 +27,7 @@ namespace mRemoteNG.Connection
|
||||
private string _panel;
|
||||
|
||||
private string _hostname;
|
||||
private Optional<Guid> _credentialRecordId = new Optional<Guid>();
|
||||
private string _username = "";
|
||||
private string _password = "";
|
||||
private string _domain = "";
|
||||
@@ -160,6 +166,7 @@ namespace mRemoteNG.Connection
|
||||
set => SetField(ref _port, value, "Port");
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Username)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionUsername)),
|
||||
@@ -170,6 +177,7 @@ namespace mRemoteNG.Connection
|
||||
set => SetField(ref _username, Settings.Default.DoNotTrimUsername ? value : value?.Trim(), "Username");
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Password)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionPassword)),
|
||||
@@ -181,6 +189,7 @@ namespace mRemoteNG.Connection
|
||||
set => SetField(ref _password, value, "Password");
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Domain)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionDomain)),
|
||||
@@ -211,6 +220,26 @@ namespace mRemoteNG.Connection
|
||||
get => GetPropertyValue("SSHTunnelConnectionName", _sshTunnelConnectionName).Trim();
|
||||
set => SetField(ref _sshTunnelConnectionName, value?.Trim(), "SSHTunnelConnectionName");
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
public virtual Optional<Guid> CredentialRecordId
|
||||
{
|
||||
get => GetPropertyValue(nameof(CredentialRecordId), _credentialRecordId);
|
||||
set => SetField(ref _credentialRecordId, value ?? Optional<Guid>.Empty, nameof(CredentialRecordId));
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Credentials)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionCredentials)),
|
||||
AttributeUsedInAllProtocolsExcept()]
|
||||
[Editor(typeof(CredentialRecordListAdaptor), typeof(UITypeEditor))]
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))]
|
||||
public virtual ICredentialRecord CredentialRecord
|
||||
{
|
||||
// TODO: this static ref to the cred service makes testing difficult. refactor it to allow easy mocking
|
||||
get => Runtime.CredentialService.GetEffectiveCredentialRecord(CredentialRecordId, false).FirstOrDefault();
|
||||
set => CredentialRecordId = Optional<Guid>.FromNullable(value?.Id);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Protocol
|
||||
@@ -589,7 +618,7 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Redirect)),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.DiskDrives)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectDrives)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.RDP)]
|
||||
@@ -634,7 +663,7 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Redirect), 6),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Redirect)),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.SmartCard)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionRedirectSmartCards)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.RDP)]
|
||||
|
||||
@@ -15,7 +15,6 @@ using mRemoteNG.Connection.Protocol.Telnet;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tree;
|
||||
|
||||
|
||||
@@ -136,22 +135,24 @@ namespace mRemoteNG.Connection
|
||||
return filteredProperties;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<PropertyInfo> GetSerializableProperties()
|
||||
{
|
||||
var excludedProperties = new[]
|
||||
{
|
||||
"Parent", "Name", "Hostname", "Port", "Inheritance", "OpenConnections",
|
||||
"IsContainer", "IsDefault", "PositionID", "ConstantID", "TreeNode", "IsQuickConnect", "PleaseConnect"
|
||||
};
|
||||
public virtual IEnumerable<PropertyInfo> GetSerializableProperties()
|
||||
{
|
||||
var excludedProperties = new[] {
|
||||
nameof(Parent), nameof(Name), nameof(Hostname), nameof(Port),
|
||||
nameof(Username), nameof(Domain), nameof(Password),
|
||||
nameof(Inheritance), nameof(OpenConnections),
|
||||
nameof(IsContainer), nameof(IsDefault), nameof(ConstantID),
|
||||
nameof(IsQuickConnect), nameof(PleaseConnect), nameof(CredentialRecord)
|
||||
};
|
||||
|
||||
return GetProperties(excludedProperties);
|
||||
}
|
||||
return GetProperties(excludedProperties);
|
||||
}
|
||||
|
||||
public virtual void SetParent(ContainerInfo newParent)
|
||||
{
|
||||
public virtual void SetParent(ContainerInfo newParent)
|
||||
{
|
||||
RemoveParent();
|
||||
newParent?.AddChild(this);
|
||||
}
|
||||
newParent?.AddChild(this);
|
||||
}
|
||||
|
||||
public void RemoveParent()
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
@@ -49,7 +48,13 @@ namespace mRemoteNG.Connection
|
||||
|
||||
#endregion
|
||||
|
||||
#region Connection
|
||||
#region
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 3),
|
||||
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.Credentials)),
|
||||
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionCredentials)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool CredentialId { get; set; }
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 3),
|
||||
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.Username)),
|
||||
|
||||
@@ -6,9 +6,9 @@ using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Panels;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.UI.Tabs;
|
||||
using mRemoteNG.UI.Window;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
@@ -20,6 +20,12 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
private readonly PanelAdder _panelAdder = new PanelAdder();
|
||||
private readonly List<string> _activeConnections = new List<string>();
|
||||
private readonly CredentialService _credentialService;
|
||||
|
||||
public ConnectionInitiator(CredentialService credentialService)
|
||||
{
|
||||
_credentialService = credentialService;
|
||||
}
|
||||
|
||||
public IEnumerable<string> ActiveConnections => _activeConnections;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
@@ -11,9 +13,9 @@ using mRemoteNG.Config.DataProviders;
|
||||
using mRemoteNG.Config.Putty;
|
||||
using mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Credential;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tree;
|
||||
@@ -22,7 +24,7 @@ using mRemoteNG.UI;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public class ConnectionsService
|
||||
public class ConnectionsService : IConnectionsService
|
||||
{
|
||||
private static readonly object SaveLock = new object();
|
||||
private readonly PuttySessionsManager _puttySessionsManager;
|
||||
@@ -31,6 +33,7 @@ namespace mRemoteNG.Connection
|
||||
private bool _batchingSaves = false;
|
||||
private bool _saveRequested = false;
|
||||
private bool _saveAsyncRequested = false;
|
||||
private readonly ICredentialService _credentialService;
|
||||
|
||||
public bool IsConnectionsFileLoaded { get; set; }
|
||||
public bool UsingDatabase { get; private set; }
|
||||
@@ -38,18 +41,18 @@ namespace mRemoteNG.Connection
|
||||
public RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
|
||||
public DateTime LastSqlUpdate { get; set; }
|
||||
|
||||
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
|
||||
public IConnectionTreeModel ConnectionTreeModel { get; private set; } = new ConnectionTreeModel();
|
||||
|
||||
public ConnectionsService(PuttySessionsManager puttySessionsManager)
|
||||
public ConnectionsService(PuttySessionsManager puttySessionsManager, ICredentialService credentialService)
|
||||
{
|
||||
if (puttySessionsManager == null)
|
||||
throw new ArgumentNullException(nameof(puttySessionsManager));
|
||||
|
||||
_puttySessionsManager = puttySessionsManager;
|
||||
_puttySessionsManager = puttySessionsManager.ThrowIfNull(nameof(puttySessionsManager));
|
||||
_credentialService = credentialService.ThrowIfNull(nameof(credentialService));
|
||||
var path = SettingsFileInfo.SettingsPath;
|
||||
_localConnectionPropertiesDataProvider =
|
||||
new FileDataProvider(Path.Combine(path, "LocalConnectionProperties.xml"));
|
||||
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
|
||||
|
||||
_puttySessionsManager.RootPuttySessionsNodes.ForEach(node => ConnectionTreeModel.AddRootNode(node));
|
||||
}
|
||||
|
||||
public void NewConnectionsFile(string filename)
|
||||
@@ -57,10 +60,9 @@ namespace mRemoteNG.Connection
|
||||
try
|
||||
{
|
||||
filename.ThrowIfNullOrEmpty(nameof(filename));
|
||||
var newConnectionsModel = new ConnectionTreeModel();
|
||||
newConnectionsModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
|
||||
SaveConnections(newConnectionsModel, false, new SaveFilter(), filename, true);
|
||||
LoadConnections(false, false, filename);
|
||||
ConnectionTreeModel.AddRootNode(new RootNodeInfo(RootNodeType.Connection));
|
||||
SaveConnections(ConnectionTreeModel, false, new SaveFilter(), filename, true);
|
||||
LoadConnections(false, filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -124,22 +126,21 @@ namespace mRemoteNG.Connection
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="import"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
public void LoadConnections(bool useDatabase, bool import, string connectionFileName)
|
||||
public void LoadConnections(bool useDatabase, string connectionFileName)
|
||||
{
|
||||
var oldConnectionTreeModel = ConnectionTreeModel;
|
||||
var oldIsUsingDatabaseValue = UsingDatabase;
|
||||
|
||||
var connectionLoader = useDatabase
|
||||
? (IConnectionsLoader)new SqlConnectionsLoader(_localConnectionPropertiesSerializer,
|
||||
_localConnectionPropertiesDataProvider)
|
||||
: new XmlConnectionsLoader(connectionFileName);
|
||||
: new XmlConnectionsLoader(connectionFileName, _credentialService, this);
|
||||
|
||||
var newConnectionTreeModel = connectionLoader.Load();
|
||||
var serializationResult = connectionLoader.Load();
|
||||
|
||||
if (useDatabase)
|
||||
LastSqlUpdate = DateTime.Now;
|
||||
|
||||
if (newConnectionTreeModel == null)
|
||||
if (serializationResult == null)
|
||||
{
|
||||
DialogFactory.ShowLoadConnectionsFailedDialog(connectionFileName, "Decrypting connection file failed",
|
||||
IsConnectionsFileLoaded);
|
||||
@@ -150,16 +151,17 @@ namespace mRemoteNG.Connection
|
||||
ConnectionFileName = connectionFileName;
|
||||
UsingDatabase = useDatabase;
|
||||
|
||||
if (!import)
|
||||
{
|
||||
_puttySessionsManager.AddSessions();
|
||||
newConnectionTreeModel.RootNodes.AddRange(_puttySessionsManager.RootPuttySessionsNodes);
|
||||
}
|
||||
if (ConnectionTreeModel.RootNodes.Any())
|
||||
ConnectionTreeModel.RemoveRootNode(ConnectionTreeModel.RootNodes.First());
|
||||
|
||||
var rootNode = new RootNodeInfo(RootNodeType.Connection);
|
||||
rootNode.AddChildRange(serializationResult.ConnectionRecords);
|
||||
ConnectionTreeModel.AddRootNode(rootNode);
|
||||
|
||||
ConnectionTreeModel = newConnectionTreeModel;
|
||||
UpdateCustomConsPathSetting(connectionFileName);
|
||||
RaiseConnectionsLoadedEvent(oldConnectionTreeModel, newConnectionTreeModel, oldIsUsingDatabaseValue,
|
||||
useDatabase, connectionFileName);
|
||||
// TODO: fix this call
|
||||
RaiseConnectionsLoadedEvent(new List<ConnectionInfo>(), new List<ConnectionInfo>(),
|
||||
oldIsUsingDatabaseValue, useDatabase, connectionFileName);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg,
|
||||
$"Connections loaded using {connectionLoader.GetType().Name}");
|
||||
}
|
||||
@@ -225,12 +227,13 @@ namespace mRemoteNG.Connection
|
||||
/// Optional. The name of the property that triggered
|
||||
/// this save.
|
||||
/// </param>
|
||||
public void SaveConnections(ConnectionTreeModel connectionTreeModel,
|
||||
bool useDatabase,
|
||||
SaveFilter saveFilter,
|
||||
string connectionFileName,
|
||||
bool forceSave = false,
|
||||
string propertyNameTrigger = "")
|
||||
public void SaveConnections(
|
||||
IConnectionTreeModel connectionTreeModel,
|
||||
bool useDatabase,
|
||||
SaveFilter saveFilter,
|
||||
string connectionFileName,
|
||||
bool forceSave = false,
|
||||
string propertyNameTrigger = "")
|
||||
{
|
||||
if (connectionTreeModel == null)
|
||||
return;
|
||||
@@ -252,9 +255,8 @@ namespace mRemoteNG.Connection
|
||||
var previouslyUsingDatabase = UsingDatabase;
|
||||
|
||||
var saver = useDatabase
|
||||
? (ISaver<ConnectionTreeModel>)new SqlConnectionsSaver(saveFilter,
|
||||
_localConnectionPropertiesSerializer,
|
||||
_localConnectionPropertiesDataProvider)
|
||||
? (ISaver<IConnectionTreeModel>)new SqlConnectionsSaver(saveFilter, _localConnectionPropertiesSerializer,
|
||||
_localConnectionPropertiesDataProvider)
|
||||
: new XmlConnectionsSaver(connectionFileName, saveFilter);
|
||||
|
||||
saver.Save(connectionTreeModel, propertyNameTrigger);
|
||||
@@ -357,31 +359,22 @@ namespace mRemoteNG.Connection
|
||||
public event EventHandler<ConnectionsLoadedEventArgs> ConnectionsLoaded;
|
||||
public event EventHandler<ConnectionsSavedEventArgs> ConnectionsSaved;
|
||||
|
||||
private void RaiseConnectionsLoadedEvent(Optional<ConnectionTreeModel> previousTreeModel,
|
||||
ConnectionTreeModel newTreeModel,
|
||||
bool previousSourceWasDatabase,
|
||||
bool newSourceIsDatabase,
|
||||
string newSourcePath)
|
||||
private void RaiseConnectionsLoadedEvent(List<ConnectionInfo> removedConnections, List<ConnectionInfo> addedConnections,
|
||||
bool previousSourceWasDatabase, bool newSourceIsDatabase,
|
||||
string newSourcePath)
|
||||
{
|
||||
ConnectionsLoaded?.Invoke(this, new ConnectionsLoadedEventArgs(
|
||||
previousTreeModel,
|
||||
newTreeModel,
|
||||
removedConnections,
|
||||
addedConnections,
|
||||
previousSourceWasDatabase,
|
||||
newSourceIsDatabase,
|
||||
newSourcePath));
|
||||
}
|
||||
|
||||
private void RaiseConnectionsSavedEvent(ConnectionTreeModel modelThatWasSaved,
|
||||
bool previouslyUsingDatabase,
|
||||
bool usingDatabase,
|
||||
string connectionFileName)
|
||||
private void RaiseConnectionsSavedEvent(IConnectionTreeModel modelThatWasSaved, bool previouslyUsingDatabase, bool usingDatabase, string connectionFileName)
|
||||
{
|
||||
ConnectionsSaved?.Invoke(this,
|
||||
new ConnectionsSavedEventArgs(modelThatWasSaved, previouslyUsingDatabase,
|
||||
usingDatabase,
|
||||
connectionFileName));
|
||||
ConnectionsSaved?.Invoke(this, new ConnectionsSavedEventArgs(modelThatWasSaved, previouslyUsingDatabase, usingDatabase, connectionFileName));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -67,8 +67,11 @@ namespace mRemoteNG.Connection
|
||||
throw new SettingsPropertyNotFoundException($"No property with name '{expectedPropertyName}' found.");
|
||||
|
||||
// ensure value is of correct type
|
||||
var value = Convert.ChangeType(property.GetValue(Instance, null),
|
||||
propertyFromDestination.PropertyType);
|
||||
var value = property.PropertyType == propertyFromDestination.PropertyType
|
||||
? property.GetValue(Instance, null)
|
||||
: propertyFromDestination.PropertyType == typeof(string)
|
||||
? property.GetValue(Instance, null).ToString()
|
||||
: Convert.ChangeType(property.GetValue(Instance, null), propertyFromDestination.PropertyType);
|
||||
|
||||
propertyFromDestination.SetValue(destinationInstance, value, null);
|
||||
}
|
||||
|
||||
78
mRemoteNG/Connection/IConnectionsService.cs
Normal file
78
mRemoteNG/Connection/IConnectionsService.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using mRemoteNG.Config.Connections;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public interface IConnectionsService
|
||||
{
|
||||
IConnectionTreeModel ConnectionTreeModel { get; }
|
||||
void NewConnectionsFile(string filename);
|
||||
ConnectionInfo CreateQuickConnect(string connectionString, ProtocolType protocol);
|
||||
|
||||
/// <summary>
|
||||
/// Load connections from a source. <see cref="connectionFileName"/> is ignored if
|
||||
/// <see cref="useDatabase"/> is true.
|
||||
/// </summary>
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="import"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
void LoadConnections(bool useDatabase, string connectionFileName);
|
||||
|
||||
/// <summary>
|
||||
/// When turned on, calls to <see cref="ConnectionsService.SaveConnections()"/> or
|
||||
/// <see cref="ConnectionsService.SaveConnectionsAsync"/> will not immediately execute.
|
||||
/// Instead, they will be deferred until <see cref="ConnectionsService.EndBatchingSaves"/>
|
||||
/// is called.
|
||||
/// </summary>
|
||||
void BeginBatchingSaves();
|
||||
|
||||
/// <summary>
|
||||
/// Immediately executes a single <see cref="ConnectionsService.SaveConnections()"/> or
|
||||
/// <see cref="ConnectionsService.SaveConnectionsAsync"/> if one has been requested
|
||||
/// since calling <see cref="ConnectionsService.BeginBatchingSaves"/>.
|
||||
/// </summary>
|
||||
void EndBatchingSaves();
|
||||
|
||||
/// <summary>
|
||||
/// Saves the currently loaded <see cref="ConnectionsService.ConnectionTreeModel"/> with
|
||||
/// no <see cref="SaveFilter"/>.
|
||||
/// </summary>
|
||||
void SaveConnections();
|
||||
|
||||
/// <summary>
|
||||
/// Saves the given <see cref="ConnectionsService.ConnectionTreeModel"/>.
|
||||
/// If <see cref="useDatabase"/> is true, <see cref="connectionFileName"/> is ignored
|
||||
/// </summary>
|
||||
/// <param name="connectionTreeModel"></param>
|
||||
/// <param name="useDatabase"></param>
|
||||
/// <param name="saveFilter"></param>
|
||||
/// <param name="connectionFileName"></param>
|
||||
/// <param name="forceSave">Bypasses safety checks that prevent saving if a connection file isn't loaded.</param>
|
||||
/// <param name="propertyNameTrigger">
|
||||
/// Optional. The name of the property that triggered
|
||||
/// this save.
|
||||
/// </param>
|
||||
void SaveConnections(
|
||||
IConnectionTreeModel connectionTreeModel,
|
||||
bool useDatabase,
|
||||
SaveFilter saveFilter,
|
||||
string connectionFileName,
|
||||
bool forceSave = false,
|
||||
string propertyNameTrigger = "");
|
||||
|
||||
/// <summary>
|
||||
/// Save the currently loaded connections asynchronously
|
||||
/// </summary>
|
||||
/// <param name="propertyNameTrigger">
|
||||
/// Optional. The name of the property that triggered
|
||||
/// this save.
|
||||
/// </param>
|
||||
void SaveConnectionsAsync(string propertyNameTrigger = "");
|
||||
|
||||
event EventHandler<ConnectionsLoadedEventArgs> ConnectionsLoaded;
|
||||
event EventHandler<ConnectionsSavedEventArgs> ConnectionsSaved;
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright © 2013 The CefSharp Authors. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
using CefSharp;
|
||||
using System;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.Http
|
||||
{
|
||||
public class DownloadHandler : IDownloadHandler
|
||||
{
|
||||
public event EventHandler<DownloadItem> OnBeforeDownloadFired;
|
||||
|
||||
public event EventHandler<DownloadItem> OnDownloadUpdatedFired;
|
||||
|
||||
public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
|
||||
{
|
||||
OnBeforeDownloadFired?.Invoke(this, downloadItem);
|
||||
|
||||
if (!callback.IsDisposed)
|
||||
{
|
||||
using (callback)
|
||||
{
|
||||
callback.Continue(downloadItem.SuggestedFileName, showDialog: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
|
||||
{
|
||||
OnDownloadUpdatedFired?.Invoke(this, downloadItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using CefSharp;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.Http
|
||||
{
|
||||
partial class RequestHandler : IRequestHandler
|
||||
{
|
||||
public bool GetAuthCredentials(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
|
||||
{
|
||||
if (request.Url.StartsWith(Cef.CefCommitHash))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start(request.Url);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDocumentAvailableInMainFrame(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnCertificateError(IWebBrowser chromiumWebBrowser, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OnOpenUrlFromTab(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnPluginCrashed(IWebBrowser chromiumWebBrowser, IBrowser browser, string pluginPath)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnQuotaRequest(IWebBrowser chromiumWebBrowser, IBrowser browser, string originUrl, long newSize, IRequestCallback callback)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnRenderProcessTerminated(IWebBrowser chromiumWebBrowser, IBrowser browser, CefTerminationStatus status)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnRenderViewReady(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||
{
|
||||
}
|
||||
|
||||
public bool OnSelectClientCertificate(IWebBrowser chromiumWebBrowser, IBrowser browser, bool isProxy, string host, int port, X509Certificate2Collection certificates, ISelectClientCertificateCallback callback)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using CefSharp;
|
||||
using CefSharp.WinForms;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.UI.Tabs;
|
||||
|
||||
|
||||
@@ -14,24 +12,22 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
{
|
||||
#region Private Properties
|
||||
|
||||
private Control wBrowser;
|
||||
private Control _wBrowser;
|
||||
private string _tabTitle;
|
||||
protected string httpOrS;
|
||||
protected int defaultPort;
|
||||
private string tabTitle;
|
||||
private bool browserInitialised = false;
|
||||
private bool connectCalled = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
protected HTTPBase(RenderingEngine RenderingEngine)
|
||||
protected HTTPBase(RenderingEngine renderingEngine)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (RenderingEngine == RenderingEngine.CEF)
|
||||
if (renderingEngine == RenderingEngine.EdgeChromium)
|
||||
{
|
||||
Control = new ChromiumWebBrowser("about:blank")
|
||||
Control = new WebView2()
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
@@ -53,33 +49,26 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
|
||||
try
|
||||
{
|
||||
if (InterfaceControl.Parent is ConnectionTab objConnectionTab) tabTitle = objConnectionTab.TabText;
|
||||
if (InterfaceControl.Parent is ConnectionTab objConnectionTab) _tabTitle = objConnectionTab.TabText;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
tabTitle = "";
|
||||
_tabTitle = "";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
wBrowser = Control;
|
||||
_wBrowser = Control;
|
||||
|
||||
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.CEF)
|
||||
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.EdgeChromium)
|
||||
{
|
||||
var CEFBrowser = (ChromiumWebBrowser)wBrowser;
|
||||
if (CEFBrowser != null)
|
||||
{
|
||||
CEFBrowser.LoadingStateChanged += CefBrowser_LoadingStateChanged;
|
||||
CEFBrowser.TitleChanged += WBrowser_DocumentTitleChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Failed to initialize CEF Rendering Engine.");
|
||||
}
|
||||
var edge = (WebView2)_wBrowser;
|
||||
|
||||
edge.CoreWebView2InitializationCompleted += Edge_CoreWebView2InitializationCompleted;
|
||||
}
|
||||
else
|
||||
{
|
||||
var objWebBrowser = (WebBrowser)wBrowser;
|
||||
var objWebBrowser = (WebBrowser)_wBrowser;
|
||||
objWebBrowser.ScrollBarsEnabled = true;
|
||||
|
||||
// http://stackoverflow.com/questions/4655662/how-to-ignore-script-errors-in-webbrowser
|
||||
@@ -87,7 +76,6 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
|
||||
objWebBrowser.Navigated += WBrowser_Navigated;
|
||||
objWebBrowser.DocumentTitleChanged += WBrowser_DocumentTitleChanged;
|
||||
browserInitialised = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -103,20 +91,16 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
{
|
||||
try
|
||||
{
|
||||
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.CEF)
|
||||
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.EdgeChromium)
|
||||
{
|
||||
if (browserInitialised)
|
||||
{
|
||||
((ChromiumWebBrowser)wBrowser).Load(GetURL());
|
||||
}
|
||||
((WebView2)_wBrowser).Source = new Uri(GetUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
((WebBrowser)wBrowser).Navigate(GetURL());
|
||||
((WebBrowser)_wBrowser).Navigate(GetUrl());
|
||||
}
|
||||
|
||||
base.Connect();
|
||||
connectCalled = true;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -130,22 +114,12 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private string GetURL()
|
||||
private string GetUrl()
|
||||
{
|
||||
try
|
||||
{
|
||||
var strHost = InterfaceControl.Info.Hostname;
|
||||
/*
|
||||
* Commenting out since this codes doesn't actually do anything at this time...
|
||||
* Possibly related to MR-221 and/or MR-533 ????
|
||||
*
|
||||
string strAuth = "";
|
||||
|
||||
if (((int)Force & (int)ConnectionInfo.Force.NoCredentials) != (int)ConnectionInfo.Force.NoCredentials && !string.IsNullOrEmpty(InterfaceControl.Info.Username) && !string.IsNullOrEmpty(InterfaceControl.Info.Password))
|
||||
{
|
||||
strAuth = "Authorization: Basic " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(InterfaceControl.Info.Username + ":" + InterfaceControl.Info.Password)) + Environment.NewLine;
|
||||
}
|
||||
*/
|
||||
if (InterfaceControl.Info.Port != defaultPort)
|
||||
{
|
||||
if (strHost.EndsWith("/"))
|
||||
@@ -161,6 +135,7 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
if (strHost.Contains(httpOrS + "://") == false)
|
||||
strHost = httpOrS + "://" + strHost;
|
||||
}
|
||||
|
||||
return strHost;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -174,26 +149,17 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
|
||||
#region Events
|
||||
|
||||
private void CefBrowser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e)
|
||||
private void Edge_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e)
|
||||
{
|
||||
browserInitialised = !e.IsLoading;
|
||||
if (browserInitialised)
|
||||
if (!e.IsSuccess)
|
||||
{
|
||||
// Unhook the loading state changes now, as navigation is done by the user on links in the control
|
||||
((ChromiumWebBrowser)wBrowser).LoadingStateChanged -= CefBrowser_LoadingStateChanged;
|
||||
|
||||
// If this Connection has already been asked to connect but the browser hadn't finished initalising
|
||||
// then the connect wouldn't have been allowed to take place, so now we can call it!
|
||||
if (connectCalled)
|
||||
{
|
||||
Connect();
|
||||
}
|
||||
Runtime.MessageCollector.AddExceptionStackTrace(Language.HttpFailedUrlBuild, e.InitializationException);
|
||||
}
|
||||
}
|
||||
|
||||
private void WBrowser_Navigated(object sender, WebBrowserNavigatedEventArgs e)
|
||||
{
|
||||
if (!(wBrowser is WebBrowser objWebBrowser)) return;
|
||||
if (!(_wBrowser is WebBrowser objWebBrowser)) return;
|
||||
|
||||
// This can only be set once the WebBrowser control is shown, it will throw a COM exception otherwise.
|
||||
objWebBrowser.AllowWebBrowserDrop = false;
|
||||
@@ -207,33 +173,18 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
{
|
||||
if (!(InterfaceControl.Parent is ConnectionTab tabP)) return;
|
||||
string shortTitle;
|
||||
|
||||
if (InterfaceControl.Info.RenderingEngine == RenderingEngine.CEF)
|
||||
if (((WebBrowser)_wBrowser).DocumentTitle.Length >= 15)
|
||||
{
|
||||
if (((TitleChangedEventArgs)e).Title.Length >= 15)
|
||||
{
|
||||
shortTitle = ((TitleChangedEventArgs)e).Title.Substring(0, 10) + "...";
|
||||
}
|
||||
else
|
||||
{
|
||||
shortTitle = ((CefSharp.TitleChangedEventArgs)e).Title;
|
||||
}
|
||||
shortTitle = ((WebBrowser)_wBrowser).DocumentTitle.Substring(0, 10) + "...";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((WebBrowser)wBrowser).DocumentTitle.Length >= 15)
|
||||
{
|
||||
shortTitle = ((WebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "...";
|
||||
}
|
||||
else
|
||||
{
|
||||
shortTitle = ((WebBrowser)wBrowser).DocumentTitle;
|
||||
}
|
||||
shortTitle = ((WebBrowser)_wBrowser).DocumentTitle;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tabTitle))
|
||||
if (!string.IsNullOrEmpty(_tabTitle))
|
||||
{
|
||||
tabP.TabText = tabTitle + @" - " + shortTitle;
|
||||
tabP.TabText = _tabTitle + @" - " + shortTitle;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -246,38 +197,6 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void geckoBrowser_DocumentTitleChanged(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(InterfaceControl.Parent is ConnectionTab tabP)) return;
|
||||
string shortTitle;
|
||||
|
||||
if (((WebBrowser)wBrowser).DocumentTitle.Length >= 15)
|
||||
{
|
||||
shortTitle = ((WebBrowser)wBrowser).DocumentTitle.Substring(0, 10) + "...";
|
||||
}
|
||||
else
|
||||
{
|
||||
shortTitle = ((WebBrowser)wBrowser).DocumentTitle;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(tabTitle))
|
||||
{
|
||||
tabP.TabText = tabTitle + @" - " + shortTitle;
|
||||
}
|
||||
else
|
||||
{
|
||||
tabP.TabText = shortTitle;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddExceptionStackTrace(Language.HttpDocumentTileChangeFailed, ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enums
|
||||
@@ -288,7 +207,7 @@ namespace mRemoteNG.Connection.Protocol.Http
|
||||
IE = 1,
|
||||
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.HttpCEF))]
|
||||
CEF = 2
|
||||
EdgeChromium = 2
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol
|
||||
@@ -64,7 +63,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
return false;
|
||||
}
|
||||
|
||||
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo);
|
||||
var argParser = new ExternalToolArgumentParser(_externalTool.ConnectionInfo, Runtime.CredentialService);
|
||||
_process = new Process
|
||||
{
|
||||
StartInfo =
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.PowerShell
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@ using mRemoteNG.Connection.Protocol.VNC;
|
||||
using System;
|
||||
using mRemoteNG.Connection.Protocol.PowerShell;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools.Cmdline;
|
||||
using mRemoteNG.UI;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Security;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
@@ -79,45 +78,20 @@ namespace mRemoteNG.Connection.Protocol
|
||||
|
||||
if (PuttyProtocol == Putty_Protocol.ssh)
|
||||
{
|
||||
var username = "";
|
||||
var password = "";
|
||||
|
||||
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Username))
|
||||
{
|
||||
username = InterfaceControl.Info.Username;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeCases
|
||||
switch (Settings.Default.EmptyCredentials)
|
||||
{
|
||||
case "windows":
|
||||
username = Environment.UserName;
|
||||
break;
|
||||
case "custom":
|
||||
username = Settings.Default.DefaultUsername;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(InterfaceControl.Info?.Password))
|
||||
{
|
||||
password = InterfaceControl.Info.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword,
|
||||
Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
arguments.Add("-" + (int)PuttySSHVersion);
|
||||
|
||||
|
||||
if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials))
|
||||
{
|
||||
var cred = Runtime.CredentialService.GetEffectiveCredentialRecord(InterfaceControl?.Info.CredentialRecordId
|
||||
.FirstOrDefault()).FirstOrDefault();
|
||||
|
||||
var username = cred.Username;
|
||||
var password = cred.Password.ConvertToUnsecureString();
|
||||
|
||||
if (!string.IsNullOrEmpty(username))
|
||||
{
|
||||
arguments.Add("-l", username);
|
||||
@@ -150,11 +124,11 @@ namespace mRemoteNG.Connection.Protocol
|
||||
PuttyProcess.Exited += ProcessExited;
|
||||
|
||||
PuttyProcess.Start();
|
||||
PuttyProcess.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
|
||||
PuttyProcess.WaitForInputIdle(Properties.Settings.Default.MaxPuttyWaitTime * 1000);
|
||||
|
||||
var startTicks = Environment.TickCount;
|
||||
while (PuttyHandle.ToInt32() == 0 &
|
||||
Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
|
||||
Environment.TickCount < startTicks + Properties.Settings.Default.MaxPuttyWaitTime * 1000)
|
||||
{
|
||||
if (_isPuttyNg)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -8,13 +8,13 @@ using AxMSTSCLib;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Properties;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Security.SymmetricEncryption;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.UI;
|
||||
using mRemoteNG.UI.Forms;
|
||||
using mRemoteNG.UI.Tabs;
|
||||
using MSTSCLib;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Security;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
@@ -379,9 +379,9 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes)
|
||||
{
|
||||
_rdpClient.TransportSettings2.GatewayUsername = connectionInfo.Username;
|
||||
_rdpClient.TransportSettings2.GatewayPassword = connectionInfo.Password;
|
||||
_rdpClient.TransportSettings2.GatewayDomain = connectionInfo?.Domain;
|
||||
_rdpClient.TransportSettings2.GatewayUsername = connectionInfo.CredentialRecord.Username;
|
||||
_rdpClient.TransportSettings2.GatewayPassword = connectionInfo.CredentialRecord.Password.ConvertToUnsecureString();
|
||||
_rdpClient.TransportSettings2.GatewayDomain = connectionInfo.CredentialRecord.Domain;
|
||||
}
|
||||
else if (connectionInfo.RDGatewayUseConnectionCredentials ==
|
||||
RDGatewayUseConnectionCredentials.SmartCard)
|
||||
@@ -457,58 +457,15 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
return;
|
||||
}
|
||||
|
||||
var userName = connectionInfo?.Username ?? "";
|
||||
var password = connectionInfo?.Password ?? "";
|
||||
var domain = connectionInfo?.Domain ?? "";
|
||||
var cred = Runtime.CredentialService.GetEffectiveCredentialRecord(connectionInfo.CredentialRecordId
|
||||
|
||||
.FirstOrDefault()).FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrEmpty(userName))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
_rdpClient.UserName = Environment.UserName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
_rdpClient.UserName = Settings.Default.DefaultUsername;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.UserName = userName;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
if (Settings.Default.DefaultPassword != "")
|
||||
{
|
||||
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
|
||||
_rdpClient.AdvancedSettings2.ClearTextPassword =
|
||||
cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.AdvancedSettings2.ClearTextPassword = password;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(domain))
|
||||
{
|
||||
if (Settings.Default.EmptyCredentials == "windows")
|
||||
{
|
||||
_rdpClient.Domain = Environment.UserDomainName;
|
||||
}
|
||||
else if (Settings.Default.EmptyCredentials == "custom")
|
||||
{
|
||||
_rdpClient.Domain = Settings.Default.DefaultDomain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_rdpClient.Domain = domain;
|
||||
}
|
||||
_rdpClient.UserName = cred.Username ?? "";
|
||||
|
||||
_rdpClient.AdvancedSettings2.ClearTextPassword = cred.Password?.ConvertToUnsecureString() ?? "";
|
||||
|
||||
_rdpClient.Domain = cred.Domain ?? "";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -817,4 +774,4 @@ namespace mRemoteNG.Connection.Protocol.RDP
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using mRemoteNG.App;
|
||||
using MSTSCLib;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Resources.Language;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Windows.Forms;
|
||||
using AxMSTSCLib;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using MSTSCLib;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.RDP
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user