TUF JavaScript Client
tuf-js is a robust JavaScript and TypeScript implementation of The Update Framework (TUF), providing secure software update mechanisms against various supply chain attacks, including rollback, mix-and-match, and freeze attacks. The package is currently at version 5.0.1 and is actively maintained, demonstrating a consistent release cadence with patches and minor updates, and major versions released to align with Node.js LTS cycles and critical dependency upgrades. It adheres directly to the TUF specification, offering a client-side library for cryptographic signature verification, secure metadata fetching, and managing trust anchors. Key differentiators include its strong focus on security, TypeScript support, and its role as a reference implementation for TUF within the JavaScript ecosystem, ensuring resilient and verifiable software distribution. It is designed for use in environments requiring robust integrity checks for updates, operating on Node.js versions 20.17.0 or higher, or 22.9.0 or higher.
Common errors
-
ERR_REQUIRE_ESM
cause Attempting to import tuf-js (an ESM-first package) using CommonJS `require()` syntax.fixMigrate your project to use ES Modules (ESM) syntax (`import ... from 'tuf-js'`) and ensure your Node.js environment or bundler correctly handles ESM. -
Error: The client is configured for Node.js version X.Y.Z, which is not supported.
cause Running tuf-js v4.x or later on an unsupported Node.js version (e.g., Node.js 18 or older).fixUpgrade your Node.js runtime environment to version 20.17.0, 22.9.0, or newer. Check the `engines` field in `package.json` for exact requirements. -
Error: Signature verification failed for role 'root'
cause The initial `root.json` provided to the `TufClient` is invalid, corrupted, or does not match the repository's actual root metadata, leading to a failure in establishing the initial trust anchor.fixVerify the `initialRoot` metadata provided to the `TufClient` constructor. Ensure it is the correct, cryptographically valid root metadata for your TUF repository. -
Error: Target 'your-target-name' not found in repository metadata.
cause The specified target file name (`targetName`) does not exist in the latest verified `targets.json` metadata from the TUF repository, or the path is incorrect.fixConfirm the exact `targetName` by inspecting your TUF repository's `targets.json` or related delegated role metadata. Ensure the target has been published and its metadata is signed and updated in the repository.
Warnings
- breaking tuf-js v4.0.0 dropped support for Node.js 18. Applications must upgrade to Node.js 20.17.0, 22.9.0, or newer to continue using tuf-js v4 and above.
- breaking Starting with v4.0.0, the internal `make-fetch-happen` dependency was bumped from 14.x to 15.x. While generally backward compatible, this might introduce subtle behavioral changes or new requirements for network operations.
- gotcha tuf-js is an ESM-first package. Attempting to import it using CommonJS `require()` syntax will result in errors.
Install
-
npm install tuf-js -
yarn add tuf-js -
pnpm add tuf-js
Imports
- TufClient
const { TufClient } = require('tuf-js')import { TufClient } from 'tuf-js' - RemoteFetcher
import { Fetcher } from 'tuf-js' // Incorrect class nameimport { RemoteFetcher } from 'tuf-js' - Root
import { Root } from 'tuf-js' // Root model is in @tufjs/modelsimport { Root } from '@tufjs/models' - InMemoryStorage
import { InMemoryStorage } from 'tuf-js' // Not exported directly by tuf-jsimport { InMemoryStorage } from '@tufjs/client'
Quickstart
import { TufClient, RemoteFetcher } from 'tuf-js';
import { Root } from '@tufjs/models';
import { InMemoryStorage } from '@tufjs/client'; // Provides simple in-memory storage
async function initializeAndDownloadTarget() {
const repoURL = 'https://example.com/tuf-repo/'; // Replace with your TUF repository base URL
// In a real application, you would bundle a trusted initial root.json.
// This is a minimal placeholder for demonstration purposes.
const initialRootJSON = JSON.stringify({
"_type": "root",
"spec_version": "1.0.0",
"version": 1,
"expires": "2030-01-01T00:00:00Z",
"keys": {},
"roles": {
"root": {"keyids": [], "threshold": 1},
"targets": {"keyids": [], "threshold": 1},
"snapshot": {"keyids": [], "threshold": 1},
"timestamp": {"keyids": [], "threshold": 1}
}
});
// Parse the initial root metadata
const initialRoot = Root.fromJSON(JSON.parse(initialRootJSON));
// Use in-memory storage for this example. In production, use persistent storage.
const client = new TufClient({
repoURL: repoURL,
root: initialRoot,
clientStorage: new InMemoryStorage(),
targetStorage: new InMemoryStorage(),
fetcher: new RemoteFetcher()
});
try {
console.log('Attempting to update TUF metadata...');
await client.update(); // Fetches and verifies the latest metadata
console.log('TUF metadata updated successfully.');
const targetName = 'path/to/my-app-binary-v1.0.0.zip'; // Replace with an actual target path
console.log(`Getting target info for: ${targetName}`);
const targetInfo = await client.getTargetInfo(targetName);
if (targetInfo) {
console.log(`Target '${targetName}' found. Downloading...`);
const targetContent = await client.downloadTarget(targetInfo);
console.log(`Downloaded ${targetContent.length} bytes for '${targetName}'.`);
// Here, targetContent (Uint8Array) can be saved to disk or processed.
} else {
console.log(`Target '${targetName}' not found in the repository.`);
}
} catch (error) {
console.error('TUF client operation failed:', error);
}
}
// To run this, ensure you have a global `fetch` (Node.js 18+ or polyfill)
// and install `@tufjs/client` and `@tufjs/models` alongside `tuf-js`.
initializeAndDownloadTarget();