fix: reject legacy SMS auth providers in production

This commit is contained in:
Codex
2026-07-04 00:39:56 +08:00
parent c71768fdb0
commit ca482f7feb
2 changed files with 13 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
import { randomBytes } from 'node:crypto';
import type pg from 'pg';
import { HttpError, type RequestContext } from '../../core/http.js';
import { config as appConfig } from '../../core/config.js';
import { intParam, optionalString, readJsonBody, requiredString, stringParam } from '../../core/request.js';
import { query, queryOne, transaction } from '../../core/db.js';
import {
@@ -390,6 +391,14 @@ function defaultAuthSecretScope(provider: string): SecretScope {
return 'oauth';
}
function assertProductionAuthProviderAllowed(provider: string, status: string) {
if (!appConfig.isProduction || !['active', 'testing'].includes(status)) return;
const normalized = provider.toLowerCase().replace(/[_\s]/g, '-');
if (normalized === 'aliyun' || normalized === 'aliyun-sms' || normalized === 'tencent' || normalized === 'tencent-sms') {
throw new HttpError(400, 'Production SMS auth providers must use aliyun-pnvs', 'PRODUCTION_SMS_PROVIDER_MUST_BE_PNVS');
}
}
function parseSecretScope(value: unknown, fallback: SecretScope): SecretScope {
const candidate = (nullableString(value) || fallback) as SecretScope;
if (!SECRET_SCOPES.has(candidate)) {
@@ -1400,6 +1409,8 @@ export async function upsertAuthProviderRoute(ctx: RequestContext) {
const fallbackScope = defaultAuthSecretScope(provider);
const secretPayload = parseSecretPayload(body, fallbackScope, provider, provider);
const configPublic = objectValue(body.configPublic);
const status = optionalStatus(body.status, AUTH_STATUSES, 'disabled');
assertProductionAuthProviderAllowed(provider, status);
const item = await transaction(async client => {
const secret = secretPayload ? await upsertTenantSecret(client, auth, secretPayload) : null;
@@ -1420,7 +1431,7 @@ export async function upsertAuthProviderRoute(ctx: RequestContext) {
[
auth.tenantId,
provider,
optionalStatus(body.status, AUTH_STATUSES, 'disabled'),
status,
optionalString(body, 'displayName') || null,
publicJsonValue(configPublic),
],