@openclaw/msteams 2026.10.10 → 2026.11.5-beta.1
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-BMvpm7sS.cjs → adapter.runtime-UOD_H_ph.cjs} +20 -23
- package/dist/.setup/{approval-card-Bo8kHYbj.cjs → approval-card-CD5q0Nla.cjs} +5 -9
- package/dist/.setup/{approval-handler.runtime-BS3avHFu.cjs → approval-handler.runtime-DbPxvynk.cjs} +4 -4
- package/dist/.setup/{channel-CdCSk3Rg.cjs → channel-DQrXOfhf.cjs} +24 -224
- package/dist/.setup/{channel.runtime--ZjTYgkY.cjs → channel.runtime-Du4GPMES.cjs} +65 -106
- package/dist/.setup/{channel.setup-nSTtK77J.cjs → channel.setup--7ko_Kxv.cjs} +161 -262
- package/dist/.setup/{config-schema-Bm15lF-j.cjs → config-schema-BEXDIOC-.cjs} +120 -123
- package/dist/.setup/{conversation-store-state-NJU9osd-.cjs → conversation-store-state-AVgRyNE9.cjs} +411 -598
- package/dist/.setup/{delegated-state-CbMd3rIh.cjs → delegated-state-DhIHahf1.cjs} +68 -6
- package/dist/.setup/{monitor-BxLDs5fk.cjs → monitor-CXjIKz7o.cjs} +1883 -2284
- package/dist/.setup/{oauth-B-Y5pNM4.cjs → oauth-BWG6qWCd.cjs} +10 -20
- package/dist/.setup/presentation-CaLawc5j.cjs +211 -0
- package/dist/.setup/{reaction-types-BaL1EVBS.cjs → reaction-types-DOzN5oTl.cjs} +1 -1
- package/dist/.setup/{resolve-allowlist-CqNzS9bZ.cjs → resolve-allowlist-Drj1jaq0.cjs} +213 -90
- package/dist/.setup/{secret-contract-api-BOzdWSn9.cjs → secret-contract-api-DFqDvc_a.cjs} +4 -6
- package/dist/.setup/{secret-contract-api-5aH1Fl_c.cjs → secret-contract-api-YGHrfAT0.cjs} +1 -1
- package/dist/.setup/{send-BXjI3ufq.cjs → send-BRUztzVJ.cjs} +86 -182
- package/dist/.setup/{setup-plugin-api-lPpin6Gg.cjs → setup-plugin-api-BHEfter5.cjs} +1 -1
- package/dist/.setup/{thread-session-DZMoCsSR.cjs → thread-session-BUUV1zk_.cjs} +4 -6
- package/dist/.setup/{token-config-DTZ00Ibq.cjs → token-config-7K6UbNCo.cjs} +0 -2
- package/dist/.source-module-urls/7e43ee3ae4faab430a47269c8217f8d99ec60ecd85233f40e81d03efeb543068.json +1 -1
- 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 +6 -13
- 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-CgVuKiIR.cjs");
|
|
2
|
-
const require_token_config = require("./token-config-
|
|
2
|
+
const require_token_config = require("./token-config-7K6UbNCo.cjs");
|
|
3
3
|
const require_runtime = require("./runtime-CbKazLGv.cjs");
|
|
4
4
|
require("../runtime-api.cjs");
|
|
5
|
-
const require_delegated_state = require("./delegated-state-
|
|
5
|
+
const require_delegated_state = require("./delegated-state-DhIHahf1.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
|
// extensions/msteams/src/accounts.ts
|
|
26
27
|
const { listAccountIds, resolveDefaultAccountId } = (0, openclaw_plugin_sdk_account_helpers.createAccountListHelpers)("msteams", {
|
|
@@ -169,6 +170,20 @@ function inspectMSTeamsAccount(params) {
|
|
|
169
170
|
path: account.config.webhook?.path ?? "/api/messages"
|
|
170
171
|
};
|
|
171
172
|
}
|
|
173
|
+
// extensions/msteams/src/microsoft-hosts.ts
|
|
174
|
+
const GRAPH_HOSTS = [
|
|
175
|
+
"graph.microsoft.com",
|
|
176
|
+
"graph.microsoft.us",
|
|
177
|
+
"graph.microsoft.de",
|
|
178
|
+
"graph.microsoft.cn"
|
|
179
|
+
];
|
|
180
|
+
const SHAREPOINT_HOSTS = [
|
|
181
|
+
"sharepoint.com",
|
|
182
|
+
"sharepoint.us",
|
|
183
|
+
"sharepoint.de",
|
|
184
|
+
"sharepoint.cn",
|
|
185
|
+
"sharepoint-df.com"
|
|
186
|
+
];
|
|
172
187
|
// extensions/msteams/src/request-timeout.ts
|
|
173
188
|
const MSTEAMS_REQUEST_TIMEOUT_MS = 3e4;
|
|
174
189
|
const MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS = 3e5;
|
|
@@ -227,7 +242,7 @@ const IMAGE_EXT_RE = /\.(avif|bmp|gif|heic|heif|jpe?g|png|tiff?|webp)$/i;
|
|
|
227
242
|
* tag wins, and a quoted value may contain `>`. Each `<tag` start is resolved from
|
|
228
243
|
* precomputed next-`>` and next-quote positions in one forward pass.
|
|
229
244
|
*/
|
|
230
|
-
function htmlTagAttributeValues(html, tag, attr) {
|
|
245
|
+
function htmlTagAttributeValues(html, tag, attr, visit) {
|
|
231
246
|
const length = html.length;
|
|
232
247
|
const nextGt = new Int32Array(length + 1).fill(length);
|
|
233
248
|
const nextQuote = new Int32Array(length + 1).fill(length);
|
|
@@ -257,13 +272,37 @@ function htmlTagAttributeValues(html, tag, attr) {
|
|
|
257
272
|
while (pastWindow < candidates.length && candidates[pastWindow].start <= lastStart) pastWindow += 1;
|
|
258
273
|
const candidate = candidates[pastWindow - 1];
|
|
259
274
|
if (candidate && candidate.start > nameEnd) {
|
|
260
|
-
|
|
275
|
+
const value = html.slice(candidate.valueStart, candidate.valueEnd);
|
|
276
|
+
if (visit) visit(value, open.index, candidate.end);
|
|
277
|
+
else values.push(value);
|
|
261
278
|
resumeAt = candidate.end;
|
|
262
279
|
}
|
|
263
280
|
}
|
|
264
281
|
return values;
|
|
265
282
|
}
|
|
266
283
|
const GRAPH_HOSTED_CONTENT_SRC_RE = /\/hostedContents\/([^/?#]+)/i;
|
|
284
|
+
const TEAMS_EMOJI_CDN_HOST = "statics.teams.cdn.office.net";
|
|
285
|
+
const TEAMS_EMOJI_ASSET_PATH_RE = /\/emoji([/?#]|$)/i;
|
|
286
|
+
const IMG_ALT_ATTR_RE = /\balt=["']([^"']*)["']/i;
|
|
287
|
+
const EMOJI_PICTOGRAPHIC_RE = /\p{Extended_Pictographic}/u;
|
|
288
|
+
function isTeamsEmojiSpriteImage(src, imgTag) {
|
|
289
|
+
const url = URL.parse(src);
|
|
290
|
+
const host = url?.hostname.toLowerCase() ?? "";
|
|
291
|
+
if (host !== TEAMS_EMOJI_CDN_HOST && !host.endsWith(`.${TEAMS_EMOJI_CDN_HOST}`)) return false;
|
|
292
|
+
return TEAMS_EMOJI_ASSET_PATH_RE.test(url?.pathname ?? "") || EMOJI_PICTOGRAPHIC_RE.test(IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
|
|
293
|
+
}
|
|
294
|
+
function replaceTeamsEmojiSpriteImagesWithAltText(html) {
|
|
295
|
+
const parts = [];
|
|
296
|
+
let cursor = 0;
|
|
297
|
+
htmlTagAttributeValues(html, "img", "src", (src, start, end) => {
|
|
298
|
+
const imgTag = html.slice(start, end);
|
|
299
|
+
if (isTeamsEmojiSpriteImage(src.trim(), imgTag)) {
|
|
300
|
+
parts.push(html.slice(cursor, start), IMG_ALT_ATTR_RE.exec(imgTag)?.[1] ?? "");
|
|
301
|
+
cursor = end;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
return parts.join("") + html.slice(cursor);
|
|
305
|
+
}
|
|
267
306
|
function resolveInlineImageSourceId(src) {
|
|
268
307
|
const hostedContentId = GRAPH_HOSTED_CONTENT_SRC_RE.exec(src)?.[1];
|
|
269
308
|
if (!hostedContentId) return src;
|
|
@@ -274,15 +313,8 @@ function resolveInlineImageSourceId(src) {
|
|
|
274
313
|
}
|
|
275
314
|
}
|
|
276
315
|
const DEFAULT_MEDIA_HOST_ALLOWLIST = [
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
"graph.microsoft.de",
|
|
280
|
-
"graph.microsoft.cn",
|
|
281
|
-
"sharepoint.com",
|
|
282
|
-
"sharepoint.us",
|
|
283
|
-
"sharepoint.de",
|
|
284
|
-
"sharepoint.cn",
|
|
285
|
-
"sharepoint-df.com",
|
|
316
|
+
...GRAPH_HOSTS,
|
|
317
|
+
...SHAREPOINT_HOSTS,
|
|
286
318
|
"1drv.ms",
|
|
287
319
|
"onedrive.com",
|
|
288
320
|
"teams.microsoft.com",
|
|
@@ -304,10 +336,7 @@ const DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST = [
|
|
|
304
336
|
"botframework.com",
|
|
305
337
|
"smba.trafficmanager.net",
|
|
306
338
|
"botframework.azure.cn",
|
|
307
|
-
|
|
308
|
-
"graph.microsoft.us",
|
|
309
|
-
"graph.microsoft.de",
|
|
310
|
-
"graph.microsoft.cn"
|
|
339
|
+
...GRAPH_HOSTS
|
|
311
340
|
];
|
|
312
341
|
const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
|
|
313
342
|
/**
|
|
@@ -319,11 +348,7 @@ const GRAPH_ROOT = "https://graph.microsoft.com/v1.0";
|
|
|
319
348
|
* https://learn.microsoft.com/en-us/graph/api/shares-get for the encoding.
|
|
320
349
|
*/
|
|
321
350
|
const GRAPH_SHARED_LINK_HOST_SUFFIXES = [
|
|
322
|
-
|
|
323
|
-
".sharepoint.us",
|
|
324
|
-
".sharepoint.de",
|
|
325
|
-
".sharepoint.cn",
|
|
326
|
-
".sharepoint-df.com",
|
|
351
|
+
...SHAREPOINT_HOSTS.map((host) => `.${host}`),
|
|
327
352
|
"1drv.ms",
|
|
328
353
|
"onedrive.live.com",
|
|
329
354
|
"onedrive.com"
|
|
@@ -401,7 +426,7 @@ function extractInlineImageReferences(attachments) {
|
|
|
401
426
|
for (const att of attachments) {
|
|
402
427
|
const html = extractHtmlFromAttachment(att);
|
|
403
428
|
if (!html) continue;
|
|
404
|
-
for (const value of htmlTagAttributeValues(html, "img", "src")) {
|
|
429
|
+
for (const value of htmlTagAttributeValues(replaceTeamsEmojiSpriteImagesWithAltText(html), "img", "src")) {
|
|
405
430
|
const src = value.trim();
|
|
406
431
|
if (src) {
|
|
407
432
|
if (src.startsWith("data:")) out.push({
|
|
@@ -434,15 +459,6 @@ function safeHostForUrl(url) {
|
|
|
434
459
|
const parsed = URL.parse(url);
|
|
435
460
|
return parsed ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(parsed.hostname) : "invalid-url";
|
|
436
461
|
}
|
|
437
|
-
function isMockFetchFn(fetchFn) {
|
|
438
|
-
const candidate = fetchFn;
|
|
439
|
-
return Boolean(candidate.mock || Object.hasOwn(candidate, "_isMockFunction"));
|
|
440
|
-
}
|
|
441
|
-
function resolveGuardedFetchImpl(fetchFn) {
|
|
442
|
-
if (!fetchFn) return;
|
|
443
|
-
if (fetchFn === fetch || fetchFn === globalThis.fetch || isMockFetchFn(fetchFn)) return fetchFn;
|
|
444
|
-
throw new Error("MSTeams attachment fetchFn must set fetchFnSupportsDispatcher to use guarded DNS pinning");
|
|
445
|
-
}
|
|
446
462
|
function resolveRetainedAuthorizationRedirectHostnameAllowlist(input) {
|
|
447
463
|
if (!input) return;
|
|
448
464
|
if (input.includes("*")) return ["*"];
|
|
@@ -464,21 +480,20 @@ function isRedirectStatus(status) {
|
|
|
464
480
|
}
|
|
465
481
|
/**
|
|
466
482
|
* Fetch a URL with redirect: "manual", validating each redirect target
|
|
467
|
-
* against the hostname allowlist and
|
|
483
|
+
* against the hostname allowlist and DNS-resolved IP (anti-SSRF).
|
|
468
484
|
*
|
|
469
485
|
* This prevents:
|
|
470
486
|
* - Auto-following redirects to non-allowlisted hosts
|
|
471
|
-
* - DNS rebinding attacks
|
|
487
|
+
* - DNS rebinding attacks through the pinned DNS lookup
|
|
472
488
|
*/
|
|
473
489
|
async function safeFetchWithPolicy(params) {
|
|
474
490
|
const { allowHosts, authAllowHosts } = params.policy;
|
|
475
|
-
const resolveFn = params.resolveFn ?? node_dns_promises.lookup;
|
|
476
491
|
const currentHeaders = new Headers(params.requestInit?.headers);
|
|
477
492
|
const currentUrl = params.url;
|
|
478
493
|
if (!(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, allowHosts)) throw new Error(`Initial download URL blocked: ${currentUrl}`);
|
|
479
494
|
if (currentHeaders.has("authorization") && !(0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(currentUrl, authAllowHosts)) currentHeaders.delete("authorization");
|
|
480
495
|
const lookupFn = async (hostname) => {
|
|
481
|
-
const resolved = await resolveFn(hostname);
|
|
496
|
+
const resolved = await params.resolveFn(hostname);
|
|
482
497
|
return [{
|
|
483
498
|
...resolved,
|
|
484
499
|
family: resolved.address.includes(":") ? 6 : 4
|
|
@@ -486,7 +501,6 @@ async function safeFetchWithPolicy(params) {
|
|
|
486
501
|
};
|
|
487
502
|
const guarded = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
488
503
|
url: currentUrl,
|
|
489
|
-
fetchImpl: resolveGuardedFetchImpl(params.fetchFn),
|
|
490
504
|
init: {
|
|
491
505
|
...params.requestInit,
|
|
492
506
|
headers: currentHeaders
|
|
@@ -792,7 +806,7 @@ const EXPIRY_BUFFER_MS = 3e5;
|
|
|
792
806
|
function parseMSTeamsTokenResponse(data, failureLabel) {
|
|
793
807
|
if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(data)) throw new Error(`MSTeams ${failureLabel} failed: invalid token response fields`);
|
|
794
808
|
const expiresAt = (0, openclaw_plugin_sdk_number_runtime.resolveExpiresAtMsFromDurationSeconds)(data.expires_in, { bufferMs: EXPIRY_BUFFER_MS });
|
|
795
|
-
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`);
|
|
809
|
+
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`);
|
|
796
810
|
return {
|
|
797
811
|
access_token: data.access_token,
|
|
798
812
|
refresh_token: data.refresh_token,
|
|
@@ -801,7 +815,11 @@ function parseMSTeamsTokenResponse(data, failureLabel) {
|
|
|
801
815
|
};
|
|
802
816
|
}
|
|
803
817
|
async function fetchMSTeamsTokens(params) {
|
|
818
|
+
let dispatched = false;
|
|
804
819
|
const { response, release } = await (0, openclaw_plugin_sdk_ssrf_runtime.fetchWithSsrFGuard)({
|
|
820
|
+
beforeRequest: () => {
|
|
821
|
+
dispatched = true;
|
|
822
|
+
},
|
|
805
823
|
url: params.tokenUrl,
|
|
806
824
|
init: {
|
|
807
825
|
method: "POST",
|
|
@@ -813,10 +831,56 @@ async function fetchMSTeamsTokens(params) {
|
|
|
813
831
|
signal: AbortSignal.timeout(MSTEAMS_DEFAULT_TOKEN_FETCH_TIMEOUT_MS)
|
|
814
832
|
},
|
|
815
833
|
auditContext: params.auditContext
|
|
834
|
+
}).catch((cause) => {
|
|
835
|
+
if (!params.refresh) throw cause;
|
|
836
|
+
throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh transport failed", dispatched ? {
|
|
837
|
+
version: 1,
|
|
838
|
+
phase: "token-response",
|
|
839
|
+
outcome: "unchanged",
|
|
840
|
+
recovery: {
|
|
841
|
+
kind: "later",
|
|
842
|
+
evidence: "documented-reusable-grant"
|
|
843
|
+
}
|
|
844
|
+
} : {
|
|
845
|
+
version: 1,
|
|
846
|
+
phase: "before-dispatch",
|
|
847
|
+
outcome: "not-attempted",
|
|
848
|
+
recovery: {
|
|
849
|
+
kind: "later",
|
|
850
|
+
evidence: "dispatch-not-started"
|
|
851
|
+
}
|
|
852
|
+
}, { cause });
|
|
816
853
|
});
|
|
817
854
|
try {
|
|
818
|
-
if (!response.ok) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
|
|
819
|
-
|
|
855
|
+
if (!response.ok && !params.refresh) throw await (0, openclaw_plugin_sdk_provider_http.createProviderHttpError)(response, `MSTeams ${params.failureLabel} failed`);
|
|
856
|
+
let data;
|
|
857
|
+
try {
|
|
858
|
+
data = await (0, openclaw_plugin_sdk_provider_http.readProviderJsonResponse)(response, `MSTeams ${params.failureLabel} failed`);
|
|
859
|
+
} catch (cause) {
|
|
860
|
+
if (!params.refresh) throw cause;
|
|
861
|
+
if (!response.ok) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshResponseError)("MSTeams token refresh", response.status, void 0, "documented-reusable-grant");
|
|
862
|
+
throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response could not be read", {
|
|
863
|
+
version: 1,
|
|
864
|
+
phase: "token-response",
|
|
865
|
+
outcome: "unchanged",
|
|
866
|
+
recovery: {
|
|
867
|
+
kind: "later",
|
|
868
|
+
evidence: "documented-reusable-grant"
|
|
869
|
+
}
|
|
870
|
+
}, { cause });
|
|
871
|
+
}
|
|
872
|
+
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");
|
|
873
|
+
try {
|
|
874
|
+
return parseMSTeamsTokenResponse(data, params.failureLabel);
|
|
875
|
+
} catch (cause) {
|
|
876
|
+
if (!params.refresh) throw cause;
|
|
877
|
+
throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("MSTeams refresh response fields are invalid", {
|
|
878
|
+
version: 1,
|
|
879
|
+
phase: "after-token-response",
|
|
880
|
+
outcome: "unknown",
|
|
881
|
+
status: response.status
|
|
882
|
+
}, { cause });
|
|
883
|
+
}
|
|
820
884
|
} finally {
|
|
821
885
|
await release();
|
|
822
886
|
}
|
|
@@ -834,7 +898,8 @@ async function requestMSTeamsDelegatedTokens(params) {
|
|
|
834
898
|
tokenUrl: buildMSTeamsTokenEndpoint(params.tenantId),
|
|
835
899
|
body,
|
|
836
900
|
auditContext: params.auditContext,
|
|
837
|
-
failureLabel: params.failureLabel
|
|
901
|
+
failureLabel: params.failureLabel,
|
|
902
|
+
refresh: params.grantType === "refresh_token"
|
|
838
903
|
});
|
|
839
904
|
return {
|
|
840
905
|
accessToken: data.access_token,
|
|
@@ -849,7 +914,6 @@ async function exchangeMSTeamsCodeForTokens(params) {
|
|
|
849
914
|
clientId: params.clientId,
|
|
850
915
|
clientSecret: params.clientSecret,
|
|
851
916
|
grantType: "authorization_code",
|
|
852
|
-
scopes: params.scopes,
|
|
853
917
|
values: {
|
|
854
918
|
code: params.code,
|
|
855
919
|
redirect_uri: MSTEAMS_OAUTH_REDIRECT_URI,
|
|
@@ -877,22 +941,67 @@ async function refreshMSTeamsDelegatedTokens(params) {
|
|
|
877
941
|
});
|
|
878
942
|
}
|
|
879
943
|
// extensions/msteams/src/token.ts
|
|
944
|
+
const refreshes = /* @__PURE__ */ new WeakMap();
|
|
880
945
|
async function resolveDelegatedAccessToken(params) {
|
|
881
|
-
const
|
|
882
|
-
|
|
946
|
+
const runtime = require_runtime.getMSTeamsRuntime();
|
|
947
|
+
const callerKey = (0, node_crypto.createHash)("sha256").update(JSON.stringify([
|
|
948
|
+
runtime.state.resolveStateDir(),
|
|
949
|
+
require_delegated_state.resolveMSTeamsAccountStateNamespace("delegated-token", params.accountId),
|
|
950
|
+
params.tenantId,
|
|
951
|
+
params.clientId,
|
|
952
|
+
params.clientSecret
|
|
953
|
+
])).digest("hex");
|
|
954
|
+
const state = await require_delegated_state.loadMSTeamsDelegatedTokenState(params.accountId);
|
|
955
|
+
const tokens = require_delegated_state.normalizeMSTeamsDelegatedTokens(state);
|
|
956
|
+
const active = refreshes.get(runtime) ?? /* @__PURE__ */ new Map();
|
|
957
|
+
refreshes.set(runtime, active);
|
|
958
|
+
if (state && "refreshClaim" in state && state.callerKey === callerKey) {
|
|
959
|
+
const pending = active.get(state.requestKey);
|
|
960
|
+
if (pending) return await pending;
|
|
961
|
+
}
|
|
962
|
+
if (!tokens) return state && "refreshClaim" in state && state.callerKey === callerKey ? await active.get(state.requestKey) : void 0;
|
|
883
963
|
if ((0, openclaw_plugin_sdk_number_runtime.isFutureDateTimestampMs)(tokens.expiresAt)) return tokens.accessToken;
|
|
964
|
+
const key = (0, node_crypto.createHash)("sha256").update(JSON.stringify([callerKey, tokens])).digest("hex");
|
|
965
|
+
const pending = active.get(key);
|
|
966
|
+
if (pending) return await pending;
|
|
967
|
+
const task = (async () => {
|
|
968
|
+
try {
|
|
969
|
+
const claim = await require_delegated_state.claimMSTeamsDelegatedTokenRefresh(tokens, key, callerKey, params.accountId);
|
|
970
|
+
if (!claim) return;
|
|
971
|
+
let refreshed;
|
|
972
|
+
try {
|
|
973
|
+
if (require_runtime.getMSTeamsRuntime() !== runtime) throw (0, openclaw_plugin_sdk_provider_oauth_runtime.createOAuthRefreshError)("Microsoft Teams token owner changed before refresh dispatch", {
|
|
974
|
+
version: 1,
|
|
975
|
+
phase: "before-dispatch",
|
|
976
|
+
outcome: "not-attempted",
|
|
977
|
+
recovery: {
|
|
978
|
+
kind: "later",
|
|
979
|
+
evidence: "dispatch-not-started"
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
refreshed = await refreshMSTeamsDelegatedTokens({
|
|
983
|
+
...params,
|
|
984
|
+
refreshToken: tokens.refreshToken,
|
|
985
|
+
scopes: tokens.scopes
|
|
986
|
+
});
|
|
987
|
+
} catch (error) {
|
|
988
|
+
if ((0, openclaw_plugin_sdk_provider_oauth_runtime.isRecoverableOAuthRefreshFailure)(error)) await claim.settle(tokens);
|
|
989
|
+
else await claim.reject();
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
return await claim.settle({
|
|
993
|
+
...tokens,
|
|
994
|
+
...refreshed
|
|
995
|
+
}) ? refreshed.accessToken : void 0;
|
|
996
|
+
} catch {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
})();
|
|
1000
|
+
active.set(key, task);
|
|
884
1001
|
try {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
clientSecret: params.clientSecret,
|
|
889
|
-
refreshToken: tokens.refreshToken,
|
|
890
|
-
scopes: tokens.scopes
|
|
891
|
-
});
|
|
892
|
-
await require_delegated_state.saveMSTeamsDelegatedTokens(refreshed, params.accountId);
|
|
893
|
-
return refreshed.accessToken;
|
|
894
|
-
} catch {
|
|
895
|
-
return;
|
|
1002
|
+
return await task;
|
|
1003
|
+
} finally {
|
|
1004
|
+
if (active.get(key) === task) active.delete(key);
|
|
896
1005
|
}
|
|
897
1006
|
}
|
|
898
1007
|
// extensions/msteams/src/graph.ts
|
|
@@ -910,9 +1019,6 @@ function captureGraphRequestCurrentness(assertReadAuthority) {
|
|
|
910
1019
|
assertCurrent();
|
|
911
1020
|
};
|
|
912
1021
|
}
|
|
913
|
-
function normalizeQuery(value) {
|
|
914
|
-
return value?.trim() ?? "";
|
|
915
|
-
}
|
|
916
1022
|
function escapeOData(value) {
|
|
917
1023
|
return value.replace(/'/g, "''");
|
|
918
1024
|
}
|
|
@@ -1053,9 +1159,6 @@ async function resolveGraphToken(cfg, options) {
|
|
|
1053
1159
|
if (!accessToken) throw new Error("MS Teams graph token unavailable");
|
|
1054
1160
|
return accessToken;
|
|
1055
1161
|
}
|
|
1056
|
-
async function listTeamsByName(token, query) {
|
|
1057
|
-
return (await listTeamsByNameWithPageInfo(token, query)).items;
|
|
1058
|
-
}
|
|
1059
1162
|
async function listTeamsByNameWithPageInfo(token, query) {
|
|
1060
1163
|
const filter = `resourceProvisioningOptions/Any(x:x eq 'Team') and startsWith(displayName,'${escapeOData(query)}')`;
|
|
1061
1164
|
return await fetchAllGraphPages({
|
|
@@ -1071,9 +1174,6 @@ async function deleteGraphRequest(params) {
|
|
|
1071
1174
|
errorPrefix: "Graph DELETE"
|
|
1072
1175
|
})).body?.cancel().catch(() => void 0);
|
|
1073
1176
|
}
|
|
1074
|
-
async function listChannelsForTeam(token, teamId) {
|
|
1075
|
-
return (await listChannelsForTeamWithPageInfo(token, teamId)).items;
|
|
1076
|
-
}
|
|
1077
1177
|
async function listChannelsForTeamWithPageInfo(token, teamId) {
|
|
1078
1178
|
return await fetchAllGraphPages({
|
|
1079
1179
|
token,
|
|
@@ -1093,7 +1193,7 @@ async function searchGraphUsers(params) {
|
|
|
1093
1193
|
path
|
|
1094
1194
|
})).value ?? [];
|
|
1095
1195
|
}
|
|
1096
|
-
const top =
|
|
1196
|
+
const top = params.top !== void 0 && params.top > 0 ? params.top : 10;
|
|
1097
1197
|
const path = `/users?$search=${encodeURIComponent(`"displayName:${query}"`)}&$select=id,displayName,mail,userPrincipalName&$top=${top}`;
|
|
1098
1198
|
return (await fetchGraphJson({
|
|
1099
1199
|
token: params.token,
|
|
@@ -1190,6 +1290,22 @@ function parseMSTeamsActivityTimestamp(value) {
|
|
|
1190
1290
|
function stripMSTeamsMentionTags(text) {
|
|
1191
1291
|
return text.replace(/<at[^>]*>.*?<\/at>/gi, "").trim();
|
|
1192
1292
|
}
|
|
1293
|
+
function normalizeMSTeamsMentionTags(text, activity, options = {}) {
|
|
1294
|
+
const normalizeTag = (tag) => tag.trim().replace(/<\/?at\b/gi, (delimiter) => delimiter.toLowerCase());
|
|
1295
|
+
const botId = activity.recipient?.id;
|
|
1296
|
+
const botMentions = /* @__PURE__ */ new Map();
|
|
1297
|
+
for (const entity of activity.entities ?? []) {
|
|
1298
|
+
if (entity.type !== "mention" || typeof entity.text !== "string") continue;
|
|
1299
|
+
const tag = normalizeTag(entity.text);
|
|
1300
|
+
const isBot = Boolean(botId && entity.mentioned?.id === botId);
|
|
1301
|
+
botMentions.set(tag, isBot && botMentions.get(tag) !== false);
|
|
1302
|
+
}
|
|
1303
|
+
return text.replace(/<at\b[^>]*>([\s\S]*?)<\/at\s*>/gi, (tag, label) => {
|
|
1304
|
+
if (botMentions.get(normalizeTag(tag))) return options.preserveHtml ? " " : "";
|
|
1305
|
+
const displayName = htmlToPlainText(label);
|
|
1306
|
+
return displayName ? `@${options.preserveHtml ? label : displayName}` : "";
|
|
1307
|
+
}).trim();
|
|
1308
|
+
}
|
|
1193
1309
|
function wasMSTeamsBotMentioned(activity) {
|
|
1194
1310
|
const botId = activity.recipient?.id;
|
|
1195
1311
|
if (!botId) return false;
|
|
@@ -1203,27 +1319,22 @@ function keepConfiguredMSTeamsAllowlistActive(configured, projected) {
|
|
|
1203
1319
|
if (!Array.isArray(configured) || configured.every((entry) => !entry?.trim())) return projected;
|
|
1204
1320
|
return projected && projected.length > 0 ? projected : [MSTEAMS_UNMATCHABLE_THREAD_ID];
|
|
1205
1321
|
}
|
|
1206
|
-
function
|
|
1322
|
+
function findExactMatches(items, query, fields = ["displayName"]) {
|
|
1323
|
+
const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
|
|
1207
1324
|
const byId = /* @__PURE__ */ new Map();
|
|
1208
1325
|
for (const item of items) {
|
|
1326
|
+
if (!fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)) continue;
|
|
1209
1327
|
const id = item.id?.trim();
|
|
1210
1328
|
if (id && !byId.has(id)) byId.set(id, item);
|
|
1211
1329
|
}
|
|
1212
1330
|
return [...byId.values()];
|
|
1213
1331
|
}
|
|
1214
|
-
function findExactMatches(items, query, fields = ["displayName"]) {
|
|
1215
|
-
const normalized = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(query);
|
|
1216
|
-
return uniqueItemsById(items.filter((item) => fields.some((field) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(item[field]) === normalized)));
|
|
1217
|
-
}
|
|
1218
|
-
function isStableMSTeamsUserId(raw) {
|
|
1219
|
-
return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(raw));
|
|
1220
|
-
}
|
|
1221
1332
|
function normalizeStaticMSTeamsAllowEntry(raw) {
|
|
1222
1333
|
const trimmed = raw.trim();
|
|
1223
1334
|
if (!trimmed) return;
|
|
1224
1335
|
if (trimmed === "*" || /^accessGroup:/i.test(trimmed)) return trimmed;
|
|
1225
1336
|
const id = normalizeMSTeamsUserInput(trimmed);
|
|
1226
|
-
return
|
|
1337
|
+
return /^[0-9a-fA-F-]{16,}$/.test(normalizeMSTeamsUserInput(id)) ? id : void 0;
|
|
1227
1338
|
}
|
|
1228
1339
|
function projectStableMSTeamsAllowlist(entries, allowConversations) {
|
|
1229
1340
|
if (!entries) return;
|
|
@@ -1645,11 +1756,17 @@ async function resolveMSTeamsUserAllowlist(params) {
|
|
|
1645
1756
|
input,
|
|
1646
1757
|
resolved: true,
|
|
1647
1758
|
id: match.id,
|
|
1648
|
-
name: match.displayName
|
|
1759
|
+
name: match.displayName
|
|
1649
1760
|
};
|
|
1650
1761
|
}
|
|
1651
1762
|
});
|
|
1652
1763
|
}
|
|
1764
|
+
Object.defineProperty(exports, "GRAPH_HOSTS", {
|
|
1765
|
+
enumerable: true,
|
|
1766
|
+
get: function() {
|
|
1767
|
+
return GRAPH_HOSTS;
|
|
1768
|
+
}
|
|
1769
|
+
});
|
|
1653
1770
|
Object.defineProperty(exports, "GRAPH_ROOT", {
|
|
1654
1771
|
enumerable: true,
|
|
1655
1772
|
get: function() {
|
|
@@ -1674,6 +1791,12 @@ Object.defineProperty(exports, "MSTEAMS_REQUEST_TIMEOUT_MS", {
|
|
|
1674
1791
|
return MSTEAMS_REQUEST_TIMEOUT_MS;
|
|
1675
1792
|
}
|
|
1676
1793
|
});
|
|
1794
|
+
Object.defineProperty(exports, "SHAREPOINT_HOSTS", {
|
|
1795
|
+
enumerable: true,
|
|
1796
|
+
get: function() {
|
|
1797
|
+
return SHAREPOINT_HOSTS;
|
|
1798
|
+
}
|
|
1799
|
+
});
|
|
1677
1800
|
Object.defineProperty(exports, "applyAuthorizationHeaderForUrl", {
|
|
1678
1801
|
enumerable: true,
|
|
1679
1802
|
get: function() {
|
|
@@ -1842,12 +1965,6 @@ Object.defineProperty(exports, "keepConfiguredMSTeamsAllowlistActive", {
|
|
|
1842
1965
|
return keepConfiguredMSTeamsAllowlistActive;
|
|
1843
1966
|
}
|
|
1844
1967
|
});
|
|
1845
|
-
Object.defineProperty(exports, "listChannelsForTeam", {
|
|
1846
|
-
enumerable: true,
|
|
1847
|
-
get: function() {
|
|
1848
|
-
return listChannelsForTeam;
|
|
1849
|
-
}
|
|
1850
|
-
});
|
|
1851
1968
|
Object.defineProperty(exports, "listChannelsForTeamWithPageInfo", {
|
|
1852
1969
|
enumerable: true,
|
|
1853
1970
|
get: function() {
|
|
@@ -1860,10 +1977,10 @@ Object.defineProperty(exports, "listMSTeamsAccountIds", {
|
|
|
1860
1977
|
return listMSTeamsAccountIds;
|
|
1861
1978
|
}
|
|
1862
1979
|
});
|
|
1863
|
-
Object.defineProperty(exports, "
|
|
1980
|
+
Object.defineProperty(exports, "listTeamsByNameWithPageInfo", {
|
|
1864
1981
|
enumerable: true,
|
|
1865
1982
|
get: function() {
|
|
1866
|
-
return
|
|
1983
|
+
return listTeamsByNameWithPageInfo;
|
|
1867
1984
|
}
|
|
1868
1985
|
});
|
|
1869
1986
|
Object.defineProperty(exports, "loadMSTeamsSdkWithAuth", {
|
|
@@ -1902,22 +2019,22 @@ Object.defineProperty(exports, "normalizeMSTeamsConversationId", {
|
|
|
1902
2019
|
return normalizeMSTeamsConversationId;
|
|
1903
2020
|
}
|
|
1904
2021
|
});
|
|
1905
|
-
Object.defineProperty(exports, "
|
|
2022
|
+
Object.defineProperty(exports, "normalizeMSTeamsMentionTags", {
|
|
1906
2023
|
enumerable: true,
|
|
1907
2024
|
get: function() {
|
|
1908
|
-
return
|
|
2025
|
+
return normalizeMSTeamsMentionTags;
|
|
1909
2026
|
}
|
|
1910
2027
|
});
|
|
1911
|
-
Object.defineProperty(exports, "
|
|
2028
|
+
Object.defineProperty(exports, "normalizeMSTeamsMessagingTarget", {
|
|
1912
2029
|
enumerable: true,
|
|
1913
2030
|
get: function() {
|
|
1914
|
-
return
|
|
2031
|
+
return normalizeMSTeamsMessagingTarget;
|
|
1915
2032
|
}
|
|
1916
2033
|
});
|
|
1917
|
-
Object.defineProperty(exports, "
|
|
2034
|
+
Object.defineProperty(exports, "normalizeMSTeamsUserInput", {
|
|
1918
2035
|
enumerable: true,
|
|
1919
2036
|
get: function() {
|
|
1920
|
-
return
|
|
2037
|
+
return normalizeMSTeamsUserInput;
|
|
1921
2038
|
}
|
|
1922
2039
|
});
|
|
1923
2040
|
Object.defineProperty(exports, "parseMSTeamsActivityTimestamp", {
|
|
@@ -1962,6 +2079,12 @@ Object.defineProperty(exports, "projectStableMSTeamsUserAllowlist", {
|
|
|
1962
2079
|
return projectStableMSTeamsUserAllowlist;
|
|
1963
2080
|
}
|
|
1964
2081
|
});
|
|
2082
|
+
Object.defineProperty(exports, "replaceTeamsEmojiSpriteImagesWithAltText", {
|
|
2083
|
+
enumerable: true,
|
|
2084
|
+
get: function() {
|
|
2085
|
+
return replaceTeamsEmojiSpriteImagesWithAltText;
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
1965
2088
|
Object.defineProperty(exports, "resolveAttachmentFetchPolicy", {
|
|
1966
2089
|
enumerable: true,
|
|
1967
2090
|
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
|
// 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-DFqDvc_a.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;
|