Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / browser / resources / gaia_auth / saml_injected.js
blobfd08bd548969d9c4368c4f2b885ee787d7c17e81
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6 * @fileoverview
7 * Script to be injected into SAML provider pages, serving three main purposes:
8 * 1. Signal hosting extension that an external page is loaded so that the
9 * UI around it should be changed accordingly;
10 * 2. Provide an API via which the SAML provider can pass user credentials to
11 * Chrome OS, allowing the password to be used for encrypting user data and
12 * offline login.
13 * 3. Scrape password fields, making the password available to Chrome OS even if
14 * the SAML provider does not support the credential passing API.
17 (function() {
18 function APICallForwarder() {
21 /**
22 * The credential passing API is used by sending messages to the SAML page's
23 * |window| object. This class forwards API calls from the SAML page to a
24 * background script and API responses from the background script to the SAML
25 * page. Communication with the background script occurs via a |Channel|.
27 APICallForwarder.prototype = {
28 // Channel to which API calls are forwarded.
29 channel_: null,
31 /**
32 * Initialize the API call forwarder.
33 * @param {!Object} channel Channel to which API calls should be forwarded.
35 init: function(channel) {
36 this.channel_ = channel;
37 this.channel_.registerMessage('apiResponse',
38 this.onAPIResponse_.bind(this));
40 window.addEventListener('message', this.onMessage_.bind(this));
43 onMessage_: function(event) {
44 if (event.source != window ||
45 typeof event.data != 'object' ||
46 !event.data.hasOwnProperty('type') ||
47 event.data.type != 'gaia_saml_api') {
48 return;
50 // Forward API calls to the background script.
51 this.channel_.send({name: 'apiCall', call: event.data.call});
54 onAPIResponse_: function(msg) {
55 // Forward API responses to the SAML page.
56 window.postMessage({type: 'gaia_saml_api_reply', response: msg.response},
57 '/');
61 /**
62 * A class to scrape password from type=password input elements under a given
63 * docRoot and send them back via a Channel.
65 function PasswordInputScraper() {
68 PasswordInputScraper.prototype = {
69 // URL of the page.
70 pageURL_: null,
72 // Channel to send back changed password.
73 channel_: null,
75 // An array to hold password fields.
76 passwordFields_: null,
78 // An array to hold cached password values.
79 passwordValues_: null,
81 /**
82 * Initialize the scraper with given channel and docRoot. Note that the
83 * scanning for password fields happens inside the function and does not
84 * handle DOM tree changes after the call returns.
85 * @param {!Object} channel The channel to send back password.
86 * @param {!string} pageURL URL of the page.
87 * @param {!HTMLElement} docRoot The root element of the DOM tree that
88 * contains the password fields of interest.
90 init: function(channel, pageURL, docRoot) {
91 this.pageURL_ = pageURL;
92 this.channel_ = channel;
94 this.passwordFields_ = docRoot.querySelectorAll('input[type=password]');
95 this.passwordValues_ = [];
97 for (var i = 0; i < this.passwordFields_.length; ++i) {
98 this.passwordFields_[i].addEventListener(
99 'input', this.onPasswordChanged_.bind(this, i));
101 this.passwordValues_[i] = this.passwordFields_[i].value;
106 * Check if the password field at |index| has changed. If so, sends back
107 * the updated value.
109 maybeSendUpdatedPassword: function(index) {
110 var newValue = this.passwordFields_[index].value;
111 if (newValue == this.passwordValues_[index])
112 return;
114 this.passwordValues_[index] = newValue;
116 // Use an invalid char for URL as delimiter to concatenate page url and
117 // password field index to construct a unique ID for the password field.
118 var passwordId = this.pageURL_ + '|' + index;
119 this.channel_.send({
120 name: 'updatePassword',
121 id: passwordId,
122 password: newValue
127 * Handles 'change' event in the scraped password fields.
128 * @param {number} index The index of the password fields in
129 * |passwordFields_|.
131 onPasswordChanged_: function(index) {
132 this.maybeSendUpdatedPassword(index);
136 function onGetSAMLFlag(channel, isSAMLPage) {
137 if (!isSAMLPage)
138 return;
139 var pageURL = window.location.href;
141 channel.send({name: 'pageLoaded', url: pageURL});
143 var apiCallForwarder = new APICallForwarder();
144 apiCallForwarder.init(channel);
146 var passwordScraper = new PasswordInputScraper();
147 passwordScraper.init(channel, pageURL, document.documentElement);
150 var channel = new Channel();
151 channel.connect('injected');
152 channel.sendWithCallback({name: 'getSAMLFlag'},
153 onGetSAMLFlag.bind(undefined, channel));
155 })();