Initial commit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
dinlo
2026-05-31 18:44:04 +08:00
commit 436a9631fc
8616 changed files with 1389957 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
import { SignOptions } from './types';
/**
* Recursively goes through an entire directory and returns an array
* of full paths for files ot sign.
*
* - Portable executable files (.exe, .dll, .sys, .efi, .scr, .node)
* - Microsoft installers (.msi)
* - APPX/MSIX packages (.appx, .appxbundle, .msix, .msixbundle)
* - Catalog files (.cat)
* - Cabinet files (.cab)
* - Silverlight applications (.xap)
* - Scripts (.vbs, .wsf, .ps1)
* If configured:
* - JavaScript files (.js)
*/
export declare function getFilesToSign(options: SignOptions, dir?: string): Array<string>;
+59
View File
@@ -0,0 +1,59 @@
import path from 'path';
import fs from 'fs-extra';
const IS_PE_REGEX = /\.(exe|dll|sys|efi|scr|node)$/i;
const IS_MSI_REGEX = /\.msi$/i;
const IS_PACKAGE_REGEX = /\.(appx|appxbundle|msix|msixbundle)$/i;
const IS_CATCAB_REGEX = /\.(cat|cab)$/i;
const IS_SILVERLIGHT_REGEX = /\.xap$/i;
const IS_SCRIPT_REGEX = /\.(vbs|wsf|ps1)$/i;
const IS_JS_REGEX = /\.js$/i;
/**
* Recursively goes through an entire directory and returns an array
* of full paths for files ot sign.
*
* - Portable executable files (.exe, .dll, .sys, .efi, .scr, .node)
* - Microsoft installers (.msi)
* - APPX/MSIX packages (.appx, .appxbundle, .msix, .msixbundle)
* - Catalog files (.cat)
* - Cabinet files (.cab)
* - Silverlight applications (.xap)
* - Scripts (.vbs, .wsf, .ps1)
* If configured:
* - JavaScript files (.js)
*/
export function getFilesToSign(options, dir) {
if (isSignOptionsForFiles(options)) {
return options.files;
}
dir = dir || options.appDirectory;
// Array of file paths to sign
const result = [];
// Iterate over the app directory, looking for files to sign
const files = fs.readdirSync(dir);
const regexes = [
IS_PE_REGEX,
IS_MSI_REGEX,
IS_PACKAGE_REGEX,
IS_CATCAB_REGEX,
IS_SILVERLIGHT_REGEX,
IS_SCRIPT_REGEX
];
if (options.signJavaScript) {
regexes.push(IS_JS_REGEX);
}
for (const file of files) {
const fullPath = path.resolve(dir, file);
if (fs.statSync(fullPath).isDirectory()) {
// If it's a directory, recurse
result.push(...getFilesToSign(options, fullPath));
}
else if (regexes.some((regex) => regex.test(file))) {
// If it's a match, add it to the list
result.push(fullPath);
}
}
return result;
}
function isSignOptionsForFiles(input) {
return !!input.files;
}
+4
View File
@@ -0,0 +1,4 @@
import { sign } from './sign';
import { createSeaSignTool, SeaOptions, InternalSeaOptions } from './sea';
import { HookFunction, OptionalHookOptions, OptionalSignToolOptions, SignOptions, SignToolOptions, SignOptionsForDirectory, SignOptionsForFiles } from './types';
export { sign, SignOptions, SignToolOptions, HookFunction, OptionalSignToolOptions, OptionalHookOptions, createSeaSignTool, SeaOptions, InternalSeaOptions, SignOptionsForDirectory, SignOptionsForFiles };
+3
View File
@@ -0,0 +1,3 @@
import { sign } from './sign';
import { createSeaSignTool } from './sea';
export { sign, createSeaSignTool };
+61
View File
@@ -0,0 +1,61 @@
import { SignToolOptions } from './types';
/**
* Options for signing with a Node.js single executable application.
*
* @category Single executable applications
*/
export interface SeaOptions {
/**
* Full path to the Node.js single executable application. Needs to end with `.exe`.
*/
path: string;
/**
* A binary to use. Will use the current executable (process.execPath) by default.
*
* @defaultValue The Node.js {@link https://nodejs.org/api/process.html#processexecpath | `process.execPath`}
*/
bin?: string;
/**
* Options to pass to SignTool.
*/
windowsSign: SignToolOptions;
}
/**
* This interface represents {@link SeaOptions} with all optional properties
* inferred by `@electron/windows-sign` if not passed in by the user.
*
* @category Single executable applications
*/
export interface InternalSeaOptions extends Required<SeaOptions> {
/**
* Directory of the Node.js single executable application.
*/
dir: string;
/**
* File name of the Node.js single executable application.
*/
filename: string;
}
/**
* cross-dir uses new Error() stacks
* to figure out our directory in a way
* that's somewhat cross-compatible.
*
* We can't just use __dirname because it's
* undefined in ESM - and we can't use import.meta.url
* because TypeScript won't allow usage unless you're
* _only_ compiling for ESM.
*/
export declare const DIRNAME: string;
/**
* Uses Node's "Single Executable App" functionality
* to create a Node-driven signtool.exe that calls this
* module.
*
* This is useful with other tooling that _always_ calls
* a signtool.exe to sign. Some of those tools cannot be
* easily configured, but we _can_ override their signtool.exe.
*
* @category Single executable applications
*/
export declare function createSeaSignTool(options?: Partial<SeaOptions>): Promise<InternalSeaOptions>;
+213
View File
@@ -0,0 +1,213 @@
import { getDirname } from 'cross-dirname';
import path from 'path';
import os from 'os';
import fs from 'fs-extra';
import postject from 'postject';
import { spawnPromise } from './spawn';
import { log } from './utils/log';
/**
* cross-dir uses new Error() stacks
* to figure out our directory in a way
* that's somewhat cross-compatible.
*
* We can't just use __dirname because it's
* undefined in ESM - and we can't use import.meta.url
* because TypeScript won't allow usage unless you're
* _only_ compiling for ESM.
*/
export const DIRNAME = getDirname();
const FILENAMES = {
SEA_CONFIG: 'sea-config.json',
SEA_MAIN: 'sea.js',
SEA_BLOB: 'sea.blob',
SEA_RECEIVER: 'receiver.mjs'
};
const SEA_MAIN_SCRIPT = `
const bin = "%PATH_TO_BIN%";
const script = "%PATH_TO_SCRIPT%";
const options = %WINDOWS_SIGN_OPTIONS%
const { spawnSync } = require('child_process');
function main() {
console.log("@electron/windows-sign sea");
console.log({ bin, script });
try {
const spawn = spawnSync(
bin,
[ script, JSON.stringify(options), JSON.stringify(process.argv.slice(1)) ],
{ stdio: ['inherit', 'inherit', 'pipe'] }
);
if (spawn.status !== 0) {
throw new Error(\`Spawn failed with code: \${spawn.status}. Stderr: \${spawn.stderr}\`);
}
} catch (error) {
// Do not rethrow the error or write it to stdout/stderr. Then the process won't terminate.
// See: https://github.com/electron/windows-sign/pull/48
process.exit(1);
}
}
main();
`;
const SEA_RECEIVER_SCRIPT = `
import { sign } from '@electron/windows-sign';
import fs from 'fs-extra';
import path from 'path';
const logPath = path.join('electron-windows-sign.log');
const options = JSON.parse(process.argv[2]);
const signArgv = JSON.parse(process.argv[3]);
const files = signArgv.slice(-1);
try {
fs.appendFileSync(logPath, \`\\nCalled with: \${JSON.stringify(process.argv, null, 2)}\`);
sign({ ...options, files })
.then((result) => {
fs.appendFileSync(logPath, \`\\nSuccessfully signed with result: \${result}\`);
})
.catch((error) => {
fs.appendFileSync(logPath, \`\\nError from sign: \${error}\`);
throw new Error(error);
});
} catch (error) {
fs.appendFileSync(logPath, \`\\Error invoking sign: \${error}\`);
throw new Error(error);
}
`;
/**
* Uses Node's "Single Executable App" functionality
* to create a Node-driven signtool.exe that calls this
* module.
*
* This is useful with other tooling that _always_ calls
* a signtool.exe to sign. Some of those tools cannot be
* easily configured, but we _can_ override their signtool.exe.
*
* @category Single executable applications
*/
export async function createSeaSignTool(options = {}) {
checkCompatibility();
const requiredOptions = await getOptions(options);
await createFiles(requiredOptions);
await createBlob(requiredOptions);
await createBinary(requiredOptions);
await createSeaReceiver(requiredOptions);
await cleanup(requiredOptions);
return requiredOptions;
}
async function createSeaReceiver(options) {
const receiverPath = path.join(options.dir, FILENAMES.SEA_RECEIVER);
await fs.ensureFile(receiverPath);
await fs.writeFile(receiverPath, SEA_RECEIVER_SCRIPT);
}
async function createFiles(options) {
const { dir, bin } = options;
const receiverPath = path.join(options.dir, FILENAMES.SEA_RECEIVER);
// sea-config.json
await fs.outputJSON(path.join(dir, FILENAMES.SEA_CONFIG), {
main: FILENAMES.SEA_MAIN,
output: FILENAMES.SEA_BLOB,
disableExperimentalSEAWarning: true
}, {
spaces: 2
});
// signtool.js
const binPath = bin || process.execPath;
const script = SEA_MAIN_SCRIPT
.replace('%PATH_TO_BIN%', escapeMaybe(binPath))
.replace('%PATH_TO_SCRIPT%', escapeMaybe(receiverPath))
.replace('%WINDOWS_SIGN_OPTIONS%', JSON.stringify(options.windowsSign));
await fs.outputFile(path.join(dir, FILENAMES.SEA_MAIN), script);
}
async function createBlob(options) {
const args = ['--experimental-sea-config', 'sea-config.json'];
const bin = process.execPath;
const cwd = options.dir;
log(`Calling ${bin} with options:`, args);
const { stderr, stdout } = await spawnPromise(bin, args, {
cwd
});
log('stdout:', stdout);
log('stderr:', stderr);
}
async function createBinary(options) {
const { dir, filename } = options;
log(`Creating ${filename} in ${dir}`);
// Copy Node over
const seaPath = path.join(dir, filename);
await fs.copyFile(process.execPath, seaPath);
// Remove the Node signature
const signtool = path.join(DIRNAME, '../../vendor/signtool.exe');
await spawnPromise(signtool, [
'remove',
'/s',
seaPath
]);
// Inject the blob
const blob = await fs.readFile(path.join(dir, FILENAMES.SEA_BLOB));
await postject.inject(seaPath, 'NODE_SEA_BLOB', blob, {
sentinelFuse: 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2'
});
}
async function cleanup(options) {
const { dir } = options;
const toRemove = [
FILENAMES.SEA_BLOB,
FILENAMES.SEA_MAIN,
FILENAMES.SEA_CONFIG
];
for (const file of toRemove) {
try {
await fs.remove(path.join(dir, file));
}
catch (error) {
console.warn(`Tried and failed to remove ${file}. Continuing.`, error);
}
}
}
async function getOptions(options) {
const cloned = { ...options };
if (!cloned.path) {
cloned.path = path.join(os.homedir(), '.electron', 'windows-sign', 'sea.exe');
await fs.ensureFile(cloned.path);
}
if (!cloned.bin) {
cloned.bin = process.execPath;
}
if (!cloned.windowsSign) {
throw new Error('Did not find windowsSign options, which are required');
}
return {
path: cloned.path,
dir: path.dirname(cloned.path),
filename: path.basename(cloned.path),
bin: cloned.bin,
windowsSign: cloned.windowsSign
};
}
/**
* Ensures that the current Node.js version supports SEA app generation and errors if not.
*/
function checkCompatibility() {
const version = process.versions.node;
const split = version.split('.');
const major = parseInt(split[0], 10);
if (major >= 20) {
return true;
}
throw new Error(`Your Node.js version (${process.version}) does not support Single Executable Applications. Please upgrade your version of Node.js.`);
}
/** Make sure that the input string has escaped backwards slashes
* - but never double-escaped backwards slashes.
*/
function escapeMaybe(input) {
const result = input.split(path.sep).join('\\\\');
if (result.includes('\\\\\\\\')) {
throw new Error(`Your passed input ${input} contains escaped slashes. Please do not escape them`);
}
return result;
}
+8
View File
@@ -0,0 +1,8 @@
import { InternalSignOptions } from './types';
/**
* Sign with a hook function, basically letting everyone
* write completely custom sign logic
*
* @param {InternalSignOptions} options
*/
export declare function signWithHook(options: InternalSignOptions): Promise<void>;
+38
View File
@@ -0,0 +1,38 @@
import path from 'path';
import { log } from './utils/log';
let hookFunction;
function getHookFunction(options) {
if (options.hookFunction) {
return options.hookFunction;
}
if (options.hookModulePath) {
const module = require(path.resolve(options.hookModulePath));
if (module.default) {
return module.default;
}
if (typeof module === 'function') {
return module;
}
}
if (!hookFunction) {
throw new Error('No hook function found. Signing will not be possible. Please see the documentation for how to pass a hook function to @electron/windows-sign');
}
return hookFunction;
}
/**
* Sign with a hook function, basically letting everyone
* write completely custom sign logic
*
* @param {InternalSignOptions} options
*/
export async function signWithHook(options) {
hookFunction = getHookFunction(options);
for (const file of options.files) {
try {
await hookFunction(file);
}
catch (error) {
log(`Error signing ${file}`, error);
}
}
}
+2
View File
@@ -0,0 +1,2 @@
import { InternalSignOptions } from './types';
export declare function signWithSignTool(options: InternalSignOptions): Promise<void>;
+111
View File
@@ -0,0 +1,111 @@
import path from 'path';
import { log } from './utils/log';
import { spawnPromise } from './spawn';
import { getDirname } from 'cross-dirname';
const DIRNAME = getDirname();
function getSigntoolArgs(options) {
// See the following url for docs
// https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
const { certificateFile, certificatePassword, hash, timestampServer } = options;
const args = ['sign'];
// Automatically select cert
if (options.automaticallySelectCertificate) {
args.push('/a');
}
// Dual-sign
if (options.appendSignature) {
args.push('/as');
}
// Timestamp
if (hash === "sha256" /* HASHES.sha256 */) {
args.push('/tr', timestampServer);
args.push('/td', hash);
}
else {
args.push('/t', timestampServer);
}
// Certificate file
if (certificateFile) {
args.push('/f', path.resolve(certificateFile));
}
// Certificate password
if (certificatePassword) {
args.push('/p', certificatePassword);
}
// Hash
args.push('/fd', hash);
// Description
if (options.description) {
args.push('/d', options.description);
}
// Website
if (options.website) {
args.push('/du', options.website);
}
// Debug
if (options.debug) {
args.push('/debug');
}
if (options.signWithParams) {
const extraArgs = [];
if (Array.isArray(options.signWithParams)) {
extraArgs.push(...options.signWithParams);
}
else {
// Split up at spaces and doublequotes
extraArgs.push(...options.signWithParams.match(/(?:[^\s"]+|"[^"]*")+/g));
}
log('Parsed signWithParams as:', extraArgs);
args.push(...extraArgs);
}
return args;
}
async function execute(options) {
const { signToolPath, files } = options;
const args = getSigntoolArgs(options);
log('Executing signtool with args', { args, files });
const { code, stderr, stdout } = await spawnPromise(signToolPath, [...args, ...files], {
env: process.env,
cwd: process.cwd()
});
if (code !== 0) {
throw new Error(`Signtool exited with code ${code}. Stderr: ${stderr}. Stdout: ${stdout}`);
}
}
export async function signWithSignTool(options) {
const certificatePassword = options.certificatePassword || process.env.WINDOWS_CERTIFICATE_PASSWORD;
const certificateFile = options.certificateFile || process.env.WINDOWS_CERTIFICATE_FILE;
const signWithParams = options.signWithParams || process.env.WINDOWS_SIGN_WITH_PARAMS;
const timestampServer = options.timestampServer || process.env.WINDOWS_TIMESTAMP_SERVER || 'http://timestamp.digicert.com';
const signToolPath = options.signToolPath || process.env.WINDOWS_SIGNTOOL_PATH || path.join(DIRNAME, '../../vendor/signtool.exe');
const description = options.description || process.env.WINDOWS_SIGN_DESCRIPTION;
const website = options.website || process.env.WINDOWS_SIGN_WEBSITE;
if (!certificateFile && !(signWithParams || signToolPath)) {
throw new Error('You must provide a certificateFile and a signToolPath or signing parameters');
}
if (!signToolPath && !signWithParams && !certificatePassword) {
throw new Error('You must provide a certificatePassword or signing parameters');
}
const internalOptions = {
appendSignature: false,
...options,
certificateFile,
certificatePassword,
signWithParams,
signToolPath,
description,
timestampServer,
website
};
const hashes = options.hashes == null || options.hashes.length === 0
? ["sha1" /* HASHES.sha1 */, "sha256" /* HASHES.sha256 */]
: options.hashes;
if (hashes.includes("sha1" /* HASHES.sha1 */)) {
await execute({ ...internalOptions, hash: "sha1" /* HASHES.sha1 */ });
// If we signed with SHA1, we need to append the SHA256 signature:
internalOptions.appendSignature = true;
}
if (hashes.includes("sha256" /* HASHES.sha256 */)) {
await execute({ ...internalOptions, hash: "sha256" /* HASHES.sha256 */ });
}
}
+13
View File
@@ -0,0 +1,13 @@
import { SignOptions } from './types';
/**
* This is the main function exported from this module. It'll
* look at your options, determine the best way to sign a file,
* and then return one of our internal functions to do the actual
* signing.
*
* @param options
* @returns {Promise<void>}
*
* @category Sign
*/
export declare function sign(options: SignOptions): Promise<void>;
+41
View File
@@ -0,0 +1,41 @@
import { getFilesToSign } from './files';
import { signWithHook } from './sign-with-hook';
import { signWithSignTool } from './sign-with-signtool';
import { enableDebugging, log } from './utils/log';
import { booleanFromEnv } from './utils/parse-env';
/**
* This is the main function exported from this module. It'll
* look at your options, determine the best way to sign a file,
* and then return one of our internal functions to do the actual
* signing.
*
* @param options
* @returns {Promise<void>}
*
* @category Sign
*/
export async function sign(options) {
const signJavaScript = options.signJavaScript || booleanFromEnv('WINDOWS_SIGN_JAVASCRIPT');
const hookModulePath = options.hookModulePath || process.env.WINDOWS_SIGN_HOOK_MODULE_PATH;
if (options.debug) {
enableDebugging();
}
log('Called with options', { options });
const files = getFilesToSign(options);
const internalOptions = {
...options,
signJavaScript,
hookModulePath,
files
};
// If a hook is provides, sign with the hook
if (internalOptions.hookFunction || internalOptions.hookModulePath) {
log('Signing with hook');
return signWithHook(internalOptions);
}
// If we're going with the defaults, we're signing
// with signtool. Custom signing tools are also
// handled here.
log('Signing with signtool');
return signWithSignTool(internalOptions);
}
+16
View File
@@ -0,0 +1,16 @@
/// <reference types="node" />
import { SpawnOptions } from 'child_process';
export interface SpawnPromiseResult {
stdout: string;
stderr: string;
code: number;
}
/**
* Spawn a process as a promise
*
* @param {string} name
* @param {Array<string>} args
* @param {SpawnOptions} [options]
* @returns {Promise<SpawnPromiseResult>}
*/
export declare function spawnPromise(name: string, args: Array<string>, options?: SpawnOptions): Promise<SpawnPromiseResult>;
+30
View File
@@ -0,0 +1,30 @@
import { log } from './utils/log';
/**
* Spawn a process as a promise
*
* @param {string} name
* @param {Array<string>} args
* @param {SpawnOptions} [options]
* @returns {Promise<SpawnPromiseResult>}
*/
export function spawnPromise(name, args, options) {
return new Promise((resolve) => {
const { spawn } = require('child_process');
const fork = spawn(name, args, options);
log(`Spawning ${name} with ${args}`);
let stdout = '';
let stderr = '';
fork.stdout.on('data', (data) => {
log(`Spawn ${name} stdout: ${data}`);
stdout += data;
});
fork.stderr.on('data', (data) => {
log(`Spawn ${name} stderr: ${data}`);
stderr += data;
});
fork.on('close', (code) => {
log(`Spawn ${name}: Child process exited with code ${code}`);
resolve({ stdout, stderr, code });
});
});
}
+143
View File
@@ -0,0 +1,143 @@
/**
* SHA-1 has been deprecated on Windows since 2016. We'll still dualsign.
* https://social.technet.microsoft.com/wiki/contents/articles/32288.windows-enforcement-of-sha1-certificates.aspx#Post-February_TwentySeventeen_Plan
*/
export declare const enum HASHES {
sha1 = "sha1",
sha256 = "sha256"
}
/**
* Signing can be either by specifying a directory of files to sign.
*
* @category Sign
*/
export type SignOptions = SignOptionsForDirectory | SignOptionsForFiles;
/**
* Options for signing by passing a path to a directory to be codesigned.
*
* @category Sign
*/
export interface SignOptionsForDirectory extends SignToolOptions {
/**
* Path to the application directory. We will scan this
* directory for any `.dll`, `.exe`, `.msi`, or `.node` files and
* codesign them with `signtool.exe`.
*/
appDirectory: string;
}
/**
* Options for signing by passing an array of files to be codesigned.
*
* @category Sign
*/
export interface SignOptionsForFiles extends SignToolOptions {
/**
* Array of paths to files to be codesigned with `signtool.exe`.
*/
files: Array<string>;
}
/**
* @category Utility
*/
export interface SignToolOptions extends OptionalSignToolOptions, OptionalHookOptions {
}
export interface InternalSignOptions extends SignOptionsForFiles {
}
export interface InternalSignToolOptions extends OptionalSignToolOptions, OptionalHookOptions {
signToolPath: string;
timestampServer: string;
files: Array<string>;
hash: HASHES;
appendSignature?: boolean;
}
/**
* @category Utility
*/
export interface OptionalSignToolOptions {
/**
* Path to a `.pfx` code signing certificate.
* Will use `process.env.WINDOWS_CERTIFICATE_FILE` if this option is not provided.
*/
certificateFile?: string;
/**
* Password to {@link certificateFile}. If you don't provide this,
* you need to provide the {@link signWithParams} option.
* Will use `process.env.WINDOWS_CERTIFICATE_PASSWORD` if this option is not provided.
*/
certificatePassword?: string;
/**
* Path to a timestamp server.
* Will use `process.env.WINDOWS_TIMESTAMP_SERVER` if this option is not provided.
*
* @defaultValue http://timestamp.digicert.com
*/
timestampServer?: string;
/**
* Description of the signed content. Will be passed to `signtool.exe` as `/d`.
*/
description?: string;
/**
* URL for the expanded description of the signed content. Will be passed to `signtool.exe` as `/du`.
*/
website?: string;
/**
* Path to the `signtool.exe` used to sign. Will use `vendor/signtool.exe` if not provided.
*/
signToolPath?: string;
/**
* Additional parameters to pass to `signtool.exe`.
*
* @see Microsoft's {@link https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe SignTool.exe documentation}
*/
signWithParams?: string | Array<string>;
/**
* Enables debug logging.
*
* @defaultValue false
*/
debug?: boolean;
/**
* Automatically selects the best signing certificate according to SignTool. Will be passed to `signtool.exe` as `/a`.
*
* @defaultValue true
*/
automaticallySelectCertificate?: boolean;
/**
* Whether or not to sign JavaScript files.
*
* @defaultValue false
*/
signJavaScript?: boolean;
/**
* Hash algorithms to use for signing.
*/
hashes?: HASHES[];
}
/**
* Custom function that is called sequentially for each file that needs to be signed.
*
* @param fileToSign Absolute path to the file to sign
*
* @category Utility
*/
export type HookFunction = (fileToSign: string) => void | Promise<void>;
/**
* @category Utility
*/
export interface OptionalHookOptions {
/**
* A hook function called for each file that needs to be signed.
* Use this for full control over your app's signing logic.
* `@electron/windows-sign` will not attempt to sign with SignTool if a custom hook is detected.
*/
hookFunction?: HookFunction;
/**
* A path to a JavaScript file, exporting a single function that will be called for each file that needs to be signed.
* Use this for full control over your app's signing logic.
* `@electron/windows-sign` will not attempt to sign with SignTool if a custom hook is detected.
*/
hookModulePath?: string;
}
export interface InternalHookOptions extends OptionalHookOptions {
files: Array<string>;
}
+1
View File
@@ -0,0 +1 @@
export {};
+2
View File
@@ -0,0 +1,2 @@
export declare function enableDebugging(): void;
export declare const log: import("debug").Debugger;
+5
View File
@@ -0,0 +1,5 @@
import { debug as debugModule } from 'debug';
export function enableDebugging() {
debugModule.enable('electron-windows-sign');
}
export const log = debugModule('electron-windows-sign');
+11
View File
@@ -0,0 +1,11 @@
/**
* Tries to parse an process.env string to a boolean.
* Will understand undefined as the default value
* Will understand "false", "False", "fAlse", or "0" as `false`
* Will understand everything else as true
*
* @export
* @param {string} name
* @return {*} {boolean}
*/
export declare function booleanFromEnv(name: string): boolean | undefined;
+20
View File
@@ -0,0 +1,20 @@
/**
* Tries to parse an process.env string to a boolean.
* Will understand undefined as the default value
* Will understand "false", "False", "fAlse", or "0" as `false`
* Will understand everything else as true
*
* @export
* @param {string} name
* @return {*} {boolean}
*/
export function booleanFromEnv(name) {
const value = process.env[name];
if (value === undefined) {
return undefined;
}
if (value.toLowerCase() === 'false' || value === '0') {
return false;
}
return !!value;
}