Gaps fill up, fixes, ui restructuring
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Telemetry.Federation.Consent;
|
||||
|
||||
public sealed class ConsentManager : IConsentManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, ConsentEntry> _consents = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public ConsentManager(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public Task<ConsentState> GetConsentStateAsync(string tenantId, CancellationToken ct = default)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
if (!_consents.TryGetValue(tenantId, out var entry))
|
||||
{
|
||||
return Task.FromResult(new ConsentState(
|
||||
Granted: false,
|
||||
GrantedBy: null,
|
||||
GrantedAt: null,
|
||||
ExpiresAt: null,
|
||||
DsseDigest: null));
|
||||
}
|
||||
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
if (entry.ExpiresAt.HasValue && now >= entry.ExpiresAt.Value)
|
||||
{
|
||||
_consents.TryRemove(tenantId, out _);
|
||||
return Task.FromResult(new ConsentState(
|
||||
Granted: false,
|
||||
GrantedBy: null,
|
||||
GrantedAt: null,
|
||||
ExpiresAt: null,
|
||||
DsseDigest: null));
|
||||
}
|
||||
|
||||
return Task.FromResult(new ConsentState(
|
||||
Granted: true,
|
||||
GrantedBy: entry.GrantedBy,
|
||||
GrantedAt: entry.GrantedAt,
|
||||
ExpiresAt: entry.ExpiresAt,
|
||||
DsseDigest: entry.DsseDigest));
|
||||
}
|
||||
|
||||
public Task<ConsentProof> GrantConsentAsync(
|
||||
string tenantId,
|
||||
string grantedBy,
|
||||
TimeSpan? ttl = null,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var expiresAt = ttl.HasValue ? now + ttl.Value : (DateTimeOffset?)null;
|
||||
|
||||
var payload = JsonSerializer.SerializeToUtf8Bytes(new
|
||||
{
|
||||
tenantId,
|
||||
grantedBy,
|
||||
grantedAt = now,
|
||||
expiresAt,
|
||||
type = "stella.ops/federatedConsent@v1"
|
||||
});
|
||||
|
||||
var digest = ComputeDigest(payload);
|
||||
var envelope = payload; // Placeholder: real DSSE envelope wraps with signature
|
||||
|
||||
var entry = new ConsentEntry(tenantId, grantedBy, now, expiresAt, digest);
|
||||
_consents[tenantId] = entry;
|
||||
|
||||
return Task.FromResult(new ConsentProof(
|
||||
TenantId: tenantId,
|
||||
GrantedBy: grantedBy,
|
||||
GrantedAt: now,
|
||||
ExpiresAt: expiresAt,
|
||||
DsseDigest: digest,
|
||||
Envelope: envelope));
|
||||
}
|
||||
|
||||
public Task RevokeConsentAsync(string tenantId, string revokedBy, CancellationToken ct = default)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
_consents.TryRemove(tenantId, out _);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static string ComputeDigest(byte[] payload)
|
||||
{
|
||||
var hash = SHA256.HashData(payload);
|
||||
return $"sha256:{Convert.ToHexStringLower(hash)}";
|
||||
}
|
||||
|
||||
private sealed record ConsentEntry(
|
||||
string TenantId,
|
||||
string GrantedBy,
|
||||
DateTimeOffset GrantedAt,
|
||||
DateTimeOffset? ExpiresAt,
|
||||
string DsseDigest);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace StellaOps.Telemetry.Federation.Consent;
|
||||
|
||||
public interface IConsentManager
|
||||
{
|
||||
Task<ConsentState> GetConsentStateAsync(string tenantId, CancellationToken ct = default);
|
||||
Task<ConsentProof> GrantConsentAsync(string tenantId, string grantedBy, TimeSpan? ttl = null, CancellationToken ct = default);
|
||||
Task RevokeConsentAsync(string tenantId, string revokedBy, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
public sealed record ConsentState(
|
||||
bool Granted,
|
||||
string? GrantedBy,
|
||||
DateTimeOffset? GrantedAt,
|
||||
DateTimeOffset? ExpiresAt,
|
||||
string? DsseDigest);
|
||||
|
||||
public sealed record ConsentProof(
|
||||
string TenantId,
|
||||
string GrantedBy,
|
||||
DateTimeOffset GrantedAt,
|
||||
DateTimeOffset? ExpiresAt,
|
||||
string DsseDigest,
|
||||
byte[] Envelope);
|
||||
Reference in New Issue
Block a user