/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "FeaturePolicyParser.h" #include "mozilla/BasePrincipal.h" #include "mozilla/dom/Feature.h" #include "mozilla/dom/FeaturePolicyUtils.h" #include "mozilla/dom/PolicyTokenizer.h" #include "nsIScriptError.h" #include "nsIURI.h" #include "nsNetUtil.h" namespace mozilla::dom { namespace { void ReportToConsoleUnsupportedFeature(Document* aDocument, const nsString& aFeatureName) { if (!aDocument) { return; } AutoTArray params = {aFeatureName}; nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, "Feature Policy"_ns, aDocument, nsContentUtils::eSECURITY_PROPERTIES, "FeaturePolicyUnsupportedFeatureName", params); } void ReportToConsoleInvalidEmptyAllowValue(Document* aDocument, const nsString& aFeatureName) { if (!aDocument) { return; } AutoTArray params = {aFeatureName}; nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, "Feature Policy"_ns, aDocument, nsContentUtils::eSECURITY_PROPERTIES, "FeaturePolicyInvalidEmptyAllowValue", params); } void ReportToConsoleInvalidAllowValue(Document* aDocument, const nsString& aValue) { if (!aDocument) { return; } AutoTArray params = {aValue}; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Feature Policy"_ns, aDocument, nsContentUtils::eSECURITY_PROPERTIES, "FeaturePolicyInvalidAllowValue", params); } } // namespace /* static */ bool FeaturePolicyParser::ParseString(const nsAString& aPolicy, Document* aDocument, nsIPrincipal* aSelfOrigin, nsIPrincipal* aSrcOrigin, nsTArray& aParsedFeatures) { MOZ_ASSERT(aSelfOrigin); nsTArray> tokens; PolicyTokenizer::tokenizePolicy(aPolicy, tokens); nsTArray parsedFeatures; for (const nsTArray& featureTokens : tokens) { if (featureTokens.IsEmpty()) { continue; } if (!FeaturePolicyUtils::IsSupportedFeature(featureTokens[0])) { ReportToConsoleUnsupportedFeature(aDocument, featureTokens[0]); continue; } Feature feature(featureTokens[0]); if (featureTokens.Length() == 1) { if (aSrcOrigin) { feature.AppendToAllowList(aSrcOrigin); } else { ReportToConsoleInvalidEmptyAllowValue(aDocument, featureTokens[0]); continue; } } else { // we gotta start at 1 here for (uint32_t i = 1; i < featureTokens.Length(); ++i) { const nsString& curVal = featureTokens[i]; if (curVal.LowerCaseEqualsASCII("'none'")) { feature.SetAllowsNone(); break; } if (curVal.EqualsLiteral("*")) { feature.SetAllowsAll(); break; } if (curVal.LowerCaseEqualsASCII("'self'")) { feature.AppendToAllowList(aSelfOrigin); continue; } if (aSrcOrigin && curVal.LowerCaseEqualsASCII("'src'")) { feature.AppendToAllowList(aSrcOrigin); continue; } nsCOMPtr uri; nsresult rv = NS_NewURI(getter_AddRefs(uri), curVal); if (NS_FAILED(rv)) { ReportToConsoleInvalidAllowValue(aDocument, curVal); continue; } nsCOMPtr origin = BasePrincipal::CreateContentPrincipal( uri, BasePrincipal::Cast(aSelfOrigin)->OriginAttributesRef()); if (NS_WARN_IF(!origin)) { ReportToConsoleInvalidAllowValue(aDocument, curVal); continue; } feature.AppendToAllowList(origin); } } // No duplicate! bool found = false; for (const Feature& parsedFeature : parsedFeatures) { if (parsedFeature.Name() == feature.Name()) { found = true; break; } } if (!found) { parsedFeatures.AppendElement(feature); } } aParsedFeatures = std::move(parsedFeatures); return true; } } // namespace mozilla::dom