1 // Copyright (c) 2011 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 #include "base/logging.h"
7 #include "base/time.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "chrome/browser/safe_browsing/protocol_manager.h"
10
11 using base::Time;
12 using base::TimeDelta;
13
14 static const char kInfoUrlPrefix[] = "http://info.prefix.com/foo";
15 static const char kMacKeyUrlPrefix[] = "https://key.prefix.com/bar";
16 static const char kClient[] = "unittest";
17 static const char kAppVer[] = "1.0";
18 static const char kClientKey[] = "SCg9lcLHd0dfksXgYsacwQ==";
19 static const char kWrappedKey[] =
20 "AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqA"
21 "BiJZnDFByc_g8B5vTwxkhBf9g==";
22 static const char kAdditionalQuery[] = "additional_query";
23
24 class SafeBrowsingProtocolManagerTest : public testing::Test {
25 };
26
27 // Ensure that we respect section 5 of the SafeBrowsing protocol specification.
TEST_F(SafeBrowsingProtocolManagerTest,TestBackOffTimes)28 TEST_F(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
29 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
30 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
31 pm.next_update_sec_ = 1800;
32 DCHECK(pm.back_off_fuzz_ >= 0.0 && pm.back_off_fuzz_ <= 1.0);
33
34 // No errors received so far.
35 EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);
36
37 // 1 error.
38 EXPECT_EQ(pm.GetNextUpdateTime(true), 60 * 1000);
39
40 // 2 errors.
41 int next_time = pm.GetNextUpdateTime(true) / (60 * 1000); // Minutes
42 EXPECT_TRUE(next_time >= 30 && next_time <= 60);
43
44 // 3 errors.
45 next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
46 EXPECT_TRUE(next_time >= 60 && next_time <= 120);
47
48 // 4 errors.
49 next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
50 EXPECT_TRUE(next_time >= 120 && next_time <= 240);
51
52 // 5 errors.
53 next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
54 EXPECT_TRUE(next_time >= 240 && next_time <= 480);
55
56 // 6 errors, reached max backoff.
57 EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);
58
59 // 7 errors.
60 EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);
61
62 // Received a successful response.
63 EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);
64 }
65
66 // Test string combinations with and without MAC.
TEST_F(SafeBrowsingProtocolManagerTest,TestChunkStrings)67 TEST_F(SafeBrowsingProtocolManagerTest, TestChunkStrings) {
68 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
69 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
70
71 // Add and Sub chunks.
72 SBListChunkRanges phish("goog-phish-shavar");
73 phish.adds = "1,4,6,8-20,99";
74 phish.subs = "16,32,64-96";
75 EXPECT_EQ(pm.FormatList(phish, false),
76 "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96\n");
77 EXPECT_EQ(pm.FormatList(phish, true),
78 "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96:mac\n");
79
80 // Add chunks only.
81 phish.subs = "";
82 EXPECT_EQ(pm.FormatList(phish, false),
83 "goog-phish-shavar;a:1,4,6,8-20,99\n");
84 EXPECT_EQ(pm.FormatList(phish, true),
85 "goog-phish-shavar;a:1,4,6,8-20,99:mac\n");
86
87 // Sub chunks only.
88 phish.adds = "";
89 phish.subs = "16,32,64-96";
90 EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;s:16,32,64-96\n");
91 EXPECT_EQ(pm.FormatList(phish, true),
92 "goog-phish-shavar;s:16,32,64-96:mac\n");
93
94 // No chunks of either type.
95 phish.adds = "";
96 phish.subs = "";
97 EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;\n");
98 EXPECT_EQ(pm.FormatList(phish, true), "goog-phish-shavar;mac\n");
99 }
100
TEST_F(SafeBrowsingProtocolManagerTest,TestGetHashBackOffTimes)101 TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashBackOffTimes) {
102 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
103 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
104
105 // No errors or back off time yet.
106 EXPECT_EQ(pm.gethash_error_count_, 0);
107 EXPECT_TRUE(pm.next_gethash_time_.is_null());
108
109 Time now = Time::Now();
110
111 // 1 error.
112 pm.HandleGetHashError(now);
113 EXPECT_EQ(pm.gethash_error_count_, 1);
114 TimeDelta margin = TimeDelta::FromSeconds(5); // Fudge factor.
115 Time future = now + TimeDelta::FromMinutes(1);
116 EXPECT_TRUE(pm.next_gethash_time_ >= future - margin &&
117 pm.next_gethash_time_ <= future + margin);
118
119 // 2 errors.
120 pm.HandleGetHashError(now);
121 EXPECT_EQ(pm.gethash_error_count_, 2);
122 EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(30));
123 EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(60));
124
125 // 3 errors.
126 pm.HandleGetHashError(now);
127 EXPECT_EQ(pm.gethash_error_count_, 3);
128 EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(60));
129 EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(120));
130
131 // 4 errors.
132 pm.HandleGetHashError(now);
133 EXPECT_EQ(pm.gethash_error_count_, 4);
134 EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(120));
135 EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(240));
136
137 // 5 errors.
138 pm.HandleGetHashError(now);
139 EXPECT_EQ(pm.gethash_error_count_, 5);
140 EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(240));
141 EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(480));
142
143 // 6 errors, reached max backoff.
144 pm.HandleGetHashError(now);
145 EXPECT_EQ(pm.gethash_error_count_, 6);
146 EXPECT_TRUE(pm.next_gethash_time_ == now + TimeDelta::FromMinutes(480));
147
148 // 7 errors.
149 pm.HandleGetHashError(now);
150 EXPECT_EQ(pm.gethash_error_count_, 7);
151 EXPECT_TRUE(pm.next_gethash_time_== now + TimeDelta::FromMinutes(480));
152 }
153
TEST_F(SafeBrowsingProtocolManagerTest,TestGetHashUrl)154 TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashUrl) {
155 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
156 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
157 pm.version_ = kAppVer;
158 EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
159 "pver=2.2", pm.GetHashUrl(false).spec());
160 EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
161 "pver=2.2&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cE"
162 "ErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf9g==",
163 pm.GetHashUrl(true).spec());
164
165 pm.set_additional_query(kAdditionalQuery);
166 EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
167 "pver=2.2&additional_query",
168 pm.GetHashUrl(false).spec());
169 EXPECT_EQ("http://info.prefix.com/foo/gethash?client=unittest&appver=1.0&"
170 "pver=2.2&additional_query&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8"
171 "nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf"
172 "9g==", pm.GetHashUrl(true).spec());
173 }
174
TEST_F(SafeBrowsingProtocolManagerTest,TestUpdateUrl)175 TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) {
176 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
177 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
178 pm.version_ = kAppVer;
179
180 EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
181 "pver=2.2", pm.UpdateUrl(false).spec());
182 EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
183 "pver=2.2&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8nNaYH47tiQ7pDe9cE"
184 "ErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf9g==",
185 pm.UpdateUrl(true).spec());
186
187 pm.set_additional_query(kAdditionalQuery);
188 EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
189 "pver=2.2&additional_query", pm.UpdateUrl(false).spec());
190 EXPECT_EQ("http://info.prefix.com/foo/downloads?client=unittest&appver=1.0&"
191 "pver=2.2&additional_query&wrkey=AKEgNisjLl7iRYrjWHmpd_XwCiilxrw8"
192 "nNaYH47tiQ7pDe9cEErjVHGZaPPUau5h61tbXSDqABiJZnDFByc_g8B5vTwxkhBf"
193 "9g==", pm.UpdateUrl(true).spec());
194 }
195
TEST_F(SafeBrowsingProtocolManagerTest,TestSafeBrowsingHitUrl)196 TEST_F(SafeBrowsingProtocolManagerTest, TestSafeBrowsingHitUrl) {
197 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
198 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
199 pm.version_ = kAppVer;
200
201 GURL malicious_url("http://malicious.url.com");
202 GURL page_url("http://page.url.com");
203 GURL referrer_url("http://referrer.url.com");
204 EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
205 "pver=2.2&evts=malblhit&evtd=http%3A%2F%2Fmalicious.url.com%2F&"
206 "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
207 "url.com%2F&evtb=1",
208 pm.SafeBrowsingHitUrl(
209 malicious_url, page_url, referrer_url,
210 true, SafeBrowsingService::URL_MALWARE).spec());
211
212 pm.set_additional_query(kAdditionalQuery);
213 EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
214 "pver=2.2&additional_query&evts=phishblhit&"
215 "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
216 "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
217 "url.com%2F&evtb=0",
218 pm.SafeBrowsingHitUrl(
219 malicious_url, page_url, referrer_url,
220 false, SafeBrowsingService::URL_PHISHING).spec());
221
222 EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
223 "pver=2.2&additional_query&evts=binurlhit&"
224 "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
225 "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
226 "url.com%2F&evtb=0",
227 pm.SafeBrowsingHitUrl(
228 malicious_url, page_url, referrer_url,
229 false, SafeBrowsingService::BINARY_MALWARE_URL).spec());
230
231 EXPECT_EQ("http://info.prefix.com/foo/report?client=unittest&appver=1.0&"
232 "pver=2.2&additional_query&evts=binhashhit&"
233 "evtd=http%3A%2F%2Fmalicious.url.com%2F&"
234 "evtr=http%3A%2F%2Fpage.url.com%2F&evhr=http%3A%2F%2Freferrer."
235 "url.com%2F&evtb=0",
236 pm.SafeBrowsingHitUrl(
237 malicious_url, page_url, referrer_url,
238 false, SafeBrowsingService::BINARY_MALWARE_HASH).spec());
239 }
240
TEST_F(SafeBrowsingProtocolManagerTest,TestMalwareDetailsUrl)241 TEST_F(SafeBrowsingProtocolManagerTest, TestMalwareDetailsUrl) {
242 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
243 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
244
245 pm.version_ = kAppVer;
246 pm.set_additional_query(kAdditionalQuery); // AdditionalQuery is not used.
247 EXPECT_EQ("https://key.prefix.com/bar/clientreport/malware?"
248 "client=unittest&appver=1.0&pver=1.0",
249 pm.MalwareDetailsUrl().spec());
250 }
251
TEST_F(SafeBrowsingProtocolManagerTest,TestMacKeyUrl)252 TEST_F(SafeBrowsingProtocolManagerTest, TestMacKeyUrl) {
253 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
254 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
255 pm.version_ = kAppVer;
256
257 EXPECT_EQ("https://key.prefix.com/bar/newkey?client=unittest&appver=1.0&"
258 "pver=2.2", pm.MacKeyUrl().spec());
259
260 pm.set_additional_query(kAdditionalQuery);
261 EXPECT_EQ("https://key.prefix.com/bar/newkey?client=unittest&appver=1.0&"
262 "pver=2.2&additional_query", pm.MacKeyUrl().spec());
263 }
264
TEST_F(SafeBrowsingProtocolManagerTest,TestNextChunkUrl)265 TEST_F(SafeBrowsingProtocolManagerTest, TestNextChunkUrl) {
266 SafeBrowsingProtocolManager pm(NULL, kClient, kClientKey, kWrappedKey, NULL,
267 kInfoUrlPrefix, kMacKeyUrlPrefix, false);
268 pm.version_ = kAppVer;
269
270 std::string url_partial = "localhost:1234/foo/bar?foo";
271 std::string url_http_full = "http://localhost:1234/foo/bar?foo";
272 std::string url_https_full = "https://localhost:1234/foo/bar?foo";
273 std::string url_https_no_query = "https://localhost:1234/foo/bar";
274
275 EXPECT_EQ("http://localhost:1234/foo/bar?foo",
276 pm.NextChunkUrl(url_partial).spec());
277 EXPECT_EQ("http://localhost:1234/foo/bar?foo",
278 pm.NextChunkUrl(url_http_full).spec());
279 EXPECT_EQ("https://localhost:1234/foo/bar?foo",
280 pm.NextChunkUrl(url_https_full).spec());
281 EXPECT_EQ("https://localhost:1234/foo/bar",
282 pm.NextChunkUrl(url_https_no_query).spec());
283
284 pm.set_additional_query(kAdditionalQuery);
285 EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
286 pm.NextChunkUrl(url_partial).spec());
287 EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
288 pm.NextChunkUrl(url_http_full).spec());
289 EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
290 pm.NextChunkUrl(url_https_full).spec());
291 EXPECT_EQ("https://localhost:1234/foo/bar?additional_query",
292 pm.NextChunkUrl(url_https_no_query).spec());
293 }
294