Isolated Web Apps load resources from a Web Bundle that is stored on the user’s computer rather than from a server. This design necessitates a system for determining when a new version of that Web Bundle should be downloaded.
The Web Application Manifest for an Isolated Web App will include two new fields related to updates,
- the
version
field allows the app publisher to identify a Web Bundle as containing a particular version of the application - the
update_manifest_url
field tells the user agent where to look for updated versions of the application
The resource served at the update_manifest_url
is a JSON document listing versions of the application that are available and the URL from which the Web Bundle containing that version can be downloaded. It also specifies which Update Channels each version is part of.
In order to check for updates the user agent follows the following steps,
- Fetch the resource from
update_manifest_url
and parse it as a JSON document. - Let selectedVersion and selectedSrc be initialized to
null
. - Let updateChannel be the identifier of the Update Channel the installed app is subscribed to.
- For each object in the document’s
versions
entry,- Let version be the object’s
version
field, skipping this item if the field does not exist. - Let src be the object’s
src
field, skipping this item if the field does not exist. - Let channels be the object’s
channels
field, defaulting to a list with a single element nameddefault
(["default"]
) if the field does not exist. - If version is not a valid version identifier or src is not a valid URL or channels is not a list of valid channel identifiers, skip this item.
- If channels does not include updateChannel, skip this item.
- If selectedVersion is
null
or selectedVersion is less than or equal to version, set selectedVersion to version and selectedSrc to src.
- Let version be the object’s
- If selectedVersion is
null
, abort these steps. - If selectedVersion is less than or equal to the currently installed version, abort these steps.
- Fetch the resource from selectedSrc.
- If the resource is not a valid Signed Web Bundle, abort these steps.
- If the Web Bundle ID of the resource is not equal to that of the currently installed app, abort these steps.
- Load
/.well-known/manifest.webmanifest
from the Web Bundle and parse it as a Web Application Manifest. - If the resource is not found or fails to parse, abort these steps.
- If the
version
field in the manifest from the Web Bundle is not equal to selectedVersion, abort these steps. - Replace the Web Bundle for the current installed app with the downloaded resource.
The version
field contains a string indicating the version of the application. This field is only used and mandatory for Isolated Web Apps, but has no meaning for normal Web Applications. For the purposes of updating version numbers only need to be ordered. For example, a plain integer versioning scheme (e.g. 1, 2, 3, etc.) would be sufficient however for ease of use and to provide for more complex comparisons to be performed on versions a structured format such as “A.B.C.D”, where A, B, C and D are positive integers (or zero) is much more useful. A format such as Semantic Versioning could also be adopted as it provides even more expressivity.
Whatever the structure of the version string, a comparison algorithm must be defined so that sorting of and comparisons between versions can be performed in the algorithms defined in this specification. Lexical comparison between version strings is inappropriate.
The optional update_manifest_url
field indicates the location where the Web Application Update Manifest can be found. It must be an absolute HTTPS URL, or for testing purposes a localhost HTTP URL.
The Web Application Update Manifest is a document listing all application versions available for download. It consists of a single JSON object with a field called versions
which is a list. Each entry in the list is an object containing at least two fields, version
and src
. The version
field is a string in the same format as the proposed Web Application Manifest version
field. The src
field is a URL and is resolved relative to the location of the manifest. It must be an HTTPS URL or a localhost HTTP URL, for testing purposes. The optional channels
field, if present, is a list of strings representing Update Channel identifiers. If it is not set, it is treated as if it was set to ["default"]
.
For example, a manifest hosted at https://developer.example.com/app/updates.json
could contain,
{
"versions": [
{
"version": "5.2.17",
"src": "https://cdn.example.com/app-package-5.2.17.swbn"
},
{
"version": "5.7.19",
"src": "v5.7.19/package.swbn",
"channels": ["default"]
},
{
"version": "6.1.13",
"src": "v6.1.13/package.swbn",
"channels": ["default", "beta"]
},
{
"version": "7.0.6",
"src": "v7.0.6/package.swbn",
"channels": ["beta"]
},
{
"version": "7.0.99",
"src": "v7.0.99/package.swbn",
"channels": []
}
]
}
For forward compatibility, implementations MUST ignore keys they do not recognize. When multiple objects in the versions
have the same version
field the algorithm above selects the last instance to allow future versions to specify more precise matching rules based on currently undefined properties (e.g. package language).
Update Channels allow app developers to provide their users with multiple "Release Trains" to choose from. There is a n:m relationship between Update Channels and versions of an app. Each version can belong to multiple channels, and each channel can contain multiple versions. A version belonging to no channels (i.e., a version where channels
is set to []
), is never updated to.
An Update Channel is identified by its ID, which MUST be a non-empty string.
An implementation SHOULD give users the option to switch the Update Channel of an installed app. In enterprise contexts, implementations SHOULD give enterprise admins the option to select Update Channels for apps they install for their users.
It is up to the app developer to define the meaning of Update Channels:
- An app developer could use the
default
channel as their stable channel, but also have abeta
channel for users who want to test new features, and adev
channel for development previews. - An app developer could use channels to allow users to stay on an older version of the app, but still receive updates. For example, the developer could define a
2.x-LTS
channel, which users who want to keep using version 2.x of the app can switch to. This allows the app developer to simultaneously provide updates to users stuck on older versions of the app, while also providing updates to users on their newest app version.
Each Update Channel has a string-based identifier. An app developer can optionally define human-readable/translated names for their Update Channels. These names are defined in a separate, optional, top-level channels
field:
{
"channels": {
"4-lts": {
"name": "4.x LTS Releases",
// further future properties could go here
},
"default": {
"name": "Stable Releases",
// further future properties could go here
},
"alpha": {
// name missing, so it defaults to the ID ("alpha")
}
// entry for beta channel is missing, so its name defaults to its ID ("beta").
},
"versions": [
{
"version": "4.3.99",
"src": "https://example.com/4.3.99.swbn",
"channels": ["4-lts", "default", "beta", "alpha"],
}
// ...
],
}
(The comments are not valid JSON and only part of this example for illustration purposes.)
Update Channel names can be translated using the HTTP content negotiation mechanism. A user agent SHOULD send requests for Update Manifests with an Accept-Language
header based on the user's preferred languages. The server SHOULD use it to pick the best available language for Update Channel names, and respond with a localized Update Manifest file.
A significantly simpler solution which mimics how normal site resources are updated would be to have the Web Application Manifest link directly to a Web Bundle. The problem with this approach is that,
- Without version numbers it doesn’t provide robust protection against rollbacks, as the value of the Last-Modified header is not part of the Web Bundle.
- Enterprise administrators want the ability to control when new versions are rolled out, which requires multiple versions to be available at once. The update steps above could be augmented to filter available versions based on administrator-defined policy.
The Integrity Block prepended to a Web Bundle to form a Signed Web Bundle provides integrity for a single version of an application, however an application which can’t be updated is not useful and so this document proposes a mechanism for doing so. The security of this mechanism relies on the secrecy of the private key used to generate the Integrity Block in order to provide assurance that the real developer of the application has provided the new version of the Web Bundle and on the comparability of the proposed version field in the Web Application Manifest to provide rollback protections. While the Web Application Update Manifest must be delivered over HTTPS to provide some protection against network-based attackers it is insufficient to trust any Web Bundle loaded over HTTPS from the developer’s origin as the threat model for Isolated Web Apps includes the possibility for temporary compromise of the developer’s website.
The update algorithm requires fetching resources over the network and so care should be taken to do so in a privacy-preserving way. The first step is to ensure all fetches are done in credentialless mode. Even so, requesting the Web Application Update Manifest reveals the public IP addresses of any systems where an application is installed to a developer-controlled server. We can safely assume that when the application itself is launched it may also make network requests and so some privacy can be achieved by trying to match the frequency of update requests to how often the user actually uses the application to prevent an unused application from being used as a tracking vector. This must be balanced with ensuring that application updates are installed in a timely manner so that security vulnerabilities can be patched. A user agent could also request the manifest via a proxy service however this may prevent updates to internally-deployed applications which are not available outside of a private network.