Skip to content

Commit 27db001

Browse files
authored
Merge branch 'main' into chore/image-edits
2 parents a4045c5 + 71f0209 commit 27db001

34 files changed

+1116
-45
lines changed

package-lock.json

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"@aws-crypto/sha256-js": "^5.2.0",
4545
"@cfworker/json-schema": "^4.0.3",
4646
"@hono/node-server": "^1.3.3",
47-
"@hono/node-ws": "^1.0.4",
47+
"@hono/node-ws": "^1.2.0",
4848
"@portkey-ai/mustache": "^2.1.3",
4949
"@smithy/signature-v4": "^2.1.1",
5050
"@types/mustache": "^4.2.5",
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import {
2+
HookEventType,
3+
PluginContext,
4+
PluginHandler,
5+
PluginParameters,
6+
} from '../types';
7+
8+
export const handler: PluginHandler = async (
9+
context: PluginContext,
10+
parameters: PluginParameters,
11+
eventType: HookEventType
12+
) => {
13+
let error = null;
14+
let verdict = false;
15+
let data: any = null;
16+
17+
try {
18+
// Get allowed and blocked request types from parameters or metadata
19+
let allowedTypes: string[] = [];
20+
let blockedTypes: string[] = [];
21+
22+
// First check if allowedTypes is provided in parameters
23+
if (parameters.allowedTypes) {
24+
if (Array.isArray(parameters.allowedTypes)) {
25+
allowedTypes = parameters.allowedTypes;
26+
} else if (typeof parameters.allowedTypes === 'string') {
27+
// Support comma-separated string
28+
allowedTypes = parameters.allowedTypes
29+
.split(',')
30+
.map((t: string) => t.trim());
31+
}
32+
}
33+
34+
// Check if blockedTypes is provided in parameters
35+
if (parameters.blockedTypes) {
36+
if (Array.isArray(parameters.blockedTypes)) {
37+
blockedTypes = parameters.blockedTypes;
38+
} else if (typeof parameters.blockedTypes === 'string') {
39+
// Support comma-separated string
40+
blockedTypes = parameters.blockedTypes
41+
.split(',')
42+
.map((t: string) => t.trim());
43+
}
44+
}
45+
46+
// If not in parameters, check metadata for supported_endpoints
47+
if (allowedTypes.length === 0 && context.metadata?.supported_endpoints) {
48+
if (Array.isArray(context.metadata.supported_endpoints)) {
49+
allowedTypes = context.metadata.supported_endpoints;
50+
} else if (typeof context.metadata.supported_endpoints === 'string') {
51+
// Support comma-separated string in metadata
52+
allowedTypes = context.metadata.supported_endpoints
53+
.split(',')
54+
.map((t: string) => t.trim());
55+
}
56+
}
57+
58+
// Check metadata for blocked_endpoints
59+
if (blockedTypes.length === 0 && context.metadata?.blocked_endpoints) {
60+
if (Array.isArray(context.metadata.blocked_endpoints)) {
61+
blockedTypes = context.metadata.blocked_endpoints;
62+
} else if (typeof context.metadata.blocked_endpoints === 'string') {
63+
// Support comma-separated string in metadata
64+
blockedTypes = context.metadata.blocked_endpoints
65+
.split(',')
66+
.map((t: string) => t.trim());
67+
}
68+
}
69+
70+
// Get the current request type from context
71+
const currentRequestType = context.requestType;
72+
73+
if (!currentRequestType) {
74+
throw new Error('Request type not found in context');
75+
}
76+
77+
// Check for conflicts when both lists are specified
78+
if (allowedTypes.length > 0 && blockedTypes.length > 0) {
79+
const conflicts = allowedTypes.filter((type) =>
80+
blockedTypes.includes(type)
81+
);
82+
if (conflicts.length > 0) {
83+
throw new Error(
84+
`Conflict detected: The following types appear in both allowedTypes and blockedTypes: ${conflicts.join(', ')}. Please remove them from one list.`
85+
);
86+
}
87+
}
88+
89+
// Determine verdict based on the lists provided
90+
let mode = 'unrestricted';
91+
92+
// If neither list is specified, allow all
93+
if (allowedTypes.length === 0 && blockedTypes.length === 0) {
94+
verdict = true;
95+
mode = 'unrestricted';
96+
}
97+
// If only blocklist is specified
98+
else if (allowedTypes.length === 0 && blockedTypes.length > 0) {
99+
verdict = !blockedTypes.includes(currentRequestType);
100+
mode = 'blocklist';
101+
}
102+
// If only allowlist is specified
103+
else if (allowedTypes.length > 0 && blockedTypes.length === 0) {
104+
verdict = allowedTypes.includes(currentRequestType);
105+
mode = 'allowlist';
106+
}
107+
// If both are specified (combined mode)
108+
else {
109+
const isBlocked = blockedTypes.includes(currentRequestType);
110+
const isInAllowList = allowedTypes.includes(currentRequestType);
111+
112+
// Blocked takes precedence, then check allowlist
113+
if (isBlocked) {
114+
verdict = false;
115+
} else {
116+
verdict = isInAllowList;
117+
}
118+
mode = 'combined';
119+
}
120+
121+
// Build appropriate explanation based on mode
122+
let explanation = '';
123+
if (mode === 'combined') {
124+
const isBlocked = blockedTypes.includes(currentRequestType);
125+
if (!verdict) {
126+
if (isBlocked) {
127+
explanation = `Request type "${currentRequestType}" is explicitly blocked.`;
128+
} else {
129+
explanation = `Request type "${currentRequestType}" is not in the allowed list. Allowed types (excluding blocked): ${allowedTypes.filter((t) => !blockedTypes.includes(t)).join(', ')}`;
130+
}
131+
} else {
132+
explanation = `Request type "${currentRequestType}" is allowed (in allowlist and not blocked).`;
133+
}
134+
} else if (mode === 'blocklist') {
135+
explanation = verdict
136+
? `Request type "${currentRequestType}" is allowed (not in blocklist).`
137+
: `Request type "${currentRequestType}" is blocked.`;
138+
} else if (mode === 'allowlist') {
139+
explanation = verdict
140+
? `Request type "${currentRequestType}" is allowed.`
141+
: `Request type "${currentRequestType}" is not allowed. Allowed types are: ${allowedTypes.join(', ')}`;
142+
} else {
143+
explanation = `Request type "${currentRequestType}" is allowed (no restrictions configured).`;
144+
}
145+
146+
data = {
147+
currentRequestType,
148+
...(allowedTypes.length > 0
149+
? { allowedTypes }
150+
: mode === 'unrestricted'
151+
? { allowedTypes: ['all'] }
152+
: {}),
153+
...(blockedTypes.length > 0 && { blockedTypes }),
154+
verdict,
155+
explanation,
156+
source:
157+
parameters.allowedTypes || parameters.blockedTypes
158+
? 'parameters'
159+
: context.metadata?.supported_endpoints ||
160+
context.metadata?.blocked_endpoints
161+
? 'metadata'
162+
: 'default',
163+
mode,
164+
};
165+
} catch (e: any) {
166+
error = e;
167+
data = {
168+
explanation: `An error occurred while checking allowed request types: ${e.message}`,
169+
currentRequestType: context.requestType || 'unknown',
170+
allowedTypes:
171+
parameters.allowedTypes || context.metadata?.supported_endpoints || [],
172+
blockedTypes:
173+
parameters.blockedTypes || context.metadata?.blocked_endpoints || [],
174+
};
175+
}
176+
177+
return { error, verdict, data };
178+
};

0 commit comments

Comments
 (0)