mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 02:47:45 +08:00
fix: restore security hardening compatibility and validation
Restore authorized rule reveal, explicit full HTTP capture and retention, video task business fields, and valid payment URLs. Add opt-in credential preservation for trusted recovery, fix frontend type contracts and async races, and eliminate PostgreSQL test fixture resource leaks. Document audit coverage and successful fmt and CI-scoped Clippy checks.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { AxiosAdapter, AxiosInstance, InternalAxiosRequestConfig } from 'axios'
|
||||
import type { AxiosAdapter, InternalAxiosRequestConfig } from 'axios'
|
||||
|
||||
import apiClient, {
|
||||
AUTH_SESSION_SIGNAL_KEY,
|
||||
@@ -8,10 +8,6 @@ import apiClient, {
|
||||
} from '@/api/client'
|
||||
import { cache, cachedRequest } from '@/utils/cache'
|
||||
|
||||
type TestableApiClient = typeof apiClient & {
|
||||
client: AxiosInstance
|
||||
}
|
||||
|
||||
describe('apiClient auth state change event', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear()
|
||||
@@ -55,10 +51,10 @@ describe('apiClient auth state change event', () => {
|
||||
})
|
||||
|
||||
it('restores a session through the refresh cookie and stores the result in memory only', async () => {
|
||||
const rawClient = apiClient as TestableApiClient
|
||||
const previousAdapter = rawClient.client.defaults.adapter
|
||||
const rawClient = apiClient['client']
|
||||
const previousAdapter = rawClient.defaults.adapter
|
||||
|
||||
rawClient.client.defaults.adapter = (async (config: InternalAxiosRequestConfig) => ({
|
||||
rawClient.defaults.adapter = (async (config: InternalAxiosRequestConfig) => ({
|
||||
data: { access_token: 'restored-access-token' },
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
@@ -72,16 +68,16 @@ describe('apiClient auth state change event', () => {
|
||||
expect(localStorage.getItem('access_token')).toBeNull()
|
||||
expect(sessionStorage.getItem('access_token')).toBeNull()
|
||||
} finally {
|
||||
rawClient.client.defaults.adapter = previousAdapter
|
||||
rawClient.defaults.adapter = previousAdapter
|
||||
}
|
||||
})
|
||||
|
||||
it('does not resurrect a session when logout wins an in-flight restore', async () => {
|
||||
const rawClient = apiClient as TestableApiClient
|
||||
const previousAdapter = rawClient.client.defaults.adapter
|
||||
const rawClient = apiClient['client']
|
||||
const previousAdapter = rawClient.defaults.adapter
|
||||
let resolveRefresh!: (response: Awaited<ReturnType<AxiosAdapter>>) => void
|
||||
|
||||
rawClient.client.defaults.adapter = (() => new Promise((resolve) => {
|
||||
rawClient.defaults.adapter = (() => new Promise((resolve) => {
|
||||
resolveRefresh = resolve
|
||||
})) as AxiosAdapter
|
||||
|
||||
@@ -100,7 +96,7 @@ describe('apiClient auth state change event', () => {
|
||||
await expect(restore).rejects.toThrow('Auth state changed')
|
||||
expect(apiClient.getToken()).toBeNull()
|
||||
} finally {
|
||||
rawClient.client.defaults.adapter = previousAdapter
|
||||
rawClient.defaults.adapter = previousAdapter
|
||||
}
|
||||
})
|
||||
|
||||
@@ -141,11 +137,11 @@ describe('apiClient auth state change event', () => {
|
||||
})
|
||||
|
||||
it('sends auth refresh without a request body', async () => {
|
||||
const rawClient = apiClient as TestableApiClient
|
||||
const previousAdapter = rawClient.client.defaults.adapter
|
||||
const rawClient = apiClient['client']
|
||||
const previousAdapter = rawClient.defaults.adapter
|
||||
const requests: InternalAxiosRequestConfig[] = []
|
||||
|
||||
rawClient.client.defaults.adapter = (async (config: InternalAxiosRequestConfig) => {
|
||||
rawClient.defaults.adapter = (async (config: InternalAxiosRequestConfig) => {
|
||||
requests.push(config)
|
||||
return {
|
||||
data: { access_token: 'new-access-token' },
|
||||
@@ -165,16 +161,16 @@ describe('apiClient auth state change event', () => {
|
||||
expect(requests[0].method).toBe('post')
|
||||
expect(requests[0].data).toBeUndefined()
|
||||
} finally {
|
||||
rawClient.client.defaults.adapter = previousAdapter
|
||||
rawClient.defaults.adapter = previousAdapter
|
||||
}
|
||||
})
|
||||
|
||||
it('authenticates protected gateway operational requests', async () => {
|
||||
const rawClient = apiClient as TestableApiClient
|
||||
const previousAdapter = rawClient.client.defaults.adapter
|
||||
const rawClient = apiClient['client']
|
||||
const previousAdapter = rawClient.defaults.adapter
|
||||
const requests: InternalAxiosRequestConfig[] = []
|
||||
|
||||
rawClient.client.defaults.adapter = (async (config: InternalAxiosRequestConfig) => {
|
||||
rawClient.defaults.adapter = (async (config: InternalAxiosRequestConfig) => {
|
||||
requests.push(config)
|
||||
return {
|
||||
data: '',
|
||||
@@ -193,7 +189,7 @@ describe('apiClient auth state change event', () => {
|
||||
expect(requests[0].headers.Authorization).toBe('Bearer operational-access-token')
|
||||
expect(requests[0].headers['X-Client-Device-Id']).toBeTruthy()
|
||||
} finally {
|
||||
rawClient.client.defaults.adapter = previousAdapter
|
||||
rawClient.defaults.adapter = previousAdapter
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { revealEndpointRules } from '../endpoints/endpoints'
|
||||
|
||||
const client = vi.hoisted(() => ({ get: vi.fn() }))
|
||||
vi.mock('../client', () => ({ default: client }))
|
||||
|
||||
beforeEach(() => {
|
||||
client.get.mockReset().mockResolvedValue({ data: { header_rules: [], body_rules: [], response_header_rules: [] } })
|
||||
})
|
||||
|
||||
describe('endpoint rule reveal API', () => {
|
||||
it('uses the scoped route and forwards cancellation', async () => {
|
||||
const controller = new AbortController()
|
||||
await revealEndpointRules('endpoint/with?reserved', controller.signal)
|
||||
expect(client.get).toHaveBeenCalledWith(
|
||||
'/api/admin/endpoints/endpoint%2Fwith%3Freserved/rules/reveal',
|
||||
{ signal: controller.signal },
|
||||
)
|
||||
})
|
||||
|
||||
it('fetches each reveal without retaining a cached response', async () => {
|
||||
await revealEndpointRules('endpoint-1')
|
||||
await revealEndpointRules('endpoint-1')
|
||||
expect(client.get).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user