PrincipalUtils.cpp (9306B)
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/. */ 6 7 #include "mozilla/dom/quota/PrincipalUtils.h" 8 9 #include "OriginParser.h" 10 #include "mozilla/SystemPrincipal.h" 11 #include "mozilla/dom/quota/CommonMetadata.h" 12 #include "mozilla/dom/quota/Constants.h" 13 #include "mozilla/dom/quota/QuotaCommon.h" 14 #include "mozilla/dom/quota/QuotaManager.h" 15 #include "mozilla/dom/quota/ResultExtensions.h" 16 #include "mozilla/ipc/PBackgroundSharedTypes.h" 17 #include "nsIScriptObjectPrincipal.h" 18 #include "nsNetUtil.h" 19 #include "nsPIDOMWindow.h" 20 21 namespace mozilla::dom::quota { 22 23 using namespace mozilla::ipc; 24 25 bool IsPrincipalInfoValid(const PrincipalInfo& aPrincipalInfo) { 26 switch (aPrincipalInfo.type()) { 27 // A system principal is acceptable. 28 case PrincipalInfo::TSystemPrincipalInfo: { 29 return true; 30 } 31 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(); 37 38 // Verify the principal spec parses. 39 nsCOMPtr<nsIURI> uri; 40 QM_TRY(MOZ_TO_RESULT(NS_NewURI(getter_AddRefs(uri), info.spec())), false); 41 42 nsCOMPtr<nsIPrincipal> principal = 43 BasePrincipal::CreateContentPrincipal(uri, info.attrs()); 44 QM_TRY(MOZ_TO_RESULT(principal), false); 45 46 // Verify the principal originNoSuffix matches spec. 47 QM_TRY_INSPECT(const auto& originNoSuffix, 48 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoCString, principal, 49 GetOriginNoSuffix), 50 false); 51 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()); 55 return false; 56 } 57 58 if (NS_WARN_IF(info.originNoSuffix().EqualsLiteral(kChromeOrigin))) { 59 return false; 60 } 61 62 if (NS_WARN_IF(info.originNoSuffix().FindChar('^', 0) != -1)) { 63 QM_WARNING("originNoSuffix (%s) contains the '^' character!", 64 info.originNoSuffix().get()); 65 return false; 66 } 67 68 // Verify the principal baseDomain exists. 69 if (NS_WARN_IF(info.baseDomain().IsVoid())) { 70 return false; 71 } 72 73 // Verify the principal baseDomain matches spec. 74 QM_TRY_INSPECT(const auto& baseDomain, 75 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsAutoCString, principal, 76 GetBaseDomain), 77 false); 78 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()); 82 return false; 83 } 84 85 return true; 86 } 87 88 default: { 89 break; 90 } 91 } 92 93 // Null and expanded principals are not acceptable. 94 return false; 95 } 96 97 Result<PrincipalMetadata, nsresult> GetInfoFromValidatedPrincipalInfo( 98 QuotaManager& aQuotaManager, const PrincipalInfo& aPrincipalInfo) { 99 MOZ_ASSERT(IsPrincipalInfoValid(aPrincipalInfo)); 100 101 switch (aPrincipalInfo.type()) { 102 case PrincipalInfo::TSystemPrincipalInfo: { 103 return GetInfoForChrome(); 104 } 105 106 case PrincipalInfo::TContentPrincipalInfo: { 107 const ContentPrincipalInfo& info = 108 aPrincipalInfo.get_ContentPrincipalInfo(); 109 110 nsCString suffix; 111 info.attrs().CreateSuffix(suffix); 112 113 nsCString origin = info.originNoSuffix() + suffix; 114 115 if (IsUUIDOrigin(origin)) { 116 QM_TRY_INSPECT(const auto& originalOrigin, 117 aQuotaManager.GetOriginFromStorageOrigin(origin)); 118 119 nsCOMPtr<nsIPrincipal> principal = 120 BasePrincipal::CreateContentPrincipal(originalOrigin); 121 QM_TRY(MOZ_TO_RESULT(principal)); 122 123 PrincipalInfo principalInfo; 124 QM_TRY( 125 MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &principalInfo))); 126 127 return GetInfoFromValidatedPrincipalInfo(aQuotaManager, principalInfo); 128 } 129 130 PrincipalMetadata principalMetadata; 131 132 principalMetadata.mSuffix = suffix; 133 134 principalMetadata.mGroup = info.baseDomain() + suffix; 135 136 principalMetadata.mOrigin = origin; 137 138 if (info.attrs().IsPrivateBrowsing()) { 139 QM_TRY_UNWRAP(principalMetadata.mStorageOrigin, 140 aQuotaManager.EnsureStorageOriginFromOrigin(origin)); 141 } else { 142 principalMetadata.mStorageOrigin = origin; 143 } 144 145 principalMetadata.mIsPrivate = info.attrs().IsPrivateBrowsing(); 146 147 return principalMetadata; 148 } 149 150 default: { 151 MOZ_ASSERT_UNREACHABLE("Should never get here!"); 152 return Err(NS_ERROR_UNEXPECTED); 153 } 154 } 155 } 156 157 nsAutoCString GetGroupFromValidatedPrincipalInfo( 158 const PrincipalInfo& aPrincipalInfo) { 159 MOZ_ASSERT(IsPrincipalInfoValid(aPrincipalInfo)); 160 161 switch (aPrincipalInfo.type()) { 162 case PrincipalInfo::TSystemPrincipalInfo: { 163 return nsAutoCString{GetGroupForChrome()}; 164 } 165 166 case PrincipalInfo::TContentPrincipalInfo: { 167 const ContentPrincipalInfo& info = 168 aPrincipalInfo.get_ContentPrincipalInfo(); 169 170 nsAutoCString suffix; 171 172 info.attrs().CreateSuffix(suffix); 173 174 return info.baseDomain() + suffix; 175 } 176 177 default: { 178 MOZ_CRASH("Should never get here!"); 179 } 180 } 181 } 182 183 nsAutoCString GetOriginFromValidatedPrincipalInfo( 184 const PrincipalInfo& aPrincipalInfo) { 185 MOZ_ASSERT(IsPrincipalInfoValid(aPrincipalInfo)); 186 187 switch (aPrincipalInfo.type()) { 188 case PrincipalInfo::TSystemPrincipalInfo: { 189 return nsAutoCString{GetOriginForChrome()}; 190 } 191 192 case PrincipalInfo::TContentPrincipalInfo: { 193 const ContentPrincipalInfo& info = 194 aPrincipalInfo.get_ContentPrincipalInfo(); 195 196 nsAutoCString suffix; 197 198 info.attrs().CreateSuffix(suffix); 199 200 return info.originNoSuffix() + suffix; 201 } 202 203 default: { 204 MOZ_CRASH("Should never get here!"); 205 } 206 } 207 } 208 209 Result<PrincipalMetadata, nsresult> GetInfoFromPrincipal( 210 nsIPrincipal* aPrincipal) { 211 MOZ_ASSERT(aPrincipal); 212 213 if (aPrincipal->IsSystemPrincipal()) { 214 return GetInfoForChrome(); 215 } 216 217 if (aPrincipal->GetIsNullPrincipal()) { 218 NS_WARNING("IndexedDB not supported from this principal!"); 219 return Err(NS_ERROR_FAILURE); 220 } 221 222 PrincipalMetadata principalMetadata; 223 224 QM_TRY(MOZ_TO_RESULT(aPrincipal->GetOrigin(principalMetadata.mOrigin))); 225 226 if (principalMetadata.mOrigin.EqualsLiteral(kChromeOrigin)) { 227 NS_WARNING("Non-chrome principal can't use chrome origin!"); 228 return Err(NS_ERROR_FAILURE); 229 } 230 231 aPrincipal->OriginAttributesRef().CreateSuffix(principalMetadata.mSuffix); 232 233 nsAutoCString baseDomain; 234 QM_TRY(MOZ_TO_RESULT(aPrincipal->GetBaseDomain(baseDomain))); 235 236 MOZ_ASSERT(!baseDomain.IsEmpty()); 237 238 principalMetadata.mGroup = baseDomain + principalMetadata.mSuffix; 239 240 principalMetadata.mStorageOrigin = principalMetadata.mOrigin; 241 242 principalMetadata.mIsPrivate = aPrincipal->GetIsInPrivateBrowsing(); 243 244 return principalMetadata; 245 } 246 247 Result<PrincipalMetadata, nsresult> GetInfoFromWindow( 248 nsPIDOMWindowOuter* aWindow) { 249 MOZ_ASSERT(NS_IsMainThread()); 250 MOZ_ASSERT(aWindow); 251 252 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); 253 QM_TRY(OkIf(sop), Err(NS_ERROR_FAILURE)); 254 255 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal(); 256 QM_TRY(OkIf(principal), Err(NS_ERROR_FAILURE)); 257 258 return GetInfoFromPrincipal(principal); 259 } 260 261 Result<nsAutoCString, nsresult> GetOriginFromPrincipal( 262 nsIPrincipal* aPrincipal) { 263 MOZ_ASSERT(NS_IsMainThread()); 264 MOZ_ASSERT(aPrincipal); 265 266 if (aPrincipal->IsSystemPrincipal()) { 267 return nsAutoCString{GetOriginForChrome()}; 268 } 269 270 if (aPrincipal->GetIsNullPrincipal()) { 271 NS_WARNING("IndexedDB not supported from this principal!"); 272 return Err(NS_ERROR_FAILURE); 273 } 274 275 QM_TRY_UNWRAP(const auto origin, MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( 276 nsAutoCString, aPrincipal, GetOrigin)); 277 278 if (origin.EqualsLiteral(kChromeOrigin)) { 279 NS_WARNING("Non-chrome principal can't use chrome origin!"); 280 return Err(NS_ERROR_FAILURE); 281 } 282 283 return origin; 284 } 285 286 Result<nsAutoCString, nsresult> GetOriginFromWindow( 287 nsPIDOMWindowOuter* aWindow) { 288 MOZ_ASSERT(NS_IsMainThread()); 289 MOZ_ASSERT(aWindow); 290 291 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); 292 QM_TRY(OkIf(sop), Err(NS_ERROR_FAILURE)); 293 294 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal(); 295 QM_TRY(OkIf(principal), Err(NS_ERROR_FAILURE)); 296 297 QM_TRY_RETURN(GetOriginFromPrincipal(principal)); 298 } 299 300 PrincipalMetadata GetInfoForChrome() { 301 return {{}, 302 GetGroupForChrome(), 303 GetOriginForChrome(), 304 GetOriginForChrome(), 305 false}; 306 } 307 308 nsLiteralCString GetGroupForChrome() { return nsLiteralCString{kChromeOrigin}; } 309 310 nsLiteralCString GetOriginForChrome() { 311 return nsLiteralCString{kChromeOrigin}; 312 } 313 314 } // namespace mozilla::dom::quota