From 941e6fa01681913ff778d5a08b6db5bc473abe6d Mon Sep 17 00:00:00 2001 From: "Y.Yamamoto" Date: Fri, 7 Nov 2025 23:01:06 +0900 Subject: [PATCH 1/2] feat: introduce restore and shuffle commands for image processing - Added `registerRestoreCommand` and `registerShuffleCommand` to the CLI for restoring fragmented images and shuffling images, respectively. - Updated types to include `RestoreOptions` and `ShuffleOptions`. - Refactored existing code to remove encryption functionality and focus on new commands. - Enhanced error handling and validation for the new commands. --- packages/cli/src/cli.ts | 8 +++---- .../src/commands/{decrypt.ts => restore.ts} | 18 +++++++------- .../src/commands/{encrypt.ts => shuffle.ts} | 18 +++++++------- packages/cli/src/index.ts | 2 +- packages/cli/src/types.ts | 4 ++-- packages/core/src/types.ts | 4 ++-- packages/node/src/index.test.ts | 16 ++++++------- packages/node/src/index.ts | 24 +++++++++---------- 8 files changed, 47 insertions(+), 47 deletions(-) rename packages/cli/src/commands/{decrypt.ts => restore.ts} (76%) rename packages/cli/src/commands/{encrypt.ts => shuffle.ts} (85%) diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index 85a6ce7..1fa53b5 100644 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -1,8 +1,8 @@ #!/usr/bin/env node import { Command } from "commander"; -import { registerDecryptCommand } from "./commands/decrypt"; -import { registerEncryptCommand } from "./commands/encrypt"; +import { registerRestoreCommand } from "./commands/restore"; +import { registerShuffleCommand } from "./commands/shuffle"; const program = new Command(); @@ -12,8 +12,8 @@ program .version("0.8.1"); // Register commands -registerEncryptCommand(program); -registerDecryptCommand(program); +registerShuffleCommand(program); +registerRestoreCommand(program); // Error handling program.on("command:*", () => { diff --git a/packages/cli/src/commands/decrypt.ts b/packages/cli/src/commands/restore.ts similarity index 76% rename from packages/cli/src/commands/decrypt.ts rename to packages/cli/src/commands/restore.ts index c8345b4..5f572d5 100644 --- a/packages/cli/src/commands/decrypt.ts +++ b/packages/cli/src/commands/restore.ts @@ -1,6 +1,6 @@ import ImageShield from "@image-shield/node"; import type { Command } from "commander"; -import type { DecryptOptions } from "../types"; +import type { RestoreOptions } from "../types"; import { validateImagePaths, validateManifestPath, @@ -8,27 +8,27 @@ import { } from "../validators"; /** - * Configures and registers the decrypt command + * Configures and registers the restore command * @param program Commander program instance */ -export function registerDecryptCommand(program: Command): void { +export function registerRestoreCommand(program: Command): void { program - .command("decrypt") + .command("restore") .description("Restore fragmented images") .argument("", "Fragment file paths") .requiredOption("-m, --manifest ", "Manifest file path") .requiredOption("-o, --output ", "Output directory") - .action(handleDecryptCommand); + .action(handleRestoreCommand); } /** - * Handles the decrypt command execution + * Handles the restore command execution * @param fragments Array of fragment file paths * @param options Command options */ -async function handleDecryptCommand( +async function handleRestoreCommand( fragments: string[], - options: DecryptOptions, + options: RestoreOptions, ): Promise { try { console.log("🔀 Starting image restoration..."); @@ -37,7 +37,7 @@ async function handleDecryptCommand( const manifestPath = validateManifestPath(options.manifest); const outputDir = validateOutputDirectory(options.output); - await ImageShield.decrypt({ + await ImageShield.restore({ imagePaths, manifestPath, outputDir, diff --git a/packages/cli/src/commands/encrypt.ts b/packages/cli/src/commands/shuffle.ts similarity index 85% rename from packages/cli/src/commands/encrypt.ts rename to packages/cli/src/commands/shuffle.ts index c528241..05eff7c 100644 --- a/packages/cli/src/commands/encrypt.ts +++ b/packages/cli/src/commands/shuffle.ts @@ -1,16 +1,16 @@ import type { FragmentationConfig } from "@image-shield/core"; import ImageShield from "@image-shield/node"; import type { Command } from "commander"; -import type { EncryptOptions } from "../types"; +import type { ShuffleOptions } from "../types"; import { validateImagePaths, validateOutputDirectory } from "../validators"; /** - * Configures and registers the encrypt command + * Configures and registers the shuffle command * @param program Commander program instance */ -export function registerEncryptCommand(program: Command): void { +export function registerShuffleCommand(program: Command): void { program - .command("encrypt") + .command("shuffle") .description("Fragment images") .argument("", "Input image file paths") .requiredOption("-o, --output ", "Output directory") @@ -30,17 +30,17 @@ export function registerEncryptCommand(program: Command): void { return num; }) .option("--restore-filename", "Restore original file names") - .action(handleEncryptCommand); + .action(handleShuffleCommand); } /** - * Handles the encrypt command execution + * Handles the shuffle command execution * @param images Array of image file paths * @param options Command options */ -async function handleEncryptCommand( +async function handleShuffleCommand( images: string[], - options: EncryptOptions, + options: ShuffleOptions, ): Promise { try { console.log("🔀 Starting image fragmentation..."); @@ -54,7 +54,7 @@ async function handleEncryptCommand( if (options.seed !== undefined) config.seed = options.seed; if (options.restoreFilename) config.restoreFileName = true; - await ImageShield.encrypt({ + await ImageShield.shuffle({ imagePaths, outputDir, config: Object.keys(config).length > 0 ? config : undefined, diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index d4283a6..89ef57d 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,4 +1,4 @@ // Export CLI functionality for programmatic usage if needed export { default as ImageShield } from "@image-shield/node"; export type { FragmentationConfig } from "@image-shield/core"; -export type { EncryptOptions, DecryptOptions } from "./types"; +export type { RestoreOptions, ShuffleOptions } from "./types"; diff --git a/packages/cli/src/types.ts b/packages/cli/src/types.ts index d0e8fe4..132fb1c 100644 --- a/packages/cli/src/types.ts +++ b/packages/cli/src/types.ts @@ -1,4 +1,4 @@ -export interface EncryptOptions { +export interface ShuffleOptions { output: string; blockSize?: number; prefix?: string; @@ -6,7 +6,7 @@ export interface EncryptOptions { restoreFilename?: boolean; } -export interface DecryptOptions { +export interface RestoreOptions { manifest: string; output: string; } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 00e859c..27424df 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1,4 +1,4 @@ -export interface EncryptOptions { +export interface ShuffleOptions { /** Image paths (e.g., ["image1.png", "image2.png"]) */ imagePaths: string[]; /** Fragmentation config */ @@ -7,7 +7,7 @@ export interface EncryptOptions { outputDir: string; } -export interface DecryptOptions { +export interface RestoreOptions { /** Image paths (e.g., ["fragment1.png", "fragment2.png"]) */ imagePaths: string[]; /** Manifest path (e.g., "./output/fragments/manifest.json") */ diff --git a/packages/node/src/index.test.ts b/packages/node/src/index.test.ts index 03db360..febe4bc 100644 --- a/packages/node/src/index.test.ts +++ b/packages/node/src/index.test.ts @@ -45,8 +45,8 @@ describe("ImageShield (integration)", () => { await image.write(filePath, JimpMime.png); imagePaths.push(filePath); } - // Fragment images using ImageShield.encrypt - await ImageShield.encrypt({ + // Fragment images using ImageShield.shuffle + await ImageShield.shuffle({ imagePaths, config: { blockSize, prefix }, outputDir: tmpDir, @@ -65,8 +65,8 @@ describe("ImageShield (integration)", () => { path.join(tmpDir, generateFragmentFileName(manifestDataForFragment, i)), ); } - // Restore images using ImageShield.decrypt - await ImageShield.decrypt({ + // Restore images using ImageShield.restore + await ImageShield.restore({ imagePaths: fragmentPaths, manifestPath, outputDir: tmpDir, @@ -168,8 +168,8 @@ describe("ImageShield (restoreFileName integration)", () => { await image.write(filePath, JimpMime.png); imagePaths.push(filePath); } - // Fragment images using ImageShield.encrypt (with restoreFileName) - await ImageShield.encrypt({ + // Fragment images using ImageShield.shuffle (with restoreFileName) + await ImageShield.shuffle({ imagePaths, config: { blockSize, prefix, restoreFileName: true }, outputDir: tmpDir, @@ -188,8 +188,8 @@ describe("ImageShield (restoreFileName integration)", () => { path.join(tmpDir, generateFragmentFileName(manifest, i)), ); } - // Restore images using ImageShield.decrypt - await ImageShield.decrypt({ + // Restore images using ImageShield.restore + await ImageShield.restore({ imagePaths: fragmentPaths, manifestPath, outputDir: tmpDir, diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 7a10d81..19d2aad 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -1,9 +1,9 @@ import { - type DecryptOptions, - type EncryptOptions, type FragmentationConfig, MANIFEST_FILE_NAME, type ManifestData, + type RestoreOptions, + type ShuffleOptions, generateFragmentFileName, generateRestoredFileName, generateRestoredOriginalFileName, @@ -20,8 +20,8 @@ export { }; export default class ImageShield { - static async encrypt(options: EncryptOptions): Promise { - const { imagePaths, config, outputDir } = validateEncryptOptions(options); + static async shuffle(options: ShuffleOptions): Promise { + const { imagePaths, config, outputDir } = validateShuffleOptions(options); const fragmenter = new ImageFragmenter(config ?? {}); const { manifest, fragmentedImages } = @@ -42,9 +42,9 @@ export default class ImageShield { ); } - static async decrypt(options: DecryptOptions): Promise { + static async restore(options: RestoreOptions): Promise { const { imagePaths, manifestPath, outputDir } = - validateDecryptOptions(options); + validateRestoreOptions(options); const manifest = await readJsonFile(manifestPath); @@ -65,7 +65,7 @@ export default class ImageShield { } } -function validateCommonOptions( +function validateCommonOptions( options: T, context: string, ) { @@ -78,13 +78,13 @@ function validateCommonOptions( return options; } -function validateEncryptOptions(options: EncryptOptions) { - return validateCommonOptions(options, "encrypt"); +function validateShuffleOptions(options: ShuffleOptions) { + return validateCommonOptions(options, "shuffle"); } -function validateDecryptOptions(options: DecryptOptions) { +function validateRestoreOptions(options: RestoreOptions) { const { manifestPath } = options; if (!manifestPath || typeof manifestPath !== "string") - throw new Error("[decrypt] manifestPath is required and must be a string."); - return validateCommonOptions(options, "decrypt"); + throw new Error("[restore] manifestPath is required and must be a string."); + return validateCommonOptions(options, "restore"); } From 88c3491622aa37c343db08f9354d1fb7be20c5c3 Mon Sep 17 00:00:00 2001 From: "Y.Yamamoto" Date: Fri, 7 Nov 2025 23:01:34 +0900 Subject: [PATCH 2/2] refactor: update README and CLI documentation for shuffle and restore commands - Renamed CLI commands from `encrypt` to `shuffle` and `decrypt` to `restore` to reflect new functionality. - Updated usage examples and command descriptions in the README files for both the main project and CLI package. - Adjusted output structure and error handling sections to align with the new command names. --- .docs/figure.png | Bin 14126 -> 11757 bytes README.md | 10 ++++------ packages/cli/README.md | 36 ++++++++++++++++++------------------ 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/.docs/figure.png b/.docs/figure.png index 15c198e1cbb8502cf70be61bf3812d2bf163f95e..643eb7fca459e51cfda7761d531b679a14b01758 100644 GIT binary patch literal 11757 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 Uon_ly;KqTpAL~CtsyRIU54b@HcmMzZ literal 14126 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 Mvo2? Fragment images - decrypt [options] Restore fragmented images + shuffle [options] Fragment images + restore [options] Restore fragmented images help [command] display help for command ``` -### Encrypt Command +### Shuffle Command Fragment images into multiple pieces. ```bash -image-shield encrypt -o [options] +image-shield shuffle -o [options] ``` #### Options @@ -55,17 +55,17 @@ image-shield encrypt -o [options] **Basic fragmentation:** ```bash -image-shield encrypt image1.jpg image2.png -o ./fragments +image-shield shuffle image1.jpg image2.png -o ./fragments ``` **Custom configuration:** ```bash -image-shield encrypt *.jpg -o ./output -b 20 -p "my_fragment" --restore-filename +image-shield shuffle *.jpg -o ./output -b 20 -p "my_fragment" --restore-filename ``` **With seed for reproducible results:** ```bash -image-shield encrypt image.png -o ./output -s 12345 +image-shield shuffle image.png -o ./output -s 12345 ``` #### Output Structure @@ -79,12 +79,12 @@ output/ └── ... ``` -### Decrypt Command +### Restore Command Restore fragmented images using the manifest file. ```bash -image-shield decrypt -m -o [options] +image-shield restore -m -o [options] ``` #### Options @@ -98,12 +98,12 @@ image-shield decrypt -m -o [op **Basic restoration:** ```bash -image-shield decrypt ./fragments/*.png -m ./fragments/manifest.json -o ./restored +image-shield restore ./fragments/*.png -m ./fragments/manifest.json -o ./restored ``` **Specific fragments:** ```bash -image-shield decrypt fragment_0000.png fragment_0001.png fragment_0002.png -m manifest.json -o ./output +image-shield restore fragment_0000.png fragment_0001.png fragment_0002.png -m manifest.json -o ./output ``` ## Error Handling @@ -127,7 +127,7 @@ The CLI provides clear error messages for common issues: 2. **Fragment images:** ```bash - image-shield encrypt images/photo1.jpg images/photo2.png -o ./backup --restore-filename + image-shield shuffle images/photo1.jpg images/photo2.png -o ./backup --restore-filename ``` ``` 🔀 Starting image fragmentation... @@ -142,7 +142,7 @@ The CLI provides clear error messages for common issues: 4. **Restore images:** ```bash - image-shield decrypt backup/*.png -m backup/manifest.json -o ./restored + image-shield restore backup/*.png -m backup/manifest.json -o ./restored ``` ``` 🔀 Starting image restoration... @@ -161,7 +161,7 @@ For custom fragmentation: ```bash # Fragment with custom settings -image-shield encrypt sensitive/*.jpg \ +image-shield shuffle sensitive/*.jpg \ -o ./vault \ -b 5 \ -p "secure_chunk" \ @@ -184,7 +184,7 @@ BACKUP_DIR="./backup" # Create backup echo "Creating backup..." -image-shield encrypt "$IMAGES_DIR"/*.{jpg,png} \ +image-shield shuffle "$IMAGES_DIR"/*.{jpg,png} \ -o "$BACKUP_DIR" \ --restore-filename @@ -208,7 +208,7 @@ RESTORE_DIR="./recovered_photos" # Restore from backup echo "Restoring from backup..." -image-shield decrypt "$BACKUP_DIR"/fragment_*.png \ +image-shield restore "$BACKUP_DIR"/fragment_*.png \ -m "$BACKUP_DIR/manifest.json" \ -o "$RESTORE_DIR" @@ -244,7 +244,7 @@ npm test ```bash cd packages/cli -npm run dev -- encrypt --help +npm run dev -- shuffle --help ``` ## Related Packages