Extension Features Files

Summary

The Extension features files specify the different requirements for extension feature availability.

An extension feature can be any component of extension capabilities. Most notably, this includes extension APIs, but there are also more structural or behavioral features, such as web accessible resources or event pages.

Files

There are four different feature files used:

  • _api_features: Specifies the requirements for API availability. If an extension doesn‘t satisfy the requirements, the API will not be accessible in the extension’s code.
  • _permission_features: Specifies the requirements for permission availability. If an extension doesn't satisfy the requirements, the permission will not be granted and the extension will have an install warning.
  • _manifest_features: Specifies the requirements for manifest entry availability. If an extension doesn't satisfy the requirements, the extension will fail to load with an error.
  • _behavior_features: Specifies the requirements for miscellaneous extension behaviors. This should typically not be used.

Note that these files may be present under chrome/common/extensions/api, as well as under extensions/common/api and extensions/shell/common/api.

Grammar

The feature files are written in JSON. Each file contains a single JSON object with properties for each feature.

{
  "feature1": <definition>,
  "feature2": <definition>,
  ...
}

Simple and Complex Features

Most features are known as “simple” features. These are features whose definition is a single object that contains the properties describing the criteria for availability. A simple feature might look like this:

"feature1": {
  "dependencies": ["permission:feature1"],
  "contexts": ["blessed_extension"]
}

feature1 has a single definition, which says for it to be available, a permission must be present and it must be executed from a blessed context. (These concepts are covered more later in this document.)

Features can also be “complex”. A complex feature has a list of objects to specify multiple groups of possible properties. A complex feature could look like this:

"feature1": [{
  "dependencies": ["permission:feature1"],
  "contexts": ["blessed_extension"]
}, {
  "dependencies": ["permission:otherPermission"],
  "contexts": ["blessed_extension", "unblessed_extension"]
}]

