Allow clients to allocate keys from the server

dashboard
Pat Hartl 2023-01-15 20:45:37 -06:00
parent a0e15514e3
commit 6863417736
9 changed files with 198 additions and 31 deletions

View File

@ -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<Key>($"/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<Key>($"/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();
}
}
}

View File

@ -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.");
}
}
};
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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
}
}

View File

@ -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; }
}
}

View File

@ -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<Data.Models.Key> 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);
}
}
}

View File

@ -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<IActionResult> Details(Guid? id)
@ -94,32 +97,14 @@ namespace LANCommander.Controllers
public async Task<IActionResult> Release(Guid id)
{
using (var repo = new Repository<Key>(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 });
}
}
}

View File

@ -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);
}
}
}