errorRegression.test.js 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import test from 'node:test';
  2. import assert from 'node:assert/strict';
  3. import config from '../src/config/index.js';
  4. import { Decrypt, Encrypt, decryptUrlMiddle } from '../src/util/crypto/index.js';
  5. import { stringUtils } from '../src/util/stringClass.js';
  6. import { GetReaderBooksChapter, GetReaderBooksChapterContent } from '../src/api/yjbdc/readerController.js';
  7. test('ReplaceAllString 将正则特殊字符按普通文本替换', () => {
  8. assert.equal(stringUtils.ReplaceAllString('a+b+c', '+', '___'), 'a___b___c');
  9. assert.equal(stringUtils.ReplaceAllString('a.b.c', '.', '-'), 'a-b-c');
  10. });
  11. test('Decrypt 正常往返并将无效密文标记为 400', () => {
  12. const encrypted = Encrypt('Ping?UserID=1', config.urlSecrets.aes_key, config.urlSecrets.aes_iv);
  13. assert.equal(Decrypt(encrypted, config.urlSecrets.aes_key, config.urlSecrets.aes_iv), 'Ping?UserID=1');
  14. assert.throws(
  15. () => Decrypt('not encrypted', config.urlSecrets.aes_key, config.urlSecrets.aes_iv),
  16. error => error.name === 'InvalidEncryptedDataError' && error.status === 400
  17. );
  18. assert.throws(
  19. () => Decrypt('AAAAAAAAAAAAAAAAAAAAAA==', config.urlSecrets.aes_key, config.urlSecrets.aes_iv),
  20. error => error.name === 'InvalidEncryptedDataError' && error.status === 400
  21. );
  22. });
  23. test('URL 解密中间件忽略 apiData 下的普通静态资源路径', async () => {
  24. const previousRequire = config.urlSecrets.require;
  25. config.urlSecrets.require = true;
  26. const ctx = { request: { url: '/apiData/web/School/0221_02.jpeg' } };
  27. let nextCalled = false;
  28. try {
  29. await decryptUrlMiddle()(ctx, async () => { nextCalled = true; });
  30. } finally {
  31. config.urlSecrets.require = previousRequire;
  32. }
  33. assert.equal(nextCalled, true);
  34. assert.equal(ctx.request.url, '/apiData/web/School/0221_02.jpeg');
  35. });
  36. test('URL 解密中间件只重写有效的加密 API 地址', async () => {
  37. const previousRequire = config.urlSecrets.require;
  38. config.urlSecrets.require = true;
  39. const encrypted = Encrypt('Ping?UserID=1', config.urlSecrets.aes_key, config.urlSecrets.aes_iv);
  40. const ctx = { request: { url: `/apiData/${encodeURIComponent(encrypted)}` } };
  41. try {
  42. await decryptUrlMiddle()(ctx, async () => {});
  43. } finally {
  44. config.urlSecrets.require = previousRequire;
  45. }
  46. assert.equal(ctx.request.url, '/api/Ping?UserID=1');
  47. });
  48. test('阅读器章节接口拒绝缺失或不在书单内的 Title', async () => {
  49. for (const controller of [GetReaderBooksChapter, GetReaderBooksChapterContent]) {
  50. const ctx = { query: { Title: '' } };
  51. await controller(ctx);
  52. assert.equal(ctx.status, 400);
  53. assert.deepEqual(ctx.body, { errcode: 400, errStr: '无效的书名' });
  54. }
  55. });
  56. test('阅读器正文接口校验章节号并正确换算回到过去变成猫的章节', async () => {
  57. const invalidCtx = { query: { Title: 'Strange-Life-of-a-Cat', Chapter: 'not-a-number' } };
  58. await GetReaderBooksChapterContent(invalidCtx);
  59. assert.equal(invalidCtx.status, 400);
  60. assert.deepEqual(invalidCtx.body, { errcode: 400, errStr: '无效的章节号' });
  61. const validCtx = { query: { Title: 'Strange-Life-of-a-Cat', Chapter: '1' } };
  62. await GetReaderBooksChapterContent(validCtx);
  63. assert.equal(validCtx.body.errcode, 10000);
  64. assert.ok(validCtx.body.result.length > 0);
  65. });