Coverage Report

Created: 2018-09-25 14:53

/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
}