view ServerMonitor/Objects/Server.cs @ 14:2db36ab759de

Add comments.
author Brad Greco <brad@bgreco.net>
date Mon, 22 Apr 2019 21:10:42 -0400
parents 052aa62cb42a
children 68d7834dc28e
line wrap: on
line source

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.ComponentModel;
using Renci.SshNet;
using System.Runtime.Serialization;
using System.Xml.Serialization;

namespace ServerMonitorApp
{
    public enum LoginType { PrivateKey = 0, Password = 1 };

    public class Server
    {
        private string _host;
        private int _port;
        private string _username;
        private LoginType _loginType;
        private string _keyFile;
        private SshClient _sshClient;
        private bool _enabled = true;
        private byte[] passwordHash;
        private PrivateKeyFile _privateKeyFile;

        public event EventHandler CheckModified;
        public event EventHandler EnabledChanged;

        public readonly BindingList<Check> Checks = new BindingList<Check>();

        public int Id { get; set; }

        public string Name { get; set; }

        public string Host
        {
            get { return _host; }
            set { _host = value; InvalidateSshConnection(); }
        }

        public int Port
        {
            get { return _port; }
            set { _port = value; InvalidateSshConnection(); }
        }

        public string Username
        {
            get { return _username; }
            set { _username = value; InvalidateSshConnection(); }
        }

        public LoginType LoginType
        {
            get { return _loginType; }
            set { _loginType = value; InvalidateSshConnection(); }
        }

        public string KeyFile
        {
            get { return _keyFile; }
            set { _keyFile = value; InvalidateSshConnection(); }
        }

        public string Password
        {
            get {
                return passwordHash == null ? null :
                    Encoding.UTF8.GetString(ProtectedData.Unprotect(passwordHash, Encoding.UTF8.GetBytes("Server".Reverse().ToString()), DataProtectionScope.CurrentUser));
            }
            set
            {
                passwordHash = ProtectedData.Protect(Encoding.UTF8.GetBytes(value),
                                    Encoding.UTF8.GetBytes("Server".Reverse().ToString()), // Minor obfuscation of additional entropy
                                    DataProtectionScope.CurrentUser);
            }
        }

        [XmlIgnore]
        public PrivateKeyFile PrivateKeyFile
        {
            get { return _privateKeyFile; }
            set
            {
                _privateKeyFile = value;
                if (LoginType == LoginType.PrivateKey)
                {
                    if (_privateKeyFile == null)
                    {
                        KeyStatus = KeyStatus.Closed;
                        Enabled = false;
                    }
                    else
                    {
                        if (!KeyStatus.In(KeyStatus.Open, KeyStatus.Closed))
                            Enabled = true;
                        KeyStatus = KeyStatus.Open;
                    }
                }
            }
        }

        public KeyStatus KeyStatus { get; set; }

        public bool Enabled
        {
            get { return _enabled; }
            set
            {
                if ((LoginType == LoginType.PrivateKey && PrivateKeyFile == null && value == true) || value == _enabled)
                    return;
                _enabled = value;
                EnabledChanged?.Invoke(this, new EventArgs());
            }
        }

        //public bool WaitingForUser { get; set; }

        public CheckStatus Status => !Enabled ? CheckStatus.Disabled : Checks
            .Where(c => c.Enabled)
            .Select(c => c.LastRunStatus)
            .DefaultIfEmpty(CheckStatus.Success)
            .Max();

        public SshClient SshClient
        {
            get
            {
                if (_sshClient == null)
                {
                    ConnectionInfo info = new ConnectionInfo(Host, Port, Username, GetAuthentication());
                    _sshClient = new SshClient(info);
                }
                return _sshClient;
            }
        }

        /*public Server() { }

        public Server(Server server)
        {
            Name = server.Name;
            Host = server.Host;
            Port = server.Port;
            Username = server.Username;
            LoginType = server.LoginType;
            KeyFile = server.KeyFile;
            Enabled = server.Enabled;
        }*/

        public void DeleteCheck(Check check)
        {
            Checks.Remove(check);
            check.Server = null;
            CheckModified?.Invoke(check, new EventArgs());
        }

        public string Validate()
        {
            string message = string.Empty;
            if (Name.Length == 0)
                message += "\"Name\" must not be empty" + Environment.NewLine;
            if (Host.Length == 0)
                message += "\"Host\" must not be empty" + Environment.NewLine;
            return message.Length > 0 ? message : null;
        }

        public void UpdateCheck(Check check)
        {
            Check oldCheck = Checks.FirstOrDefault(c => c.Id == check.Id);
            if (!ReferenceEquals(check, oldCheck))
            {
                int index = Checks.IndexOf(oldCheck);
                if (index == -1)
                    Checks.Add(check);
                else
                    Checks[index] = check;
            }
            CheckModified?.Invoke(check, new EventArgs());
        }

        public bool IsEmpty()
        {
            return Name.IsNullOrEmpty()
                && Host.IsNullOrEmpty()
                && Checks.Count == 0;
        }

        private AuthenticationMethod GetAuthentication()
        {
            if (LoginType == LoginType.Password)
                return new PasswordAuthenticationMethod(Username, Password);
            else
                return new PrivateKeyAuthenticationMethod(Username, PrivateKeyFile);
        }

        private void InvalidateSshConnection()
        {
            _sshClient?.Dispose();
            _sshClient = null;
        }

        public override string ToString()
        {
            return Name.IsNullOrEmpty() ? Host : Name;
        }
    }

    public enum KeyStatus
    {
        Closed,
        Open,
        NotAccessible,
        NeedPassword,
    }


}