livebook/assets/js/hooks/js_view/iframe.js
Cristine Guadelupe bf09441555
Secrets from modal (#1406)
* Secrets from modal

* Format assets

* Applying suggestions

* Format assets

* Applying suggestions

* Unavailable secret

* Applying suggestions - select_secret_ref

* Applying suggestions

* Applying suggestions - iframe v4
2022-09-16 17:56:40 -03:00

72 lines
2.9 KiB
JavaScript

import { sha256Base64 } from "../../lib/utils";
// Loading iframe using `srcdoc` disables cookies and browser APIs,
// such as camera and microphone (1), the same applies to `src` with
// data URL, so we need to load the iframe through a regular request.
// Since the iframe is sandboxed we also need `allow-same-origin`.
// Additionally, we cannot load the iframe from the same origin as
// the app, because using `allow-same-origin` together with `allow-scripts`
// would be insecure (2). Consequently, we need to load the iframe
// from a different origin.
//
// When running Livebook on https:// we load the iframe from another
// https:// origin. On the other hand, when running on http:// we want
// to load the iframe from http:// as well, otherwise the browser could
// block asset requests from the https:// iframe to http:// Livebook.
// However, external http:// content is not considered a secure context (3),
// which implies no access to user media. Therefore, instead of using
// http://livebook.space we use another localhost endpoint. Note that
// this endpoint has a different port than the Livebook web app, that's
// because we need separate origins, as outlined above.
//
// To ensure integrity of the loaded content we manually verify the
// checksum against the expected value.
//
// (1): https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#document_source_security
// (2): https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-sandbox
// (3): https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts
const IFRAME_SHA256 = "6aUFRKEwZbbohB7OpFdKqnJJVRhccJxHGV+tArREQ+I=";
export function initializeIframeSource(iframe, iframePort, iframeUrl) {
const url = getIframeUrl(iframePort, iframeUrl);
return verifyIframeSource(url).then(() => {
iframe.sandbox =
"allow-scripts allow-same-origin allow-downloads allow-modals allow-popups";
iframe.allow =
"accelerometer; ambient-light-sensor; camera; display-capture; encrypted-media; geolocation; gyroscope; microphone; midi; usb; xr-spatial-tracking; clipboard-read; clipboard-write";
iframe.src = url;
});
}
function getIframeUrl(iframePort, iframeUrl) {
const protocol = window.location.protocol;
if (iframeUrl) {
return iframeUrl.replace(/^https?:/, protocol);
}
return protocol === "https:"
? "https://livebook.space/iframe/v4.html"
: `http://${window.location.hostname}:${iframePort}/iframe/v4.html`;
}
let iframeVerificationPromise = null;
function verifyIframeSource(iframeUrl) {
if (!iframeVerificationPromise) {
iframeVerificationPromise = fetch(iframeUrl)
.then((response) => response.text())
.then((html) => {
if (sha256Base64(html) !== IFRAME_SHA256) {
throw new Error(
"The loaded iframe content doesn't have the expected checksum"
);
}
});
}
return iframeVerificationPromise;
}