yamlock 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cli/cli.js +66 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -67,6 +67,7 @@ The CLI detects YAML (`.yaml`/`.yml`) and JSON extensions automatically and writ
|
|
|
67
67
|
Options of note:
|
|
68
68
|
- `--output <file>` writes the result to a separate file instead of overwriting the input.
|
|
69
69
|
- `--paths <path1,path2>` targets only the specified fields (dot/bracket notation like `db.password` or `users[0].token`).
|
|
70
|
+
- `--dry-run` shows the would-be changes without modifying files (prints original vs new content).
|
|
70
71
|
- Command `keygen` produces a random key and shows how to store it (shell export or `.env`).
|
|
71
72
|
- Command `algorithms` prints two lists: tested presets (covered by yamlock) and additional ciphers available from the runtime.
|
|
72
73
|
- Command `version` prints the installed CLI version.
|
package/dist/cli/cli.js
CHANGED
|
@@ -37,6 +37,7 @@ Options:
|
|
|
37
37
|
-a, --algorithm <value> Cipher algorithm (default: aes-256-cbc).
|
|
38
38
|
-o, --output <file> Write the result to a different file (otherwise overwrites the input file).
|
|
39
39
|
-p, --paths <p1,p2> Comma-separated list of field paths to process (dot/bracket notation).
|
|
40
|
+
-d, --dry-run Show the diff without modifying files.
|
|
40
41
|
--length <bytes> (keygen) Number of random bytes to generate (default: 32).
|
|
41
42
|
--format <hex|base64> (keygen) Output format (default: base64).
|
|
42
43
|
`;
|
|
@@ -64,21 +65,22 @@ function readConfigFile(filePath) {
|
|
|
64
65
|
const format = detectFormat(filePath);
|
|
65
66
|
|
|
66
67
|
if (format === 'yaml') {
|
|
67
|
-
return { format, data: yaml.load(content) ?? {} };
|
|
68
|
+
return { format, data: yaml.load(content) ?? {}, raw: content };
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
return { format, data: JSON.parse(content) };
|
|
71
|
+
return { format, data: JSON.parse(content), raw: content };
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
function
|
|
74
|
+
function serializeConfig(format, data) {
|
|
74
75
|
if (format === 'yaml') {
|
|
75
|
-
|
|
76
|
-
writeFileSync(filePath, serialized, 'utf8');
|
|
77
|
-
return;
|
|
76
|
+
return yaml.dump(data, { lineWidth: 120 });
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
return `${JSON.stringify(data, null, 2)}\n`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function writeConfigFile(filePath, serialized) {
|
|
83
|
+
writeFileSync(filePath, serialized, 'utf8');
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
function parsePaths(value) {
|
|
@@ -97,7 +99,7 @@ function parseArgs(argv) {
|
|
|
97
99
|
const result = {
|
|
98
100
|
command: args[0],
|
|
99
101
|
file: undefined,
|
|
100
|
-
options: {}
|
|
102
|
+
options: { dryRun: false }
|
|
101
103
|
};
|
|
102
104
|
|
|
103
105
|
let index = 1;
|
|
@@ -131,9 +133,15 @@ function parseArgs(argv) {
|
|
|
131
133
|
} else if (arg === '--format') {
|
|
132
134
|
result.options.format = next;
|
|
133
135
|
i += 1;
|
|
136
|
+
} else if (arg === '-d' || arg === '--dry-run') {
|
|
137
|
+
result.options.dryRun = true;
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
|
|
141
|
+
if (result.options.dryRun && result.command && !result.file && !['version', 'algorithms', 'keygen'].includes(result.command)) {
|
|
142
|
+
// dry-run without file is invalid, but we'll let later validation handle file requirement
|
|
143
|
+
}
|
|
144
|
+
|
|
137
145
|
return result;
|
|
138
146
|
}
|
|
139
147
|
|
|
@@ -146,6 +154,30 @@ function generateRandomKey(length, format) {
|
|
|
146
154
|
return buffer.toString('base64');
|
|
147
155
|
}
|
|
148
156
|
|
|
157
|
+
function fail(code, message) {
|
|
158
|
+
printError(`[yamlock:${code}] ${message}`);
|
|
159
|
+
return exit(1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function handleWrite({ dryRun, file, outputPath, format, originalRaw, data, operation }) {
|
|
163
|
+
const serialized = serializeConfig(format, data);
|
|
164
|
+
if (dryRun) {
|
|
165
|
+
print(`DRY-RUN (${operation}) ${file}`);
|
|
166
|
+
print('--- original');
|
|
167
|
+
print((originalRaw ?? '').trimEnd());
|
|
168
|
+
print('+++ result');
|
|
169
|
+
print(serialized.trimEnd());
|
|
170
|
+
if (outputPath !== file) {
|
|
171
|
+
print(`(would write to ${outputPath})`);
|
|
172
|
+
}
|
|
173
|
+
print('No files were modified.');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
writeConfigFile(outputPath, serialized);
|
|
178
|
+
print(`${operation === 'encrypt' ? 'Encrypted' : 'Decrypted'} values in ${outputPath}`);
|
|
179
|
+
}
|
|
180
|
+
|
|
149
181
|
export async function runCli(argv = process.argv) {
|
|
150
182
|
const { command, file, options } = parseArgs(argv);
|
|
151
183
|
|
|
@@ -181,13 +213,11 @@ export async function runCli(argv = process.argv) {
|
|
|
181
213
|
const normalizedFormat = (options.format ?? 'base64').toLowerCase();
|
|
182
214
|
|
|
183
215
|
if (!Number.isFinite(desiredLength) || desiredLength <= 0) {
|
|
184
|
-
|
|
185
|
-
return exit(1);
|
|
216
|
+
return fail('ERR_INVALID_LENGTH', 'Key length must be a positive number.');
|
|
186
217
|
}
|
|
187
218
|
|
|
188
219
|
if (!['base64', 'hex'].includes(normalizedFormat)) {
|
|
189
|
-
|
|
190
|
-
return exit(1);
|
|
220
|
+
return fail('ERR_INVALID_FORMAT', 'Key format must be either "base64" or "hex".');
|
|
191
221
|
}
|
|
192
222
|
|
|
193
223
|
const keyValue = generateRandomKey(desiredLength, normalizedFormat);
|
|
@@ -200,15 +230,13 @@ export async function runCli(argv = process.argv) {
|
|
|
200
230
|
}
|
|
201
231
|
|
|
202
232
|
if (!file) {
|
|
203
|
-
printError('A file path is required for this command.');
|
|
204
233
|
print(getHelpText().trim());
|
|
205
|
-
return
|
|
234
|
+
return fail('ERR_FILE_REQUIRED', 'A file path is required for this command.');
|
|
206
235
|
}
|
|
207
236
|
|
|
208
237
|
const key = options.key ?? process.env.YAMLOCK_KEY;
|
|
209
238
|
if (!key) {
|
|
210
|
-
|
|
211
|
-
return exit(1);
|
|
239
|
+
return fail('ERR_MISSING_KEY', 'Encryption key is required via --key or YAMLOCK_KEY.');
|
|
212
240
|
}
|
|
213
241
|
|
|
214
242
|
const absolutePath = resolve(process.cwd(), file);
|
|
@@ -216,8 +244,7 @@ export async function runCli(argv = process.argv) {
|
|
|
216
244
|
try {
|
|
217
245
|
config = readConfigFile(absolutePath);
|
|
218
246
|
} catch (error) {
|
|
219
|
-
|
|
220
|
-
return exit(1);
|
|
247
|
+
return fail('ERR_READ_FAILED', `Failed to read config file: ${error.message}`);
|
|
221
248
|
}
|
|
222
249
|
|
|
223
250
|
const outputPath = options.output
|
|
@@ -232,8 +259,15 @@ export async function runCli(argv = process.argv) {
|
|
|
232
259
|
algorithm: options.algorithm,
|
|
233
260
|
paths: options.paths
|
|
234
261
|
});
|
|
235
|
-
|
|
236
|
-
|
|
262
|
+
handleWrite({
|
|
263
|
+
dryRun: options.dryRun,
|
|
264
|
+
file,
|
|
265
|
+
outputPath,
|
|
266
|
+
format: config.format,
|
|
267
|
+
originalRaw: config.raw,
|
|
268
|
+
data: result,
|
|
269
|
+
operation: 'encrypt'
|
|
270
|
+
});
|
|
237
271
|
return exit(0);
|
|
238
272
|
}
|
|
239
273
|
|
|
@@ -244,17 +278,22 @@ export async function runCli(argv = process.argv) {
|
|
|
244
278
|
algorithm: options.algorithm,
|
|
245
279
|
paths: options.paths
|
|
246
280
|
});
|
|
247
|
-
|
|
248
|
-
|
|
281
|
+
handleWrite({
|
|
282
|
+
dryRun: options.dryRun,
|
|
283
|
+
file,
|
|
284
|
+
outputPath,
|
|
285
|
+
format: config.format,
|
|
286
|
+
originalRaw: config.raw,
|
|
287
|
+
data: result,
|
|
288
|
+
operation: 'decrypt'
|
|
289
|
+
});
|
|
249
290
|
return exit(0);
|
|
250
291
|
}
|
|
251
292
|
|
|
252
|
-
printError(`Unknown command: ${command}`);
|
|
253
293
|
print(getHelpText().trim());
|
|
254
|
-
return
|
|
294
|
+
return fail('ERR_UNKNOWN_COMMAND', `Unknown command: ${command}`);
|
|
255
295
|
} catch (error) {
|
|
256
|
-
|
|
257
|
-
return exit(1);
|
|
296
|
+
return fail('ERR_PROCESS_FAILED', `Operation failed: ${error.message}`);
|
|
258
297
|
}
|
|
259
298
|
}
|
|
260
299
|
|
package/package.json
CHANGED