// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Provides utility methods used by the cellular activation flow.
* Current: chrome://mobilesetup (mobile_setup.html/mobile_setup_portal.html)
* New UI: cr_components/chromeos/cellular_setup/cellular_setup.html
*/
declare global {
interface HTMLElementEventMap {
'loadcommit': CommitEvent;
}
}
interface CommitEvent extends Event {
isTopLevel: boolean;
url: string;
}
/**
* The script executed in the webview that is expected to be initialized
* using POST request. The script parses the POST data (which is provided as
* list of name value pairs) and adds appropriate input elements to the form,
* sets the form action to the paymentUrl, and submits the form.
*
* The script should be run with the following arguments:
* <code>form</code> - Form element that should be initialized and submitted.
* <code>paymentUrl</code> - The target form action URL.
* <code>postData</code> - The post request data submitted through the form.
* Example format of post data:
* <code>name1=value1&name2=value2&name3</code>
* Note that for <code>name3</code>, the value will be set to
* <code>true</code>.
* @const {string}
*/
const WEBVIEW_REDIRECT_SCRIPT = '(function(form, paymentUrl, postData) {' +
'function addInputElement(form, name, value) {' +
' var input = document.createElement(\'input\');' +
' input.type = \'hidden\';' +
' input.name = name;' +
' input.value = value;' +
' form.appendChild(input);' +
'}' +
'function initFormFromPostData(form, postData) {' +
' if (!postData) return;' +
' var pairs = postData.split(\'&\');' +
' pairs.forEach(pairStr => {' +
' var pair = pairStr.split(\'=\');' +
' if (pair.length === 2)' +
' addInputElement(form, pair[0], pair[1]);' +
' else if (pair.length === 1)' +
' addInputElement(form, pair[0], true);' +
' });' +
'}' +
'form.action = unescape(paymentUrl);' +
'form.method = \'POST\';' +
'initFormFromPostData(form, unescape(postData));' +
'form.submit();' +
'})';
/**
* @const {string} The ID used for the form element in the initial webiew
* HTML.
*/
const WEBVIEW_REDIRECT_FORM_ID = 'redirectForm';
/**
* @const {string} The initial webview HTML - this will be loaded into the
* webview using data URL before executing
* <code>WEBVIEW_REDIRECT_SCRIPT</code>.
*/
const WEBVIEW_REDIRECT_HTML = '<html><body>' +
'<form id="' + WEBVIEW_REDIRECT_FORM_ID + '"></form>' +
'</body></html>';
/**
* Handles load commit event in the webview.
* It runs <code>WEBVIEW_REDIRECT_SCRIPT</code> in the webview.
*/
function initializeWebviewRedirectForm(
webview: chrome.webviewTag.WebView, paymentUrl: string, postData: string,
webviewSrc: string,
commitEvent: CommitEvent): void {
if (!commitEvent.isTopLevel || commitEvent.url !== webviewSrc) {
return;
}
webview.executeScript({
code: WEBVIEW_REDIRECT_SCRIPT + '(' +
'document.getElementById(\'' + WEBVIEW_REDIRECT_FORM_ID + '\'),' +
' \'' + escape(paymentUrl) + '\',' +
' \'' + escape(postData || '') + '\');',
});
}
/**
* Initialized webview using a POST request described in by
* <code>paymentUrl</code> and <code>postData</code>.
*/
export function postDeviceDataToWebview(webview: chrome.webviewTag.WebView,
paymentUrl: string, postData: string): void {
const webviewSrc = 'data:text/html;charset=utf-8,' +
encodeURIComponent(WEBVIEW_REDIRECT_HTML);
webview.addEventListener(
'loadcommit',
(commitEvent: CommitEvent) => {
initializeWebviewRedirectForm(webview, paymentUrl, postData,
webviewSrc, commitEvent);
});
webview.src = webviewSrc;
}