Files
Antifraude.Net/Antifraude.Net/ApiDenuncias/Services/GlobalLeaksSessionStore.cs
Pedro 6f9392f3d0 cambiso en denuncias, mejoras de 30 min en inicio de sesion e incorporacion de grupos
Cambiso de certificado en registro de personal para aañadir el origen
2026-07-27 08:46:41 +02:00

270 lines
8.0 KiB
C#

using System.Text;
using System.Text.Json;
using System.Security.Cryptography;
using GestionaDenuncias.Shared.Models;
using Microsoft.AspNetCore.DataProtection;
namespace ApiDenuncias.Services;
public sealed class GlobalLeaksSessionStore
{
private const string RootPath = @"C:\GestionaDenuncias\.gl-auth";
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web)
{
WriteIndented = false,
};
private readonly SemaphoreSlim _gate = new(1, 1);
private readonly IDataProtector _protector;
public GlobalLeaksSessionStore(IDataProtectionProvider dataProtectionProvider)
{
_protector = dataProtectionProvider.CreateProtector("GestionaDenunciasAN.GlobalLeaksSessionStore");
}
public async Task<GlobalLeaksStoredSession?> GetAsync(string username, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(username))
{
return null;
}
var path = GetFilePath(username);
await _gate.WaitAsync(cancellationToken);
try
{
return await ReadUnsafeAsync(path, cancellationToken);
}
finally
{
_gate.Release();
}
}
public async Task SaveAsync(
string username,
string password,
string sessionId,
string? role,
string? dpopPrivateKey,
GlobalLeaksProofOfWorkToken? proofOfWorkToken,
DateTimeOffset? sessionExpiresAtUtc,
CancellationToken cancellationToken = default)
{
var now = DateTimeOffset.UtcNow;
var data = new GlobalLeaksStoredSession
{
Username = username,
Password = password,
SessionId = sessionId,
Role = role,
DpopPrivateKey = dpopPrivateKey,
ProofOfWorkToken = proofOfWorkToken,
SessionExpiresAtUtc = sessionExpiresAtUtc,
LastKeepAliveAtUtc = now,
UpdatedAt = now,
};
await WriteAsync(data, cancellationToken);
}
public async Task UpdateSessionAsync(
string username,
string sessionId,
string? role,
string? dpopPrivateKey,
GlobalLeaksProofOfWorkToken? proofOfWorkToken,
DateTimeOffset? sessionExpiresAtUtc,
CancellationToken cancellationToken = default)
{
var path = GetFilePath(username);
await _gate.WaitAsync(cancellationToken);
try
{
var current = await ReadUnsafeAsync(path, cancellationToken)
?? throw new InvalidOperationException("No hay credenciales guardadas para este usuario.");
var now = DateTimeOffset.UtcNow;
current.SessionId = sessionId;
current.Role = role;
current.DpopPrivateKey = dpopPrivateKey;
current.ProofOfWorkToken = proofOfWorkToken;
current.SessionExpiresAtUtc = sessionExpiresAtUtc;
current.LastKeepAliveAtUtc = now;
current.UpdatedAt = now;
await WriteUnsafeAsync(path, current, cancellationToken);
}
finally
{
_gate.Release();
}
}
public async Task<bool> UpdateKeepAliveAsync(
string username,
string expectedSessionId,
GlobalLeaksProofOfWorkToken proofOfWorkToken,
DateTimeOffset? sessionExpiresAtUtc,
CancellationToken cancellationToken = default)
{
var path = GetFilePath(username);
await _gate.WaitAsync(cancellationToken);
try
{
var current = await ReadUnsafeAsync(path, cancellationToken);
if (current is null ||
!string.Equals(current.SessionId, expectedSessionId, StringComparison.Ordinal))
{
return false;
}
var now = DateTimeOffset.UtcNow;
current.ProofOfWorkToken = proofOfWorkToken;
current.SessionExpiresAtUtc = sessionExpiresAtUtc;
current.LastKeepAliveAtUtc = now;
current.UpdatedAt = now;
await WriteUnsafeAsync(path, current, cancellationToken);
return true;
}
finally
{
_gate.Release();
}
}
public async Task ClearSessionAsync(string username, CancellationToken cancellationToken = default)
{
var path = GetFilePath(username);
await _gate.WaitAsync(cancellationToken);
try
{
var current = await ReadUnsafeAsync(path, cancellationToken);
if (current is null)
{
return;
}
ClearSessionValues(current);
await WriteUnsafeAsync(path, current, cancellationToken);
}
finally
{
_gate.Release();
}
}
public async Task<bool> ClearSessionIfMatchesAsync(
string username,
string expectedSessionId,
CancellationToken cancellationToken = default)
{
var path = GetFilePath(username);
await _gate.WaitAsync(cancellationToken);
try
{
var current = await ReadUnsafeAsync(path, cancellationToken);
if (current is null ||
!string.Equals(current.SessionId, expectedSessionId, StringComparison.Ordinal))
{
return false;
}
ClearSessionValues(current);
await WriteUnsafeAsync(path, current, cancellationToken);
return true;
}
finally
{
_gate.Release();
}
}
public async Task DeleteAsync(string username, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(username))
{
return;
}
var path = GetFilePath(username);
await _gate.WaitAsync(cancellationToken);
try
{
if (File.Exists(path))
{
File.Delete(path);
}
}
finally
{
_gate.Release();
}
}
private async Task WriteAsync(GlobalLeaksStoredSession data, CancellationToken cancellationToken)
{
var path = GetFilePath(data.Username);
await _gate.WaitAsync(cancellationToken);
try
{
await WriteUnsafeAsync(path, data, cancellationToken);
}
finally
{
_gate.Release();
}
}
private static string GetFilePath(string username)
{
Directory.CreateDirectory(RootPath);
var normalized = username.Trim().ToLowerInvariant();
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(normalized));
return Path.Combine(RootPath, $"{Convert.ToHexString(hash).ToLowerInvariant()}.bin");
}
private async Task<GlobalLeaksStoredSession?> ReadUnsafeAsync(
string path,
CancellationToken cancellationToken)
{
if (!File.Exists(path))
{
return null;
}
var protectedBytes = await File.ReadAllBytesAsync(path, cancellationToken);
var protectedBase64 = Encoding.UTF8.GetString(protectedBytes);
var json = _protector.Unprotect(protectedBase64);
return JsonSerializer.Deserialize<GlobalLeaksStoredSession>(json, JsonOptions);
}
private async Task WriteUnsafeAsync(
string path,
GlobalLeaksStoredSession data,
CancellationToken cancellationToken)
{
Directory.CreateDirectory(RootPath);
var json = JsonSerializer.Serialize(data, JsonOptions);
var protectedValue = _protector.Protect(json);
var protectedBytes = Encoding.UTF8.GetBytes(protectedValue);
await File.WriteAllBytesAsync(path, protectedBytes, cancellationToken);
}
private static void ClearSessionValues(GlobalLeaksStoredSession session)
{
session.SessionId = null;
session.DpopPrivateKey = null;
session.ProofOfWorkToken = null;
session.SessionExpiresAtUtc = null;
session.LastKeepAliveAtUtc = null;
session.UpdatedAt = DateTimeOffset.UtcNow;
}
}