feat(api): add account workspaces and signed content events

This commit is contained in:
justme committed 2026-10-14 04:05:30 +08:00
1 parent 937b774a93
commit 7b8d61d1ba
63 files changed
+5407 -370

No files matched your search

@@ -0,0 +1,25 @@
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)));
}