/src/mozilla-central/toolkit/components/url-classifier/tests/gtest/TestFindFullHash.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "safebrowsing.pb.h" |
2 | | #include "gtest/gtest.h" |
3 | | #include "nsUrlClassifierUtils.h" |
4 | | #include "mozilla/Base64.h" |
5 | | |
6 | | using namespace mozilla; |
7 | | using namespace mozilla::safebrowsing; |
8 | | |
9 | | namespace { |
10 | | |
11 | | // |Base64EncodedStringArray| and |MakeBase64EncodedStringArray| |
12 | | // works together to make us able to do things "literally" and easily. |
13 | | |
14 | | // Given a nsCString array, construct an object which can be implicitly |
15 | | // casted to |const char**|, where all owning c-style strings have been |
16 | | // base64 encoded. The memory life cycle of what the "cast operator" |
17 | | // returns is just as the object itself. |
18 | | class Base64EncodedStringArray |
19 | | { |
20 | | public: |
21 | | Base64EncodedStringArray(nsCString aArray[], size_t N); |
22 | 0 | operator const char** () const { return (const char**)&mArray[0]; } |
23 | | |
24 | | private: |
25 | | // Since we can't guarantee the layout of nsCString (can we?), |
26 | | // an additional nsTArray<nsCString> is required to manage the |
27 | | // allocated string. |
28 | | nsTArray<const char*> mArray; |
29 | | nsTArray<nsCString> mStringStorage; |
30 | | }; |
31 | | |
32 | | // Simply used to infer the fixed-array size automatically. |
33 | | template<size_t N> |
34 | | Base64EncodedStringArray |
35 | | MakeBase64EncodedStringArray(nsCString (&aArray)[N]) |
36 | 0 | { |
37 | 0 | return Base64EncodedStringArray(aArray, N); |
38 | 0 | } Unexecuted instantiation: Unified_cpp_tests_gtest0.cpp:(anonymous namespace)::Base64EncodedStringArray (anonymous namespace)::MakeBase64EncodedStringArray<2ul>(nsTString<char> (&) [2ul]) Unexecuted instantiation: Unified_cpp_tests_gtest0.cpp:(anonymous namespace)::Base64EncodedStringArray (anonymous namespace)::MakeBase64EncodedStringArray<5ul>(nsTString<char> (&) [5ul]) |
39 | | |
40 | | } // end of unnamed namespace. |
41 | | |
42 | | |
43 | | TEST(UrlClassifierFindFullHash, Request) |
44 | 0 | { |
45 | 0 | nsCOMPtr<nsIUrlClassifierUtils> urlUtil = |
46 | 0 | do_GetService("@mozilla.org/url-classifier/utils;1"); |
47 | 0 |
|
48 | 0 | const char* listNames[] = { "test-phish-proto", "test-unwanted-proto" }; |
49 | 0 |
|
50 | 0 | nsCString listStates[] = { nsCString("sta\x00te1", 7), |
51 | 0 | nsCString("sta\x00te2", 7) }; |
52 | 0 |
|
53 | 0 | nsCString prefixes[] = { nsCString("\x00\x00\x00\x01", 4), |
54 | 0 | nsCString("\x00\x00\x00\x00\x01", 5), |
55 | 0 | nsCString("\x00\xFF\x00\x01", 4), |
56 | 0 | nsCString("\x00\xFF\x00\x01\x11\x23\xAA\xBC", 8), |
57 | 0 | nsCString("\x00\x00\x00\x01\x00\x01\x98", 7) }; |
58 | 0 |
|
59 | 0 | nsCString requestBase64; |
60 | 0 | nsresult rv; |
61 | 0 | rv = urlUtil->MakeFindFullHashRequestV4(listNames, |
62 | 0 | MakeBase64EncodedStringArray(listStates), |
63 | 0 | MakeBase64EncodedStringArray(prefixes), |
64 | 0 | ArrayLength(listNames), |
65 | 0 | ArrayLength(prefixes), |
66 | 0 | requestBase64); |
67 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
68 | 0 |
|
69 | 0 | // Base64 URL decode first. |
70 | 0 | FallibleTArray<uint8_t> requestBinary; |
71 | 0 | rv = Base64URLDecode(requestBase64, |
72 | 0 | Base64URLDecodePaddingPolicy::Require, |
73 | 0 | requestBinary); |
74 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
75 | 0 |
|
76 | 0 | // Parse the FindFullHash binary and compare with the expected values. |
77 | 0 | FindFullHashesRequest r; |
78 | 0 | ASSERT_TRUE(r.ParseFromArray(&requestBinary[0], requestBinary.Length())); |
79 | 0 |
|
80 | 0 | // Compare client states. |
81 | 0 | ASSERT_EQ(r.client_states_size(), (int)ArrayLength(listStates)); |
82 | 0 | for(int i = 0; i < r.client_states_size(); i++) { |
83 | 0 | auto s = r.client_states(i); |
84 | 0 | ASSERT_TRUE(listStates[i].Equals(nsCString(s.c_str(), s.size()))); |
85 | 0 | } |
86 | 0 |
|
87 | 0 | auto threatInfo = r.threat_info(); |
88 | 0 |
|
89 | 0 | // Compare threat types. |
90 | 0 | ASSERT_EQ(threatInfo.threat_types_size(), (int)ArrayLength(listStates)); |
91 | 0 | for (int i = 0; i < threatInfo.threat_types_size(); i++) { |
92 | 0 | uint32_t expectedThreatType; |
93 | 0 | rv = urlUtil->ConvertListNameToThreatType(nsCString(listNames[i]), |
94 | 0 | &expectedThreatType); |
95 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
96 | 0 | ASSERT_EQ(threatInfo.threat_types(i), expectedThreatType); |
97 | 0 | } |
98 | 0 |
|
99 | 0 | // Compare prefixes. |
100 | 0 | ASSERT_EQ(threatInfo.threat_entries_size(), (int)ArrayLength(prefixes)); |
101 | 0 | for (int i = 0; i < threatInfo.threat_entries_size(); i++) { |
102 | 0 | auto p = threatInfo.threat_entries(i).hash(); |
103 | 0 | ASSERT_TRUE(prefixes[i].Equals(nsCString(p.c_str(), p.size()))); |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | ///////////////////////////////////////////////////////////// |
108 | | // Following is to test parsing the gethash response. |
109 | | |
110 | | namespace { |
111 | | |
112 | | // safebrowsing::Duration manipulation. |
113 | | struct MyDuration { |
114 | | uint32_t mSecs; |
115 | | uint32_t mNanos; |
116 | | }; |
117 | | void PopulateDuration(Duration& aDest, const MyDuration& aSrc) |
118 | 0 | { |
119 | 0 | aDest.set_seconds(aSrc.mSecs); |
120 | 0 | aDest.set_nanos(aSrc.mNanos); |
121 | 0 | } |
122 | | |
123 | | // The expected match data. |
124 | | static MyDuration EXPECTED_MIN_WAIT_DURATION = { 12, 10 }; |
125 | | static MyDuration EXPECTED_NEG_CACHE_DURATION = { 120, 9 }; |
126 | | static const struct ExpectedMatch { |
127 | | nsCString mCompleteHash; |
128 | | ThreatType mThreatType; |
129 | | MyDuration mPerHashCacheDuration; |
130 | | } EXPECTED_MATCH[] = { |
131 | | { nsCString("01234567890123456789012345678901"), SOCIAL_ENGINEERING_PUBLIC, { 8, 500 } }, |
132 | | { nsCString("12345678901234567890123456789012"), SOCIAL_ENGINEERING_PUBLIC, { 7, 100} }, |
133 | | { nsCString("23456789012345678901234567890123"), SOCIAL_ENGINEERING_PUBLIC, { 1, 20 } }, |
134 | | }; |
135 | | |
136 | | class MyParseCallback final : |
137 | | public nsIUrlClassifierParseFindFullHashCallback { |
138 | | public: |
139 | | NS_DECL_ISUPPORTS |
140 | | |
141 | | explicit MyParseCallback(uint32_t& aCallbackCount) |
142 | | : mCallbackCount(aCallbackCount) |
143 | 0 | { |
144 | 0 | } |
145 | | |
146 | | NS_IMETHOD |
147 | | OnCompleteHashFound(const nsACString& aCompleteHash, |
148 | | const nsACString& aTableNames, |
149 | | uint32_t aPerHashCacheDuration) override |
150 | 0 | { |
151 | 0 | Verify(aCompleteHash, |
152 | 0 | aTableNames, |
153 | 0 | aPerHashCacheDuration); |
154 | 0 |
|
155 | 0 | return NS_OK; |
156 | 0 | } |
157 | | |
158 | | NS_IMETHOD |
159 | | OnResponseParsed(uint32_t aMinWaitDuration, |
160 | | uint32_t aNegCacheDuration) override |
161 | 0 | { |
162 | 0 | VerifyDuration(aMinWaitDuration / 1000, EXPECTED_MIN_WAIT_DURATION); |
163 | 0 | VerifyDuration(aNegCacheDuration, EXPECTED_NEG_CACHE_DURATION); |
164 | 0 |
|
165 | 0 | return NS_OK; |
166 | 0 | } |
167 | | |
168 | | private: |
169 | | void |
170 | | Verify(const nsACString& aCompleteHash, |
171 | | const nsACString& aTableNames, |
172 | | uint32_t aPerHashCacheDuration) |
173 | 0 | { |
174 | 0 | auto expected = EXPECTED_MATCH[mCallbackCount]; |
175 | 0 |
|
176 | 0 | ASSERT_TRUE(aCompleteHash.Equals(expected.mCompleteHash)); |
177 | 0 |
|
178 | 0 | // Verify aTableNames |
179 | 0 | nsCOMPtr<nsIUrlClassifierUtils> urlUtil = |
180 | 0 | do_GetService("@mozilla.org/url-classifier/utils;1"); |
181 | 0 | nsCString tableNames; |
182 | 0 | nsresult rv = urlUtil->ConvertThreatTypeToListNames(expected.mThreatType, tableNames); |
183 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
184 | 0 | ASSERT_TRUE(aTableNames.Equals(tableNames)); |
185 | 0 |
|
186 | 0 | VerifyDuration(aPerHashCacheDuration, expected.mPerHashCacheDuration); |
187 | 0 |
|
188 | 0 | mCallbackCount++; |
189 | 0 | } |
190 | | |
191 | | void |
192 | | VerifyDuration(uint32_t aToVerify, const MyDuration& aExpected) |
193 | 0 | { |
194 | 0 | ASSERT_TRUE(aToVerify == aExpected.mSecs); |
195 | 0 | } |
196 | | |
197 | 0 | ~MyParseCallback() {} |
198 | | |
199 | | uint32_t& mCallbackCount; |
200 | | }; |
201 | | |
202 | | NS_IMPL_ISUPPORTS(MyParseCallback, nsIUrlClassifierParseFindFullHashCallback) |
203 | | |
204 | | } // end of unnamed namespace. |
205 | | |
206 | | TEST(UrlClassifierFindFullHash, ParseRequest) |
207 | 0 | { |
208 | 0 | // Build response. |
209 | 0 | FindFullHashesResponse r; |
210 | 0 |
|
211 | 0 | // Init response-wise durations. |
212 | 0 | auto minWaitDuration = r.mutable_minimum_wait_duration(); |
213 | 0 | PopulateDuration(*minWaitDuration, EXPECTED_MIN_WAIT_DURATION); |
214 | 0 | auto negCacheDuration = r.mutable_negative_cache_duration(); |
215 | 0 | PopulateDuration(*negCacheDuration, EXPECTED_NEG_CACHE_DURATION); |
216 | 0 |
|
217 | 0 | // Init matches. |
218 | 0 | for (uint32_t i = 0; i < ArrayLength(EXPECTED_MATCH); i++) { |
219 | 0 | auto expected = EXPECTED_MATCH[i]; |
220 | 0 | auto match = r.mutable_matches()->Add(); |
221 | 0 | match->set_threat_type(expected.mThreatType); |
222 | 0 | match->mutable_threat()->set_hash(expected.mCompleteHash.BeginReading(), |
223 | 0 | expected.mCompleteHash.Length()); |
224 | 0 | auto perHashCacheDuration = match->mutable_cache_duration(); |
225 | 0 | PopulateDuration(*perHashCacheDuration, expected.mPerHashCacheDuration); |
226 | 0 | } |
227 | 0 | std::string s; |
228 | 0 | r.SerializeToString(&s); |
229 | 0 |
|
230 | 0 | uint32_t callbackCount = 0; |
231 | 0 | nsCOMPtr<nsIUrlClassifierParseFindFullHashCallback> callback |
232 | 0 | = new MyParseCallback(callbackCount); |
233 | 0 |
|
234 | 0 | nsCOMPtr<nsIUrlClassifierUtils> urlUtil = |
235 | 0 | do_GetService("@mozilla.org/url-classifier/utils;1"); |
236 | 0 | nsresult rv = urlUtil->ParseFindFullHashResponseV4(nsCString(s.c_str(), s.size()), |
237 | 0 | callback); |
238 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
239 | 0 |
|
240 | 0 | ASSERT_EQ(callbackCount, ArrayLength(EXPECTED_MATCH)); |
241 | 0 | } |
242 | | |
243 | | |
244 | | ///////////////////////////////////////////////////////////// |
245 | | namespace { |
246 | | |
247 | | Base64EncodedStringArray::Base64EncodedStringArray(nsCString aArray[], |
248 | | size_t N) |
249 | 0 | { |
250 | 0 | for (size_t i = 0; i < N; i++) { |
251 | 0 | nsCString encoded; |
252 | 0 | nsresult rv = Base64Encode(aArray[i], encoded); |
253 | 0 | NS_ENSURE_SUCCESS_VOID(rv); |
254 | 0 | mStringStorage.AppendElement(encoded); |
255 | 0 | mArray.AppendElement(encoded.get()); |
256 | 0 | } |
257 | 0 | } |
258 | | |
259 | | } |