Line data Source code
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 nsIContentSecurityPolicy;
16 : class nsIObjectOutputStream;
17 : class nsIObjectInputStream;
18 : class nsIURI;
19 :
20 : class ExpandedPrincipal;
21 :
22 : namespace mozilla {
23 :
24 : /*
25 : * Base class from which all nsIPrincipal implementations inherit. Use this for
26 : * default implementations and other commonalities between principal
27 : * implementations.
28 : *
29 : * We should merge nsJSPrincipals into this class at some point.
30 : */
31 : class BasePrincipal : public nsJSPrincipals
32 : {
33 : public:
34 : enum PrincipalKind {
35 : eNullPrincipal,
36 : eCodebasePrincipal,
37 : eExpandedPrincipal,
38 : eSystemPrincipal
39 : };
40 :
41 : explicit BasePrincipal(PrincipalKind aKind);
42 :
43 : enum DocumentDomainConsideration { DontConsiderDocumentDomain, ConsiderDocumentDomain};
44 : bool Subsumes(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration);
45 :
46 : NS_IMETHOD GetOrigin(nsACString& aOrigin) final;
47 : NS_IMETHOD GetOriginNoSuffix(nsACString& aOrigin) final;
48 : NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval) final;
49 : NS_IMETHOD EqualsConsideringDomain(nsIPrincipal* other, bool* _retval) final;
50 : NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval) final;
51 : NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
52 : NS_IMETHOD SubsumesConsideringDomainIgnoringFPD(nsIPrincipal* other, bool* _retval) final;
53 : NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final;
54 : NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
55 : NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
56 : NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
57 : NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
58 : NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
59 : NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
60 : NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
61 : NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
62 : NS_IMETHOD GetIsExpandedPrincipal(bool* aResult) override;
63 : NS_IMETHOD GetIsSystemPrincipal(bool* aResult) override;
64 : NS_IMETHOD GetOriginAttributes(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) final;
65 : NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
66 : NS_IMETHOD GetAppId(uint32_t* aAppId) final;
67 : NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement) final;
68 : NS_IMETHOD GetUserContextId(uint32_t* aUserContextId) final;
69 : NS_IMETHOD GetPrivateBrowsingId(uint32_t* aPrivateBrowsingId) final;
70 :
71 : virtual bool AddonHasPermission(const nsAString& aPerm);
72 :
73 2 : virtual bool IsCodebasePrincipal() const { return false; };
74 :
75 76808 : static BasePrincipal* Cast(nsIPrincipal* aPrin) { return static_cast<BasePrincipal*>(aPrin); }
76 :
77 : static already_AddRefed<BasePrincipal>
78 : CreateCodebasePrincipal(const nsACString& aOrigin);
79 :
80 : // These following method may not create a codebase principal in case it's
81 : // not possible to generate a correct origin from the passed URI. If this
82 : // happens, a NullPrincipal is returned.
83 :
84 : static already_AddRefed<BasePrincipal>
85 : CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs);
86 :
87 1300 : const OriginAttributes& OriginAttributesRef() final { return mOriginAttributes; }
88 55 : uint32_t AppId() const { return mOriginAttributes.mAppId; }
89 0 : uint32_t UserContextId() const { return mOriginAttributes.mUserContextId; }
90 4 : uint32_t PrivateBrowsingId() const { return mOriginAttributes.mPrivateBrowsingId; }
91 23 : bool IsInIsolatedMozBrowserElement() const { return mOriginAttributes.mInIsolatedMozBrowser; }
92 :
93 98693 : PrincipalKind Kind() const { return mKind; }
94 :
95 : already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
96 :
97 : // Helper to check whether this principal is associated with an addon that
98 : // allows unprivileged code to load aURI. aExplicit == true will prevent
99 : // use of all_urls permission, requiring the domain in its permissions.
100 : bool AddonAllowsLoad(nsIURI* aURI, bool aExplicit = false);
101 :
102 : // Call these to avoid the cost of virtual dispatch.
103 : inline bool FastEquals(nsIPrincipal* aOther);
104 : inline bool FastEqualsConsideringDomain(nsIPrincipal* aOther);
105 : inline bool FastSubsumes(nsIPrincipal* aOther);
106 : inline bool FastSubsumesConsideringDomain(nsIPrincipal* aOther);
107 : inline bool FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther);
108 :
109 : protected:
110 : virtual ~BasePrincipal();
111 :
112 : // Note that this does not check OriginAttributes. Callers that depend on
113 : // those must call Subsumes instead.
114 : virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;
115 :
116 : // Internal, side-effect-free check to determine whether the concrete
117 : // principal would allow the load ignoring any common behavior implemented in
118 : // BasePrincipal::CheckMayLoad.
119 : virtual bool MayLoadInternal(nsIURI* aURI) = 0;
120 : friend class ::ExpandedPrincipal;
121 :
122 : void
123 1 : SetHasExplicitDomain()
124 : {
125 1 : mHasExplicitDomain = true;
126 1 : }
127 :
128 : // This function should be called as the last step of the initialization of the
129 : // principal objects. It's typically called as the last step from the Init()
130 : // method of the child classes.
131 : void FinishInit(const nsACString& aOriginNoSuffix,
132 : const OriginAttributes& aOriginAttributes);
133 :
134 : nsCOMPtr<nsIContentSecurityPolicy> mCSP;
135 : nsCOMPtr<nsIContentSecurityPolicy> mPreloadCSP;
136 :
137 : private:
138 : static already_AddRefed<BasePrincipal>
139 : CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAttrs,
140 : const nsACString& aOriginNoSuffix);
141 :
142 : nsCOMPtr<nsIAtom> mOriginNoSuffix;
143 : nsCOMPtr<nsIAtom> mOriginSuffix;
144 :
145 : OriginAttributes mOriginAttributes;
146 : PrincipalKind mKind;
147 : bool mHasExplicitDomain;
148 : bool mInitialized;
149 : };
150 :
151 : inline bool
152 19459 : BasePrincipal::FastEquals(nsIPrincipal* aOther)
153 : {
154 19459 : auto other = Cast(aOther);
155 19459 : if (Kind() != other->Kind()) {
156 : // Principals of different kinds can't be equal.
157 2517 : return false;
158 : }
159 :
160 : // Two principals are considered to be equal if their origins are the same.
161 : // If the two principals are codebase principals, their origin attributes
162 : // (aka the origin suffix) must also match.
163 : // If the two principals are null principals, they're only equal if they're
164 : // the same object.
165 16942 : if (Kind() == eNullPrincipal || Kind() == eSystemPrincipal) {
166 16881 : return this == other;
167 : }
168 :
169 61 : if (Kind() == eCodebasePrincipal) {
170 122 : return mOriginNoSuffix == other->mOriginNoSuffix &&
171 122 : mOriginSuffix == other->mOriginSuffix;
172 : }
173 :
174 0 : MOZ_ASSERT(Kind() == eExpandedPrincipal);
175 0 : return mOriginNoSuffix == other->mOriginNoSuffix;
176 : }
177 :
178 : inline bool
179 0 : BasePrincipal::FastEqualsConsideringDomain(nsIPrincipal* aOther)
180 : {
181 : // If neither of the principals have document.domain set, we use the fast path
182 : // in Equals(). Otherwise, we fall back to the slow path below.
183 0 : auto other = Cast(aOther);
184 0 : if (!mHasExplicitDomain && !other->mHasExplicitDomain) {
185 0 : return FastEquals(aOther);
186 : }
187 :
188 0 : return Subsumes(aOther, ConsiderDocumentDomain) &&
189 0 : other->Subsumes(this, ConsiderDocumentDomain);
190 : }
191 :
192 : inline bool
193 19374 : BasePrincipal::FastSubsumes(nsIPrincipal* aOther)
194 : {
195 : // If two principals are equal, then they both subsume each other.
196 : // We deal with two special cases first:
197 : // Null principals only subsume each other if they are equal, and are only
198 : // equal if they're the same object.
199 19374 : auto other = Cast(aOther);
200 19374 : if (Kind() == eNullPrincipal && other->Kind() == eNullPrincipal) {
201 0 : return this == other;
202 : }
203 19374 : if (FastEquals(aOther)) {
204 16861 : return true;
205 : }
206 :
207 : // Otherwise, fall back to the slow path.
208 2513 : return Subsumes(aOther, DontConsiderDocumentDomain);
209 : }
210 :
211 : inline bool
212 19257 : BasePrincipal::FastSubsumesConsideringDomain(nsIPrincipal* aOther)
213 : {
214 : // If neither of the principals have document.domain set, we hand off to
215 : // FastSubsumes() which has fast paths for some special cases. Otherwise, we fall
216 : // back to the slow path below.
217 19257 : if (!mHasExplicitDomain && !Cast(aOther)->mHasExplicitDomain) {
218 19257 : return FastSubsumes(aOther);
219 : }
220 :
221 0 : return Subsumes(aOther, ConsiderDocumentDomain);
222 : }
223 :
224 : inline bool
225 0 : BasePrincipal::FastSubsumesConsideringDomainIgnoringFPD(nsIPrincipal* aOther)
226 : {
227 0 : if (Kind() == eCodebasePrincipal &&
228 0 : !dom::ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
229 0 : mOriginAttributes, Cast(aOther)->mOriginAttributes)) {
230 0 : return false;
231 : }
232 :
233 0 : return SubsumesInternal(aOther, ConsiderDocumentDomain);
234 : }
235 :
236 : } // namespace mozilla
237 :
238 : #endif /* mozilla_BasePrincipal_h */
|