@openclaw/msteams 2026.11.3 → 2026.11.5-beta.2
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/dist/.setup/{adapter.runtime-B-6Q3nMI.cjs → adapter.runtime-BB38Rdj_.cjs} +20 -23
- package/dist/.setup/{approval-card-DWPDItvq.cjs → approval-card-BHAKsdAM.cjs} +5 -9
- package/dist/.setup/{approval-handler.runtime-D0jbDypb.cjs → approval-handler.runtime-C16UvawQ.cjs} +4 -4
- package/dist/.setup/{channel-Ci6K9Njb.cjs → channel-BaTw0JW3.cjs} +35 -254
- package/dist/.setup/{channel.runtime-DeHVAVxL.cjs → channel.runtime-Ch2M_-jN.cjs} +65 -107
- package/dist/.setup/{channel.setup-BN3uhq3r.cjs → channel.setup-B9yKGEse.cjs} +161 -262
- package/dist/.setup/{config-schema-CkKdphSp.cjs → config-schema-3lVZ45cB.cjs} +120 -125
- package/dist/.setup/{conversation-store-state-B-4g4uq5.cjs → conversation-store-state-CVhMM0QY.cjs} +411 -601
- package/dist/.setup/{delegated-state-Bv5cWuec.cjs → delegated-state-ilYzKwD8.cjs} +68 -6
- package/dist/.setup/{monitor-cuifGELM.cjs → monitor-b0zPpnmW.cjs} +1883 -2310
- package/dist/.setup/{oauth-BBUQCwmq.cjs → oauth-CUtfkgKE.cjs} +10 -21
- package/dist/.setup/presentation-Duoi9Ijn.cjs +213 -0
- package/dist/.setup/{reaction-types-CwP5RVQB.cjs → reaction-types-C6F6g2nk.cjs} +1 -1
- package/dist/.setup/{resolve-allowlist-gI34MnpE.cjs → resolve-allowlist-7mIEepXB.cjs} +214 -90
- package/dist/.setup/{secret-contract-api-wAyY5UHv.cjs → secret-contract-api-D554HIrH.cjs} +4 -6
- package/dist/.setup/{secret-contract-api-YY3v6MP8.cjs → secret-contract-api-r3hRtbBW.cjs} +1 -1
- package/dist/.setup/{send-C9JY42T6.cjs → send-D1w7a_ip.cjs} +86 -182
- package/dist/.setup/{setup-plugin-api-B-NYBLkF.cjs → setup-plugin-api-ChovZJU6.cjs} +1 -1
- package/dist/.setup/{thread-session-BWVCoYza.cjs → thread-session-CeWYiol_.cjs} +4 -6
- package/dist/.setup/{token-config-bEpua_Q7.cjs → token-config-DICiuJWr.cjs} +0 -2
- package/dist/.source-module-urls/7e43ee3ae4faab430a47269c8217f8d99ec60ecd85233f40e81d03efeb543068.json +1 -0
- package/dist/api.cjs +2 -2
- package/dist/channel-config-api.cjs +1 -1
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +3 -11
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/secret-contract-api.cjs +1 -1
- package/dist/setup-entry.cjs +2 -2
- package/dist/setup-plugin-api.cjs +1 -1
- package/openclaw.plugin.json +0 -30
- package/package.json +11 -11
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
const require_bot_framework_service_url = require("./bot-framework-service-url-B3FWn2SV.cjs");
|
|
2
|
-
const require_token_config = require("./token-config-
|
|
2
|
+
const require_token_config = require("./token-config-DICiuJWr.cjs");
|
|
3
3
|
const require_runtime = require("./runtime-gZTAuFux.cjs");
|
|
4
4
|
require("../runtime-api.cjs");
|
|
5
|
-
const require_delegated_state = require("./delegated-state-
|
|
5
|
+
const require_delegated_state = require("./delegated-state-ilYzKwD8.cjs");
|
|
6
6
|
let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
|
|
7
7
|
let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
|
|
8
8
|
let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
|
|
@@ -14,13 +14,14 @@ let openclaw_plugin_sdk_fetch_runtime = require("openclaw/plugin-sdk/fetch-runti
|
|
|
14
14
|
let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
|
|
15
15
|
let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
|
|
16
16
|
let node_buffer = require("node:buffer");
|
|
17
|
-
let node_dns_promises = require("node:dns/promises");
|
|
18
17
|
let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
|
|
19
18
|
let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
|
|
20
19
|
let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
|
|
21
20
|
let openclaw_plugin_sdk_secret_file = require("openclaw/plugin-sdk/secret-file");
|
|
22
21
|
let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
|
|
23
22
|
let node_module = require("node:module");
|
|
23
|
+
let node_crypto = require("node:crypto");
|
|
24
|
+
let openclaw_plugin_sdk_provider_oauth_runtime = require("openclaw/plugin-sdk/provider-oauth-runtime");
|
|
24
25
|
let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
|
|
25
26
|
//#region extensions/msteams/src/accounts.ts
|
|
26
27
|
const { listAccountIds, resolveDefaultAccountId } = (0, openclaw_plugin_sdk_account_helpers.createAccountListHelpers)("msteams", {
|
|
@@ -170,6 +171,21 @@ function inspectMSTeamsAccount(params) {
|
|
|
170
171
|
};
|
|
171
172
|
}
|
|
172
173
|
//#endregion
|
|
174
|
+
//#region extensions/msteams/src/microsoft-hosts.ts
|
|
175
|
+
const GRAPH_HOSTS = [
|
|
176
|
+
"graph.microsoft.com",
|
|
177
|
+
"graph.microsoft.us",
|
|
178
|
+
"graph.microsoft.de",
|
|
179
|
+
"graph.microsoft.cn"
|
|
180
|
+
];
|
|
181
|
+
const SHAREPOINT_HOSTS = [
|
|
182
|
+
"sharepoint.com",
|
|
183
|
+
"sharepoint.us",
|
|
184
|
+
"sharepoint.de",
|
|
185
|
+
"sharepoint.cn",
|
|
186
|
+
"sharepoint-df.com"
|
|
187
|
+
];
|
|
188
|
+
//#endregion
|
|
173
189
|
//#region extensions/msteams/src/request-timeout.ts
|
|
174
190
|
const MSTEAMS_REQUEST_TIMEOUT_MS = 3e4;
|
|
175
191
|
const MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS = 3e5;
|
|
@@ -229,7 +245,7 @@ const IMAGE_EXT_RE = /\.(avif|bmp|gif|heic|heif|jpe?g|png|tiff?|webp)$/i;
|
|
|
229
245
|
* tag wins, and a quoted value may contain `>`. Each `<tag` start is resolved from
|
|
230
246
|
* precomputed next-`>` and next-quote positions in one forward pass.
|
|
231
247
|
*/
|
|
232
|
-
function htmlTagAttributeValues(html, tag, attr) {
|
|
248
|
+
function htmlTagAttributeValues(html, tag, attr, visit) {
|
|
233
249
|
const length = html.length;
|
|
234
250
|
const nextGt = new Int32Array(length + 1).fill(length);
|
|
235
251
|
const nextQuote = new Int32Array(length + 1).fill(length);
|
|
@@ -259,13 +275,37 @@ function htmlTagAttributeValues(html, tag, attr) {
|
|
|
259
275
|
while (pastWindow < candidates.length && candidates[pastWindow].start <= lastStart) pastWindow += 1;
|
|
260
276
|
const candidate = candidates[pastWindow - 1];
|
|
261
277
|
if (candidate && candidate.start > nameEnd) {
|
|
262
|
-
|
|
278
|
+
const value = html.slice(candidate.valueStart, candidate.valueEnd);
|
|
279
|
+
if (visit) visit(value, open.index, candidate.end);
|
|
280
|
+
else values.push(value);
|
|
263
281
|
resumeAt = candidate.end;
|
|
264
282
|
}
|
|
265
283
|
}
|
|
266
284
|
return values;
|
|
267
285
|
}
|
|
268
286
|
const GRAPH_HOSTED_CONTENT_SRC_RE = /\/hostedContents\/([^/?#]+)/i;
|
|
287
|
+
const TEAMS_EMOJI_CDN_HOST = "statics.teams.cdn.office.net";
|
|
288
|
+
const TEAMS_EMOJI_ASSET_PATH_RE = /\/emoji([/?#]|$)/i;
|
|
289
|
+
const IMG_ALT_ATTR_RE = /\balt=["']([^"']*)["']/i;
|
|
290
|
+
const EMOJI_PICTOGRAPHIC_RE = /\p{Extended_Pictographic}/u;
|
|
291
|
+
function isTeamsEmojiSpriteImage(src, imgTag) {
|
|
292
|
+
const url = URL.parse(src);
|
|
293
|
+
const host = url?.hostname.toLowerCase() ?? "";
|
|
294
|
+
if (host !== TEAMS_EMOJI_CDN_HOST && !host.endsWith(`.${TEAMS_EMOJI_CDN_HOST}`)) return false;
|
|
295
|
+
return TEAMS_EMOJI_ASSET_PATH_RE.test(url?.pathname ?? "") || EMOJI_PICTOGRAPHIC_RE.test(IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
|
|
296
|
+
}
|
|
297
|
+
function replaceTeamsEmojiSpriteImagesWithAltText(html) {
|
|
298
|
+
const parts = [];
|
|
299
|
+
let cursor = 0;
|
|
300
|
+
htmlTagAttributeValues(html, "img", "src", (src, start, end) => {
|
|
301
|
+
const imgTag = html.slice(start, end);
|
|
302
|
+
if (isTeamsEmojiSpriteImage(src.trim(), imgTag)) {
|
|
303
|
+
parts.push(html.slice(cursor, start), IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
|
|
304
|
+
cursor = end;
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
return parts.join("") + html.slice(cursor);
|
|
308
|
+
}
|
|
269
309
|
function resolveInlineImageSourceId(src) {
|
|
270
310
|
const hostedContentId = GRAPH_HOSTED_CONTENT_SRC_RE.exec(src)?.[1];
|
|
271
311
|
if (!hostedContentId) return src;
|
|
@@ -276,15 +316,8 @@ function resolveInlineImageSourceId(src) {
|
|
|
276
316
|
}
|
|
277
317
|
}
|
|
278
318
|
const DEFAULT_MEDIA_HOST_ALLOWLIST = [
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
"graph.microsoft.de",
|
|
282
|
-
"graph.microsoft.cn",
|
|
283
|
-
"sharepoint.com",
|
|
284
|
-
"sharepoint.us",
|
|
285
|
-
"sharepoint.de",
|
|
286
|
-
"sharepoint.cn",
|
|
287
|
-
"sharepoint-df.com",
|
|
319
|
+
...GRAPH_HOSTS,
|
|
320
|
+
...SHAREPOINT_HOSTS,
|
|
288
321
|
"1drv.ms",
|
|
289
322
|
"onedrive.com",
|
|
290
323
|
"teams.microsoft.com",
|
|
@@ -306,10 +339,7 @@ const DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST = [
|
|
|
306
339
|
"botframework.com",
|
|
307
340
|
"smba.trafficmanager.net",
|
|
308
341
|
"botframework.azure.cn",
|
|
309
|
-
|
|
310
|
-
"graph.microsoft.us",
|
|
311
|
-
"graph.microsoft.de",
|
|
312
|
-
"graph.microsoft.cn"
|
|
342
|
+
...GRAPH_HOSTS
|
|
313
343
|
];
|
|
314
344
|
const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
|
|
315
345
|
/**
|
|
@@ -321,11 +351,7 @@ const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
|
|
|
321
351
|
* https://learn.microsoft.com/en-us/graph/api/shares-get for the encoding.
|
|
322
352
|
*/
|
|
323
353
|
const GRAPH_SHARED_LINK_HOST_SUFFIXES = [
|
|
324
|
-
|
|
325
|
-
".sharepoint.us",
|
|
326
|
-
".sharepoint.de",
|
|
327
|
-
".sharepoint.cn",
|
|
328
|
-
".sharepoint-df.com",
|
|
354
|
+
...SHAREPOINT_HOSTS.map((host) => `.${host}`),
|
|
329
355
|
"1drv.ms",
|
|
330
356
|
"onedrive.live.com",
|
|
331
357
|
"onedrive.com"
|
|
@@ -403,7 +429,7 @@ function extractInlineImageReferences(attachments) {
|
|
|
403
429
|
for (const att of attachments) {
|
|
404
430
|
const html = extractHtmlFromAttachment(att);
|
|
405
431
|
if (!html) continue;
|
|
406
|
-
for (const value of htmlTagAttributeValues(html, "img", "src")) {
|
|
432
|
+
for (const value of htmlTagAttributeValues(replaceTeamsEmojiSpriteImagesWithAltText(html), "img", "src")) {
|
|
407
433
|
const src = value.trim();
|
|
408
434
|
if (src) {
|
|
409
435
|
if (src.startsWith("data:")) out.push({
|
|
@@ -436,15 +462,6 @@ function safeHostForUrl(url) {
|
|
|
436
462
|
const parsed = URL.parse(url);
|
|
437
463
|
return parsed ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(parsed.hostname) : "invalid-url";
|
|
438
464
|
}
|
|
439
|
-
function isMockFetchFn(fetchFn) {
|
|
440
|
-
const candidate = fetchFn;
|
|
441
|
-
return Boolean(candidate.mock || Object.hasOwn(candidate, "_isMockFunction"));
|
|
442
|
-
}
|
|
443
|
-
function resolveGuardedFetchImpl(fetchFn) {
|
|
444
|
-
if (!fetchFn) return;
|
|
445
|
-
if (fetchFn === fetch || fetchFn === globalThis.fetch || isMockFetchFn(fetchFn)) return fetchFn;
|
|
446
|
-
throw new Error("MSTeams attachment fetchFn must set fetchFnSupportsDispatcher to use guarded DNS pinning");
|
|
447
|
-
}
|
|
448
465
|
function resolveRetainedAuthorizationRedirectHostnameAllowlist(input) {
|
|
449
466
|
if (!input) return;
|
|
450
467
|
if (input.includes("*")) return ["*"];
|
|
@@ -466,21 +483,20 @@ function isRedirectStatus(status) {
|
|
|
466
483
|
}
|
|
467
484
|
/**
|
|
468
485
|
* Fetch a URL with redirect: "manual", validating each redirect target
|
|
469
|
-
* against the hostname allowlist and
|
|
486
|
+
* against the hostname allowlist and DNS-resolved IP (anti-SSRF).
|
|
470
487
|
*
|
|
471
488
|
* This prevents:
|
|
472
489
|
* - Auto-following redirects to non-allowlisted hosts
|
|
473
|
-
* - DNS rebinding attacks
|
|
490
|
+
* - DNS rebinding attacks through the pinned DNS lookup
|
|
474
491
|
*/
|
|
475
492
|
async function safeFetchWithPolicy(params) {
|
|
476
493
|
const { allowHosts, authAllowHosts } = params.policy;
|
|
477
|
-
const resolveFn = params.resolveFn ?? node_dns_promises.lookup;
|
|
478
494
|
const currentHeaders = new Headers(params.requestInit?.headers);
|
|
479
495
|
const currentUrl = params.url;
|
|
480
496
|
if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, allowHosts)) throw new Error(`Initial download URL blocked: ${currentUrl}`);
|
|
481
497
|
if (currentHeaders.has("authorization") && !(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, authAllowHosts)) currentHeaders.delete("authorization");
|
|
482
498
|
const lookupFn = async (hostname) => {
|
|
483
|
-
const resolved = await resolveFn(hostname);
|
|
499
|
+
const resolved = await params.resolveFn(hostname);
|
|
484
500
|
return [{
|
|
485
501
|
...resolved,
|
|
486
502
|
family: resolved.address.includes(":") ? 6 : 4
|
|
@@ -488,7 +504,6 @@ async function safeFetchWithPolicy(params) {
|
|
|
488
504
|
};
|
|
489
505
|
const guarded = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
490
506
|
url: currentUrl,
|
|
491
|
-
fetchImpl: resolveGuardedFetchImpl(params.fetchFn),
|
|
492
507
|
init: {
|
|
493
508
|
...params.requestInit,
|
|
494
509
|
headers: currentHeaders
|
|
@@ -801,7 +816,7 @@ const EXPIRY_BUFFER_MS = 3e5;
|
|
|
801
816
|
function parseMSTeamsTokenResponse(data, failureLabel) {
|
|
802
817
|
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data)) throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
|
|
803
818
|
const expiresAt = (0, openclaw_plugin_sdk_number_runtime.resolveExpiresAtMsFromDurationSeconds)(data.expires_in, { bufferMs: EXPIRY_BUFFER_MS });
|
|
804
|
-
if (typeof data.access_token !== "string" || !data.access_token || expiresAt === void 0 || data.refresh_token !== void 0 && typeof data.refresh_token !== "string" || data.scope !== void 0 && typeof data.scope !== "string") throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
|
|
819
|
+
if (typeof data.access_token !== "string" || !data.access_token || expiresAt === void 0 || data.refresh_token !== void 0 && (typeof data.refresh_token !== "string" || !data.refresh_token) || data.scope !== void 0 && typeof data.scope !== "string") throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
|
|
805
820
|
return {
|
|
806
821
|
access_token: data.access_token,
|
|
807
822
|
refresh_token: data.refresh_token,
|
|
@@ -810,7 +825,11 @@ function parseMSTeamsTokenResponse(data, failureLabel) {
|
|
|
810
825
|
};
|
|
811
826
|
}
|
|
812
827
|
async function fetchMSTeamsTokens(params) {
|
|
828
|
+
let dispatched = false;
|
|
813
829
|
const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
830
|
+
beforeRequest: () => {
|
|
831
|
+
dispatched = true;
|
|
832
|
+
},
|
|
814
833
|
url: params.tokenUrl,
|
|
815
834
|
init: {
|
|
816
835
|
method: "POST",
|
|
@@ -822,10 +841,56 @@ async function fetchMSTeamsTokens(params) {
|
|
|
822
841
|
signal: AbortSignal.timeout(MSTEAMS_DEFAULT_TOKEN_FETCH_TIMEOUT_MS)
|
|
823
842
|
},
|
|
824
843
|
auditContext: params.auditContext
|
|
844
|
+
}).catch((cause) => {
|
|
845
|
+
if (!params.refresh) throw cause;
|
|
846
|
+
throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh transport failed", dispatched ? {
|
|
847
|
+
version: 1,
|
|
848
|
+
phase: "token-response",
|
|
849
|
+
outcome: "unchanged",
|
|
850
|
+
recovery: {
|
|
851
|
+
kind: "later",
|
|
852
|
+
evidence: "documented-reusable-grant"
|
|
853
|
+
}
|
|
854
|
+
} : {
|
|
855
|
+
version: 1,
|
|
856
|
+
phase: "before-dispatch",
|
|
857
|
+
outcome: "not-attempted",
|
|
858
|
+
recovery: {
|
|
859
|
+
kind: "later",
|
|
860
|
+
evidence: "dispatch-not-started"
|
|
861
|
+
}
|
|
862
|
+
}, { cause });
|
|
825
863
|
});
|
|
826
864
|
try {
|
|
827
|
-
if (!response.ok) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
|
|
828
|
-
|
|
865
|
+
if (!response.ok && !params.refresh) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
|
|
866
|
+
let data;
|
|
867
|
+
try {
|
|
868
|
+
data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, `MSTeams ${params.failureLabel} failed`);
|
|
869
|
+
} catch (cause) {
|
|
870
|
+
if (!params.refresh) throw cause;
|
|
871
|
+
if (!response.ok) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshResponseError)("MSTeams token refresh", response.status, void 0, "documented-reusable-grant");
|
|
872
|
+
throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response could not be read", {
|
|
873
|
+
version: 1,
|
|
874
|
+
phase: "token-response",
|
|
875
|
+
outcome: "unchanged",
|
|
876
|
+
recovery: {
|
|
877
|
+
kind: "later",
|
|
878
|
+
evidence: "documented-reusable-grant"
|
|
879
|
+
}
|
|
880
|
+
}, { cause });
|
|
881
|
+
}
|
|
882
|
+
if (params.refresh && (!response.ok || (0, openclaw_plugin_sdk_provider_oauth_runtime.readOAuthRefreshErrorReason)(data))) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshResponseError)("MSTeams token refresh", response.status, data, "documented-reusable-grant");
|
|
883
|
+
try {
|
|
884
|
+
return parseMSTeamsTokenResponse(data, params.failureLabel);
|
|
885
|
+
} catch (cause) {
|
|
886
|
+
if (!params.refresh) throw cause;
|
|
887
|
+
throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response fields are invalid", {
|
|
888
|
+
version: 1,
|
|
889
|
+
phase: "after-token-response",
|
|
890
|
+
outcome: "unknown",
|
|
891
|
+
status: response.status
|
|
892
|
+
}, { cause });
|
|
893
|
+
}
|
|
829
894
|
} finally {
|
|
830
895
|
await release();
|
|
831
896
|
}
|
|
@@ -843,7 +908,8 @@ async function requestMSTeamsDelegatedTokens(params) {
|
|
|
843
908
|
tokenUrl: buildMSTeamsTokenEndpoint(params.tenantId),
|
|
844
909
|
body,
|
|
845
910
|
auditContext: params.auditContext,
|
|
846
|
-
failureLabel: params.failureLabel
|
|
911
|
+
failureLabel: params.failureLabel,
|
|
912
|
+
refresh: params.grantType === "refresh_token"
|
|
847
913
|
});
|
|
848
914
|
return {
|
|
849
915
|
accessToken: data.access_token,
|
|
@@ -858,7 +924,6 @@ async function exchangeMSTeamsCodeForTokens(params) {
|
|
|
858
924
|
clientId: params.clientId,
|
|
859
925
|
clientSecret: params.clientSecret,
|
|
860
926
|
grantType: "authorization_code",
|
|
861
|
-
scopes: params.scopes,
|
|
862
927
|
values: {
|
|
863
928
|
code: params.code,
|
|
864
929
|
redirect_uri: MSTEAMS_OAUTH_REDIRECT_URI,
|
|
@@ -887,22 +952,67 @@ async function refreshMSTeamsDelegatedTokens(params) {
|
|
|
887
952
|
}
|
|
888
953
|
//#endregion
|
|
889
954
|
//#region extensions/msteams/src/token.ts
|
|
955
|
+
const refreshes = /* @__PURE__ */ new WeakMap();
|
|
890
956
|
async function resolveDelegatedAccessToken(params) {
|
|
891
|
-
const
|
|
892
|
-
|
|
957
|
+
const runtime = require_runtime.getMSTeamsRuntime();
|
|
958
|
+
const callerKey = (0, node_crypto.createHash)("sha256").update(JSON.stringify([
|
|
959
|
+
runtime.state.resolveStateDir(),
|
|
960
|
+
require_delegated_state.resolveMSTeamsAccountStateNamespace("delegated-token", params.accountId),
|
|
961
|
+
params.tenantId,
|
|
962
|
+
params.clientId,
|
|
963
|
+
params.clientSecret
|
|
964
|
+
])).digest("hex");
|
|
965
|
+
const state = await require_delegated_state.loadMSTeamsDelegatedTokenState(params.accountId);
|
|
966
|
+
const tokens = require_delegated_state.normalizeMSTeamsDelegatedTokens(state);
|
|
967
|
+
const active = refreshes.get(runtime) ?? /* @__PURE__ */ new Map();
|
|
968
|
+
refreshes.set(runtime, active);
|
|
969
|
+
if (state && "refreshClaim" in state && state.callerKey === callerKey) {
|
|
970
|
+
const pending = active.get(state.requestKey);
|
|
971
|
+
if (pending) return await pending;
|
|
972
|
+
}
|
|
973
|
+
if (!tokens) return state && "refreshClaim" in state && state.callerKey === callerKey ? await active.get(state.requestKey) : void 0;
|
|
893
974
|
if ((0, openclaw_plugin_sdk_number_runtime.isFutureDateTimestampMs)(tokens.expiresAt)) return tokens.accessToken;
|
|
975
|
+
const key = (0, node_crypto.createHash)("sha256").update(JSON.stringify([callerKey, tokens])).digest("hex");
|
|
976
|
+
const pending = active.get(key);
|
|
977
|
+
if (pending) return await pending;
|
|
978
|
+
const task = (async () => {
|
|
979
|
+
try {
|
|
980
|
+
const claim = await require_delegated_state.claimMSTeamsDelegatedTokenRefresh(tokens, key, callerKey, params.accountId);
|
|
981
|
+
if (!claim) return;
|
|
982
|
+
let refreshed;
|
|
983
|
+
try {
|
|
984
|
+
if (require_runtime.getMSTeamsRuntime() !== runtime) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("Microsoft Teams token owner changed before refresh dispatch", {
|
|
985
|
+
version: 1,
|
|
986
|
+
phase: "before-dispatch",
|
|
987
|
+
outcome: "not-attempted",
|
|
988
|
+
recovery: {
|
|
989
|
+
kind: "later",
|
|
990
|
+
evidence: "dispatch-not-started"
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
refreshed = await refreshMSTeamsDelegatedTokens({
|
|
994
|
+
...params,
|
|
995
|
+
refreshToken: tokens.refreshToken,
|
|
996
|
+
scopes: tokens.scopes
|
|
997
|
+
});
|
|
998
|
+
} catch (error) {
|
|
999
|
+
if ((0, openclaw_plugin_sdk_provider_oauth_runtime.isRecoverableOAuthRefreshFailure)(error)) await claim.settle(tokens);
|
|
1000
|
+
else await claim.reject();
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
return await claim.settle({
|
|
1004
|
+
...tokens,
|
|
1005
|
+
...refreshed
|
|
1006
|
+
}) ? refreshed.accessToken : void 0;
|
|
1007
|
+
} catch {
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
})();
|
|
1011
|
+
active.set(key, task);
|
|
894
1012
|
try {
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
clientSecret: params.clientSecret,
|
|
899
|
-
refreshToken: tokens.refreshToken,
|
|
900
|
-
scopes: tokens.scopes
|
|
901
|
-
});
|
|
902
|
-
await require_delegated_state.saveMSTeamsDelegatedTokens(refreshed, params.accountId);
|
|
903
|
-
return refreshed.accessToken;
|
|
904
|
-
} catch {
|
|
905
|
-
return;
|
|
1013
|
+
return await task;
|
|
1014
|
+
} finally {
|
|
1015
|
+
if (active.get(key) === task) active.delete(key);
|
|
906
1016
|
}
|
|
907
1017
|
}
|
|
908
1018
|
//#endregion
|
|
@@ -921,9 +1031,6 @@ function captureGraphRequestCurrentness(assertReadAuthority) {
|
|
|
921
1031
|
assertCurrent();
|
|
922
1032
|
};
|
|
923
1033
|
}
|
|
924
|
-
function normalizeQuery(value) {
|
|
925
|
-
return value?.trim() ?? "";
|
|
926
|
-
}
|
|
927
1034
|
function escapeOData(value) {
|
|
928
1035
|
return value.replace(/'/g, "''");
|
|
929
1036
|
}
|
|
@@ -1064,9 +1171,6 @@ async function resolveGraphToken(cfg, options) {
|
|
|
1064
1171
|
if (!accessToken) throw new Error("MS Teams graph token unavailable");
|
|
1065
1172
|
return accessToken;
|
|
1066
1173
|
}
|
|
1067
|
-
async function listTeamsByName(token, query) {
|
|
1068
|
-
return (await listTeamsByNameWithPageInfo(token, query)).items;
|
|
1069
|
-
}
|
|
1070
1174
|
async function listTeamsByNameWithPageInfo(token, query) {
|
|
1071
1175
|
const filter = `resourceProvisioningOptions/Any(x:x eq 'Team') and startsWith(displayName,'${escapeOData(query)}')`;
|
|
1072
1176
|
return await fetchAllGraphPages({
|
|
@@ -1082,9 +1186,6 @@ async function deleteGraphRequest(params) {
|
|
|
1082
1186
|
errorPrefix: "Graph DELETE"
|
|
1083
1187
|
})).body?.cancel().catch(() => void 0);
|
|
1084
1188
|
}
|
|
1085
|
-
async function listChannelsForTeam(token, teamId) {
|
|
1086
|
-
return (await listChannelsForTeamWithPageInfo(token, teamId)).items;
|
|
1087
|
-
}
|
|
1088
1189
|
async function listChannelsForTeamWithPageInfo(token, teamId) {
|
|
1089
1190
|
return await fetchAllGraphPages({
|
|
1090
1191
|
token,
|
|
@@ -1105,7 +1206,7 @@ async function searchGraphUsers(params) {
|
|
|
1105
1206
|
path
|
|
1106
1207
|
})).value ?? [];
|
|
1107
1208
|
}
|
|
1108
|
-
const top =
|
|
1209
|
+
const top = params.top !== void 0 && params.top > 0 ? params.top : 10;
|
|
1109
1210
|
const path = `/users?$search=${encodeURIComponent(`"displayName:${query}"`)}&$select=id,displayName,mail,userPrincipalName&$top=${top}`;
|
|
1110
1211
|
return (await fetchGraphJson({
|
|
1111
1212
|
token: params.token,
|
|
@@ -1203,6 +1304,22 @@ function parseMSTeamsActivityTimestamp(value) {
|
|
|
1203
1304
|
function stripMSTeamsMentionTags(text) {
|
|
1204
1305
|
return text.replace(/<at[^>]*>.*?<\/at>/gi, "").trim();
|
|
1205
1306
|
}
|
|
1307
|
+
function normalizeMSTeamsMentionTags(text, activity, options = {}) {
|
|
1308
|
+
const normalizeTag = (tag) => tag.trim().replace(/<\/?at\b/gi, (delimiter) => delimiter.toLowerCase());
|
|
1309
|
+
const botId = activity.recipient?.id;
|
|
1310
|
+
const botMentions = /* @__PURE__ */ new Map();
|
|
1311
|
+
for (const entity of activity.entities ?? []) {
|
|
1312
|
+
if (entity.type !== "mention" || typeof entity.text !== "string") continue;
|
|
1313
|
+
const tag = normalizeTag(entity.text);
|
|
1314
|
+
const isBot = Boolean(botId && entity.mentioned?.id === botId);
|
|
1315
|
+
botMentions.set(tag, isBot && botMentions.get(tag) !== false);
|
|
1316
|
+
}
|
|
1317
|
+
return text.replace(/<at\b[^>]*>([\s\S]*?)<\/at\s*>/gi, (tag, label) => {
|
|
1318
|
+
if (botMentions.get(normalizeTag(tag))) return options.preserveHtml ? " " : "";
|
|
1319
|
+
const displayName = htmlToPlainText(label);
|
|
1320
|
+
return displayName ? `@${options.preserveHtml ? label : displayName}` : "";
|
|
1321
|
+
}).trim();
|
|
1322
|
+
}
|
|
1206
1323
|
function wasMSTeamsBotMentioned(activity) {
|
|
1207
1324
|
const botId = activity.recipient?.id;
|
|
1208
1325
|
if (!botId) return false;
|
|
@@ -1217,27 +1334,22 @@ function keepConfiguredMSTeamsAllowlistActive(configured, projected) {
|
|
|
1217
1334
|
if (!Array.isArray(configured) || configured.every((entry) => !entry?.trim())) return projected;
|
|
1218
1335
|
return projected && projected.length > 0 ? projected : [MSTEAMS_UNMATCHABLE_THREAD_ID];
|
|
1219
1336
|
}
|
|
1220
|
-
function
|
|
1337
|
+
function findExactMatches(items, query, fields = ["displayName"]) {
|
|
1338
|
+
const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
|
|
1221
1339
|
const byId = /* @__PURE__ */ new Map();
|
|
1222
1340
|
for (const item of items) {
|
|
1341
|
+
if (!fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)) continue;
|
|
1223
1342
|
const id = item.id?.trim();
|
|
1224
1343
|
if (id && !byId.has(id)) byId.set(id, item);
|
|
1225
1344
|
}
|
|
1226
1345
|
return [...byId.values()];
|
|
1227
1346
|
}
|
|
1228
|
-
function findExactMatches(items, query, fields = ["displayName"]) {
|
|
1229
|
-
const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
|
|
1230
|
-
return uniqueItemsById(items.filter((item) => fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)));
|
|
1231
|
-
}
|
|
1232
|
-
function isStableMSTeamsUserId(raw) {
|
|
1233
|
-
return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(raw));
|
|
1234
|
-
}
|
|
1235
1347
|
function normalizeStaticMSTeamsAllowEntry(raw) {
|
|
1236
1348
|
const trimmed = raw.trim();
|
|
1237
1349
|
if (!trimmed) return;
|
|
1238
1350
|
if (trimmed === "*" || /^accessGroup:/i.test(trimmed)) return trimmed;
|
|
1239
1351
|
const id = normalizeMSTeamsUserInput(trimmed);
|
|
1240
|
-
return
|
|
1352
|
+
return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(id)) ? id : void 0;
|
|
1241
1353
|
}
|
|
1242
1354
|
function projectStableMSTeamsAllowlist(entries, allowConversations) {
|
|
1243
1355
|
if (!entries) return;
|
|
@@ -1659,12 +1771,18 @@ async function resolveMSTeamsUserAllowlist(params) {
|
|
|
1659
1771
|
input,
|
|
1660
1772
|
resolved: true,
|
|
1661
1773
|
id: match.id,
|
|
1662
|
-
name: match.displayName
|
|
1774
|
+
name: match.displayName
|
|
1663
1775
|
};
|
|
1664
1776
|
}
|
|
1665
1777
|
});
|
|
1666
1778
|
}
|
|
1667
1779
|
//#endregion
|
|
1780
|
+
Object.defineProperty(exports, "GRAPH_HOSTS", {
|
|
1781
|
+
enumerable: true,
|
|
1782
|
+
get: function() {
|
|
1783
|
+
return GRAPH_HOSTS;
|
|
1784
|
+
}
|
|
1785
|
+
});
|
|
1668
1786
|
Object.defineProperty(exports, "GRAPH_ROOT", {
|
|
1669
1787
|
enumerable: true,
|
|
1670
1788
|
get: function() {
|
|
@@ -1689,6 +1807,12 @@ Object.defineProperty(exports, "MSTEAMS_REQUEST_TIMEOUT_MS", {
|
|
|
1689
1807
|
return MSTEAMS_REQUEST_TIMEOUT_MS;
|
|
1690
1808
|
}
|
|
1691
1809
|
});
|
|
1810
|
+
Object.defineProperty(exports, "SHAREPOINT_HOSTS", {
|
|
1811
|
+
enumerable: true,
|
|
1812
|
+
get: function() {
|
|
1813
|
+
return SHAREPOINT_HOSTS;
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1692
1816
|
Object.defineProperty(exports, "applyAuthorizationHeaderForUrl", {
|
|
1693
1817
|
enumerable: true,
|
|
1694
1818
|
get: function() {
|
|
@@ -1857,12 +1981,6 @@ Object.defineProperty(exports, "keepConfiguredMSTeamsAllowlistActive", {
|
|
|
1857
1981
|
return keepConfiguredMSTeamsAllowlistActive;
|
|
1858
1982
|
}
|
|
1859
1983
|
});
|
|
1860
|
-
Object.defineProperty(exports, "listChannelsForTeam", {
|
|
1861
|
-
enumerable: true,
|
|
1862
|
-
get: function() {
|
|
1863
|
-
return listChannelsForTeam;
|
|
1864
|
-
}
|
|
1865
|
-
});
|
|
1866
1984
|
Object.defineProperty(exports, "listChannelsForTeamWithPageInfo", {
|
|
1867
1985
|
enumerable: true,
|
|
1868
1986
|
get: function() {
|
|
@@ -1875,10 +1993,10 @@ Object.defineProperty(exports, "listMSTeamsAccountIds", {
|
|
|
1875
1993
|
return listMSTeamsAccountIds;
|
|
1876
1994
|
}
|
|
1877
1995
|
});
|
|
1878
|
-
Object.defineProperty(exports, "
|
|
1996
|
+
Object.defineProperty(exports, "listTeamsByNameWithPageInfo", {
|
|
1879
1997
|
enumerable: true,
|
|
1880
1998
|
get: function() {
|
|
1881
|
-
return
|
|
1999
|
+
return listTeamsByNameWithPageInfo;
|
|
1882
2000
|
}
|
|
1883
2001
|
});
|
|
1884
2002
|
Object.defineProperty(exports, "loadMSTeamsSdkWithAuth", {
|
|
@@ -1917,22 +2035,22 @@ Object.defineProperty(exports, "normalizeMSTeamsConversationId", {
|
|
|
1917
2035
|
return normalizeMSTeamsConversationId;
|
|
1918
2036
|
}
|
|
1919
2037
|
});
|
|
1920
|
-
Object.defineProperty(exports, "
|
|
2038
|
+
Object.defineProperty(exports, "normalizeMSTeamsMentionTags", {
|
|
1921
2039
|
enumerable: true,
|
|
1922
2040
|
get: function() {
|
|
1923
|
-
return
|
|
2041
|
+
return normalizeMSTeamsMentionTags;
|
|
1924
2042
|
}
|
|
1925
2043
|
});
|
|
1926
|
-
Object.defineProperty(exports, "
|
|
2044
|
+
Object.defineProperty(exports, "normalizeMSTeamsMessagingTarget", {
|
|
1927
2045
|
enumerable: true,
|
|
1928
2046
|
get: function() {
|
|
1929
|
-
return
|
|
2047
|
+
return normalizeMSTeamsMessagingTarget;
|
|
1930
2048
|
}
|
|
1931
2049
|
});
|
|
1932
|
-
Object.defineProperty(exports, "
|
|
2050
|
+
Object.defineProperty(exports, "normalizeMSTeamsUserInput", {
|
|
1933
2051
|
enumerable: true,
|
|
1934
2052
|
get: function() {
|
|
1935
|
-
return
|
|
2053
|
+
return normalizeMSTeamsUserInput;
|
|
1936
2054
|
}
|
|
1937
2055
|
});
|
|
1938
2056
|
Object.defineProperty(exports, "parseMSTeamsActivityTimestamp", {
|
|
@@ -1977,6 +2095,12 @@ Object.defineProperty(exports, "projectStableMSTeamsUserAllowlist", {
|
|
|
1977
2095
|
return projectStableMSTeamsUserAllowlist;
|
|
1978
2096
|
}
|
|
1979
2097
|
});
|
|
2098
|
+
Object.defineProperty(exports, "replaceTeamsEmojiSpriteImagesWithAltText", {
|
|
2099
|
+
enumerable: true,
|
|
2100
|
+
get: function() {
|
|
2101
|
+
return replaceTeamsEmojiSpriteImagesWithAltText;
|
|
2102
|
+
}
|
|
2103
|
+
});
|
|
1980
2104
|
Object.defineProperty(exports, "resolveAttachmentFetchPolicy", {
|
|
1981
2105
|
enumerable: true,
|
|
1982
2106
|
get: function() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
let
|
|
1
|
+
let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
|
|
2
2
|
let openclaw_plugin_sdk_channel_secret_basic_runtime = require("openclaw/plugin-sdk/channel-secret-basic-runtime");
|
|
3
3
|
//#region extensions/msteams/src/secret-contract.ts
|
|
4
4
|
const secretTargetRegistryEntries = (0, openclaw_plugin_sdk_channel_secret_basic_runtime.createChannelSecretTargetRegistryEntries)({
|
|
@@ -10,13 +10,14 @@ function collectRuntimeConfigAssignments(params) {
|
|
|
10
10
|
const resolved = (0, openclaw_plugin_sdk_channel_secret_basic_runtime.getChannelSurface)(params.config, "msteams");
|
|
11
11
|
if (!resolved) return;
|
|
12
12
|
const { channel: msteams, surface } = resolved;
|
|
13
|
+
const defaultEnabled = (surface.hasExplicitAccounts ? surface.accounts.find(({ accountId }) => (0, openclaw_plugin_sdk_account_id.normalizeAccountId)(accountId) === openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID) : void 0)?.enabled ?? surface.channelEnabled;
|
|
13
14
|
(0, openclaw_plugin_sdk_channel_secret_basic_runtime.collectSecretInputAssignment)({
|
|
14
15
|
value: msteams.appPassword,
|
|
15
16
|
path: "channels.msteams.appPassword",
|
|
16
17
|
expected: "string",
|
|
17
18
|
defaults: params.defaults,
|
|
18
19
|
context: params.context,
|
|
19
|
-
active:
|
|
20
|
+
active: defaultEnabled && (isConfiguredIdentityField(msteams.appId) || isConfiguredIdentityField(msteams.appPassword)),
|
|
20
21
|
inactiveReason: "no enabled account inherits this top-level Microsoft Teams appPassword.",
|
|
21
22
|
owner: {
|
|
22
23
|
ownerKind: "account",
|
|
@@ -42,7 +43,7 @@ function collectRuntimeConfigAssignments(params) {
|
|
|
42
43
|
inactiveReason: "Microsoft Teams account is disabled.",
|
|
43
44
|
owner: {
|
|
44
45
|
ownerKind: "account",
|
|
45
|
-
ownerId: `msteams:${(0,
|
|
46
|
+
ownerId: `msteams:${(0, openclaw_plugin_sdk_account_id.normalizeAccountId)(accountId)}`,
|
|
46
47
|
requiredForGateway: false,
|
|
47
48
|
disposition: "isolate",
|
|
48
49
|
contract: account
|
|
@@ -57,9 +58,6 @@ function isConfiguredIdentityField(value) {
|
|
|
57
58
|
if (typeof value === "string") return value.trim().length > 0;
|
|
58
59
|
return value !== void 0 && value !== null;
|
|
59
60
|
}
|
|
60
|
-
function isRootDefaultIdentityActive(channel, surface) {
|
|
61
|
-
return ((surface.hasExplicitAccounts ? surface.accounts.find(({ accountId }) => (0, openclaw_plugin_sdk_setup.normalizeAccountId)(accountId) === openclaw_plugin_sdk_setup.DEFAULT_ACCOUNT_ID) : void 0)?.enabled ?? surface.channelEnabled) && (isConfiguredIdentityField(channel.appId) || isConfiguredIdentityField(channel.appPassword));
|
|
62
|
-
}
|
|
63
61
|
const channelSecrets = {
|
|
64
62
|
secretTargetRegistryEntries,
|
|
65
63
|
collectRuntimeConfigAssignments
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_secret_contract_api = require("./secret-contract-api-
|
|
1
|
+
const require_secret_contract_api = require("./secret-contract-api-D554HIrH.cjs");
|
|
2
2
|
exports.channelSecrets = require_secret_contract_api.channelSecrets;
|
|
3
3
|
exports.collectRuntimeConfigAssignments = require_secret_contract_api.collectRuntimeConfigAssignments;
|
|
4
4
|
exports.secretTargetRegistryEntries = require_secret_contract_api.secretTargetRegistryEntries;
|