gongxiangp2/lib/__tests__/dingtalk-session-ticket.test.ts
2026-07-17 18:55:37 +08:00

81 lines
2.5 KiB
TypeScript

/** @jest-environment node */
import { createHash } from 'crypto'
import {
consumeDingtalkSessionTicket,
createDingtalkSessionTicket,
} from '@/lib/dingtalk-session-ticket'
describe('DingTalk one-time session ticket', () => {
const originalUseRedis = process.env.USE_REDIS
const originalRedisUrl = process.env.REDIS_URL
beforeEach(() => {
process.env.USE_REDIS = 'false'
delete process.env.REDIS_URL
})
afterAll(() => {
if (originalUseRedis === undefined) delete process.env.USE_REDIS
else process.env.USE_REDIS = originalUseRedis
if (originalRedisUrl === undefined) delete process.env.REDIS_URL
else process.env.REDIS_URL = originalRedisUrl
})
test('必须匹配原内网地址和浏览器绑定值,且只能消费一次', async () => {
const binding = 'binding-for-original-browser'
const ticketId = await createDingtalkSessionTicket({
userId: 'user-1',
redirectPath: '/admin?tab=users',
targetOrigin: 'http://192.168.58.20:4320',
handoffId: 'handoff-1',
handoffBindingHash: createHash('sha256').update(binding).digest('hex'),
})
await expect(
consumeDingtalkSessionTicket(ticketId, {
expectedTargetOrigin: 'http://192.168.58.20:4320',
expectedHandoffBinding: 'other-browser-binding',
}),
).resolves.toBeNull()
await expect(
consumeDingtalkSessionTicket(ticketId, {
expectedTargetOrigin: 'http://192.168.58.20:4321',
expectedHandoffBinding: binding,
}),
).resolves.toBeNull()
await expect(
consumeDingtalkSessionTicket(ticketId, {
expectedTargetOrigin: 'http://192.168.58.20:4320',
expectedHandoffBinding: binding,
}),
).resolves.toMatchObject({
userId: 'user-1',
redirectPath: '/admin?tab=users',
targetOrigin: 'http://192.168.58.20:4320',
})
await expect(
consumeDingtalkSessionTicket(ticketId, {
expectedTargetOrigin: 'http://192.168.58.20:4320',
expectedHandoffBinding: binding,
}),
).resolves.toBeNull()
})
test('现有仅写 Cookie 的会话票据仍能正常消费', async () => {
const ticketId = await createDingtalkSessionTicket({
redirectPath: '/performance-survey',
cookies: ['next-auth.session-token=test-token; Path=/; HttpOnly'],
})
await expect(consumeDingtalkSessionTicket(ticketId)).resolves.toMatchObject({
redirectPath: '/performance-survey',
cookies: ['next-auth.session-token=test-token; Path=/; HttpOnly'],
})
})
})