26 lines
1.3 KiB
C#
26 lines
1.3 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Security.Cryptography;
|
|
using WebDrop.Core;
|
|
|
|
namespace WebDrop.Api;
|
|
|
|
public sealed record PasskeyCeremony(string Username, string Purpose, string State, string PrfSalt, string? SessionHash, DateTimeOffset Expires);
|
|
public sealed class PasskeyCeremonies
|
|
{
|
|
private readonly ConcurrentDictionary<string, PasskeyCeremony> _pending = new();
|
|
public string Put(PasskeyCeremony ceremony)
|
|
{
|
|
foreach (var entry in _pending) if (entry.Value.Expires <= DateTimeOffset.UtcNow) _pending.TryRemove(entry.Key, out _);
|
|
if (_pending.Count >= 1000) throw new WebDropException(ErrorCode.RateLimited);
|
|
var id = Codec.Encode(RandomNumberGenerator.GetBytes(32));
|
|
_pending[id] = ceremony; return id;
|
|
}
|
|
public PasskeyCeremony Take(string id, string username, string purpose, string? token)
|
|
{
|
|
if (string.IsNullOrEmpty(id) || id.Length > 100 || !_pending.TryRemove(id, out var ceremony) || ceremony.Expires <= DateTimeOffset.UtcNow
|
|
|| ceremony.Username != username || ceremony.Purpose != purpose || ceremony.SessionHash != Hash(token)) throw new WebDropException(ErrorCode.BadRequest);
|
|
return ceremony;
|
|
}
|
|
public static string? Hash(string? token) => token is null ? null : Convert.ToHexString(SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(token)));
|
|
}
|