-
Notifications
You must be signed in to change notification settings - Fork 6
How the plugin works
Let's first discuss what happens when Composer is downloading package metadata.
Just before it downloads a metadata file, Composer dispatches a PreFileDownload
event, which the plugin intercepts. If the repository concerned is TUF-protected, then the URL is processed into a TUF target identifier (for example, https://repo.url/targets/packages.json
will become, simply, packages.json
). The plugin then passes that identifier to PHP-TUF and asks it to verify that it's a known target. If it is, the plugin asks TUF what the file's expected size is in bytes, and tells Composer to limit the download size to that. (This prevents certain kinds of DOS attacks.)
Immediately after the metadata file is downloaded, Composer dispatches a PostFileDownload
event. The plugin will once again use the URL to determine a TUF target identifier, then ask TUF to verify that the downloaded data actually matches the hashes TUF knows about. If that check fails, TUF will rightfully throw an exception and that's that. Job well done.
When downloading an actual package (i.e., a ZIP archive or similar), the flow is nearly identical. The only difference is the way the plugin determines the package's TUF identifier. Because the packages could legitimately come from anywhere on the Internet, the URL is pretty much useless for this purpose. Instead, the plugin uses the following format to identify a package to TUF: VENDOR/PACKAGE_NAME/NORMALIZED_VERSION
. For example, symfony/http-foundation/6.2.1.0
.
The normalized version should be what you get when you pass the human-readable version through \Composer\Semver\VersionParser::normalize()
. Note that, for dev packages (e.g., symfony/http-foundation:6.2.x-dev
), dev-6.2.x
normalizes to dev-6.2.x
, whereas 6.2.x-dev
becomes 6.2.9999999.9999999-dev
. Composer internally uses the second form, so you should identify dev packages to TUF like so: symfony/http-foundation/6.2.9999999.9999999-dev
.
What that means is that the TUF metadata needs to have a target called (to use the previous example) symfony/http-foundation/6.2.1.0
. It doesn't need to correspond to a real physical file, but it DOES need to correspond to a set of hashes that TUF knows about (which can then be compared against a downloaded file). Each and every version of every package available in the Composer repository needs to be known to TUF in this way.