Compare commits

..

5 Commits

Author SHA1 Message Date
Dimitrij
15149f9e2c Merge pull request #2133 from david-sway/v1.77.2-dev
Made changes to prevent two settings-scenarios that brick the app.
2022-01-18 16:14:43 +00:00
david-sway
ab3d85b089 Made changes to prevent two settings-scenarios that brick the app. 2022-01-18 11:00:58 -05:00
Dimitrij
2f3a03eab7 manual merge from Filippo125:add_winbox - Improve log 2022-01-18 12:19:49 +00:00
Dimitrij
629515b81a manual merge from Filippo125:add_winbox - Integrate winbox client mRemoteNG#895 2022-01-18 11:39:08 +00:00
Dimitrij
05c8da3ee4 manual merge from Filippo125:add_winbox - save only 2022-01-18 11:31:23 +00:00
634 changed files with 16471 additions and 38723 deletions

View File

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

6
.gitignore vendored
View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
namespace ExternalConnectors.DSS
namespace ExternalConnectors.TSS
{
public partial class SSConnectionForm : Form
{
@@ -13,12 +13,7 @@
if (cbUseSSO.Checked)
btnOK.Focus();
else
{
if (tbPassword.Text.Length == 0)
tbPassword.Focus();
else
tbOTP.Focus();
}
tbPassword.Focus();
}
private void cbUseSSO_CheckedChanged(object sender, EventArgs e)

View File

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

View File

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

View File

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

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -20,8 +20,8 @@
<a href="https://twitter.com/mremoteng">
<img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/mremoteng?color=%231DA1F2&label=Twitter&logo=Twitter&style=flat-square">
</a>
<a href="https://app.element.io/#/room/#mremoteng:matrix.org">
<img alt="Element" src="https://img.shields.io/matrix/mremoteng:matrix.org?label=Join%20to%20chat%20about%20mRemoteNG&logo=element&style=social&link=https://app.element.io/#/room/#mremoteng:matrix.org">
<a href="https://gitter.im/mRemoteNG/PublicChat">
<img alt="Gitter" src="https://img.shields.io/gitter/room/mRemoteNG/PublicChat?label=Join%20the%20Chat&logo=Gitter&style=flat-square">
</a>
</p>
<p align="center">
@@ -43,9 +43,6 @@
<a href='https://mremoteng.readthedocs.io/en/latest/?badge=latest'>
<img src='https://readthedocs.org/projects/mremoteng/badge/?version=latest' alt='Documentation Status' />
</a>
<a href="https://gurubase.io/g/mremoteng">
<img alt="Gurubase" src="https://img.shields.io/badge/Gurubase-Ask%20mRemoteNG%20Guru-006BFF?style=flat-square">
</a>
</p>
---
@@ -54,7 +51,7 @@
| ---------------|--------------|-----------|
| Stable | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.76.20/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76.20) |
| Preview | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf/branch/preview?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.77.1/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.77.1) |
| Nightly | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf/branch/develop?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/2023.03.03-v1.77.3-nb/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/2023.03.03-v1.77.3-nb) |
| Nightly | ![Build status](https://ci.appveyor.com/api/projects/status/rqwxjxldail7btcf/branch/develop?svg=true) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/2022.01.07-1.77.2-nb/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/2022.01.07-1.77.2-nb) |
## Features
@@ -91,14 +88,12 @@ You will need to compile it yourself using Visual Studio.
### Minimum Requirements
* [Microsoft Visual C++ Redistributable for Visual Studio 2015 - 2022](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads)
* [Microsoft .NET 6.0 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/6.0)
* [Microsoft .NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0)
* Microsoft Terminal Service Client 6.0 or later
* Needed if you use RDP. mstscax.dll and/or msrdp.ocx be registered.
### Download
> :star: Starting Windows 11 you can use winget to install mRemoteNG. Just run `winget install -e --id mRemoteNG.mRemoteNG`
mRemoteNG is available as a redistributable MSI package or as a portable ZIP package and can be downloaded from the following locations:
* [GitHub](https://github.com/mRemoteNG/mRemoteNG/releases)
* [Project Website](https://mremoteng.org/download)

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,23 +1,24 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Versioning;
using System.Windows.Forms;
using mRemoteNG.Connection;
namespace mRemoteNG.App.Info
{
[SupportedOSPlatform("windows")]
public static class SettingsFileInfo
{
private static readonly string ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
private static readonly string ExePath =
Path.GetDirectoryName(Assembly.GetAssembly(typeof(ConnectionInfo))?.Location);
public static string SettingsPath => Runtime.IsPortableEdition ? ExePath : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
public static string SettingsPath =>
Runtime.IsPortableEdition
? ExePath
: Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Application.ProductName;
public static string LayoutFileName { get; } = "pnlLayout.xml";
public static string ExtAppsFilesName { get; } = "extApps.xml";
public static string ThemesFileName { get; } = "Themes.xml";
public static string LocalConnectionProperties { get; } = "LocalConnectionProperties.xml";
public static string ThemeFolder { get; } =
SettingsPath != null ? Path.Combine(SettingsPath, "Themes") : String.Empty;

View File

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

View File

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

View File

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

View File

@@ -1,19 +1,19 @@
using System.IO;
using System.Runtime.Versioning;
using mRemoteNG.Config.Connections;
using mRemoteNG.Properties;
namespace mRemoteNG.App.Initialization
{
[SupportedOSPlatform("windows")]
public class CredsAndConsSetup
{
public void LoadCredsAndCons()
{
new SaveConnectionsOnEdit(Runtime.ConnectionsService);
if (Properties.App.Default.FirstStart && !Properties.OptionsBackupPage.Default.LoadConsFromCustomLocation && !File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService.GetStartupConnectionFileName());
if (Settings.Default.FirstStart && !Settings.Default.LoadConsFromCustomLocation &&
!File.Exists(Runtime.ConnectionsService.GetStartupConnectionFileName()))
Runtime.ConnectionsService.NewConnectionsFile(Runtime.ConnectionsService
.GetStartupConnectionFileName());
Runtime.LoadConnections();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,11 +17,9 @@ using System.Threading;
using System.Windows.Forms;
using mRemoteNG.Properties;
using mRemoteNG.Resources.Language;
using System.Runtime.Versioning;
namespace mRemoteNG.App
{
[SupportedOSPlatform("windows")]
public static class Runtime
{
public static bool IsPortableEdition
@@ -46,19 +44,21 @@ namespace mRemoteNG.App
public static NotificationAreaIcon NotificationAreaIcon { get; set; }
public static ExternalToolsService ExternalToolsService { get; } = new ExternalToolsService();
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static SecureString EncryptionKey { get; set; } =
new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ICredentialRepositoryList CredentialProviderCatalog { get; } = new CredentialRepositoryList();
public static ConnectionInitiator ConnectionInitiator { get; set; } = new ConnectionInitiator();
public static ConnectionsService ConnectionsService { get; } = new ConnectionsService(PuttySessionsManager.Instance);
public static ConnectionsService ConnectionsService { get; } =
new ConnectionsService(PuttySessionsManager.Instance);
#region Connections Loading/Saving
public static void LoadConnectionsAsync()
{
Thread t = new(LoadConnectionsBGd);
var t = new Thread(LoadConnectionsBGd);
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
@@ -77,7 +77,7 @@ namespace mRemoteNG.App
/// </param>
public static void LoadConnections(bool withDialog = false)
{
string connectionFileName = "";
var connectionFileName = "";
try
{
@@ -86,24 +86,24 @@ namespace mRemoteNG.App
if (withDialog)
{
OpenFileDialog loadDialog = DialogFactory.BuildLoadConnectionsDialog();
var loadDialog = DialogFactory.BuildLoadConnectionsDialog();
if (loadDialog.ShowDialog() != DialogResult.OK)
return;
connectionFileName = loadDialog.FileName;
Properties.OptionsDBsPage.Default.UseSQLServer = false;
Properties.OptionsDBsPage.Default.Save();
Settings.Default.UseSQLServer = false;
Settings.Default.Save();
}
else if (!Properties.OptionsDBsPage.Default.UseSQLServer)
else if (!Settings.Default.UseSQLServer)
{
connectionFileName = ConnectionsService.GetStartupConnectionFileName();
}
ConnectionsService.LoadConnections(Properties.OptionsDBsPage.Default.UseSQLServer, false, connectionFileName);
ConnectionsService.LoadConnections(Settings.Default.UseSQLServer, false, connectionFileName);
if (Properties.OptionsDBsPage.Default.UseSQLServer)
if (Settings.Default.UseSQLServer)
{
ConnectionsService.LastSqlUpdate = DateTime.Now.ToUniversalTime();
ConnectionsService.LastSqlUpdate = DateTime.Now;
}
else
{
@@ -115,20 +115,26 @@ namespace mRemoteNG.App
}
catch (Exception ex)
{
FrmSplashScreenNew.GetInstance().Close();
FrmSplashScreen.getInstance().Close();
if (Properties.OptionsDBsPage.Default.UseSQLServer)
if (Settings.Default.UseSQLServer)
{
MessageCollector.AddExceptionMessage(Language.LoadFromSqlFailed, ex);
string commandButtons = string.Join("|", Language._TryAgain, Language.CommandOpenConnectionFile, string.Format(Language.CommandExitProgram, Application.ProductName));
CTaskDialog.ShowCommandBox(Application.ProductName, Language.LoadFromSqlFailed, Language.LoadFromSqlFailedContent, MiscTools.GetExceptionMessageRecursive(ex), "", "", commandButtons, false, ESysIcons.Error, ESysIcons.Error);
var commandButtons = string.Join("|", Language._TryAgain,
Language.CommandOpenConnectionFile,
string.Format(Language.CommandExitProgram,
Application.ProductName));
CTaskDialog.ShowCommandBox(Application.ProductName, Language.LoadFromSqlFailed,
Language.LoadFromSqlFailedContent,
MiscTools.GetExceptionMessageRecursive(ex), "", "",
commandButtons, false, ESysIcons.Error, ESysIcons.Error);
switch (CTaskDialog.CommandButtonResult)
{
case 0:
LoadConnections(withDialog);
return;
case 1:
Properties.OptionsDBsPage.Default.UseSQLServer = false;
Settings.Default.UseSQLServer = false;
LoadConnections(true);
return;
default:
@@ -152,12 +158,19 @@ namespace mRemoteNG.App
Language.Exit
};
bool answered = false;
var answered = false;
while (!answered)
{
try
{
CTaskDialog.ShowTaskDialogBox(GeneralAppInfo.ProductName, Language.ConnectionFileNotFound, "", "", "", "", "", string.Join(" | ", commandButtons), ETaskDialogButtons.None, ESysIcons.Question, ESysIcons.Question);
CTaskDialog.ShowTaskDialogBox(
GeneralAppInfo.ProductName,
Language.ConnectionFileNotFound,
"", "", "", "", "",
string.Join(" | ", commandButtons),
ETaskDialogButtons.None,
ESysIcons.Question,
ESysIcons.Question);
switch (CTaskDialog.CommandButtonResult)
{
@@ -182,7 +195,11 @@ namespace mRemoteNG.App
}
catch (Exception exc)
{
MessageCollector.AddExceptionMessage(string.Format(Language.ConnectionsFileCouldNotBeLoadedNew, connectionFileName), exc, MessageClass.InformationMsg);
MessageCollector.AddExceptionMessage(
string
.Format(Language.ConnectionsFileCouldNotBeLoadedNew,
connectionFileName), exc,
MessageClass.InformationMsg);
}
}
@@ -198,7 +215,12 @@ namespace mRemoteNG.App
}
else
{
MessageBox.Show(FrmMain.Default, string.Format(Language.ErrorStartupConnectionFileLoad, Environment.NewLine, Application.ProductName, ConnectionsService.GetStartupConnectionFileName(), MiscTools.GetExceptionMessageRecursive(ex)), @"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBox.Show(FrmMain.Default,
string.Format(Language.ErrorStartupConnectionFileLoad, Environment.NewLine,
Application.ProductName,
ConnectionsService.GetStartupConnectionFileName(),
MiscTools.GetExceptionMessageRecursive(ex)),
@"Could not load startup file.", MessageBoxButtons.OK, MessageBoxIcon.Error);
Application.Exit();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +0,0 @@
namespace mRemoteNG.Config.ACL
{
public enum ACLPermissions
{
Hidden = 0,
ReadOnly = 1,
WriteAllow = 2
}
}

View File

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

View File

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

View File

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

View File

@@ -4,11 +4,9 @@ using System.ComponentModel;
using mRemoteNG.Connection;
using mRemoteNG.UI.Forms;
using mRemoteNG.Properties;
using System.Runtime.Versioning;
namespace mRemoteNG.Config.Connections
{
[SupportedOSPlatform("windows")]
public class SaveConnectionsOnEdit
{
private readonly ConnectionsService _connectionsService;
@@ -22,24 +20,29 @@ namespace mRemoteNG.Config.Connections
connectionsService.ConnectionsLoaded += ConnectionsServiceOnConnectionsLoaded;
}
private void ConnectionsServiceOnConnectionsLoaded(object sender, ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
private void ConnectionsServiceOnConnectionsLoaded(object sender,
ConnectionsLoadedEventArgs connectionsLoadedEventArgs)
{
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged += ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.CollectionChanged +=
ConnectionTreeModelOnCollectionChanged;
connectionsLoadedEventArgs.NewConnectionTreeModel.PropertyChanged += ConnectionTreeModelOnPropertyChanged;
foreach (Tree.ConnectionTreeModel oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
foreach (var oldTree in connectionsLoadedEventArgs.PreviousConnectionTreeModel)
{
oldTree.CollectionChanged -= ConnectionTreeModelOnCollectionChanged;
oldTree.PropertyChanged -= ConnectionTreeModelOnPropertyChanged;
}
}
private void ConnectionTreeModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
private void ConnectionTreeModelOnPropertyChanged(object sender,
PropertyChangedEventArgs propertyChangedEventArgs)
{
SaveConnectionOnEdit(propertyChangedEventArgs.PropertyName);
}
private void ConnectionTreeModelOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
private void ConnectionTreeModelOnCollectionChanged(object sender,
NotifyCollectionChangedEventArgs
notifyCollectionChangedEventArgs)
{
SaveConnectionOnEdit();
}
@@ -47,7 +50,7 @@ namespace mRemoteNG.Config.Connections
private void SaveConnectionOnEdit(string propertyName = "")
{
//OBSOLETE: mRemoteNG.Settings.Default.SaveConnectionsAfterEveryEdit is obsolete and should be removed in a future release
if (Properties.OptionsBackupPage.Default.SaveConnectionsAfterEveryEdit || (Properties.OptionsBackupPage.Default.SaveConnectionsFrequency == (int)ConnectionsBackupFrequencyEnum.OnEdit))
if (mRemoteNG.Properties.Settings.Default.SaveConnectionsAfterEveryEdit || (mRemoteNG.Properties.Settings.Default.SaveConnectionsFrequency == (int)ConnectionsBackupFrequencyEnum.OnEdit))
{
if (FrmMain.Default.IsClosing)
return;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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