src/messages/manifestjson.js (768 lines of code) (raw):

import { i18n, errorParamsToUnsupportedVersionRange } from 'utils'; import { MANIFEST_JSON, PERMS_DATAPATH_REGEX } from 'const'; const PRIVILEGED_EXTENSION_SIGNING_DOCS = i18n._(` Please refer to https://github.com/mozilla-extensions/xpi-manifest to learn more about privileged extensions and signing. `); export const MANIFEST_FIELD_REQUIRED = { code: 'MANIFEST_FIELD_REQUIRED', message: i18n._('The field is required.'), description: i18n._( 'See https://mzl.la/1ZOhoEN (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_FIELD_INVALID = { code: 'MANIFEST_FIELD_INVALID', message: i18n._('The field is invalid.'), description: i18n._( 'See https://mzl.la/1ZOhoEN (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_FIELD_PRIVILEGEDONLY = 'MANIFEST_FIELD_PRIVILEGEDONLY'; export function manifestFieldPrivilegedOnly(fieldName) { return { code: MANIFEST_FIELD_PRIVILEGEDONLY, message: i18n.sprintf( i18n._(`"%(fieldName)s" is ignored for non-privileged add-ons.`), { fieldName } ), description: i18n.sprintf( i18n._(`"%(fieldName)s" manifest field is only used for privileged and temporarily installed extensions.`), { fieldName } ), file: MANIFEST_JSON, }; } export const MANIFEST_FIELD_UNSUPPORTED = 'MANIFEST_FIELD_UNSUPPORTED'; export function manifestFieldUnsupported(fieldName, error) { const versionRange = error ? errorParamsToUnsupportedVersionRange(error.params) : null; const messageTmpl = versionRange ? i18n._(`"%(fieldName)s" is not supported in manifest versions %(versionRange)s.`) : i18n._(`"%(fieldName)s" is not supported.`); const message = i18n.sprintf(messageTmpl, { fieldName, versionRange }); return { code: MANIFEST_FIELD_UNSUPPORTED, message, description: message, file: MANIFEST_JSON, }; } export const MANIFEST_FIELD_PRIVILEGED = 'MANIFEST_FIELD_PRIVILEGED'; export function manifestFieldPrivileged(error) { const messageTmpl = i18n._(`%(instancePath)s: privileged manifest fields are only allowed in privileged extensions.`); const message = i18n.sprintf(messageTmpl, { instancePath: error.instancePath, }); return { code: MANIFEST_FIELD_PRIVILEGED, message, description: PRIVILEGED_EXTENSION_SIGNING_DOCS, file: MANIFEST_JSON, }; } export const MANIFEST_PERMISSION_UNSUPPORTED = 'MANIFEST_PERMISSION_UNSUPPORTED'; export function manifestPermissionUnsupported(permissionName, error) { const versionRange = errorParamsToUnsupportedVersionRange(error.params); const messageTmpl = versionRange ? i18n._(`/%(fieldName)s: "%(permissionName)s" is not supported in manifest versions %(versionRange)s.`) : i18n._(`/%(fieldName)s: "%(permissionName)s" is not supported.`); const message = i18n.sprintf(messageTmpl, { permissionName, versionRange, fieldName: error.instancePath.match(PERMS_DATAPATH_REGEX)[1], }); return { code: MANIFEST_PERMISSION_UNSUPPORTED, message, description: message, file: MANIFEST_JSON, }; } export const MANIFEST_BAD_PERMISSION = { code: 'MANIFEST_BAD_PERMISSION', message: i18n._('The permission type is unsupported.'), description: i18n._(`See https://mzl.la/1R1n1t0 (MDN Docs) for more information.`), file: MANIFEST_JSON, }; export const MANIFEST_BAD_OPTIONAL_PERMISSION = { code: 'MANIFEST_BAD_OPTIONAL_PERMISSION', message: i18n._('The permission type is unsupported.'), description: i18n._(`See https://mzl.la/2Qn0fWC (MDN Docs) for more information.`), file: MANIFEST_JSON, }; export const MANIFEST_BAD_HOST_PERMISSION = { code: 'MANIFEST_BAD_HOST_PERMISSION', message: i18n._('The permission type is unsupported.'), description: i18n._( 'See https://mzl.la/3Woeqv4 (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_PERMISSIONS = { code: 'MANIFEST_PERMISSIONS', message: i18n._('Unknown permission.'), description: i18n._( 'See https://mzl.la/1R1n1t0 (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_PERMISSIONS_PRIVILEGED = 'MANIFEST_PERMISSIONS_PRIVILEGED'; export function manifestPermissionsPrivileged(error) { const messageTmpl = i18n._(`%(instancePath)s: the following privileged permissions are only allowed in privileged extensions: %(privilegedPermissions)s.`); const message = i18n.sprintf(messageTmpl, { instancePath: error.instancePath, privilegedPermissions: JSON.stringify(error.params.privilegedPermissions), }); return { code: MANIFEST_PERMISSIONS_PRIVILEGED, message, description: PRIVILEGED_EXTENSION_SIGNING_DOCS, file: MANIFEST_JSON, }; } export const MANIFEST_OPTIONAL_PERMISSIONS = { code: 'MANIFEST_OPTIONAL_PERMISSIONS', message: i18n._('Unknown permission.'), description: i18n._( 'See https://mzl.la/2Qn0fWC (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_HOST_PERMISSIONS = { code: 'MANIFEST_HOST_PERMISSIONS', message: i18n._('Invalid host permission.'), description: i18n._( 'See https://mzl.la/3Woeqv4 (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_INSTALL_ORIGINS = { code: 'MANIFEST_INSTALL_ORIGINS', message: i18n._('Invalid install origin.'), description: i18n._(`Invalid install origin. A valid origin has - only - a scheme, hostname and optional port. See https://mzl.la/3TEbqbE (MDN Docs) for more information.`), file: MANIFEST_JSON, }; export const MANIFEST_VERSION_INVALID = { code: 'MANIFEST_VERSION_INVALID', message: i18n._( '"manifest_version" in the manifest.json is not a valid value' ), description: i18n._( 'See https://mzl.la/20PenXl (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_CSP = 'MANIFEST_CSP'; export function manifestCsp(property) { return { // Note: don't change this 'code' without updating addons-server first, as // it depends on it to detect add-ons with a custom content security policy. code: MANIFEST_CSP, message: i18n.sprintf( i18n._(`"%(property)s" allows remote code execution in manifest.json`), { property } ), description: i18n.sprintf( i18n._(`A custom "%(property)s" needs additional review.`), { property } ), file: MANIFEST_JSON, }; } export const MANIFEST_CSP_UNSAFE_EVAL = 'MANIFEST_CSP_UNSAFE_EVAL'; export function manifestCspUnsafeEval(property) { return { code: MANIFEST_CSP_UNSAFE_EVAL, message: i18n.sprintf( i18n._(`"%(property)s" allows 'eval', which has strong security and performance implications.`), { property } ), description: i18n._(`In most cases the same result can be achieved differently, therefore it is generally prohibited`), file: MANIFEST_JSON, }; } export const PROP_NAME_INVALID = { code: 'PROP_NAME_INVALID', message: i18n._( 'The "name" property must be a string with no leading/trailing whitespaces.' ), description: i18n._( 'See http://mzl.la/1STmr48 (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_UPDATE_URL = { code: 'MANIFEST_UPDATE_URL', message: i18n._('"update_url" is not allowed.'), description: i18n._(` "applications.gecko.update_url" or "browser_specific_settings.gecko.update_url" are not allowed for Mozilla-hosted add-ons.`), file: MANIFEST_JSON, }; export const MANIFEST_UNUSED_UPDATE = { code: 'MANIFEST_UNUSED_UPDATE', message: i18n._('The "update_url" property is not used by Firefox.'), description: i18n._(`The "update_url" is not used by Firefox in the root of a manifest; your add-on will be updated via the Add-ons site and not your "update_url". See: https://mzl.la/25zqk4O`), file: MANIFEST_JSON, }; export const STRICT_MAX_VERSION = { code: 'STRICT_MAX_VERSION', message: i18n._('"strict_max_version" not required.'), description: i18n._(`"strict_max_version" shouldn't be used unless the add-on is expected not to work with future versions of Firefox.`), file: MANIFEST_JSON, }; export function manifestPropMissing(property) { return { code: `PROP_${property.toUpperCase()}_MISSING`, message: i18n.sprintf( i18n._(`No "%(property)s" property found in manifest.json`), { property } ), description: i18n.sprintf(i18n._(`"%(property)s" is required`), { property, }), file: MANIFEST_JSON, }; } export const MANIFEST_ICON_NOT_FOUND = 'MANIFEST_ICON_NOT_FOUND'; export function manifestIconMissing(path) { return { code: MANIFEST_ICON_NOT_FOUND, message: i18n._( 'An icon defined in the manifest could not be found in the package.' ), description: i18n.sprintf( i18n._('Icon could not be found at "%(path)s".'), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_BACKGROUND_FILE_NOT_FOUND = 'MANIFEST_BACKGROUND_FILE_NOT_FOUND'; export function manifestBackgroundMissing(path, type) { return { code: MANIFEST_BACKGROUND_FILE_NOT_FOUND, legacyCode: null, message: type === 'script' ? i18n._( 'A background script defined in the manifest could not be found.' ) : i18n._( 'A background page defined in the manifest could not be found.' ), description: i18n.sprintf( type === 'script' ? i18n._('Background script could not be found at "%(path)s".') : i18n._('Background page could not be found at "%(path)s".'), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_CONTENT_SCRIPT_FILE_NOT_FOUND = 'MANIFEST_CONTENT_SCRIPT_FILE_NOT_FOUND'; export function manifestContentScriptFileMissing(path, type) { return { code: MANIFEST_CONTENT_SCRIPT_FILE_NOT_FOUND, legacyCode: null, message: type === 'script' ? i18n._('A content script defined in the manifest could not be found.') : i18n._( 'A content script css file defined in the manifest could not be found.' ), description: i18n.sprintf( type === 'script' ? i18n._( 'Content script defined in the manifest could not be found at "%(path)s".' ) : i18n._( 'Content script css file defined in the manifest could not be found at "%(path)s".' ), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_DICT_NOT_FOUND = 'MANIFEST_DICT_NOT_FOUND'; export function manifestDictionaryFileMissing(path) { return { code: MANIFEST_DICT_NOT_FOUND, legacyCode: null, message: i18n._( 'A dictionary file defined in the manifest could not be found.' ), description: i18n.sprintf( i18n._( 'Dictionary file defined in the manifest could not be found at "%(path)s".' ), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_MULTIPLE_DICTS = { code: 'MANIFEST_MULTIPLE_DICTS', legacyCode: null, message: i18n._('The manifest contains multiple dictionaries.'), description: i18n._( 'Multiple dictionaries were defined in the manifest, which is unsupported.' ), file: MANIFEST_JSON, }; export const MANIFEST_EMPTY_DICTS = { code: 'MANIFEST_EMPTY_DICTS', legacyCode: null, message: i18n._( 'The manifest contains a dictionaries object, but it is empty.' ), description: i18n._( 'A dictionaries object was defined in the manifest, but it was empty.' ), file: MANIFEST_JSON, }; export const MANIFEST_DICT_MISSING_ID = { code: 'MANIFEST_DICT_MISSING_ID', legacyCode: null, message: i18n._('The manifest contains a dictionary but no id property.'), description: i18n._( 'A dictionary was found in the manifest, but there was no id set.' ), file: MANIFEST_JSON, }; // https://github.com/mozilla/addons-linter/issues/1650 // Potentially temporary export const MANIFEST_INVALID_CONTENT = { code: 'MANIFEST_INVALID_CONTENT', message: i18n._('Forbidden content found in add-on.'), description: i18n._('This add-on contains forbidden content.'), file: MANIFEST_JSON, }; export const ICON_NOT_SQUARE = 'ICON_NOT_SQUARE'; export function iconIsNotSquare(path) { return { code: ICON_NOT_SQUARE, message: i18n._('Icons must be square.'), description: i18n.sprintf(i18n._('Icon at "%(path)s" must be square.'), { path, }), file: MANIFEST_JSON, }; } export const ICON_SIZE_INVALID = 'ICON_SIZE_INVALID'; export function iconSizeInvalid({ path, expected, actual }) { return { code: ICON_SIZE_INVALID, message: i18n._('The size of the icon does not match the manifest.'), description: i18n.sprintf( i18n._(` Expected icon at "%(path)s" to be %(expected)d pixels wide but was %(actual)d. `), { path, expected, actual } ), file: MANIFEST_JSON, }; } export const CORRUPT_ICON_FILE = 'CORRUPT_ICON_FILE'; export function corruptIconFile({ path }) { return { code: CORRUPT_ICON_FILE, message: i18n._('Corrupt image file'), description: i18n.sprintf( i18n._('Expected icon file at "%(path)s" is corrupted'), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_FIELD_DEPRECATED = { code: 'MANIFEST_FIELD_DEPRECATED', message: i18n._('This property has been deprecated.'), description: null, file: MANIFEST_JSON, }; export const MANIFEST_THEME_LWT_ALIAS = { code: 'MANIFEST_THEME_LWT_ALIAS', message: i18n._('This theme LWT alias has been removed in Firefox 70.'), description: i18n._( 'See https://mzl.la/2T11Lkc (MDN Docs) for more information.' ), file: MANIFEST_JSON, }; export const MANIFEST_THEME_IMAGE_NOT_FOUND = 'MANIFEST_THEME_IMAGE_NOT_FOUND'; export function manifestThemeImageMissing(path, type) { return { code: MANIFEST_THEME_IMAGE_NOT_FOUND, message: i18n.sprintf( 'Theme image for "%(type)s" could not be found in the package', { type } ), description: i18n.sprintf( i18n._('Theme image for "%(type)s" could not be found at "%(path)s"'), { path, type } ), file: MANIFEST_JSON, }; } export const MANIFEST_THEME_IMAGE_CORRUPTED = 'MANIFEST_THEME_IMAGE_CORRUPTED'; export function manifestThemeImageCorrupted({ path }) { return { code: MANIFEST_THEME_IMAGE_CORRUPTED, message: i18n._('Corrupted theme image file'), description: i18n.sprintf( i18n._('Theme image file at "%(path)s" is corrupted'), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_THEME_IMAGE_WRONG_EXT = 'MANIFEST_THEME_IMAGE_WRONG_EXT'; export function manifestThemeImageWrongExtension({ path }) { return { code: MANIFEST_THEME_IMAGE_WRONG_EXT, message: i18n._('Theme image file has an unsupported file extension'), description: i18n.sprintf( i18n._( 'Theme image file at "%(path)s" has an unsupported file extension' ), { path } ), file: MANIFEST_JSON, }; } export const MANIFEST_THEME_IMAGE_WRONG_MIME = 'MANIFEST_THEME_IMAGE_WRONG_MIME'; export function manifestThemeImageWrongMime({ path, mime }) { return { code: MANIFEST_THEME_IMAGE_WRONG_MIME, message: i18n._('Theme image file has an unsupported mime type'), description: i18n.sprintf( i18n._( 'Theme image file at "%(path)s" has the unsupported mime type "%(mime)s"' ), { path, mime } ), file: MANIFEST_JSON, }; } export const MANIFEST_THEME_IMAGE_MIME_MISMATCH = 'MANIFEST_THEME_IMAGE_MIME_MISMATCH'; export function manifestThemeImageMimeMismatch({ path, mime }) { return { code: MANIFEST_THEME_IMAGE_MIME_MISMATCH, message: i18n._( 'Theme image file mime type does not match its file extension' ), description: i18n.sprintf( i18n._( 'Theme image file extension at "%(path)s" does not match its actual mime type "%(mime)s"' ), { path, mime } ), file: MANIFEST_JSON, }; } export const PROP_NAME_MISSING = manifestPropMissing('name'); export const NO_MESSAGES_FILE = { code: 'NO_MESSAGES_FILE', message: i18n._('The "default_locale" is missing localizations.'), description: i18n._(`The "default_locale" value is specified in the manifest, but no matching "messages.json" in the "_locales" directory exists. See: https://mzl.la/2hjcaEE`), file: MANIFEST_JSON, }; export const NO_DEFAULT_LOCALE = { code: 'NO_DEFAULT_LOCALE', message: i18n._('The "default_locale" is missing but "_locales" exist.'), description: i18n._(`The "default_locale" value is not specifed in the manifest, but a "_locales" directory exists. See: https://mzl.la/2hjcaEE`), file: MANIFEST_JSON, }; export const WRONG_ICON_EXTENSION = { code: 'WRONG_ICON_EXTENSION', message: i18n._('Unsupported image extension'), description: i18n._( 'Icons should be one of JPG/JPEG, WebP, GIF, PNG or SVG.' ), file: MANIFEST_JSON, }; export const IGNORED_APPLICATIONS_PROPERTY = { code: 'IGNORED_APPLICATIONS_PROPERTY', message: i18n._( '"applications" property overridden by "browser_specific_settings" property' ), description: i18n._( `The "applications" property is being ignored because it is superseded by the "browser_specific_settings" property which is also defined in your manifest. Consider removing applications.` ), file: MANIFEST_JSON, }; export const NO_MESSAGES_FILE_IN_LOCALES = 'NO_MESSAGES_FILE_IN_LOCALES'; export function noMessagesFileInLocales(path) { return { code: NO_MESSAGES_FILE_IN_LOCALES, message: i18n._('Empty language directory'), description: i18n.sprintf( i18n._('messages.json file missing in "%(path)s"'), { path } ), file: MANIFEST_JSON, }; } export const KEY_FIREFOX_UNSUPPORTED_BY_MIN_VERSION = 'KEY_FIREFOX_UNSUPPORTED_BY_MIN_VERSION'; export function keyFirefoxUnsupportedByMinVersion( key, minVersion, versionAdded ) { return { code: KEY_FIREFOX_UNSUPPORTED_BY_MIN_VERSION, message: i18n._( 'Manifest key not supported by the specified minimum Firefox version' ), description: i18n.sprintf( i18n._(`"strict_min_version" requires Firefox %(minVersion)s, which was released before version %(versionAdded)s introduced support for "%(key)s".`), { key, minVersion, versionAdded } ), file: MANIFEST_JSON, }; } export const PERMISSION_FIREFOX_UNSUPPORTED_BY_MIN_VERSION = 'PERMISSION_FIREFOX_UNSUPPORTED_BY_MIN_VERSION'; export function permissionFirefoxUnsupportedByMinVersion( key, minVersion, versionAdded ) { return { code: PERMISSION_FIREFOX_UNSUPPORTED_BY_MIN_VERSION, message: i18n._( 'Permission not supported by the specified minimum Firefox version' ), description: i18n.sprintf( i18n._(`"strict_min_version" requires Firefox %(minVersion)s, which was released before version %(versionAdded)s introduced support for "%(key)s".`), { key, minVersion, versionAdded } ), file: MANIFEST_JSON, }; } export const KEY_FIREFOX_ANDROID_UNSUPPORTED_BY_MIN_VERSION = 'KEY_FIREFOX_ANDROID_UNSUPPORTED_BY_MIN_VERSION'; export function keyFirefoxAndroidUnsupportedByMinVersion( key, minVersion, versionAdded ) { return { code: KEY_FIREFOX_ANDROID_UNSUPPORTED_BY_MIN_VERSION, message: i18n._( 'Manifest key not supported by the specified minimum Firefox for Android version' ), description: i18n.sprintf( i18n._(`"strict_min_version" requires Firefox for Android %(minVersion)s, which was released before version %(versionAdded)s introduced support for "%(key)s".`), { key, minVersion, versionAdded } ), file: MANIFEST_JSON, }; } export const PERMISSION_FIREFOX_ANDROID_UNSUPPORTED_BY_MIN_VERSION = 'PERMISSION_FIREFOX_ANDROID_UNSUPPORTED_BY_MIN_VERSION'; export function permissionFirefoxAndroidUnsupportedByMinVersion( key, minVersion, versionAdded ) { return { code: PERMISSION_FIREFOX_ANDROID_UNSUPPORTED_BY_MIN_VERSION, message: i18n._( 'Permission not supported by the specified minimum Firefox for Android version' ), description: i18n.sprintf( i18n._(`"strict_min_version" requires Firefox for Android %(minVersion)s, which was released before version %(versionAdded)s introduced support for "%(key)s".`), { key, minVersion, versionAdded } ), file: MANIFEST_JSON, }; } export const RESTRICTED_HOMEPAGE_URL = { code: 'RESTRICTED_HOMEPAGE_URL', message: i18n._('Linking to "addons.mozilla.org" is not allowed'), description: i18n._( 'Links directing to "addons.mozilla.org" are not allowed to be used for homepage' ), file: MANIFEST_JSON, }; export const RESTRICTED_PERMISSION = 'RESTRICTED_PERMISSION'; export const makeRestrictedPermission = (permission, minFirefoxVersion) => { return { code: RESTRICTED_PERMISSION, message: i18n.sprintf( i18n._(`The "%(permission)s" permission requires "strict_min_version" to be set to "%(minFirefoxVersion)s" or above`), { permission, minFirefoxVersion } ), description: i18n.sprintf( i18n._(`The "%(permission)s" permission requires "strict_min_version" to be set to "%(minFirefoxVersion)s" or above. Please update your manifest.json version to specify a minimum Firefox version.`), { permission, minFirefoxVersion } ), file: MANIFEST_JSON, }; }; export const EXTENSION_ID_REQUIRED = { code: 'EXTENSION_ID_REQUIRED', message: i18n._( 'The extension ID is required in Manifest Version 3 and above.' ), description: i18n._('See https://mzl.la/3PLZYdo for more information.'), file: MANIFEST_JSON, }; export const PRIVILEGED_FEATURES_REQUIRED = 'PRIVILEGED_FEATURES_REQUIRED'; export function privilegedFeaturesRequired(error) { const messageTmpl = i18n._( `%(instancePath)s: Privileged extensions should declare privileged permissions.` ); const message = i18n.sprintf(messageTmpl, { instancePath: error.instancePath, }); return { code: PRIVILEGED_FEATURES_REQUIRED, message, description: i18n._(` This extension does not declare any privileged permission. It does not need to be signed with the privileged certificate. Please upload it directly to https://addons.mozilla.org/. `), file: MANIFEST_JSON, }; } export const MOZILLA_ADDONS_PERMISSION_REQUIRED = 'MOZILLA_ADDONS_PERMISSION_REQUIRED'; export function mozillaAddonsPermissionRequired(error) { const messageTmpl = error.instancePath === '/permissions' ? i18n._( `%(instancePath)s: The "mozillaAddons" permission is required for privileged extensions.` ) : i18n._( `%(instancePath)s: The "mozillaAddons" permission is required for extensions that include privileged manifest fields.` ); const message = i18n.sprintf(messageTmpl, { instancePath: error.instancePath, }); return { code: MOZILLA_ADDONS_PERMISSION_REQUIRED, message, description: error.instancePath === '/permissions' ? i18n._( `This extension does not include the "mozillaAddons" permission, which is required for privileged extensions.` ) : message, file: MANIFEST_JSON, }; } export const HIDDEN_NO_ACTION = { code: 'HIDDEN_NO_ACTION', message: i18n._('Cannot use actions in hidden add-ons.'), description: i18n._(`The hidden and browser_action/page_action (or action in Manifest Version 3 and above) properties are mutually exclusive.`), file: MANIFEST_JSON, }; export const APPLICATIONS_DEPRECATED = { code: 'APPLICATIONS_DEPRECATED', message: i18n._('Use "browser_specific_settings" instead of "applications".'), description: i18n._(`The "applications" property in the manifest is deprecated and will no longer be accepted in Manifest Version 3 and above.`), file: MANIFEST_JSON, }; export const APPLICATIONS_INVALID = { code: 'APPLICATIONS_INVALID', message: i18n._(`"applications" is no longer allowed in Manifest Version 3 and above.`), description: i18n._(`The "applications" property in the manifest is no longer allowed in Manifest Version 3 and above. Use "browser_specific_settings" instead.`), file: MANIFEST_JSON, }; export const VERSION_FORMAT_DEPRECATED = { code: 'VERSION_FORMAT_DEPRECATED', message: i18n._(`The version string should be simplified because it won't be compatible with Manifest Version 3 and above.`), description: i18n._(`The version should be a string with 1 to 4 numbers separated with dots. Each number should have up to 9 digits and leading zeros will no longer be allowed. Letters will no longer be allowed either. See https://mzl.la/3h3mCRu (MDN Docs) for more information.`), file: MANIFEST_JSON, }; export const VERSION_FORMAT_INVALID = { code: 'VERSION_FORMAT_INVALID', message: i18n._('The version string should be simplified.'), description: i18n._(`The version should be a string with 1 to 4 numbers separated with dots. Each number should have up to 9 digits and leading zeros are not allowed. Letters are no longer allowed. See https://mzl.la/3h3mCRu (MDN Docs) for more information.`), file: MANIFEST_JSON, }; export const INCOGNITO_SPLIT_UNSUPPORTED = { code: 'INCOGNITO_SPLIT_UNSUPPORTED', message: i18n._('incognito "split" is unsupported.'), description: i18n._(`The incognito "split" value is unsupported and will be treated as "not_allowed" in Firefox. Remove the key from the manifest file, if your extension is compatible with Firefox's private browsing mode.`), file: MANIFEST_JSON, }; export const ADMIN_INSTALL_ONLY_PROP_RESERVED = { code: 'ADMIN_INSTALL_ONLY_PROP_RESERVED', message: i18n._('The "admin_install_only" property is reserved.'), description: i18n._(`The "admin_install_only" property is reserved and can only be used in enterprise add-ons.`), file: MANIFEST_JSON, }; export const ADMIN_INSTALL_ONLY_REQUIRED = { code: 'ADMIN_INSTALL_ONLY_REQUIRED', message: i18n._(`"/browser_specific_settings/gecko/admin_install_only" property must be set to "true".`), description: i18n._(`The "admin_install_only" property must be set to "true" in an enterprise add-on.`), file: MANIFEST_JSON, }; export const DATA_COLLECTION_PERMISSIONS_PROP_RESERVED = { code: 'DATA_COLLECTION_PERMISSIONS_PROP_RESERVED', message: i18n._('The "data_collection_permissions" property is reserved.'), description: i18n._(`The "data_collection_permissions" property is reserved for future usage and cannot be used in an extension at the moment.`), file: MANIFEST_JSON, };