With complex features, if either of the definitions are matched, the feature is available (in other words, the feature definitions are logically OR'd together). Complex features should frequently be avoided, as it makes the logic more involved and slower.

Inheritance

By default, features inherit from parents. A feature‘s ancestry is specified by its name, where a child feature is the parent’s name followed by a ‘.’ and the child's name. That is, feature1.child is the child of feature1. Inheritance can carry for multiple levels (e.g. feature1.child.child), but this is rarely (if ever) useful.

A child feature inherits all the properties of its parent, but can choose to override them or add additional properties. Take the example:

"feature1": {
  "dependencies": ["permission:feature1"],
  "contexts": ["blessed_extension"]
},
"feature1.child": {
  "contexts": ["unblessed_extension"],
  "extension_types": ["extension"]
}

In this case, feature1.child will effectively have the properties

"dependencies": ["permission:feature1"], # inherited from feature1
"contexts": ["unblessed_extension"],     # inherited value overridden by child
"extension_types": ["extension]          # specified by child

If you don‘t want a child to inherit any features from the parent, add the property "noparent": true. This is useful if, for instance, you have a prefixed API name that isn’t dependent on the prefix, such as app.window (which is fully separate from the app API).

If the parent of a feature is a complex feature, the feature system needs to know which parent to inherit from. To do this, add the property "default_parent": true to one of the feature definitions in the parent feature.

Properties

The following properties are supported in the feature system.

alias

The alias property specifies that the feature has an associated alias feature. An alias feature is a feature that provides the same functionality as it's source feature (i.e. the feature referenced by the alias). For example, an API alias provides bindings for the source API under a different name. If one wanted to declare an API alias, they would have to introduce an API alias feature - defined as a feature that has source property, and set alias property on the original feature. For example, the following would introduce an API alias feature named featureAlias for API feature:

{
  "feature": {
    "contexts": ["blessed_extension"],
    "channel": "dev",
    "alias": "featureAlias"
  },
  "featureAlias": {
   "contexts": ["blessed_extension"],
   "channel": "dev",
   "source": "feature"
  }
}

featureAlias[source] value specifies that featureAlias is an alias for API feature feature

feature[alias] value specifies that feature API has an API alias featureAlias

When feature featureAlias is available, feature bindings would be accessible using feauteAlias. In other words chrome.featureAlias would point to an API with the bindings equivalent to the bindings of feature API.

The alias API will inherit the schema from the source API, but it will not respect the source API child features. To accomplish parity with the source API feature children, identical child features should be added for the alias API.

Note that to properly create an alias, both source property on the alias feature and alias property on the aliased feature have to be set.

Alias features are only available for API features, and each API can have at most one alias. For complex features, alias property will be set to the alias value of the first component simple feature that has it set.

blacklist

The blacklist property specifies a list of ID hashes for extensions that cannot access a feature. See ID Hashes in this document for how to generate these hashes.

Accepted values are lists of id hashes.

channel

The channel property specifies a maximum channel for the feature availability. That is, specifying dev means that the feature is available on dev, canary, and trunk.

Accepted values are a single string from trunk, canary, dev, beta, and stable.

command_line_switch

The command_line_switch property specifies a command line switch that must be present for the feature to be available.

Accepted values are a single string for the command line switch (without the preceeding ‘--’).

feature_flag

The feature_flag property specifies the name of a base::Feature flag that must be enabled for the feature to be available. This can be used to implement a remote kill switch for the feature. These feature flags should be defined at feature_flags.cc.

Accepted value is a single string for the feature flag.

component_extensions_auto_granted

The component_extensions_auto_granted specifies whether or not component extensions should be automatically granted access to the feature. By default, this is true.

The only accepted value is the bool false (since true is the default).

contexts

The contexts property specifies which JavaScript contexts can access the feature. All API features must specify at least one context, and only API features can specify contexts.

Accepted values are a list of strings from blessed_extension, blessed_web_page, content_script, extension_service_worker, lock_screen_extension, web_page, webui, webui_untrusted, and unblessed_extension.

The lock_screen_extension context is used instead of blessed_extension context for extensions on the Chrome OS lock screen. Other extensions related contexts (blessed_web_page, content_script, extension_service_worker, unblessed_extension) are not expected to be present on the lock screen.

default_parent

The default_parent property specifies a feature definition from a complex feature to be used as the parent for any children. See also Inheritance.

The only accepted value is the bool true.

dependencies

The dependencies property specifies which other features must be present in order to access this feature. This is useful so that you don't have to re-specify all the same properties on an API feature and a permission feature.

A common practice is to put as many restrictions as possible in the permission or manifest feature so that we warn at extension load, and put relatively limited properties in an API feature with a dependency on the manifest or permission feature.

To specify a dependent feature, use the prefix the feature name with the type of feature it is, followed by a colon. For example, in order to specify a dependency on a permission feature foo, we would add the dependency entry permission:foo.

Accepted values are lists of strings specifying the dependent features.

extension_types

The extension_types properties specifies the different classes of extensions that can use the feature. It is very common for certain features to only be allowed in certain extension classes, rather than available to all types.

Accepted values are lists of strings from extension, hosted_app, legacy_packaged_app, platform_app, shared_module, theme, and login_screen_extension.

location

The location property specifies the required install location of the extension.

Accepted values are a single string from component, external_component, policy, and unpacked.

internal

The internal property specifies whether or not a feature is considered internal to Chromium. Internal features are not exposed to extensions, and can only be used from Chromium code.

The only accepted value is the bool true.

matches

The matches property specifies url patterns which should be allowed to access the feature. Only API features may specify matches, and matches only make sense with a context of either webui or web_page.

Accepted values are a list of strings specifying the match patterns.

max_manifest_version

The max_manifest_version property specifies the maximum manifest version to be allowed to access a feature. Extensions with a greater manifest version cannot access the feature.

The only accepted value is 1, as currently the highest possible manifest version is 2.

min_manifest_version

The min_manifest_version property specifies the minimum manifest version to be allowed to access a feature. Extensions with a lesser manifest version cannot access the feature.

Accepted values are 2 and 3, as 3 is currently the highest possible manifest version.

noparent

The noparent property specifies that a feature should not inherit any properties from a derived parent. See also Inheritance.

The only accepted value is the bool true.

platforms

The platforms property specifies the properties the feature should be available on.

The accepted values are lists of strings from chromeos, mac, ‘lacros’, linux, and win.

session_types

The session_types property specifies in which types of sessions a feature should be available. The session type describes the type of user that is logged in the current session. Session types to which feature can be restricted are only supported on Chrome OS - features restricted to set of session types will be disabled on other platforms. Also, note that all currently supported session types imply that a user is logged into the session (i.e. features that use session_types property will be disabled when a user is not logged in).

The accepted values are lists of strings from regular, kiosk and kiosk.autolaunched.

regular session is a session launched for a regular, authenticated user.

kiosk session is a session launched for a kiosk app - an app that runs on its own, in full control of the current session.

kiosk.autolaunched represents auto-launched kiosk session - a kiosk session that is launched automatically from Chrome OS login screen, without any user interaction. Note that allowing kiosk session implies allowing kiosk.autolaunched session.

source

The source property specifies that the feature is an alias for the feature specified by the property value, and is only allowed for API features. For more information about alias features, see alias property documentation.

For complex features, source property will be set to the source value of the first component simple feature that has it set.

whitelist

The whitelist property specifies a list of ID hashes for extensions that are the only extensions allowed to access a feature.

Accepted values are lists of id hashes.

ID Hashes

Instead of listing the ID directly in the whitelist or blacklist section, we use an uppercased SHA1 hash of the id.

To generate a new whitelisted ID for an extension ID, do the following in bash:

$ echo -n "aaaabbbbccccddddeeeeffffgggghhhh" | \
     sha1sum | tr '[:lower:]' '[:upper:]'

(Replacing aaaabbbbccccddddeeeeffffgggghhhh with your extension ID.)

The output should be something like:

9A0417016F345C934A1A88F55CA17C05014EEEBA  -

Add the ID to the whitelist or blacklist for the desired feature. It is also often useful to link the crbug next to the id hash, e.g.:

"whitelist": [
  "9A0417016F345C934A1A88F55CA17C05014EEEBA"  // crbug.com/<num>
]

Google employees: please update http://go/chrome-api-whitelist to map hashes back to ids.

Feature Contexts

A Feature Context is the type of JavaScript context that a feature can be made available in. This allows us to restrict certain features to only being accessible in more secure contexts, or to expose features to contexts outside of extensions.

For each of these contexts, an “extension” context can refer to a context of either an app or an extension.

Blessed Extension Contexts

The blessed_extension context refers to a JavaScript context running from an extension process. These are typically the most secure JavaScript contexts, as it reduces the likelihood that a compromised web page renderer will have access to secure APIs.

Traditionally, only pages with a top-level extension frame (with a chrome-extension:// scheme), extension popups, and app windows were blessed extension contexts. With site isolation, extension frames running in web pages are also considered blessed extension contexts, since they are running in the extension process (rather than in the same process as the web page).

Blessed Web Page Contexts

The blessed_web_page context refers to a JavaScript context running from a hosted app. These are similar to blessed extension contexts in that they are (partially) isolated from other processes, but are typically more restricted than blessed extension processes, since hosted apps generally have fewer permissions. Note that these contexts are unaffected by the matches property.

Content Script Contexts

The content_script context refers to a JavaScript context for an extension content script. Since content scripts share a process with (and run on the same content as) web pages, these are considered very insecure contexts. Very few features should be exposed to these contexts.

Service Worker Contexts

The extension_service_worker context refers to a JavaScript context for an extension‘s service worker. An extension can only register a service worker for it’s own domain, and these should only be run within an extension process. Thus, these have similar privilege levels to blessed extension processes.

Web Page Contexts

The web_page context refers to a JavaScript context for a simple web page, completely separate from extensions. This is the least secure of all contexts, and very few features should be exposed to these contexts. When specifying this context, an accompanying URL pattern should be provided with the matches property.

WebUI Contexts

The webui context refers to a JavaScript context for a page with WebUI bindings, such as internal chrome pages like chrome://settings or chrome://extensions. These are considered secure contexts, since they are an internal part of chrome. When specifying this context, an accompanying URL pattern should be provided with the matches property.

Unblessed Extension Contexts

The unblessed_extension context refers to a JavaScript context for an extension frame that is embedded in an external page, like a web page, and runs in the same process as the embedder. Given the limited separation between the (untrusted) embedder and the extension frame, relatively few features are exposed in these contexts. Note that with site isolation, extension frames (even those embedded in web pages) run in the trusted extension process, and become blessed extension contexts.

Compilation

The feature files are compiled as part of the suite of tools in //tools/json_schema_compiler/. The output is a set of FeatureProviders that contain a mapping of all features.

In addition to being significantly more performant than parsing the JSON files at runtime, this has the added benefit of allowing us to validate at compile time rather than needing a unittest (or allowing incorrect features).

In theory, invalid features should result in a compilation failure; in practice, the compiler is probably missing some cases.

Still to come

TODO(devlin): Add documentation for extension types. Probably also more on requirements for individual features.