Merge branch 'master' of http://82.157.175.59:3000/GenarrativeAI/Genarrative
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-18 17:01:59 +08:00
14 changed files with 321 additions and 60 deletions

View File

@@ -0,0 +1,53 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import pino from 'pino';
import type { AppConfig } from '../config.js';
import { createSmsVerificationService } from './smsVerificationService.js';
function createAliyunSmsConfig(): AppConfig {
return {
smsAuth: {
enabled: true,
provider: 'aliyun',
endpoint: 'dypnsapi.aliyuncs.com',
accessKeyId: 'test-access-key-id',
accessKeySecret: 'test-access-key-secret',
signName: '测试签名',
templateCode: 'SMS_100001',
templateParamKey: 'code',
countryCode: '86',
schemeName: '',
codeLength: 6,
codeType: 1,
validTimeSeconds: 300,
intervalSeconds: 60,
duplicatePolicy: 1,
caseAuthPolicy: 1,
returnVerifyCode: false,
mockVerifyCode: '123456',
maxSendPerPhonePerDay: 20,
maxSendPerIpPerHour: 30,
maxVerifyFailuresPerPhonePerHour: 12,
maxVerifyFailuresPerIpPerHour: 24,
captchaTtlSeconds: 180,
captchaTriggerVerifyFailuresPerPhone: 3,
captchaTriggerVerifyFailuresPerIp: 5,
blockPhoneFailureThreshold: 6,
blockIpFailureThreshold: 10,
blockPhoneDurationMinutes: 30,
blockIpDurationMinutes: 30,
},
} as AppConfig;
}
test('createSmsVerificationService initializes aliyun sdk client under tsx esm runtime', () => {
const service = createSmsVerificationService(
createAliyunSmsConfig(),
pino({ enabled: false }),
);
assert.equal(typeof service.sendLoginCode, 'function');
assert.equal(typeof service.verifyLoginCode, 'function');
});

View File

@@ -1,6 +1,6 @@
import crypto from 'node:crypto';
import DypnsClient, {
import DypnsApiModule, {
CheckSmsVerifyCodeRequest,
SendSmsVerifyCodeRequest,
} from '@alicloud/dypnsapi20170525';
@@ -29,6 +29,30 @@ export type SmsVerificationService = {
): Promise<void>;
};
type DypnsClientInstance = InstanceType<typeof DypnsApiModule>;
type DypnsClientConstructor = new (
config: OpenApiClient.Config,
) => DypnsClientInstance;
function resolveDypnsClientConstructor(): DypnsClientConstructor {
const directExport = DypnsApiModule as unknown;
if (typeof directExport === 'function') {
return directExport as DypnsClientConstructor;
}
// 兼容 CommonJS SDK 在 ESM/tsx 运行时被包一层 default 的情况。
const nestedDefault = (
DypnsApiModule as unknown as { default?: unknown }
).default;
if (typeof nestedDefault === 'function') {
return nestedDefault as DypnsClientConstructor;
}
throw new Error('阿里云短信 SDK Client 导出异常');
}
const DypnsClient = resolveDypnsClientConstructor();
function isAliyunConfigMissing(config: AppConfig['smsAuth']) {
return !config.accessKeyId || !config.accessKeySecret;
}
@@ -74,6 +98,7 @@ class AliyunSmsVerificationService implements SmsVerificationService {
async sendLoginCode(phoneNumber: NormalizedPhoneNumber) {
const templateParam = JSON.stringify({
[this.config.templateParamKey]: '##code##',
"min": this.config.validTimeSeconds,
});
const request = new SendSmsVerifyCodeRequest({
phoneNumber: phoneNumber.nationalNumber,