robotrock 1.3.3 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/ai/index.js +8 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/trigger.js +8 -0
- package/dist/ai/trigger.js.map +1 -1
- package/dist/ai/workflow.js +8 -0
- package/dist/ai/workflow.js.map +1 -1
- package/dist/eve/agent/index.d.ts +2 -1
- package/dist/eve/agent/index.js +171 -153
- package/dist/eve/agent/index.js.map +1 -1
- package/dist/eve/index.d.ts +2 -1
- package/dist/eve/index.js +62 -47
- package/dist/eve/index.js.map +1 -1
- package/dist/eve/tools/admin/assign-tasks.d.ts +15 -4
- package/dist/eve/tools/admin/assign-tasks.js +8 -43
- package/dist/eve/tools/admin/assign-tasks.js.map +1 -1
- package/dist/eve/tools/admin/manage-groups.d.ts +2 -3
- package/dist/eve/tools/admin/manage-groups.js +18 -71
- package/dist/eve/tools/admin/manage-groups.js.map +1 -1
- package/dist/eve/tools/admin/manage-team-members.d.ts +2 -3
- package/dist/eve/tools/admin/manage-team-members.js +20 -64
- package/dist/eve/tools/admin/manage-team-members.js.map +1 -1
- package/dist/eve/tools/admin/query-tasks.d.ts +5 -6
- package/dist/eve/tools/admin/query-tasks.js +22 -86
- package/dist/eve/tools/admin/query-tasks.js.map +1 -1
- package/dist/eve/tools/catalog/search-products.d.ts +4 -5
- package/dist/eve/tools/catalog/search-products.js +2 -33
- package/dist/eve/tools/catalog/search-products.js.map +1 -1
- package/dist/eve/tools/identity/index.d.ts +0 -1
- package/dist/eve/tools/identity/index.js +15 -44
- package/dist/eve/tools/identity/index.js.map +1 -1
- package/dist/eve/tools/identity/my-access.d.ts +2 -3
- package/dist/eve/tools/identity/my-access.js +15 -44
- package/dist/eve/tools/identity/my-access.js.map +1 -1
- package/dist/eve/tools/identity/whoami.js.map +1 -1
- package/dist/eve/tools/inbox/create-task.js.map +1 -1
- package/dist/eve/tools/inbox/index.js.map +1 -1
- package/dist/eve/tools/index.d.ts +1 -1
- package/dist/eve/tools/index.js +44 -193
- package/dist/eve/tools/index.js.map +1 -1
- package/dist/{index-DePyAbTI.d.ts → index-Blq0XoAr.d.ts} +17 -16
- package/dist/index.d.ts +2 -1
- package/dist/index.js +19 -7
- package/dist/index.js.map +1 -1
- package/dist/tool-ui-hint-CMpug5sC.d.ts +13 -0
- package/package.json +2 -2
|
@@ -7,13 +7,14 @@ import { TaskPriority } from '../../schemas/index.js';
|
|
|
7
7
|
import { HookDefinition } from 'eve/hooks';
|
|
8
8
|
export { AgentAdminApi, createAgentAdminApi, createBoundAgentAdminClient, requireBoundAgentAdminClient } from '../../agent-admin.js';
|
|
9
9
|
export { ROBOTROCK_PLATFORM_USER_CONTEXT_PUBLIC_KEY_URL } from '@robotrock/core/eve/platform-user-context-public-key';
|
|
10
|
-
export { R as ROBOTROCK_READY_HOOK_SLUG } from '../../index-
|
|
10
|
+
export { R as ROBOTROCK_READY_HOOK_SLUG } from '../../index-Blq0XoAr.js';
|
|
11
11
|
export { ROBOTROCK_USER_CONTEXT_AUDIENCE, ROBOTROCK_USER_CONTEXT_ISSUER } from '@robotrock/core/eve/user-context-jwt';
|
|
12
12
|
import '@robotrock/core';
|
|
13
13
|
import 'zod';
|
|
14
14
|
import '../../chat-correlation-BsHD-tOQ.js';
|
|
15
15
|
import '@robotrock/core/schemas';
|
|
16
16
|
import '../../tool-reply-guidance-C3qrT1In.js';
|
|
17
|
+
import '../../tool-ui-hint-CMpug5sC.js';
|
|
17
18
|
|
|
18
19
|
/** Header carrying the dashboard user-context JWT on proxied Eve requests. */
|
|
19
20
|
declare const ROBOTROCK_USER_CONTEXT_HEADER = "x-robotrock-user-token";
|
package/dist/eve/agent/index.js
CHANGED
|
@@ -118,6 +118,158 @@ function verifyRobotRockPlatformUserContextJwt(args) {
|
|
|
118
118
|
// ../core/src/eve/platform-user-context-public-key.ts
|
|
119
119
|
var ROBOTROCK_PLATFORM_USER_CONTEXT_PUBLIC_KEY_URL = "https://app.robotrock.io/.well-known/robotrock-user-context-public-key";
|
|
120
120
|
|
|
121
|
+
// ../core/src/utils/decode-html-entities.ts
|
|
122
|
+
function decodeHtmlEntities(value) {
|
|
123
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code))).replace(
|
|
124
|
+
/&#x([0-9a-f]+);/gi,
|
|
125
|
+
(_, code) => String.fromCharCode(parseInt(code, 16))
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ../core/src/utils/safe-url.ts
|
|
130
|
+
var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
131
|
+
"localhost",
|
|
132
|
+
"metadata.google.internal",
|
|
133
|
+
"metadata.goog"
|
|
134
|
+
]);
|
|
135
|
+
function normalizeHostname(hostname) {
|
|
136
|
+
return hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
137
|
+
}
|
|
138
|
+
function isBlockedIpv4(host) {
|
|
139
|
+
const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
140
|
+
if (!match) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
const octets = match.slice(1, 5).map((part) => Number(part));
|
|
144
|
+
if (octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255)) {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
const [a, b, _c, _d] = octets;
|
|
148
|
+
if (a === void 0 || b === void 0) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
if (a === 127 || a === 0) return true;
|
|
152
|
+
if (a === 10) return true;
|
|
153
|
+
if (a === 169 && b === 254) return true;
|
|
154
|
+
if (a === 192 && b === 168) return true;
|
|
155
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
156
|
+
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
function ipv4FromNumericHost(host) {
|
|
160
|
+
if (/^\d+$/.test(host)) {
|
|
161
|
+
const num = Number(host);
|
|
162
|
+
if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
const a = num >>> 24 & 255;
|
|
166
|
+
const b = num >>> 16 & 255;
|
|
167
|
+
const c = num >>> 8 & 255;
|
|
168
|
+
const d = num & 255;
|
|
169
|
+
return `${a}.${b}.${c}.${d}`;
|
|
170
|
+
}
|
|
171
|
+
const hexMatch = /^0x([0-9a-f]{1,8})$/i.exec(host);
|
|
172
|
+
if (hexMatch) {
|
|
173
|
+
const num = Number.parseInt(hexMatch[1], 16);
|
|
174
|
+
if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
const a = num >>> 24 & 255;
|
|
178
|
+
const b = num >>> 16 & 255;
|
|
179
|
+
const c = num >>> 8 & 255;
|
|
180
|
+
const d = num & 255;
|
|
181
|
+
return `${a}.${b}.${c}.${d}`;
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
function isBlockedIpv4Mapped(host) {
|
|
186
|
+
const mappedDotted = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(host);
|
|
187
|
+
if (mappedDotted) {
|
|
188
|
+
return isBlockedIpv4(mappedDotted[1]);
|
|
189
|
+
}
|
|
190
|
+
const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(host);
|
|
191
|
+
if (mappedHex) {
|
|
192
|
+
const high = Number.parseInt(mappedHex[1], 16);
|
|
193
|
+
const low = Number.parseInt(mappedHex[2], 16);
|
|
194
|
+
if (Number.isFinite(high) && Number.isFinite(low)) {
|
|
195
|
+
const a = high >> 8 & 255;
|
|
196
|
+
const b = high & 255;
|
|
197
|
+
const c = low >> 8 & 255;
|
|
198
|
+
const d = low & 255;
|
|
199
|
+
return isBlockedIpv4(`${a}.${b}.${c}.${d}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
function isBlockedIpv6(host) {
|
|
205
|
+
if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
if (host.startsWith("fc") || host.startsWith("fd")) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
if (host.startsWith("fe80:")) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
if (isBlockedIpv4Mapped(host)) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
function isBlockedHostname(hostname) {
|
|
220
|
+
const host = normalizeHostname(hostname);
|
|
221
|
+
if (!host) {
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
if (BLOCKED_HOSTNAMES.has(host)) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
if (host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
const numericIpv4 = ipv4FromNumericHost(host);
|
|
231
|
+
if (numericIpv4 && isBlockedIpv4(numericIpv4)) {
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
return isBlockedIpv4(host) || isBlockedIpv6(host);
|
|
235
|
+
}
|
|
236
|
+
function isLoopbackHandlerUrl(urlString) {
|
|
237
|
+
let url;
|
|
238
|
+
try {
|
|
239
|
+
url = new URL(urlString);
|
|
240
|
+
} catch {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (url.username || url.password) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
const host = url.hostname.toLowerCase();
|
|
250
|
+
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
251
|
+
}
|
|
252
|
+
function isAllowedHandlerUrl(urlString) {
|
|
253
|
+
return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
|
|
254
|
+
}
|
|
255
|
+
function isPublicHttpUrl(urlString) {
|
|
256
|
+
let url;
|
|
257
|
+
try {
|
|
258
|
+
url = new URL(urlString);
|
|
259
|
+
} catch {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
if (url.username || url.password) {
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
return !isBlockedHostname(url.hostname);
|
|
269
|
+
}
|
|
270
|
+
var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
|
|
271
|
+
var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
|
|
272
|
+
|
|
121
273
|
// src/eve/input-request.ts
|
|
122
274
|
var EVE_INPUT_SUBMIT_ACTION_ID = "submit";
|
|
123
275
|
var EVE_INPUT_OTHER_CHOICE_ID = "__other__";
|
|
@@ -127,6 +279,9 @@ var CONFIRMATION_DEFAULT_OPTIONS = [
|
|
|
127
279
|
{ id: "deny", label: "Deny", style: "danger" }
|
|
128
280
|
];
|
|
129
281
|
var SELECT_PER_OPTION_THRESHOLD = 6;
|
|
282
|
+
function decodeDisplayText(value) {
|
|
283
|
+
return decodeHtmlEntities(value);
|
|
284
|
+
}
|
|
130
285
|
function resolveEveInputDisplay(request, toolName) {
|
|
131
286
|
if (request.display) {
|
|
132
287
|
return request.display;
|
|
@@ -143,11 +298,12 @@ function confirmationActions(request) {
|
|
|
143
298
|
const options = request.options && request.options.length > 0 ? request.options : CONFIRMATION_DEFAULT_OPTIONS;
|
|
144
299
|
return options.map((option) => ({
|
|
145
300
|
id: option.id,
|
|
146
|
-
title: option.label,
|
|
147
|
-
...option.description ? { description: option.description } : {}
|
|
301
|
+
title: decodeDisplayText(option.label),
|
|
302
|
+
...option.description ? { description: decodeDisplayText(option.description) } : {}
|
|
148
303
|
}));
|
|
149
304
|
}
|
|
150
305
|
function textSubmitAction(prompt) {
|
|
306
|
+
const decodedPrompt = decodeDisplayText(prompt);
|
|
151
307
|
return {
|
|
152
308
|
id: EVE_INPUT_SUBMIT_ACTION_ID,
|
|
153
309
|
title: "Submit",
|
|
@@ -163,7 +319,7 @@ function textSubmitAction(prompt) {
|
|
|
163
319
|
},
|
|
164
320
|
ui: {
|
|
165
321
|
answer: {
|
|
166
|
-
"ui:title":
|
|
322
|
+
"ui:title": decodedPrompt.trim() || "Your answer",
|
|
167
323
|
"ui:widget": "textarea"
|
|
168
324
|
}
|
|
169
325
|
}
|
|
@@ -172,15 +328,15 @@ function textSubmitAction(prompt) {
|
|
|
172
328
|
function selectPerOptionActions(options) {
|
|
173
329
|
return options.map((option) => ({
|
|
174
330
|
id: option.id,
|
|
175
|
-
title: option.label,
|
|
176
|
-
...option.description ? { description: option.description } : {}
|
|
331
|
+
title: decodeDisplayText(option.label),
|
|
332
|
+
...option.description ? { description: decodeDisplayText(option.description) } : {}
|
|
177
333
|
}));
|
|
178
334
|
}
|
|
179
335
|
function selectFormAction(request) {
|
|
180
336
|
const options = request.options ?? [];
|
|
181
337
|
const allowFreeform = request.allowFreeform === true;
|
|
182
338
|
const enumValues = options.map((option) => option.id);
|
|
183
|
-
const enumNames = options.map((option) => option.label);
|
|
339
|
+
const enumNames = options.map((option) => decodeDisplayText(option.label));
|
|
184
340
|
if (allowFreeform) {
|
|
185
341
|
enumValues.push(EVE_INPUT_OTHER_CHOICE_ID);
|
|
186
342
|
enumNames.push(EVE_INPUT_OTHER_CHOICE_LABEL);
|
|
@@ -303,6 +459,12 @@ function isEveApprovalInputRequest(request) {
|
|
|
303
459
|
const options = request.options ?? [];
|
|
304
460
|
return options.length === 2 && options[0]?.id === "approve" && options[1]?.id === "deny";
|
|
305
461
|
}
|
|
462
|
+
function buildOptionIdFormData(display, optionId) {
|
|
463
|
+
if (display === "select" || display === "confirmation") {
|
|
464
|
+
return { choice: optionId };
|
|
465
|
+
}
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
306
468
|
function eveInputResponseToActionSubmission(request, response, options) {
|
|
307
469
|
const display = resolveEveInputDisplay(request, options?.toolName);
|
|
308
470
|
const actions = eveInputRequestToActions(request, options);
|
|
@@ -312,7 +474,7 @@ function eveInputResponseToActionSubmission(request, response, options) {
|
|
|
312
474
|
return {
|
|
313
475
|
actionId: response.optionId,
|
|
314
476
|
actionTitle: action.title,
|
|
315
|
-
formData:
|
|
477
|
+
formData: buildOptionIdFormData(display, response.optionId)
|
|
316
478
|
};
|
|
317
479
|
}
|
|
318
480
|
const option = request.options?.find((entry) => entry.id === response.optionId);
|
|
@@ -320,13 +482,13 @@ function eveInputResponseToActionSubmission(request, response, options) {
|
|
|
320
482
|
return {
|
|
321
483
|
actionId: response.optionId,
|
|
322
484
|
actionTitle: option.label,
|
|
323
|
-
formData:
|
|
485
|
+
formData: buildOptionIdFormData(display, response.optionId)
|
|
324
486
|
};
|
|
325
487
|
}
|
|
326
488
|
return {
|
|
327
489
|
actionId: response.optionId,
|
|
328
490
|
actionTitle: response.optionId,
|
|
329
|
-
formData:
|
|
491
|
+
formData: buildOptionIdFormData(display, response.optionId)
|
|
330
492
|
};
|
|
331
493
|
}
|
|
332
494
|
const text = response.text?.trim();
|
|
@@ -705,150 +867,6 @@ function robotrockEveChannel(options) {
|
|
|
705
867
|
// src/schemas/index.ts
|
|
706
868
|
import { z as z4 } from "zod";
|
|
707
869
|
|
|
708
|
-
// ../core/src/utils/safe-url.ts
|
|
709
|
-
var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
710
|
-
"localhost",
|
|
711
|
-
"metadata.google.internal",
|
|
712
|
-
"metadata.goog"
|
|
713
|
-
]);
|
|
714
|
-
function normalizeHostname(hostname) {
|
|
715
|
-
return hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
716
|
-
}
|
|
717
|
-
function isBlockedIpv4(host) {
|
|
718
|
-
const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
719
|
-
if (!match) {
|
|
720
|
-
return false;
|
|
721
|
-
}
|
|
722
|
-
const octets = match.slice(1, 5).map((part) => Number(part));
|
|
723
|
-
if (octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255)) {
|
|
724
|
-
return true;
|
|
725
|
-
}
|
|
726
|
-
const [a, b, _c, _d] = octets;
|
|
727
|
-
if (a === void 0 || b === void 0) {
|
|
728
|
-
return true;
|
|
729
|
-
}
|
|
730
|
-
if (a === 127 || a === 0) return true;
|
|
731
|
-
if (a === 10) return true;
|
|
732
|
-
if (a === 169 && b === 254) return true;
|
|
733
|
-
if (a === 192 && b === 168) return true;
|
|
734
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
735
|
-
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
736
|
-
return false;
|
|
737
|
-
}
|
|
738
|
-
function ipv4FromNumericHost(host) {
|
|
739
|
-
if (/^\d+$/.test(host)) {
|
|
740
|
-
const num = Number(host);
|
|
741
|
-
if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
|
|
742
|
-
return null;
|
|
743
|
-
}
|
|
744
|
-
const a = num >>> 24 & 255;
|
|
745
|
-
const b = num >>> 16 & 255;
|
|
746
|
-
const c = num >>> 8 & 255;
|
|
747
|
-
const d = num & 255;
|
|
748
|
-
return `${a}.${b}.${c}.${d}`;
|
|
749
|
-
}
|
|
750
|
-
const hexMatch = /^0x([0-9a-f]{1,8})$/i.exec(host);
|
|
751
|
-
if (hexMatch) {
|
|
752
|
-
const num = Number.parseInt(hexMatch[1], 16);
|
|
753
|
-
if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
|
|
754
|
-
return null;
|
|
755
|
-
}
|
|
756
|
-
const a = num >>> 24 & 255;
|
|
757
|
-
const b = num >>> 16 & 255;
|
|
758
|
-
const c = num >>> 8 & 255;
|
|
759
|
-
const d = num & 255;
|
|
760
|
-
return `${a}.${b}.${c}.${d}`;
|
|
761
|
-
}
|
|
762
|
-
return null;
|
|
763
|
-
}
|
|
764
|
-
function isBlockedIpv4Mapped(host) {
|
|
765
|
-
const mappedDotted = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(host);
|
|
766
|
-
if (mappedDotted) {
|
|
767
|
-
return isBlockedIpv4(mappedDotted[1]);
|
|
768
|
-
}
|
|
769
|
-
const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(host);
|
|
770
|
-
if (mappedHex) {
|
|
771
|
-
const high = Number.parseInt(mappedHex[1], 16);
|
|
772
|
-
const low = Number.parseInt(mappedHex[2], 16);
|
|
773
|
-
if (Number.isFinite(high) && Number.isFinite(low)) {
|
|
774
|
-
const a = high >> 8 & 255;
|
|
775
|
-
const b = high & 255;
|
|
776
|
-
const c = low >> 8 & 255;
|
|
777
|
-
const d = low & 255;
|
|
778
|
-
return isBlockedIpv4(`${a}.${b}.${c}.${d}`);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
function isBlockedIpv6(host) {
|
|
784
|
-
if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
|
|
785
|
-
return true;
|
|
786
|
-
}
|
|
787
|
-
if (host.startsWith("fc") || host.startsWith("fd")) {
|
|
788
|
-
return true;
|
|
789
|
-
}
|
|
790
|
-
if (host.startsWith("fe80:")) {
|
|
791
|
-
return true;
|
|
792
|
-
}
|
|
793
|
-
if (isBlockedIpv4Mapped(host)) {
|
|
794
|
-
return true;
|
|
795
|
-
}
|
|
796
|
-
return false;
|
|
797
|
-
}
|
|
798
|
-
function isBlockedHostname(hostname) {
|
|
799
|
-
const host = normalizeHostname(hostname);
|
|
800
|
-
if (!host) {
|
|
801
|
-
return true;
|
|
802
|
-
}
|
|
803
|
-
if (BLOCKED_HOSTNAMES.has(host)) {
|
|
804
|
-
return true;
|
|
805
|
-
}
|
|
806
|
-
if (host.endsWith(".localhost") || host.endsWith(".local")) {
|
|
807
|
-
return true;
|
|
808
|
-
}
|
|
809
|
-
const numericIpv4 = ipv4FromNumericHost(host);
|
|
810
|
-
if (numericIpv4 && isBlockedIpv4(numericIpv4)) {
|
|
811
|
-
return true;
|
|
812
|
-
}
|
|
813
|
-
return isBlockedIpv4(host) || isBlockedIpv6(host);
|
|
814
|
-
}
|
|
815
|
-
function isLoopbackHandlerUrl(urlString) {
|
|
816
|
-
let url;
|
|
817
|
-
try {
|
|
818
|
-
url = new URL(urlString);
|
|
819
|
-
} catch {
|
|
820
|
-
return false;
|
|
821
|
-
}
|
|
822
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
823
|
-
return false;
|
|
824
|
-
}
|
|
825
|
-
if (url.username || url.password) {
|
|
826
|
-
return false;
|
|
827
|
-
}
|
|
828
|
-
const host = url.hostname.toLowerCase();
|
|
829
|
-
return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
|
|
830
|
-
}
|
|
831
|
-
function isAllowedHandlerUrl(urlString) {
|
|
832
|
-
return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
|
|
833
|
-
}
|
|
834
|
-
function isPublicHttpUrl(urlString) {
|
|
835
|
-
let url;
|
|
836
|
-
try {
|
|
837
|
-
url = new URL(urlString);
|
|
838
|
-
} catch {
|
|
839
|
-
return false;
|
|
840
|
-
}
|
|
841
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
842
|
-
return false;
|
|
843
|
-
}
|
|
844
|
-
if (url.username || url.password) {
|
|
845
|
-
return false;
|
|
846
|
-
}
|
|
847
|
-
return !isBlockedHostname(url.hostname);
|
|
848
|
-
}
|
|
849
|
-
var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
|
|
850
|
-
var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
|
|
851
|
-
|
|
852
870
|
// ../core/src/schemas/task.ts
|
|
853
871
|
import { z } from "zod";
|
|
854
872
|
|