import test from 'node:test'; import assert from 'node:assert/strict'; import config from '../src/config/index.js'; import { Decrypt, Encrypt, decryptUrlMiddle } from '../src/util/crypto/index.js'; import { stringUtils } from '../src/util/stringClass.js'; import { GetReaderBooksChapter, GetReaderBooksChapterContent } from '../src/api/yjbdc/readerController.js'; test('ReplaceAllString 将正则特殊字符按普通文本替换', () => { assert.equal(stringUtils.ReplaceAllString('a+b+c', '+', '___'), 'a___b___c'); assert.equal(stringUtils.ReplaceAllString('a.b.c', '.', '-'), 'a-b-c'); }); test('Decrypt 正常往返并将无效密文标记为 400', () => { const encrypted = Encrypt('Ping?UserID=1', config.urlSecrets.aes_key, config.urlSecrets.aes_iv); assert.equal(Decrypt(encrypted, config.urlSecrets.aes_key, config.urlSecrets.aes_iv), 'Ping?UserID=1'); assert.throws( () => Decrypt('not encrypted', config.urlSecrets.aes_key, config.urlSecrets.aes_iv), error => error.name === 'InvalidEncryptedDataError' && error.status === 400 ); assert.throws( () => Decrypt('AAAAAAAAAAAAAAAAAAAAAA==', config.urlSecrets.aes_key, config.urlSecrets.aes_iv), error => error.name === 'InvalidEncryptedDataError' && error.status === 400 ); }); test('URL 解密中间件忽略 apiData 下的普通静态资源路径', async () => { const previousRequire = config.urlSecrets.require; config.urlSecrets.require = true; const ctx = { request: { url: '/apiData/web/School/0221_02.jpeg' } }; let nextCalled = false; try { await decryptUrlMiddle()(ctx, async () => { nextCalled = true; }); } finally { config.urlSecrets.require = previousRequire; } assert.equal(nextCalled, true); assert.equal(ctx.request.url, '/apiData/web/School/0221_02.jpeg'); }); test('URL 解密中间件只重写有效的加密 API 地址', async () => { const previousRequire = config.urlSecrets.require; config.urlSecrets.require = true; const encrypted = Encrypt('Ping?UserID=1', config.urlSecrets.aes_key, config.urlSecrets.aes_iv); const ctx = { request: { url: `/apiData/${encodeURIComponent(encrypted)}` } }; try { await decryptUrlMiddle()(ctx, async () => {}); } finally { config.urlSecrets.require = previousRequire; } assert.equal(ctx.request.url, '/api/Ping?UserID=1'); }); test('阅读器章节接口拒绝缺失或不在书单内的 Title', async () => { for (const controller of [GetReaderBooksChapter, GetReaderBooksChapterContent]) { const ctx = { query: { Title: '' } }; await controller(ctx); assert.equal(ctx.status, 400); assert.deepEqual(ctx.body, { errcode: 400, errStr: '无效的书名' }); } }); test('阅读器正文接口校验章节号并正确换算回到过去变成猫的章节', async () => { const invalidCtx = { query: { Title: 'Strange-Life-of-a-Cat', Chapter: 'not-a-number' } }; await GetReaderBooksChapterContent(invalidCtx); assert.equal(invalidCtx.status, 400); assert.deepEqual(invalidCtx.body, { errcode: 400, errStr: '无效的章节号' }); const validCtx = { query: { Title: 'Strange-Life-of-a-Cat', Chapter: '1' } }; await GetReaderBooksChapterContent(validCtx); assert.equal(validCtx.body.errcode, 10000); assert.ok(validCtx.body.result.length > 0); });