Bug 1733490 - Migrate CSP error messages from extensions.properties to Fluent. r=zbraniecki,mixedpuppy,flod

The actual messages were migrated using https://github.com/mozilla/properties-to-ftl,
while C++ changes use patterns established by https://bugzilla.mozilla.org/show_bug.cgi?id=1742106.

Differential Revision: https://phabricator.services.mozilla.com/D131594
This commit is contained in:
Eemeli Aro 2021-12-15 16:09:03 +00:00
parent 3113e4d131
commit 18caf861b1
5 changed files with 160 additions and 61 deletions

View File

@ -142,6 +142,9 @@ var whitelist = [
{ file: "resource://gre/res/fonts/mathfontSTIXGeneral.properties" },
{ file: "resource://gre/res/fonts/mathfontUnicode.properties" },
// toolkit/mozapps/extensions/AddonContentPolicy.cpp
{ file: "resource://gre/localization/en-US/toolkit/global/cspErrors.ftl" },
// The l10n build system can't package string files only for some platforms.
{
file:

View File

@ -0,0 +1,82 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
import fluent.syntax.ast as FTL
from fluent.migrate.helpers import VARIABLE_REFERENCE
from fluent.migrate.transforms import REPLACE
def migrate(ctx):
"""Bug 1733490 - Convert CSP errors from extensions.properties to Fluent, part {index}."""
source = "toolkit/chrome/global/extensions.properties"
target = "toolkit/toolkit/global/cspErrors.ftl"
ctx.add_transforms(
target,
target,
[
FTL.Message(
id=FTL.Identifier("csp-error-missing-directive"),
value=REPLACE(
source,
"csp.error.missing-directive",
{"%1$S": VARIABLE_REFERENCE("directive")},
),
),
FTL.Message(
id=FTL.Identifier("csp-error-illegal-keyword"),
value=REPLACE(
source,
"csp.error.illegal-keyword",
{
"%1$S": VARIABLE_REFERENCE("directive"),
"%2$S": VARIABLE_REFERENCE("keyword"),
},
),
),
FTL.Message(
id=FTL.Identifier("csp-error-illegal-protocol"),
value=REPLACE(
source,
"csp.error.illegal-protocol",
{
"%1$S": VARIABLE_REFERENCE("directive"),
"%2$S": VARIABLE_REFERENCE("scheme"),
},
),
),
FTL.Message(
id=FTL.Identifier("csp-error-missing-host"),
value=REPLACE(
source,
"csp.error.missing-host",
{
"%2$S": VARIABLE_REFERENCE("scheme"),
"%1$S": VARIABLE_REFERENCE("directive"),
},
),
),
FTL.Message(
id=FTL.Identifier("csp-error-missing-source"),
value=REPLACE(
source,
"csp.error.missing-source",
{
"%1$S": VARIABLE_REFERENCE("directive"),
"%2$S": VARIABLE_REFERENCE("source"),
},
),
),
FTL.Message(
id=FTL.Identifier("csp-error-illegal-host-wildcard"),
value=REPLACE(
source,
"csp.error.illegal-host-wildcard",
{
"%2$S": VARIABLE_REFERENCE("scheme"),
"%1$S": VARIABLE_REFERENCE("directive"),
},
),
),
],
)

View File

@ -2,23 +2,6 @@
# 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/.
csp.error.missing-directive = Policy is missing a required %S directive
#LOCALIZATION NOTE (csp.error.illegal-keyword) %1$S is the name of a CSP directive, such as "script-src". %2$S is the name of a CSP keyword, usually 'unsafe-inline'.
csp.error.illegal-keyword = %1$S directive contains a forbidden %2$S keyword
#LOCALIZATION NOTE (csp.error.illegal-protocol) %2$S a protocol name, such as "http", which appears as "http:", as it would in a URL.
csp.error.illegal-protocol = %1$S directive contains a forbidden %2$S: protocol source
#LOCALIZATION NOTE (csp.error.missing-host) %2$S a protocol name, such as "http", which appears as "http:", as it would in a URL.
csp.error.missing-host = %2$S: protocol requires a host in %1$S directives
#LOCALIZATION NOTE (csp.error.missing-source) %1$S is the name of a CSP directive, such as "script-src". %2$S is the name of a CSP source, usually 'self'.
csp.error.missing-source = %1$S must include the source %2$S
#LOCALIZATION NOTE (csp.error.illegal-host-wildcard) %2$S a protocol name, such as "http", which appears as "http:", as it would in a URL.
csp.error.illegal-host-wildcard = %2$S: wildcard sources in %1$S directives must include at least one non-generic sub-domain (e.g., *.example.com rather than *.com)
#LOCALIZATION NOTE (uninstall.confirmation.title) %S is the name of the extension which is about to be uninstalled.
uninstall.confirmation.title = Uninstall %S

View File

@ -0,0 +1,32 @@
# 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/.
# Variables:
# $directive (String): the name of a CSP directive, such as "script-src".
csp-error-missing-directive = Policy is missing a required { $directive } directive
# Variables:
# $directive (String): the name of a CSP directive, such as "script-src".
# $keyword (String): the name of a CSP keyword, usually 'unsafe-inline'.
csp-error-illegal-keyword = { $directive } directive contains a forbidden { $keyword } keyword
# Variables:
# $directive (String): the name of a CSP directive, such as "script-src".
# $scheme (String): a protocol name, such as "http", which appears as "http:", as it would in a URL.
csp-error-illegal-protocol = { $directive } directive contains a forbidden { $scheme }: protocol source
# Variables:
# $directive (String): the name of a CSP directive, such as "script-src".
# $scheme (String): a protocol name, such as "http", which appears as "http:", as it would in a URL.
csp-error-missing-host = { $scheme }: protocol requires a host in { $directive } directives
# Variables:
# $directive (String): the name of a CSP directive, such as "script-src".
# $source (String): the name of a CSP source, usually 'self'.
csp-error-missing-source = { $directive } must include the source { $source }
# Variables:
# $directive (String): the name of a CSP directive, such as "script-src".
# $scheme (String): a protocol name, such as "http", which appears as "http:", as it would in a URL.
csp-error-illegal-host-wildcard = { $scheme }: wildcard sources in { $directive } directives must include at least one non-generic sub-domain (e.g., *.example.com rather than *.com)

View File

@ -17,6 +17,7 @@
#include "nsIContent.h"
#include "mozilla/Components.h"
#include "mozilla/dom/Document.h"
#include "mozilla/intl/Localization.h"
#include "nsIEffectiveTLDService.h"
#include "nsIScriptError.h"
#include "nsIStringBundle.h"
@ -26,6 +27,7 @@
#include "nsNetUtil.h"
using namespace mozilla;
using namespace mozilla::intl;
/* Enforces content policies for WebExtension scopes. Currently:
*
@ -189,7 +191,7 @@ class CSPValidator final : public nsCSPSrcVisitor {
// visitors will be called if the directive isn't present.
mError.SetIsVoid(true);
if (aDirectiveRequired) {
FormatError("csp.error.missing-directive");
FormatError("csp-error-missing-directive"_ns);
}
}
@ -200,11 +202,11 @@ class CSPValidator final : public nsCSPSrcVisitor {
src.getScheme(scheme);
if (SchemeInList(scheme, allowedHostSchemes)) {
FormatError("csp.error.missing-host", scheme);
FormatError("csp-error-missing-host"_ns, "scheme"_ns, scheme);
return false;
}
if (!SchemeInList(scheme, allowedSchemes)) {
FormatError("csp.error.illegal-protocol", scheme);
FormatError("csp-error-illegal-protocol"_ns, "scheme"_ns, scheme);
return false;
}
return true;
@ -222,7 +224,7 @@ class CSPValidator final : public nsCSPSrcVisitor {
HostIsLocal(host)) {
return true;
}
FormatError("csp.error.illegal-protocol", scheme);
FormatError("csp-error-illegal-protocol"_ns, "scheme"_ns, scheme);
return false;
}
if (scheme.LowerCaseEqualsLiteral("https")) {
@ -231,11 +233,11 @@ class CSPValidator final : public nsCSPSrcVisitor {
return true;
}
if (!(mPermittedPolicy & nsIAddonContentPolicy::CSP_ALLOW_REMOTE)) {
FormatError("csp.error.illegal-protocol", scheme);
FormatError("csp-error-illegal-protocol"_ns, "scheme"_ns, scheme);
return false;
}
if (!HostIsAllowed(host)) {
FormatError("csp.error.illegal-host-wildcard", scheme);
FormatError("csp-error-illegal-host-wildcard"_ns, "scheme"_ns, scheme);
return false;
}
} else if (scheme.LowerCaseEqualsLiteral("moz-extension")) {
@ -249,11 +251,11 @@ class CSPValidator final : public nsCSPSrcVisitor {
}
if (host.IsEmpty() || host.EqualsLiteral("*")) {
FormatError("csp.error.missing-host", scheme);
FormatError("csp-error-missing-host"_ns, "scheme"_ns, scheme);
return false;
}
} else if (!SchemeInList(scheme, allowedSchemes)) {
FormatError("csp.error.illegal-protocol", scheme);
FormatError("csp-error-illegal-protocol"_ns, "scheme"_ns, scheme);
return false;
}
@ -273,14 +275,14 @@ class CSPValidator final : public nsCSPSrcVisitor {
[[fallthrough]];
default:
FormatError(
"csp.error.illegal-keyword",
"csp-error-illegal-keyword"_ns, "keyword"_ns,
nsDependentString(CSP_EnumToUTF16Keyword(src.getKeyword())));
return false;
}
};
bool visitNonceSrc(const nsCSPNonceSrc& src) override {
FormatError("csp.error.illegal-keyword", u"'nonce-*'"_ns);
FormatError("csp-error-illegal-keyword"_ns, "keyword"_ns, u"'nonce-*'"_ns);
return false;
};
@ -294,11 +296,35 @@ class CSPValidator final : public nsCSPSrcVisitor {
// Formatters
template <typename... T>
inline void FormatError(const char* aName, const T... aParams) {
AutoTArray<nsString, sizeof...(aParams) + 1> params = {mDirective,
aParams...};
FormatErrorParams(aName, params);
inline void FormatError(const nsACString& l10nId,
const nsACString& aKey = ""_ns,
const nsAString& aValue = u""_ns) {
nsTArray<nsCString> resIds = {"toolkit/global/cspErrors.ftl"_ns};
RefPtr<intl::Localization> l10n = intl::Localization::Create(resIds, true);
auto l10nArgs = dom::Optional<intl::L10nArgs>();
l10nArgs.Construct();
auto dirArg = l10nArgs.Value().Entries().AppendElement();
dirArg->mKey = "directive";
dirArg->mValue.SetValue().SetAsUTF8String().Assign(
NS_ConvertUTF16toUTF8(mDirective));
if (!aKey.IsEmpty()) {
auto optArg = l10nArgs.Value().Entries().AppendElement();
optArg->mKey = aKey;
optArg->mValue.SetValue().SetAsUTF8String().Assign(
NS_ConvertUTF16toUTF8(aValue));
}
nsAutoCString translation;
IgnoredErrorResult rv;
l10n->FormatValueSync(l10nId, l10nArgs, translation, rv);
if (rv.Failed()) {
mError.AssignLiteral("An unexpected error occurred");
} else {
mError = NS_ConvertUTF8toUTF16(translation);
}
};
private:
@ -342,34 +368,6 @@ class CSPValidator final : public nsCSPSrcVisitor {
return false;
};
// Formatters
already_AddRefed<nsIStringBundle> GetStringBundle() {
nsCOMPtr<nsIStringBundleService> sbs =
mozilla::components::StringBundle::Service();
NS_ENSURE_TRUE(sbs, nullptr);
nsCOMPtr<nsIStringBundle> stringBundle;
sbs->CreateBundle("chrome://global/locale/extensions.properties",
getter_AddRefs(stringBundle));
return stringBundle.forget();
};
void FormatErrorParams(const char* aName, const nsTArray<nsString>& aParams) {
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIStringBundle> stringBundle = GetStringBundle();
if (stringBundle) {
rv = stringBundle->FormatStringFromName(aName, aParams, mError);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
mError.AssignLiteral("An unexpected error occurred");
}
};
// Data members
nsAutoString mURL;
@ -453,7 +451,8 @@ AddonContentPolicy::ValidateAddonCSP(const nsAString& aPolicyString,
if (!policy->visitDirectiveSrcs(directive, &validator)) {
aResult.Assign(validator.GetError());
} else if (!validator.FoundSelf()) {
validator.FormatError("csp.error.missing-source", u"'self'"_ns);
validator.FormatError("csp-error-missing-source"_ns, "source"_ns,
u"'self'"_ns);
aResult.Assign(validator.GetError());
}
hasValidScriptSrc = true;