You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
3.4 KiB
84 lines
3.4 KiB
3 years ago
|
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;
|