Confirmed users
920
edits
LesOrchard (talk | contribs) (Created page with 'Building a service to help keep plugins up to date is hard. __TOC__ == Browser identification == The first step in the process is identifying the user's browser. This consist…') |
LesOrchard (talk | contribs) No edit summary |
||
Line 7: | Line 7: | ||
of determining values for the following properties: | of determining values for the following properties: | ||
; appID : A unique identifier for the browser application (eg. {ec8030f7-c20a-464f-9b0e-13a3a9e97384}, Safari) | ; appID : A unique identifier for the browser application (eg. <code>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</code> for Firefox, <code>Safari</code> for Safari) | ||
; appRelease : The official release version number for the browser (eg. 3.5.8, 4.0.4) | ; appRelease : The official release version number for the browser (eg. 3.5.8, 4.0.4) | ||
; appVersion : A more specific indicator of the release build (eg. 20100202, 531.21.10) | ; appVersion : A more specific indicator of the release build (eg. 20100202, 531.21.10) | ||
; clientOS : An identifier describing the OS on which the browser runs (eg. Intel Mac OS X 10.6) | ; clientOS : An identifier describing the OS on which the browser runs (eg. Windows NT 6.1, Linux i686, Intel Mac OS X 10.6) | ||
; | ; chromeLocale : The primary locale / language chosen by the user (eg. en-US, zn-CH) | ||
Although most plugins are compatible with a wide range of values for the above | Although most plugins are compatible with a wide range of values for the above | ||
Line 37: | Line 37: | ||
You might notice that this list is missing a few particularly useful details: | You might notice that this list is missing a few particularly useful details: | ||
=== No GUIDs or UUIDs === | === No reliable GUIDs or UUIDs === | ||
There is no unique identifier, such as a GUID or UUID. | There is no reliable unique identifier, such as a GUID or UUID. | ||
This means that we'll need to use a combination of all of | This means that we'll need to use a combination of all of the above properties | ||
to uniquely identify a plugin, any of which has the potential to change between | to uniquely identify a plugin, any of which has the potential to change between | ||
plugin versions. | plugin versions. | ||
For example | For example: The Adobe Flash plugin has gone through many changes throughout | ||
changes throughout its lifespan, both through changes in the name of the product | its lifespan, both through changes in the name of the product itself to the | ||
itself to the acquisition of Macromedia by Adobe. | acquisition of Macromedia by Adobe. | ||
=== Version is not directly exposed === | === Version is not directly exposed, scraped from name / description === | ||
A version property is not | A version property for plugins is not exposed by most browsers in | ||
<code>navigator.plugins</code>. | <code>navigator.plugins</code>. | ||
Most plugins include some expression of a version in the name or | |||
description, this version does not always exactly match the '''fully | description. But, this version does not always exactly match the | ||
qualified version''' of the plugin. | '''fully qualified version number''' of the plugin. Thus, there can be some | ||
discrepancy or fuzziness in version detection. | |||
For example, use the '''Tools > Add-ons''' menu in Firefox to open the Add-ons dialog | For example, use the '''Tools > Add-ons''' menu in Firefox to open the Add-ons dialog | ||
and view the Plugins tab. If you have "Shockwave Flash" installed, you may see | and view the Plugins tab. If you have "Shockwave Flash" installed, you may see | ||
it reported as version 10.0.45.2. | it reported as version 10.0.45.2. However, this version is not usually available via | ||
<code>navigator.plugins</code>. Instead, client-side detection code has to | |||
inspect the name or description - which lists the version as "10.0 r45". | |||
So, suppose that there were two releases of Flash - say, versions 10.0.45.2 and | |||
10.0.45.6. Now suppose that they both listed "10.0 r45" as the version in the | |||
description. Since client-side code can't see the real '''fully qualified version number''' | |||
for either plugin, it can't tell a difference between the two. And, if it can't | |||
tell a difference, then there's no way to decide whether an upgrade is advisable. | |||
In practice, the Adobe Flash plugin in particular tends to update that version in | |||
the description between siginificant updates - but not all plugins do. So, plugin | |||
version detection can be problematic and imprecise. | |||
And, what's worse: Some plugins don't include a version number at all in either | And, what's worse: Some plugins don't include a version number at all, in either | ||
the name or description. In this case, there's not much we can do besides shrug | the name or description. In this case, there's not much we can do besides shrug | ||
and report the version as undetectable. | and report the version as undetectable. | ||
Firefox 3.6 and above ''does'' offer a | On the bright side, Firefox 3.6 and above ''does'' offer a version property in | ||
<code>navigator.plugins</code>, which reflects the '''fully qualified version number''' | |||
as seen in the Add-ons dialog. In this case, we can detect plugin versions with | |||
great certainty. Hopefully more browsers follow suit in this, and the plugin | |||
version detection story will get better. | |||
== Server-side plugin search == | |||
One of the [[Plugins:PluginDirectory#Goals|goals of the Plugin Directory]] is | |||
to provide a service allowing clients to check whether installed plugins are | |||
up-to-date or in need of an upgrade, by performing a search on directory data. | |||
The first thing the service requires are all the details revealed by | |||
[[Plugins:PluginDirectory/HowPluginDetectionWorks#Browser_identification|browser identification]]. | |||
This allows the search to be restricted to just those plugins asserting | |||
compatibility with the user's browser. | |||
The second thing the service requires are details revealed by the | |||
[[Plugins:PluginDirectory/HowPluginDetectionWorks#Client_plugin_scan|client plugin scan]]. | |||
One of the most unique properties of a plugin is the set of MIME types it | |||
claims to handle, so sending that along will further restrict the search | |||
to plugins that likely contain a given installed plugin. | |||
(By the way: While it might be useful to send along other details - such as name, | |||
description, or filename - these change more often than the set of MIME types, | |||
and don't actually help narrow down the search enough to be worth the trouble.) | |||
=== PFS2 search API === | |||
The above is a plain-language description of [[PFS2#Request_Parameters|the PFS2 search API]]. | |||
This is a simple HTTP GET service which responds with a JSON data structure, given | |||
the following URL parameters: | |||
; <tt>mimetype</tt> : A space-separated list of mimetypes for a plugin. (Note: space can be encoded as <tt>+</tt> in URLs.) | |||
; <tt>detection</tt> : An identifier for the form of version detection available to the client (eg. 'original' for name/description scraping, 'version_available' for Fx 3.6 and above where a real version is available) | |||
; <tt>clientOS</tt> : The client's OS (eg. <tt>navigator.oscpu</tt>, "Windows NT 5.1", "Intel Mac OS X 10.5") | |||
; <tt>chromeLocale</tt> : The client's locale (eg. <tt>navigator.language</tt>) | |||
; <tt>appID</tt> : The client's app ID (eg. Firefox is "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}") | |||
; <tt>appRelease</tt> : Client app release version (eg. "3.5.3") | |||
; <tt>appVersion</tt> : Client's application build version (eg. "20090824085414") | |||
; <tt>callback</tt> : Function wrapper for JSON output, (see also: [http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/ JSONP technique]) | |||
==== Example PFS2 request / response ==== | |||
So, suppose you wanted to search for the Flash plugin. On the | |||
Plugin Directory staging server, you could perform an HTTP GET like the following, | |||
using cURL (line breaks added for clarity): | |||
curl -s 'http://plugins.stage.mozilla.com/en-us/pfs/v2? | |||
appID=%7Bec8030f7-c20a-464f-9b0e-13a3a9e97384%7D& | |||
appRelease=3.5.8& | |||
appVersion=20100202152834& | |||
clientOS=Intel+Mac+OS+X+10.6& | |||
chromeLocale=en-US& | |||
detection=original& | |||
mimetype=application%2Fx-shockwave-flash+application%2Ffuturesplash' | |||
This might result in the following JSON, for example: | |||
[ | |||
{ | |||
"releases": { | |||
"others": [], | |||
"latest": { | |||
"app_release": "*", | |||
"fetched": "2010-02-18T19:06:27-08:00", | |||
"locale": "*", | |||
"app_id": "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}", | |||
"detection_type": "original", | |||
"guid": "{89977581-9028-4be0-b151-7c4f9bcd3211}", | |||
"xpi_location": "http://fpdownload.macromedia.com/get/flashplayer/xpi/current/flashplayer-mac.xpi", | |||
"pfs_id": "adobe-flash-player", | |||
"version": "10.0.32.0", | |||
"app_version": "*", | |||
"status": "latest", | |||
"os_name": "mac", | |||
"vendor": "Adobe", | |||
"detected_version": "10.0.32.0", | |||
"name": "Adobe Flash Player", | |||
"created": "2010-02-19T08:09:18+00:00", | |||
"url": "http://www.adobe.com/go/getflashplayer", | |||
"modified": "2010-02-19T08:11:10+00:00", | |||
"license_url": "http://www.adobe.com/go/eula_flashplayer" | |||
} | |||
}, | |||
"aliases": { | |||
"regex": [ | |||
".*Flash.*" | |||
], | |||
"literal": [ | |||
"Adobe Flash Player", | |||
"Shockwave Flash" | |||
] | |||
} | |||
} | |||
] | |||
A more detailed description of this exchange is available in | |||
[[PFS2#Plugin_release_descriptions|the wiki page on the PFS2 API]]. | |||
== Client-side plugin matching == | == Client-side plugin matching == | ||
A single search request is made to the PFS2 API for each plugin detected. | |||
Since multiple plugins can claim to handle the same set of MIME times passed | |||
to the search API, multiple plugin results may be returned. | |||
=== Plugin name matching via aliases === | |||
So, the next step is to look at each of these results and use the "aliases" | |||
data stucture to match against the detected plugin's name. If the name | |||
matches either one of the literal strings values, or one of the regular | |||
expressions, then that search result is paired up with the detected plugin. | |||
Note that this alias matching system helps account for name changes | |||
between plugin releases - eg. Shockwave Flash to Adobe Flash Player, as | |||
a hypothetical example. | |||
For example: Assume that a plugin named "QuickTime Plug-in" was detected, | |||
which claims to handle the MIME type "video/mpeg". | |||
In response to a search including a MIME type of "video/mpeg", the search API | |||
might respond with results including the plugins "VLC Multimedia Plug-in" and | |||
"QuickTime Plug-in". We can use the aliases of the "QuickTime Plug-in" result | |||
to pair it up with our detected plugin, and go from there. | |||
=== Version comparison === | |||
Once we have a search result paired with a detected installed plugin, we can | |||
perform version comparisons. | |||
For quick access, the latest release of a plugin is pulled out of the general | |||
list of plugin releases known by the directory. A comparison between this | |||
release and the detected plugin can result in one of the following results: | |||
; current : The installed plugin is the up-to-date with respect to the directory | |||
; newer : The installed plugin appears to be newer than what the directory knows about | |||
; should_disable : The installed plugin matches the latest known version, but that version has a known vulnerability and should be disabled until an update is made available. | |||
; maybe_outdated: Version detection for this plugin is imprecise, and matches both the latest version as well as a version known to be out of date. Manual inspection is advised. | |||
; maybe_vulnerable : Version detection for this plugin is imprecise, and matches both the latest version as well as a version with a known vulnerability. Manual inspection is advised. | |||
If the installed plugin doesn't match or exceed the version of the latest known | |||
release, then we know an upgrade is advised. But, we want to report on the | |||
urgency of the upgrade. | |||
So, we step through the other known releases, looking | |||
for vulnerable versions. This will then result in one of the following | |||
status flags: | |||
; outdated : The installed plugin should be upgraded, but is not an immediate danger | |||
; vulnerable : The installed plugin matches a version with a known vulnerability, and should be updated immediately |