Deployed the page to Github Pages.

This commit is contained in:
Batuhan Berk Başoğlu 2024-11-03 21:30:09 -05:00
parent 1d79754e93
commit 2c89899458
Signed by: batuhan-basoglu
SSH key fingerprint: SHA256:kEsnuHX+qbwhxSAXPUQ4ox535wFHu/hIRaa53FzxRpo
62797 changed files with 6551425 additions and 15279 deletions

21
node_modules/tuf-js/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 GitHub and the TUF Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

3
node_modules/tuf-js/README.md generated vendored Normal file
View file

@ -0,0 +1,3 @@
# tuf-js
JavaScript TUF client implementation.

14
node_modules/tuf-js/dist/config.d.ts generated vendored Normal file
View file

@ -0,0 +1,14 @@
import type { MakeFetchHappenOptions } from 'make-fetch-happen';
export type Config = {
maxRootRotations: number;
maxDelegations: number;
rootMaxLength: number;
timestampMaxLength: number;
snapshotMaxLength: number;
targetsMaxLength: number;
prefixTargetsWithHash: boolean;
fetchTimeout: number;
fetchRetries: number | undefined;
fetchRetry: MakeFetchHappenOptions['retry'];
};
export declare const defaultConfig: Config;

15
node_modules/tuf-js/dist/config.js generated vendored Normal file
View file

@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultConfig = void 0;
exports.defaultConfig = {
maxRootRotations: 32,
maxDelegations: 32,
rootMaxLength: 512000, //bytes
timestampMaxLength: 16384, // bytes
snapshotMaxLength: 2000000, // bytes
targetsMaxLength: 5000000, // bytes
prefixTargetsWithHash: true,
fetchTimeout: 100000, // milliseconds
fetchRetries: undefined,
fetchRetry: 2,
};

22
node_modules/tuf-js/dist/error.d.ts generated vendored Normal file
View file

@ -0,0 +1,22 @@
export declare class ValueError extends Error {
}
export declare class RuntimeError extends Error {
}
export declare class PersistError extends Error {
}
export declare class RepositoryError extends Error {
}
export declare class BadVersionError extends RepositoryError {
}
export declare class EqualVersionError extends BadVersionError {
}
export declare class ExpiredMetadataError extends RepositoryError {
}
export declare class DownloadError extends Error {
}
export declare class DownloadLengthMismatchError extends DownloadError {
}
export declare class DownloadHTTPError extends DownloadError {
statusCode: number;
constructor(message: string, statusCode: number);
}

48
node_modules/tuf-js/dist/error.js generated vendored Normal file
View file

