Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/extensions/cookie/nsCookiePermission.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: */
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 "nsCookiePermission.h"
8
9
#include "mozIThirdPartyUtil.h"
10
#include "nsICookie2.h"
11
#include "nsIServiceManager.h"
12
#include "nsICookieManager.h"
13
#include "nsNetUtil.h"
14
#include "nsIInterfaceRequestorUtils.h"
15
#include "nsIProtocolHandler.h"
16
#include "nsIURI.h"
17
#include "nsIPrefService.h"
18
#include "nsIPrefBranch.h"
19
#include "nsIChannel.h"
20
#include "nsIHttpChannelInternal.h"
21
#include "nsIDOMWindow.h"
22
#include "nsIPrincipal.h"
23
#include "nsString.h"
24
#include "nsCRT.h"
25
#include "nsILoadContext.h"
26
#include "nsIScriptObjectPrincipal.h"
27
#include "nsNetCID.h"
28
#include "prtime.h"
29
#include "mozilla/StaticPtr.h"
30
31
/****************************************************************
32
 ************************ nsCookiePermission ********************
33
 ****************************************************************/
34
35
// values for mCookiesLifetimePolicy
36
// 0 == accept normally
37
// 1 == ask before accepting, no more supported, treated like ACCEPT_NORMALLY (Bug 606655).
38
// 2 == downgrade to session
39
// 3 == limit lifetime to N days
40
static const uint32_t ACCEPT_NORMALLY = 0;
41
static const uint32_t ACCEPT_SESSION = 2;
42
43
static const bool kDefaultPolicy = true;
44
static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
45
46
static const char kPermissionType[] = "cookie";
47
48
namespace {
49
mozilla::StaticRefPtr<nsCookiePermission> gSingleton;
50
}
51
52
NS_IMPL_ISUPPORTS(nsCookiePermission,
53
                  nsICookiePermission,
54
                  nsIObserver)
55
56
// static
57
already_AddRefed<nsICookiePermission>
58
nsCookiePermission::GetOrCreate()
59
0
{
60
0
  if (!gSingleton) {
61
0
    gSingleton = new nsCookiePermission();
62
0
  }
63
0
  return do_AddRef(gSingleton);
64
0
}
65
66
// static
67
void
68
nsCookiePermission::Shutdown()
69
0
{
70
0
  gSingleton = nullptr;
71
0
}
72
73
bool
74
nsCookiePermission::Init()
75
0
{
76
0
  // Initialize nsIPermissionManager and fetch relevant prefs. This is only
77
0
  // required for some methods on nsICookiePermission, so it should be done
78
0
  // lazily.
79
0
  nsresult rv;
80
0
  mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
81
0
  if (NS_FAILED(rv)) return false;
82
0
  mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
83
0
  if (NS_FAILED(rv)) return false;
84
0
85
0
  // failure to access the pref service is non-fatal...
86
0
  nsCOMPtr<nsIPrefBranch> prefBranch =
87
0
      do_GetService(NS_PREFSERVICE_CONTRACTID);
88
0
  if (prefBranch) {
89
0
    prefBranch->AddObserver(kCookiesLifetimePolicy, this, false);
90
0
    PrefChanged(prefBranch, nullptr);
91
0
  }
92
0
93
0
  return true;
94
0
}
95
96
void
97
nsCookiePermission::PrefChanged(nsIPrefBranch *aPrefBranch,
98
                                const char    *aPref)
99
0
{
100
0
  int32_t val;
101
0
102
0
#define PREF_CHANGED(_P) (!aPref || !strcmp(aPref, _P))
103
0
104
0
  if (PREF_CHANGED(kCookiesLifetimePolicy) &&
105
0
      NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookiesLifetimePolicy, &val))) {
106
0
    if (val != static_cast<int32_t>(ACCEPT_SESSION)) {
107
0
      val = ACCEPT_NORMALLY;
108
0
    }
109
0
    mCookiesLifetimePolicy = val;
110
0
  }
111
0
}
112
113
NS_IMETHODIMP
114
nsCookiePermission::SetAccess(nsIURI         *aURI,
115
                              nsCookieAccess  aAccess)
116
0
{
117
0
  // Lazily initialize ourselves
118
0
  if (!EnsureInitialized())
119
0
    return NS_ERROR_UNEXPECTED;
120
0
121
0
  //
122
0
  // NOTE: nsCookieAccess values conveniently match up with
123
0
  //       the permission codes used by nsIPermissionManager.
124
0
  //       this is nice because it avoids conversion code.
125
0
  //
126
0
  return mPermMgr->Add(aURI, kPermissionType, aAccess,
127
0
                       nsIPermissionManager::EXPIRE_NEVER, 0);
128
0
}
129
130
NS_IMETHODIMP
131
nsCookiePermission::CanAccess(nsIPrincipal   *aPrincipal,
132
                              nsCookieAccess *aResult)
