1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/quota/PrincipalUtils.h"
9 #include "mozilla/SystemPrincipal.h"
10 #include "mozilla/dom/quota/Constants.h"
11 #include "mozilla/dom/quota/CommonMetadata.h"
12 #include "mozilla/dom/quota/QuotaCommon.h"
13 #include "mozilla/dom/quota/QuotaManager.h"
14 #include "mozilla/dom/quota/ResultExtensions.h"
15 #include "mozilla/ipc/PBackgroundSharedTypes.h"
16 #include "nsIScriptObjectPrincipal.h"
17 #include "nsNetUtil.h"
18 #include "nsPIDOMWindow.h"
19 #include "OriginParser.h"
21 namespace mozilla::dom::quota
{
23 using namespace mozilla::ipc
;
25 bool IsPrincipalInfoValid(const PrincipalInfo
& aPrincipalInfo
) {
26 switch (aPrincipalInfo
.type()) {
27 // A system principal is acceptable.
28 case PrincipalInfo::TSystemPrincipalInfo
: {
32 // Validate content principals to ensure that the spec, originNoSuffix and
33 // baseDomain are sane.
34 case PrincipalInfo::TContentPrincipalInfo
: {
35 const ContentPrincipalInfo
& info
=
36 aPrincipalInfo
.get_ContentPrincipalInfo();
38 // Verify the principal spec parses.
40 QM_TRY(MOZ_TO_RESULT(NS_NewURI(getter_AddRefs(uri
), info
.spec())), false);
42 nsCOMPtr
<nsIPrincipal
> principal
=
43 BasePrincipal::CreateContentPrincipal(uri
, info
.attrs());
44 QM_TRY(MOZ_TO_RESULT(principal
), false);
46 // Verify the principal originNoSuffix matches spec.
47 QM_TRY_INSPECT(const auto& originNoSuffix
,
48 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoCString
, principal
,
52 if (NS_WARN_IF(originNoSuffix
!= info
.originNoSuffix())) {
53 QM_WARNING("originNoSuffix (%s) doesn't match passed one (%s)!",
54 originNoSuffix
.get(), info
.originNoSuffix().get());
58 if (NS_WARN_IF(info
.originNoSuffix().EqualsLiteral(kChromeOrigin
))) {
62 if (NS_WARN_IF(info
.originNoSuffix().FindChar('^', 0) != -1)) {
63 QM_WARNING("originNoSuffix (%s) contains the '^' character!",
64 info
.originNoSuffix().get());
68 // Verify the principal baseDomain exists.
69 if (NS_WARN_IF(info
.baseDomain().IsVoid())) {
73 // Verify the principal baseDomain matches spec.
74 QM_TRY_INSPECT(const auto& baseDomain
,
75 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoCString
, principal
,
79 if (NS_WARN_IF(baseDomain
!= info
.baseDomain())) {
80 QM_WARNING("baseDomain (%s) doesn't match passed one (%s)!",
81 baseDomain
.get(), info
.baseDomain().get());
93 // Null and expanded principals are not acceptable.
97 Result
<PrincipalMetadata
, nsresult
> GetInfoFromValidatedPrincipalInfo(
98 QuotaManager
& aQuotaManager
, const PrincipalInfo
& aPrincipalInfo
) {
99 MOZ_ASSERT(IsPrincipalInfoValid(aPrincipalInfo
));
101 switch (aPrincipalInfo
.type()) {
102 case PrincipalInfo::TSystemPrincipalInfo
: {
103 return GetInfoForChrome();
106 case PrincipalInfo::TContentPrincipalInfo
: {
107 const ContentPrincipalInfo
& info
=
108 aPrincipalInfo
.get_ContentPrincipalInfo();
111 info
.attrs().CreateSuffix(suffix
);
113 nsCString origin
= info
.originNoSuffix() + suffix
;
115 if (IsUUIDOrigin(origin
)) {
116 QM_TRY_INSPECT(const auto& originalOrigin
,
117 aQuotaManager
.GetOriginFromStorageOrigin(origin
));
119 nsCOMPtr
<nsIPrincipal
> principal
=
120 BasePrincipal::CreateContentPrincipal(originalOrigin
);
121 QM_TRY(MOZ_TO_RESULT(principal
));
123 PrincipalInfo principalInfo
;
125 MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal
, &principalInfo
)));
127 return GetInfoFromValidatedPrincipalInfo(aQuotaManager
, principalInfo
);
130 PrincipalMetadata principalMetadata
;
132 principalMetadata
.mSuffix
= suffix
;
134 principalMetadata
.mGroup
= info
.baseDomain() + suffix
;
136 principalMetadata
.mOrigin
= origin
;
138 if (info
.attrs().IsPrivateBrowsing()) {
139 QM_TRY_UNWRAP(principalMetadata
.mStorageOrigin
,
140 aQuotaManager
.EnsureStorageOriginFromOrigin(origin
));
142 principalMetadata
.mStorageOrigin
= origin
;
145 principalMetadata
.mIsPrivate
= info
.attrs().IsPrivateBrowsing();
147 return principalMetadata
;
151 MOZ_ASSERT_UNREACHABLE("Should never get here!");
152 return Err(NS_ERROR_UNEXPECTED
);
157 nsAutoCString
GetGroupFromValidatedPrincipalInfo(
158 const PrincipalInfo
& aPrincipalInfo
) {
159 MOZ_ASSERT(IsPrincipalInfoValid(aPrincipalInfo
));
161 switch (aPrincipalInfo
.type()) {
162 case PrincipalInfo::TSystemPrincipalInfo
: {
163 return nsAutoCString
{GetGroupForChrome()};
166 case PrincipalInfo::TContentPrincipalInfo
: {
167 const ContentPrincipalInfo
& info
=
168 aPrincipalInfo
.get_ContentPrincipalInfo();
170 nsAutoCString suffix
;
172 info
.attrs().CreateSuffix(suffix
);
174 return info
.baseDomain() + suffix
;
178 MOZ_CRASH("Should never get here!");
183 nsAutoCString
GetOriginFromValidatedPrincipalInfo(
184 const PrincipalInfo
& aPrincipalInfo
) {
185 MOZ_ASSERT(IsPrincipalInfoValid(aPrincipalInfo
));
187 switch (aPrincipalInfo
.type()) {
188 case PrincipalInfo::TSystemPrincipalInfo
: {
189 return nsAutoCString
{GetOriginForChrome()};
192 case PrincipalInfo::TContentPrincipalInfo
: {
193 const ContentPrincipalInfo
& info
=
194 aPrincipalInfo
.get_ContentPrincipalInfo();
196 nsAutoCString suffix
;
198 info
.attrs().CreateSuffix(suffix
);
200 return info
.originNoSuffix() + suffix
;
204 MOZ_CRASH("Should never get here!");
209 Result
<PrincipalMetadata
, nsresult
> GetInfoFromPrincipal(
210 nsIPrincipal
* aPrincipal
) {
211 MOZ_ASSERT(aPrincipal
);
213 if (aPrincipal
->IsSystemPrincipal()) {
214 return GetInfoForChrome();
217 if (aPrincipal
->GetIsNullPrincipal()) {
218 NS_WARNING("IndexedDB not supported from this principal!");
219 return Err(NS_ERROR_FAILURE
);
222 PrincipalMetadata principalMetadata
;
224 QM_TRY(MOZ_TO_RESULT(aPrincipal
->GetOrigin(principalMetadata
.mOrigin
)));
226 if (principalMetadata
.mOrigin
.EqualsLiteral(kChromeOrigin
)) {
227 NS_WARNING("Non-chrome principal can't use chrome origin!");
228 return Err(NS_ERROR_FAILURE
);
231 aPrincipal
->OriginAttributesRef().CreateSuffix(principalMetadata
.mSuffix
);
233 nsAutoCString baseDomain
;
234 QM_TRY(MOZ_TO_RESULT(aPrincipal
->GetBaseDomain(baseDomain
)));
236 MOZ_ASSERT(!baseDomain
.IsEmpty());
238 principalMetadata
.mGroup
= baseDomain
+ principalMetadata
.mSuffix
;
240 principalMetadata
.mStorageOrigin
= principalMetadata
.mOrigin
;
242 principalMetadata
.mIsPrivate
= aPrincipal
->GetIsInPrivateBrowsing();
244 return principalMetadata
;
247 Result
<PrincipalMetadata
, nsresult
> GetInfoFromWindow(
248 nsPIDOMWindowOuter
* aWindow
) {
249 MOZ_ASSERT(NS_IsMainThread());
252 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(aWindow
);
253 QM_TRY(OkIf(sop
), Err(NS_ERROR_FAILURE
));
255 nsCOMPtr
<nsIPrincipal
> principal
= sop
->GetPrincipal();
256 QM_TRY(OkIf(principal
), Err(NS_ERROR_FAILURE
));
258 return GetInfoFromPrincipal(principal
);
261 Result
<nsAutoCString
, nsresult
> GetOriginFromPrincipal(
262 nsIPrincipal
* aPrincipal
) {
263 MOZ_ASSERT(NS_IsMainThread());
264 MOZ_ASSERT(aPrincipal
);
266 if (aPrincipal
->IsSystemPrincipal()) {
267 return nsAutoCString
{GetOriginForChrome()};
270 if (aPrincipal
->GetIsNullPrincipal()) {
271 NS_WARNING("IndexedDB not supported from this principal!");
272 return Err(NS_ERROR_FAILURE
);
275 QM_TRY_UNWRAP(const auto origin
, MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
276 nsAutoCString
, aPrincipal
, GetOrigin
));
278 if (origin
.EqualsLiteral(kChromeOrigin
)) {
279 NS_WARNING("Non-chrome principal can't use chrome origin!");
280 return Err(NS_ERROR_FAILURE
);
286 Result
<nsAutoCString
, nsresult
> GetOriginFromWindow(
287 nsPIDOMWindowOuter
* aWindow
) {
288 MOZ_ASSERT(NS_IsMainThread());
291 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(aWindow
);
292 QM_TRY(OkIf(sop
), Err(NS_ERROR_FAILURE
));
294 nsCOMPtr
<nsIPrincipal
> principal
= sop
->GetPrincipal();
295 QM_TRY(OkIf(principal
), Err(NS_ERROR_FAILURE
));
297 QM_TRY_RETURN(GetOriginFromPrincipal(principal
));
300 PrincipalMetadata
GetInfoForChrome() {
303 GetOriginForChrome(),
304 GetOriginForChrome(),
308 nsLiteralCString
GetGroupForChrome() { return nsLiteralCString
{kChromeOrigin
}; }
310 nsLiteralCString
GetOriginForChrome() {
311 return nsLiteralCString
{kChromeOrigin
};
314 } // namespace mozilla::dom::quota