"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ipcRendererUtils = require("@electron/internal/renderer/ipc-renderer-internal-utils"); const web_view_impl_1 = require("@electron/internal/renderer/web-view/web-view-impl"); // Helper function to resolve url set in attribute. const a = document.createElement('a'); const resolveURL = function (url) { if (!url) return ''; a.href = url; return a.href; }; // Attribute objects. // Default implementation of a WebView attribute. class WebViewAttribute { constructor(name, webViewImpl) { this.name = name; this.webViewImpl = webViewImpl; this.ignoreMutation = false; // Called when the attribute's value changes. this.handleMutation = () => undefined; this.name = name; this.value = webViewImpl.webviewNode[name] || ''; this.webViewImpl = webViewImpl; this.defineProperty(); } // Retrieves and returns the attribute's value. getValue() { return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value; } // Sets the attribute's value. setValue(value) { this.webViewImpl.webviewNode.setAttribute(this.name, value || ''); } // Changes the attribute's value without triggering its mutation handler. setValueIgnoreMutation(value) { this.ignoreMutation = true; this.setValue(value); this.ignoreMutation = false; } // Defines this attribute as a property on the webview node. defineProperty() { return Object.defineProperty(this.webViewImpl.webviewNode, this.name, { get: () => { return this.getValue(); }, set: (value) => { return this.setValue(value); }, enumerable: true }); } } // An attribute that is treated as a Boolean. class BooleanAttribute extends WebViewAttribute { getValue() { return this.webViewImpl.webviewNode.hasAttribute(this.name); } setValue(value) { if (value) { this.webViewImpl.webviewNode.setAttribute(this.name, ''); } else { this.webViewImpl.webviewNode.removeAttribute(this.name); } } } // Attribute representing the state of the storage partition. class PartitionAttribute extends WebViewAttribute { constructor(webViewImpl) { super("partition" /* ATTRIBUTE_PARTITION */, webViewImpl); this.webViewImpl = webViewImpl; this.validPartitionId = true; this.handleMutation = (oldValue, newValue) => { newValue = newValue || ''; // The partition cannot change if the webview has already navigated. if (!this.webViewImpl.beforeFirstNavigation) { console.error("The object has already navigated, so its partition cannot be changed." /* ERROR_MSG_ALREADY_NAVIGATED */); this.setValueIgnoreMutation(oldValue); return; } if (newValue === 'persist:') { this.validPartitionId = false; console.error("Invalid partition attribute." /* ERROR_MSG_INVALID_PARTITION_ATTRIBUTE */); } }; } } // Attribute that handles the location and navigation of the webview. class SrcAttribute extends WebViewAttribute { constructor(webViewImpl) { super("src" /* ATTRIBUTE_SRC */, webViewImpl); this.webViewImpl = webViewImpl; this.handleMutation = (oldValue, newValue) => { // Once we have navigated, we don't allow clearing the src attribute. // Once enters a navigated state, it cannot return to a // placeholder state. if (!newValue && oldValue) { // src attribute changes normally initiate a navigation. We suppress // the next src attribute handler call to avoid reloading the page // on every guest-initiated navigation. this.setValueIgnoreMutation(oldValue); return; } this.parse(); }; this.setupMutationObserver(); } getValue() { if (this.webViewImpl.webviewNode.hasAttribute(this.name)) { return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); } else { return this.value; } } setValueIgnoreMutation(value) { super.setValueIgnoreMutation(value); // takeRecords() is needed to clear queued up src mutations. Without it, it // is possible for this change to get picked up asyncronously by src's // mutation observer |observer|, and then get handled even though we do not // want to handle this mutation. this.observer.takeRecords(); } // The purpose of this mutation observer is to catch assignment to the src // attribute without any changes to its value. This is useful in the case // where the webview guest has crashed and navigating to the same address // spawns off a new process. setupMutationObserver() { this.observer = new MutationObserver((mutations) => { for (const mutation of mutations) { const { oldValue } = mutation; const newValue = this.getValue(); if (oldValue !== newValue) { return; } this.handleMutation(oldValue, newValue); } }); const params = { attributes: true, attributeOldValue: true, attributeFilter: [this.name] }; this.observer.observe(this.webViewImpl.webviewNode, params); } parse() { if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes["partition" /* ATTRIBUTE_PARTITION */].validPartitionId || !this.getValue()) { return; } if (this.webViewImpl.guestInstanceId == null) { if (this.webViewImpl.beforeFirstNavigation) { this.webViewImpl.beforeFirstNavigation = false; this.webViewImpl.createGuest(); } return; } // Navigate to |this.src|. const opts = {}; const httpreferrer = this.webViewImpl.attributes["httpreferrer" /* ATTRIBUTE_HTTPREFERRER */].getValue(); if (httpreferrer) { opts.httpReferrer = httpreferrer; } const useragent = this.webViewImpl.attributes["useragent" /* ATTRIBUTE_USERAGENT */].getValue(); if (useragent) { opts.userAgent = useragent; } const guestInstanceId = this.webViewImpl.guestInstanceId; const method = 'loadURL'; const args = [this.getValue(), opts]; ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CALL', guestInstanceId, method, args); } } // Attribute specifies HTTP referrer. class HttpReferrerAttribute extends WebViewAttribute { constructor(webViewImpl) { super("httpreferrer" /* ATTRIBUTE_HTTPREFERRER */, webViewImpl); } } // Attribute specifies user agent class UserAgentAttribute extends WebViewAttribute { constructor(webViewImpl) { super("useragent" /* ATTRIBUTE_USERAGENT */, webViewImpl); } } // Attribute that set preload script. class PreloadAttribute extends WebViewAttribute { constructor(webViewImpl) { super("preload" /* ATTRIBUTE_PRELOAD */, webViewImpl); } getValue() { if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) { return this.value; } let preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)); const protocol = preload.substr(0, 5); if (protocol !== 'file:') { console.error("Only \"file:\" protocol is supported in \"preload\" attribute." /* ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE */); preload = ''; } return preload; } } // Attribute that specifies the blink features to be enabled. class BlinkFeaturesAttribute extends WebViewAttribute { constructor(webViewImpl) { super("blinkfeatures" /* ATTRIBUTE_BLINKFEATURES */, webViewImpl); } } // Attribute that specifies the blink features to be disabled. class DisableBlinkFeaturesAttribute extends WebViewAttribute { constructor(webViewImpl) { super("disableblinkfeatures" /* ATTRIBUTE_DISABLEBLINKFEATURES */, webViewImpl); } } // Attribute that specifies the web preferences to be enabled. class WebPreferencesAttribute extends WebViewAttribute { constructor(webViewImpl) { super("webpreferences" /* ATTRIBUTE_WEBPREFERENCES */, webViewImpl); } } class EnableRemoteModuleAttribute extends WebViewAttribute { constructor(webViewImpl) { super("enableremotemodule" /* ATTRIBUTE_ENABLEREMOTEMODULE */, webViewImpl); } getValue() { return this.webViewImpl.webviewNode.getAttribute(this.name) !== 'false'; } setValue(value) { this.webViewImpl.webviewNode.setAttribute(this.name, value ? 'true' : 'false'); } } // Sets up all of the webview attributes. web_view_impl_1.WebViewImpl.prototype.setupWebViewAttributes = function () { this.attributes = {}; this.attributes["partition" /* ATTRIBUTE_PARTITION */] = new PartitionAttribute(this); this.attributes["src" /* ATTRIBUTE_SRC */] = new SrcAttribute(this); this.attributes["httpreferrer" /* ATTRIBUTE_HTTPREFERRER */] = new HttpReferrerAttribute(this); this.attributes["useragent" /* ATTRIBUTE_USERAGENT */] = new UserAgentAttribute(this); this.attributes["nodeintegration" /* ATTRIBUTE_NODEINTEGRATION */] = new BooleanAttribute("nodeintegration" /* ATTRIBUTE_NODEINTEGRATION */, this); this.attributes["nodeintegrationinsubframes" /* ATTRIBUTE_NODEINTEGRATIONINSUBFRAMES */] = new BooleanAttribute("nodeintegrationinsubframes" /* ATTRIBUTE_NODEINTEGRATIONINSUBFRAMES */, this); this.attributes["plugins" /* ATTRIBUTE_PLUGINS */] = new BooleanAttribute("plugins" /* ATTRIBUTE_PLUGINS */, this); this.attributes["disablewebsecurity" /* ATTRIBUTE_DISABLEWEBSECURITY */] = new BooleanAttribute("disablewebsecurity" /* ATTRIBUTE_DISABLEWEBSECURITY */, this); this.attributes["allowpopups" /* ATTRIBUTE_ALLOWPOPUPS */] = new BooleanAttribute("allowpopups" /* ATTRIBUTE_ALLOWPOPUPS */, this); this.attributes["enableremotemodule" /* ATTRIBUTE_ENABLEREMOTEMODULE */] = new EnableRemoteModuleAttribute(this); this.attributes["preload" /* ATTRIBUTE_PRELOAD */] = new PreloadAttribute(this); this.attributes["blinkfeatures" /* ATTRIBUTE_BLINKFEATURES */] = new BlinkFeaturesAttribute(this); this.attributes["disableblinkfeatures" /* ATTRIBUTE_DISABLEBLINKFEATURES */] = new DisableBlinkFeaturesAttribute(this); this.attributes["webpreferences" /* ATTRIBUTE_WEBPREFERENCES */] = new WebPreferencesAttribute(this); };