@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DownloadHTTPError = exports.DownloadLengthMismatchError = exports.DownloadError = exports.ExpiredMetadataError = exports.EqualVersionError = exports.BadVersionError = exports.RepositoryError = exports.PersistError = exports.RuntimeError = exports.ValueError = void 0;
// An error about insufficient values
class ValueError extends Error {
}
exports.ValueError = ValueError;
class RuntimeError extends Error {
}
exports.RuntimeError = RuntimeError;
class PersistError extends Error {
}
exports.PersistError = PersistError;
// An error with a repository's state, such as a missing file.
// It covers all exceptions that come from the repository side when
// looking from the perspective of users of metadata API or ngclient.
class RepositoryError extends Error {
}
exports.RepositoryError = RepositoryError;
// An error for metadata that contains an invalid version number.
class BadVersionError extends RepositoryError {
}
exports.BadVersionError = BadVersionError;
// An error for metadata containing a previously verified version number.
class EqualVersionError extends BadVersionError {
}
exports.EqualVersionError = EqualVersionError;
// Indicate that a TUF Metadata file has expired.
class ExpiredMetadataError extends RepositoryError {
}
exports.ExpiredMetadataError = ExpiredMetadataError;
//----- Download Errors -------------------------------------------------------
// An error occurred while attempting to download a file.
class DownloadError extends Error {
}
exports.DownloadError = DownloadError;
// Indicate that a mismatch of lengths was seen while downloading a file
class DownloadLengthMismatchError extends DownloadError {
}
exports.DownloadLengthMismatchError = DownloadLengthMismatchError;
// Returned by FetcherInterface implementations for HTTP errors.
class DownloadHTTPError extends DownloadError {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
exports.DownloadHTTPError = DownloadHTTPError;

25
node_modules/tuf-js/dist/fetcher.d.ts generated vendored Normal file
View file

@ -0,0 +1,25 @@
/// <reference types="node" />
/// <reference types="node" />
import type { MakeFetchHappenOptions } from 'make-fetch-happen';
type DownloadFileHandler<T> = (file: string) => Promise<T>;
export interface Fetcher {
downloadFile<T>(url: string, maxLength: number, handler: DownloadFileHandler<T>): Promise<T>;
downloadBytes(url: string, maxLength: number): Promise<Buffer>;
}
export declare abstract class BaseFetcher implements Fetcher {
abstract fetch(url: string): Promise<NodeJS.ReadableStream>;
downloadFile<T>(url: string, maxLength: number, handler: DownloadFileHandler<T>): Promise<T>;
downloadBytes(url: string, maxLength: number): Promise<Buffer>;
}
type Retry = MakeFetchHappenOptions['retry'];
interface FetcherOptions {
timeout?: number;
retry?: Retry;
}
export declare class DefaultFetcher extends BaseFetcher {
private timeout?;
private retry?;
constructor(options?: FetcherOptions);
fetch(url: string): Promise<NodeJS.ReadableStream>;
}
export {};

84
node_modules/tuf-js/dist/fetcher.js generated vendored Normal file
View file

@ -0,0 +1,84 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultFetcher = exports.BaseFetcher = void 0;
const debug_1 = __importDefault(require("debug"));
const fs_1 = __importDefault(require("fs"));
const make_fetch_happen_1 = __importDefault(require("make-fetch-happen"));
const util_1 = __importDefault(require("util"));
const error_1 = require("./error");
const tmpfile_1 = require("./utils/tmpfile");
const log = (0, debug_1.default)('tuf:fetch');
class BaseFetcher {
// Download file from given URL. The file is downloaded to a temporary
// location and then passed to the given handler. The handler is responsible
// for moving the file to its final location. The temporary file is deleted
// after the handler returns.
async downloadFile(url, maxLength, handler) {
return (0, tmpfile_1.withTempFile)(async (tmpFile) => {
const reader = await this.fetch(url);
let numberOfBytesReceived = 0;
const fileStream = fs_1.default.createWriteStream(tmpFile);
// Read the stream a chunk at a time so that we can check
// the length of the file as we go
try {
for await (const chunk of reader) {
const bufferChunk = Buffer.from(chunk);
numberOfBytesReceived += bufferChunk.length;
if (numberOfBytesReceived > maxLength) {
throw new error_1.DownloadLengthMismatchError('Max length reached');
}
await writeBufferToStream(fileStream, bufferChunk);
}
}
finally {
// Make sure we always close the stream
await util_1.default.promisify(fileStream.close).bind(fileStream)();
}
return handler(tmpFile);
});
}
// Download bytes from given URL.
async downloadBytes(url, maxLength) {
return this.downloadFile(url, maxLength, async (file) => {
const stream = fs_1.default.createReadStream(file);
const chunks = [];
for await (const chunk of stream) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
});
}
}
exports.BaseFetcher = BaseFetcher;
class DefaultFetcher extends BaseFetcher {
constructor(options = {}) {
super();
this.timeout = options.timeout;
this.retry = options.retry;
}
async fetch(url) {
log('GET %s', url);
const response = await (0, make_fetch_happen_1.default)(url, {
timeout: this.timeout,
retry: this.retry,
});
if (!response.ok || !response?.body) {
throw new error_1.DownloadHTTPError('Failed to download', response.status);
}
return response.body;
}
}
exports.DefaultFetcher = DefaultFetcher;
const writeBufferToStream = async (stream, buffer) => {
return new Promise((resolve, reject) => {
stream.write(buffer, (err) => {
if (err) {
reject(err);
}
resolve(true);
});
});
};

4
node_modules/tuf-js/dist/index.d.ts generated vendored Normal file
View file

@ -0,0 +1,4 @@
export { TargetFile } from '@tufjs/models';
export { BaseFetcher, Fetcher } from './fetcher';
export { Updater, UpdaterOptions } from './updater';
export type { Config } from './config';

9
node_modules/tuf-js/dist/index.js generated vendored Normal file
View file

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Updater = exports.BaseFetcher = exports.TargetFile = void 0;
var models_1 = require("@tufjs/models");
Object.defineProperty(exports, "TargetFile", { enumerable: true, get: function () { return models_1.TargetFile; } });
var fetcher_1 = require("./fetcher");
Object.defineProperty(exports, "BaseFetcher", { enumerable: true, get: function () { return fetcher_1.BaseFetcher; } });
var updater_1 = require("./updater");
Object.defineProperty(exports, "Updater", { enumerable: true, get: function () { return updater_1.Updater; } });

19
node_modules/tuf-js/dist/store.d.ts generated vendored Normal file
View file

@ -0,0 +1,19 @@
/// <reference types="node" />
import { Metadata, Root, Snapshot, Targets, Timestamp } from '@tufjs/models';
export declare class TrustedMetadataStore {
private trustedSet;
private referenceTime;
constructor(rootData: Buffer);
get root(): Metadata<Root>;
get timestamp(): Metadata<Timestamp> | undefined;
get snapshot(): Metadata<Snapshot> | undefined;
get targets(): Metadata<Targets> | undefined;
getRole(name: string): Metadata<Targets> | undefined;
updateRoot(bytesBuffer: Buffer): Metadata<Root>;
updateTimestamp(bytesBuffer: Buffer): Metadata<Timestamp>;
updateSnapshot(bytesBuffer: Buffer, trusted?: boolean): Metadata<Snapshot>;
updateDelegatedTargets(bytesBuffer: Buffer, roleName: string, delegatorName: string): void;
private loadTrustedRoot;
private checkFinalTimestamp;
private checkFinalSnapsnot;
}

208
node_modules/tuf-js/dist/store.js generated vendored Normal file
View file

@ -0,0 +1,208 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TrustedMetadataStore = void 0;
const models_1 = require("@tufjs/models");
const error_1 = require("./error");
class TrustedMetadataStore {
constructor(rootData) {
this.trustedSet = {};
// Client workflow 5.1: record fixed update start time
this.referenceTime = new Date();
// Client workflow 5.2: load trusted root metadata
this.loadTrustedRoot(rootData);
}
get root() {
if (!this.trustedSet.root) {
throw new ReferenceError('No trusted root metadata');
}
return this.trustedSet.root;
}
get timestamp() {
return this.trustedSet.timestamp;
}
get snapshot() {
return this.trustedSet.snapshot;
}
get targets() {
return this.trustedSet.targets;
}
getRole(name) {
return this.trustedSet[name];
}
updateRoot(bytesBuffer) {
const data = JSON.parse(bytesBuffer.toString('utf8'));
const newRoot = models_1.Metadata.fromJSON(models_1.MetadataKind.Root, data);
if (newRoot.signed.type != models_1.MetadataKind.Root) {
throw new error_1.RepositoryError(`Expected 'root', got ${newRoot.signed.type}`);
}
// Client workflow 5.4: check for arbitrary software attack
this.root.verifyDelegate(models_1.MetadataKind.Root, newRoot);
// Client workflow 5.5: check for rollback attack
if (newRoot.signed.version != this.root.signed.version + 1) {
throw new error_1.BadVersionError(`Expected version ${this.root.signed.version + 1}, got ${newRoot.signed.version}`);
}
// Check that new root is signed by self
newRoot.verifyDelegate(models_1.MetadataKind.Root, newRoot);
// Client workflow 5.7: set new root as trusted root
this.trustedSet.root = newRoot;
return newRoot;
}
updateTimestamp(bytesBuffer) {
if (this.snapshot) {
throw new error_1.RuntimeError('Cannot update timestamp after snapshot');
}
if (this.root.signed.isExpired(this.referenceTime)) {
throw new error_1.ExpiredMetadataError('Final root.json is expired');
}
const data = JSON.parse(bytesBuffer.toString('utf8'));
const newTimestamp = models_1.Metadata.fromJSON(models_1.MetadataKind.Timestamp, data);
if (newTimestamp.signed.type != models_1.MetadataKind.Timestamp) {
throw new error_1.RepositoryError(`Expected 'timestamp', got ${newTimestamp.signed.type}`);
}
// Client workflow 5.4.2: check for arbitrary software attack
this.root.verifyDelegate(models_1.MetadataKind.Timestamp, newTimestamp);
if (this.timestamp) {
// Prevent rolling back timestamp version
// Client workflow 5.4.3.1: check for rollback attack
if (newTimestamp.signed.version < this.timestamp.signed.version) {
throw new error_1.BadVersionError(`New timestamp version ${newTimestamp.signed.version} is less than current version ${this.timestamp.signed.version}`);
}
// Keep using old timestamp if versions are equal.
if (newTimestamp.signed.version === this.timestamp.signed.version) {
throw new error_1.EqualVersionError(`New timestamp version ${newTimestamp.signed.version} is equal to current version ${this.timestamp.signed.version}`);
}
// Prevent rolling back snapshot version
// Client workflow 5.4.3.2: check for rollback attack
const snapshotMeta = this.timestamp.signed.snapshotMeta;
const newSnapshotMeta = newTimestamp.signed.snapshotMeta;
if (newSnapshotMeta.version < snapshotMeta.version) {
throw new error_1.BadVersionError(`New snapshot version ${newSnapshotMeta.version} is less than current version ${snapshotMeta.version}`);
}
}
// expiry not checked to allow old timestamp to be used for rollback
// protection of new timestamp: expiry is checked in update_snapshot
this.trustedSet.timestamp = newTimestamp;
// Client workflow 5.4.4: check for freeze attack
this.checkFinalTimestamp();
return newTimestamp;
}
updateSnapshot(bytesBuffer, trusted = false) {
if (!this.timestamp) {
throw new error_1.RuntimeError('Cannot update snapshot before timestamp');
}
if (this.targets) {
throw new error_1.RuntimeError('Cannot update snapshot after targets');
}
// Snapshot cannot be loaded if final timestamp is expired
this.checkFinalTimestamp();
const snapshotMeta = this.timestamp.signed.snapshotMeta;
// Verify non-trusted data against the hashes in timestamp, if any.
// Trusted snapshot data has already been verified once.
// Client workflow 5.5.2: check against timestamp role's snaphsot hash
if (!trusted) {
snapshotMeta.verify(bytesBuffer);
}
const data = JSON.parse(bytesBuffer.toString('utf8'));
const newSnapshot = models_1.Metadata.fromJSON(models_1.MetadataKind.Snapshot, data);
if (newSnapshot.signed.type != models_1.MetadataKind.Snapshot) {
throw new error_1.RepositoryError(`Expected 'snapshot', got ${newSnapshot.signed.type}`);
}
// Client workflow 5.5.3: check for arbitrary software attack
this.root.verifyDelegate(models_1.MetadataKind.Snapshot, newSnapshot);
// version check against meta version (5.5.4) is deferred to allow old
// snapshot to be used in rollback protection
// Client workflow 5.5.5: check for rollback attack
if (this.snapshot) {
Object.entries(this.snapshot.signed.meta).forEach(([fileName, fileInfo]) => {
const newFileInfo = newSnapshot.signed.meta[fileName];
if (!newFileInfo) {
throw new error_1.RepositoryError(`Missing file ${fileName} in new snapshot`);
}
if (newFileInfo.version < fileInfo.version) {
throw new error_1.BadVersionError(`New version ${newFileInfo.version} of ${fileName} is less than current version ${fileInfo.version}`);
}
});
}
this.trustedSet.snapshot = newSnapshot;
// snapshot is loaded, but we raise if it's not valid _final_ snapshot
// Client workflow 5.5.4 & 5.5.6
this.checkFinalSnapsnot();
return newSnapshot;
}
updateDelegatedTargets(bytesBuffer, roleName, delegatorName) {
if (!this.snapshot) {
throw new error_1.RuntimeError('Cannot update delegated targets before snapshot');
}
// Targets cannot be loaded if final snapshot is expired or its version
// does not match meta version in timestamp.
this.checkFinalSnapsnot();
const delegator = this.trustedSet[delegatorName];
if (!delegator) {
throw new error_1.RuntimeError(`No trusted ${delegatorName} metadata`);
}
// Extract metadata for the delegated role from snapshot
const meta = this.snapshot.signed.meta?.[`${roleName}.json`];
if (!meta) {
throw new error_1.RepositoryError(`Missing ${roleName}.json in snapshot`);
}
// Client workflow 5.6.2: check against snapshot role's targets hash
meta.verify(bytesBuffer);
const data = JSON.parse(bytesBuffer.toString('utf8'));
const newDelegate = models_1.Metadata.fromJSON(models_1.MetadataKind.Targets, data);
if (newDelegate.signed.type != models_1.MetadataKind.Targets) {
throw new error_1.RepositoryError(`Expected 'targets', got ${newDelegate.signed.type}`);
}
// Client workflow 5.6.3: check for arbitrary software attack
delegator.verifyDelegate(roleName, newDelegate);
// Client workflow 5.6.4: Check against snapshot roles targets version
const version = newDelegate.signed.version;
if (version != meta.version) {
throw new error_1.BadVersionError(`Version ${version} of ${roleName} does not match snapshot version ${meta.version}`);
}
// Client workflow 5.6.5: check for a freeze attack
if (newDelegate.signed.isExpired(this.referenceTime)) {
throw new error_1.ExpiredMetadataError(`${roleName}.json is expired`);
}
this.trustedSet[roleName] = newDelegate;
}
// Verifies and loads data as trusted root metadata.
// Note that an expired initial root is still considered valid.
loadTrustedRoot(bytesBuffer) {
const data = JSON.parse(bytesBuffer.toString('utf8'));
const root = models_1.Metadata.fromJSON(models_1.MetadataKind.Root, data);
if (root.signed.type != models_1.MetadataKind.Root) {
throw new error_1.RepositoryError(`Expected 'root', got ${root.signed.type}`);
}
root.verifyDelegate(models_1.MetadataKind.Root, root);
this.trustedSet['root'] = root;
}
checkFinalTimestamp() {
// Timestamp MUST be loaded
if (!this.timestamp) {
throw new ReferenceError('No trusted timestamp metadata');
}
// Client workflow 5.4.4: check for freeze attack
if (this.timestamp.signed.isExpired(this.referenceTime)) {
throw new error_1.ExpiredMetadataError('Final timestamp.json is expired');
}
}
checkFinalSnapsnot() {
// Snapshot and timestamp MUST be loaded
if (!this.snapshot) {
throw new ReferenceError('No trusted snapshot metadata');
}
if (!this.timestamp) {
throw new ReferenceError('No trusted timestamp metadata');
}
// Client workflow 5.5.6: check for freeze attack
if (this.snapshot.signed.isExpired(this.referenceTime)) {
throw new error_1.ExpiredMetadataError('snapshot.json is expired');
}
// Client workflow 5.5.4: check against timestamp roles snapshot version
const snapshotMeta = this.timestamp.signed.snapshotMeta;
if (this.snapshot.signed.version !== snapshotMeta.version) {
throw new error_1.BadVersionError("Snapshot version doesn't match timestamp");
}
}
}
exports.TrustedMetadataStore = TrustedMetadataStore;

35
node_modules/tuf-js/dist/updater.d.ts generated vendored Normal file
View file

@ -0,0 +1,35 @@
import { TargetFile } from '@tufjs/models';
import { Config } from './config';
import { Fetcher } from './fetcher';
export interface UpdaterOptions {
metadataDir: string;
metadataBaseUrl: string;
targetDir?: string;
targetBaseUrl?: string;
fetcher?: Fetcher;
forceCache?: boolean;
config?: Partial<Config>;
}
export declare class Updater {
private dir;
private metadataBaseUrl;
private targetDir?;
private targetBaseUrl?;
private forceCache;
private trustedSet;
private config;
private fetcher;
constructor(options: UpdaterOptions);
refresh(): Promise<void>;
getTargetInfo(targetPath: string): Promise<TargetFile | undefined>;
downloadTarget(targetInfo: TargetFile, filePath?: string, targetBaseUrl?: string): Promise<string>;
findCachedTarget(targetInfo: TargetFile, filePath?: string): Promise<string | undefined>;
private loadLocalMetadata;
private loadRoot;
private loadTimestamp;
private loadSnapshot;
private loadTargets;
private preorderDepthFirstWalk;
private generateTargetPath;
private persistMetadata;
}

343
node_modules/tuf-js/dist/updater.js generated vendored Normal file
View file

@ -0,0 +1,343 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Updater = void 0;
const models_1 = require("@tufjs/models");
const debug_1 = __importDefault(require("debug"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const config_1 = require("./config");
const error_1 = require("./error");
const fetcher_1 = require("./fetcher");
const store_1 = require("./store");
const url = __importStar(require("./utils/url"));
const log = (0, debug_1.default)('tuf:cache');
class Updater {
constructor(options) {
const { metadataDir, metadataBaseUrl, targetDir, targetBaseUrl, fetcher, config, } = options;
this.dir = metadataDir;
this.metadataBaseUrl = metadataBaseUrl;
this.targetDir = targetDir;
this.targetBaseUrl = targetBaseUrl;
this.forceCache = options.forceCache ?? false;
const data = this.loadLocalMetadata(models_1.MetadataKind.Root);
this.trustedSet = new store_1.TrustedMetadataStore(data);
this.config = { ...config_1.defaultConfig, ...config };
this.fetcher =
fetcher ||
new fetcher_1.DefaultFetcher({
timeout: this.config.fetchTimeout,
retry: this.config.fetchRetries ?? this.config.fetchRetry,
});
}
// refresh and load the metadata before downloading the target
// refresh should be called once after the client is initialized
async refresh() {
// If forceCache is true, try to load the timestamp from local storage
// without fetching it from the remote. Otherwise, load the root and
// timestamp from the remote per the TUF spec.
if (this.forceCache) {
// If anything fails, load the root and timestamp from the remote. This
// should cover any situation where the local metadata is corrupted or
// expired.
try {
await this.loadTimestamp({ checkRemote: false });
}
catch (error) {
await this.loadRoot();
await this.loadTimestamp();
}
}
else {
await this.loadRoot();
await this.loadTimestamp();
}
await this.loadSnapshot();
await this.loadTargets(models_1.MetadataKind.Targets, models_1.MetadataKind.Root);
}
// Returns the TargetFile instance with information for the given target path.
//
// Implicitly calls refresh if it hasn't already been called.
async getTargetInfo(targetPath) {
if (!this.trustedSet.targets) {
await this.refresh();
}
return this.preorderDepthFirstWalk(targetPath);
}
async downloadTarget(targetInfo, filePath, targetBaseUrl) {
const targetPath = filePath || this.generateTargetPath(targetInfo);
if (!targetBaseUrl) {
if (!this.targetBaseUrl) {
throw new error_1.ValueError('Target base URL not set');
}
targetBaseUrl = this.targetBaseUrl;
}
let targetFilePath = targetInfo.path;
const consistentSnapshot = this.trustedSet.root.signed.consistentSnapshot;
if (consistentSnapshot && this.config.prefixTargetsWithHash) {
const hashes = Object.values(targetInfo.hashes);
const { dir, base } = path.parse(targetFilePath);
const filename = `${hashes[0]}.${base}`;
targetFilePath = dir ? `${dir}/${filename}` : filename;
}
const targetUrl = url.join(targetBaseUrl, targetFilePath);
// Client workflow 5.7.3: download target file
await this.fetcher.downloadFile(targetUrl, targetInfo.length, async (fileName) => {
// Verify hashes and length of downloaded file
await targetInfo.verify(fs.createReadStream(fileName));
// Copy file to target path
log('WRITE %s', targetPath);
fs.copyFileSync(fileName, targetPath);
});
return targetPath;
}
async findCachedTarget(targetInfo, filePath) {
if (!filePath) {
filePath = this.generateTargetPath(targetInfo);
}
try {
if (fs.existsSync(filePath)) {
await targetInfo.verify(fs.createReadStream(filePath));
return filePath;
}
}
catch (error) {
return; // File not found
}
return; // File not found
}
loadLocalMetadata(fileName) {
const filePath = path.join(this.dir, `${fileName}.json`);
log('READ %s', filePath);
return fs.readFileSync(filePath);
}
// Sequentially load and persist on local disk every newer root metadata
// version available on the remote.
// Client workflow 5.3: update root role
async loadRoot() {
// Client workflow 5.3.2: version of trusted root metadata file
const rootVersion = this.trustedSet.root.signed.version;
const lowerBound = rootVersion + 1;
const upperBound = lowerBound + this.config.maxRootRotations;
for (let version = lowerBound; version <= upperBound; version++) {
const rootUrl = url.join(this.metadataBaseUrl, `${version}.root.json`);
try {
// Client workflow 5.3.3: download new root metadata file
const bytesData = await this.fetcher.downloadBytes(rootUrl, this.config.rootMaxLength);
// Client workflow 5.3.4 - 5.4.7
this.trustedSet.updateRoot(bytesData);
// Client workflow 5.3.8: persist root metadata file
this.persistMetadata(models_1.MetadataKind.Root, bytesData);
}
catch (error) {
break;
}
}
}
// Load local and remote timestamp metadata.
// Client workflow 5.4: update timestamp role
async loadTimestamp({ checkRemote } = { checkRemote: true }) {
// Load local and remote timestamp metadata
try {
const data = this.loadLocalMetadata(models_1.MetadataKind.Timestamp);
this.trustedSet.updateTimestamp(data);
// If checkRemote is disabled, return here to avoid fetching the remote
// timestamp metadata.
if (!checkRemote) {
return;
}
}
catch (error) {
// continue
}
//Load from remote (whether local load succeeded or not)
const timestampUrl = url.join(this.metadataBaseUrl, 'timestamp.json');
// Client workflow 5.4.1: download timestamp metadata file
const bytesData = await this.fetcher.downloadBytes(timestampUrl, this.config.timestampMaxLength);
try {
// Client workflow 5.4.2 - 5.4.4
this.trustedSet.updateTimestamp(bytesData);
}
catch (error) {
// If new timestamp version is same as current, discardd the new one.
// This is normal and should NOT raise an error.
if (error instanceof error_1.EqualVersionError) {
return;
}
// Re-raise any other error
throw error;
}
// Client workflow 5.4.5: persist timestamp metadata
this.persistMetadata(models_1.MetadataKind.Timestamp, bytesData);
}
// Load local and remote snapshot metadata.
// Client workflow 5.5: update snapshot role
async loadSnapshot() {
//Load local (and if needed remote) snapshot metadata
try {
const data = this.loadLocalMetadata(models_1.MetadataKind.Snapshot);
this.trustedSet.updateSnapshot(data, true);
}
catch (error) {
if (!this.trustedSet.timestamp) {
throw new ReferenceError('No timestamp metadata');
}
const snapshotMeta = this.trustedSet.timestamp.signed.snapshotMeta;
const maxLength = snapshotMeta.length || this.config.snapshotMaxLength;
const version = this.trustedSet.root.signed.consistentSnapshot
? snapshotMeta.version
: undefined;
const snapshotUrl = url.join(this.metadataBaseUrl, version ? `${version}.snapshot.json` : 'snapshot.json');
try {
// Client workflow 5.5.1: download snapshot metadata file
const bytesData = await this.fetcher.downloadBytes(snapshotUrl, maxLength);
// Client workflow 5.5.2 - 5.5.6
this.trustedSet.updateSnapshot(bytesData);
// Client workflow 5.5.7: persist snapshot metadata file
this.persistMetadata(models_1.MetadataKind.Snapshot, bytesData);
}
catch (error) {
throw new error_1.RuntimeError(`Unable to load snapshot metadata error ${error}`);
}
}
}
// Load local and remote targets metadata.
// Client workflow 5.6: update targets role
async loadTargets(role, parentRole) {
if (this.trustedSet.getRole(role)) {
return this.trustedSet.getRole(role);
}
try {
const buffer = this.loadLocalMetadata(role);
this.trustedSet.updateDelegatedTargets(buffer, role, parentRole);
}
catch (error) {
// Local 'role' does not exist or is invalid: update from remote
if (!this.trustedSet.snapshot) {
throw new ReferenceError('No snapshot metadata');
}
const metaInfo = this.trustedSet.snapshot.signed.meta[`${role}.json`];
// TODO: use length for fetching
const maxLength = metaInfo.length || this.config.targetsMaxLength;
const version = this.trustedSet.root.signed.consistentSnapshot
? metaInfo.version
: undefined;
const metadataUrl = url.join(this.metadataBaseUrl, version ? `${version}.${role}.json` : `${role}.json`);
try {
// Client workflow 5.6.1: download targets metadata file
const bytesData = await this.fetcher.downloadBytes(metadataUrl, maxLength);
// Client workflow 5.6.2 - 5.6.6
this.trustedSet.updateDelegatedTargets(bytesData, role, parentRole);
// Client workflow 5.6.7: persist targets metadata file
this.persistMetadata(role, bytesData);
}
catch (error) {
throw new error_1.RuntimeError(`Unable to load targets error ${error}`);
}
}
return this.trustedSet.getRole(role);
}
async preorderDepthFirstWalk(targetPath) {
// Interrogates the tree of target delegations in order of appearance
// (which implicitly order trustworthiness), and returns the matching
// target found in the most trusted role.
// List of delegations to be interrogated. A (role, parent role) pair
// is needed to load and verify the delegated targets metadata.
const delegationsToVisit = [
{
roleName: models_1.MetadataKind.Targets,
parentRoleName: models_1.MetadataKind.Root,
},
];
const visitedRoleNames = new Set();
// Client workflow 5.6.7: preorder depth-first traversal of the graph of
// target delegations
while (visitedRoleNames.size <= this.config.maxDelegations &&
delegationsToVisit.length > 0) {
// Pop the role name from the top of the stack.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { roleName, parentRoleName } = delegationsToVisit.pop();
// Skip any visited current role to prevent cycles.
// Client workflow 5.6.7.1: skip already-visited roles
if (visitedRoleNames.has(roleName)) {
continue;
}
// The metadata for 'role_name' must be downloaded/updated before
// its targets, delegations, and child roles can be inspected.
const targets = (await this.loadTargets(roleName, parentRoleName))
?.signed;
if (!targets) {
continue;
}
const target = targets.targets?.[targetPath];
if (target) {
return target;
}
// After preorder check, add current role to set of visited roles.
visitedRoleNames.add(roleName);
if (targets.delegations) {
const childRolesToVisit = [];
// NOTE: This may be a slow operation if there are many delegated roles.
const rolesForTarget = targets.delegations.rolesForTarget(targetPath);
for (const { role: childName, terminating } of rolesForTarget) {
childRolesToVisit.push({
roleName: childName,
parentRoleName: roleName,
});
// Client workflow 5.6.7.2.1
if (terminating) {
delegationsToVisit.splice(0); // empty the array
break;
}
}
childRolesToVisit.reverse();
delegationsToVisit.push(...childRolesToVisit);
}
}
return; // no matching target found
}
generateTargetPath(targetInfo) {
if (!this.targetDir) {
throw new error_1.ValueError('Target directory not set');
}
// URL encode target path
const filePath = encodeURIComponent(targetInfo.path);
return path.join(this.targetDir, filePath);
}
persistMetadata(metaDataName, bytesData) {
try {
const filePath = path.join(this.dir, `${metaDataName}.json`);
log('WRITE %s', filePath);
fs.writeFileSync(filePath, bytesData.toString('utf8'));
}
catch (error) {
throw new error_1.PersistError(`Failed to persist metadata ${metaDataName} error: ${error}`);
}
}
}
exports.Updater = Updater;

3
node_modules/tuf-js/dist/utils/tmpfile.d.ts generated vendored Normal file
View file

@ -0,0 +1,3 @@
type TempFileHandler<T> = (file: string) => Promise<T>;
export declare const withTempFile: <T>(handler: TempFileHandler<T>) => Promise<T>;
export {};

25
node_modules/tuf-js/dist/utils/tmpfile.js generated vendored Normal file
View file

@ -0,0 +1,25 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.withTempFile = void 0;
const promises_1 = __importDefault(require("fs/promises"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
// Invokes the given handler with the path to a temporary file. The file
// is deleted after the handler returns.
const withTempFile = async (handler) => withTempDir(async (dir) => handler(path_1.default.join(dir, 'tempfile')));
exports.withTempFile = withTempFile;
// Invokes the given handler with a temporary directory. The directory is
// deleted after the handler returns.
const withTempDir = async (handler) => {
const tmpDir = await promises_1.default.realpath(os_1.default.tmpdir());
const dir = await promises_1.default.mkdtemp(tmpDir + path_1.default.sep);
try {
return await handler(dir);
}
finally {
await promises_1.default.rm(dir, { force: true, recursive: true, maxRetries: 3 });
}
};

1
node_modules/tuf-js/dist/utils/url.d.ts generated vendored Normal file
View file

@ -0,0 +1 @@
export declare function join(base: string, path: string): string;

14
node_modules/tuf-js/dist/utils/url.js generated vendored Normal file
View file

@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.join = void 0;
const url_1 = require("url");
function join(base, path) {
return new url_1.URL(ensureTrailingSlash(base) + removeLeadingSlash(path)).toString();
}
exports.join = join;
function ensureTrailingSlash(path) {
return path.endsWith('/') ? path : path + '/';
}
function removeLeadingSlash(path) {
return path.startsWith('/') ? path.slice(1) : path;
}

43
node_modules/tuf-js/package.json generated vendored Normal file
View file

@ -0,0 +1,43 @@
{
"name": "tuf-js",
"version": "2.2.1",
"description": "JavaScript implementation of The Update Framework (TUF)",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc --build",
"clean": "rm -rf dist",
"test": "jest"
},
"repository": {
"type": "git",
"url": "git+https://github.com/theupdateframework/tuf-js.git"
},
"files": [
"dist"
],
"keywords": [
"tuf",
"security",
"update"
],
"author": "bdehamer@github.com",
"license": "MIT",
"bugs": {
"url": "https://github.com/theupdateframework/tuf-js/issues"
},
"homepage": "https://github.com/theupdateframework/tuf-js/tree/main/packages/client#readme",
"devDependencies": {
"@tufjs/repo-mock": "2.0.1",
"@types/debug": "^4.1.12",
"@types/make-fetch-happen": "^10.0.4"
},
"dependencies": {
"@tufjs/models": "2.0.1",
"debug": "^4.3.4",
"make-fetch-happen": "^13.0.1"
},
"engines": {
"node": "^16.14.0 || >=18.0.0"
}
}