import {main as bakedInMain} from './indexer.mjs' import {readFile} from 'fs/promises' import {join} from "path" import chalk from "chalk" import parseDataUrl from "data-urls" import publicKeyDataUrl from "./smva-indexer-release.pub.pem" import envPaths from "env-paths" import configName from "consts:configName" import {signatureGuardStart, signatureGuardEnd, algorithm, absolutize} from "./signing-common.mjs" import {createPublicKey, createVerify} from "crypto" const publicKey = createPublicKey({ key: parseDataUrl(publicKeyDataUrl).body, format: "pem" }) async function validateSignature(input) { if (!input.subarray(0, signatureGuardStart.length).equals(signatureGuardStart)) { throw new Error(`File does not start with ${JSON.stringify(signatureGuardStart.toString())}`) } const signatureLength = input.subarray(signatureGuardStart.length).indexOf(signatureGuardEnd) if (signatureLength === -1) { throw new Error(`Signature does not end with ${JSON.stringify(signatureGuardEnd.toString())}`) } const verify = createVerify(algorithm) const signedContent = input.subarray(signatureGuardStart.length + signatureLength + signatureGuardEnd.length) verify.update(signedContent) const signature = input.subarray(signatureGuardStart.length, signatureGuardStart.length + signatureLength).toString("utf-8") if (!verify.verify(publicKey, signature, "base64")) { throw new Error(`Signature was incorrect`) } } async function tryFiles(paths) { for (const path of paths) { try { const input = await readFile(path) if (!process.env.SMVA_INDEXER_IGNORE_SIGNATURES) { await validateSignature(input) } const {main: result} = await import(absolutize(path)) if (result !== bakedInMain) { process.stderr.write(chalk.cyan(`Loaded code for ${chalk.cyanBright.bold(`v${result.version}`)} from ${chalk.cyanBright.bold(path)}\n`)) return result } } catch (ex) { if (ex.code === "ENOENT" || ex.code === "EACCES") { // That's okay, just move on to the next file } else { process.stderr.write(chalk.red(`Error while checking for an updated bundle at ${chalk.redBright.bold(path)}: ${chalk.redBright.bold(ex)}\n`)) } } } // None of the files both existed AND were valid. return null } const bundleFilename = "smva-indexer-bundle-signed.js" async function start() { const bundlesToTry = [] const cwdBundle = join(process.cwd(), bundleFilename) if (!bundlesToTry.includes(cwdBundle) && !process.env.SMVA_INDEXER_IGNORE_CWD_BUNDLE) { bundlesToTry.push(cwdBundle) } const besideBundle = join(module.path, bundleFilename) if (!bundlesToTry.includes(besideBundle) && !process.env.SMVA_INDEXER_IGNORE_NEARBY_BUNDLE) { bundlesToTry.push(besideBundle) } const configBundle = join(envPaths(configName).config, bundleFilename) if (!bundlesToTry.includes(configBundle) && !process.env.SMVA_INDEXER_IGNORE_CONFIG_BUNDLE) { bundlesToTry.push(configBundle) } const loadedMain = process.env.SMVA_INDEXER_IGNORE_ALL_BUNDLES ? null : await tryFiles(bundlesToTry); await (loadedMain || bakedInMain)() } if (!global.main) { global.main = true start() } export const main = bakedInMain;