Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/caps/OriginAttributes.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=2 sw=2 et tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/OriginAttributes.h"
8
#include "mozilla/Preferences.h"
9
#include "mozilla/dom/BlobURLProtocolHandler.h"
10
#include "mozilla/dom/URLSearchParams.h"
11
#include "mozilla/dom/quota/QuotaManager.h"
12
#include "nsIEffectiveTLDService.h"
13
#include "nsIURI.h"
14
#include "nsURLHelper.h"
15
16
namespace mozilla {
17
18
using dom::URLParams;
19
20
bool OriginAttributes::sFirstPartyIsolation = false;
21
bool OriginAttributes::sRestrictedOpenerAccess = false;
22
23
void
24
OriginAttributes::InitPrefs()
25
3
{
26
3
  MOZ_ASSERT(NS_IsMainThread());
27
3
  static bool sInited = false;
28
3
  if (!sInited) {
29
3
    sInited = true;
30
3
    Preferences::AddBoolVarCache(&sFirstPartyIsolation,
31
3
                                 "privacy.firstparty.isolate");
32
3
    Preferences::AddBoolVarCache(&sRestrictedOpenerAccess,
33
3
                                 "privacy.firstparty.isolate.restrict_opener_access");
34
3
  }
35
3
}
36
37
void
38
OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
39
                                      nsIURI* aURI)
40
0
{
41
0
  bool isFirstPartyEnabled = IsFirstPartyEnabled();
42
0
43
0
  // If the pref is off or this is not a top level load, bail out.
44
0
  if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
45
0
    return;
46
0
  }
47
0
48
0
  nsCOMPtr<nsIEffectiveTLDService> tldService =
49
0
    do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
50
0
  MOZ_ASSERT(tldService);
51
0
  if (!tldService) {
52
0
    return;
53
0
  }
54
0
55
0
  nsAutoCString baseDomain;
56
0
  nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain);
57
0
  if (NS_SUCCEEDED(rv)) {
58
0
    mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain);
59
0
    return;
60
0
  }
61
0
62
0
  if (rv == NS_ERROR_HOST_IS_IP_ADDRESS) {
63
0
    // If the host is an IPv4/IPv6 address, we still accept it as a
64
0
    // valid firstPartyDomain.
65
0
    nsAutoCString ipAddr;
66
0
    rv = aURI->GetHost(ipAddr);
67
0
    NS_ENSURE_SUCCESS_VOID(rv);
68
0
69
0
    if (net_IsValidIPv6Addr(ipAddr.BeginReading(), ipAddr.Length())) {
70
0
      // According to RFC2732, the host of an IPv6 address should be an
71
0
      // IPv6reference. The GetHost() of nsIURI will only return the IPv6
72
0
      // address. So, we need to convert it back to IPv6reference here.
73
0
      mFirstPartyDomain.Truncate();
74
0
      mFirstPartyDomain.AssignLiteral("[");
75
0
      mFirstPartyDomain.Append(NS_ConvertUTF8toUTF16(ipAddr));
76
0
      mFirstPartyDomain.AppendLiteral("]");
77
0
    } else {
78
0
      mFirstPartyDomain = NS_ConvertUTF8toUTF16(ipAddr);
79
0
    }
80
0
81
0
    return;
82
0
  }
83
0
84
0
  nsAutoCString scheme;
85
0
  rv = aURI->GetScheme(scheme);
86
0
  NS_ENSURE_SUCCESS_VOID(rv);
87
0
  if (scheme.EqualsLiteral("about")) {
88
0
    mFirstPartyDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN);
89
0
    return;
90
0
  }
91
0
92
0
  nsCOMPtr<nsIPrincipal> blobPrincipal;
93
0
  if (dom::BlobURLProtocolHandler::GetBlobURLPrincipal(aURI,
94
0
                                                       getter_AddRefs(blobPrincipal))) {
95
0
    MOZ_ASSERT(blobPrincipal);
96
0
    mFirstPartyDomain = blobPrincipal->OriginAttributesRef().mFirstPartyDomain;
97
0
    return;
98
0
  }
