import type { Request, Response } from "express"; import {
DEFAULT_WEBHOOK_MAX_BODY_BYTES,
keepHttpServerTaskAlive,
mergeAllowlist,
summarizeMapping,
type OpenClawConfig,
type RuntimeEnv,
} from "../runtime-api.js"; import { createMSTeamsConversationStoreFs } from "./conversation-store-fs.js"; import type { MSTeamsConversationStore } from "./conversation-store.js"; import { formatUnknownError } from "./errors.js"; import type { MSTeamsAdapter } from "./messenger.js"; import { registerMSTeamsHandlers, type MSTeamsActivityHandler } from "./monitor-handler.js"; import { createMSTeamsPollStoreFs, type MSTeamsPollStore } from "./polls.js"; import {
resolveMSTeamsChannelAllowlist,
resolveMSTeamsUserAllowlist,
} from "./resolve-allowlist.js"; import { getMSTeamsRuntime } from "./runtime.js"; import {
createBotFrameworkJwtValidator,
createMSTeamsAdapter,
createMSTeamsTokenProvider,
loadMSTeamsSdkWithAuth,
} from "./sdk.js"; import { createMSTeamsSsoTokenStoreFs } from "./sso-token-store.js"; import type { MSTeamsSsoDeps } from "./sso.js"; import { resolveMSTeamsCredentials } from "./token.js"; import { applyMSTeamsWebhookTimeouts } from "./webhook-timeouts.js";
// Build a token provider adapter for Graph API operations const tokenProvider = createMSTeamsTokenProvider(app);
const adapter = createMSTeamsAdapter(app, sdk);
// Build SSO deps when the operator has opted in and a connection name // is configured. Leaving `sso` undefined matches the pre-SSO behavior // (the plugin will still ack signin invokes, but will not attempt a // Bot Framework token exchange or persist anything).
let ssoDeps: MSTeamsSsoDeps | undefined; if (msteamsCfg.sso?.enabled && msteamsCfg.sso.connectionName) {
ssoDeps = {
tokenProvider,
tokenStore: createMSTeamsSsoTokenStoreFs(),
connectionName: msteamsCfg.sso.connectionName,
};
log.debug?.("msteams sso enabled", {
connectionName: msteamsCfg.sso.connectionName,
});
}
// Build a simple ActivityHandler-compatible object const handler = buildActivityHandler();
registerMSTeamsHandlers(handler, {
cfg,
runtime,
appId,
adapter: adapter as unknown as MSTeamsAdapter,
tokenProvider,
textLimit,
mediaMaxBytes,
conversationStore,
pollStore,
log,
sso: ssoDeps,
});
// Create Express server const expressApp = express.default();
// Cheap pre-parse auth gate: reject requests without a Bearer token before // spending CPU/memory on JSON body parsing. This prevents unauthenticated // request floods from forcing body parsing on internet-exposed webhooks.
expressApp.use((req: Request, res: Response, next: (err?: unknown) => void) => { const auth = req.headers.authorization; if (!auth || !auth.startsWith("Bearer ")) {
res.status(401).json({ error: "Unauthorized" }); return;
}
next();
});
// JWT validation — verify Bot Framework tokens using the Teams SDK's // JwtValidator (validates signature via JWKS, audience, issuer, expiration). const jwtValidator = await createBotFrameworkJwtValidator(creds);
expressApp.use((req: Request, res: Response, next: (err?: unknown) => void) => { // Authorization header is guaranteed by the pre-parse auth gate above. // `serviceUrl` is optional, so authenticate from headers alone before body // I/O to avoid spending memory and CPU on unauthenticated requests. const authHeader = req.headers.authorization!;
jwtValidator
.validate(authHeader)
.then((valid) => { if (!valid) {
log.debug?.("JWT validation failed");
res.status(401).json({ error: "Unauthorized" }); return;
}
next();
})
.catch((err) => {
log.debug?.(`JWT validation error: ${formatUnknownError(err)}`);
res.status(401).json({ error: "Unauthorized" });
});
});
const shutdown = async () => {
log.info("shutting down msteams provider"); returnnew Promise<void>((resolve) => {
httpServer.close((err) => { if (err) {
log.debug?.("msteams server close error", { error: formatUnknownError(err) });
}
resolve();
});
});
};
// Keep this task alive until close so gateway runtime does not treat startup as exit.
await keepHttpServerTaskAlive({
server: httpServer,
abortSignal: opts.abortSignal,
onAbort: shutdown,
});
return { app: expressApp, shutdown };
}
/** * Build a minimal ActivityHandler-compatible object that supports * onMessage / onMembersAdded registration and a run() method.
*/ function buildActivityHandler(): MSTeamsActivityHandler {
type Handler = (context: unknown, next: () => Promise<void>) => Promise<void>; const messageHandlers: Handler[] = []; const membersAddedHandlers: Handler[] = []; const reactionsAddedHandlers: Handler[] = []; const reactionsRemovedHandlers: Handler[] = [];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.