Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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<nsString, 1> 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<nsString, 1> 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<nsString, 1> 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<Feature>& aParsedFeatures) {
MOZ_ASSERT(aSelfOrigin);
nsTArray<CopyableTArray<nsString>> tokens;
PolicyTokenizer::tokenizePolicy(aPolicy, tokens);
nsTArray<Feature> parsedFeatures;
for (const nsTArray<nsString>& 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<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), curVal);
if (NS_FAILED(rv)) {
ReportToConsoleInvalidAllowValue(aDocument, curVal);
continue;
}
nsCOMPtr<nsIPrincipal> 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