Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ignore files with sensitive information, and remove debug flag #30

Merged
merged 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions src/commands/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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<void> => {
add: async (file: FileInfo, stream?: ReadableStream): Promise<void> => {
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()
};
Expand All @@ -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> | void): Promise<PackageInfo> {
async function getPackageContents(path: string, fileFn?: (file: FileInfo, stream?: ReadableStream) => Promise<void> | void): Promise<PackageInfo> {
// Get the manifest, and generate the base contents.
const manifest = await readJsonFile<Manifest>(join(path, "manifest.json"));
const contents: PackageInfo = {
Expand All @@ -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);
}
}
}

Expand Down
45 changes: 23 additions & 22 deletions src/system/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<FileInfo> {
export async function* getFiles(path: string, ignorePatterns?: string[]): AsyncGenerator<FileInfo> {
if (!existsSync(path)) {
return;
}
Expand All @@ -22,7 +24,7 @@ export async function* getFiles(path: string): AsyncGenerator<FileInfo> {
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 })) {
Expand Down Expand Up @@ -56,30 +58,29 @@ export async function* getFiles(path: string): AsyncGenerator<FileInfo> {
/**
* 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);
Expand Down