xaq-cli 0.0.0 → 0.1.0-nightly.71
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/LICENSE +21 -0
- package/README.md +79 -0
- package/dist/admin-5gThRwgj.js +162 -0
- package/dist/admin-5gThRwgj.js.map +1 -0
- package/dist/admin-Btrm8mCd.js +218 -0
- package/dist/admin-Btrm8mCd.js.map +1 -0
- package/dist/admin-CWofnT_Q.js +2 -0
- package/dist/api-BFpElwqK.js +89 -0
- package/dist/api-BFpElwqK.js.map +1 -0
- package/dist/audit-BB7jK9Z5.js +2 -0
- package/dist/audit-BVYknW2i.js +79 -0
- package/dist/audit-BVYknW2i.js.map +1 -0
- package/dist/auth-CXmBdMqw.js +2 -0
- package/dist/auth-D-GmwNv-.js +550 -0
- package/dist/auth-D-GmwNv-.js.map +1 -0
- package/dist/brand--ZB8jTn1.js +32 -0
- package/dist/brand--ZB8jTn1.js.map +1 -0
- package/dist/bus-Cz0flS37.js +12 -0
- package/dist/bus-Cz0flS37.js.map +1 -0
- package/dist/bus-OKIGut72.js +2 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands-BNVLjYXA.js +167 -0
- package/dist/commands-BNVLjYXA.js.map +1 -0
- package/dist/commands-CdA6-WE7.js +112 -0
- package/dist/commands-CdA6-WE7.js.map +1 -0
- package/dist/config-C9XmYZWO.js +94 -0
- package/dist/config-C9XmYZWO.js.map +1 -0
- package/dist/config-CNVi0v5t.js +2 -0
- package/dist/connect-TtJ9n0Rw.js +362 -0
- package/dist/connect-TtJ9n0Rw.js.map +1 -0
- package/dist/content-C1lKMxFS.js +1170 -0
- package/dist/content-C1lKMxFS.js.map +1 -0
- package/dist/content-worker.js +28 -0
- package/dist/content-worker.js.map +1 -0
- package/dist/crypto-fv2fj3S8.js +75 -0
- package/dist/crypto-fv2fj3S8.js.map +1 -0
- package/dist/db-BEUEUPyP.js +561 -0
- package/dist/db-BEUEUPyP.js.map +1 -0
- package/dist/db-Q5BQuwga.js +2 -0
- package/dist/errors-FbMS3QBo.js +39 -0
- package/dist/errors-FbMS3QBo.js.map +1 -0
- package/dist/filter-Ck6OMxvu.js +158 -0
- package/dist/filter-Ck6OMxvu.js.map +1 -0
- package/dist/hermes-CKyzt1mH.js +3 -0
- package/dist/hermes-DHnDTYJp.js +1023 -0
- package/dist/hermes-DHnDTYJp.js.map +1 -0
- package/dist/import-DsN5NZT3.js +910 -0
- package/dist/import-DsN5NZT3.js.map +1 -0
- package/dist/instance-CwWbFbJ8.js +2 -0
- package/dist/instance-Dj9TpJB2.js +195 -0
- package/dist/instance-Dj9TpJB2.js.map +1 -0
- package/dist/listen-B9iO7HgQ.js +1568 -0
- package/dist/listen-B9iO7HgQ.js.map +1 -0
- package/dist/listen-CXVKG9XD.js +2 -0
- package/dist/manage-Bo6COB4p.js +477 -0
- package/dist/manage-Bo6COB4p.js.map +1 -0
- package/dist/manage-DoXqvjnU.js +2 -0
- package/dist/mcpheader-B8c5YO1B.js +2 -0
- package/dist/mcpheader-C9H4vudu.js +185 -0
- package/dist/mcpheader-C9H4vudu.js.map +1 -0
- package/dist/mcpsetup-BnHudwpq.js +2 -0
- package/dist/mcpsetup-DXXo2qjf.js +1053 -0
- package/dist/mcpsetup-DXXo2qjf.js.map +1 -0
- package/dist/node-check-CjTk6VNL.js +24 -0
- package/dist/node-check-CjTk6VNL.js.map +1 -0
- package/dist/paths-d-C2kdjo.js +2 -0
- package/dist/paths-yzOKD6ow.js +46 -0
- package/dist/paths-yzOKD6ow.js.map +1 -0
- package/dist/profile-CcMZ4hn7.js +2 -0
- package/dist/profile-NmMKAczz.js +222 -0
- package/dist/profile-NmMKAczz.js.map +1 -0
- package/dist/prompt-CKMQx_MJ.js +114 -0
- package/dist/prompt-CKMQx_MJ.js.map +1 -0
- package/dist/recipes-C7TIDlRj.js +3 -0
- package/dist/recipes-DG_-doGq.js +314 -0
- package/dist/recipes-DG_-doGq.js.map +1 -0
- package/dist/send-Dk-t8ia-.js +108 -0
- package/dist/send-Dk-t8ia-.js.map +1 -0
- package/dist/server-CDqDp1q3.js +20640 -0
- package/dist/server-CDqDp1q3.js.map +1 -0
- package/dist/service-BVn3soZZ.js +766 -0
- package/dist/service-BVn3soZZ.js.map +1 -0
- package/dist/service-BaWGPmSd.js +2 -0
- package/dist/service-C7jfo-Ex.js +457 -0
- package/dist/service-C7jfo-Ex.js.map +1 -0
- package/dist/service-DxDyKDQ-.js +2 -0
- package/dist/settings-B5qSHxRM.js +134 -0
- package/dist/settings-B5qSHxRM.js.map +1 -0
- package/dist/settings-DQvZaMN1.js +2 -0
- package/dist/setup-token-CwuSzfLK.js +48 -0
- package/dist/setup-token-CwuSzfLK.js.map +1 -0
- package/dist/skill/SKILL.md +445 -0
- package/dist/skill-1UQj3qgW.js +69 -0
- package/dist/skill-1UQj3qgW.js.map +1 -0
- package/dist/skill-pelq18JQ.js +2 -0
- package/dist/ssrf-BlVpGZ7C.js +181 -0
- package/dist/ssrf-BlVpGZ7C.js.map +1 -0
- package/dist/types-BhJDbSzE.js +135 -0
- package/dist/types-BhJDbSzE.js.map +1 -0
- package/dist/ui-B8Sd4Y7Y.js +81 -0
- package/dist/ui-B8Sd4Y7Y.js.map +1 -0
- package/dist/urls-Dp8pBGMU.js +2 -0
- package/dist/urls-U_LfYV61.js +27 -0
- package/dist/urls-U_LfYV61.js.map +1 -0
- package/dist/version-BxH7OuWD.js +20 -0
- package/dist/version-BxH7OuWD.js.map +1 -0
- package/dist/web/assets/_agentId-DonOCOlC.js +1 -0
- package/dist/web/assets/_app-B7t5lEia.js +1 -0
- package/dist/web/assets/_app-DMTGqYpM.js +65 -0
- package/dist/web/assets/_connectionId-DR5vFXOg.js +1 -0
- package/dist/web/assets/_webhookId-LfUlsULp.js +1 -0
- package/dist/web/assets/account-status-CEszs13C.js +1 -0
- package/dist/web/assets/accounts-5m7aiXuZ.js +1 -0
- package/dist/web/assets/accounts-list-YfJzThZa.js +1 -0
- package/dist/web/assets/activity-DOIe7SAg.js +1 -0
- package/dist/web/assets/add-connection-C8JR-13R.js +1 -0
- package/dist/web/assets/agent-create-form-CPxnPYH4.js +1 -0
- package/dist/web/assets/agents-B2Qj5KxT.js +1 -0
- package/dist/web/assets/approvals-BGaVaoFy.js +1 -0
- package/dist/web/assets/approve._id-BLrQnzPM.js +1 -0
- package/dist/web/assets/arrow-left-DZVAXoKj.js +1 -0
- package/dist/web/assets/arrow-right-C2zcqRr2.js +1 -0
- package/dist/web/assets/attention-gO9Nw5uW.js +1 -0
- package/dist/web/assets/audit-BPXXre8S.js +1 -0
- package/dist/web/assets/audit-bits-CGyIprzK.js +1 -0
- package/dist/web/assets/bell-ring-ig3zn1iS.js +1 -0
- package/dist/web/assets/bot-Zk76q_39.js +1 -0
- package/dist/web/assets/calendar-notice-DsCfq3VJ.js +1 -0
- package/dist/web/assets/calendar-plus-Cycfkk0y.js +1 -0
- package/dist/web/assets/calendar-setup-Pn61Wj1n.js +2 -0
- package/dist/web/assets/card-GSO5o-Ug.js +1 -0
- package/dist/web/assets/check-check-Ds1bPIGv.js +1 -0
- package/dist/web/assets/checkbox-B937U-Fd.js +1 -0
- package/dist/web/assets/chevron-right-Cqh4mDk1.js +1 -0
- package/dist/web/assets/chips-input-2xWDofmE.js +1 -0
- package/dist/web/assets/choice-cards-CgAIqBGX.js +1 -0
- package/dist/web/assets/circle-x-DcU-0zVh.js +1 -0
- package/dist/web/assets/command-khhto70y.js +1 -0
- package/dist/web/assets/common-BPZV8TFb.js +1 -0
- package/dist/web/assets/connect-agent-guide-CJdw31p2.js +1 -0
- package/dist/web/assets/connect-host-lr2c3xWh.js +6 -0
- package/dist/web/assets/connection-row-DYx_5o0c.js +1 -0
- package/dist/web/assets/connections-C4NOFb5R.js +1 -0
- package/dist/web/assets/data-table-kW1pkRB5.js +1 -0
- package/dist/web/assets/empty-DzTDioBP.js +1 -0
- package/dist/web/assets/events-C9zJnPKK.js +1 -0
- package/dist/web/assets/eye-B9gT1QSq.js +1 -0
- package/dist/web/assets/eye-off-Diktqz_g.js +1 -0
- package/dist/web/assets/field-C6ejurju.js +1 -0
- package/dist/web/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/web/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/web/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/web/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/web/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/dist/web/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/dist/web/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/dist/web/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/web/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/dist/web/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/dist/web/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/web/assets/get-started-C38bq1gZ.js +2 -0
- package/dist/web/assets/hidden-chars-Dr9TxfvF.js +1 -0
- package/dist/web/assets/index-DGzo3kGh.js +11 -0
- package/dist/web/assets/index-zKOCQLGX.css +2 -0
- package/dist/web/assets/input-CWwJgozn.js +1 -0
- package/dist/web/assets/input-group-HG8OXcJ4.js +1 -0
- package/dist/web/assets/label-multi-select-sH8mllw8.js +1 -0
- package/dist/web/assets/labels-B5UqVwFo.js +1 -0
- package/dist/web/assets/laptop-BxJ4Nbj7.js +1 -0
- package/dist/web/assets/last-call-D-O5O94z.js +1 -0
- package/dist/web/assets/listener-handled-HNCuVrQ7.js +1 -0
- package/dist/web/assets/login-DaeKclcf.js +1 -0
- package/dist/web/assets/mail-C5fm2pTC.js +1 -0
- package/dist/web/assets/mcp-call-UoOTPFyh.js +1 -0
- package/dist/web/assets/mcp-call-card-Cr-OEDX2.js +3 -0
- package/dist/web/assets/message-square-quote-se8Bf3RP.js +1 -0
- package/dist/web/assets/mutations-CLPqJ6cj.js +1 -0
- package/dist/web/assets/network-igNw0VVx.js +1 -0
- package/dist/web/assets/pairing-XjuaVr2u.js +1 -0
- package/dist/web/assets/pairing-notifier-KPzOEZSO.js +1 -0
- package/dist/web/assets/paperclip-znS4iTrg.js +1 -0
- package/dist/web/assets/password-input-DV3aqcNf.js +1 -0
- package/dist/web/assets/pause-o-dK3khK.js +1 -0
- package/dist/web/assets/pencil-DkPFAhEq.js +1 -0
- package/dist/web/assets/play-DvCHND93.js +1 -0
- package/dist/web/assets/plug-CXAniEiR.js +1 -0
- package/dist/web/assets/plug-zap-BwR-l5wb.js +1 -0
- package/dist/web/assets/plus-B_TUslu3.js +1 -0
- package/dist/web/assets/preload-helper-Cc_aKyUb.js +1 -0
- package/dist/web/assets/public-url-rF2Xjyel.js +1 -0
- package/dist/web/assets/queries-Cv3nXx0U.js +42 -0
- package/dist/web/assets/refresh-cw-Ch5FNrby.js +1 -0
- package/dist/web/assets/revealed-keys-C_9NtJPY.js +1 -0
- package/dist/web/assets/rolldown-runtime-XKyaHtl9.js +1 -0
- package/dist/web/assets/rotate-ccw-B-mzPDk0.js +1 -0
- package/dist/web/assets/search-CTVKGomS.js +1 -0
- package/dist/web/assets/select-Bb806bpq.js +1 -0
- package/dist/web/assets/send-DuMVuYs1.js +1 -0
- package/dist/web/assets/settings-BWauhfFf.js +1 -0
- package/dist/web/assets/setup-B7bNKQOp.js +1 -0
- package/dist/web/assets/sheet-CYPwpUsH.js +1 -0
- package/dist/web/assets/shield-alert-CSYB-ThV.js +1 -0
- package/dist/web/assets/shield-check-BulpsYqK.js +1 -0
- package/dist/web/assets/sparkles-CUTiob4K.js +1 -0
- package/dist/web/assets/stamp-BNXUGNa3.js +1 -0
- package/dist/web/assets/step-url-51aMNak-.js +1 -0
- package/dist/web/assets/stream-Du7fY5_Y.js +1 -0
- package/dist/web/assets/tag-I5_-1jFL.js +1 -0
- package/dist/web/assets/terminal-BvxDFTJc.js +1 -0
- package/dist/web/assets/test-email-button-DYi7V_6X.js +1 -0
- package/dist/web/assets/toggle-group-Bdo1gmQ1.js +1 -0
- package/dist/web/assets/trash-Ci0aICEl.js +1 -0
- package/dist/web/assets/use-delivery-speed-BBh7W2q6.js +1 -0
- package/dist/web/assets/use-label-names-BXicesnP.js +1 -0
- package/dist/web/assets/use-sign-out-CPrY_oVO.js +1 -0
- package/dist/web/assets/useInfiniteQuery-DJLIM8yJ.js +1 -0
- package/dist/web/assets/useQuery-MrTwwNy5.js +1 -0
- package/dist/web/assets/useRouterState-D4OBK8l5.js +1 -0
- package/dist/web/assets/webhook-DjeeZiNC.js +1 -0
- package/dist/web/assets/webhook-bits-jw-y2D3u.js +1 -0
- package/dist/web/assets/webhook-sheet-B8h0skDe.js +34 -0
- package/dist/web/assets/webhooks-Cfsdpoyd.js +1 -0
- package/dist/web/assets/x-MF2TZ9aG.js +1 -0
- package/dist/web/favicon.svg +1 -0
- package/dist/web/index.html +27 -0
- package/package.json +98 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
//#region server/util/errors.ts
|
|
3
|
+
/** Throw from anywhere in request handling; the API layer turns it into an ApiError response. */
|
|
4
|
+
var HttpError = class extends Error {
|
|
5
|
+
status;
|
|
6
|
+
code;
|
|
7
|
+
hint;
|
|
8
|
+
constructor(status, code, message, hint) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.hint = hint;
|
|
13
|
+
}
|
|
14
|
+
toJSON() {
|
|
15
|
+
return { error: {
|
|
16
|
+
code: this.code,
|
|
17
|
+
message: this.message,
|
|
18
|
+
...this.hint ? { hint: this.hint } : {}
|
|
19
|
+
} };
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const badRequest = (message, hint) => new HttpError(400, "bad_request", message, hint);
|
|
23
|
+
const notFound = (what) => new HttpError(404, "not_found", `${what} not found`);
|
|
24
|
+
const conflict = (message, hint) => new HttpError(409, "conflict", message, hint);
|
|
25
|
+
/** Thrown by policy checks. `reason` is the guardrail name recorded in the audit log. */
|
|
26
|
+
var PolicyDenied = class extends Error {
|
|
27
|
+
reason;
|
|
28
|
+
constructor(reason, message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.reason = reason;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function errorMessage(err) {
|
|
34
|
+
return err instanceof Error ? err.message : String(err);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { errorMessage as a, conflict as i, PolicyDenied as n, notFound as o, badRequest as r, HttpError as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=errors-FbMS3QBo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors-FbMS3QBo.js","names":[],"sources":["../server/util/errors.ts"],"sourcesContent":["import type { ApiError } from \"../../shared/types.ts\";\n\n/** Throw from anywhere in request handling; the API layer turns it into an ApiError response. */\nexport class HttpError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n message: string,\n readonly hint?: string,\n ) {\n super(message);\n }\n\n toJSON(): ApiError {\n return { error: { code: this.code, message: this.message, ...(this.hint ? { hint: this.hint } : {}) } };\n }\n}\n\nexport const badRequest = (message: string, hint?: string) => new HttpError(400, \"bad_request\", message, hint);\nexport const notFound = (what: string) => new HttpError(404, \"not_found\", `${what} not found`);\nexport const conflict = (message: string, hint?: string) => new HttpError(409, \"conflict\", message, hint);\n\n/** Thrown by policy checks. `reason` is the guardrail name recorded in the audit log. */\nexport class PolicyDenied extends Error {\n constructor(\n readonly reason: string,\n message: string,\n ) {\n super(message);\n }\n}\n\nexport function errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n"],"mappings":";;;AAGA,IAAa,YAAb,cAA+B,MAAM;CAExB;CACA;CAEA;CAJX,YACE,QACA,MACA,SACA,MACA;EACA,MAAM,OAAO;EALJ,KAAA,SAAA;EACA,KAAA,OAAA;EAEA,KAAA,OAAA;CAGX;CAEA,SAAmB;EACjB,OAAO,EAAE,OAAO;GAAE,MAAM,KAAK;GAAM,SAAS,KAAK;GAAS,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EAAG,EAAE;CACxG;AACF;AAEA,MAAa,cAAc,SAAiB,SAAkB,IAAI,UAAU,KAAK,eAAe,SAAS,IAAI;AAC7G,MAAa,YAAY,SAAiB,IAAI,UAAU,KAAK,aAAa,GAAG,KAAK,WAAW;AAC7F,MAAa,YAAY,SAAiB,SAAkB,IAAI,UAAU,KAAK,YAAY,SAAS,IAAI;;AAGxG,IAAa,eAAb,cAAkC,MAAM;CAE3B;CADX,YACE,QACA,SACA;EACA,MAAM,OAAO;EAHJ,KAAA,SAAA;CAIX;AACF;AAEA,SAAgB,aAAa,KAAsB;CACjD,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { _ as isConnectionEventType, v as isEventType } from "./types-BhJDbSzE.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { RE2JS } from "re2js";
|
|
5
|
+
//#region server/util/glob.ts
|
|
6
|
+
/**
|
|
7
|
+
* Case-insensitive address globs used by grant allowlists (`allowTo`) and webhook filters
|
|
8
|
+
* (`from`, `to`). `*` matches any run of characters, everything else is literal:
|
|
9
|
+
* "*@example.com", "billing@*", "alice@example.com".
|
|
10
|
+
*
|
|
11
|
+
* Case folding is ASCII-only: Unicode folding would let look-alikes such as the Kelvin sign (U+212A)
|
|
12
|
+
* match "k". Domains are NFKC-normalized first (as IDNA does), local parts are compared as written.
|
|
13
|
+
*/
|
|
14
|
+
const asciiLower = (s) => s.replace(/[A-Z]/g, (c) => c.toLowerCase());
|
|
15
|
+
function normalize(address) {
|
|
16
|
+
const s = address.trim();
|
|
17
|
+
const at = s.lastIndexOf("@");
|
|
18
|
+
if (at < 0) return asciiLower(s);
|
|
19
|
+
return asciiLower(s.slice(0, at)) + "@" + asciiLower(s.slice(at + 1).normalize("NFKC"));
|
|
20
|
+
}
|
|
21
|
+
function globToRegExp(glob) {
|
|
22
|
+
const body = normalize(glob).split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
23
|
+
return new RegExp(`^${body}$`, "s");
|
|
24
|
+
}
|
|
25
|
+
function matchesGlob(value, glob) {
|
|
26
|
+
return globToRegExp(glob).test(normalize(value));
|
|
27
|
+
}
|
|
28
|
+
function matchesAnyGlob(value, globs) {
|
|
29
|
+
return globs.some((g) => matchesGlob(value, g));
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region server/webhooks/regex.ts
|
|
33
|
+
/**
|
|
34
|
+
* Webhook subject filters run synchronously on attacker-controlled subjects during events.emit, so
|
|
35
|
+
* they use RE2 (re2js): matching is linear in the input, with no catastrophic backtracking. RE2
|
|
36
|
+
* syntax is JavaScript's minus lookarounds and backreferences.
|
|
37
|
+
*/
|
|
38
|
+
const RE2_SYNTAX_HINT = "Subject patterns use RE2 syntax, which runs in linear time: lookarounds ((?=…), (?!…), (?<=…), (?<!…)) and backreferences (\\1) aren't supported.";
|
|
39
|
+
/** Compiled patterns by source; null marks a pattern RE2 rejects. Bounded so it can't grow forever. */
|
|
40
|
+
const cache = /* @__PURE__ */ new Map();
|
|
41
|
+
const CACHE_MAX = 1e3;
|
|
42
|
+
/** RE2's reason for rejecting the pattern, or null when it compiles. */
|
|
43
|
+
function subjectPatternError(pattern) {
|
|
44
|
+
try {
|
|
45
|
+
RE2JS.compile(pattern, RE2JS.CASE_INSENSITIVE);
|
|
46
|
+
return null;
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return (err instanceof Error ? err.message : String(err)).replace(/^error parsing regexp: /, "");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** Case-insensitive search. A pattern RE2 rejects (e.g. stored before this check existed) never matches. */
|
|
52
|
+
function subjectMatches(pattern, subject) {
|
|
53
|
+
let re = cache.get(pattern);
|
|
54
|
+
if (re === void 0) {
|
|
55
|
+
try {
|
|
56
|
+
re = RE2JS.compile(pattern, RE2JS.CASE_INSENSITIVE);
|
|
57
|
+
} catch {
|
|
58
|
+
re = null;
|
|
59
|
+
}
|
|
60
|
+
if (cache.size >= CACHE_MAX) cache.delete(cache.keys().next().value);
|
|
61
|
+
cache.set(pattern, re);
|
|
62
|
+
}
|
|
63
|
+
return re ? re.matcher(subject).find() : false;
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region server/webhooks/filter.ts
|
|
67
|
+
/** Events about the account itself rather than a message: filters only narrow them by account. */
|
|
68
|
+
const ACCOUNT_EVENT_TYPES = ["account.auth_failed", "sync.gap"];
|
|
69
|
+
/** Bounds glob backtracking: filters run on attacker-controlled addresses during every emit. */
|
|
70
|
+
const MAX_GLOB_STARS = 8;
|
|
71
|
+
const list = (max, label) => z.array(z.string().trim().min(1, `${label} entries must not be empty`).max(320)).max(max, `At most ${max} ${label} entries`).optional();
|
|
72
|
+
const globList = (max, label) => list(max, label).refine((globs) => !globs?.some((g) => g.split("*").length - 1 > MAX_GLOB_STARS), `${label} patterns may use at most ${MAX_GLOB_STARS} "*"`);
|
|
73
|
+
/** Strict, so a misspelled criterion is an error rather than a filter that silently matches everything. */
|
|
74
|
+
const webhookFilterSchema = z.object({
|
|
75
|
+
accountIds: list(100, "account"),
|
|
76
|
+
labelIds: list(100, "label"),
|
|
77
|
+
from: globList(100, "from"),
|
|
78
|
+
to: globList(100, "to"),
|
|
79
|
+
subject: z.string().max(200, "Subject pattern must be at most 200 characters").optional().superRefine((s, issues) => {
|
|
80
|
+
const error = s === void 0 ? null : subjectPatternError(s);
|
|
81
|
+
if (error) issues.addIssue({
|
|
82
|
+
code: "custom",
|
|
83
|
+
message: `Subject pattern is not a valid regular expression (${error}). ${RE2_SYNTAX_HINT}`
|
|
84
|
+
});
|
|
85
|
+
}),
|
|
86
|
+
hasAttachments: z.boolean().optional(),
|
|
87
|
+
calendarIds: list(100, "calendar")
|
|
88
|
+
}).strict();
|
|
89
|
+
const webhookFields = {
|
|
90
|
+
agentId: z.string().min(1, "Choose an agent"),
|
|
91
|
+
name: z.string().trim().min(1, "Name is required").max(100, "Name must be at most 100 characters"),
|
|
92
|
+
url: z.string().trim().max(2048).refine((u) => URL.canParse(u) && /^https?:$/.test(new URL(u).protocol), "URL must be a full http(s) URL, e.g. https://example.com/hooks/mail").refine((u) => !URL.canParse(u) || !new URL(u).username && !new URL(u).password, "URL must not contain credentials; verify requests with the signing secret instead"),
|
|
93
|
+
eventTypes: z.array(z.string().refine(isEventType, "Unknown event type")).min(1, "Pick at least one event type").transform((t) => t),
|
|
94
|
+
filter: webhookFilterSchema,
|
|
95
|
+
includeBody: z.boolean(),
|
|
96
|
+
enabled: z.boolean()
|
|
97
|
+
};
|
|
98
|
+
const webhookInputSchema = z.object({
|
|
99
|
+
...webhookFields,
|
|
100
|
+
filter: webhookFilterSchema.default({}),
|
|
101
|
+
includeBody: z.boolean().default(false),
|
|
102
|
+
enabled: z.boolean().default(true)
|
|
103
|
+
});
|
|
104
|
+
const webhookPatchSchema = z.object(webhookFields).partial();
|
|
105
|
+
/** Drops empty lists and blank values so stored filters stay minimal. */
|
|
106
|
+
function normalizeFilter(f) {
|
|
107
|
+
const out = {};
|
|
108
|
+
for (const key of [
|
|
109
|
+
"accountIds",
|
|
110
|
+
"labelIds",
|
|
111
|
+
"from",
|
|
112
|
+
"to",
|
|
113
|
+
"calendarIds"
|
|
114
|
+
]) {
|
|
115
|
+
const v = f[key]?.map((s) => s.trim()).filter(Boolean);
|
|
116
|
+
if (v?.length) out[key] = [...new Set(v)];
|
|
117
|
+
}
|
|
118
|
+
if (f.subject?.trim()) out.subject = f.subject;
|
|
119
|
+
if (typeof f.hasAttachments === "boolean") out.hasAttachments = f.hasAttachments;
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
/** Whether an event passes a webhook filter. Every set criterion must pass. */
|
|
123
|
+
function matchesFilter(f, ev) {
|
|
124
|
+
if (f.accountIds?.length && !f.accountIds.includes(ev.accountId)) return false;
|
|
125
|
+
if (ACCOUNT_EVENT_TYPES.includes(ev.type)) return true;
|
|
126
|
+
if (isConnectionEventType(ev.type)) return true;
|
|
127
|
+
if (ev.calendarEvent) return matchesCalendar(f, ev.calendarEvent, ev.accountEmail);
|
|
128
|
+
const hasMessageCriteria = !!(f.labelIds?.length || f.from?.length || f.to?.length || f.subject || f.hasAttachments !== void 0);
|
|
129
|
+
const m = ev.message;
|
|
130
|
+
if (!m) return !hasMessageCriteria;
|
|
131
|
+
if (f.labelIds?.length) {
|
|
132
|
+
const labels = /* @__PURE__ */ new Set([...m.labelIds, ...ev.labelIds ?? []]);
|
|
133
|
+
if (!f.labelIds.some((l) => labels.has(l))) return false;
|
|
134
|
+
}
|
|
135
|
+
if (f.from?.length && !(m.from && matchesAnyGlob(m.from.email, f.from))) return false;
|
|
136
|
+
if (f.to?.length && ![...m.to, ...m.cc].some((a) => matchesAnyGlob(a.email, f.to))) return false;
|
|
137
|
+
if (f.subject && !subjectMatches(f.subject, m.subject.slice(0, 256))) return false;
|
|
138
|
+
if (f.hasAttachments !== void 0 && m.hasAttachments !== f.hasAttachments) return false;
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* calendar.* events: `calendarIds` picks calendars ("primary" is the account's own), `from` matches the
|
|
143
|
+
* organizer, `to` any attendee and `subject` the summary. labelIds and hasAttachments don't apply.
|
|
144
|
+
*/
|
|
145
|
+
function matchesCalendar(f, e, accountEmail) {
|
|
146
|
+
if (f.calendarIds?.length) {
|
|
147
|
+
const cal = e.calendarId.toLowerCase();
|
|
148
|
+
if (!f.calendarIds.some((id) => (id === "primary" ? accountEmail : id).toLowerCase() === cal)) return false;
|
|
149
|
+
}
|
|
150
|
+
if (f.from?.length && !(e.organizer && matchesAnyGlob(e.organizer.email, f.from))) return false;
|
|
151
|
+
if (f.to?.length && !e.attendees.some((a) => matchesAnyGlob(a.email, f.to))) return false;
|
|
152
|
+
if (f.subject && !subjectMatches(f.subject, e.summary.slice(0, 256))) return false;
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
export { webhookPatchSchema as a, matchesGlob as c, webhookInputSchema as i, normalizeFilter as n, subjectPatternError as o, webhookFilterSchema as r, matchesAnyGlob as s, matchesFilter as t };
|
|
157
|
+
|
|
158
|
+
//# sourceMappingURL=filter-Ck6OMxvu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-Ck6OMxvu.js","names":[],"sources":["../server/util/glob.ts","../server/webhooks/regex.ts","../server/webhooks/filter.ts"],"sourcesContent":["/**\n * Case-insensitive address globs used by grant allowlists (`allowTo`) and webhook filters\n * (`from`, `to`). `*` matches any run of characters, everything else is literal:\n * \"*@example.com\", \"billing@*\", \"alice@example.com\".\n *\n * Case folding is ASCII-only: Unicode folding would let look-alikes such as the Kelvin sign (U+212A)\n * match \"k\". Domains are NFKC-normalized first (as IDNA does), local parts are compared as written.\n */\nconst asciiLower = (s: string) => s.replace(/[A-Z]/g, (c) => c.toLowerCase());\n\nfunction normalize(address: string): string {\n const s = address.trim();\n const at = s.lastIndexOf(\"@\");\n if (at < 0) return asciiLower(s);\n return asciiLower(s.slice(0, at)) + \"@\" + asciiLower(s.slice(at + 1).normalize(\"NFKC\"));\n}\n\nexport function globToRegExp(glob: string): RegExp {\n const body = normalize(glob)\n .split(\"*\")\n .map((part) => part.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\"))\n .join(\".*\");\n return new RegExp(`^${body}$`, \"s\");\n}\n\nexport function matchesGlob(value: string, glob: string): boolean {\n return globToRegExp(glob).test(normalize(value));\n}\n\nexport function matchesAnyGlob(value: string, globs: readonly string[]): boolean {\n return globs.some((g) => matchesGlob(value, g));\n}\n","import { RE2JS } from \"re2js\";\n\n/**\n * Webhook subject filters run synchronously on attacker-controlled subjects during events.emit, so\n * they use RE2 (re2js): matching is linear in the input, with no catastrophic backtracking. RE2\n * syntax is JavaScript's minus lookarounds and backreferences.\n */\n\nexport const RE2_SYNTAX_HINT =\n \"Subject patterns use RE2 syntax, which runs in linear time: lookarounds ((?=…), (?!…), (?<=…), (?<!…)) and backreferences (\\\\1) aren't supported.\";\n\n/** Compiled patterns by source; null marks a pattern RE2 rejects. Bounded so it can't grow forever. */\nconst cache = new Map<string, RE2JS | null>();\nconst CACHE_MAX = 1000;\n\n/** RE2's reason for rejecting the pattern, or null when it compiles. */\nexport function subjectPatternError(pattern: string): string | null {\n try {\n RE2JS.compile(pattern, RE2JS.CASE_INSENSITIVE);\n return null;\n } catch (err) {\n return (err instanceof Error ? err.message : String(err)).replace(/^error parsing regexp: /, \"\");\n }\n}\n\n/** Case-insensitive search. A pattern RE2 rejects (e.g. stored before this check existed) never matches. */\nexport function subjectMatches(pattern: string, subject: string): boolean {\n let re = cache.get(pattern);\n if (re === undefined) {\n try {\n re = RE2JS.compile(pattern, RE2JS.CASE_INSENSITIVE);\n } catch {\n re = null;\n }\n if (cache.size >= CACHE_MAX) cache.delete(cache.keys().next().value!);\n cache.set(pattern, re);\n }\n return re ? re.matcher(subject).find() : false;\n}\n","import { z } from \"zod\";\nimport { type CalendarEventSummary, type EventType, isConnectionEventType, isEventType, type WebhookFilter } from \"../../shared/types.ts\";\nimport type { StoredEvent } from \"../events/types.ts\";\nimport { matchesAnyGlob } from \"../util/glob.ts\";\nimport { RE2_SYNTAX_HINT, subjectMatches, subjectPatternError } from \"./regex.ts\";\n\n/** Events about the account itself rather than a message: filters only narrow them by account. */\nexport const ACCOUNT_EVENT_TYPES: readonly EventType[] = [\"account.auth_failed\", \"sync.gap\"];\n\n/** Bounds glob backtracking: filters run on attacker-controlled addresses during every emit. */\nconst MAX_GLOB_STARS = 8;\n/** Only this much of the subject is tested against the pattern (bounds matching cost). */\nexport const MAX_SUBJECT_TESTED = 256;\n\nconst list = (max: number, label: string) =>\n z\n .array(z.string().trim().min(1, `${label} entries must not be empty`).max(320))\n .max(max, `At most ${max} ${label} entries`)\n .optional();\n\nconst globList = (max: number, label: string) =>\n list(max, label).refine((globs) => !globs?.some((g) => g.split(\"*\").length - 1 > MAX_GLOB_STARS), `${label} patterns may use at most ${MAX_GLOB_STARS} \"*\"`);\n\n/** Strict, so a misspelled criterion is an error rather than a filter that silently matches everything. */\nexport const webhookFilterSchema = z\n .object({\n accountIds: list(100, \"account\"),\n labelIds: list(100, \"label\"),\n from: globList(100, \"from\"),\n to: globList(100, \"to\"),\n subject: z\n .string()\n .max(200, \"Subject pattern must be at most 200 characters\")\n .optional()\n .superRefine((s, issues) => {\n const error = s === undefined ? null : subjectPatternError(s);\n if (error) issues.addIssue({ code: \"custom\", message: `Subject pattern is not a valid regular expression (${error}). ${RE2_SYNTAX_HINT}` });\n }),\n hasAttachments: z.boolean().optional(),\n calendarIds: list(100, \"calendar\"),\n })\n .strict();\n\nconst webhookFields = {\n agentId: z.string().min(1, \"Choose an agent\"),\n name: z.string().trim().min(1, \"Name is required\").max(100, \"Name must be at most 100 characters\"),\n url: z\n .string()\n .trim()\n .max(2048)\n .refine((u) => URL.canParse(u) && /^https?:$/.test(new URL(u).protocol), \"URL must be a full http(s) URL, e.g. https://example.com/hooks/mail\")\n .refine((u) => !URL.canParse(u) || (!new URL(u).username && !new URL(u).password), \"URL must not contain credentials; verify requests with the signing secret instead\"),\n eventTypes: z\n .array(z.string().refine(isEventType, \"Unknown event type\"))\n .min(1, \"Pick at least one event type\")\n .transform((t) => t as EventType[]),\n filter: webhookFilterSchema,\n includeBody: z.boolean(),\n enabled: z.boolean(),\n};\n\nexport const webhookInputSchema = z\n .object({\n ...webhookFields,\n filter: webhookFilterSchema.default({}),\n includeBody: z.boolean().default(false),\n enabled: z.boolean().default(true),\n });\n\nexport const webhookPatchSchema = z.object(webhookFields).partial();\n\n/** Drops empty lists and blank values so stored filters stay minimal. */\nexport function normalizeFilter(f: WebhookFilter): WebhookFilter {\n const out: WebhookFilter = {};\n const lists = [\"accountIds\", \"labelIds\", \"from\", \"to\", \"calendarIds\"] as const;\n for (const key of lists) {\n const v = f[key]?.map((s) => s.trim()).filter(Boolean);\n if (v?.length) out[key] = [...new Set(v)];\n }\n if (f.subject?.trim()) out.subject = f.subject;\n if (typeof f.hasAttachments === \"boolean\") out.hasAttachments = f.hasAttachments;\n return out;\n}\n\n/** Whether an event passes a webhook filter. Every set criterion must pass. */\nexport function matchesFilter(f: WebhookFilter, ev: StoredEvent): boolean {\n if (f.accountIds?.length && !f.accountIds.includes(ev.accountId)) return false;\n if (ACCOUNT_EVENT_TYPES.includes(ev.type)) return true;\n // Connection events have no account (an accountIds filter excludes them, above) and no message.\n if (isConnectionEventType(ev.type)) return true;\n if (ev.calendarEvent) return matchesCalendar(f, ev.calendarEvent, ev.accountEmail);\n const hasMessageCriteria = !!(f.labelIds?.length || f.from?.length || f.to?.length || f.subject || f.hasAttachments !== undefined);\n const m = ev.message;\n if (!m) return !hasMessageCriteria;\n if (f.labelIds?.length) {\n // Label events also match on the labels that changed (a removed label is no longer on the message).\n const labels = new Set([...m.labelIds, ...(ev.labelIds ?? [])]);\n if (!f.labelIds.some((l) => labels.has(l))) return false;\n }\n if (f.from?.length && !(m.from && matchesAnyGlob(m.from.email, f.from))) return false;\n if (f.to?.length && ![...m.to, ...m.cc].some((a) => matchesAnyGlob(a.email, f.to!))) return false;\n if (f.subject && !subjectMatches(f.subject, m.subject.slice(0, MAX_SUBJECT_TESTED))) return false;\n if (f.hasAttachments !== undefined && m.hasAttachments !== f.hasAttachments) return false;\n return true;\n}\n\n/**\n * calendar.* events: `calendarIds` picks calendars (\"primary\" is the account's own), `from` matches the\n * organizer, `to` any attendee and `subject` the summary. labelIds and hasAttachments don't apply.\n */\nfunction matchesCalendar(f: WebhookFilter, e: CalendarEventSummary, accountEmail: string): boolean {\n if (f.calendarIds?.length) {\n const cal = e.calendarId.toLowerCase();\n if (!f.calendarIds.some((id) => (id === \"primary\" ? accountEmail : id).toLowerCase() === cal)) return false;\n }\n if (f.from?.length && !(e.organizer && matchesAnyGlob(e.organizer.email, f.from))) return false;\n if (f.to?.length && !e.attendees.some((a) => matchesAnyGlob(a.email, f.to!))) return false;\n if (f.subject && !subjectMatches(f.subject, e.summary.slice(0, MAX_SUBJECT_TESTED))) return false;\n return true;\n}\n"],"mappings":"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"}
|