280 lines
11 KiB
C#
280 lines
11 KiB
C#
using System.Drawing;
|
|
using System.Security.Cryptography;
|
|
using System.Windows.Forms;
|
|
using MonsterMonitor.Models;
|
|
|
|
namespace MonsterMonitor.UI
|
|
{
|
|
public sealed class SettingsForm : Form
|
|
{
|
|
private readonly AppSettings _settings;
|
|
private readonly TextBox _txtHost = new TextBox();
|
|
private readonly NumericUpDown _numSshPort = new NumericUpDown();
|
|
private readonly TextBox _txtUser = new TextBox();
|
|
private readonly TextBox _txtPassword = new TextBox();
|
|
private readonly CheckBox _chkSavePassword = new CheckBox();
|
|
private readonly NumericUpDown _numRemotePort = new NumericUpDown();
|
|
private readonly NumericUpDown _numLocalPort = new NumericUpDown();
|
|
private readonly NumericUpDown _numMaxFailures = new NumericUpDown();
|
|
private readonly NumericUpDown _numReconnectTimeout = new NumericUpDown();
|
|
private readonly TextBox _txtProxy = new TextBox();
|
|
private readonly TextBox _txtSsPath = new TextBox();
|
|
private readonly TextBox _txtSsArgs = new TextBox();
|
|
private readonly TextBox _txtSystemPassword = new TextBox();
|
|
private readonly CheckBox _chkShowSystemPassword = new CheckBox();
|
|
private readonly TextBox _txtThreeProxyPassword = new TextBox();
|
|
private readonly CheckBox _chkShowThreeProxyPassword = new CheckBox();
|
|
private readonly Button _btnGenerateThreeProxyPassword = new Button();
|
|
|
|
public SettingsForm(AppSettings settings)
|
|
{
|
|
_settings = settings;
|
|
Text = "Настройки";
|
|
Width = 560;
|
|
Height = 560;
|
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
MaximizeBox = false;
|
|
MinimizeBox = false;
|
|
StartPosition = FormStartPosition.CenterParent;
|
|
|
|
BuildLayout();
|
|
LoadValues();
|
|
}
|
|
|
|
private void BuildLayout()
|
|
{
|
|
var panel = new TableLayoutPanel
|
|
{
|
|
Dock = DockStyle.Fill,
|
|
Padding = new Padding(10),
|
|
ColumnCount = 2,
|
|
RowCount = 15
|
|
};
|
|
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 44f));
|
|
panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 56f));
|
|
|
|
Controls.Add(panel);
|
|
|
|
AddRow(panel, "Сервер:", _txtHost, 0);
|
|
AddRow(panel, "Порт:", _numSshPort, 1);
|
|
AddRow(panel, "Логин:", _txtUser, 2);
|
|
_txtPassword.PasswordChar = '*';
|
|
AddRow(panel, "Пароль:", _txtPassword, 3);
|
|
_chkSavePassword.Text = "Сохранить пароль";
|
|
AddRow(panel, string.Empty, _chkSavePassword, 4);
|
|
AddRow(panel, "Удаленный порт:", _numRemotePort, 5);
|
|
AddRow(panel, "Локальный порт:", _numLocalPort, 6);
|
|
AddRow(panel, "Макс. потерь:", _numMaxFailures, 7);
|
|
AddRow(panel, "Таймаут reconnect (сек):", _numReconnectTimeout, 8);
|
|
AddRow(panel, "Прокси (http://host:port):", _txtProxy, 9);
|
|
AddRow(panel, "Путь к ss:", _txtSsPath, 10);
|
|
AddRow(panel, "Аргументы ss:", _txtSsArgs, 11);
|
|
BuildSystemPasswordRow(panel, 12);
|
|
BuildThreeProxyPasswordRow(panel, 13);
|
|
|
|
foreach (var num in new[] { _numSshPort, _numRemotePort, _numLocalPort })
|
|
{
|
|
num.Minimum = 1;
|
|
num.Maximum = 65535;
|
|
}
|
|
|
|
_numMaxFailures.Minimum = 1;
|
|
_numMaxFailures.Maximum = 10;
|
|
_numReconnectTimeout.Minimum = 5;
|
|
_numReconnectTimeout.Maximum = 60;
|
|
|
|
var buttonsPanel = new FlowLayoutPanel
|
|
{
|
|
Dock = DockStyle.Fill,
|
|
FlowDirection = FlowDirection.RightToLeft
|
|
};
|
|
var btnSave = new Button { Text = "Сохранить", Width = 120, Height = 30 };
|
|
var btnCancel = new Button { Text = "Отмена", Width = 120, Height = 30 };
|
|
btnSave.Click += (_, __) => SaveAndClose();
|
|
btnCancel.Click += (_, __) => DialogResult = DialogResult.Cancel;
|
|
|
|
buttonsPanel.Controls.Add(btnSave);
|
|
buttonsPanel.Controls.Add(btnCancel);
|
|
panel.Controls.Add(buttonsPanel, 0, 14);
|
|
panel.SetColumnSpan(buttonsPanel, 2);
|
|
}
|
|
|
|
private void BuildSystemPasswordRow(TableLayoutPanel panel, int row)
|
|
{
|
|
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 34f));
|
|
panel.Controls.Add(new Label
|
|
{
|
|
Text = "Пароль Sterra:",
|
|
TextAlign = ContentAlignment.MiddleLeft,
|
|
Dock = DockStyle.Fill
|
|
}, 0, row);
|
|
|
|
var passPanel = new FlowLayoutPanel
|
|
{
|
|
Dock = DockStyle.Fill,
|
|
FlowDirection = FlowDirection.LeftToRight,
|
|
WrapContents = false,
|
|
AutoSize = false
|
|
};
|
|
|
|
_txtSystemPassword.Width = 170;
|
|
_txtSystemPassword.PasswordChar = '*';
|
|
|
|
_chkShowSystemPassword.Text = "Показать";
|
|
_chkShowSystemPassword.AutoSize = true;
|
|
_chkShowSystemPassword.CheckedChanged += (_, __) =>
|
|
{
|
|
_txtSystemPassword.PasswordChar = _chkShowSystemPassword.Checked ? '\0' : '*';
|
|
};
|
|
|
|
passPanel.Controls.Add(_txtSystemPassword);
|
|
passPanel.Controls.Add(_chkShowSystemPassword);
|
|
panel.Controls.Add(passPanel, 1, row);
|
|
}
|
|
|
|
private void BuildThreeProxyPasswordRow(TableLayoutPanel panel, int row)
|
|
{
|
|
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 34f));
|
|
panel.Controls.Add(new Label
|
|
{
|
|
Text = "Пароль прокси:",
|
|
TextAlign = ContentAlignment.MiddleLeft,
|
|
Dock = DockStyle.Fill
|
|
}, 0, row);
|
|
|
|
var passPanel = new FlowLayoutPanel
|
|
{
|
|
Dock = DockStyle.Fill,
|
|
FlowDirection = FlowDirection.LeftToRight,
|
|
WrapContents = false,
|
|
AutoSize = false
|
|
};
|
|
|
|
_txtThreeProxyPassword.Width = 170;
|
|
_txtThreeProxyPassword.PasswordChar = '*';
|
|
|
|
_chkShowThreeProxyPassword.Text = "Показать";
|
|
_chkShowThreeProxyPassword.AutoSize = true;
|
|
_chkShowThreeProxyPassword.CheckedChanged += (_, __) =>
|
|
{
|
|
_txtThreeProxyPassword.PasswordChar = _chkShowThreeProxyPassword.Checked ? '\0' : '*';
|
|
};
|
|
|
|
_btnGenerateThreeProxyPassword.Text = "Сгенерировать";
|
|
_btnGenerateThreeProxyPassword.AutoSize = true;
|
|
_btnGenerateThreeProxyPassword.Click += (_, __) =>
|
|
{
|
|
_txtThreeProxyPassword.Text = GeneratePassword();
|
|
};
|
|
|
|
passPanel.Controls.Add(_txtThreeProxyPassword);
|
|
passPanel.Controls.Add(_chkShowThreeProxyPassword);
|
|
passPanel.Controls.Add(_btnGenerateThreeProxyPassword);
|
|
panel.Controls.Add(passPanel, 1, row);
|
|
}
|
|
|
|
private static void AddRow(TableLayoutPanel panel, string label, Control control, int row)
|
|
{
|
|
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 34f));
|
|
|
|
if (!string.IsNullOrEmpty(label))
|
|
{
|
|
panel.Controls.Add(new Label
|
|
{
|
|
Text = label,
|
|
TextAlign = ContentAlignment.MiddleLeft,
|
|
Dock = DockStyle.Fill
|
|
}, 0, row);
|
|
}
|
|
|
|
control.Dock = DockStyle.Fill;
|
|
panel.Controls.Add(control, 1, row);
|
|
}
|
|
|
|
private void LoadValues()
|
|
{
|
|
_txtHost.Text = _settings.SshHost;
|
|
_numSshPort.Value = Clamp(_numSshPort, _settings.SshPort);
|
|
_txtUser.Text = _settings.SshUsername;
|
|
_txtPassword.Text = _settings.GetPassword();
|
|
_chkSavePassword.Checked = _settings.SavePassword;
|
|
_numRemotePort.Value = Clamp(_numRemotePort, _settings.RemotePort);
|
|
_numLocalPort.Value = Clamp(_numLocalPort, _settings.LocalPort);
|
|
_numMaxFailures.Value = Clamp(_numMaxFailures, _settings.MaxPingFailures);
|
|
_numReconnectTimeout.Value = Clamp(_numReconnectTimeout, _settings.ReconnectTimeoutSec);
|
|
_txtProxy.Text = _settings.Proxy;
|
|
_txtSsPath.Text = _settings.SsProcessPath;
|
|
_txtSsArgs.Text = _settings.SsArguments;
|
|
_txtSystemPassword.Text = _settings.GetSystemPassword();
|
|
_txtThreeProxyPassword.Text = _settings.GetThreeProxyPassword();
|
|
}
|
|
|
|
// Приводит значение из настроек к допустимому диапазону контрола,
|
|
// иначе NumericUpDown.Value бросит ArgumentOutOfRangeException и окно не откроется.
|
|
private static decimal Clamp(NumericUpDown control, int value)
|
|
{
|
|
if (value < control.Minimum)
|
|
{
|
|
return control.Minimum;
|
|
}
|
|
|
|
if (value > control.Maximum)
|
|
{
|
|
return control.Maximum;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
private void SaveAndClose()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(_txtHost.Text))
|
|
{
|
|
MessageBox.Show(this, "Поле сервера обязательно.", "Валидация", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
return;
|
|
}
|
|
|
|
_settings.SshHost = _txtHost.Text.Trim();
|
|
_settings.SshPort = (int)_numSshPort.Value;
|
|
_settings.SshUsername = _txtUser.Text.Trim();
|
|
_settings.SavePassword = _chkSavePassword.Checked;
|
|
_settings.SetPassword(_txtPassword.Text);
|
|
_settings.RemotePort = (int)_numRemotePort.Value;
|
|
_settings.LocalPort = (int)_numLocalPort.Value;
|
|
_settings.MaxPingFailures = (int)_numMaxFailures.Value;
|
|
_settings.ReconnectTimeoutSec = (int)_numReconnectTimeout.Value;
|
|
_settings.Proxy = _txtProxy.Text.Trim();
|
|
_settings.SsProcessPath = string.IsNullOrWhiteSpace(_txtSsPath.Text)
|
|
? System.IO.Path.Combine("App_Data", "ss", "ss.exe")
|
|
: _txtSsPath.Text.Trim();
|
|
_settings.SsArguments = string.IsNullOrWhiteSpace(_txtSsArgs.Text)
|
|
? System.IO.Path.Combine("App_Data", "ss", "ss.cfg")
|
|
: _txtSsArgs.Text.Trim();
|
|
_settings.SetSystemPassword(_txtSystemPassword.Text.Trim());
|
|
_settings.SetThreeProxyPassword(_txtThreeProxyPassword.Text.Trim());
|
|
_settings.Save();
|
|
|
|
DialogResult = DialogResult.OK;
|
|
}
|
|
|
|
private static string GeneratePassword()
|
|
{
|
|
const string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
const int length = 20;
|
|
var bytes = new byte[length];
|
|
using (var rng = RandomNumberGenerator.Create())
|
|
{
|
|
rng.GetBytes(bytes);
|
|
}
|
|
|
|
var chars = new char[length];
|
|
for (var i = 0; i < length; i++)
|
|
{
|
|
chars[i] = alphabet[bytes[i] % alphabet.Length];
|
|
}
|
|
|
|
return new string(chars);
|
|
}
|
|
}
|
|
}
|