133
0
{
134
0
  // Check this protocol doesn't allow cookies
135
0
  bool hasFlags;
136
0
  nsCOMPtr<nsIURI> uri;
137
0
  aPrincipal->GetURI(getter_AddRefs(uri));
138
0
  nsresult rv =
139
0
    NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_FORBIDS_COOKIE_ACCESS,
140
0
                        &hasFlags);
141
0
  if (NS_FAILED(rv) || hasFlags) {
142
0
    *aResult = ACCESS_DENY;
143
0
    return NS_OK;
144
0
  }
145
0
146
0
  // Lazily initialize ourselves
147
0
  if (!EnsureInitialized())
148
0
    return NS_ERROR_UNEXPECTED;
149
0
150
0
  // finally, check with permission manager...
151
0
  rv = mPermMgr->TestPermissionFromPrincipal(aPrincipal, kPermissionType, (uint32_t *) aResult);
152
0
  if (NS_SUCCEEDED(rv)) {
153
0
    if (*aResult == nsICookiePermission::ACCESS_SESSION) {
154
0
      *aResult = nsICookiePermission::ACCESS_ALLOW;
155
0
    }
156
0
  }
157
0
158
0
  return rv;
159
0
}
160
161
NS_IMETHODIMP
162
nsCookiePermission::CanSetCookie(nsIURI     *aURI,
163
                                 nsIChannel *aChannel,
164
                                 nsICookie2 *aCookie,
165
                                 bool       *aIsSession,
166
                                 int64_t    *aExpiry,
167
                                 bool       *aResult)
168
0
{
169
0
  NS_ASSERTION(aURI, "null uri");
170
0
171
0
  *aResult = kDefaultPolicy;
172
0
173
0
  // Lazily initialize ourselves
174
0
  if (!EnsureInitialized())
175
0
    return NS_ERROR_UNEXPECTED;
176
0
177
0
  uint32_t perm;
178
0
  mPermMgr->TestPermission(aURI, kPermissionType, &perm);
179
0
  bool isThirdParty = false;
180
0
  switch (perm) {
181
0
  case nsICookiePermission::ACCESS_SESSION:
182
0
    *aIsSession = true;
183
0
    MOZ_FALLTHROUGH;
184
0
185
0
  case nsICookiePermission::ACCESS_ALLOW:
186
0
    *aResult = true;
187
0
    break;
188
0
189
0
  case nsICookiePermission::ACCESS_DENY:
190
0
    *aResult = false;
191
0
    break;
192
0
193
0
  case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY:
194
0
    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &isThirdParty);
195
0
    // If it's third party, we can't set the cookie
196
0
    if (isThirdParty)
197
0
      *aResult = false;
198
0
    break;
199
0
200
0
  case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY:
201
0
    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aURI, &isThirdParty);
202
0
    // If it's third party, check whether cookies are already set
203
0
    if (isThirdParty) {
204
0
      nsresult rv;
205
0
      nsCOMPtr<nsICookieManager> cookieManager = do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv);
206
0
      if (NS_FAILED(rv)) {
207
0
        *aResult = false;
208
0
        break;
209
0
      }
210
0
      uint32_t priorCookieCount = 0;
211
0
      nsAutoCString hostFromURI;
212
0
      aURI->GetHost(hostFromURI);
213
0
      cookieManager->CountCookiesFromHost(hostFromURI, &priorCookieCount);
214
0
      *aResult = priorCookieCount != 0;
215
0
    }
216
0
    break;
217
0
218
0
  default:
219
0
    // the permission manager has nothing to say about this cookie -
220
0
    // so, we apply the default prefs to it.
221
0
    NS_ASSERTION(perm == nsIPermissionManager::UNKNOWN_ACTION, "unknown permission");
222
0
223
0
    // now we need to figure out what type of accept policy we're dealing with
224
0
    // if we accept cookies normally, just bail and return
225
0
    if (mCookiesLifetimePolicy == ACCEPT_NORMALLY) {
226
0
      *aResult = true;
227
0
      return NS_OK;
228
0
    }
229
0
230
0
    // declare this here since it'll be used in all of the remaining cases
231
0
    int64_t currentTime = PR_Now() / PR_USEC_PER_SEC;
232
0
    int64_t delta = *aExpiry - currentTime;
233
0
234
0
    // We are accepting the cookie, but,
235
0
    // if it's not a session cookie, we may have to limit its lifetime.
236
0
    if (!*aIsSession && delta > 0) {
237
0
      if (mCookiesLifetimePolicy == ACCEPT_SESSION) {
238
0
        // limit lifetime to session
239
0
        *aIsSession = true;
240
0
      }
241
0
    }
242
0
  }
243
0
244
0
  return NS_OK;
245
0
}
246
247
NS_IMETHODIMP
248
nsCookiePermission::Observe(nsISupports     *aSubject,
249
                            const char      *aTopic,
250
                            const char16_t *aData)
251
0
{
252
0
  nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
253
0
  NS_ASSERTION(!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic),
254
0
               "unexpected topic - we only deal with pref changes!");
255
0
256
0
  if (prefBranch)
257
0
    PrefChanged(prefBranch, NS_LossyConvertUTF16toASCII(aData).get());
258
0
  return NS_OK;
259
0
}