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.
7 * The background script of auth extension that bridges the communications
8 * between main and injected script.
9 * Here are the communications along a SAML sign-in flow:
10 * 1. Main script sends an 'onAuthStarted' signal to indicate the authentication
11 * flow is started and SAML pages might be loaded from now on;
12 * 2. After the 'onAuthTstarted' signal, injected script starts to scraping
13 * all password fields on normal page (i.e. http or https) and sends page
14 * load signal as well as the passwords to the background script here;
18 * BackgroundBridge holds the main script's state and the scraped passwords
19 * from the injected script to help the two collaborate.
21 function BackgroundBridge() {
24 BackgroundBridge.prototype = {
25 // Gaia URL base that is set from main auth script.
28 // Whether auth flow has started. It is used as a signal of whether the
29 // injected script should scrape passwords.
35 channelInjected_: null,
38 chrome.runtime.onConnect.addListener(this.onConnect_.bind(this));
40 // Workarounds for loading SAML page in an iframe.
41 chrome.webRequest.onHeadersReceived.addListener(
43 if (!this.authStarted_)
46 var headers = details.responseHeaders;
47 for (var i = 0; headers && i < headers.length; ++i) {
48 if (headers[i].name.toLowerCase() == 'x-frame-options') {
53 return {responseHeaders: headers};
55 {urls: ['<all_urls>'], types: ['sub_frame']},
56 ['blocking', 'responseHeaders']);
59 onConnect_: function(port) {
60 if (port.name == 'authMain')
61 this.setupForAuthMain_(port);
62 else if (port.name == 'injected')
63 this.setupForInjected_(port);
65 console.error('Unexpected connection, port.name=' + port.name);
69 * Sets up the communication channel with the main script.
71 setupForAuthMain_: function(port) {
72 this.channelMain_ = new Channel();
73 this.channelMain_.init(port);
74 this.channelMain_.registerMessage(
75 'setGaiaUrl', this.onSetGaiaUrl_.bind(this));
76 this.channelMain_.registerMessage(
77 'resetAuth', this.onResetAuth_.bind(this));
78 this.channelMain_.registerMessage(
79 'startAuth', this.onAuthStarted_.bind(this));
80 this.channelMain_.registerMessage(
81 'getScrapedPasswords',
82 this.onGetScrapedPasswords_.bind(this));
86 * Sets up the communication channel with the injected script.
88 setupForInjected_: function(port) {
89 this.channelInjected_ = new Channel();
90 this.channelInjected_.init(port);
91 this.channelInjected_.registerMessage(
92 'updatePassword', this.onUpdatePassword_.bind(this));
93 this.channelInjected_.registerMessage(
94 'pageLoaded', this.onPageLoaded_.bind(this));
98 * Handler for 'setGaiaUrl' signal sent from the main script.
100 onSetGaiaUrl_: function(msg) {
101 this.gaiaUrl_ = msg.gaiaUrl;
103 // Set request header to let Gaia know that saml support is on.
104 chrome.webRequest.onBeforeSendHeaders.addListener(
106 details.requestHeaders.push({
107 name: 'X-Cros-Auth-Ext-Support',
110 return {requestHeaders: details.requestHeaders};
112 {urls: [this.gaiaUrl_ + '*'], types: ['sub_frame']},
113 ['blocking', 'requestHeaders']);
117 * Handler for 'resetAuth' signal sent from the main script.
119 onResetAuth_: function() {
120 this.authStarted_ = false;
121 this.passwordStore_ = {};
125 * Handler for 'authStarted' signal sent from the main script.
127 onAuthStarted_: function() {
128 this.authStarted_ = true;
129 this.passwordStore_ = {};
133 * Handler for 'getScrapedPasswords' request sent from the main script.
134 * @return {Array.<string>} The array with de-duped scraped passwords.
136 onGetScrapedPasswords_: function() {
138 for (var property in this.passwordStore_) {
139 passwords[this.passwordStore_[property]] = true;
141 return Object.keys(passwords);
144 onUpdatePassword_: function(msg) {
145 if (!this.authStarted_)
148 this.passwordStore_[msg.id] = msg.password;
151 onPageLoaded_: function(msg) {
152 this.channelMain_.send({name: 'onAuthPageLoaded', url: msg.url});
156 var backgroundBridge = new BackgroundBridge();
157 backgroundBridge.run();