99
0
}
100
101
void
102
OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument,
103
                                      const nsACString& aDomain)
104
0
{
105
0
  bool isFirstPartyEnabled = IsFirstPartyEnabled();
106
0
107
0
  // If the pref is off or this is not a top level load, bail out.
108
0
  if (!isFirstPartyEnabled || !aIsTopLevelDocument) {
109
0
    return;
110
0
  }
111
0
112
0
  mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain);
113
0
}
114
115
void
116
OriginAttributes::CreateSuffix(nsACString& aStr) const
117
5.78k
{
118
5.78k
  URLParams params;
119
5.78k
  nsAutoString value;
120
5.78k
121
5.78k
  //
122
5.78k
  // Important: While serializing any string-valued attributes, perform a
123
5.78k
  // release-mode assertion to make sure that they don't contain characters that
124
5.78k
  // will break the quota manager when it uses the serialization for file
125
5.78k
  // naming.
126
5.78k
  //
127
5.78k
128
5.78k
  if (mAppId != nsIScriptSecurityManager::NO_APP_ID) {
129
0
    value.AppendInt(mAppId);
130
0
    params.Set(NS_LITERAL_STRING("appId"), value);
131
0
  }
132
5.78k
133
5.78k
  if (mInIsolatedMozBrowser) {
134
0
    params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1"));
135
0
  }
136
5.78k
137
5.78k
  if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
138
0
    value.Truncate();
139
0
    value.AppendInt(mUserContextId);
140
0
    params.Set(NS_LITERAL_STRING("userContextId"), value);
141
0
  }
142
5.78k
143
5.78k
144
5.78k
  if (mPrivateBrowsingId) {
145
0
    value.Truncate();
146
0
    value.AppendInt(mPrivateBrowsingId);
147
0
    params.Set(NS_LITERAL_STRING("privateBrowsingId"), value);
148
0
  }
149
5.78k
150
5.78k
  if (!mFirstPartyDomain.IsEmpty()) {
151
0
    nsAutoString sanitizedFirstPartyDomain(mFirstPartyDomain);
152
0
    sanitizedFirstPartyDomain.ReplaceChar(dom::quota::QuotaManager::kReplaceChars, '+');
153
0
154
0
    params.Set(NS_LITERAL_STRING("firstPartyDomain"), sanitizedFirstPartyDomain);
155
0
  }
156
5.78k
157
5.78k
  aStr.Truncate();
158
5.78k
159
5.78k
  params.Serialize(value);
160
5.78k
  if (!value.IsEmpty()) {
161
0
    aStr.AppendLiteral("^");
162
0
    aStr.Append(NS_ConvertUTF16toUTF8(value));
163
0
  }
164
5.78k
165
5.78k
// In debug builds, check the whole string for illegal characters too (just in case).
166
#ifdef DEBUG
167
  nsAutoCString str;
168
  str.Assign(aStr);
169
  MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound);
