OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Handles web page requests for gnubby sign requests. | 6 * @fileoverview Handles web page requests for gnubby sign requests. |
7 */ | 7 */ |
8 | 8 |
9 'use strict'; | 9 'use strict'; |
10 | 10 |
11 var signRequestQueue = new OriginKeyedRequestQueue(); | 11 var signRequestQueue = new OriginKeyedRequestQueue(); |
12 | 12 |
13 /** | 13 /** |
14 * Handles a sign request. | 14 * Handles a sign request. |
15 * @param {!SignHelperFactory} factory Factory to create a sign helper. | 15 * @param {!SignHelperFactory} factory Factory to create a sign helper. |
16 * @param {MessageSender} sender The sender of the message. | 16 * @param {MessageSender} sender The sender of the message. |
17 * @param {Object} request The web page's sign request. | 17 * @param {Object} request The web page's sign request. |
18 * @param {boolean} enforceAppIdValid Whether to enforce that the app id in the | |
19 * request matches the sender's origin. | |
20 * @param {Function} sendResponse Called back with the result of the sign. | 18 * @param {Function} sendResponse Called back with the result of the sign. |
21 * @param {boolean} toleratesMultipleResponses Whether the sendResponse | 19 * @param {boolean} toleratesMultipleResponses Whether the sendResponse |
22 * callback can be called more than once, e.g. for progress updates. | 20 * callback can be called more than once, e.g. for progress updates. |
23 * @return {Closeable} Request handler that should be closed when the browser | 21 * @return {Closeable} Request handler that should be closed when the browser |
24 * message channel is closed. | 22 * message channel is closed. |
25 */ | 23 */ |
26 function handleSignRequest(factory, sender, request, enforceAppIdValid, | 24 function handleSignRequest(factory, sender, request, sendResponse, |
27 sendResponse, toleratesMultipleResponses) { | 25 toleratesMultipleResponses) { |
28 var sentResponse = false; | 26 var sentResponse = false; |
29 function sendResponseOnce(r) { | 27 function sendResponseOnce(r) { |
30 if (queuedSignRequest) { | 28 if (queuedSignRequest) { |
31 queuedSignRequest.close(); | 29 queuedSignRequest.close(); |
32 queuedSignRequest = null; | 30 queuedSignRequest = null; |
33 } | 31 } |
34 if (!sentResponse) { | 32 if (!sentResponse) { |
35 sentResponse = true; | 33 sentResponse = true; |
36 try { | 34 try { |
37 // If the page has gone away or the connection has otherwise gone, | 35 // If the page has gone away or the connection has otherwise gone, |
(...skipping 17 matching lines...) Expand all Loading... |
55 for (var k in challenge) { | 53 for (var k in challenge) { |
56 responseData[k] = challenge[k]; | 54 responseData[k] = challenge[k]; |
57 } | 55 } |
58 responseData['browserData'] = B64_encode(UTIL_StringToBytes(browserData)); | 56 responseData['browserData'] = B64_encode(UTIL_StringToBytes(browserData)); |
59 responseData['signatureData'] = info; | 57 responseData['signatureData'] = info; |
60 var response = formatWebPageResponse(GnubbyMsgTypes.SIGN_WEB_REPLY, | 58 var response = formatWebPageResponse(GnubbyMsgTypes.SIGN_WEB_REPLY, |
61 GnubbyCodeTypes.OK, responseData); | 59 GnubbyCodeTypes.OK, responseData); |
62 sendResponseOnce(response); | 60 sendResponseOnce(response); |
63 } | 61 } |
64 | 62 |
65 function sendNotification(code) { | |
66 console.log(UTIL_fmt('notification, code=' + code)); | |
67 // Can the callback handle progress updates? If so, send one. | |
68 if (toleratesMultipleResponses) { | |
69 var response = formatWebPageResponse( | |
70 GnubbyMsgTypes.SIGN_WEB_NOTIFICATION, code); | |
71 if (request['requestId']) { | |
72 response['requestId'] = request['requestId']; | |
73 } | |
74 sendResponse(response); | |
75 } | |
76 } | |
77 | |
78 var origin = getOriginFromUrl(/** @type {string} */ (sender.url)); | 63 var origin = getOriginFromUrl(/** @type {string} */ (sender.url)); |
79 if (!origin) { | 64 if (!origin) { |
80 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); | 65 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); |
81 return null; | 66 return null; |
82 } | 67 } |
83 // More closure type inference fail. | 68 // More closure type inference fail. |
84 var nonNullOrigin = /** @type {string} */ (origin); | 69 var nonNullOrigin = /** @type {string} */ (origin); |
85 | 70 |
86 if (!isValidSignRequest(request)) { | 71 if (!isValidSignRequest(request)) { |
87 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); | 72 sendErrorResponse(GnubbyCodeTypes.BAD_REQUEST); |
88 return null; | 73 return null; |
89 } | 74 } |
90 | 75 |
91 var signData = request['signData']; | 76 var signData = request['signData']; |
92 // A valid sign data has at least one challenge, so get the first appId from | 77 // A valid sign data has at least one challenge, so get the first appId from |
93 // the first challenge. | 78 // the first challenge. |
94 var firstAppId = signData[0]['appId']; | 79 var firstAppId = signData[0]['appId']; |
95 var timeoutMillis = Signer.DEFAULT_TIMEOUT_MILLIS; | 80 var timeoutMillis = Signer.DEFAULT_TIMEOUT_MILLIS; |
96 if (request['timeout']) { | 81 if (request['timeout']) { |
97 // Request timeout is in seconds. | 82 // Request timeout is in seconds. |
98 timeoutMillis = request['timeout'] * 1000; | 83 timeoutMillis = request['timeout'] * 1000; |
99 } | 84 } |
100 var timer = new CountdownTimer(timeoutMillis); | 85 var timer = new CountdownTimer(timeoutMillis); |
101 var logMsgUrl = request['logMsgUrl']; | 86 var logMsgUrl = request['logMsgUrl']; |
102 | 87 |
103 // Queue sign requests from the same origin, to protect against simultaneous | 88 // Queue sign requests from the same origin, to protect against simultaneous |
104 // sign-out on many tabs resulting in repeated sign-in requests. | 89 // sign-out on many tabs resulting in repeated sign-in requests. |
105 var queuedSignRequest = new QueuedSignRequest(signData, factory, timer, | 90 var queuedSignRequest = new QueuedSignRequest(signData, factory, timer, |
106 nonNullOrigin, enforceAppIdValid, sendErrorResponse, sendSuccessResponse, | 91 nonNullOrigin, sendErrorResponse, sendSuccessResponse, |
107 sendNotification, sender.tlsChannelId, logMsgUrl); | 92 sender.tlsChannelId, logMsgUrl); |
108 var requestToken = signRequestQueue.queueRequest(firstAppId, nonNullOrigin, | 93 var requestToken = signRequestQueue.queueRequest(firstAppId, nonNullOrigin, |
109 queuedSignRequest.begin.bind(queuedSignRequest), timer); | 94 queuedSignRequest.begin.bind(queuedSignRequest), timer); |
110 queuedSignRequest.setToken(requestToken); | 95 queuedSignRequest.setToken(requestToken); |
111 return queuedSignRequest; | 96 return queuedSignRequest; |
112 } | 97 } |
113 | 98 |
114 /** | 99 /** |
115 * Returns whether the request appears to be a valid sign request. | 100 * Returns whether the request appears to be a valid sign request. |
116 * @param {Object} request the request. | 101 * @param {Object} request the request. |
117 * @return {boolean} whether the request appears valid. | 102 * @return {boolean} whether the request appears valid. |
118 */ | 103 */ |
119 function isValidSignRequest(request) { | 104 function isValidSignRequest(request) { |
120 if (!request.hasOwnProperty('signData')) | 105 if (!request.hasOwnProperty('signData')) |
121 return false; | 106 return false; |
122 var signData = request['signData']; | 107 var signData = request['signData']; |
123 // If a sign request contains an empty array of challenges, it could never | 108 // If a sign request contains an empty array of challenges, it could never |
124 // be fulfilled. Fail. | 109 // be fulfilled. Fail. |
125 if (!signData.length) | 110 if (!signData.length) |
126 return false; | 111 return false; |
127 return isValidSignData(signData); | 112 return isValidSignData(signData); |
128 } | 113 } |
129 | 114 |
130 /** | 115 /** |
131 * Adapter class representing a queued sign request. | 116 * Adapter class representing a queued sign request. |
132 * @param {!SignData} signData Signature data | 117 * @param {!SignData} signData Signature data |
133 * @param {!SignHelperFactory} factory Factory for SignHelper instances | 118 * @param {!SignHelperFactory} factory Factory for SignHelper instances |
134 * @param {Countdown} timer Timeout timer | 119 * @param {Countdown} timer Timeout timer |
135 * @param {string} origin Signature origin | 120 * @param {string} origin Signature origin |
136 * @param {boolean} enforceAppIdValid If to enforce appId validity | |
137 * @param {function(number)} errorCb Error callback | 121 * @param {function(number)} errorCb Error callback |
138 * @param {function(SignChallenge, string, string)} successCb Success callback | 122 * @param {function(SignChallenge, string, string)} successCb Success callback |
139 * @param {(function(number)|undefined)} opt_progressCb Progress callback | |
140 * @param {string|undefined} opt_tlsChannelId TLS Channel Id | 123 * @param {string|undefined} opt_tlsChannelId TLS Channel Id |
141 * @param {string|undefined} opt_logMsgUrl Url to post log messages to | 124 * @param {string|undefined} opt_logMsgUrl Url to post log messages to |
142 * @constructor | 125 * @constructor |
143 * @implements {Closeable} | 126 * @implements {Closeable} |
144 */ | 127 */ |
145 function QueuedSignRequest(signData, factory, timer, origin, enforceAppIdValid, | 128 function QueuedSignRequest(signData, factory, timer, origin, errorCb, successCb, |
146 errorCb, successCb, opt_progressCb, opt_tlsChannelId, opt_logMsgUrl) { | 129 opt_tlsChannelId, opt_logMsgUrl) { |
147 /** @private {!SignData} */ | 130 /** @private {!SignData} */ |
148 this.signData_ = signData; | 131 this.signData_ = signData; |
149 /** @private {!SignHelperFactory} */ | 132 /** @private {!SignHelperFactory} */ |
150 this.factory_ = factory; | 133 this.factory_ = factory; |
151 /** @private {Countdown} */ | 134 /** @private {Countdown} */ |
152 this.timer_ = timer; | 135 this.timer_ = timer; |
153 /** @private {string} */ | 136 /** @private {string} */ |
154 this.origin_ = origin; | 137 this.origin_ = origin; |
155 /** @private {boolean} */ | |
156 this.enforceAppIdValid_ = enforceAppIdValid; | |
157 /** @private {function(number)} */ | 138 /** @private {function(number)} */ |
158 this.errorCb_ = errorCb; | 139 this.errorCb_ = errorCb; |
159 /** @private {function(SignChallenge, string, string)} */ | 140 /** @private {function(SignChallenge, string, string)} */ |
160 this.successCb_ = successCb; | 141 this.successCb_ = successCb; |
161 /** @private {(function(number)|undefined)} */ | |
162 this.progressCb_ = opt_progressCb; | |
163 /** @private {string|undefined} */ | 142 /** @private {string|undefined} */ |
164 this.tlsChannelId_ = opt_tlsChannelId; | 143 this.tlsChannelId_ = opt_tlsChannelId; |
165 /** @private {string|undefined} */ | 144 /** @private {string|undefined} */ |
166 this.logMsgUrl_ = opt_logMsgUrl; | 145 this.logMsgUrl_ = opt_logMsgUrl; |
167 /** @private {boolean} */ | 146 /** @private {boolean} */ |
168 this.begun_ = false; | 147 this.begun_ = false; |
169 /** @private {boolean} */ | 148 /** @private {boolean} */ |
170 this.closed_ = false; | 149 this.closed_ = false; |
171 } | 150 } |
172 | 151 |
(...skipping 18 matching lines...) Expand all Loading... |
191 }; | 170 }; |
192 | 171 |
193 /** | 172 /** |
194 * Called when this sign request may begin work. | 173 * Called when this sign request may begin work. |
195 * @param {QueuedRequestToken} token Token for this sign request. | 174 * @param {QueuedRequestToken} token Token for this sign request. |
196 */ | 175 */ |
197 QueuedSignRequest.prototype.begin = function(token) { | 176 QueuedSignRequest.prototype.begin = function(token) { |
198 this.begun_ = true; | 177 this.begun_ = true; |
199 this.setToken(token); | 178 this.setToken(token); |
200 this.signer_ = new Signer(this.factory_, this.timer_, this.origin_, | 179 this.signer_ = new Signer(this.factory_, this.timer_, this.origin_, |
201 this.enforceAppIdValid_, this.signerFailed_.bind(this), | 180 this.signerFailed_.bind(this), this.signerSucceeded_.bind(this), |
202 this.signerSucceeded_.bind(this), this.progressCb_, | |
203 this.tlsChannelId_, this.logMsgUrl_); | 181 this.tlsChannelId_, this.logMsgUrl_); |
204 if (!this.signer_.setChallenges(this.signData_)) { | 182 if (!this.signer_.setChallenges(this.signData_)) { |
205 token.complete(); | 183 token.complete(); |
206 this.errorCb_(GnubbyCodeTypes.BAD_REQUEST); | 184 this.errorCb_(GnubbyCodeTypes.BAD_REQUEST); |
207 } | 185 } |
208 }; | 186 }; |
209 | 187 |
210 /** | 188 /** |
211 * Called when this request's signer fails. | 189 * Called when this request's signer fails. |
212 * @param {number} code The failure code reported by the signer. | 190 * @param {number} code The failure code reported by the signer. |
(...skipping 15 matching lines...) Expand all Loading... |
228 function(challenge, info, browserData) { | 206 function(challenge, info, browserData) { |
229 this.token_.complete(); | 207 this.token_.complete(); |
230 this.successCb_(challenge, info, browserData); | 208 this.successCb_(challenge, info, browserData); |
231 }; | 209 }; |
232 | 210 |
233 /** | 211 /** |
234 * Creates an object to track signing with a gnubby. | 212 * Creates an object to track signing with a gnubby. |
235 * @param {!SignHelperFactory} helperFactory Factory to create a sign helper. | 213 * @param {!SignHelperFactory} helperFactory Factory to create a sign helper. |
236 * @param {Countdown} timer Timer for sign request. | 214 * @param {Countdown} timer Timer for sign request. |
237 * @param {string} origin The origin making the request. | 215 * @param {string} origin The origin making the request. |
238 * @param {boolean} enforceAppIdValid Whether to enforce that the appId in the | |
239 * request matches the sender's origin. | |
240 * @param {function(number)} errorCb Called when the sign operation fails. | 216 * @param {function(number)} errorCb Called when the sign operation fails. |
241 * @param {function(SignChallenge, string, string)} successCb Called when the | 217 * @param {function(SignChallenge, string, string)} successCb Called when the |
242 * sign operation succeeds. | 218 * sign operation succeeds. |
243 * @param {(function(number)|undefined)} opt_progressCb Called with progress | |
244 * updates to the sign request. | |
245 * @param {string=} opt_tlsChannelId the TLS channel ID, if any, of the origin | 219 * @param {string=} opt_tlsChannelId the TLS channel ID, if any, of the origin |
246 * making the request. | 220 * making the request. |
247 * @param {string=} opt_logMsgUrl The url to post log messages to. | 221 * @param {string=} opt_logMsgUrl The url to post log messages to. |
248 * @constructor | 222 * @constructor |
249 */ | 223 */ |
250 function Signer(helperFactory, timer, origin, enforceAppIdValid, | 224 function Signer(helperFactory, timer, origin, errorCb, successCb, |
251 errorCb, successCb, opt_progressCb, opt_tlsChannelId, opt_logMsgUrl) { | 225 opt_tlsChannelId, opt_logMsgUrl) { |
252 /** @private {Countdown} */ | 226 /** @private {Countdown} */ |
253 this.timer_ = timer; | 227 this.timer_ = timer; |
254 /** @private {string} */ | 228 /** @private {string} */ |
255 this.origin_ = origin; | 229 this.origin_ = origin; |
256 /** @private {boolean} */ | |
257 this.enforceAppIdValid_ = enforceAppIdValid; | |
258 /** @private {function(number)} */ | 230 /** @private {function(number)} */ |
259 this.errorCb_ = errorCb; | 231 this.errorCb_ = errorCb; |
260 /** @private {function(SignChallenge, string, string)} */ | 232 /** @private {function(SignChallenge, string, string)} */ |
261 this.successCb_ = successCb; | 233 this.successCb_ = successCb; |
262 /** @private {(function(number)|undefined)} */ | |
263 this.progressCb_ = opt_progressCb; | |
264 /** @private {string|undefined} */ | 234 /** @private {string|undefined} */ |
265 this.tlsChannelId_ = opt_tlsChannelId; | 235 this.tlsChannelId_ = opt_tlsChannelId; |
266 /** @private {string|undefined} */ | 236 /** @private {string|undefined} */ |
267 this.logMsgUrl_ = opt_logMsgUrl; | 237 this.logMsgUrl_ = opt_logMsgUrl; |
268 | 238 |
269 /** @private {boolean} */ | 239 /** @private {boolean} */ |
270 this.challengesSet_ = false; | 240 this.challengesSet_ = false; |
271 /** @private {Array.<SignHelperChallenge>} */ | 241 /** @private {Array.<SignHelperChallenge>} */ |
272 this.pendingChallenges_ = []; | 242 this.pendingChallenges_ = []; |
273 /** @private {boolean} */ | 243 /** @private {boolean} */ |
274 this.done_ = false; | 244 this.done_ = false; |
275 | 245 |
276 /** @private {Object.<string, string>} */ | 246 /** @private {Object.<string, string>} */ |
277 this.browserData_ = {}; | 247 this.browserData_ = {}; |
278 /** @private {Object.<string, SignChallenge>} */ | 248 /** @private {Object.<string, SignChallenge>} */ |
279 this.serverChallenges_ = {}; | 249 this.serverChallenges_ = {}; |
280 // Allow http appIds for http origins. (Broken, but the caller deserves | 250 // Allow http appIds for http origins. (Broken, but the caller deserves |
281 // what they get.) | 251 // what they get.) |
282 /** @private {boolean} */ | 252 /** @private {boolean} */ |
283 this.allowHttp_ = this.origin_ ? this.origin_.indexOf('http://') == 0 : false; | 253 this.allowHttp_ = this.origin_ ? this.origin_.indexOf('http://') == 0 : false; |
284 | 254 |
285 // Protect against helper failure with a watchdog. | 255 // Protect against helper failure with a watchdog. |
286 this.createWatchdog_(timer); | 256 this.createWatchdog_(timer); |
287 /** @private {SignHelper} */ | 257 /** @private {SignHelper} */ |
288 this.helper_ = helperFactory.createHelper( | 258 this.helper_ = helperFactory.createHelper( |
289 timer, this.helperError_.bind(this), this.helperSuccess_.bind(this), | 259 timer, this.helperError_.bind(this), this.helperSuccess_.bind(this), |
290 this.helperProgress_.bind(this), this.logMsgUrl_); | 260 this.logMsgUrl_); |
291 } | 261 } |
292 | 262 |
293 /** | 263 /** |
294 * Creates a timer with an expiry greater than the expiration time of the given | 264 * Creates a timer with an expiry greater than the expiration time of the given |
295 * timer. | 265 * timer. |
296 * @param {Countdown} timer Timeout timer | 266 * @param {Countdown} timer Timeout timer |
297 * @private | 267 * @private |
298 */ | 268 */ |
299 Signer.prototype.createWatchdog_ = function(timer) { | 269 Signer.prototype.createWatchdog_ = function(timer) { |
300 var millis = timer.millisecondsUntilExpired(); | 270 var millis = timer.millisecondsUntilExpired(); |
(...skipping 13 matching lines...) Expand all Loading... |
314 * @return {boolean} Whether the challenges could be set. | 284 * @return {boolean} Whether the challenges could be set. |
315 */ | 285 */ |
316 Signer.prototype.setChallenges = function(signData) { | 286 Signer.prototype.setChallenges = function(signData) { |
317 if (this.challengesSet_ || this.done_) | 287 if (this.challengesSet_ || this.done_) |
318 return false; | 288 return false; |
319 /** @private {SignData} */ | 289 /** @private {SignData} */ |
320 this.signData_ = signData; | 290 this.signData_ = signData; |
321 /** @private {boolean} */ | 291 /** @private {boolean} */ |
322 this.challengesSet_ = true; | 292 this.challengesSet_ = true; |
323 | 293 |
324 // If app id enforcing isn't in effect, go ahead and start the helper with | |
325 // all of the incoming challenges. | |
326 var success = true; | |
327 if (!this.enforceAppIdValid_) { | |
328 success = this.addChallenges(signData, true /* finalChallenges */); | |
329 } | |
330 | |
331 this.checkAppIds_(); | 294 this.checkAppIds_(); |
332 return success; | 295 return true; |
333 }; | 296 }; |
334 | 297 |
335 /** | 298 /** |
336 * Adds new challenges to the challenges being signed. | 299 * Adds new challenges to the challenges being signed. |
337 * @param {SignData} signData Challenges to add. | 300 * @param {SignData} signData Challenges to add. |
338 * @param {boolean} finalChallenges Whether these are the final challenges. | 301 * @param {boolean} finalChallenges Whether these are the final challenges. |
339 * @return {boolean} Whether the challenge could be added. | 302 * @return {boolean} Whether the challenge could be added. |
340 */ | 303 */ |
341 Signer.prototype.addChallenges = function(signData, finalChallenges) { | 304 Signer.prototype.addChallenges = function(signData, finalChallenges) { |
342 var newChallenges = this.encodeSignChallenges_(signData); | 305 var newChallenges = this.encodeSignChallenges_(signData); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 /** @private {number} */ | 361 /** @private {number} */ |
399 this.validAppIds_ = 0; | 362 this.validAppIds_ = 0; |
400 for (var i = 0, appIdRequestsPair; i < this.orderedRequests_.length; i++) { | 363 for (var i = 0, appIdRequestsPair; i < this.orderedRequests_.length; i++) { |
401 var appIdRequestsPair = this.orderedRequests_[i]; | 364 var appIdRequestsPair = this.orderedRequests_[i]; |
402 var appId = appIdRequestsPair[0]; | 365 var appId = appIdRequestsPair[0]; |
403 var requests = appIdRequestsPair[1]; | 366 var requests = appIdRequestsPair[1]; |
404 if (appId == this.origin_) { | 367 if (appId == this.origin_) { |
405 // Trivially allowed. | 368 // Trivially allowed. |
406 this.fetchedAppIds_++; | 369 this.fetchedAppIds_++; |
407 this.validAppIds_++; | 370 this.validAppIds_++; |
408 // Only add challenges if in enforcing mode, i.e. they weren't added | 371 this.addChallenges(requests, |
409 // earlier. | 372 this.fetchedAppIds_ == this.orderedRequests_.length); |
410 if (this.enforceAppIdValid_) { | |
411 this.addChallenges(requests, | |
412 this.fetchedAppIds_ == this.orderedRequests_.length); | |
413 } | |
414 } else { | 373 } else { |
415 var start = new Date(); | 374 var start = new Date(); |
416 fetchAllowedOriginsForAppId(appId, this.allowHttp_, | 375 fetchAllowedOriginsForAppId(appId, this.allowHttp_, |
417 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, | 376 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, |
418 requests)); | 377 requests)); |
419 } | 378 } |
420 } | 379 } |
421 }; | 380 }; |
422 | 381 |
423 /** | 382 /** |
(...skipping 18 matching lines...) Expand all Loading... |
442 fetchAllowedOriginsForAppId(appId, this.allowHttp_, | 401 fetchAllowedOriginsForAppId(appId, this.allowHttp_, |
443 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, | 402 this.fetchedAllowedOriginsForAppId_.bind(this, appId, start, |
444 challenges)); | 403 challenges)); |
445 } | 404 } |
446 return; | 405 return; |
447 } | 406 } |
448 this.fetchedAppIds_++; | 407 this.fetchedAppIds_++; |
449 var finalChallenges = (this.fetchedAppIds_ == this.orderedRequests_.length); | 408 var finalChallenges = (this.fetchedAppIds_ == this.orderedRequests_.length); |
450 if (isValidAppIdForOrigin(appId, this.origin_, allowedOrigins)) { | 409 if (isValidAppIdForOrigin(appId, this.origin_, allowedOrigins)) { |
451 this.validAppIds_++; | 410 this.validAppIds_++; |
452 // Only add challenges if in enforcing mode, i.e. they weren't added | 411 this.addChallenges(challenges, finalChallenges); |
453 // earlier. | |
454 if (this.enforceAppIdValid_) { | |
455 this.addChallenges(challenges, finalChallenges); | |
456 } | |
457 } else { | 412 } else { |
458 logInvalidOriginForAppId(this.origin_, appId, this.logMsgUrl_); | 413 logInvalidOriginForAppId(this.origin_, appId, this.logMsgUrl_); |
459 // If in enforcing mode and this is the final request, sign the valid | 414 // If this is the final request, sign the valid challenges. |
460 // challenges. | 415 if (finalChallenges) { |
461 if (this.enforceAppIdValid_ && finalChallenges) { | |
462 if (!this.helper_.doSign(this.pendingChallenges_)) { | 416 if (!this.helper_.doSign(this.pendingChallenges_)) { |
463 this.notifyError_(GnubbyCodeTypes.BAD_REQUEST); | 417 this.notifyError_(GnubbyCodeTypes.BAD_REQUEST); |
464 return; | 418 return; |
465 } | 419 } |
466 } | 420 } |
467 } | 421 } |
468 if (this.enforceAppIdValid_ && finalChallenges && !this.validAppIds_) { | 422 if (finalChallenges && !this.validAppIds_) { |
469 // If all app ids are invalid, notify the caller, otherwise implicitly | 423 // If all app ids are invalid, notify the caller, otherwise implicitly |
470 // allow the helper to report whether any of the valid challenges succeeded. | 424 // allow the helper to report whether any of the valid challenges succeeded. |
471 this.notifyError_(GnubbyCodeTypes.BAD_APP_ID); | 425 this.notifyError_(GnubbyCodeTypes.BAD_APP_ID); |
472 } | 426 } |
473 }; | 427 }; |
474 | 428 |
475 /** | 429 /** |
476 * Called when the timeout expires on this signer. | 430 * Called when the timeout expires on this signer. |
477 * @private | 431 * @private |
478 */ | 432 */ |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
510 */ | 464 */ |
511 Signer.prototype.notifySuccess_ = function(challenge, info, browserData) { | 465 Signer.prototype.notifySuccess_ = function(challenge, info, browserData) { |
512 if (this.done_) | 466 if (this.done_) |
513 return; | 467 return; |
514 this.close(); | 468 this.close(); |
515 this.done_ = true; | 469 this.done_ = true; |
516 this.successCb_(challenge, info, browserData); | 470 this.successCb_(challenge, info, browserData); |
517 }; | 471 }; |
518 | 472 |
519 /** | 473 /** |
520 * Notifies the caller of progress with the error code. | |
521 * @param {number} code Status code | |
522 * @private | |
523 */ | |
524 Signer.prototype.notifyProgress_ = function(code) { | |
525 if (this.done_) | |
526 return; | |
527 if (code != this.lastProgressUpdate_) { | |
528 this.lastProgressUpdate_ = code; | |
529 // If there is no progress callback, treat it like an error and clean up. | |
530 if (this.progressCb_) { | |
531 this.progressCb_(code); | |
532 } else { | |
533 this.notifyError_(code); | |
534 } | |
535 } | |
536 }; | |
537 | |
538 /** | |
539 * Maps a sign helper's error code namespace to the page's error code namespace. | 474 * Maps a sign helper's error code namespace to the page's error code namespace. |
540 * @param {number} code Error code from DeviceStatusCodes namespace. | 475 * @param {number} code Error code from DeviceStatusCodes namespace. |
541 * @param {boolean} anyGnubbies Whether any gnubbies were found. | 476 * @param {boolean} anyGnubbies Whether any gnubbies were found. |
542 * @return {number} A GnubbyCodeTypes error code. | 477 * @return {number} A GnubbyCodeTypes error code. |
543 * @private | 478 * @private |
544 */ | 479 */ |
545 Signer.mapError_ = function(code, anyGnubbies) { | 480 Signer.mapError_ = function(code, anyGnubbies) { |
546 var reportedError; | 481 var reportedError; |
547 switch (code) { | 482 switch (code) { |
548 case DeviceStatusCodes.WRONG_DATA_STATUS: | 483 case DeviceStatusCodes.WRONG_DATA_STATUS: |
(...skipping 30 matching lines...) Expand all Loading... |
579 var reportedError = Signer.mapError_(code, anyGnubbies); | 514 var reportedError = Signer.mapError_(code, anyGnubbies); |
580 console.log(UTIL_fmt('helper reported ' + code.toString(16) + | 515 console.log(UTIL_fmt('helper reported ' + code.toString(16) + |
581 ', returning ' + reportedError)); | 516 ', returning ' + reportedError)); |
582 this.notifyError_(reportedError); | 517 this.notifyError_(reportedError); |
583 }; | 518 }; |
584 | 519 |
585 /** | 520 /** |
586 * Called by helper upon success. | 521 * Called by helper upon success. |
587 * @param {SignHelperChallenge} challenge The challenge that was signed. | 522 * @param {SignHelperChallenge} challenge The challenge that was signed. |
588 * @param {string} info The sign result. | 523 * @param {string} info The sign result. |
| 524 * @param {string=} opt_source The source, if any, if the signature. |
589 * @private | 525 * @private |
590 */ | 526 */ |
591 Signer.prototype.helperSuccess_ = function(challenge, info) { | 527 Signer.prototype.helperSuccess_ = function(challenge, info, opt_source) { |
592 // Got a good reply, kill timer. | 528 // Got a good reply, kill timer. |
593 this.clearTimeout_(); | 529 this.clearTimeout_(); |
594 | 530 |
| 531 if (this.logMsgUrl_ && opt_source) { |
| 532 var logMsg = 'signed&source=' + opt_source; |
| 533 logMessage(logMsg, this.logMsgUrl_); |
| 534 } |
| 535 |
595 var key = challenge['keyHandle'] + challenge['challengeHash']; | 536 var key = challenge['keyHandle'] + challenge['challengeHash']; |
596 var browserData = this.browserData_[key]; | 537 var browserData = this.browserData_[key]; |
597 // Notify with server-provided challenge, not the encoded one: the | 538 // Notify with server-provided challenge, not the encoded one: the |
598 // server-provided challenge contains additional fields it relies on. | 539 // server-provided challenge contains additional fields it relies on. |
599 var serverChallenge = this.serverChallenges_[key]; | 540 var serverChallenge = this.serverChallenges_[key]; |
600 this.notifySuccess_(serverChallenge, info, browserData); | 541 this.notifySuccess_(serverChallenge, info, browserData); |
601 }; | 542 }; |
602 | 543 |
603 /** | 544 /** |
604 * Called by helper to notify progress. | |
605 * @param {number} code Status code | |
606 * @param {boolean} anyGnubbies If any gnubbies were found | |
607 * @private | |
608 */ | |
609 Signer.prototype.helperProgress_ = function(code, anyGnubbies) { | |
610 var reportedError = Signer.mapError_(code, anyGnubbies); | |
611 console.log(UTIL_fmt('helper notified ' + code.toString(16) + | |
612 ', returning ' + reportedError)); | |
613 this.notifyProgress_(reportedError); | |
614 }; | |
615 | |
616 /** | |
617 * Clears the timeout for this signer. | 545 * Clears the timeout for this signer. |
618 * @private | 546 * @private |
619 */ | 547 */ |
620 Signer.prototype.clearTimeout_ = function() { | 548 Signer.prototype.clearTimeout_ = function() { |
621 if (this.watchdogTimer_) { | 549 if (this.watchdogTimer_) { |
622 this.watchdogTimer_.clearTimeout(); | 550 this.watchdogTimer_.clearTimeout(); |
623 this.watchdogTimer_ = undefined; | 551 this.watchdogTimer_ = undefined; |
624 } | 552 } |
625 }; | 553 }; |
OLD | NEW |