namespace ZB.MOM.WW.Auth.ApiKeys.SqlServer;
///
/// Options for the shared SQL Server API-key store (section supplied by the host, e.g.
/// ScadaBridge:InboundApi:ApiKeyStore:SqlServer).
///
public sealed class SqlServerApiKeyOptions
{
///
/// Full SQL Server connection string. Required. Never a ${secret:} reference on hosts
/// whose secret store is itself SQL-backed.
///
public string ConnectionString { get; set; } = string.Empty;
/// Schema that owns the three tables. Letters, digits and underscore only (it is interpolated into DDL).
public string Schema { get; set; } = "zbauth";
///
/// Command timeout applied to every store operation. Defaults to 30 seconds — long enough for
/// a contended shared database, short enough that a hung server surfaces as an error rather
/// than stalling a resolve indefinitely.
///
public TimeSpan CommandTimeout { get; set; } = TimeSpan.FromSeconds(30);
/// Fails fast on a blank connection string, an unsafe schema identifier, or a non-positive command timeout.
/// The options are not usable.
public void Validate()
{
if (string.IsNullOrWhiteSpace(ConnectionString))
throw new InvalidOperationException("SQL Server API-key store requires a ConnectionString.");
ValidateIdentifier(Schema);
if (CommandTimeout <= TimeSpan.Zero)
throw new InvalidOperationException($"SQL Server API-key store CommandTimeout must be positive (was {CommandTimeout}).");
}
///
/// Strict allow-list for a SQL identifier that will be interpolated into DDL or query text.
/// Rejects everything that is not [A-Za-z_][A-Za-z0-9_]{0,63} — no brackets, quotes, dots
/// or spaces — so no bracket-escape (]]) trick can break out of the quoting applied at the
/// use site. Uses the ASCII-only character tests deliberately, so homoglyph and full-width
/// look-alikes are rejected rather than accepted as "letters".
///
/// The candidate identifier.
/// The same value, once validated.
/// The value is not a plain identifier.
///
/// Public because is public and must
/// defend itself rather than trust that every caller routed through .
///
public static string ValidateIdentifier(string schemaName)
{
if (string.IsNullOrEmpty(schemaName)
|| schemaName.Length > 64
|| (!char.IsAsciiLetter(schemaName[0]) && schemaName[0] != '_')
|| !schemaName.All(c => char.IsAsciiLetterOrDigit(c) || c == '_'))
{
throw new InvalidOperationException(
$"SQL Server API-key store schema name '{schemaName}' is not a safe identifier.");
}
return schemaName;
}
}