170
#endif
171
}
172
173
void
174
OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const
175
0
{
176
0
  OriginAttributes attrs = *this;
177
0
178
0
  if (!attrs.mFirstPartyDomain.IsEmpty()) {
179
0
    attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_");
180
0
  }
181
0
182
0
  attrs.CreateSuffix(aStr);
183
0
}
184
185
namespace {
186
187
class MOZ_STACK_CLASS PopulateFromSuffixIterator final
188
  : public URLParams::ForEachIterator
189
{
190
public:
191
  explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes)
192
    : mOriginAttributes(aOriginAttributes)
193
0
  {
194
0
    MOZ_ASSERT(aOriginAttributes);
195
0
    // If mPrivateBrowsingId is passed in as >0 and is not present in the suffix,
196
0
    // then it will remain >0 when it should be 0 according to the suffix. Set to 0 before
197
0
    // iterating to fix this.
198
0
    mOriginAttributes->mPrivateBrowsingId = 0;
199
0
  }
200
201
  bool URLParamsIterator(const nsAString& aName,
202
                         const nsAString& aValue) override
203
0
  {
204
0
    if (aName.EqualsLiteral("appId")) {
205
0
      nsresult rv;
206
0
      int64_t val  = aValue.ToInteger64(&rv);
207
0
      NS_ENSURE_SUCCESS(rv, false);
208
0
      NS_ENSURE_TRUE(val <= UINT32_MAX, false);
209
0
      mOriginAttributes->mAppId = static_cast<uint32_t>(val);
210
0
211
0
      return true;
212
0
    }
213
0
214
0
    if (aName.EqualsLiteral("inBrowser")) {
215
0
      if (!aValue.EqualsLiteral("1")) {
216
0
        return false;
217
0
      }
218
0
219
0
      mOriginAttributes->mInIsolatedMozBrowser = true;
220
0
      return true;
221
0
    }
222
0
223
0
    if (aName.EqualsLiteral("addonId")) {
224
0
      // No longer supported. Silently ignore so that legacy origin strings
225
0
      // don't cause failures.
226
0
      return true;
227
0
    }
228
0
229
0
    if (aName.EqualsLiteral("userContextId")) {
230
0
      nsresult rv;
231
0
      int64_t val  = aValue.ToInteger64(&rv);
232
0
      NS_ENSURE_SUCCESS(rv, false);
233
0
      NS_ENSURE_TRUE(val <= UINT32_MAX, false);
234
0
      mOriginAttributes->mUserContextId  = static_cast<uint32_t>(val);
235
0
236
0
      return true;
237
0
    }
238
0
239
0
    if (aName.EqualsLiteral("privateBrowsingId")) {
240
0
      nsresult rv;
241
0
      int64_t val = aValue.ToInteger64(&rv);
242
0
      NS_ENSURE_SUCCESS(rv, false);
243
0
      NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false);
244
0
      mOriginAttributes->mPrivateBrowsingId = static_cast<uint32_t>(val);
245
0
246
0
      return true;
247
0
    }
248
0
249
0
    if (aName.EqualsLiteral("firstPartyDomain")) {
250
0
      MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty());
251
0
      mOriginAttributes->mFirstPartyDomain.Assign(aValue);
252
0
      return true;
253
0
    }
254
0
255
0
    // No other attributes are supported.
256
0
    return false;
257
0
  }
258
259
private:
260
  OriginAttributes* mOriginAttributes;
261
};
262
263
} // namespace
264
265
bool
266
OriginAttributes::PopulateFromSuffix(const nsACString& aStr)
267
0
{
268
0
  if (aStr.IsEmpty()) {
269
0
    return true;
270
0
  }
271
0
272
0
  if (aStr[0] != '^') {
273
0
    return false;
274
0
  }
275
0
276
0
  PopulateFromSuffixIterator iterator(this);
277
0
  return URLParams::Parse(Substring(aStr, 1, aStr.Length() - 1), iterator);
278
0
}
279
280
bool
281
OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin,
282
                                     nsACString& aOriginNoSuffix)
283
0
{
284
0
  // RFindChar is only available on nsCString.
285
0
  nsCString origin(aOrigin);
286
0
  int32_t pos = origin.RFindChar('^');
287
0
288
0
  if (pos == kNotFound) {
289
0
    aOriginNoSuffix = origin;
290
0
    return true;
291
0
  }
292
0
293
0
  aOriginNoSuffix = Substring(origin, 0, pos);
294
0
  return PopulateFromSuffix(Substring(origin, pos));
295
0
}
296
297
void
298
OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing)
299
0
{
300
0
  mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0;
301
0
}
302
303
/* static */
304
bool
305
OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin)
306
0
{
307
0
  nsAutoCString dummy;
308
0
  OriginAttributes attrs;
309
0
  if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) {
310
0
    return false;
311
0
  }
312
0
313
0
  return !!attrs.mPrivateBrowsingId;
314
0
}
315
316
} // namespace mozilla