Skip to content

Commit

Permalink
Create LoginLoop for retrying login on error, improve interface
Browse files Browse the repository at this point in the history
  • Loading branch information
hiilikewiki committed Nov 20, 2022
1 parent 7a21e3d commit dc05fe2
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 141 deletions.
35 changes: 20 additions & 15 deletions Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
using System;
using System.Net.Http;
using NinkyNonk.Shared.Environment;

namespace SophosSessionHolder {
public static class Extensions {
public static bool CheckSuccess(this HttpResponseMessage msg) {
try {
msg.EnsureSuccessStatusCode();
if (msg.Content == null)
throw new Exception("Did not receive proper response");
if (msg.Content.ToString()!.ToLower().Contains("invalid user name"))
throw new Exception("Invalid username or password!");
}
catch (Exception e) {
Project.LoggingProxy.LogError(e.Message);
return false;
}
return true;
namespace SophosSessionHolder;

public static class Extensions {
public static bool CheckSuccess(this HttpResponseMessage msg)
{
try
{
msg.EnsureSuccessStatusCode();
if (msg.Content.ToString() == null)
throw new Exception("Did not receive proper response");
if (msg.Content.ToString()!.ToLower().Contains("invalid user name"))
throw new Exception("Invalid username or password!");
}
catch (Exception e)
{
Project.LoggingProxy.LogError(e.Message);
return false;
}
return true;
}
}
56 changes: 35 additions & 21 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,55 +1,69 @@
using SophosSessionHolder;
using NinkyNonk.Shared.Logging;
using System;
using System.IO;
using SophosSessionHolder;
using Newtonsoft.Json;
using NinkyNonk.Shared.Environment;
using NinkyNonk.Shared.Framework.Exception;

SophosSessionConfiguration? config = new SophosSessionConfiguration();

try {
try
{
Project.LoggingProxy.LogProgramInfo();
Project.LoggingProxy.LogInfo("Starting...");
if (args.Length > 0) {
if (args.Length >= 2) {
if (args.Length > 0)
{
if (args.Length >= 2)
{
config.Username = args[0];
config.Password = args[1];
if (args.Length == 3)
config.EndpointRoot = args[2];
}
else {
throw new ArgumentException("Not enough arguments!");
config.EndpointRoot = args[2];
}
else
throw new FatalException("Not enough arguments!");
}
else if (File.Exists("Config.json")) {
else if (File.Exists("Config.json"))
{
string text = File.ReadAllText("Config.json");
if (text == null)
throw new Exception("Could not load config file");
if (string.IsNullOrEmpty(text))
throw new FatalException("Could not load config file");
config = JsonConvert.DeserializeObject<SophosSessionConfiguration>(text);
if (config == null) {
throw new Exception("Could not load config");
}
if (config == null)
throw new FatalException("Could not load config");
}
else {
else
{
config.EndpointRoot = Project.LoggingProxy.AskInput("Host: ");
if (!config.EndpointRoot.Contains("https://") || !config.EndpointRoot.Contains("http://"))
config.EndpointRoot = "http://" + config.EndpointRoot;
config.Username = Project.LoggingProxy.AskInput("Username: ");
config.Password = Project.LoggingProxy.AskInput("Password: ");
ConsoleLogger.LogInfo("Saving config....");
Project.LoggingProxy.LogInfo("Saving config....");
File.WriteAllText("Config.json", JsonConvert.SerializeObject(config));
}

Project.LoggingProxy.LogInfo("Testing connection...");
SophosSession sesh = new(config);

if (!(await sesh.Test())) {
Project.LoggingProxy.LogError("Could not connect to host");
if (!await sesh.Test())
{
Console.ReadKey();
return;
}
}

Project.LoggingProxy.LogInfo("Logging in...");
await sesh.Login();
Project.LoggingProxy.LogSuccess("Logged in successfully - do not close program");
await sesh.KeepAlive();
}
catch (Exception e) {
catch (FatalException e)
{
Project.LoggingProxy.LogFatal(e.Message);
Project.LoggingProxy.Log("Press any key to exit...");
}
catch (Exception e)
{
Project.LoggingProxy.LogError(e.Message);
}

Expand Down
181 changes: 106 additions & 75 deletions SophosSession.cs
Original file line number Diff line number Diff line change
@@ -1,101 +1,132 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using NinkyNonk.Shared.Data;
using NinkyNonk.Shared.Environment;
using NinkyNonk.Shared.Logging;
using NinkyNonk.Shared.Framework.Exception;

namespace SophosSessionHolder {
public class SophosSession
{
private const string Endpoint = "login.xml";
private const string LiveEndpoint = "live?mode=192&username={username}&a={time}&producttype=0";
private readonly string _username;
private readonly string _password;
private readonly string _host;
private readonly int _heartbeatTimeout;
namespace SophosSessionHolder;

private readonly HttpClient _client;
public class SophosSession
{
private const string Endpoint = "login.xml";
private const string LiveEndpoint = "live?mode=192&username={username}&a={time}&producttype=0";

private readonly string _username;
private readonly string _password;
private readonly string _host;
private readonly int _heartbeatTimeout;

private int _goodRequests;
private int _failedRequests;
private readonly HttpClient _client;

public int TotalSessionRequests { get => _goodRequests + _failedRequests; }
private int _goodRequests;
private int _failedRequests;
private bool _loggedIn;

public int TotalSessionRequests { get => _goodRequests + _failedRequests; }

public SophosSession(SophosSessionConfiguration config)
{
_username = config.Username;
_password = config.Password;
_host = config.EndpointRoot;
_heartbeatTimeout = config.HeartbeatMiliseconds;
_client = new HttpClient();
_client.DefaultRequestHeaders.Referrer = new Uri(_host);
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
}

public SophosSession(SophosSessionConfiguration config) {
_username = config.Username;
_password = config.Password;
_host = config.EndpointRoot;
_heartbeatTimeout = config.HeartbeatMiliseconds;
_client = new HttpClient();
_client.DefaultRequestHeaders.Referrer = new Uri(_host);
}

private string EncodeUsername() {
return _username.Replace("@", "%40");
}
private string EncodeUsername() {
return _username.Replace("@", "%40");
}

public async Task<bool> Test() {
public async Task<bool> Test()
{
try
{
HttpResponseMessage response = await _client.GetAsync(_host);
response.EnsureSuccessStatusCode();
return true;
}

public async Task Login() {
string url = _host + Endpoint;

Dictionary<string, string> body = new Dictionary<string, string>() {
{"mode", "191"},
{"username", _username},
{"password", _password},
{"a", DateTime.Now.GetEpoch().ToString()},
{"producttype", "0"},
};

_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

HttpResponseMessage msg = await _client.PostAsync(url, new FormUrlEncodedContent(body));
catch (Exception e)
{
Project.LoggingProxy.LogError(e.Message);
throw new FatalException("Could not connect to host.");
}
}

if (!msg.CheckSuccess()) {
throw new WebException("Request failed: " + msg.StatusCode);
private async Task LoginLoop()
{
while (!_loggedIn)
{
try
{
await Login();
_loggedIn = true;
}
catch (Exception e)
{
Project.LoggingProxy.LogError(e.Message);
Project.LoggingProxy.LogUpdate("Retrying login in 5 seconds.");
await Task.Delay(5000);
}

}
Project.LoggingProxy.LogSuccess("Logged in successfully");
}

public async Task Login()
{
string url = _host + Endpoint;

Dictionary<string, string> body = new Dictionary<string, string>
{
{"mode", "191"},
{"username", _username},
{"password", _password},
{"a", DateTime.Now.GetEpoch().ToString()},
{"producttype", "0"},
};

HttpResponseMessage msg = await _client.PostAsync(url, new FormUrlEncodedContent(body));

if (!msg.CheckSuccess())
throw new WebException("Request failed: " + msg.StatusCode);
}

private string FillEndpoint(string endpoint) {
return _host + endpoint.Replace("{username}", EncodeUsername())
private string FillEndpoint(string endpoint) {
return _host + endpoint.Replace("{username}", EncodeUsername())
.Replace("{password}", _password)
.Replace("{time}", DateTime.Now.GetEpoch().ToString());
}

public async Task KeepAlive() {

string url = FillEndpoint(LiveEndpoint);


ThreadPool.QueueUserWorkItem(async _ => {
while (true) {
await Task.Delay(300000);
Project.LoggingProxy.LogUpdate($"Sent {TotalSessionRequests} heartbeats in the past five minutes. {_goodRequests}/{TotalSessionRequests} succeeded");
_goodRequests = 0;
_failedRequests = 0;
}
});
}

public async Task KeepAlive()
{
string url = FillEndpoint(LiveEndpoint);

ThreadPool.QueueUserWorkItem(async _ => {
while (true) {
await Task.Delay(_heartbeatTimeout);
var msg = await _client.GetAsync(url);
if (!msg.CheckSuccess())
{
_failedRequests++;
ConsoleLogger.LogInfo("Re-logging in due to error...");
await Login();
}
else
_goodRequests++;
await Task.Delay(300000);
Project.LoggingProxy.LogUpdate($"Sent {TotalSessionRequests} heartbeats in the past five minutes. {_goodRequests}/{TotalSessionRequests} succeeded");
_goodRequests = 0;
_failedRequests = 0;
}
});

while (true) {
await Task.Delay(_heartbeatTimeout);
var msg = await _client.GetAsync(url);
if (!msg.CheckSuccess())
{
_failedRequests++;
Project.LoggingProxy.LogInfo("Re-logging in due to error...");
_loggedIn = false;
await LoginLoop();
}
else
_goodRequests++;
}



}
}
38 changes: 19 additions & 19 deletions SophosSessionConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
namespace SophosSessionHolder {
public class SophosSessionConfiguration {
public string Username { get; set; }
public string Password { get; set; }
public string EndpointRoot {get; set;}
public int HeartbeatMiliseconds { get; set;}
namespace SophosSessionHolder;

public SophosSessionConfiguration() {
Username = "";
Password = "";
EndpointRoot = "https://sophosxg.queenelizabeth.cumbria.sch.uk:8090/";
HeartbeatMiliseconds = 180000;
}
public class SophosSessionConfiguration {
public string Username { get; set; }
public string Password { get; set; }
public string EndpointRoot {get; set;}
public int HeartbeatMiliseconds { get; set;}

public SophosSessionConfiguration(string username, string password, string endpointRoot, int heartbeatMiliseconds) {
Username = username;
Password = password;
EndpointRoot = endpointRoot;
HeartbeatMiliseconds = heartbeatMiliseconds;
}

public SophosSessionConfiguration()
{
Username = "";
Password = "";
EndpointRoot = "https://sophosxg.queenelizabeth.cumbria.sch.uk:8090/";
HeartbeatMiliseconds = 180000;
}

public SophosSessionConfiguration(string username, string password, string endpointRoot, int heartbeatMiliseconds) {
Username = username;
Password = password;
EndpointRoot = endpointRoot;
HeartbeatMiliseconds = heartbeatMiliseconds;
}
}
Loading

0 comments on commit dc05fe2

Please sign in to comment.