This commit is contained in:
Louis Lam 2022-10-28 23:30:39 +08:00
parent 2c913e194a
commit 2d71097cd2
14 changed files with 1574 additions and 25 deletions

100
About.Designer.cs generated Normal file
View File

@ -0,0 +1,100 @@
using System.ComponentModel;
namespace RDP_Portal {
partial class About {
/// <summary>
/// Required designer variable.
/// </summary>
private 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(About));
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.labelName = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.buttonOK = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// linkLabel1
//
this.linkLabel1.Location = new System.Drawing.Point(12, 67);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(503, 23);
this.linkLabel1.TabIndex = 0;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "https://github.com/louislam/rdp-portal";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// labelName
//
this.labelName.Location = new System.Drawing.Point(12, 21);
this.labelName.Name = "labelName";
this.labelName.Size = new System.Drawing.Size(301, 23);
this.labelName.TabIndex = 1;
this.labelName.Text = "RDP Portal";
//
// label2
//
this.label2.Location = new System.Drawing.Point(12, 44);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(301, 23);
this.label2.TabIndex = 2;
this.label2.Text = "By Louis Lam";
//
// buttonOK
//
this.buttonOK.Location = new System.Drawing.Point(238, 110);
this.buttonOK.Name = "buttonOK";
this.buttonOK.Size = new System.Drawing.Size(75, 23);
this.buttonOK.TabIndex = 3;
this.buttonOK.Text = "OK";
this.buttonOK.UseVisualStyleBackColor = true;
this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
//
// About
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(325, 145);
this.Controls.Add(this.buttonOK);
this.Controls.Add(this.label2);
this.Controls.Add(this.labelName);
this.Controls.Add(this.linkLabel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "About";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "About";
this.Load += new System.EventHandler(this.About_Load);
this.ResumeLayout(false);
}
private System.Windows.Forms.LinkLabel linkLabel1;
private System.Windows.Forms.Label labelName;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button buttonOK;
#endregion
}
}

32
About.cs Normal file
View File

@ -0,0 +1,32 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace RDP_Portal {
public partial class About : Form {
public About() {
InitializeComponent();
}
private void About_Load(object sender, EventArgs e) {
Location = new Point(Owner.Location.X + Owner.Width / 2 - ClientSize.Width / 2,
Owner.Location.Y + Owner.Height / 2 - ClientSize.Height / 2);
// https://stackoverflow.com/questions/909555/how-can-i-get-the-assembly-file-version
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fvi.FileVersion;
labelName.Text = "RDP Portal v" + version;
}
private void buttonOK_Click(object sender, EventArgs e) {
this.Close();
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) {
System.Diagnostics.Process.Start(((LinkLabel)sender).Text);
}
}
}

1117
About.resx Normal file

File diff suppressed because it is too large Load Diff

3
FodyWeavers.xml Normal file
View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>

141
FodyWeavers.xsd Normal file
View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

25
MainForm.Designer.cs generated
View File

@ -26,7 +26,7 @@
private void InitializeComponent() {
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.checkBoxKeepOpening = new System.Windows.Forms.CheckBox();
this.button1 = new System.Windows.Forms.Button();
this.buttonAbout = new System.Windows.Forms.Button();
this.buttonConnect = new System.Windows.Forms.Button();
this.textBoxComputer = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
@ -62,16 +62,17 @@
this.checkBoxKeepOpening.UseVisualStyleBackColor = true;
this.checkBoxKeepOpening.CheckedChanged += new System.EventHandler(this.checkBoxKeepOpening_CheckedChanged);
//
// button1
// buttonAbout
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.button1.Location = new System.Drawing.Point(487, 432);
this.button1.Margin = new System.Windows.Forms.Padding(4);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(100, 28);
this.button1.TabIndex = 2;
this.button1.Text = "About";
this.button1.UseVisualStyleBackColor = true;
this.buttonAbout.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonAbout.Location = new System.Drawing.Point(487, 432);
this.buttonAbout.Margin = new System.Windows.Forms.Padding(4);
this.buttonAbout.Name = "buttonAbout";
this.buttonAbout.Size = new System.Drawing.Size(100, 28);
this.buttonAbout.TabIndex = 2;
this.buttonAbout.Text = "About";
this.buttonAbout.UseVisualStyleBackColor = true;
this.buttonAbout.Click += new System.EventHandler(this.buttonAbout_Click);
//
// buttonConnect
//
@ -296,7 +297,7 @@
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.buttonNew);
this.Controls.Add(this.buttonConnect);
this.Controls.Add(this.button1);
this.Controls.Add(this.buttonAbout);
this.Controls.Add(this.checkBoxKeepOpening);
this.Controls.Add(this.listBox);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
@ -346,7 +347,7 @@
private System.Windows.Forms.Button buttonConnect;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button buttonAbout;
private System.Windows.Forms.CheckBox checkBoxKeepOpening;

View File

@ -174,5 +174,10 @@ namespace RDP_Portal {
_config.KeepOpening = checkBoxKeepOpening.Checked;
_config.Save();
}
private void buttonAbout_Click(object sender, EventArgs e) {
About about = new About();
about.ShowDialog(this);
}
}
}

