28 lines
1.7 KiB
TypeScript
28 lines
1.7 KiB
TypeScript
export type EmailOAuthProvider = "gmail" | "microsoft";
|
|
export type EmailOAuthAttempt = { provider: EmailOAuthProvider; origin: string; popup: Window };
|
|
type TerminalMessage = { status: "connected" | "error"; message?: string };
|
|
|
|
export function emailOAuthCallbackOrigin(authorizationUrl: unknown, provider: EmailOAuthProvider): string | null {
|
|
if (typeof authorizationUrl !== "string") return null;
|
|
try {
|
|
const authorization = new URL(authorizationUrl);
|
|
if (!["https:", "http:"].includes(authorization.protocol) || authorization.username || authorization.password) return null;
|
|
const redirects = authorization.searchParams.getAll("redirect_uri");
|
|
if (redirects.length !== 1) return null;
|
|
const callback = new URL(redirects[0]);
|
|
const path = provider === "gmail" ? "/api/gmail/oauth/callback" : "/api/microsoft-graph/oauth/callback";
|
|
return ["https:", "http:"].includes(callback.protocol) && !callback.username && !callback.password
|
|
&& callback.pathname === path && !callback.search && !callback.hash ? callback.origin : null;
|
|
} catch { return null; }
|
|
}
|
|
|
|
export function emailOAuthMessage(event: MessageEvent, attempt: EmailOAuthAttempt): TerminalMessage | null {
|
|
if (event.origin !== attempt.origin || event.source !== attempt.popup) return null;
|
|
const data = event.data as { source?: unknown; status?: unknown; message?: unknown } | null;
|
|
if (!data || typeof data !== "object" || Array.isArray(data)
|
|
|| data.source !== (attempt.provider === "gmail" ? "jobtracker-gmail-oauth" : "jobtracker-microsoft-oauth")
|
|
|| (data.status !== "connected" && data.status !== "error")
|
|
|| (data.message !== undefined && typeof data.message !== "string")) return null;
|
|
return { status: data.status, message: data.message };
|
|
}
|