Source code

Revision control

Other Tools

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
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef mozilla_BasePrincipal_h
8
#define mozilla_BasePrincipal_h
9
10
#include "nsJSPrincipals.h"
11
12
#include "mozilla/Attributes.h"
13
#include "mozilla/OriginAttributes.h"
14
15
class nsAtom;
16
class nsIContentSecurityPolicy;
17
class nsIObjectOutputStream;
18
class nsIObjectInputStream;
19
class nsIURI;
20
21
class ExpandedPrincipal;
22
23
namespace Json {
24
class Value;
25
}
26
namespace mozilla {
27
namespace dom {
28
class Document;
29
}
30
namespace extensions {
31
class WebExtensionPolicy;
32
}
33
34
class BasePrincipal;
35
36
// Content principals (and content principals embedded within expanded
37
// principals) stored in SiteIdentifier are guaranteed to contain only the
38
// eTLD+1 part of the original domain. This is used to determine whether two
39
// origins are same-site: if it's possible for two origins to access each other
40
// (maybe after mutating document.domain), then they must have the same site
41
// identifier.
42
class SiteIdentifier {
43
public:
44
void Init(BasePrincipal* aPrincipal) {
45
MOZ_ASSERT(aPrincipal);
46
mPrincipal = aPrincipal;
47
}
48
49
bool IsInitialized() const { return !!mPrincipal; }
50
51
bool Equals(const SiteIdentifier& aOther) const;
52
53
private:
54
friend class ::ExpandedPrincipal;
55
56
BasePrincipal* GetPrincipal() const {
57
MOZ_ASSERT(IsInitialized());
58
return mPrincipal;
59
}
60
61
RefPtr<BasePrincipal> mPrincipal;
62
};
63
64
/*
65
* Base class from which all nsIPrincipal implementations inherit. Use this for
66
* default implementations and other commonalities between principal
67
* implementations.
68
*
69
* We should merge nsJSPrincipals into this class at some point.
70
*/
71
class BasePrincipal : public nsJSPrincipals {
72
public:
73
// Warning: this enum impacts Principal serialization into JSON format.
74
// Only update if you know exactly what you are doing
75
enum PrincipalKind {
76
eNullPrincipal = 0,
77
eContentPrincipal,
78
eExpandedPrincipal,
79
eSystemPrincipal,
80
eKindMax = eSystemPrincipal
81
};
82
83
explicit BasePrincipal(PrincipalKind aKind);
84
85
template <typename T>
86
bool Is() const {
87
return mKind == T::Kind();
88
}
89
90
template <typename T>
91
T* As() {
92
MOZ_ASSERT(Is<T>());
93
return static_cast<T*>(this);
94
}
95
96
enum DocumentDomainConsideration {
97
DontConsiderDocumentDomain,
98
ConsiderDocumentDomain
99
};
100
bool Subsumes(nsIPrincipal* aOther,
101
DocumentDomainConsideration aConsideration);
102
103
NS_IMETHOD GetOrigin(nsACString& aOrigin) final;
104
NS_IMETHOD GetAsciiOrigin(nsACString& aOrigin) override;
105
NS_IMETHOD GetOriginNoSuffix(nsACString& aOrigin) final;
106
NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) final;
107
NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
108
NS_IMETHOD EqualsURI(nsIURI* aOtherURI, bool* _retval) override;
109
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
110
NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other,
111
bool* _retval) final;
112
NS_IMETHOD SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* other,
113
bool* _retval) final;
114
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool allowIfInheritsPrincipal) final;
115
NS_IMETHOD CheckMayLoadWithReporting(nsIURI* uri,
116
bool allowIfInheritsPrincipal,
117
uint64_t innerWindowID) final;
118
NS_IMETHOD GetAddonPolicy(nsISupports** aResult) final;
119
NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
120
NS_IMETHOD GetIsContentPrincipal(bool* aResult) override;
121
NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
122
NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
123
NS_IMETHOD SchemeIs(const char* aScheme, bool* aResult) override;
124
NS_IMETHOD IsURIInPrefList(const char* aPref, bool* aResult) override;
125
NS_IMETHOD IsL10nAllowed(nsIURI* aURI, bool* aResult) override;
126
NS_IMETHOD GetAboutModuleFlags(uint32_t* flags) override;
127
NS_IMETHOD GetIsAddonOrExpandedAddonPrincipal(bool* aResult) override;
128
NS_IMETHOD GetOriginAttributes(JSContext* aCx,
129
JS::MutableHandle<JS::Value> aVal) final;
130
NS_IMETHOD GetAsciiSpec(nsACString& aSpec) override;
131
NS_IMETHOD GetExposablePrePath(nsACString& aResult) override;
132
NS_IMETHOD GetHostPort(nsACString& aRes) override;
133
NS_IMETHOD GetHost(nsACString& aRes) override;
134
NS_IMETHOD GetPrepath(nsACString& aResult) override;
135
NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
136
NS_IMETHOD GetIsIpAddress(bool* aIsIpAddress) override;
137
NS_IMETHOD GetIsOnion(bool* aIsOnion) override;
138
NS_IMETHOD GetIsInIsolatedMozBrowserElement(
139
bool* aIsInIsolatedMozBrowserElement) final;
140
NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
141
NS_IMETHOD GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) final;
142
NS_IMETHOD GetSiteOrigin(nsACString& aOrigin) override;
143
NS_IMETHOD IsThirdPartyURI(nsIURI* uri, bool* aRes) override;
144
NS_IMETHOD IsThirdPartyPrincipal(nsIPrincipal* uri, bool* aRes) override;
145
NS_IMETHOD GetIsOriginPotentiallyTrustworthy(bool* aResult) override;
146
NS_IMETHOD IsSameOrigin(nsIURI* aURI, bool aIsPrivateWin,
147
bool* aRes) override;
148
NS_IMETHOD GetPrefLightCacheKey(nsIURI* aURI, bool aWithCredentials,
149
nsACString& _retval) override;
150
NS_IMETHOD GetAsciiHost(nsACString& aAsciiHost) override;
151
NS_IMETHOD GetLocalStorageQuotaKey(nsACString& aRes) override;
152
NS_IMETHOD AllowsRelaxStrictFileOriginPolicy(nsIURI* aURI,
153
bool* aRes) override;
154
NS_IMETHOD CreateReferrerInfo(mozilla::dom::ReferrerPolicy aReferrerPolicy,
155
nsIReferrerInfo** _retval) override;
156
NS_IMETHOD GetIsScriptAllowedByPolicy(
157
bool* aIsScriptAllowedByPolicy) override;
158
NS_IMETHOD GetStorageOriginKey(nsACString& aOriginKey) override;
159
nsresult ToJSON(nsACString& aJSON);
160
static already_AddRefed<BasePrincipal> FromJSON(const nsACString& aJSON);
161
// Method populates a passed Json::Value with serializable fields
162
// which represent all of the fields to deserialize the principal
163
virtual nsresult PopulateJSONObject(Json::Value& aObject);
164
165
virtual bool AddonHasPermission(const nsAtom* aPerm);
166
167
virtual bool IsContentPrincipal() const { return false; };
168
169
static BasePrincipal* Cast(nsIPrincipal* aPrin) {
170
return static_cast<BasePrincipal*>(aPrin);
171
}
172
173
static BasePrincipal& Cast(nsIPrincipal& aPrin) {
174
return *static_cast<BasePrincipal*>(&aPrin);
175
}
176
177
static const BasePrincipal* Cast(const nsIPrincipal* aPrin) {
178
return static_cast<const BasePrincipal*>(aPrin);
179
}
180
181
static const BasePrincipal& Cast(const nsIPrincipal& aPrin) {
182
return *static_cast<const BasePrincipal*>(&aPrin);
183
}
184
185
static already_AddRefed<BasePrincipal> CreateContentPrincipal(
186
const nsACString& aOrigin);
187
188
// These following method may not create a content principal in case it's
189
// not possible to generate a correct origin from the passed URI. If this
190
// happens, a NullPrincipal is returned.
191
192
static already_AddRefed<BasePrincipal> CreateContentPrincipal(
193
nsIURI* aURI, const OriginAttributes& aAttrs);
194
195
const OriginAttributes& OriginAttributesRef() final {
196
return mOriginAttributes;
197
}
198
extensions::WebExtensionPolicy* AddonPolicy();
199
uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
200
uint32_t PrivateBrowsingId() const {
201
return mOriginAttributes.mPrivateBrowsingId;
202
}
203
bool IsInIsolatedMozBrowserElement() const {
204
return mOriginAttributes.mInIsolatedMozBrowser;
205
}
206
207
PrincipalKind Kind() const { return mKind; }
208
209
already_AddRefed<BasePrincipal> CloneForcingOriginAttributes(
210
const OriginAttributes& aOriginAttributes);
211
212
// If this is an add-on content script principal, returns its AddonPolicy.
213
// Otherwise returns null.
214
extensions::WebExtensionPolicy* ContentScriptAddonPolicy();
215
216
// Helper to check whether this principal is associated with an addon that
217
// allows unprivileged code to load aURI. aExplicit == true will prevent
218
// use of all_urls permission, requiring the domain in its permissions.
219
bool AddonAllowsLoad(nsIURI* aURI, bool aExplicit = false);
220
221
// Call these to avoid the cost of virtual dispatch.
222
inline bool FastEquals(nsIPrincipal* aOther);
223
inline bool FastEqualsConsideringDomain(nsIPrincipal* aOther);
224
inline bool FastSubsumes(nsIPrincipal* aOther);
225
inline bool FastSubsumesConsideringDomain(nsIPrincipal* aOther);
226
inline bool FastSubsumesIgnoringFPD(nsIPrincipal* aOther);
227
inline bool FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther);
228
229
// Fast way to check whether we have a system principal.
230
inline bool IsSystemPrincipal() const;
231
232
// Returns the principal to inherit when a caller with this principal loads
233
// the given URI.
234
//
235
// For most principal types, this returns the principal itself. For expanded
236
// principals, it returns the first sub-principal which subsumes the given URI
237
// (or, if no URI is given, the last allowlist principal).
238
nsIPrincipal* PrincipalToInherit(nsIURI* aRequestedURI = nullptr);
239
240
/* Returns true if this principal's CSP should override a document's CSP for
241
* loads that it triggers. Currently true for expanded principals which
242
* subsume the document principal, and add-on content principals regardless
243
* of whether they subsume the document principal.
244
*/
245
bool OverridesCSP(nsIPrincipal* aDocumentPrincipal) {
246
MOZ_ASSERT(aDocumentPrincipal);
247
248
// Expanded principals override CSP if and only if they subsume the document
249
// principal.
250
if (mKind == eExpandedPrincipal) {
251
return FastSubsumes(aDocumentPrincipal);
252
}
253
// Extension principals always override the CSP non-extension principals.
254
// This is primarily for the sake of their stylesheets, which are usually
255
// loaded from channels and cannot have expanded principals.
256
return (AddonPolicy() &&
257
!BasePrincipal::Cast(aDocumentPrincipal)->AddonPolicy());
258
}
259
260
uint32_t GetOriginNoSuffixHash() const { return mOriginNoSuffix->hash(); }
261
uint32_t GetOriginSuffixHash() const { return mOriginSuffix->hash(); }
262
263
virtual nsresult GetSiteIdentifier(SiteIdentifier& aSite) = 0;
264
265
protected:
266
virtual ~BasePrincipal();
267
268
// Note that this does not check OriginAttributes. Callers that depend on
269
// those must call Subsumes instead.
270
virtual bool SubsumesInternal(nsIPrincipal* aOther,
271
DocumentDomainConsideration aConsider) = 0;
272
273
// Internal, side-effect-free check to determine whether the concrete
274
// principal would allow the load ignoring any common behavior implemented in
275
// BasePrincipal::CheckMayLoad.
276
virtual bool MayLoadInternal(nsIURI* aURI) = 0;
277
friend class ::ExpandedPrincipal;
278
279
// Helper for implementing CheckMayLoad and CheckMayLoadWithReporting.
280
nsresult CheckMayLoadHelper(nsIURI* aURI, bool aAllowIfInheritsPrincipal,
281
bool aReport, uint64_t aInnerWindowID);
282
283
void SetHasExplicitDomain() { mHasExplicitDomain = true; }
284
285
// Either of these functions should be called as the last step of the
286
// initialization of the principal objects. It's typically called as the
287
// last step from the Init() method of the child classes.
288
void FinishInit(const nsACString& aOriginNoSuffix,
289
const OriginAttributes& aOriginAttributes);
290
void FinishInit(BasePrincipal* aOther,
291
const OriginAttributes& aOriginAttributes);
292
293
// KeyValT holds a principal subtype-specific key value and the associated
294
// parsed value after JSON parsing.
295
template <typename SerializedKey>
296
struct KeyValT {
297
static_assert(sizeof(SerializedKey) == 1,
298
"SerializedKey should be a uint8_t");
299
SerializedKey key;
300
bool valueWasSerialized;
301
nsCString value;
302
};
303
304
private:
305
static already_AddRefed<BasePrincipal> CreateContentPrincipal(
306
nsIURI* aURI, const OriginAttributes& aAttrs,
307
const nsACString& aOriginNoSuffix);
308
309
inline bool FastSubsumesIgnoringFPD(
310
nsIPrincipal* aOther, DocumentDomainConsideration aConsideration);
311
312
RefPtr<nsAtom> mOriginNoSuffix;
313
RefPtr<nsAtom> mOriginSuffix;
314
315
OriginAttributes mOriginAttributes;
316
PrincipalKind mKind;
317
bool mHasExplicitDomain;
318
bool mInitialized;
319
};
320
321
inline bool BasePrincipal::FastEquals(nsIPrincipal* aOther) {
322
MOZ_ASSERT(aOther);
323
324
auto other = Cast(aOther);
325
if (Kind() != other->Kind()) {
326
// Principals of different kinds can't be equal.
327
return false;
328
}
329
330
// Two principals are considered to be equal if their origins are the same.
331
// If the two principals are content principals, their origin attributes
332
// (aka the origin suffix) must also match.
333
if (Kind() == eSystemPrincipal) {
334
return this == other;
335
}
336
337
if (Kind() == eContentPrincipal || Kind() == eNullPrincipal) {
338
return mOriginNoSuffix == other->mOriginNoSuffix &&
339
mOriginSuffix == other->mOriginSuffix;
340
}
341
342
MOZ_ASSERT(Kind() == eExpandedPrincipal);
343
return mOriginNoSuffix == other->mOriginNoSuffix;
344
}
345
346
inline bool BasePrincipal::FastEqualsConsideringDomain(nsIPrincipal* aOther) {
347
MOZ_ASSERT(aOther);
348
349
// If neither of the principals have document.domain set, we use the fast path
350
// in Equals(). Otherwise, we fall back to the slow path below.
351
auto other = Cast(aOther);
352
if (!mHasExplicitDomain && !other->mHasExplicitDomain) {
353
return FastEquals(aOther);
354
}
355
356
return Subsumes(aOther, ConsiderDocumentDomain) &&
357
other->Subsumes(this, ConsiderDocumentDomain);
358
}
359
360
inline bool BasePrincipal::FastSubsumes(nsIPrincipal* aOther) {
361
MOZ_ASSERT(aOther);
362
363
// If two principals are equal, then they both subsume each other.
364
if (FastEquals(aOther)) {
365
return true;
366
}
367
368
// Otherwise, fall back to the slow path.
369
return Subsumes(aOther, DontConsiderDocumentDomain);
370
}
371
372
inline bool BasePrincipal::FastSubsumesConsideringDomain(nsIPrincipal* aOther) {
373
MOZ_ASSERT(aOther);
374
375
// If neither of the principals have document.domain set, we hand off to
376
// FastSubsumes() which has fast paths for some special cases. Otherwise, we
377
// fall back to the slow path below.
378
if (!mHasExplicitDomain && !Cast(aOther)->mHasExplicitDomain) {
379
return FastSubsumes(aOther);
380
}
381
382
return Subsumes(aOther, ConsiderDocumentDomain);
383
}
384
385
inline bool BasePrincipal::FastSubsumesIgnoringFPD(
386
nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) {
387
MOZ_ASSERT(aOther);
388
389
if (Kind() == eContentPrincipal &&
390
!dom::ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
391
mOriginAttributes, Cast(aOther)->mOriginAttributes)) {
392
return false;
393
}
394
395
return SubsumesInternal(aOther, aConsideration);
396
}
397
398
inline bool BasePrincipal::FastSubsumesIgnoringFPD(nsIPrincipal* aOther) {
399
return FastSubsumesIgnoringFPD(aOther, DontConsiderDocumentDomain);
400
}
401
402
inline bool BasePrincipal::FastSubsumesConsideringDomainIgnoringFPD(
403
nsIPrincipal* aOther) {
404
return FastSubsumesIgnoringFPD(aOther, ConsiderDocumentDomain);
405
}
406
407
inline bool BasePrincipal::IsSystemPrincipal() const {
408
return Kind() == eSystemPrincipal;
409
}
410
411
} // namespace mozilla
412
413
inline bool nsIPrincipal::IsSystemPrincipal() const {
414
return mozilla::BasePrincipal::Cast(this)->IsSystemPrincipal();
415
}
416
417
#endif /* mozilla_BasePrincipal_h */