Skip to content

Commit 9b58b5c

Browse files
committed
Enhance encrypt-commands.js utility with master password support and improved decryption handling
- Updated encryption process to allow for a master password that can encrypt multiple files into a single entry. - Modified decryption logic to support outputting decrypted content to a directory when using a master password. - Improved error handling and feedback during decryption, including handling cases for invalid passwords and corrupted files. - Adjusted command-line usage instructions for clarity on new features.
1 parent b82a016 commit 9b58b5c

File tree

1 file changed

+60
-17
lines changed

1 file changed

+60
-17
lines changed

utils/encrypt-commands.js

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// This script encrypts/decrypts your secret commands with multiple passwords
22
// Each password will decrypt to different content
33
// Run it with Node.js:
4-
// To encrypt: node encrypt-commands.js encrypt
5-
// To decrypt: node encrypt-commands.js decrypt "password" "output.js"
4+
// To encrypt: node encrypt-commands.js encrypt [master_password]
5+
// To decrypt: node encrypt-commands.js decrypt password output.js
6+
// or node encrypt-commands.js decrypt master_password src/ (recreates all files)
67

78
const crypto = require("crypto");
89
const path = require("path");
@@ -42,7 +43,7 @@ function encryptContent(content, password, salt, iv) {
4243
return { encrypted, authTag: cipher.getAuthTag() };
4344
}
4445

45-
async function encryptCommands() {
46+
async function encryptCommands(masterPassword) {
4647
const srcDir = path.resolve(__dirname, "src");
4748
const files = fs.readdirSync(srcDir);
4849

@@ -51,7 +52,7 @@ async function encryptCommands() {
5152
const password = path.parse(filename).name; // Use filename without extension as password
5253
const file = path.resolve(srcDir, filename);
5354
const content = fs.readFileSync(file, "utf8");
54-
return { password, content };
55+
return { password, content, filename };
5556
});
5657

5758
if (entries.length === 0) {
@@ -62,6 +63,17 @@ async function encryptCommands() {
6263
const salt = crypto.randomBytes(CONFIG.saltLength);
6364
const iv = crypto.randomBytes(CONFIG.ivLength);
6465

66+
// If master password provided, add master entry with all files info
67+
if (masterPassword) {
68+
const masterContent = JSON.stringify(
69+
entries.map((e) => ({
70+
filename: e.filename,
71+
content: e.content,
72+
}))
73+
);
74+
entries.push({ password: masterPassword, content: masterContent });
75+
}
76+
6577
// Encrypt each content with its password
6678
const encryptedParts = entries.map(({ password, content }) => {
6779
const { encrypted, authTag } = encryptContent(content, password, salt, iv);
@@ -93,7 +105,7 @@ async function encryptCommands() {
93105
console.log(`- Number of encrypted parts: ${entries.length}`);
94106
}
95107

96-
async function decryptCommands(password, outputFile) {
108+
async function decryptCommands(password, outputPath) {
97109
const encryptedData = fs.readFileSync(ENCRYPTED_FILE);
98110

99111
// Extract common components
@@ -102,6 +114,7 @@ async function decryptCommands(password, outputFile) {
102114
const iv = encryptedData.slice(offset, (offset += CONFIG.ivLength));
103115

104116
const key = deriveKey(password, salt);
117+
const decryptedParts = [];
105118

106119
// Try to decrypt each part
107120
while (offset < encryptedData.length) {
@@ -124,18 +137,44 @@ async function decryptCommands(password, outputFile) {
124137
decipher.final(),
125138
]);
126139

127-
// If we get here, decryption was successful
128-
fs.writeFileSync(outputFile, decrypted);
129-
console.log(`Decrypted commands saved to ${outputFile}`);
130-
return;
140+
decryptedParts.push(decrypted);
131141
} catch (error) {
132142
// Try next part
133143
continue;
134144
}
135145
}
136146

137-
console.error("Decryption failed. Invalid password or corrupted file.");
138-
process.exit(1);
147+
if (decryptedParts.length === 0) {
148+
console.error("Decryption failed. Invalid password or corrupted file.");
149+
process.exit(1);
150+
}
151+
152+
// If output is a directory, try to parse as master password result
153+
if (outputPath.endsWith("/")) {
154+
try {
155+
// Try to parse as JSON (master password result)
156+
const files = JSON.parse(decryptedParts[0]);
157+
158+
// Ensure directory exists
159+
if (!fs.existsSync(outputPath)) {
160+
fs.mkdirSync(outputPath, { recursive: true });
161+
}
162+
163+
// Write each file
164+
files.forEach(({ filename, content }) => {
165+
const outputFile = path.join(outputPath, filename);
166+
fs.writeFileSync(outputFile, content);
167+
console.log(`Decrypted ${filename} saved to ${outputFile}`);
168+
});
169+
return;
170+
} catch (e) {
171+
// Not master password result, fall through to single file
172+
}
173+
}
174+
175+
// Normal single-file decryption
176+
fs.writeFileSync(outputPath, decryptedParts[0]);
177+
console.log(`Decrypted commands saved to ${outputPath}`);
139178
}
140179

141180
const action = process.argv[2];
@@ -144,19 +183,23 @@ const args = process.argv.slice(3);
144183
if (!action || !["encrypt", "decrypt"].includes(action)) {
145184
console.error(
146185
"Usage:\n" +
147-
" Encrypt: node encrypt-commands.js encrypt\n" +
186+
" Encrypt: node encrypt-commands.js encrypt [master_password]\n" +
148187
" Decrypt: node encrypt-commands.js decrypt password output.js"
149188
);
150189
process.exit(1);
151190
}
152191

153192
if (action === "encrypt") {
154-
encryptCommands();
193+
const masterPassword = args[0]; // Optional master password
194+
encryptCommands(masterPassword);
155195
} else {
156-
const [password, outputFile] = args;
157-
if (!password || !outputFile) {
158-
console.error("Decrypt requires password and output file");
196+
const [password, outputPath] = args;
197+
if (!password || !outputPath) {
198+
console.error("Decrypt requires password and output path");
199+
console.error(
200+
"Use directory path ending with / for master password to recreate all files"
201+
);
159202
process.exit(1);
160203
}
161-
decryptCommands(password, outputFile);
204+
decryptCommands(password, outputPath);
162205
}

0 commit comments

Comments
 (0)