96
Mstscpw.cs Normal file
View File

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Security.Cryptography;
using System.Linq;
using System.Text;
namespace RDP_Portal {
/**
* By ChipForster
* https://www.remkoweijnen.nl/blog/2007/10/18/how-rdp-passwords-are-encrypted/
*/
class Mstscpw {
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
// Wrapper for the NULL handle or pointer.
static private IntPtr NullPtr = ((IntPtr)((int)(0)));
// Wrapper for DPAPI CryptProtectData function.
[DllImport( "crypt32.dll", SetLastError = true,
CharSet = System.Runtime.InteropServices.CharSet.Auto )]
private static extern bool CryptProtectData(
ref DATA_BLOB pPlainText,
[MarshalAs(UnmanagedType.LPWStr)] string szDescription,
IntPtr pEntroy,
IntPtr pReserved,
IntPtr pPrompt,
int dwFlags,
ref DATA_BLOB pCipherText);
// BLOB structure used to pass data to DPAPI functions.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DATA_BLOB {
public int cbData;
public IntPtr pbData;
}
private static void InitBLOB(byte[] data, ref DATA_BLOB blob) {
blob.pbData = Marshal.AllocHGlobal(data.Length);
if (blob.pbData == IntPtr.Zero)
throw new Exception( "Unable to allocate buffer for BLOB data." );
blob.cbData = data.Length;
Marshal.Copy(data, 0, blob.pbData, data.Length);
}
public string encryptpw(string pw) {
byte[] pwba = Encoding.Unicode.GetBytes(pw);
DATA_BLOB dataIn = new DATA_BLOB();
DATA_BLOB dataOut = new DATA_BLOB();
StringBuilder epwsb = new StringBuilder();
try {
try {
InitBLOB(pwba, ref dataIn);
} catch (Exception ex) {
throw new Exception( "Cannot initialize dataIn BLOB.", ex );
}
bool success = CryptProtectData(
ref dataIn,
"psw",
NullPtr,
NullPtr,
NullPtr,
CRYPTPROTECT_UI_FORBIDDEN,
ref dataOut );
if (!success) {
int errCode = Marshal.GetLastWin32Error();
throw new Exception( "CryptProtectData failed.", new Win32Exception(errCode) );
}
byte[] epwba = new byte[dataOut.cbData];
Marshal.Copy(dataOut.pbData, epwba, 0, dataOut.cbData);
// Convert hex data to hex characters (suitable for a string)
for (int i = 0; i < dataOut.cbData; i++) {
epwsb.Append(Convert.ToString(epwba[i], 16).PadLeft(2, '0').ToUpper());
}
} catch (Exception ex) {
throw new Exception( "unable to encrypt data.", ex );
} finally {
if (dataIn.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(dataIn.pbData);
if (dataOut.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(dataOut.pbData);
}
return epwsb.ToString();
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using Newtonsoft.Json;
@ -21,6 +22,17 @@ namespace RDP_Portal {
public string Computer { get; set; }
public string Username { get; set; }
/**
* Encrypted Password used by mstsc.exe
*/
public string GetRDPEncryptedPassword() {
var mstscpw = new Mstscpw();
return mstscpw.encryptpw(this.Password);
}
/**
* Encrypted Password in config.json
*/
public string EncryptedPassword { get; set; } = "";
[JsonIgnore]
@ -59,28 +71,56 @@ namespace RDP_Portal {
justCreated = true;
}
var writer = File.AppendText(Filename);
var lines = File.ReadAllLines(Filename);
var removeList = new [] {
"full address:",
"username:",
"password",
"domain:",
};
var result = new List<string>();
foreach (var line in lines) {
var ok = true;
foreach (var startKeyword in removeList) {
if (line.StartsWith(startKeyword)) {
ok = false;
break;
}
}
if (ok) {
result.Add(line);
}
}
if (Computer != "") {
writer.WriteLine("full address:s:" + Computer);
result.Add("full address:s:" + Computer);
}
if (Username != "") {
writer.WriteLine("username:s:" + Username);
result.Add("username:s:" + Username);
}
if (Password != "") {
// TODO
writer.WriteLine("password 51:b:" + Password);
result.Add("password 51:b:" + GetRDPEncryptedPassword());
}
if (Domain != "") {
writer.WriteLine("domain:s:" + Domain);
result.Add("domain:s:" + Domain);
}
if (justCreated) {
writer.WriteLine("authentication level:i:0");
writer.WriteLine("prompt for credentials:i:0");
result.Add("authentication level:i:0");
result.Add("prompt for credentials:i:0");
}
var writer = new StreamWriter(Filename, false);
foreach (var line in result) {
writer.WriteLine(line);
}
writer.Close();

View File

@ -5,12 +5,12 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("rdp_portal")]
[assembly: AssemblyTitle("RDP Portal")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("rdp_portal")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyCompany("Louis Lam")]
[assembly: AssemblyProduct("RDP Protal")]
[assembly: AssemblyCopyright("Copyright © 2022 Louis Lam")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -33,4 +33,4 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

BIN
extra/banner.ufo Normal file

Binary file not shown.

BIN
extra/icon.ufo Normal file

Binary file not shown.

View File

@ -140,6 +140,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="About.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="About.Designer.cs">
<DependentUpon>About.cs</DependentUpon>
</Compile>
<Compile Include="Config.cs" />
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
@ -147,11 +153,15 @@
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Mstscpw.cs" />
<Compile Include="Profile.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RdpFile.cs" />
<Compile Include="StringUtil.cs" />
<EmbeddedResource Include="About.resx">
<DependentUpon>About.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -0,0 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=rdp_002Dportal_002FMainForm/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=rdp_002Dportal_002FProperties_002FResources/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/ResxEditorPersonal/Initialized/@EntryValue">True</s:Boolean></wpf:ResourceDictionary>