From 0dc1118e5bf6e187a9c94e9e5618d0e49c651b24 Mon Sep 17 00:00:00 2001 From: Richard Herman Date: Fri, 8 Mar 2024 12:54:50 +0000 Subject: [PATCH 1/2] fix: remove Nodejs.Debug property when bundling --- src/commands/pack.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/commands/pack.ts b/src/commands/pack.ts index c5ad5e7..67f3984 100644 --- a/src/commands/pack.ts +++ b/src/commands/pack.ts @@ -5,6 +5,7 @@ import { createReadStream, createWriteStream, existsSync, writeFileSync } from " import { readFile, rm } from "node:fs/promises"; import { basename, dirname, join, resolve } from "node:path"; import { Readable, Writable } from "node:stream"; +import type { ReadableStream } from "node:stream/web"; import { command } from "../common/command"; import { StdoutError } from "../common/stdout"; import { getPluginId } from "../stream-deck"; @@ -110,9 +111,9 @@ function getPackageBuilder(sourcePath: string, outputPath: string, dryRun = fals const zipStream = new ZipWriter(Writable.toWeb(createWriteStream(outputPath))); return { - add: async (file: FileInfo): Promise => { + add: async (file: FileInfo, stream?: ReadableStream): Promise => { const name = join(entryPrefix, file.path.relative).replaceAll("\\", "/"); - await zipStream.add(name, Readable.toWeb(createReadStream(file.path.absolute))); + await zipStream.add(name, stream ?? Readable.toWeb(createReadStream(file.path.absolute))); }, close: () => zipStream.close() }; @@ -124,7 +125,7 @@ function getPackageBuilder(sourcePath: string, outputPath: string, dryRun = fals * @param fileFn Optional function called for each file that is considered part of the package. * @returns Information about the package contents. */ -async function getPackageContents(path: string, fileFn?: (file: FileInfo) => Promise | void): Promise { +async function getPackageContents(path: string, fileFn?: (file: FileInfo, stream?: ReadableStream) => Promise | void): Promise { // Get the manifest, and generate the base contents. const manifest = await readJsonFile(join(path, "manifest.json")); const contents: PackageInfo = { @@ -138,10 +139,23 @@ async function getPackageContents(path: string, fileFn?: (file: FileInfo) => Pro for await (const file of getFiles(path)) { contents.files.push(file); contents.sizePad = Math.max(contents.sizePad, file.size.text.length); - contents.size += file.size.bytes; if (fileFn) { - await fileFn(file); + // When the entry is the manifest, remove the `Nodejs.Debug` flag. + if (file.path.relative === "manifest.json") { + delete manifest.Nodejs?.Debug; + const sanitizedManifest = JSON.stringify(manifest, undefined, "".repeat(4)); + + const stream = new Readable(); + stream.push(sanitizedManifest, "utf-8"); + stream.push(null); // End-of-file. + + contents.size += sanitizedManifest.length; + await fileFn(file, Readable.toWeb(stream)); + } else { + contents.size += file.size.bytes; + await fileFn(file); + } } } From 89f34172732d5dd01cbb1123c3e2a21d1035f3a7 Mon Sep 17 00:00:00 2001 From: Richard Herman Date: Fri, 8 Mar 2024 13:43:32 +0000 Subject: [PATCH 2/2] feat: ignore files with potentially sensitive information --- src/system/fs.ts | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/system/fs.ts b/src/system/fs.ts index 3ae4e42..c0441d1 100644 --- a/src/system/fs.ts +++ b/src/system/fs.ts @@ -6,14 +6,16 @@ import { basename, join, resolve } from "node:path"; import { createInterface } from "node:readline"; export const streamDeckIgnoreFilename = ".sdignore"; +export const defaultIgnorePatterns = [streamDeckIgnoreFilename, ".git", "/.env*", "*.log", "*.js.map"]; /** * Gets files within the specified {@link path}, and their associated information, for example file size. When a `.sdignore` file is found within the {@link path}, it is respected, * and the files are ignored. * @param path Path to the directory to read. + * @param ignorePatterns Collection of default ignore patterns; this will be concatenated with patterns defined in a `.sdignore` file if one exists. * @yields Files in the directory. */ -export async function* getFiles(path: string): AsyncGenerator { +export async function* getFiles(path: string, ignorePatterns?: string[]): AsyncGenerator { if (!existsSync(path)) { return; } @@ -22,7 +24,7 @@ export async function* getFiles(path: string): AsyncGenerator { throw new Error("Path is not a directory"); } - const ignores = await getIgnores(path); + const ignores = await getIgnores(path, ignorePatterns); // We don't use withFileTypes as this yields incomplete results in Node.js 20.5.1; as we need the size anyway, we instead can rely on lstatSync as a direct call. for (const entry of await readdir(path, { encoding: "utf-8", recursive: true })) { @@ -56,30 +58,29 @@ export async function* getFiles(path: string): AsyncGenerator { /** * Builds an ignore predicate from the `.sdignore` file located within the specified {@link path}. The predicate will return `true` when the path supplied to it should be ignored. * @param path Path to the directory that contains the optional `.sdignore` file. + * @param defaultPatterns Collection of default ignore patterns. * @returns Predicate that determines whether the path should be ignored; returns `true` when the path should be ignored. */ -export async function getIgnores(path: string): Promise<(path: string) => boolean> { - const file = join(path, streamDeckIgnoreFilename); - if (!existsSync(file)) { - return () => false; - } - - // Open the ".sdignore" to determine the ignore patterns. - const fileStream = createReadStream(file); - const i = ignore().add(streamDeckIgnoreFilename); +export async function getIgnores(path: string, defaultPatterns: string[] = defaultIgnorePatterns): Promise<(path: string) => boolean> { + const i = ignore().add(defaultPatterns); - try { - const rl = createInterface({ - input: fileStream, - crlfDelay: Infinity - }); - - // Treat each line as a pattern, adding it to the ignore. - for await (const line of rl) { - i.add(line); + // When a ".sdignore" file is present, add the ignore patterns. + const file = join(path, streamDeckIgnoreFilename); + if (existsSync(file)) { + const fileStream = createReadStream(file); + try { + const rl = createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + + // Treat each line as a pattern, adding it to the ignore. + for await (const line of rl) { + i.add(line); + } + } finally { + fileStream.close(); } - } finally { - fileStream.close(); } return (p) => i.ignores(p);