95 lines
2.6 KiB
TypeScript
95 lines
2.6 KiB
TypeScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import { unsafeOriginGuard } from '../originGuard'
|
|
|
|
const originalEnv = {
|
|
nodeEnv: process.env.NODE_ENV,
|
|
publicBaseUrl: process.env.APP_PUBLIC_BASE_URL,
|
|
centerUrl: process.env.YYD_NOTIFICATION_CENTER_URL,
|
|
corsOrigins: process.env.CORS_ALLOWED_ORIGINS
|
|
}
|
|
|
|
test.before(() => {
|
|
process.env.NODE_ENV = 'production'
|
|
process.env.APP_PUBLIC_BASE_URL = 'https://asset.example.com'
|
|
process.env.YYD_NOTIFICATION_CENTER_URL = 'https://sc.example.com/notification-center'
|
|
process.env.CORS_ALLOWED_ORIGINS = ''
|
|
})
|
|
|
|
test.after(() => {
|
|
for (const [key, value] of Object.entries({
|
|
NODE_ENV: originalEnv.nodeEnv,
|
|
APP_PUBLIC_BASE_URL: originalEnv.publicBaseUrl,
|
|
YYD_NOTIFICATION_CENTER_URL: originalEnv.centerUrl,
|
|
CORS_ALLOWED_ORIGINS: originalEnv.corsOrigins
|
|
})) {
|
|
if (value === undefined) delete process.env[key]
|
|
else process.env[key] = value
|
|
}
|
|
})
|
|
|
|
const runGuard = (input: { method: string; origin?: string; path: string }) => {
|
|
const state = { status: 200, body: null as any, nextCalls: 0 }
|
|
const req = {
|
|
method: input.method,
|
|
protocol: 'https',
|
|
path: input.path,
|
|
get(name: string) {
|
|
if (name === 'host') return 'asset.example.com'
|
|
if (name === 'origin') return input.origin
|
|
return undefined
|
|
}
|
|
}
|
|
const res = {
|
|
status(code: number) {
|
|
state.status = code
|
|
return this
|
|
},
|
|
json(body: any) {
|
|
state.body = body
|
|
return this
|
|
}
|
|
}
|
|
unsafeOriginGuard(req as any, res as any, () => {
|
|
state.nextCalls += 1
|
|
})
|
|
return state
|
|
}
|
|
|
|
test('恶意同站来源的资产写操作在进入业务路由前返回403', () => {
|
|
const result = runGuard({
|
|
method: 'POST',
|
|
origin: 'https://sc.example.com',
|
|
path: '/api/equipment'
|
|
})
|
|
assert.equal(result.status, 403)
|
|
assert.equal(result.nextCalls, 0)
|
|
assert.deepEqual(result.body, { code: 403, message: '请求来源不允许', data: null })
|
|
})
|
|
|
|
test('通知中心来源只可进入一次性票据回调', () => {
|
|
assert.equal(runGuard({
|
|
method: 'POST',
|
|
origin: 'https://sc.example.com',
|
|
path: '/api/dingtalk/broker-login'
|
|
}).nextCalls, 1)
|
|
assert.equal(runGuard({
|
|
method: 'DELETE',
|
|
origin: 'https://sc.example.com',
|
|
path: '/api/equipment/1'
|
|
}).status, 403)
|
|
})
|
|
|
|
test('钉钉 WebView 的 null Origin 只可进入一次性票据回调', () => {
|
|
assert.equal(runGuard({
|
|
method: 'POST',
|
|
origin: 'null',
|
|
path: '/api/dingtalk/broker-login'
|
|
}).nextCalls, 1)
|
|
assert.equal(runGuard({
|
|
method: 'POST',
|
|
origin: 'null',
|
|
path: '/api/equipment'
|
|
}).status, 403)
|
|
})
|