feat: harden support, localize knowledge and add operator availability [skip ci]
Source-only publication of reviewed commit 64e96a7f423673dc29ad56485be9fc79bce8af1c.
Passed in isolation: focused frontend/backend tests, race checks, TypeScript typecheck, lint, Go compilation, Flowgram build, and deterministic SDK build/tests.
Not accepted as a production release: Next.js export/native assembly remains blocked by environment memory limits; browser interaction and MySQL staging acceptance remain unverified. No production server, database/schema, runtime configuration, deployment, release tag, or workflow execution was performed.
Expected source tree: 0a4a7528e9.
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
import { expireSession, readSession } from "@/lib/auth"
|
||||
// Modified in the independent hardening fork; see docs/hardening/README.md.
|
||||
// Modified for AgentDeskFixes: scope authentication expiry to the session that issued each request.
|
||||
import { expireSession, readSession, type AuthSession } from "@/lib/auth"
|
||||
import { isSameSession } from "@/lib/session-request-guard"
|
||||
import { translateCurrentMessage } from "@/i18n/messages"
|
||||
|
||||
const API_BASE_URL =
|
||||
@@ -50,10 +53,10 @@ function normalizeApiRequestError(error: unknown) {
|
||||
)
|
||||
}
|
||||
|
||||
async function parseResult<T>(response: Response) {
|
||||
async function parseResult<T>(response: Response, requestSession: AuthSession | null) {
|
||||
const payload = (await response.json()) as JsonResult<T>
|
||||
if (!response.ok || !payload.success) {
|
||||
if (payload.errorCode === 3000 || payload.errorCode === 3002) {
|
||||
if ((payload.errorCode === 3000 || payload.errorCode === 3002) && isSameSession(requestSession, readSession())) {
|
||||
expireSession()
|
||||
}
|
||||
throw new ApiRequestError(
|
||||
@@ -65,11 +68,10 @@ async function parseResult<T>(response: Response) {
|
||||
return payload.data
|
||||
}
|
||||
|
||||
function buildRequestHeaders(headers: HeadersInit | undefined, skipAuth?: boolean, body?: BodyInit | null) {
|
||||
const session = readSession()
|
||||
function buildRequestHeaders(headers: HeadersInit | undefined, session: AuthSession | null, body?: BodyInit | null) {
|
||||
const authHeaders = new Headers(headers)
|
||||
|
||||
if (!skipAuth && session?.accessToken) {
|
||||
if (session?.accessToken) {
|
||||
authHeaders.set("Authorization", `Bearer ${session.accessToken}`)
|
||||
}
|
||||
if (
|
||||
@@ -101,7 +103,8 @@ export async function request<T>(
|
||||
const { headers, skipAuth, baseUrl, onResponse, ...rest } = options
|
||||
delete (rest as RequestOptions).baseUrl
|
||||
delete (rest as RequestOptions).onResponse
|
||||
const authHeaders = buildRequestHeaders(headers, skipAuth, rest.body)
|
||||
const requestSession = skipAuth ? null : readSession()
|
||||
const authHeaders = buildRequestHeaders(headers, requestSession, rest.body)
|
||||
|
||||
const requestBaseUrl = baseUrl !== undefined ? baseUrl : API_BASE_URL
|
||||
try {
|
||||
@@ -111,7 +114,7 @@ export async function request<T>(
|
||||
cache: "no-store",
|
||||
})
|
||||
onResponse?.(response)
|
||||
return await parseResult<T>(response)
|
||||
return await parseResult<T>(response, requestSession)
|
||||
} catch (error) {
|
||||
throw normalizeApiRequestError(error)
|
||||
}
|
||||
@@ -124,7 +127,8 @@ export async function requestBlob(
|
||||
const { headers, skipAuth, baseUrl, onResponse, ...rest } = options
|
||||
delete (rest as RequestOptions).baseUrl
|
||||
delete (rest as RequestOptions).onResponse
|
||||
const authHeaders = buildRequestHeaders(headers, skipAuth, rest.body)
|
||||
const requestSession = skipAuth ? null : readSession()
|
||||
const authHeaders = buildRequestHeaders(headers, requestSession, rest.body)
|
||||
const requestBaseUrl = baseUrl !== undefined ? baseUrl : API_BASE_URL
|
||||
const response = await fetch(`${requestBaseUrl}${path}`, {
|
||||
...rest,
|
||||
@@ -136,7 +140,7 @@ export async function requestBlob(
|
||||
const contentType = response.headers.get("Content-Type") ?? ""
|
||||
if (contentType.includes("application/json")) {
|
||||
try {
|
||||
await parseResult<never>(response)
|
||||
await parseResult<never>(response, requestSession)
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user