UNPKG

@atomicjolt/lti-client

Version:

Client Javascript libraries to handle LTI.

171 lines (155 loc) 5.21 kB
import i18next from "i18next"; import { STATE_KEY_PREFIX } from "./constants"; import { LTIStorageParams, InitSettings } from "../types"; import { setCookie } from "./cookies"; import { showLaunchNewWindow } from "../html/launch_new_window"; import { getCapability } from "../libs/capabilities"; export async function getTargetFrame( storageParams: LTIStorageParams ): Promise<Window> { let target = storageParams.target; if (target == null) { const cap = await getCapability("lti.get_data"); target = cap?.frame; } if (target == null) { target = "_parent"; } const parent = window.parent || window.opener; return target === "_parent" ? parent : parent.frames[target as any] || parent; } export async function storeState( state: string, storageParams: LTIStorageParams ): Promise<void> { return new Promise<void>((resolve, reject) => { let platformOrigin = new URL(storageParams.platformOIDCUrl).origin; if (storageParams.originSupportBroken) { // The spec requires that the message's target origin be set to the platform's OIDC Authorization url // but Canvas does not yet support this, so we have to use '*'. platformOrigin = "*"; } let timeout = setTimeout(() => { console.error("postMessage timeout"); reject( new Error(i18next.t("Timeout while waiting for platform response")) ); }, 2000); let receiveMessage = (event: any) => { if ( typeof event.data === "object" && event.data.subject === "lti.put_data.response" && event.data.message_id === state && (event.origin === platformOrigin || (storageParams.originSupportBroken && platformOrigin === "*")) ) { removeEventListener("message", receiveMessage); clearTimeout(timeout); if (event.data.error) { // handle errors console.error(event.data.error.code); console.error(event.data.error.message); reject(new Error(event.data.errormessage)); } resolve(); } }; window.addEventListener("message", receiveMessage); getTargetFrame(storageParams) .then((targetFrame) => targetFrame?.postMessage( { subject: "lti.put_data", message_id: state, key: `${STATE_KEY_PREFIX}${state}`, value: state, }, platformOrigin ) ) .catch((e: unknown) => { console.log(i18next.t("Could not find target frame")); console.log(e); reject(new Error(i18next.t("Could not find target frame"))); }); // Platform should post a message back }); } export function hasStorageAccessAPI() { return ( typeof document.hasStorageAccess === "function" && typeof document.requestStorageAccess === "function" ); } export function tryRequestStorageAccess(settings: InitSettings) { document .requestStorageAccess() .then(() => { // We should have cookies now setCookie(settings); window.location.replace(settings.responseUrl); }) .catch((e) => { console.log(e); showLaunchNewWindow(settings, { showStorageAccessDenied: true, disableLaunch: true, showRequestStorageAccess: false, }); }); } export function loadState( state: string, storageParams: LTIStorageParams ): Promise<string> { return new Promise((resolve, reject) => { let platformOrigin = new URL(storageParams.platformOIDCUrl).origin; if (storageParams.originSupportBroken) { // The spec requires that the message's target origin be set to the platform's OIDC Authorization url // but Canvas does not yet support this, so we have to use '*'. platformOrigin = "*"; } const timeout = setTimeout(() => { console.log(i18next.t("postMessage timeout")); reject( new Error(i18next.t("Timeout while waiting for platform response")) ); }, 2000); const receiveMessage = (event: MessageEvent) => { if ( typeof event.data === "object" && event.data.subject === "lti.get_data.response" && event.data.message_id === state && (event.origin === platformOrigin || platformOrigin === "*") ) { removeEventListener("message", receiveMessage); clearTimeout(timeout); if (event.data.error) { // handle errors console.error(event.data.error.code); console.error(event.data.error.message); reject(new Error(event.data.errormessage)); } resolve(event.data.value); } }; window.addEventListener("message", receiveMessage); getTargetFrame(storageParams) .then((targetFrame) => targetFrame.postMessage( { subject: "lti.get_data", message_id: state, key: `${STATE_KEY_PREFIX}${state}`, }, platformOrigin ) ) .catch((e: unknown) => { console.log(i18next.t("Could not find target frame")); console.log(e); reject(new Error(i18next.t("Could not find target frame"))); }); // Platform will post a message back }); }