frontend-auth-model.test.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import assert from 'node:assert/strict';
  2. import { test } from 'node:test';
  3. import { authModeFromLocation, nextAuthSuccessState, safeInternalPath } from '../src/frontend/auth/auth-model.js';
  4. test('registration success returns to login without navigating to the protected app', () => {
  5. assert.deepEqual(
  6. nextAuthSuccessState('/api/register', {
  7. user: { status: 'pending_email' },
  8. message: '注册成功,验证邮件已发送,请先验证邮箱。'
  9. }),
  10. {
  11. mode: 'login',
  12. path: '/login',
  13. message: '注册成功,验证邮件已发送,请先验证邮箱。',
  14. redirectTo: ''
  15. }
  16. );
  17. });
  18. test('registration fallback does not assume administrator approval is enabled', () => {
  19. assert.equal(
  20. nextAuthSuccessState('/api/register', { user: { status: 'pending_email' } }).message,
  21. '注册成功,请先验证邮箱。'
  22. );
  23. });
  24. test('login success still redirects to the protected app', () => {
  25. assert.deepEqual(
  26. nextAuthSuccessState('/api/login', {
  27. user: { status: 'active' }
  28. }),
  29. {
  30. mode: 'login',
  31. path: '/login',
  32. message: '',
  33. redirectTo: '/overview'
  34. }
  35. );
  36. });
  37. test('login success returns to a safe internal deep link', () => {
  38. assert.equal(
  39. nextAuthSuccessState('/api/login', {}, '/activity?status=failed#event-12').redirectTo,
  40. '/activity?status=failed#event-12'
  41. );
  42. });
  43. test('rejects external and ambiguous auth next destinations', () => {
  44. for (const value of [
  45. 'https://example.com',
  46. '//example.com/path',
  47. '/\\example.com',
  48. '/login',
  49. '/register?next=/overview',
  50. '/api/events',
  51. 'javascript:alert(1)',
  52. '/overview\nLocation:https://example.com'
  53. ]) {
  54. assert.equal(safeInternalPath(value, '/overview'), '/overview');
  55. }
  56. assert.equal(safeInternalPath('/domains/12/dns?tab=records'), '/domains/12/dns?tab=records');
  57. });
  58. test('detects account recovery modes from auth routes', () => {
  59. assert.deepEqual(authModeFromLocation('/forgot-password'), { mode: 'forgot', token: '' });
  60. assert.deepEqual(authModeFromLocation('/resend-verification'), { mode: 'resend', token: '' });
  61. assert.deepEqual(authModeFromLocation('/reset-password', '?token=abc123'), { mode: 'reset', token: 'abc123' });
  62. assert.deepEqual(authModeFromLocation('/login'), { mode: 'login', token: '' });
  63. assert.deepEqual(authModeFromLocation('/register'), { mode: 'register', token: '' });
  64. });