using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using SharedLibraryCore;
using SharedLibraryCore.Interfaces;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using static SharedLibraryCore.Database.Models.EFClient;
using static SharedLibraryCore.GameEvent;
namespace WebfrontCore.Middleware
{
///
/// Facilitates the removal of identity claims when client is demoted
///
internal class ClaimsPermissionRemoval
{
private readonly IManager _manager;
private readonly List _privilegedClientIds;
private readonly RequestDelegate _nextRequest;
public ClaimsPermissionRemoval(RequestDelegate nextRequest, IManager manager)
{
_manager = manager;
_manager.OnGameEventExecuted += OnGameEvent;
_privilegedClientIds = new List();
_nextRequest = nextRequest;
}
///
/// Callback for the game event
///
///
///
private void OnGameEvent(object sender, GameEvent gameEvent)
{
if (gameEvent.Type == EventType.ChangePermission &&
gameEvent.Extra is Permission perm)
{
// we want to remove the claims when the client is demoted
if (perm < Permission.Trusted)
{
lock (_privilegedClientIds)
{
_privilegedClientIds.RemoveAll(id => id == gameEvent.Target.ClientId);
}
}
// and add if promoted
else if (perm > Permission.Trusted &&
!_privilegedClientIds.Contains(gameEvent.Target.ClientId))
{
lock (_privilegedClientIds)
{
_privilegedClientIds.Add(gameEvent.Target.ClientId);
}
}
}
}
public async Task Invoke(HttpContext context)
{
// we want to load the initial list of privileged clients
if (_privilegedClientIds.Count == 0)
{
var ids = (await _manager.GetClientService().GetPrivilegedClients())
.Select(_client => _client.ClientId);
lock (_privilegedClientIds)
{
_privilegedClientIds.AddRange(ids);
}
}
// sid stores the clientId
string claimsId = context.User.Claims.FirstOrDefault(_claim => _claim.Type == ClaimTypes.Sid)?.Value;
if (!string.IsNullOrEmpty(claimsId))
{
int clientId = int.Parse(claimsId);
// they've been removed
if (!_privilegedClientIds.Contains(clientId) && clientId != 1)
{
await context.SignOutAsync();
}
}
await _nextRequest.Invoke(context);
}
}
}