mirror of
https://github.com/donavon04/MPELicenseAgent.git
synced 2025-01-18 00:50:57 -07:00
339 lines
13 KiB
C#
339 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Management;
|
|
using System.Net.Http;
|
|
using System.ServiceProcess;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Timers;
|
|
using System.Xml.Linq;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace MPELicenseAgent
|
|
{
|
|
public partial class Service1 : ServiceBase
|
|
{
|
|
private string homeBaseAddress = "apilicenses.mpe.ca";
|
|
private string apiKey = "&v94gt8ZHFTTTeuT";
|
|
private string[] requestedPrograms = new string[30];
|
|
private Timer pollRateTimer;
|
|
private int pollRate;
|
|
private bool canPhoneHome = false;
|
|
|
|
public Service1()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
// Function that starts when the service is run
|
|
protected override async void OnStart(string[] args)
|
|
{
|
|
this.WriteToFile("\n*******************************************************\nMPE License Tracker\nMade by: Donavon McDowell\n");
|
|
try
|
|
{
|
|
await this.getHealth();
|
|
if (this.canPhoneHome)
|
|
{
|
|
this.WriteToFile(DateTime.Now.ToString() + " Connected to home base " + this.homeBaseAddress);
|
|
await this.getPollRate();
|
|
await this.getRequestedPrograms();
|
|
await this.getClientPrograms();
|
|
}
|
|
}
|
|
catch (Exception ex1)
|
|
{
|
|
Exception ex = ex1;
|
|
}
|
|
this.pollRateTimer = new Timer();
|
|
this.pollRateTimer.Interval = (double)this.pollRate;
|
|
this.pollRateTimer.Elapsed += new ElapsedEventHandler(this.OnElapsedTime);
|
|
this.pollRateTimer.Start();
|
|
}
|
|
|
|
protected override void OnStop()
|
|
{
|
|
if (this.pollRateTimer == null)
|
|
return;
|
|
this.pollRateTimer.Stop();
|
|
this.pollRateTimer.Dispose();
|
|
}
|
|
|
|
// Params: STRING data
|
|
// Description: Takes a string and writes it to an output / log file
|
|
// Location: Where the exe file for this service exists
|
|
public void WriteToFile(string data)
|
|
{
|
|
string str1 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
|
|
if (!Directory.Exists(str1))
|
|
Directory.CreateDirectory(str1);
|
|
string str2 = Path.Combine(str1, "ServiceLog.txt");
|
|
if (File.Exists(str2) && new FileInfo(str2).Length / 1024L > 100L)
|
|
{
|
|
File.Delete(str2);
|
|
using (StreamWriter text = File.CreateText(str2))
|
|
text.WriteLine(data);
|
|
}
|
|
else
|
|
{
|
|
using (StreamWriter streamWriter = File.AppendText(str2))
|
|
streamWriter.WriteLine(data);
|
|
}
|
|
}
|
|
|
|
|
|
private async void OnElapsedTime(object source, ElapsedEventArgs e)
|
|
{
|
|
await this.getHealth();
|
|
if (!this.canPhoneHome)
|
|
return;
|
|
await this.getRequestedPrograms();
|
|
await this.getPollRate();
|
|
await this.getClientPrograms();
|
|
this.pollRateTimer.Interval = (double)this.pollRate;
|
|
}
|
|
|
|
// Checks the health of the api, if there are any issues it will wait and probe again in a little bit
|
|
// This is used so that we don't DDOS the reverse proxy
|
|
private async Task getHealth()
|
|
{
|
|
string baseUrl = "https://" + this.homeBaseAddress;
|
|
string endpoint = "/api/healthcheck";
|
|
HttpMethod method = HttpMethod.Get;
|
|
HttpClient httpClient = new HttpClient()
|
|
{
|
|
Timeout = TimeSpan.FromSeconds(4.0)
|
|
};
|
|
try
|
|
{
|
|
HttpResponseMessage response = await httpClient.GetAsync(baseUrl + endpoint);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
string responses = await response.Content.ReadAsStringAsync();
|
|
if (!string.IsNullOrEmpty(responses))
|
|
{
|
|
this.canPhoneHome = true;
|
|
}
|
|
else
|
|
{
|
|
this.canPhoneHome = false;
|
|
this.WriteToFile(DateTime.Now.ToString() + " Disconnected from home base " + this.homeBaseAddress);
|
|
}
|
|
responses = (string)null;
|
|
}
|
|
else
|
|
{
|
|
this.canPhoneHome = false;
|
|
this.WriteToFile(DateTime.Now.ToString() + " Disconnected from home base " + this.homeBaseAddress);
|
|
}
|
|
response = (HttpResponseMessage)null;
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
httpClient = (HttpClient)null;
|
|
}
|
|
catch (TaskCanceledException ex)
|
|
{
|
|
this.canPhoneHome = false;
|
|
this.WriteToFile(DateTime.Now.ToString() + " [Error]: Connection timed out while trying to phone home to " + this.homeBaseAddress);
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
httpClient = (HttpClient)null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
this.canPhoneHome = false;
|
|
this.WriteToFile(DateTime.Now.ToString() + " [Error]: There was an error in the getHealth() function. " + ex.Message);
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
httpClient = (HttpClient)null;
|
|
}
|
|
}
|
|
|
|
// This talks to the backend and gets all of the programs that we are interested in monitoring
|
|
private async Task getRequestedPrograms()
|
|
{
|
|
string baseUrl = "https://" + this.homeBaseAddress;
|
|
string endpoint = "/api/programs";
|
|
HttpMethod method = HttpMethod.Get;
|
|
try
|
|
{
|
|
string responses = await Service1.ApiClient.hitApi(baseUrl, endpoint, method);
|
|
string cleanedResponses = responses.Trim('[', ']');
|
|
string[] responseArray = cleanedResponses.Split(new string[1]
|
|
{
|
|
"\",\""
|
|
}, StringSplitOptions.None);
|
|
responseArray[0] = responseArray[0].Trim('"');
|
|
responseArray[responseArray.Length - 1] = responseArray[responseArray.Length - 1].Trim('"');
|
|
this.requestedPrograms = responseArray;
|
|
responses = (string)null;
|
|
cleanedResponses = (string)null;
|
|
responseArray = (string[])null;
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
this.WriteToFile(DateTime.Now.ToString() + " [Error]: There was an error in the getRequestedPrograms() function. " + ex?.ToString());
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
}
|
|
}
|
|
|
|
// This looks at the computer itself and determines any applications that match our requested programs
|
|
private async Task getClientPrograms()
|
|
{
|
|
Process[] processes = Process.GetProcesses();
|
|
string[] matchingProcesses = processes
|
|
.Select(p => p.ProcessName)
|
|
.Where(pn => this.requestedPrograms.Contains(pn, StringComparer.OrdinalIgnoreCase))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.ToArray();
|
|
|
|
foreach (string processName in matchingProcesses)
|
|
{
|
|
Process[] processList = processes.Where(p => p.ProcessName.Equals(processName, StringComparison.OrdinalIgnoreCase)).ToArray();
|
|
foreach (Process process in processList)
|
|
{
|
|
string userName = GetProcessOwner(process.Id);
|
|
await this.sendMatchingPrograms(processName, userName);
|
|
}
|
|
}
|
|
|
|
processes = null;
|
|
matchingProcesses = null;
|
|
}
|
|
|
|
// Method to get the username of the process owner
|
|
private string GetProcessOwner(int processId)
|
|
{
|
|
try
|
|
{
|
|
string query = "Select * From Win32_Process Where ProcessID = " + processId;
|
|
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
|
|
using (ManagementObjectCollection processList = searcher.Get())
|
|
{
|
|
foreach (ManagementObject obj in processList)
|
|
{
|
|
object[] argList = new object[2] { string.Empty, string.Empty };
|
|
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
|
|
if (returnVal == 0)
|
|
{
|
|
return argList[0]?.ToString(); // Return the username
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Handle any exceptions
|
|
}
|
|
return "Unknown"; // Return 'Unknown' if unable to retrieve username
|
|
}
|
|
|
|
|
|
// This actually sends the matching applications to the backend
|
|
// This actually sends the matching applications to the backend
|
|
private async Task sendMatchingPrograms(string applicationName, string userName)
|
|
{
|
|
string baseUrl = "https://" + this.homeBaseAddress;
|
|
string endpoint = "/api/currentPrograms";
|
|
HttpMethod method = HttpMethod.Post;
|
|
try
|
|
{
|
|
var payload = new
|
|
{
|
|
applicationName = applicationName,
|
|
machineName = userName, // Replacing currentMachineName with userName
|
|
apiKey = this.apiKey
|
|
};
|
|
string response = await Service1.ApiClient.hitApi(baseUrl, endpoint, method, (object)payload);
|
|
Console.WriteLine("Response from server: " + response);
|
|
}
|
|
catch (HttpRequestException ex)
|
|
{
|
|
Console.WriteLine("Network error: " + ex.Message);
|
|
}
|
|
catch (JsonException ex)
|
|
{
|
|
Console.WriteLine("JSON parsing error: " + ex.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Error: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private async Task getPollRate()
|
|
{
|
|
string baseUrl = "https://" + this.homeBaseAddress;
|
|
string endpoint = "/api/pollrate";
|
|
HttpMethod method = HttpMethod.Get;
|
|
try
|
|
{
|
|
string response = await Service1.ApiClient.hitApi(baseUrl, endpoint, method);
|
|
JObject jsonObject = JObject.Parse(response);
|
|
string pollrateString = (string)jsonObject["pollrate"];
|
|
this.pollRate = int.Parse(pollrateString);
|
|
response = (string)null;
|
|
jsonObject = (JObject)null;
|
|
pollrateString = (string)null;
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.Message);
|
|
baseUrl = (string)null;
|
|
endpoint = (string)null;
|
|
method = (HttpMethod)null;
|
|
}
|
|
}
|
|
|
|
public static class ApiClient
|
|
{
|
|
public static async Task<string> hitApi(
|
|
string baseUrl,
|
|
string endpoint,
|
|
HttpMethod method,
|
|
object data = null)
|
|
{
|
|
string str;
|
|
using (HttpClient client = new HttpClient())
|
|
{
|
|
client.BaseAddress = new Uri(baseUrl);
|
|
HttpResponseMessage response;
|
|
if (method == HttpMethod.Get)
|
|
{
|
|
response = await client.GetAsync(endpoint);
|
|
}
|
|
else
|
|
{
|
|
if (!(method == HttpMethod.Post))
|
|
throw new NotSupportedException(string.Format("HTTP method {0} is not supported.", (object)method));
|
|
string jsonData = JsonConvert.SerializeObject(data);
|
|
StringContent content = new StringContent(jsonData, Encoding.UTF8, "application/json");
|
|
response = await client.PostAsync(endpoint, (HttpContent)content);
|
|
jsonData = (string)null;
|
|
content = (StringContent)null;
|
|
}
|
|
response.EnsureSuccessStatusCode();
|
|
str = await response.Content.ReadAsStringAsync();
|
|
}
|
|
return str;
|
|
}
|
|
}
|
|
}
|
|
}
|