1.7 ApiKey value type
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
33
src/FrameProcessor/Domain/ApiKey.cs
Normal file
33
src/FrameProcessor/Domain/ApiKey.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace FrameProcessor.Domain;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps the shared API key. <see cref="Matches"/> uses a constant-time comparison
|
||||
/// over UTF-8 bytes to avoid leaking key length or content via timing side channels.
|
||||
/// </summary>
|
||||
public readonly record struct ApiKey
|
||||
{
|
||||
private readonly string? _value;
|
||||
|
||||
public ApiKey(string value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public string Value => _value ?? string.Empty;
|
||||
|
||||
public bool Matches(string? candidate)
|
||||
{
|
||||
if (candidate is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var expectedBytes = Encoding.UTF8.GetBytes(Value);
|
||||
var candidateBytes = Encoding.UTF8.GetBytes(candidate);
|
||||
return CryptographicOperations.FixedTimeEquals(expectedBytes, candidateBytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user