livebook/assets/js/hooks/js_view/iframe.js
Jonatan Kłosko 9a016e439d
Synchronize smart cell source before evaluation (#1164)
* Synchronize smart cell source before evaluation

* Sync JS view only if present

* Synchronize with smart cell only when started

* Update references to kino packages

* Update the Smart cells notebook

* Rename add dependnecy to add package

* Update changelog
2022-05-03 15:09:37 +02:00

66 lines
2.7 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 = "fA00WeO9LAvgpbMz9vKEU0WTr4Uk5bTt/BxKHdweEz8=";
export function initializeIframeSource(iframe, iframePort) {
const iframeUrl = getIframeUrl(iframePort);
return verifyIframeSource(iframeUrl).then(() => {
iframe.sandbox =
"allow-scripts allow-same-origin allow-downloads allow-modals";
iframe.allow =
"accelerometer; ambient-light-sensor; camera; display-capture; encrypted-media; geolocation; gyroscope; microphone; midi; usb; xr-spatial-tracking";
iframe.src = iframeUrl;
});
}
function getIframeUrl(iframePort) {
return window.location.protocol === "https:"
? "https://livebook.space/iframe/v3.html"
: `http://${window.location.hostname}:${iframePort}/iframe/v3.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;
}