From 686341773612d96d6b7f35e1d37025ea9b62aabf Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Sun, 15 Jan 2023 20:45:37 -0600 Subject: [PATCH] Allow clients to allocate keys from the server --- .../LANCommanderClient.cs | 51 +++++++++++++++++++ .../LANCommanderLibraryPlugin.cs | 18 ++++++- .../PowerShellRuntime.cs | 18 +++++-- .../Views/Authentication.xaml.cs | 2 +- LANCommander.SDK/Models/Key.cs | 21 ++++++++ LANCommander.SDK/Models/KeyRequest.cs | 14 +++++ .../Controllers/Api/KeysController.cs | 49 ++++++++++++++++++ LANCommander/Controllers/KeysController.cs | 33 ++++-------- LANCommander/Services/KeyService.cs | 23 +++++++++ 9 files changed, 198 insertions(+), 31 deletions(-) create mode 100644 LANCommander.SDK/Models/Key.cs create mode 100644 LANCommander.SDK/Models/KeyRequest.cs create mode 100644 LANCommander/Controllers/Api/KeysController.cs diff --git a/LANCommander.Playnite.Extension/LANCommanderClient.cs b/LANCommander.Playnite.Extension/LANCommanderClient.cs index 55833a8..03f9d34 100644 --- a/LANCommander.Playnite.Extension/LANCommanderClient.cs +++ b/LANCommander.Playnite.Extension/LANCommanderClient.cs @@ -8,6 +8,7 @@ using System.ComponentModel; using System.IO; using System.Linq; using System.Net; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; @@ -129,5 +130,55 @@ namespace LANCommander.PlaynitePlugin { return DownloadRequest($"/api/Archives/Download/{id}", progressHandler, completeHandler); } + + public string GetKey(Guid id) + { + var macAddress = GetMacAddress(); + + var request = new KeyRequest() + { + GameId = id, + MacAddress = macAddress, + ComputerName = Environment.MachineName, + IpAddress = GetIpAddress(), + }; + + var response = PostRequest($"/api/Keys/Get", request); + + return response.Value; + } + + public string GetNewKey(Guid id) + { + var macAddress = GetMacAddress(); + + var request = new KeyRequest() + { + GameId = id, + MacAddress = macAddress, + ComputerName = Environment.MachineName, + IpAddress = GetIpAddress(), + }; + + var response = PostRequest($"/api/Keys/Allocate/{id}", request); + + if (response == null) + return String.Empty; + + return response.Value; + } + + private string GetMacAddress() + { + return NetworkInterface.GetAllNetworkInterfaces() + .Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback) + .Select(nic => nic.GetPhysicalAddress().ToString()) + .FirstOrDefault(); + } + + private string GetIpAddress() + { + return Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString(); + } } } diff --git a/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs b/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs index 093096a..a066de4 100644 --- a/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs +++ b/LANCommander.Playnite.Extension/LANCommanderLibraryPlugin.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -171,7 +172,22 @@ namespace LANCommander.PlaynitePlugin Description = "Change Game Key", Action = (keyChangeArgs) => { - PowerShellRuntime.RunScript(keyChangeArgs.Games.First(), SDK.Enums.ScriptType.KeyChange); + Guid gameId; + + if (Guid.TryParse(keyChangeArgs.Games.First().GameId, out gameId)) + { + // NUKIEEEE + var newKey = LANCommander.GetNewKey(gameId); + + if (String.IsNullOrEmpty(newKey)) + PlayniteApi.Dialogs.ShowErrorMessage("There are no more keys available on the server.", "No Keys Available"); + else + PowerShellRuntime.RunScript(keyChangeArgs.Games.First(), SDK.Enums.ScriptType.KeyChange, $@"""{newKey}"""); + } + else + { + PlayniteApi.Dialogs.ShowErrorMessage("This game could not be found on the server. Your game may be corrupted."); + } } }; } diff --git a/LANCommander.Playnite.Extension/PowerShellRuntime.cs b/LANCommander.Playnite.Extension/PowerShellRuntime.cs index 050bc28..59fc06f 100644 --- a/LANCommander.Playnite.Extension/PowerShellRuntime.cs +++ b/LANCommander.Playnite.Extension/PowerShellRuntime.cs @@ -13,27 +13,35 @@ namespace LANCommander.PlaynitePlugin { internal class PowerShellRuntime { - public void RunScript(string path) + public void RunScript(string path, string arguments = null) { var process = new Process(); process.StartInfo.FileName = "powershell.exe"; process.StartInfo.Arguments = $@"-File ""{path}"""; + + if (arguments != null) + process.StartInfo.Arguments += " " + arguments; + process.Start(); process.WaitForExit(); } - public void RunScriptAsAdmin(string path) + public void RunScriptAsAdmin(string path, string arguments = null) { var process = new Process(); process.StartInfo.FileName = "powershell.exe"; process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runas"; process.StartInfo.Arguments = $@"-ExecutionPolicy Unrestricted -File ""{path}"""; + + if (arguments != null) + process.StartInfo.Arguments += " " + arguments; + process.Start(); process.WaitForExit(); } - public void RunScript(Game game, ScriptType type) + public void RunScript(Game game, ScriptType type, string arguments = null) { var path = GetScriptFilePath(game, type); @@ -42,9 +50,9 @@ namespace LANCommander.PlaynitePlugin var contents = File.ReadAllText(path); if (contents.StartsWith("# Requires Admin")) - RunScriptAsAdmin(path); + RunScriptAsAdmin(path, arguments); else - RunScript(path); + RunScript(path, arguments); } } diff --git a/LANCommander.Playnite.Extension/Views/Authentication.xaml.cs b/LANCommander.Playnite.Extension/Views/Authentication.xaml.cs index c789e50..91d267b 100644 --- a/LANCommander.Playnite.Extension/Views/Authentication.xaml.cs +++ b/LANCommander.Playnite.Extension/Views/Authentication.xaml.cs @@ -31,7 +31,7 @@ namespace LANCommander.PlaynitePlugin.Views private void TextBox_KeyDown(object sender, KeyEventArgs e) { - if (e.Key == Key.Enter || e.Key == Key.Return) + if (e.Key == System.Windows.Input.Key.Enter || e.Key == System.Windows.Input.Key.Return) { Authenticate(); } diff --git a/LANCommander.SDK/Models/Key.cs b/LANCommander.SDK/Models/Key.cs new file mode 100644 index 0000000..01c6834 --- /dev/null +++ b/LANCommander.SDK/Models/Key.cs @@ -0,0 +1,21 @@ +using System; + +namespace LANCommander.SDK.Models +{ + public class Key : BaseModel + { + public string Value { get; set; } + public virtual Game Game { get; set; } + public KeyAllocationMethod AllocationMethod { get; set; } + public string ClaimedByMacAddress { get; set; } + public string ClaimedByIpv4Address { get; set; } + public string ClaimedByComputerName { get; set; } + public DateTime? ClaimedOn { get; set; } + } + + public enum KeyAllocationMethod + { + UserAccount, + MacAddress + } +} diff --git a/LANCommander.SDK/Models/KeyRequest.cs b/LANCommander.SDK/Models/KeyRequest.cs new file mode 100644 index 0000000..a1beb11 --- /dev/null +++ b/LANCommander.SDK/Models/KeyRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.Models +{ + public class KeyRequest + { + public Guid GameId { get; set; } + public string MacAddress { get; set; } + public string IpAddress { get; set; } + public string ComputerName { get; set; } + } +} diff --git a/LANCommander/Controllers/Api/KeysController.cs b/LANCommander/Controllers/Api/KeysController.cs new file mode 100644 index 0000000..36d44fd --- /dev/null +++ b/LANCommander/Controllers/Api/KeysController.cs @@ -0,0 +1,49 @@ +using LANCommander.Data; +using LANCommander.Data.Models; +using LANCommander.Extensions; +using LANCommander.SDK.Models; +using LANCommander.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace LANCommander.Controllers.Api +{ + [Authorize(AuthenticationSchemes = "Bearer")] + [Route("api/[controller]")] + [ApiController] + public class KeysController : ControllerBase + { + private KeyService KeyService; + + public KeysController(KeyService keyService) + { + KeyService = keyService; + } + + [HttpPost] + public Data.Models.Key Get(KeyRequest keyRequest) + { + return KeyService.Get(k => k.AllocationMethod == Data.Models.KeyAllocationMethod.MacAddress && k.ClaimedByMacAddress == keyRequest.MacAddress).First(); + } + + [HttpPost("Allocate/{id}")] + public async Task Allocate(Guid id, KeyRequest keyRequest) + { + var existing = KeyService.Get(k => k.Game.Id == id && k.AllocationMethod == Data.Models.KeyAllocationMethod.MacAddress && keyRequest.MacAddress == keyRequest.MacAddress).FirstOrDefault(); + + if (existing != null) + await KeyService.Release(existing.Id); + + var availableKey = KeyService.Get(k => + (k.AllocationMethod == Data.Models.KeyAllocationMethod.MacAddress && String.IsNullOrWhiteSpace(k.ClaimedByMacAddress)) + || + (k.AllocationMethod == Data.Models.KeyAllocationMethod.UserAccount && k.ClaimedByUser == null)) + .FirstOrDefault(); + + if (availableKey == null) + return null; + + return await KeyService.Allocate(availableKey, keyRequest.MacAddress); + } + } +} diff --git a/LANCommander/Controllers/KeysController.cs b/LANCommander/Controllers/KeysController.cs index c2013bf..b62f42f 100644 --- a/LANCommander/Controllers/KeysController.cs +++ b/LANCommander/Controllers/KeysController.cs @@ -9,6 +9,7 @@ using LANCommander.Data; using LANCommander.Data.Models; using Microsoft.AspNetCore.Authorization; using LANCommander.Models; +using LANCommander.Services; namespace LANCommander.Controllers { @@ -16,10 +17,12 @@ namespace LANCommander.Controllers public class KeysController : Controller { private readonly DatabaseContext Context; + private readonly KeyService KeyService; - public KeysController(DatabaseContext context) + public KeysController(DatabaseContext context, KeyService keyService) { Context = context; + KeyService = keyService; } public async Task Details(Guid? id) @@ -94,32 +97,14 @@ namespace LANCommander.Controllers public async Task Release(Guid id) { - using (var repo = new Repository(Context, HttpContext)) - { - var key = await repo.Find(id); + var existing = await KeyService.Get(id); - if (key == null) - return NotFound(); + if (existing == null) + return NotFound(); - switch (key.AllocationMethod) - { - case KeyAllocationMethod.UserAccount: - key.ClaimedByUser = null; - key.ClaimedOn = null; - break; + await KeyService.Release(id); - case KeyAllocationMethod.MacAddress: - key.ClaimedByMacAddress = ""; - key.ClaimedOn = null; - break; - } - - repo.Update(key); - - await repo.SaveChanges(); - - return RedirectToAction("Details", "Keys", new { id = key.Game.Id }); - } + return RedirectToAction("Details", "Keys", new { id = existing.Game.Id }); } } } diff --git a/LANCommander/Services/KeyService.cs b/LANCommander/Services/KeyService.cs index 0fcd661..d331bac 100644 --- a/LANCommander/Services/KeyService.cs +++ b/LANCommander/Services/KeyService.cs @@ -28,5 +28,28 @@ namespace LANCommander.Services return key; } + + public async Task Release(Guid id) + { + var key = await Get(id); + + if (key == null) + return; + + switch (key.AllocationMethod) + { + case KeyAllocationMethod.UserAccount: + key.ClaimedByUser = null; + key.ClaimedOn = null; + break; + + case KeyAllocationMethod.MacAddress: + key.ClaimedByMacAddress = ""; + key.ClaimedOn = null; + break; + } + + await Update(key); + } } }