Merge branch 'master' of http://82.157.175.59:3000/GenarrativeAI/Genarrative
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -7,6 +7,10 @@ import type { AppConfig } from './config.js';
|
||||
|
||||
const LOG_RETENTION_DAYS = 7;
|
||||
|
||||
function shouldUseTransport(config: AppConfig) {
|
||||
return config.nodeEnv !== 'test' && config.logLevel !== 'silent';
|
||||
}
|
||||
|
||||
function cleanupExpiredLogs(logsDir: string) {
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
return;
|
||||
@@ -28,6 +32,14 @@ function cleanupExpiredLogs(logsDir: string) {
|
||||
}
|
||||
|
||||
export function createLogger(config: AppConfig): Logger {
|
||||
if (!shouldUseTransport(config)) {
|
||||
return pino({
|
||||
level: config.logLevel,
|
||||
timestamp: pino.stdTimeFunctions.isoTime,
|
||||
base: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
fs.mkdirSync(config.logsDir, { recursive: true });
|
||||
cleanupExpiredLogs(config.logsDir);
|
||||
|
||||
|
||||
@@ -151,9 +151,23 @@ async function main() {
|
||||
process.on('SIGTERM', shutdown);
|
||||
}
|
||||
|
||||
const isEntryPoint =
|
||||
typeof process.argv[1] === 'string' &&
|
||||
import.meta.url === pathToFileURL(process.argv[1]).href;
|
||||
function isEntryModule() {
|
||||
if (typeof process.argv[1] !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const entryHref = pathToFileURL(process.argv[1]).href;
|
||||
if (typeof import.meta.url === 'string' && import.meta.url === entryHref) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
typeof __filename === 'string' &&
|
||||
pathToFileURL(__filename).href === entryHref
|
||||
);
|
||||
}
|
||||
|
||||
const isEntryPoint = isEntryModule();
|
||||
|
||||
if (isEntryPoint) {
|
||||
void main().catch((error) => {
|
||||
|
||||
53
server-node/src/services/smsVerificationService.test.ts
Normal file
53
server-node/src/services/smsVerificationService.test.ts
Normal 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');
|
||||
});
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user