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 Implements a check whether an app id lists an origin. | 6 * @fileoverview Implements a check whether an app id lists an origin. |
7 */ | 7 */ |
8 'use strict'; | 8 'use strict'; |
9 | 9 |
10 /** | 10 /** |
11 * Parses the text as JSON and returns it as an array of strings. | 11 * Parses the text as JSON and returns it as an array of strings. |
12 * @param {string} text Input JSON | 12 * @param {string} text Input JSON |
13 * @return {!Array.<string>} Array of origins | 13 * @return {!Array<string>} Array of origins |
14 */ | 14 */ |
15 function getOriginsFromJson(text) { | 15 function getOriginsFromJson(text) { |
16 try { | 16 try { |
17 var urls = JSON.parse(text); | 17 var urls = JSON.parse(text); |
18 var origins = {}; | 18 var origins = {}; |
19 for (var i = 0, url; url = urls[i]; i++) { | 19 for (var i = 0, url; url = urls[i]; i++) { |
20 var origin = getOriginFromUrl(url); | 20 var origin = getOriginFromUrl(url); |
21 if (origin) { | 21 if (origin) { |
22 origins[origin] = origin; | 22 origins[origin] = origin; |
23 } | 23 } |
24 } | 24 } |
25 return Object.keys(origins); | 25 return Object.keys(origins); |
26 } catch (e) { | 26 } catch (e) { |
27 console.log(UTIL_fmt('could not parse ' + text)); | 27 console.log(UTIL_fmt('could not parse ' + text)); |
28 return []; | 28 return []; |
29 } | 29 } |
30 } | 30 } |
31 | 31 |
32 /** | 32 /** |
33 * Retrieves a set of distinct app ids from the sign challenges. | 33 * Retrieves a set of distinct app ids from the sign challenges. |
34 * @param {Array.<SignChallenge>=} signChallenges Input sign challenges. | 34 * @param {Array<SignChallenge>=} signChallenges Input sign challenges. |
35 * @return {Array.<string>} array of distinct app ids. | 35 * @return {Array<string>} array of distinct app ids. |
36 */ | 36 */ |
37 function getDistinctAppIds(signChallenges) { | 37 function getDistinctAppIds(signChallenges) { |
38 if (!signChallenges) { | 38 if (!signChallenges) { |
39 return []; | 39 return []; |
40 } | 40 } |
41 var appIds = {}; | 41 var appIds = {}; |
42 for (var i = 0, request; request = signChallenges[i]; i++) { | 42 for (var i = 0, request; request = signChallenges[i]; i++) { |
43 var appId = request['appId']; | 43 var appId = request['appId']; |
44 if (appId) { | 44 if (appId) { |
45 appIds[appId] = appId; | 45 appIds[appId] = appId; |
46 } | 46 } |
47 } | 47 } |
48 return Object.keys(appIds); | 48 return Object.keys(appIds); |
49 } | 49 } |
50 | 50 |
51 /** | 51 /** |
52 * Provides an object to track checking a list of appIds. | 52 * Provides an object to track checking a list of appIds. |
53 * @param {!TextFetcher} fetcher A URL fetcher. | 53 * @param {!TextFetcher} fetcher A URL fetcher. |
54 * @param {!Countdown} timer A timer by which to resolve all provided app ids. | 54 * @param {!Countdown} timer A timer by which to resolve all provided app ids. |
55 * @param {string} origin The origin to check. | 55 * @param {string} origin The origin to check. |
56 * @param {!Array.<string>} appIds The app ids to check. | 56 * @param {!Array<string>} appIds The app ids to check. |
57 * @param {boolean} allowHttp Whether to allow http:// URLs. | 57 * @param {boolean} allowHttp Whether to allow http:// URLs. |
58 * @param {string=} opt_logMsgUrl A log message URL. | 58 * @param {string=} opt_logMsgUrl A log message URL. |
59 * @constructor | 59 * @constructor |
60 */ | 60 */ |
61 function AppIdChecker(fetcher, timer, origin, appIds, allowHttp, opt_logMsgUrl) | 61 function AppIdChecker(fetcher, timer, origin, appIds, allowHttp, opt_logMsgUrl) |
62 { | 62 { |
63 /** @private {!TextFetcher} */ | 63 /** @private {!TextFetcher} */ |
64 this.fetcher_ = fetcher; | 64 this.fetcher_ = fetcher; |
65 /** @private {!Countdown} */ | 65 /** @private {!Countdown} */ |
66 this.timer_ = timer; | 66 this.timer_ = timer; |
67 /** @private {string} */ | 67 /** @private {string} */ |
68 this.origin_ = origin; | 68 this.origin_ = origin; |
69 var appIdsMap = {}; | 69 var appIdsMap = {}; |
70 if (appIds) { | 70 if (appIds) { |
71 for (var i = 0; i < appIds.length; i++) { | 71 for (var i = 0; i < appIds.length; i++) { |
72 appIdsMap[appIds[i]] = appIds[i]; | 72 appIdsMap[appIds[i]] = appIds[i]; |
73 } | 73 } |
74 } | 74 } |
75 /** @private {Array.<string>} */ | 75 /** @private {Array<string>} */ |
76 this.distinctAppIds_ = Object.keys(appIdsMap); | 76 this.distinctAppIds_ = Object.keys(appIdsMap); |
77 /** @private {boolean} */ | 77 /** @private {boolean} */ |
78 this.allowHttp_ = allowHttp; | 78 this.allowHttp_ = allowHttp; |
79 /** @private {string|undefined} */ | 79 /** @private {string|undefined} */ |
80 this.logMsgUrl_ = opt_logMsgUrl; | 80 this.logMsgUrl_ = opt_logMsgUrl; |
81 | 81 |
82 /** @private {boolean} */ | 82 /** @private {boolean} */ |
83 this.closed_ = false; | 83 this.closed_ = false; |
84 /** @private {boolean} */ | 84 /** @private {boolean} */ |
85 this.anyInvalidAppIds_ = false; | 85 this.anyInvalidAppIds_ = false; |
86 /** @private {number} */ | 86 /** @private {number} */ |
87 this.fetchedAppIds_ = 0; | 87 this.fetchedAppIds_ = 0; |
88 } | 88 } |
89 | 89 |
90 /** | 90 /** |
91 * Checks whether all the app ids provided can be asserted by the given origin. | 91 * Checks whether all the app ids provided can be asserted by the given origin. |
92 * @return {Promise.<boolean>} A promise for the result of the check | 92 * @return {Promise<boolean>} A promise for the result of the check |
93 */ | 93 */ |
94 AppIdChecker.prototype.doCheck = function() { | 94 AppIdChecker.prototype.doCheck = function() { |
95 if (!this.distinctAppIds_.length) | 95 if (!this.distinctAppIds_.length) |
96 return Promise.resolve(false); | 96 return Promise.resolve(false); |
97 | 97 |
98 if (this.allAppIdsEqualOrigin_()) { | 98 if (this.allAppIdsEqualOrigin_()) { |
99 // Trivially allowed. | 99 // Trivially allowed. |
100 return Promise.resolve(true); | 100 return Promise.resolve(true); |
101 } else { | 101 } else { |
102 var self = this; | 102 var self = this; |
103 // Begin checking remaining app ids. | 103 // Begin checking remaining app ids. |
104 var appIdChecks = self.distinctAppIds_.map(self.checkAppId_.bind(self)); | 104 var appIdChecks = self.distinctAppIds_.map(self.checkAppId_.bind(self)); |
105 return Promise.all(appIdChecks).then(function(results) { | 105 return Promise.all(appIdChecks).then(function(results) { |
106 return results.every(function(result) { | 106 return results.every(function(result) { |
107 if (!result) | 107 if (!result) |
108 self.anyInvalidAppIds_ = true; | 108 self.anyInvalidAppIds_ = true; |
109 return result; | 109 return result; |
110 }); | 110 }); |
111 }); | 111 }); |
112 } | 112 } |
113 }; | 113 }; |
114 | 114 |
115 /** | 115 /** |
116 * Checks if a single appId can be asserted by the given origin. | 116 * Checks if a single appId can be asserted by the given origin. |
117 * @param {string} appId The appId to check | 117 * @param {string} appId The appId to check |
118 * @return {Promise.<boolean>} A promise for the result of the check | 118 * @return {Promise<boolean>} A promise for the result of the check |
119 * @private | 119 * @private |
120 */ | 120 */ |
121 AppIdChecker.prototype.checkAppId_ = function(appId) { | 121 AppIdChecker.prototype.checkAppId_ = function(appId) { |
122 if (appId == this.origin_) { | 122 if (appId == this.origin_) { |
123 // Trivially allowed | 123 // Trivially allowed |
124 return Promise.resolve(true); | 124 return Promise.resolve(true); |
125 } | 125 } |
126 var p = this.fetchAllowedOriginsForAppId_(appId); | 126 var p = this.fetchAllowedOriginsForAppId_(appId); |
127 var self = this; | 127 var self = this; |
128 return p.then(function(allowedOrigins) { | 128 return p.then(function(allowedOrigins) { |
(...skipping 21 matching lines...) Expand all Loading... |
150 AppIdChecker.prototype.allAppIdsEqualOrigin_ = function() { | 150 AppIdChecker.prototype.allAppIdsEqualOrigin_ = function() { |
151 var self = this; | 151 var self = this; |
152 return this.distinctAppIds_.every(function(appId) { | 152 return this.distinctAppIds_.every(function(appId) { |
153 return appId == self.origin_; | 153 return appId == self.origin_; |
154 }); | 154 }); |
155 }; | 155 }; |
156 | 156 |
157 /** | 157 /** |
158 * Fetches the allowed origins for an appId. | 158 * Fetches the allowed origins for an appId. |
159 * @param {string} appId Application id | 159 * @param {string} appId Application id |
160 * @return {Promise.<!Array.<string>>} A promise for a list of allowed origins | 160 * @return {Promise<!Array<string>>} A promise for a list of allowed origins |
161 * for appId | 161 * for appId |
162 * @private | 162 * @private |
163 */ | 163 */ |
164 AppIdChecker.prototype.fetchAllowedOriginsForAppId_ = function(appId) { | 164 AppIdChecker.prototype.fetchAllowedOriginsForAppId_ = function(appId) { |
165 if (!appId) { | 165 if (!appId) { |
166 return Promise.resolve([]); | 166 return Promise.resolve([]); |
167 } | 167 } |
168 | 168 |
169 if (appId.indexOf('http://') == 0 && !this.allowHttp_) { | 169 if (appId.indexOf('http://') == 0 && !this.allowHttp_) { |
170 console.log(UTIL_fmt('http app ids disallowed, ' + appId + ' requested')); | 170 console.log(UTIL_fmt('http app ids disallowed, ' + appId + ' requested')); |
(...skipping 10 matching lines...) Expand all Loading... |
181 return p.then(getOriginsFromJson, function(rc_) { | 181 return p.then(getOriginsFromJson, function(rc_) { |
182 var rc = /** @type {number} */(rc_); | 182 var rc = /** @type {number} */(rc_); |
183 console.log(UTIL_fmt('fetching ' + appId + ' failed: ' + rc)); | 183 console.log(UTIL_fmt('fetching ' + appId + ' failed: ' + rc)); |
184 if (!(rc >= 400 && rc < 500) && !self.timer_.expired()) { | 184 if (!(rc >= 400 && rc < 500) && !self.timer_.expired()) { |
185 // Retry | 185 // Retry |
186 return self.fetchAllowedOriginsForAppId_(appId); | 186 return self.fetchAllowedOriginsForAppId_(appId); |
187 } | 187 } |
188 return []; | 188 return []; |
189 }); | 189 }); |
190 }; | 190 }; |
OLD | NEW |