Allow clients to allocate keys from the server

This commit is contained in:
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.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -129,5 +130,55 @@ namespace LANCommander.PlaynitePlugin
{ {
return DownloadRequest($"/api/Archives/Download/{id}", progressHandler, completeHandler); 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.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -171,7 +172,22 @@ namespace LANCommander.PlaynitePlugin
Description = "Change Game Key", Description = "Change Game Key",
Action = (keyChangeArgs) => 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 internal class PowerShellRuntime
{ {
public void RunScript(string path) public void RunScript(string path, string arguments = null)
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = "powershell.exe"; process.StartInfo.FileName = "powershell.exe";
process.StartInfo.Arguments = $@"-File ""{path}"""; process.StartInfo.Arguments = $@"-File ""{path}""";
if (arguments != null)
process.StartInfo.Arguments += " " + arguments;
process.Start(); process.Start();
process.WaitForExit(); process.WaitForExit();
} }
public void RunScriptAsAdmin(string path) public void RunScriptAsAdmin(string path, string arguments = null)
{ {
var process = new Process(); var process = new Process();
process.StartInfo.FileName = "powershell.exe"; process.StartInfo.FileName = "powershell.exe";
process.StartInfo.UseShellExecute = true; process.StartInfo.UseShellExecute = true;
process.StartInfo.Verb = "runas"; process.StartInfo.Verb = "runas";
process.StartInfo.Arguments = $@"-ExecutionPolicy Unrestricted -File ""{path}"""; process.StartInfo.Arguments = $@"-ExecutionPolicy Unrestricted -File ""{path}""";
if (arguments != null)
process.StartInfo.Arguments += " " + arguments;
process.Start(); process.Start();
process.WaitForExit(); process.WaitForExit();
} }
public void RunScript(Game game, ScriptType type) public void RunScript(Game game, ScriptType type, string arguments = null)
{ {
var path = GetScriptFilePath(game, type); var path = GetScriptFilePath(game, type);
@ -42,9 +50,9 @@ namespace LANCommander.PlaynitePlugin
var contents = File.ReadAllText(path); var contents = File.ReadAllText(path);
if (contents.StartsWith("# Requires Admin")) if (contents.StartsWith("# Requires Admin"))
RunScriptAsAdmin(path); RunScriptAsAdmin(path, arguments);
else else
RunScript(path); RunScript(path, arguments);
} }
} }

View file

@ -31,7 +31,7 @@ namespace LANCommander.PlaynitePlugin.Views
private void TextBox_KeyDown(object sender, KeyEventArgs e) 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(); 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 LANCommander.Data.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using LANCommander.Models; using LANCommander.Models;
using LANCommander.Services;
namespace LANCommander.Controllers namespace LANCommander.Controllers
{ {
@ -16,10 +17,12 @@ namespace LANCommander.Controllers
public class KeysController : Controller public class KeysController : Controller
{ {
private readonly DatabaseContext Context; private readonly DatabaseContext Context;
private readonly KeyService KeyService;
public KeysController(DatabaseContext context) public KeysController(DatabaseContext context, KeyService keyService)
{ {
Context = context; Context = context;
KeyService = keyService;
} }
public async Task<IActionResult> Details(Guid? id) public async Task<IActionResult> Details(Guid? id)
@ -94,32 +97,14 @@ namespace LANCommander.Controllers
public async Task<IActionResult> Release(Guid id) public async Task<IActionResult> Release(Guid id)
{ {
using (var repo = new Repository<Key>(Context, HttpContext)) var existing = await KeyService.Get(id);
{
var key = await repo.Find(id);
if (key == null) if (existing == null)
return NotFound(); return NotFound();
switch (key.AllocationMethod) await KeyService.Release(id);
{
case KeyAllocationMethod.UserAccount:
key.ClaimedByUser = null;
key.ClaimedOn = null;
break;
case KeyAllocationMethod.MacAddress: return RedirectToAction("Details", "Keys", new { id = existing.Game.Id });
key.ClaimedByMacAddress = "";
key.ClaimedOn = null;
break;
}
repo.Update(key);
await repo.SaveChanges();
return RedirectToAction("Details", "Keys", new { id = key.Game.Id });
}
} }
} }
} }

View file

@ -28,5 +28,28 @@ namespace LANCommander.Services
return key; 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);
}
} }
} }