using System.Security.Cryptography;
using Microsoft.AspNetCore.Identity;
using SameBeat.Application.Interfejsy;
using SameBeat.Domain.Encje;
namespace SameBeat.Infrastructure.Autoryzacja;
///
/// Implementacja oparta na tym samym Microsoft.AspNetCore.Identity.PasswordHasher (PBKDF2) co
/// UslugaHaszowaniaHasel -- tylko sparametryzowana encja to UczestnikOczekujacy zamiast Uzytkownik.
/// Sekret jawny generujemy tu, nie w domenie -- RandomNumberGenerator to szczegol implementacyjny
/// infrastruktury, tak samo jak PasswordHasher.
///
public class UslugaHaszowaniaSekretowSesji : IUslugaHaszowaniaSekretowSesji
{
// Min. 32 bajty (256 bitow) losowosci -- wymog bezpieczenstwa dla sekretu sesji uczestnika.
private const int DlugoscSekretuBajty = 32;
private readonly PasswordHasher _hasher = new();
public string WygenerujSekret()
{
var bajty = RandomNumberGenerator.GetBytes(DlugoscSekretuBajty);
return ZakodujBase64Url(bajty);
}
public string Haszuj(UczestnikOczekujacy uczestnik, string sekretJawny) => _hasher.HashPassword(uczestnik, sekretJawny);
public WynikWeryfikacjiHasla Weryfikuj(UczestnikOczekujacy uczestnik, string sekretHash, string sekretJawny)
{
var wynik = _hasher.VerifyHashedPassword(uczestnik, sekretHash, sekretJawny);
return wynik switch
{
PasswordVerificationResult.Failed => WynikWeryfikacjiHasla.Niepoprawne,
PasswordVerificationResult.Success => WynikWeryfikacjiHasla.Poprawne,
PasswordVerificationResult.SuccessRehashNeeded => WynikWeryfikacjiHasla.PoprawneWymagaRehaszowania,
_ => WynikWeryfikacjiHasla.Niepoprawne
};
}
// Base64Url (RFC 4648 ยง5) recznie, zeby nie wciagac dodatkowej zaleznosci -- standardowy Base64
// z '+'/'/' zamienionymi na '-'/'_' i bez wyrownania '='.
private static string ZakodujBase64Url(byte[] bajty) =>
Convert.ToBase64String(bajty).TrimEnd('=').Replace('+', '-').Replace('/', '_');
}