1"use strict"; 2var __importDefault = (this && this.__importDefault) || function (mod) { 3 return (mod && mod.__esModule) ? mod : { "default": mod }; 4}; 5Object.defineProperty(exports, "__esModule", { value: true }); 6exports.TUFClient = void 0; 7/* 8Copyright 2023 The Sigstore Authors. 9 10Licensed under the Apache License, Version 2.0 (the "License"); 11you may not use this file except in compliance with the License. 12You may obtain a copy of the License at 13 14 http://www.apache.org/licenses/LICENSE-2.0 15 16Unless required by applicable law or agreed to in writing, software 17distributed under the License is distributed on an "AS IS" BASIS, 18WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19See the License for the specific language governing permissions and 20limitations under the License. 21*/ 22const fs_1 = __importDefault(require("fs")); 23const path_1 = __importDefault(require("path")); 24const tuf_js_1 = require("tuf-js"); 25const target_1 = require("./target"); 26class TUFClient { 27 constructor(options) { 28 initTufCache(options.cachePath, options.rootPath); 29 const remote = initRemoteConfig(options.cachePath, options.mirrorURL); 30 this.updater = initClient(options.cachePath, remote, options); 31 } 32 async refresh() { 33 return this.updater.refresh(); 34 } 35 getTarget(targetName) { 36 return (0, target_1.readTarget)(this.updater, targetName); 37 } 38} 39exports.TUFClient = TUFClient; 40// Initializes the TUF cache directory structure including the initial 41// root.json file. If the cache directory does not exist, it will be 42// created. If the targets directory does not exist, it will be created. 43// If the root.json file does not exist, it will be copied from the 44// rootPath argument. 45function initTufCache(cachePath, tufRootPath) { 46 const targetsPath = path_1.default.join(cachePath, 'targets'); 47 const cachedRootPath = path_1.default.join(cachePath, 'root.json'); 48 if (!fs_1.default.existsSync(cachePath)) { 49 fs_1.default.mkdirSync(cachePath, { recursive: true }); 50 } 51 if (!fs_1.default.existsSync(targetsPath)) { 52 fs_1.default.mkdirSync(targetsPath); 53 } 54 if (!fs_1.default.existsSync(cachedRootPath)) { 55 fs_1.default.copyFileSync(tufRootPath, cachedRootPath); 56 } 57 return cachePath; 58} 59// Initializes the remote.json file, which contains the URL of the TUF 60// repository. If the file does not exist, it will be created. If the file 61// exists, it will be parsed and returned. 62function initRemoteConfig(rootDir, mirrorURL) { 63 let remoteConfig; 64 const remoteConfigPath = path_1.default.join(rootDir, 'remote.json'); 65 if (fs_1.default.existsSync(remoteConfigPath)) { 66 const data = fs_1.default.readFileSync(remoteConfigPath, 'utf-8'); 67 remoteConfig = JSON.parse(data); 68 } 69 if (!remoteConfig) { 70 remoteConfig = { mirror: mirrorURL }; 71 fs_1.default.writeFileSync(remoteConfigPath, JSON.stringify(remoteConfig)); 72 } 73 return remoteConfig; 74} 75function initClient(cachePath, remote, options) { 76 const baseURL = remote.mirror; 77 const config = { 78 fetchTimeout: options.timeout, 79 }; 80 // tuf-js only supports a number for fetchRetries so we have to 81 // convert the boolean and object options to a number. 82 /* istanbul ignore if */ 83 if (typeof options.retry !== 'undefined') { 84 if (typeof options.retry === 'number') { 85 config.fetchRetries = options.retry; 86 } 87 else if (typeof options.retry === 'object') { 88 config.fetchRetries = options.retry.retries; 89 } 90 else if (options.retry === true) { 91 config.fetchRetries = 1; 92 } 93 } 94 return new tuf_js_1.Updater({ 95 metadataBaseUrl: baseURL, 96 targetBaseUrl: `${baseURL}/targets`, 97 metadataDir: cachePath, 98 targetDir: path_1.default.join(cachePath, 'targets'), 99 config, 100 }); 101} 102