Add secure administrator operations console

Provide TOTP-authenticated, role-controlled user and credit workflows with paginated audit data and SQL-backed statistics so operations can manage growth safely.
This commit is contained in:
Rocky
2026-08-17 15:20:34 +08:00
parent 676bfd2451
commit 1a9c518f96
76 changed files with 14602 additions and 3 deletions
@@ -3,6 +3,7 @@ package com.osglab.account.config
import io.ktor.server.config.ApplicationConfig
import java.net.URI
import java.util.Base64
import java.util.UUID
data class AppConfig(
val environment: Environment,
@@ -17,6 +18,7 @@ data class AppConfig(
val credits: CreditsConfig,
val providers: ProvidersConfig,
val integrity: IntegrityConfig,
val admin: AdminConfig = AdminConfig(),
) {
val isProduction: Boolean = environment == Environment.PRODUCTION
@@ -119,6 +121,41 @@ data class AppConfig(
300,
),
)
val adminEnabled = config.booleanOrDefault("app.admin.enabled", false)
val adminBootstrapEnabled = config.booleanOrDefault(
"app.admin.bootstrapEnabled",
false,
)
require(!adminBootstrapEnabled || adminEnabled) {
"app.admin.bootstrapEnabled requires app.admin.enabled"
}
val admin = AdminConfig(
enabled = adminEnabled,
bootstrapEnabled = adminBootstrapEnabled,
bootstrapOperatorId = config.optionalValue("app.admin.bootstrapOperatorId")
?.let {
runCatching { UUID.fromString(it) }.getOrElse { cause ->
throw ConfigValidationException(
"app.admin.bootstrapOperatorId must be a UUID",
cause,
)
}
},
bootstrapUsername = config.optionalValue("app.admin.bootstrapUsername"),
bootstrapPasswordHash = config.optionalLiteralSecret(
"app.admin.bootstrapPasswordHash",
production && adminBootstrapEnabled,
),
bootstrapTotpSecretBase32 = config.optionalSecret(
"app.admin.bootstrapTotpSecretBase32",
production && adminBootstrapEnabled,
),
sessionHours = config.positiveLong("app.admin.sessionHours", 8),
maximumManualGrant = config.positiveLong(
"app.admin.maximumManualGrant",
100_000,
),
)
require(session.hmacSecret.size >= MIN_HMAC_SECRET_BYTES) {
"app.session.secret must contain at least $MIN_HMAC_SECRET_BYTES bytes"
@@ -199,6 +236,26 @@ data class AppConfig(
require(!production || apple.clientId == APP_ATTEST_BUNDLE_ID) {
"Production Apple client ID must be $APP_ATTEST_BUNDLE_ID"
}
require(admin.sessionHours in 1..24) {
"app.admin.sessionHours must be between 1 and 24"
}
require(admin.maximumManualGrant in 1..100_000_000) {
"app.admin.maximumManualGrant must be between 1 and 100000000"
}
if (admin.bootstrapEnabled) {
requireNotNull(admin.bootstrapOperatorId) {
"app.admin.bootstrapOperatorId is required when admin bootstrap is enabled"
}
require(!admin.bootstrapUsername.isNullOrBlank()) {
"app.admin.bootstrapUsername is required when admin bootstrap is enabled"
}
require(!admin.bootstrapPasswordHash.isNullOrBlank()) {
"app.admin.bootstrapPasswordHash is required when admin bootstrap is enabled"
}
require(!admin.bootstrapTotpSecretBase32.isNullOrBlank()) {
"app.admin.bootstrapTotpSecretBase32 is required when admin bootstrap is enabled"
}
}
if (production) {
requireExactAppleEndpoint(apple.jwksUrl, "/auth/keys", "JWKS")
requireExactAppleEndpoint(apple.tokenUrl, "/auth/token", "token")
@@ -239,6 +296,7 @@ data class AppConfig(
credits = credits,
providers = providers,
integrity = integrity,
admin = admin,
)
}
}
@@ -335,6 +393,17 @@ data class IntegrityConfig(
val appAttestBundleId: String = APP_ATTEST_BUNDLE_ID,
)
data class AdminConfig(
val enabled: Boolean = false,
val bootstrapEnabled: Boolean = false,
val bootstrapOperatorId: UUID? = null,
val bootstrapUsername: String? = null,
val bootstrapPasswordHash: String? = null,
val bootstrapTotpSecretBase32: String? = null,
val sessionHours: Long = 8,
val maximumManualGrant: Long = 100_000,
)
enum class IntegrityPolicy {
MONITOR,
ENFORCE;
@@ -393,6 +462,19 @@ private fun ApplicationConfig.optionalSecret(path: String, production: Boolean):
return value?.takeUnless(String::isPlaceholder)
}
private fun ApplicationConfig.optionalLiteralSecret(path: String, production: Boolean): String? {
val value = propertyOrNull(path)?.getString()?.trim()?.takeIf(String::isNotEmpty)
val placeholder = value?.let {
it.contains("replace-with", ignoreCase = true) ||
it.contains("change-me", ignoreCase = true) ||
it.contains("\${")
} == true
if (production && (value == null || placeholder)) {
throw ConfigValidationException("Production secret is missing or uses a placeholder: $path")
}
return value?.takeUnless { placeholder }
}
private fun String.isPlaceholder(): Boolean =
PLACEHOLDER_MARKERS.any { marker -> contains(marker, ignoreCase = true) }
@@ -419,6 +501,15 @@ private fun ApplicationConfig.boolean(path: String): Boolean =
}
}
private fun ApplicationConfig.booleanOrDefault(path: String, default: Boolean): Boolean =
propertyOrNull(path)?.getString()?.trim()?.takeIf(String::isNotEmpty)?.let {
when (it.lowercase()) {
"true" -> true
"false" -> false
else -> throw ConfigValidationException("$path must be true or false")
}
} ?: default
private fun ApplicationConfig.base64Key(path: String, production: Boolean): ByteArray {
val encoded = secret(path, production)
return try {