mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-26 14:37:44 +01:00
Merge pull request #420 from Cyberboss/MultiLoginCP
Control Panel can now save multiple logins
This commit is contained in:
@@ -52,7 +52,7 @@ namespace TGS.CommandLine
|
||||
}
|
||||
argsAsList.RemoveAt(I);
|
||||
argsAsList.RemoveAt(I);
|
||||
ReplaceInterface(new ServerInterface(address, port, username, password));
|
||||
ReplaceInterface(new ServerInterface(new RemoteLoginInfo(address, port, username, password)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace TGS.CommandLine
|
||||
var username = Console.ReadLine();
|
||||
Console.Write("Enter password: ");
|
||||
var password = ReadLineSecure();
|
||||
ReplaceInterface(new ServerInterface(address, port, username, password));
|
||||
ReplaceInterface(new ServerInterface(new RemoteLoginInfo(address, port, username, password)));
|
||||
var res = currentInterface.ConnectionStatus(out string error);
|
||||
if (!res.HasFlag(ConnectivityLevel.Connected))
|
||||
{
|
||||
|
||||
@@ -26,24 +26,9 @@
|
||||
<setting name="LastChatProvider" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="RemoteIP" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="RemoteUsername" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="RemotePort" serializeAs="String">
|
||||
<value>38607</value>
|
||||
</setting>
|
||||
<setting name="RemoteDefault" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="RemotePassword" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="RemoteEntropy" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="GitHubAPIKey" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace TGS.ControlPanel
|
||||
FormClosed += ControlPanel_FormClosed;
|
||||
Interface = I;
|
||||
if (Interface.IsRemoteConnection)
|
||||
Text = String.Format("TGS {0}: {1}:{2}", Interface.ServerVersion, Interface.HTTPSURL, Interface.HTTPSPort);
|
||||
Text = String.Format("TGS {0}: {1}:{2}", Interface.ServerVersion, Interface.LoginInfo.IP, Interface.LoginInfo.Port);
|
||||
Text = String.Format("{0} Instance: {1}", Text, I.InstanceName);
|
||||
Panels.SelectedIndexChanged += Panels_SelectedIndexChanged;
|
||||
Panels.SelectedIndex += Math.Min(Properties.Settings.Default.LastPageIndex, Panels.TabCount - 1);
|
||||
|
||||
@@ -6,10 +6,9 @@ namespace TGS.ControlPanel
|
||||
/// Calls <see cref="Application.Exit()"/> when all <see cref="CountedForm"/>s are <see cref="Form.Close"/>d
|
||||
/// </summary>
|
||||
#if !DEBUG
|
||||
abstract class CountedForm : ServerOpForm
|
||||
#else
|
||||
class CountedForm : ServerOpForm
|
||||
abstract
|
||||
#endif
|
||||
class CountedForm : ServerOpForm
|
||||
{
|
||||
/// <summary>
|
||||
/// The current number of active <see cref="CountedForm"/>s
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace TGS.ControlPanel
|
||||
activeCP.BringToFront();
|
||||
return;
|
||||
}
|
||||
var InstanceAccessor = new ServerInterface(masterInterface as ServerInterface);
|
||||
var InstanceAccessor = new ServerInterface(masterInterface.LoginInfo);
|
||||
try
|
||||
{
|
||||
ConnectivityLevel res = ConnectivityLevel.None;
|
||||
|
||||
Generated
+40
-25
@@ -31,16 +31,17 @@
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Login));
|
||||
this.LocalLoginButton = new System.Windows.Forms.Button();
|
||||
this.CurrentRevisionTitle = new System.Windows.Forms.Label();
|
||||
this.IPTextBox = new System.Windows.Forms.TextBox();
|
||||
this.UsernameTextBox = new System.Windows.Forms.TextBox();
|
||||
this.PasswordTextBox = new System.Windows.Forms.TextBox();
|
||||
this.RemoteLoginButton = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.AddressLabel = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.PortSelector = new System.Windows.Forms.NumericUpDown();
|
||||
this.SavePasswordCheckBox = new System.Windows.Forms.CheckBox();
|
||||
this.IPComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.DeleteLoginButton = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)(this.PortSelector)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
@@ -50,7 +51,7 @@
|
||||
this.LocalLoginButton.Location = new System.Drawing.Point(102, 12);
|
||||
this.LocalLoginButton.Name = "LocalLoginButton";
|
||||
this.LocalLoginButton.Size = new System.Drawing.Size(157, 25);
|
||||
this.LocalLoginButton.TabIndex = 13;
|
||||
this.LocalLoginButton.TabIndex = 1;
|
||||
this.LocalLoginButton.Text = "Connect to Local Service";
|
||||
this.LocalLoginButton.UseVisualStyleBackColor = true;
|
||||
this.LocalLoginButton.Click += new System.EventHandler(this.LocalLoginButton_Click);
|
||||
@@ -67,13 +68,6 @@
|
||||
this.CurrentRevisionTitle.Text = "Remote Login:";
|
||||
this.CurrentRevisionTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// IPTextBox
|
||||
//
|
||||
this.IPTextBox.Location = new System.Drawing.Point(129, 99);
|
||||
this.IPTextBox.Name = "IPTextBox";
|
||||
this.IPTextBox.Size = new System.Drawing.Size(146, 20);
|
||||
this.IPTextBox.TabIndex = 15;
|
||||
//
|
||||
// UsernameTextBox
|
||||
//
|
||||
this.UsernameTextBox.Location = new System.Drawing.Point(129, 132);
|
||||
@@ -100,17 +94,17 @@
|
||||
this.RemoteLoginButton.UseVisualStyleBackColor = true;
|
||||
this.RemoteLoginButton.Click += new System.EventHandler(this.RemoteLoginButton_Click);
|
||||
//
|
||||
// label1
|
||||
// AddressLabel
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label1.Location = new System.Drawing.Point(9, 99);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(120, 18);
|
||||
this.label1.TabIndex = 19;
|
||||
this.label1.Text = "Address/Port:";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
this.AddressLabel.AutoSize = true;
|
||||
this.AddressLabel.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.AddressLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.AddressLabel.Location = new System.Drawing.Point(9, 99);
|
||||
this.AddressLabel.Name = "AddressLabel";
|
||||
this.AddressLabel.Size = new System.Drawing.Size(80, 18);
|
||||
this.AddressLabel.TabIndex = 19;
|
||||
this.AddressLabel.Text = "Address:";
|
||||
this.AddressLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
@@ -165,7 +159,7 @@
|
||||
this.PortSelector.Size = new System.Drawing.Size(80, 20);
|
||||
this.PortSelector.TabIndex = 16;
|
||||
this.PortSelector.Value = new decimal(new int[] {
|
||||
1,
|
||||
38607,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
@@ -182,22 +176,42 @@
|
||||
this.SavePasswordCheckBox.UseVisualStyleBackColor = true;
|
||||
this.SavePasswordCheckBox.CheckedChanged += new System.EventHandler(this.SavePasswordCheckBox_CheckedChanged);
|
||||
//
|
||||
// IPComboBox
|
||||
//
|
||||
this.IPComboBox.FormattingEnabled = true;
|
||||
this.IPComboBox.Location = new System.Drawing.Point(130, 98);
|
||||
this.IPComboBox.Name = "IPComboBox";
|
||||
this.IPComboBox.Size = new System.Drawing.Size(146, 21);
|
||||
this.IPComboBox.TabIndex = 24;
|
||||
//
|
||||
// DeleteLoginButton
|
||||
//
|
||||
this.DeleteLoginButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.DeleteLoginButton.Location = new System.Drawing.Point(105, 98);
|
||||
this.DeleteLoginButton.Name = "DeleteLoginButton";
|
||||
this.DeleteLoginButton.Size = new System.Drawing.Size(19, 19);
|
||||
this.DeleteLoginButton.TabIndex = 25;
|
||||
this.DeleteLoginButton.Text = "x";
|
||||
this.DeleteLoginButton.UseVisualStyleBackColor = true;
|
||||
this.DeleteLoginButton.Click += new System.EventHandler(this.DeleteLoginButton_Click);
|
||||
//
|
||||
// Login
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34)))));
|
||||
this.ClientSize = new System.Drawing.Size(374, 237);
|
||||
this.Controls.Add(this.DeleteLoginButton);
|
||||
this.Controls.Add(this.IPComboBox);
|
||||
this.Controls.Add(this.SavePasswordCheckBox);
|
||||
this.Controls.Add(this.PortSelector);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.label3);
|
||||
this.Controls.Add(this.label2);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.AddressLabel);
|
||||
this.Controls.Add(this.RemoteLoginButton);
|
||||
this.Controls.Add(this.PasswordTextBox);
|
||||
this.Controls.Add(this.UsernameTextBox);
|
||||
this.Controls.Add(this.IPTextBox);
|
||||
this.Controls.Add(this.CurrentRevisionTitle);
|
||||
this.Controls.Add(this.LocalLoginButton);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
@@ -216,15 +230,16 @@
|
||||
|
||||
private System.Windows.Forms.Button LocalLoginButton;
|
||||
private System.Windows.Forms.Label CurrentRevisionTitle;
|
||||
private System.Windows.Forms.TextBox IPTextBox;
|
||||
private System.Windows.Forms.TextBox UsernameTextBox;
|
||||
private System.Windows.Forms.TextBox PasswordTextBox;
|
||||
private System.Windows.Forms.Button RemoteLoginButton;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label AddressLabel;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.NumericUpDown PortSelector;
|
||||
private System.Windows.Forms.CheckBox SavePasswordCheckBox;
|
||||
private System.Windows.Forms.ComboBox IPComboBox;
|
||||
private System.Windows.Forms.Button DeleteLoginButton;
|
||||
}
|
||||
}
|
||||
+114
-35
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows.Forms;
|
||||
using TGS.Interface;
|
||||
|
||||
@@ -7,58 +8,123 @@ namespace TGS.ControlPanel
|
||||
sealed partial class Login : CountedForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="Login"/> form
|
||||
/// Currently selected saved <see cref="RemoteLoginInfo"/>
|
||||
/// </summary>
|
||||
RemoteLoginInfo currentLoginInfo;
|
||||
|
||||
bool updatingFields;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="Login"/>
|
||||
/// </summary>
|
||||
public Login()
|
||||
{
|
||||
InitializeComponent();
|
||||
var Config = Properties.Settings.Default;
|
||||
IPTextBox.Text = Config.RemoteIP;
|
||||
UsernameTextBox.Text = Config.RemoteUsername;
|
||||
PortSelector.Value = Config.RemotePort;
|
||||
AcceptButton = RemoteLoginButton;
|
||||
if(Config.RemoteDefault)
|
||||
RemoteLoginButton.TabIndex = 0; //make this the first thing selected when loading
|
||||
var decrypted = Helpers.DecryptData(Config.RemotePassword, Config.RemoteEntropy);
|
||||
if (decrypted != null)
|
||||
|
||||
IPComboBox.SelectedIndexChanged += IPComboBox_SelectedIndexChanged;
|
||||
var loginInfo = Config.RemoteLoginInfo;
|
||||
if (loginInfo != null)
|
||||
{
|
||||
PasswordTextBox.Text = decrypted;
|
||||
SavePasswordCheckBox.Checked = true;
|
||||
foreach(var I in loginInfo)
|
||||
IPComboBox.Items.Add(new RemoteLoginInfo(I));
|
||||
if (IPComboBox.Items.Count > 0)
|
||||
IPComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
UsernameTextBox.TextChanged += (a, b) => ClearFields();
|
||||
PortSelector.ValueChanged += (a, b) => ClearFields();
|
||||
PasswordTextBox.TextChanged += (a, b) => ClearFields();
|
||||
IPComboBox.TextChanged += (a, b) => ClearFields();
|
||||
}
|
||||
|
||||
private void RemoteLoginButton_Click(object sender, EventArgs e)
|
||||
void ClearFields()
|
||||
{
|
||||
IPTextBox.Text = IPTextBox.Text.Trim();
|
||||
UsernameTextBox.Text = UsernameTextBox.Text.Trim();
|
||||
using (var I = new ServerInterface(IPTextBox.Text, (ushort)PortSelector.Value, UsernameTextBox.Text, PasswordTextBox.Text))
|
||||
if (updatingFields || currentLoginInfo == null)
|
||||
return;
|
||||
updatingFields = true;
|
||||
currentLoginInfo = null;
|
||||
IPComboBox.Text = "";
|
||||
PortSelector.Value = 38607;
|
||||
UsernameTextBox.Text = "";
|
||||
PasswordTextBox.Text = "";
|
||||
updatingFields = false;
|
||||
}
|
||||
|
||||
void IPComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
currentLoginInfo = IPComboBox.SelectedItem as RemoteLoginInfo;
|
||||
//new thing
|
||||
if (currentLoginInfo == null)
|
||||
{
|
||||
ClearFields();
|
||||
return;
|
||||
}
|
||||
updatingFields = true;
|
||||
IPComboBox.Text = currentLoginInfo.IP;
|
||||
PortSelector.Value = currentLoginInfo.Port;
|
||||
UsernameTextBox.Text = currentLoginInfo.Username;
|
||||
SavePasswordCheckBox.Checked = currentLoginInfo.HasPassword;
|
||||
if (currentLoginInfo.HasPassword)
|
||||
PasswordTextBox.Text = "************";
|
||||
else
|
||||
PasswordTextBox.Text = "";
|
||||
updatingFields = false;
|
||||
}
|
||||
|
||||
void RemoteLoginButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(PasswordTextBox.Text) || String.IsNullOrWhiteSpace(UsernameTextBox.Text) || String.IsNullOrWhiteSpace(IPComboBox.Text) || PortSelector.Value == 0)
|
||||
return;
|
||||
|
||||
RemoteLoginInfo loginInfo;
|
||||
if (currentLoginInfo == null)
|
||||
{
|
||||
loginInfo = new RemoteLoginInfo(IPComboBox.Text, (ushort)PortSelector.Value, UsernameTextBox.Text.Trim(), PasswordTextBox.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
loginInfo = (RemoteLoginInfo)IPComboBox.SelectedItem;
|
||||
if (!loginInfo.HasPassword)
|
||||
loginInfo.Password = PasswordTextBox.Text;
|
||||
}
|
||||
|
||||
using (var I = new ServerInterface(loginInfo))
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
Config.RemoteIP = IPTextBox.Text;
|
||||
Config.RemotePort = (ushort)PortSelector.Value;
|
||||
Config.RemoteUsername = UsernameTextBox.Text;
|
||||
if (SavePasswordCheckBox.Checked)
|
||||
//This needs to be read here because V&C Closing us will corrupt the data
|
||||
var savePassword = SavePasswordCheckBox.Checked;
|
||||
if (VerifyAndConnect(I))
|
||||
{
|
||||
Config.RemotePassword = Helpers.EncryptData(PasswordTextBox.Text, out string entrop);
|
||||
Config.RemoteEntropy = entrop;
|
||||
Config.RemoteDefault = true;
|
||||
|
||||
if (!savePassword)
|
||||
loginInfo.Password = null;
|
||||
|
||||
Config.RemoteLoginInfo = new StringCollection { loginInfo.ToJSON() };
|
||||
|
||||
foreach (RemoteLoginInfo info in IPComboBox.Items)
|
||||
if (!info.Equals(loginInfo))
|
||||
Config.RemoteLoginInfo.Add(info.ToJSON());
|
||||
}
|
||||
else
|
||||
{
|
||||
Config.RemotePassword = null;
|
||||
Config.RemoteEntropy = null;
|
||||
}
|
||||
Config.RemoteDefault = true;
|
||||
VerifyAndConnect(I);
|
||||
}
|
||||
}
|
||||
|
||||
private void LocalLoginButton_Click(object sender, EventArgs e)
|
||||
void LocalLoginButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Properties.Settings.Default.RemoteDefault = false;
|
||||
VerifyAndConnect(new ServerInterface());
|
||||
}
|
||||
|
||||
void VerifyAndConnect(IServerInterface I)
|
||||
/// <summary>
|
||||
/// Attempts a connection on a given <see cref="IServerInterface"/>
|
||||
/// </summary>
|
||||
/// <param name="I">The <see cref="IServerInterface"/> to attempt a connection on</param>
|
||||
/// <returns><see langword="true"/> if the connection was made and authenticated, <see langword="false"/> otherwise</returns>
|
||||
bool VerifyAndConnect(IServerInterface I)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -66,19 +132,20 @@ namespace TGS.ControlPanel
|
||||
if (!res.HasFlag(ConnectivityLevel.Connected))
|
||||
{
|
||||
MessageBox.Show("Unable to connect to service! Error: " + error);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!res.HasFlag(ConnectivityLevel.Authenticated))
|
||||
{
|
||||
MessageBox.Show("Authentication error: Username/password/windows identity is not authorized! Ensure you are a system administrator or in the correct Windows group on the service machine.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (I.VersionMismatch(out error) && MessageBox.Show(error, "Warning", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
|
||||
return;
|
||||
return true;
|
||||
|
||||
new InstanceSelector(I).Show();
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -87,14 +154,26 @@ namespace TGS.ControlPanel
|
||||
}
|
||||
}
|
||||
|
||||
private void SavePasswordCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
void SavePasswordCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!SavePasswordCheckBox.Checked)
|
||||
if (!updatingFields && !SavePasswordCheckBox.Checked && currentLoginInfo != null)
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
Config.RemotePassword = null;
|
||||
Config.RemoteEntropy = null;
|
||||
currentLoginInfo = null;
|
||||
PasswordTextBox.Text = "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the selected item from <see cref="IPComboBox"/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/></param>
|
||||
void DeleteLoginButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
//make sure we're trying to delete a real item
|
||||
if (IPComboBox.SelectedItem as RemoteLoginInfo == null)
|
||||
return;
|
||||
IPComboBox.Items.RemoveAt(IPComboBox.SelectedIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-52
@@ -73,37 +73,12 @@ namespace TGS.ControlPanel.Properties {
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string RemoteIP {
|
||||
public global::System.Collections.Specialized.StringCollection RemoteLoginInfo {
|
||||
get {
|
||||
return ((string)(this["RemoteIP"]));
|
||||
return ((global::System.Collections.Specialized.StringCollection)(this["RemoteLoginInfo"]));
|
||||
}
|
||||
set {
|
||||
this["RemoteIP"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string RemoteUsername {
|
||||
get {
|
||||
return ((string)(this["RemoteUsername"]));
|
||||
}
|
||||
set {
|
||||
this["RemoteUsername"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("38607")]
|
||||
public ushort RemotePort {
|
||||
get {
|
||||
return ((ushort)(this["RemotePort"]));
|
||||
}
|
||||
set {
|
||||
this["RemotePort"] = value;
|
||||
this["RemoteLoginInfo"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,30 +94,6 @@ namespace TGS.ControlPanel.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string RemotePassword {
|
||||
get {
|
||||
return ((string)(this["RemotePassword"]));
|
||||
}
|
||||
set {
|
||||
this["RemotePassword"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string RemoteEntropy {
|
||||
get {
|
||||
return ((string)(this["RemoteEntropy"]));
|
||||
}
|
||||
set {
|
||||
this["RemoteEntropy"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
|
||||
@@ -14,24 +14,12 @@
|
||||
<Setting Name="LastChatProvider" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="RemoteIP" Type="System.String" Scope="User">
|
||||
<Setting Name="RemoteLoginInfo" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="RemoteUsername" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="RemotePort" Type="System.UInt16" Scope="User">
|
||||
<Value Profile="(Default)">38607</Value>
|
||||
</Setting>
|
||||
<Setting Name="RemoteDefault" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="RemotePassword" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="RemoteEntropy" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="GitHubAPIKey" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
|
||||
@@ -8,10 +8,9 @@ namespace TGS.ControlPanel
|
||||
/// Used to provide an ATP function for calls into an <see cref="TGS.Interface.IServerInterface"/>
|
||||
/// </summary>
|
||||
#if !DEBUG
|
||||
abstract class ServerOpForm : Form
|
||||
#else
|
||||
class ServerOpForm : Form
|
||||
abstract
|
||||
#endif
|
||||
class ServerOpForm : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to wrap <see cref="TGS.Interface.IServerInterface"/> calls in a non-blocking fashion while disabling the <see cref="Form"/> and enabling the wait cursor
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Script.Serialization;
|
||||
|
||||
namespace TGS.Interface
|
||||
{
|
||||
/// <summary>
|
||||
/// Information representing a remote server connection
|
||||
/// </summary>
|
||||
public sealed class RemoteLoginInfo : IEquatable<RemoteLoginInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for <see cref="Password"/> serialization
|
||||
/// </summary>
|
||||
const string EntropyFormatter = "{0}Entropy";
|
||||
|
||||
/// <summary>
|
||||
/// The IP address or URL of the target server
|
||||
/// </summary>
|
||||
public string IP { get { return _ip; } }
|
||||
/// <summary>
|
||||
/// The port to connect to the target server
|
||||
/// </summary>
|
||||
public ushort Port { get { return _port; } }
|
||||
/// <summary>
|
||||
/// A Windows username for the target server
|
||||
/// </summary>
|
||||
public string Username { get { return _username; } }
|
||||
/// <summary>
|
||||
/// The Windows password for <see cref="Username"/>
|
||||
/// </summary>
|
||||
public string Password { internal get; set; }
|
||||
/// <summary>
|
||||
/// Check if the <see cref="RemoteLoginInfo"/> has been initialized with a <see cref="Password"/>
|
||||
/// </summary>
|
||||
[ScriptIgnore]
|
||||
public bool HasPassword { get { return !String.IsNullOrWhiteSpace(Password); } }
|
||||
|
||||
/// <summary>
|
||||
/// Backing field for <see cref="IP"/>
|
||||
/// </summary>
|
||||
readonly string _ip;
|
||||
/// <summary>
|
||||
/// Backing field for <see cref="Port"/>
|
||||
/// </summary>
|
||||
readonly ushort _port;
|
||||
/// <summary>
|
||||
/// Backing field for <see cref="Username"/>
|
||||
/// </summary>
|
||||
readonly string _username;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="RemoteLoginInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="ip">The value for <see cref="IP"/></param>
|
||||
/// <param name="port">The value for <see cref="Port"/></param>
|
||||
/// <param name="username">The value for <see cref="Username"/></param>
|
||||
/// <param name="password">The value for <see cref="Password"/></param>
|
||||
public RemoteLoginInfo(string ip, ushort port, string username, string password)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(ip))
|
||||
throw new InvalidOperationException("ip must be set!");
|
||||
_ip = ip;
|
||||
if (port == 0)
|
||||
throw new InvalidOperationException("port may not be 0!");
|
||||
_port = port;
|
||||
if (String.IsNullOrWhiteSpace(username))
|
||||
throw new InvalidOperationException("username must be set!");
|
||||
_username = username;
|
||||
Password = password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="RemoteLoginInfo"/> from JSON
|
||||
/// </summary>
|
||||
/// <param name="json">The result of a call to <see cref="ToJSON"/></param>
|
||||
public RemoteLoginInfo(string json)
|
||||
{
|
||||
var dic = new JavaScriptSerializer().Deserialize<IDictionary<string, object>>(json);
|
||||
var ip = (string)dic[nameof(IP)];
|
||||
if (String.IsNullOrWhiteSpace(ip))
|
||||
throw new InvalidOperationException("ip must be set!");
|
||||
_ip = ip;
|
||||
var port = (ushort)(int)dic[nameof(Port)];
|
||||
if (port == 0)
|
||||
throw new InvalidOperationException("port may not be 0!");
|
||||
_port = port;
|
||||
var username = (string)dic[nameof(Username)];
|
||||
if (String.IsNullOrWhiteSpace(username))
|
||||
throw new InvalidOperationException("username must be set!");
|
||||
_username = username;
|
||||
if(dic.ContainsKey(nameof(Password)))
|
||||
Password = Helpers.DecryptData((string)dic[nameof(Password)], (string)dic[String.Format(EntropyFormatter, nameof(Password))]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see cref="IP"/>
|
||||
/// </summary>
|
||||
/// <returns><see cref="IP"/></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return IP;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if another <see cref="RemoteLoginInfo"/> matches <see langword="this"/> one
|
||||
/// </summary>
|
||||
/// <param name="other">Another <see cref="RemoteLoginInfo"/></param>
|
||||
/// <returns><see langword="true"/> if <see langword="this"/> and <paramref name="other"/> have the same <see cref="IP"/>, <see cref="Port"/>, and <see cref="Username"/></returns>
|
||||
public bool Equals(RemoteLoginInfo other)
|
||||
{
|
||||
return other != null && IP == other.IP && Port == other.Port && Username == other.Username;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a JSON representation of the <see cref="RemoteLoginInfo"/> with the <see cref="Password"/> encrypted
|
||||
/// </summary>
|
||||
/// <returns>A JSON representation of the <see cref="RemoteLoginInfo"/></returns>
|
||||
public string ToJSON()
|
||||
{
|
||||
//serialize it to a dic first so we can store the entropy
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var raw = serializer.Serialize(this);
|
||||
var dic = serializer.Deserialize<IDictionary<string, object>>(raw);
|
||||
if (HasPassword)
|
||||
{
|
||||
dic.Add(nameof(Password), Helpers.EncryptData(Password, out string entropy));
|
||||
dic.Add(String.Format(EntropyFormatter, nameof(Password)), entropy);
|
||||
}
|
||||
return serializer.Serialize(dic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
@@ -27,14 +26,9 @@ namespace TGS.Interface
|
||||
string InstanceName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If this is set, we will try and connect to an HTTPS server running at this address
|
||||
/// The <see cref="RemoteLoginInfo"/> for the <see cref="IServerInterface"/>. Is <see langword="null"/> for local connections
|
||||
/// </summary>
|
||||
string HTTPSURL { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The port used to connect to the <see cref="ITGSService"/>
|
||||
/// </summary>
|
||||
ushort HTTPSPort { get; }
|
||||
RemoteLoginInfo LoginInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="IServerInterface"/> is setup for a remote connection
|
||||
@@ -151,30 +145,12 @@ namespace TGS.Interface
|
||||
public string InstanceName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this is set, we will try and connect to an HTTPS server running at this address
|
||||
/// Backing field for <see cref="LoginInfo"/>
|
||||
/// </summary>
|
||||
readonly string _HTTPSURL;
|
||||
readonly RemoteLoginInfo _loginInfo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string HTTPSURL { get { return _HTTPSURL; } }
|
||||
|
||||
/// <summary>
|
||||
/// The port used to connect to the <see cref="ITGSService"/>
|
||||
/// </summary>
|
||||
readonly ushort _HTTPSPort;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ushort HTTPSPort { get { return _HTTPSPort; } }
|
||||
|
||||
/// <summary>
|
||||
/// Username for remote operations
|
||||
/// </summary>
|
||||
readonly string HTTPSUsername;
|
||||
|
||||
/// <summary>
|
||||
/// Password for remote operations
|
||||
/// </summary>
|
||||
readonly string HTTPSPassword;
|
||||
public RemoteLoginInfo LoginInfo { get { return _loginInfo; } }
|
||||
|
||||
/// <summary>
|
||||
/// Associated list of open <see cref="ChannelFactory"/>s keyed by <see langword="interface"/> type name. A <see cref="ChannelFactory"/> in this list may close or fault at any time. Must be locked before being accessed
|
||||
@@ -237,24 +213,14 @@ namespace TGS.Interface
|
||||
/// <summary>
|
||||
/// Construct an <see cref="ServerInterface"/> for a remote connection
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the remote server</param>
|
||||
/// <param name="port">The port the remote server runs on</param>
|
||||
/// <param name="username">Windows account username for the remote server</param>
|
||||
/// <param name="password">Windows account password for the remote server</param>
|
||||
public ServerInterface(string address, ushort port, string username, string password)
|
||||
/// <param name="loginInfo">The <see cref="RemoteLoginInfo"/> for a remote connection</param>
|
||||
public ServerInterface(RemoteLoginInfo loginInfo)
|
||||
{
|
||||
_HTTPSURL = address;
|
||||
_HTTPSPort = port;
|
||||
HTTPSUsername = username;
|
||||
HTTPSPassword = password;
|
||||
if (!loginInfo.HasPassword)
|
||||
throw new InvalidOperationException("password must be set on loginInfo!");
|
||||
_loginInfo = loginInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an <see cref="ServerInterface"/> that connects to the same <see cref="ITGSService"/> as some <paramref name="other"/> <see cref="ITGInstance"/>
|
||||
/// </summary>
|
||||
/// <param name="other">Another <see cref="ServerInterface"/> to copy settings from</param>
|
||||
public ServerInterface(ServerInterface other) : this(other.HTTPSURL, other.HTTPSPort, other.HTTPSUsername, other.HTTPSPassword) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConnectivityLevel ConnectToInstance(string instanceName = null, bool skipChecks = false)
|
||||
{
|
||||
@@ -297,7 +263,7 @@ namespace TGS.Interface
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsRemoteConnection { get { return HTTPSURL != null; } }
|
||||
public bool IsRemoteConnection { get { return LoginInfo != null; } }
|
||||
|
||||
/// <summary>
|
||||
/// Closes all <see cref="ChannelFactory"/>s stored in <see cref="ChannelFactoryCache"/> and clears it
|
||||
@@ -436,12 +402,13 @@ namespace TGS.Interface
|
||||
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
|
||||
binding.Security.Mode = requireAuth ? SecurityMode.TransportWithMessageCredential : SecurityMode.Transport; //do not require auth for a connectivity check
|
||||
binding.Security.Message.ClientCredentialType = requireAuth ? MessageCredentialType.UserName : MessageCredentialType.None;
|
||||
var address = new EndpointAddress(String.Format("https://{0}:{1}/{2}/{3}", HTTPSURL, HTTPSPort, accessPath, InterfaceName));
|
||||
var url = String.Format("https://{0}:{1}/{2}/{3}", LoginInfo.IP, LoginInfo.Port, accessPath, InterfaceName);
|
||||
var address = new EndpointAddress(url);
|
||||
var res = new ChannelFactory<T>(binding, address);
|
||||
if (requireAuth)
|
||||
{
|
||||
res.Credentials.UserName.UserName = HTTPSUsername;
|
||||
res.Credentials.UserName.Password = HTTPSPassword;
|
||||
res.Credentials.UserName.UserName = LoginInfo.Username;
|
||||
res.Credentials.UserName.Password = LoginInfo.Password;
|
||||
res.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
|
||||
}
|
||||
return res;
|
||||
@@ -460,7 +427,7 @@ namespace TGS.Interface
|
||||
{
|
||||
GetComponentImpl<ITGConnectivity>(false).VerifyConnection();
|
||||
}
|
||||
catch (CommunicationException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e.ToString();
|
||||
return ConnectivityLevel.None;
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Components\Repository.cs" />
|
||||
<Compile Include="PullRequestInfo.cs" />
|
||||
<Compile Include="RemoteLoginInfo.cs" />
|
||||
<Compile Include="RootCommand.cs" />
|
||||
<Compile Include="ServerInterface.cs" />
|
||||
<Compile Include="..\AssemblyInfo.global.cs" />
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace TGS.Interface.Tests
|
||||
/// <returns>The created <see cref="Interface"/></returns>
|
||||
ServerInterface CreateFakeRemoteInterface()
|
||||
{
|
||||
return new ServerInterface("some.fake.url.420", 34752, "user", "password");
|
||||
return new ServerInterface(new RemoteLoginInfo("some.fake.url.420", 34752, "user", "password"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,9 +77,11 @@ namespace TGS.Interface.Tests
|
||||
public void TestCopyRemoteInterface()
|
||||
{
|
||||
var first = CreateFakeRemoteInterface();
|
||||
var second = new ServerInterface(first);
|
||||
Assert.AreEqual(first.HTTPSURL, second.HTTPSURL);
|
||||
Assert.AreEqual(first.HTTPSPort, second.HTTPSPort);
|
||||
var second = new ServerInterface(first.LoginInfo);
|
||||
Assert.AreEqual(first.LoginInfo.IP, second.LoginInfo.IP);
|
||||
Assert.AreEqual(first.LoginInfo.Port, second.LoginInfo.Port);
|
||||
Assert.AreEqual(first.LoginInfo.Username, second.LoginInfo.Username);
|
||||
Assert.AreEqual(first.LoginInfo.Password, second.LoginInfo.Password);
|
||||
Assert.IsTrue(second.IsRemoteConnection);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user