- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / gaia_auth / background.js
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.
4
5 /**
6  * @fileoverview
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;
15  */
16
17 /**
18  * BackgroundBridge holds the main script's state and the scraped passwords
19  * from the injected script to help the two collaborate.
20  */
21 function BackgroundBridge() {
22 }
23
24 BackgroundBridge.prototype = {
25   // Gaia URL base that is set from main auth script.
26   gaiaUrl_: null,
27
28   // Whether auth flow has started. It is used as a signal of whether the
29   // injected script should scrape passwords.
30   authStarted_: false,
31
32   passwordStore_: {},
33
34   channelMain_: null,
35   channelInjected_: null,
36
37   run: function() {
38     chrome.runtime.onConnect.addListener(this.onConnect_.bind(this));
39
40     // Workarounds for loading SAML page in an iframe.
41     chrome.webRequest.onHeadersReceived.addListener(
42         function(details) {
43           if (!this.authStarted_)
44             return;
45
46           var headers = details.responseHeaders;
47           for (var i = 0; headers && i < headers.length; ++i) {
48             if (headers[i].name.toLowerCase() == 'x-frame-options') {
49               headers.splice(i, 1);
50               break;
51             }
52           }
53           return {responseHeaders: headers};
54         }.bind(this),
55         {urls: ['<all_urls>'], types: ['sub_frame']},
56         ['blocking', 'responseHeaders']);
57   },
58
59   onConnect_: function(port) {
60     if (port.name == 'authMain')
61       this.setupForAuthMain_(port);
62     else if (port.name == 'injected')
63       this.setupForInjected_(port);
64     else
65       console.error('Unexpected connection, port.name=' + port.name);
66   },
67
68   /**
69    * Sets up the communication channel with the main script.
70    */
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));
83   },
84
85   /**
86    * Sets up the communication channel with the injected script.
87    */
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));
95   },
96
97   /**
98    * Handler for 'setGaiaUrl' signal sent from the main script.
99    */
100   onSetGaiaUrl_: function(msg) {
101     this.gaiaUrl_ = msg.gaiaUrl;
102
103     // Set request header to let Gaia know that saml support is on.
104     chrome.webRequest.onBeforeSendHeaders.addListener(
105         function(details) {
106           details.requestHeaders.push({
107             name: 'X-Cros-Auth-Ext-Support',
108             value: 'SAML'
109           });
110           return {requestHeaders: details.requestHeaders};
111         },
112         {urls: [this.gaiaUrl_ + '*'], types: ['sub_frame']},
113         ['blocking', 'requestHeaders']);
114   },
115
116   /**
117    * Handler for 'resetAuth' signal sent from the main script.
118    */
119   onResetAuth_: function() {
120     this.authStarted_ = false;
121     this.passwordStore_ = {};
122   },
123
124   /**
125    * Handler for 'authStarted' signal sent from the main script.
126    */
127   onAuthStarted_: function() {
128     this.authStarted_ = true;
129     this.passwordStore_ = {};
130   },
131
132   /**
133    * Handler for 'getScrapedPasswords' request sent from the main script.
134    * @return {Array.<string>} The array with de-duped scraped passwords.
135    */
136   onGetScrapedPasswords_: function() {
137     var passwords = {};
138     for (var property in this.passwordStore_) {
139       passwords[this.passwordStore_[property]] = true;
140     }
141     return Object.keys(passwords);
142   },
143
144   onUpdatePassword_: function(msg) {
145     if (!this.authStarted_)
146       return;
147
148     this.passwordStore_[msg.id] = msg.password;
149   },
150
151   onPageLoaded_: function(msg) {
152     this.channelMain_.send({name: 'onAuthPageLoaded', url: msg.url});
153   }
154 };
155
156 var backgroundBridge = new BackgroundBridge();
157 backgroundBridge.run();