diff --git a/plugins/outlook/src/index.ts b/plugins/outlook/src/index.ts index b4e88edf..199c2fbb 100644 --- a/plugins/outlook/src/index.ts +++ b/plugins/outlook/src/index.ts @@ -1,3 +1,27 @@ +// Outlook on cloud.microsoft enforces Trusted Types (CSP). Zod's allowsEval +// feature-detect calls new Function("") the first time a zod parser runs +// (lazy, memoized via cached()). This policy just needs to exist before that +// first runtime call — import statements are hoisted regardless, but the probe +// only fires when a tool handler first invokes a zod schema at runtime. +if (typeof window !== 'undefined') { + try { + const tt = (window as Window & { + trustedTypes?: TrustedTypePolicyFactory & { defaultPolicy?: TrustedTypePolicy | null }; + }).trustedTypes; + if (tt && !tt.defaultPolicy) { + tt.createPolicy('default', { + createScript: (s: string) => { + // Only allow the empty-string probe used by zod's allowsEval feature-detect. + if (s !== '') throw new TypeError('Blocked Trusted Types script conversion'); + return s; + }, + }); + } + } catch { + // 'default' policy already exists, or Trusted Types not supported — safe to ignore. + } +} + import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk'; import type { ToolDefinition } from '@opentabs-dev/plugin-sdk'; import { isAuthenticated, waitForAuth } from './outlook-api.js'; diff --git a/plugins/outlook/src/outlook-api.ts b/plugins/outlook/src/outlook-api.ts index 31d714f8..c620ec22 100644 --- a/plugins/outlook/src/outlook-api.ts +++ b/plugins/outlook/src/outlook-api.ts @@ -158,7 +158,14 @@ const getAuth = (): OutlookAuth | null => { return auth; }; -export const isAuthenticated = (): boolean => getAuth() !== null; +export const isAuthenticated = (): boolean => { + // During OAuth redirect the #code= fragment is present but MSAL tokens are + // not yet in localStorage. Return false early so the platform's 30s re-poll + // catches the token once the handshake completes, rather than burning the + // 5s isReady window on token searches that will all fail. + if (typeof window !== 'undefined' && window.location.hash.includes('code=')) return false; + return getAuth() !== null; +}; export const waitForAuth = (): Promise => waitUntil(() => isAuthenticated(), { interval: 500, timeout: 5000 }).then(