

























@@ -6,7 +6,7 @@ import {
66} from "../../../packages/gateway-protocol/src/client-info.js";
77import { PROTOCOL_VERSION } from "../../../packages/gateway-protocol/src/index.js";
88import type { createSubsystemLogger } from "../../logging/subsystem.js";
9-import type { PluginRegistry } from "../../plugins/registry.js";
9+import type { PluginHttpRouteRegistration, PluginRegistry } from "../../plugins/registry.js";
1010import { withPluginRuntimeGatewayRequestScope } from "../../plugins/runtime/gateway-request-scope.js";
1111import type { AuthorizedGatewayHttpRequest } from "../http-utils.js";
1212import type { GatewayRequestContext, GatewayRequestOptions } from "../server-methods/types.js";
@@ -30,6 +30,18 @@ export {
3030export { shouldEnforceGatewayAuthForPluginPath } from "./plugins-http/route-auth.js";
31313232type SubsystemLogger = ReturnType<typeof createSubsystemLogger>;
33+type PluginRouteRuntimeScope = Parameters<typeof withPluginRuntimeGatewayRequestScope>[0];
34+35+function resolvePluginRoutePathContextForRequest(
36+req: IncomingMessage,
37+providedPathContext: PluginRoutePathContext | undefined,
38+): PluginRoutePathContext {
39+if (providedPathContext) {
40+return providedPathContext;
41+}
42+const url = new URL(req.url ?? "/", "http://localhost");
43+return resolvePluginRoutePathContext(url.pathname);
44+}
33453446function createPluginRouteRuntimeClient(
3547scopes: readonly string[],
@@ -55,6 +67,54 @@ function writeUpgradeUnauthorized(socket: Duplex) {
5567socket.destroy();
5668}
576970+type PluginRouteRuntimeDispatchContext = {
71+gatewayRequestAuth?: AuthorizedGatewayHttpRequest;
72+gatewayRequestOperatorScopes?: readonly string[];
73+};
74+75+function getMissingPluginRouteRuntimeContext(
76+route: PluginHttpRouteRegistration,
77+context: PluginRouteRuntimeDispatchContext,
78+): "caller auth context" | "caller scope context" | undefined {
79+if (route.auth !== "gateway") {
80+return undefined;
81+}
82+if (route.gatewayRuntimeScopeSurface === "trusted-operator") {
83+return context.gatewayRequestAuth ? undefined : "caller auth context";
84+}
85+return context.gatewayRequestOperatorScopes === undefined ? "caller scope context" : undefined;
86+}
87+88+function createPluginRouteRuntimeScope(params: {
89+route: PluginHttpRouteRegistration;
90+req: IncomingMessage;
91+gatewayRequestContext?: GatewayRequestContext;
92+gatewayRequestAuth?: AuthorizedGatewayHttpRequest;
93+gatewayRequestOperatorScopes?: readonly string[];
94+}): PluginRouteRuntimeScope {
95+const runtimeScopes =
96+params.route.auth !== "gateway"
97+ ? []
98+ : params.route.gatewayRuntimeScopeSurface === "trusted-operator"
99+ ? resolvePluginRouteRuntimeOperatorScopes(
100+params.req,
101+params.gatewayRequestAuth!,
102+"trusted-operator",
103+)
104+ : params.gatewayRequestOperatorScopes!;
105+const runtimeClient = createPluginRouteRuntimeClient(runtimeScopes);
106+return {
107+ ...(params.gatewayRequestContext ? { context: params.gatewayRequestContext } : {}),
108+client: runtimeClient,
109+isWebchatConnect: () => false,
110+ ...(params.route.pluginId ? { pluginId: params.route.pluginId } : {}),
111+ ...(params.route.source ? { pluginSource: params.route.source } : {}),
112+ ...(params.route.gatewayMethodDispatchAllowed === true
113+ ? { gatewayMethodDispatchAllowed: true }
114+ : {}),
115+};
116+}
117+58118export type PluginRouteDispatchContext = {
59119gatewayAuthSatisfied?: boolean;
60120gatewayRequestAuth?: AuthorizedGatewayHttpRequest;
@@ -91,12 +151,7 @@ export function createGatewayPluginRequestHandler(params: {
91151return false;
92152}
9315394-const pathContext =
95-providedPathContext ??
96-(() => {
97-const url = new URL(req.url ?? "/", "http://localhost");
98-return resolvePluginRoutePathContext(url.pathname);
99-})();
154+const pathContext = resolvePluginRoutePathContextForRequest(req, providedPathContext);
100155const matchedRoutes = findMatchingPluginHttpRoutes(registry, pathContext);
101156if (matchedRoutes.length === 0) {
102157return false;
@@ -112,53 +167,28 @@ export function createGatewayPluginRequestHandler(params: {
112167// Fail closed before invoking any handlers when matched gateway routes are
113168// missing the runtime auth/scope context they require.
114169for (const route of matchedRoutes) {
115-if (route.auth !== "gateway") {
116-continue;
117-}
118-if (route.gatewayRuntimeScopeSurface === "trusted-operator") {
119-if (!gatewayRequestAuth) {
120-log.warn(
121-`plugin http route blocked without caller auth context (${pathContext.canonicalPath})`,
122-);
123-return false;
124-}
125-continue;
126-}
127-if (gatewayRequestOperatorScopes === undefined) {
170+const missingRuntimeContext = getMissingPluginRouteRuntimeContext(route, {
171+ gatewayRequestAuth,
172+ gatewayRequestOperatorScopes,
173+});
174+if (missingRuntimeContext) {
128175log.warn(
129-`plugin http route blocked without caller scope context (${pathContext.canonicalPath})`,
176+`plugin http route blocked without ${missingRuntimeContext} (${pathContext.canonicalPath})`,
130177);
131178return false;
132179}
133180}
134181135182for (const route of matchedRoutes) {
136-let runtimeScopes: readonly string[] = [];
137-if (route.auth === "gateway") {
138-if (route.gatewayRuntimeScopeSurface === "trusted-operator") {
139-runtimeScopes = resolvePluginRouteRuntimeOperatorScopes(
140-req,
141-gatewayRequestAuth!,
142-"trusted-operator",
143-);
144-} else {
145-runtimeScopes = gatewayRequestOperatorScopes!;
146-}
147-}
148-149-const runtimeClient = createPluginRouteRuntimeClient(runtimeScopes);
150183try {
151184const handled = await withPluginRuntimeGatewayRequestScope(
152-{
153- ...(gatewayRequestContext ? { context: gatewayRequestContext } : {}),
154-client: runtimeClient,
155-isWebchatConnect: () => false,
156- ...(route.pluginId ? { pluginId: route.pluginId } : {}),
157- ...(route.source ? { pluginSource: route.source } : {}),
158- ...(route.gatewayMethodDispatchAllowed === true
159- ? { gatewayMethodDispatchAllowed: true }
160- : {}),
161-},
185+createPluginRouteRuntimeScope({
186+ route,
187+ req,
188+ gatewayRequestContext,
189+ gatewayRequestAuth,
190+ gatewayRequestOperatorScopes,
191+}),
162192async () => route.handler(req, res),
163193);
164194if (handled !== false) {
@@ -193,12 +223,7 @@ export function createGatewayPluginUpgradeHandler(params: {
193223return false;
194224}
195225196-const pathContext =
197-providedPathContext ??
198-(() => {
199-const url = new URL(req.url ?? "/", "http://localhost");
200-return resolvePluginRoutePathContext(url.pathname);
201-})();
226+const pathContext = resolvePluginRoutePathContextForRequest(req, providedPathContext);
202227const matchedRoutes = findMatchingPluginHttpRoutes(registry, pathContext).filter(
203228(route) => typeof route.handleUpgrade === "function",
204229);
@@ -215,55 +240,29 @@ export function createGatewayPluginUpgradeHandler(params: {
215240const gatewayRequestOperatorScopes = dispatchContext?.gatewayRequestOperatorScopes;
216241217242for (const route of matchedRoutes) {
218-if (route.auth !== "gateway") {
219-continue;
220-}
221-if (route.gatewayRuntimeScopeSurface === "trusted-operator") {
222-if (!gatewayRequestAuth) {
223-log.warn(
224-`plugin http upgrade blocked without caller auth context (${pathContext.canonicalPath})`,
225-);
226-writeUpgradeUnauthorized(socket);
227-return true;
228-}
229-continue;
230-}
231-if (gatewayRequestOperatorScopes === undefined) {
243+const missingRuntimeContext = getMissingPluginRouteRuntimeContext(route, {
244+ gatewayRequestAuth,
245+ gatewayRequestOperatorScopes,
246+});
247+if (missingRuntimeContext) {
232248log.warn(
233-`plugin http upgrade blocked without caller scope context (${pathContext.canonicalPath})`,
249+`plugin http upgrade blocked without ${missingRuntimeContext} (${pathContext.canonicalPath})`,
234250);
235251writeUpgradeUnauthorized(socket);
236252return true;
237253}
238254}
239255240256for (const route of matchedRoutes) {
241-let runtimeScopes: readonly string[] = [];
242-if (route.auth === "gateway") {
243-if (route.gatewayRuntimeScopeSurface === "trusted-operator") {
244-runtimeScopes = resolvePluginRouteRuntimeOperatorScopes(
245-req,
246-gatewayRequestAuth!,
247-"trusted-operator",
248-);
249-} else {
250-runtimeScopes = gatewayRequestOperatorScopes!;
251-}
252-}
253-254-const runtimeClient = createPluginRouteRuntimeClient(runtimeScopes);
255257try {
256258const handled = await withPluginRuntimeGatewayRequestScope(
257-{
258- ...(gatewayRequestContext ? { context: gatewayRequestContext } : {}),
259-client: runtimeClient,
260-isWebchatConnect: () => false,
261- ...(route.pluginId ? { pluginId: route.pluginId } : {}),
262- ...(route.source ? { pluginSource: route.source } : {}),
263- ...(route.gatewayMethodDispatchAllowed === true
264- ? { gatewayMethodDispatchAllowed: true }
265- : {}),
266-},
259+createPluginRouteRuntimeScope({
260+ route,
261+ req,
262+ gatewayRequestContext,
263+ gatewayRequestAuth,
264+ gatewayRequestOperatorScopes,
265+}),
267266async () => route.handleUpgrade?.(req, socket, head),
268267);
269268if (handled !== false) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。