1eb6e972b0
Bulk CommentChecker pass: fills in <param>/<inheritdoc> tags on public APIs across all 23 src/ projects so the doc-coverage gate is green. Also adds a Sister Projects section to CLAUDE.md pointing at the MxAccess Gateway and OtOpcUa sibling repos, and gitignores local credential captures (*login*.txt) and the wonder-app-vd03 deploy/ artifacts.
69 lines
2.9 KiB
C#
69 lines
2.9 KiB
C#
using ScadaLink.Commons.Types.InboundApi;
|
|
|
|
namespace ScadaLink.Commons.Entities.InboundApi;
|
|
|
|
/// <summary>
|
|
/// An inbound-API bearer credential. Per ConfigurationDatabase-012 the plaintext key
|
|
/// is never persisted: the entity stores only <see cref="KeyHash"/>, a deterministic
|
|
/// keyed hash of the key (HMAC-SHA256 with a server-side pepper). The plaintext is
|
|
/// generated at creation, shown to the operator exactly once, and then discarded.
|
|
/// </summary>
|
|
public class ApiKey
|
|
{
|
|
/// <summary>Database primary key.</summary>
|
|
public int Id { get; set; }
|
|
/// <summary>Display name for the API key.</summary>
|
|
public string Name { get; set; }
|
|
|
|
/// <summary>
|
|
/// Deterministic keyed hash of the API key value. This is the only form of the
|
|
/// credential persisted; the plaintext key is never stored. Authentication hashes
|
|
/// the presented candidate with the same scheme and compares against this value.
|
|
/// </summary>
|
|
public string KeyHash { get; set; }
|
|
|
|
/// <summary>When false, the key is rejected even if the hash matches.</summary>
|
|
public bool IsEnabled { get; set; }
|
|
|
|
/// <summary>
|
|
/// Creates an API key from a plaintext value, immediately hashing it with the
|
|
/// unpeppered default hasher (<see cref="ApiKeyHasher.Default"/>) so the entity
|
|
/// never holds the plaintext. Production code paths that have a configured pepper
|
|
/// should use <see cref="FromHash(string, string)"/> with a peppered hash instead.
|
|
/// </summary>
|
|
/// <param name="name">Display name for the API key.</param>
|
|
/// <param name="keyValue">Plaintext key value; hashed immediately and never stored.</param>
|
|
public ApiKey(string name, string keyValue)
|
|
{
|
|
Name = name ?? throw new ArgumentNullException(nameof(name));
|
|
if (keyValue is null) throw new ArgumentNullException(nameof(keyValue));
|
|
KeyHash = ApiKeyHasher.Default.Hash(keyValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parameterless constructor for the EF Core materializer. Application code uses
|
|
/// <see cref="ApiKey(string, string)"/> or <see cref="FromHash(string, string)"/>.
|
|
/// </summary>
|
|
private ApiKey()
|
|
{
|
|
Name = string.Empty;
|
|
KeyHash = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an API key from an already-computed key hash. Used by the creation
|
|
/// path, which generates a random key, hashes it with the configured (peppered)
|
|
/// <see cref="IApiKeyHasher"/>, and stores only the resulting hash.
|
|
/// </summary>
|
|
/// <param name="name">Display name for the API key.</param>
|
|
/// <param name="keyHash">Pre-computed keyed hash of the API key value.</param>
|
|
public static ApiKey FromHash(string name, string keyHash)
|
|
{
|
|
return new ApiKey
|
|
{
|
|
Name = name ?? throw new ArgumentNullException(nameof(name)),
|
|
KeyHash = keyHash ?? throw new ArgumentNullException(nameof(keyHash)),
|
|
};
|
|
}
|
|
}
|