1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "nsPermission.h"
7 #include "nsContentUtils.h"
8 #include "nsIClassInfoImpl.h"
9 #include "nsIEffectiveTLDService.h"
10 #include "mozilla/BasePrincipal.h"
11 
12 // nsPermission Implementation
13 
14 NS_IMPL_CLASSINFO(nsPermission, nullptr, 0, {0})
NS_IMPL_ISUPPORTS_CI(nsPermission,nsIPermission)15 NS_IMPL_ISUPPORTS_CI(nsPermission, nsIPermission)
16 
17 nsPermission::nsPermission(nsIPrincipal* aPrincipal, const nsACString& aType,
18                            uint32_t aCapability, uint32_t aExpireType,
19                            int64_t aExpireTime)
20     : mPrincipal(aPrincipal),
21       mType(aType),
22       mCapability(aCapability),
23       mExpireType(aExpireType),
24       mExpireTime(aExpireTime) {}
25 
Create(nsIPrincipal * aPrincipal,const nsACString & aType,uint32_t aCapability,uint32_t aExpireType,int64_t aExpireTime)26 already_AddRefed<nsPermission> nsPermission::Create(nsIPrincipal* aPrincipal,
27                                                     const nsACString& aType,
28                                                     uint32_t aCapability,
29                                                     uint32_t aExpireType,
30                                                     int64_t aExpireTime) {
31   NS_ENSURE_TRUE(aPrincipal, nullptr);
32   nsCOMPtr<nsIPrincipal> principal =
33       mozilla::BasePrincipal::Cast(aPrincipal)
34           ->CloneStrippingUserContextIdAndFirstPartyDomain();
35 
36   NS_ENSURE_TRUE(principal, nullptr);
37 
38   RefPtr<nsPermission> permission =
39       new nsPermission(principal, aType, aCapability, aExpireType, aExpireTime);
40   return permission.forget();
41 }
42 
43 NS_IMETHODIMP
GetPrincipal(nsIPrincipal ** aPrincipal)44 nsPermission::GetPrincipal(nsIPrincipal** aPrincipal) {
45   nsCOMPtr<nsIPrincipal> copy = mPrincipal;
46   copy.forget(aPrincipal);
47   return NS_OK;
48 }
49 
50 NS_IMETHODIMP
GetType(nsACString & aType)51 nsPermission::GetType(nsACString& aType) {
52   aType = mType;
53   return NS_OK;
54 }
55 
56 NS_IMETHODIMP
GetCapability(uint32_t * aCapability)57 nsPermission::GetCapability(uint32_t* aCapability) {
58   *aCapability = mCapability;
59   return NS_OK;
60 }
61 
62 NS_IMETHODIMP
GetExpireType(uint32_t * aExpireType)63 nsPermission::GetExpireType(uint32_t* aExpireType) {
64   *aExpireType = mExpireType;
65   return NS_OK;
66 }
67 
68 NS_IMETHODIMP
GetExpireTime(int64_t * aExpireTime)69 nsPermission::GetExpireTime(int64_t* aExpireTime) {
70   *aExpireTime = mExpireTime;
71   return NS_OK;
72 }
73 
74 NS_IMETHODIMP
Matches(nsIPrincipal * aPrincipal,bool aExactHost,bool * aMatches)75 nsPermission::Matches(nsIPrincipal* aPrincipal, bool aExactHost,
76                       bool* aMatches) {
77   NS_ENSURE_ARG_POINTER(aPrincipal);
78   NS_ENSURE_ARG_POINTER(aMatches);
79 
80   *aMatches = false;
81 
82   nsCOMPtr<nsIPrincipal> principal =
83       mozilla::BasePrincipal::Cast(aPrincipal)
84           ->CloneStrippingUserContextIdAndFirstPartyDomain();
85 
86   if (!principal) {
87     *aMatches = false;
88     return NS_OK;
89   }
90 
91   // If the principals are equal, then they match.
92   if (mPrincipal->Equals(principal)) {
93     *aMatches = true;
94     return NS_OK;
95   }
96 
97   // If we are matching with an exact host, we're done now - the permissions
98   // don't match otherwise, we need to start comparing subdomains!
99   if (aExactHost) {
100     return NS_OK;
101   }
102 
103   // Compare their OriginAttributes
104   const mozilla::OriginAttributes& theirAttrs =
105       principal->OriginAttributesRef();
106   const mozilla::OriginAttributes& ourAttrs = mPrincipal->OriginAttributesRef();
107 
108   if (theirAttrs != ourAttrs) {
109     return NS_OK;
110   }
111 
112   nsCOMPtr<nsIURI> theirURI;
113   nsresult rv = principal->GetURI(getter_AddRefs(theirURI));
114   NS_ENSURE_SUCCESS(rv, rv);
115 
116   nsCOMPtr<nsIURI> ourURI;
117   rv = mPrincipal->GetURI(getter_AddRefs(ourURI));
118   NS_ENSURE_SUCCESS(rv, rv);
119 
120   // Compare schemes
121   nsAutoCString theirScheme;
122   rv = theirURI->GetScheme(theirScheme);
123   NS_ENSURE_SUCCESS(rv, rv);
124 
125   nsAutoCString ourScheme;
126   rv = ourURI->GetScheme(ourScheme);
127   NS_ENSURE_SUCCESS(rv, rv);
128 
129   if (theirScheme != ourScheme) {
130     return NS_OK;
131   }
132 
133   // Compare ports
134   int32_t theirPort;
135   rv = theirURI->GetPort(&theirPort);
136   NS_ENSURE_SUCCESS(rv, rv);
137 
138   int32_t ourPort;
139   rv = ourURI->GetPort(&ourPort);
140   NS_ENSURE_SUCCESS(rv, rv);
141 
142   if (theirPort != ourPort) {
143     return NS_OK;
144   }
145 
146   // Check if the host or any subdomain of their host matches.
147   nsAutoCString theirHost;
148   rv = theirURI->GetHost(theirHost);
149   if (NS_FAILED(rv) || theirHost.IsEmpty()) {
150     return NS_OK;
151   }
152 
153   nsAutoCString ourHost;
154   rv = ourURI->GetHost(ourHost);
155   if (NS_FAILED(rv) || ourHost.IsEmpty()) {
156     return NS_OK;
157   }
158 
159   nsCOMPtr<nsIEffectiveTLDService> tldService =
160       do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
161   if (!tldService) {
162     NS_ERROR("Should have a tld service!");
163     return NS_ERROR_FAILURE;
164   }
165 
166   // This loop will not loop forever, as GetNextSubDomain will eventually fail
167   // with NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS.
168   while (theirHost != ourHost) {
169     rv = tldService->GetNextSubDomain(theirHost, theirHost);
170     if (NS_FAILED(rv)) {
171       if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
172         return NS_OK;
173       } else {
174         return rv;
175       }
176     }
177   }
178 
179   *aMatches = true;
180   return NS_OK;
181 }
182 
183 NS_IMETHODIMP
MatchesURI(nsIURI * aURI,bool aExactHost,bool * aMatches)184 nsPermission::MatchesURI(nsIURI* aURI, bool aExactHost, bool* aMatches) {
185   NS_ENSURE_ARG_POINTER(aURI);
186 
187   mozilla::OriginAttributes attrs;
188   nsCOMPtr<nsIPrincipal> principal =
189       mozilla::BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
190   NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
191 
192   return Matches(principal, aExactHost, aMatches);
193 }
194