dotsec 0.1.1 → 0.2.0

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/dist/esm/cli.js CHANGED
@@ -25,19 +25,15 @@ var __export = (target, all) => {
25
25
  import { hideBin } from "yargs/helpers";
26
26
  import yargs from "yargs/yargs";
27
27
 
28
- // src/commands/decryptSecCommand.ts
29
- var decryptSecCommand_exports = {};
30
- __export(decryptSecCommand_exports, {
28
+ // src/commands/debugCommand.ts
29
+ var debugCommand_exports = {};
30
+ __export(debugCommand_exports, {
31
31
  builder: () => builder,
32
32
  command: () => command,
33
33
  desc: () => desc,
34
34
  handler: () => handler
35
35
  });
36
- import { KMSClient, DecryptCommand } from "@aws-sdk/client-kms";
37
- import { redBright } from "chalk";
38
- import { parse } from "dotenv";
39
- import fs from "node:fs";
40
- import path from "node:path";
36
+ import { GetParametersByPathCommand } from "@aws-sdk/client-ssm";
41
37
 
42
38
  // src/commonCliOptions.ts
43
39
  var commonCliOptions = {
@@ -51,12 +47,27 @@ var commonCliOptions = {
51
47
  },
52
48
  awsKeyAlias: {
53
49
  string: true,
50
+ default: "alias/top-secret",
54
51
  describe: "AWS KMS asymmetric key alias"
55
52
  },
56
53
  awsKey: {
57
54
  string: true,
58
55
  describe: "AWS KMS asymmetric key arn"
59
56
  },
57
+ envFile: {
58
+ string: true,
59
+ describe: ".env file",
60
+ default: ".env"
61
+ },
62
+ secFile: {
63
+ string: true,
64
+ describe: ".sec file",
65
+ default: ".sec"
66
+ },
67
+ awsAssumeRoleArn: {
68
+ string: true,
69
+ describe: "arn or role to assume"
70
+ },
60
71
  verbose: {
61
72
  boolean: true,
62
73
  describe: "Be verbose"
@@ -72,12 +83,23 @@ var commonCliOptions = {
72
83
  };
73
84
 
74
85
  // src/utils/getCredentialsProfileRegion.ts
75
- import { fromEnv, fromIni } from "@aws-sdk/credential-providers";
86
+ import {
87
+ fromEnv,
88
+ fromIni,
89
+ fromTemporaryCredentials
90
+ } from "@aws-sdk/credential-providers";
76
91
  import { loadSharedConfigFiles } from "@aws-sdk/shared-ini-file-loader";
77
92
 
78
93
  // src/utils/logger.ts
79
94
  import chalk from "chalk";
80
- var bold = (str) => chalk.yellowBright.bold(str);
95
+ var _logger;
96
+ var getLogger = () => {
97
+ if (!_logger) {
98
+ _logger = console;
99
+ }
100
+ return _logger;
101
+ };
102
+ var bold = (str) => chalk.greenBright.bold(str);
81
103
  var underline = (str) => chalk.cyanBright.bold(str);
82
104
 
83
105
  // src/utils/getCredentialsProfileRegion.ts
@@ -91,12 +113,25 @@ var getCredentialsProfileRegion = async ({
91
113
  let profileAndOrigin = void 0;
92
114
  let regionAndOrigin = void 0;
93
115
  if (argv.profile) {
94
- profileAndOrigin = { value: argv.profile, origin: `command line option: ${bold(argv.profile)}` };
95
- credentialsAndOrigin = { value: await fromIni({ profile: argv.profile })(), origin: `${bold(`[${argv.profile}]`)} in credentials file` };
116
+ profileAndOrigin = {
117
+ value: argv.profile,
118
+ origin: `command line option: ${bold(argv.profile)}`
119
+ };
120
+ credentialsAndOrigin = {
121
+ value: await fromIni({
122
+ profile: argv.profile
123
+ })(),
124
+ origin: `${bold(`[${argv.profile}]`)} in credentials file`
125
+ };
96
126
  } else if (env.AWS_PROFILE) {
97
- profileAndOrigin = { value: env.AWS_PROFILE, origin: `env variable ${bold("AWS_PROFILE")}: ${underline(env.AWS_PROFILE)}` };
127
+ profileAndOrigin = {
128
+ value: env.AWS_PROFILE,
129
+ origin: `env variable ${bold("AWS_PROFILE")}: ${underline(env.AWS_PROFILE)}`
130
+ };
98
131
  credentialsAndOrigin = {
99
- value: await fromIni({ profile: env.AWS_PROFILE })(),
132
+ value: await fromIni({
133
+ profile: env.AWS_PROFILE
134
+ })(),
100
135
  origin: `env variable ${underline("AWS_PROFILE")}: ${bold(env.AWS_PROFILE)}`
101
136
  };
102
137
  } else if (env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY) {
@@ -105,13 +140,27 @@ var getCredentialsProfileRegion = async ({
105
140
  origin: `env variables ${bold("AWS_ACCESS_KEY_ID")} and ${bold("AWS_SECRET_ACCESS_KEY")}`
106
141
  };
107
142
  } else if ((_a = sharedConfigFiles.credentialsFile) == null ? void 0 : _a.default) {
108
- profileAndOrigin = { value: "default", origin: `${bold("[default]")} in credentials file` };
109
- credentialsAndOrigin = { value: await fromIni({ profile: "default" })(), origin: `profile ${bold("[default]")}` };
143
+ profileAndOrigin = {
144
+ value: "default",
145
+ origin: `${bold("[default]")} in credentials file`
146
+ };
147
+ credentialsAndOrigin = {
148
+ value: await fromIni({
149
+ profile: "default"
150
+ })(),
151
+ origin: `profile ${bold("[default]")}`
152
+ };
110
153
  }
111
154
  if (argv.region) {
112
- regionAndOrigin = { value: argv.region, origin: `command line option: ${bold(argv.region)}` };
155
+ regionAndOrigin = {
156
+ value: argv.region,
157
+ origin: `command line option: ${bold(argv.region)}`
158
+ };
113
159
  } else if (env.AWS_REGION) {
114
- regionAndOrigin = { value: env.AWS_REGION, origin: `env variable ${bold("AWS_REGION")}: ${underline(env.AWS_REGION)}` };
160
+ regionAndOrigin = {
161
+ value: env.AWS_REGION,
162
+ origin: `env variable ${bold("AWS_REGION")}: ${underline(env.AWS_REGION)}`
163
+ };
115
164
  } else if (env.AWS_DEFAULT_REGION) {
116
165
  regionAndOrigin = {
117
166
  value: env.AWS_DEFAULT_REGION,
@@ -120,9 +169,27 @@ var getCredentialsProfileRegion = async ({
120
169
  } else if (profileAndOrigin) {
121
170
  const foundRegion = (_c = (_b = sharedConfigFiles == null ? void 0 : sharedConfigFiles.configFile) == null ? void 0 : _b[profileAndOrigin.value]) == null ? void 0 : _c.region;
122
171
  if (foundRegion) {
123
- regionAndOrigin = { value: foundRegion, origin: `${bold(`[profile ${profileAndOrigin.value}]`)} in config file` };
172
+ regionAndOrigin = {
173
+ value: foundRegion,
174
+ origin: `${bold(`[profile ${profileAndOrigin.value}]`)} in config file`
175
+ };
124
176
  }
125
177
  }
178
+ if (argv.assumeRoleArn) {
179
+ console.log("assume this yo");
180
+ credentialsAndOrigin = {
181
+ value: await fromTemporaryCredentials({
182
+ masterCredentials: credentialsAndOrigin == null ? void 0 : credentialsAndOrigin.value,
183
+ params: {
184
+ RoleArn: argv.assumeRoleArn
185
+ },
186
+ clientConfig: {
187
+ region: regionAndOrigin == null ? void 0 : regionAndOrigin.value
188
+ }
189
+ })(),
190
+ origin: `assume role ${bold(`[${argv.assumeRoleArn}]`)}`
191
+ };
192
+ }
126
193
  return { credentialsAndOrigin, regionAndOrigin, profileAndOrigin };
127
194
  };
128
195
  var printVerboseCredentialsProfileRegion = ({
@@ -148,12 +215,20 @@ var handleCredentialsAndRegion = async ({
148
215
  argv,
149
216
  env
150
217
  }) => {
151
- const { credentialsAndOrigin, regionAndOrigin } = await getCredentialsProfileRegion({
152
- argv: { region: argv.awsRegion, profile: argv.awsProfile },
218
+ const { credentialsAndOrigin, regionAndOrigin, profileAndOrigin } = await getCredentialsProfileRegion({
219
+ argv: {
220
+ region: argv.awsRegion,
221
+ profile: argv.awsProfile,
222
+ assumeRoleArn: argv.awsAssumeRoleArn
223
+ },
153
224
  env: __spreadValues({}, env)
154
225
  });
155
226
  if (argv.verbose === true) {
156
- console.log(printVerboseCredentialsProfileRegion({ credentialsAndOrigin, regionAndOrigin }));
227
+ console.log(printVerboseCredentialsProfileRegion({
228
+ credentialsAndOrigin,
229
+ regionAndOrigin,
230
+ profileAndOrigin
231
+ }));
157
232
  }
158
233
  if (!credentialsAndOrigin || !regionAndOrigin) {
159
234
  if (!credentialsAndOrigin) {
@@ -168,8 +243,67 @@ var handleCredentialsAndRegion = async ({
168
243
  return { credentialsAndOrigin, regionAndOrigin };
169
244
  };
170
245
 
246
+ // src/utils/ssm.ts
247
+ import { SSMClient } from "@aws-sdk/client-ssm";
248
+ var getSSMClient = ({
249
+ configuration
250
+ }) => {
251
+ const ssmClient = new SSMClient(configuration);
252
+ return ssmClient;
253
+ };
254
+
255
+ // src/commands/debugCommand.ts
256
+ var command = "debug";
257
+ var desc = "Debugs all the things";
258
+ var builder = {
259
+ "aws-profile": commonCliOptions.awsProfile,
260
+ "aws-region": commonCliOptions.awsRegion,
261
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
262
+ "aws-assume-role-arn": commonCliOptions.awsAssumeRoleArn,
263
+ verbose: commonCliOptions.verbose,
264
+ yes: __spreadValues({}, commonCliOptions.yes)
265
+ };
266
+ var handler = async (argv) => {
267
+ try {
268
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
269
+ argv: __spreadValues({}, argv),
270
+ env: __spreadValues({}, process.env)
271
+ });
272
+ const ssmClient = getSSMClient({
273
+ configuration: {
274
+ credentials: credentialsAndOrigin.value,
275
+ region: regionAndOrigin.value
276
+ },
277
+ verbose: argv.verbose
278
+ });
279
+ const getParametersByPathCommand = new GetParametersByPathCommand({
280
+ Path: `arn:aws:ssm:eu-west-1:060014838622:parameter/dotsec/*`,
281
+ Recursive: true
282
+ });
283
+ const commandResult = await ssmClient.send(getParametersByPathCommand);
284
+ console.log(commandResult);
285
+ } catch (e) {
286
+ console.error(e);
287
+ }
288
+ };
289
+
290
+ // src/commands/decryptSecCommand.ts
291
+ var decryptSecCommand_exports = {};
292
+ __export(decryptSecCommand_exports, {
293
+ builder: () => builder2,
294
+ command: () => command2,
295
+ desc: () => desc2,
296
+ handler: () => handler2
297
+ });
298
+ import { KMSClient, DecryptCommand } from "@aws-sdk/client-kms";
299
+ import { redBright } from "chalk";
300
+ import { parse } from "dotenv";
301
+ import fs from "node:fs";
302
+ import path from "node:path";
303
+
171
304
  // src/utils/io.ts
172
305
  import { stat } from "fs/promises";
306
+ import prompts from "prompts";
173
307
  var fileExists = async (source) => {
174
308
  try {
175
309
  await stat(source);
@@ -178,30 +312,43 @@ var fileExists = async (source) => {
178
312
  return false;
179
313
  }
180
314
  };
315
+ var promptOverwriteIfFileExists = async ({
316
+ filePath,
317
+ skip
318
+ }) => {
319
+ let overwriteResponse;
320
+ if (await fileExists(filePath) && skip !== true) {
321
+ overwriteResponse = await prompts({
322
+ type: "confirm",
323
+ name: "overwrite",
324
+ message: () => {
325
+ return `Overwrite '${filePath}' ?`;
326
+ }
327
+ });
328
+ } else {
329
+ overwriteResponse = void 0;
330
+ }
331
+ return overwriteResponse;
332
+ };
181
333
 
182
334
  // src/commands/decryptSecCommand.ts
183
- var command = "decrypt-sec";
184
- var desc = "Decrypts a dotsec file";
185
- var builder = {
186
- "aws-profile": __spreadValues({}, commonCliOptions.awsProfile),
187
- "aws-region": __spreadValues({}, commonCliOptions.awsRegion),
188
- "aws-key-alias": { string: true, default: "alias/top-secret" },
189
- "env-file": {
190
- string: true,
191
- describe: ".env file",
192
- default: ".env"
193
- },
194
- "sec-file": {
195
- string: true,
196
- describe: ".sec file",
197
- default: ".sec"
198
- },
199
- verbose: __spreadValues({}, commonCliOptions.verbose),
200
- yes: __spreadValues({}, commonCliOptions.yes)
335
+ var command2 = "decrypt-sec";
336
+ var desc2 = "Decrypts a dotsec file";
337
+ var builder2 = {
338
+ "aws-profile": commonCliOptions.awsProfile,
339
+ "aws-region": commonCliOptions.awsRegion,
340
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
341
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
342
+ "env-file": commonCliOptions.envFile,
343
+ "sec-file": commonCliOptions.secFile,
344
+ verbose: commonCliOptions.verbose
201
345
  };
202
- var handler = async (argv) => {
346
+ var handler2 = async (argv) => {
203
347
  try {
204
- const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({ argv: __spreadValues({}, argv), env: __spreadValues({}, process.env) });
348
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
349
+ argv: __spreadValues({}, argv),
350
+ env: __spreadValues({}, process.env)
351
+ });
205
352
  const secSource = path.resolve(process.cwd(), argv.secFile);
206
353
  if (!await fileExists(secSource)) {
207
354
  console.error(`Could not open ${redBright(secSource)}`);
@@ -220,7 +367,11 @@ var handler = async (argv) => {
220
367
  });
221
368
  const decryptionResult = await kmsClient.send(decryptCommand);
222
369
  if (!(decryptionResult == null ? void 0 : decryptionResult.Plaintext)) {
223
- throw new Error(`No: ${JSON.stringify({ key, cipherText, decryptCommand })}`);
370
+ throw new Error(`No: ${JSON.stringify({
371
+ key,
372
+ cipherText,
373
+ decryptCommand
374
+ })}`);
224
375
  }
225
376
  const value = Buffer.from(decryptionResult.Plaintext).toString();
226
377
  return [key, value];
@@ -231,57 +382,177 @@ var handler = async (argv) => {
231
382
  }
232
383
  };
233
384
 
234
- // src/commands/defaultCommand.ts
235
- var defaultCommand_exports = {};
236
- __export(defaultCommand_exports, {
237
- builder: () => builder2,
238
- command: () => command2,
239
- desc: () => desc2,
240
- handler: () => handler2
385
+ // src/commands/decryptSecretsJson.ts
386
+ var decryptSecretsJson_exports = {};
387
+ __export(decryptSecretsJson_exports, {
388
+ builder: () => builder3,
389
+ command: () => command3,
390
+ desc: () => desc3,
391
+ handler: () => handler3
241
392
  });
242
- import { KMSClient as KMSClient2, DecryptCommand as DecryptCommand2 } from "@aws-sdk/client-kms";
393
+ import { DecryptCommand as DecryptCommand2, DescribeKeyCommand } from "@aws-sdk/client-kms";
243
394
  import { redBright as redBright2 } from "chalk";
244
- import { spawn } from "cross-spawn";
245
- import { parse as parse2 } from "dotenv";
395
+ import flat from "flat";
246
396
  import fs2 from "node:fs";
247
397
  import path2 from "node:path";
248
- var command2 = "$0 <command>";
249
- var desc2 = "Decrypts a .sec file, injects the results into a separate process and runs a command";
250
- var builder2 = {
251
- "aws-profile": __spreadValues({}, commonCliOptions.awsProfile),
252
- "aws-region": __spreadValues({}, commonCliOptions.awsRegion),
253
- "aws-key-alias": { string: true, default: "alias/top-secret" },
254
- "sec-file": {
398
+
399
+ // src/utils/kms.ts
400
+ import { KMSClient as KMSClient2 } from "@aws-sdk/client-kms";
401
+ var getKMSClient = ({
402
+ configuration
403
+ }) => {
404
+ const kmsClient = new KMSClient2(configuration);
405
+ return kmsClient;
406
+ };
407
+
408
+ // src/commands/decryptSecretsJson.ts
409
+ var command3 = "decrypt-secrets-json";
410
+ var desc3 = "Derypts an encrypted file";
411
+ var builder3 = {
412
+ "aws-profile": commonCliOptions.awsProfile,
413
+ "aws-region": commonCliOptions.awsRegion,
414
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
415
+ "secrets-file": {
255
416
  string: true,
256
- describe: ".sec file",
257
- default: ".sec"
417
+ describe: "filename of json file writing secrets",
418
+ default: "secrets.json"
258
419
  },
259
- verbose: __spreadValues({}, commonCliOptions.verbose),
260
- yes: __spreadValues({}, commonCliOptions.yes),
420
+ "encrypted-secrets-file": {
421
+ string: true,
422
+ describe: "filename of json file for reading encrypted secrets",
423
+ default: "secrets.encrypted.json"
424
+ },
425
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
426
+ verbose: commonCliOptions.verbose,
427
+ yes: __spreadValues({}, commonCliOptions.yes)
428
+ };
429
+ var handler3 = async (argv) => {
430
+ const { info, error } = getLogger();
431
+ try {
432
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
433
+ argv: __spreadValues({}, argv),
434
+ env: __spreadValues({}, process.env)
435
+ });
436
+ const encryptedSecretsPath = path2.resolve(process.cwd(), argv.encryptedSecretsFile);
437
+ if (!await fileExists(encryptedSecretsPath)) {
438
+ error(`Could not open ${redBright2(encryptedSecretsPath)}`);
439
+ return;
440
+ }
441
+ const encryptedSecrets = JSON.parse(fs2.readFileSync(encryptedSecretsPath, { encoding: "utf8" }));
442
+ if (!encryptedSecrets.encryptedParameters) {
443
+ throw new Error(`Expected 'encryptedParameters' property, but got none`);
444
+ }
445
+ const flatEncryptedParameters = flat(encryptedSecrets.encryptedParameters, { delimiter: "/" });
446
+ const kmsClient = getKMSClient({
447
+ configuration: {
448
+ credentials: credentialsAndOrigin.value,
449
+ region: regionAndOrigin.value
450
+ },
451
+ verbose: argv.verbose
452
+ });
453
+ if (argv.verbose) {
454
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
455
+ const describeKeyCommand = new DescribeKeyCommand({
456
+ KeyId: argv.awsKeyAlias
457
+ });
458
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
459
+ console.log("describeKeyResult", { describeKeyResult });
460
+ }
461
+ const flatParameters = Object.fromEntries(await Promise.all(Object.entries(flatEncryptedParameters).map(async ([parameterName, encryptedParameter]) => {
462
+ const decryptCommand = new DecryptCommand2({
463
+ KeyId: argv.awsKeyAlias,
464
+ CiphertextBlob: Buffer.from(encryptedParameter, "base64"),
465
+ EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
466
+ });
467
+ const decryptionResult = await kmsClient.send(decryptCommand);
468
+ if (!decryptionResult.Plaintext) {
469
+ throw new Error(`Something bad happened: ${JSON.stringify({
470
+ key: parameterName,
471
+ cipherText: encryptedParameter,
472
+ decryptCommand
473
+ })}`);
474
+ }
475
+ if (argv.verbose) {
476
+ info(`Encrypting key ${bold(parameterName)} ${underline("ok")}`);
477
+ }
478
+ const value = Buffer.from(decryptionResult.Plaintext).toString();
479
+ return [parameterName, value];
480
+ })));
481
+ const parameters = flat.unflatten(flatParameters, { delimiter: "/" });
482
+ const secrets = {
483
+ config: encryptedSecrets.config,
484
+ parameters
485
+ };
486
+ const secretsPath = path2.resolve(process.cwd(), argv.secretsFile);
487
+ const overwriteResponse = await promptOverwriteIfFileExists({
488
+ filePath: secretsPath,
489
+ skip: argv.yes
490
+ });
491
+ if (overwriteResponse === void 0 || overwriteResponse.overwrite === true) {
492
+ fs2.writeFileSync(secretsPath, JSON.stringify(secrets, null, 4));
493
+ }
494
+ } catch (e) {
495
+ error(e);
496
+ }
497
+ };
498
+
499
+ // src/commands/defaultCommand.ts
500
+ var defaultCommand_exports = {};
501
+ __export(defaultCommand_exports, {
502
+ builder: () => builder4,
503
+ command: () => command4,
504
+ desc: () => desc4,
505
+ handler: () => handler4
506
+ });
507
+ import { KMSClient as KMSClient3, DecryptCommand as DecryptCommand3 } from "@aws-sdk/client-kms";
508
+ import { redBright as redBright3 } from "chalk";
509
+ import { spawn } from "cross-spawn";
510
+ import { parse as parse2 } from "dotenv";
511
+ import fs3 from "node:fs";
512
+ import path3 from "node:path";
513
+ var command4 = "$0 <command>";
514
+ var desc4 = "Decrypts a .sec file, injects the results into a separate process and runs a command";
515
+ var builder4 = {
516
+ "aws-profile": commonCliOptions.awsProfile,
517
+ "aws-region": commonCliOptions.awsRegion,
518
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
519
+ "sec-file": commonCliOptions.secFile,
520
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
521
+ verbose: commonCliOptions.verbose,
261
522
  command: { string: true, required: true }
262
523
  };
263
- var handler2 = async (argv) => {
524
+ var handler4 = async (argv) => {
264
525
  try {
265
- const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({ argv: __spreadValues({}, argv), env: __spreadValues({}, process.env) });
266
- const secSource = path2.resolve(process.cwd(), argv.secFile);
526
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
527
+ argv: __spreadValues({}, argv),
528
+ env: __spreadValues({}, process.env)
529
+ });
530
+ if (argv.verbose) {
531
+ console.log({ credentialsAndOrigin, regionAndOrigin });
532
+ }
533
+ const secSource = path3.resolve(process.cwd(), argv.secFile);
267
534
  if (!await fileExists(secSource)) {
268
- console.error(`Could not open ${redBright2(secSource)}`);
535
+ console.error(`Could not open ${redBright3(secSource)}`);
269
536
  return;
270
537
  }
271
- const parsedSec = parse2(fs2.readFileSync(secSource, { encoding: "utf8" }));
272
- const kmsClient = new KMSClient2({
538
+ const parsedSec = parse2(fs3.readFileSync(secSource, { encoding: "utf8" }));
539
+ const kmsClient = new KMSClient3({
273
540
  credentials: credentialsAndOrigin.value,
274
541
  region: regionAndOrigin.value
275
542
  });
276
543
  const envEntries = await Promise.all(Object.entries(parsedSec).map(async ([key, cipherText]) => {
277
- const decryptCommand = new DecryptCommand2({
544
+ const decryptCommand = new DecryptCommand3({
278
545
  KeyId: argv.awsKeyAlias,
279
546
  CiphertextBlob: Buffer.from(cipherText, "base64"),
280
547
  EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
281
548
  });
282
549
  const decryptionResult = await kmsClient.send(decryptCommand);
283
550
  if (!(decryptionResult == null ? void 0 : decryptionResult.Plaintext)) {
284
- throw new Error(`No: ${JSON.stringify({ key, cipherText, decryptCommand })}`);
551
+ throw new Error(`No: ${JSON.stringify({
552
+ key,
553
+ cipherText,
554
+ decryptCommand
555
+ })}`);
285
556
  }
286
557
  const value = Buffer.from(decryptionResult.Plaintext).toString();
287
558
  return [key, value];
@@ -303,48 +574,55 @@ var handler2 = async (argv) => {
303
574
  // src/commands/encryptEnvCommand.ts
304
575
  var encryptEnvCommand_exports = {};
305
576
  __export(encryptEnvCommand_exports, {
306
- builder: () => builder3,
307
- command: () => command3,
308
- desc: () => desc3,
309
- handler: () => handler3
577
+ builder: () => builder5,
578
+ command: () => command5,
579
+ desc: () => desc5,
580
+ handler: () => handler5
310
581
  });
311
- import { KMSClient as KMSClient3, EncryptCommand } from "@aws-sdk/client-kms";
312
- import { redBright as redBright3 } from "chalk";
582
+ import { DescribeKeyCommand as DescribeKeyCommand2, EncryptCommand } from "@aws-sdk/client-kms";
583
+ import { redBright as redBright4 } from "chalk";
313
584
  import { parse as parse3 } from "dotenv";
314
- import fs3 from "node:fs";
315
- import path3 from "node:path";
316
- var command3 = "encrypt-env";
317
- var desc3 = "Encrypts a dotenv file";
318
- var builder3 = {
319
- "aws-profile": __spreadValues({}, commonCliOptions.awsProfile),
320
- "aws-region": __spreadValues({}, commonCliOptions.awsRegion),
321
- "aws-key-alias": { string: true, default: "alias/top-secret" },
322
- "env-file": {
323
- string: true,
324
- describe: ".env file",
325
- default: ".env"
326
- },
327
- "sec-file": {
328
- string: true,
329
- describe: ".sec file",
330
- default: ".sec"
331
- },
332
- verbose: __spreadValues({}, commonCliOptions.verbose),
333
- yes: __spreadValues({}, commonCliOptions.yes)
585
+ import fs4 from "node:fs";
586
+ import path4 from "node:path";
587
+ var command5 = "encrypt-env";
588
+ var desc5 = "Encrypts a dotenv file";
589
+ var builder5 = {
590
+ "aws-profile": commonCliOptions.awsProfile,
591
+ "aws-region": commonCliOptions.awsRegion,
592
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
593
+ "env-file": commonCliOptions.envFile,
594
+ "sec-file": commonCliOptions.secFile,
595
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
596
+ verbose: commonCliOptions.verbose
334
597
  };
335
- var handler3 = async (argv) => {
598
+ var handler5 = async (argv) => {
599
+ const { info, error } = getLogger();
336
600
  try {
337
- const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({ argv: __spreadValues({}, argv), env: __spreadValues({}, process.env) });
338
- const envSource = path3.resolve(process.cwd(), argv.envFile);
601
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
602
+ argv: __spreadValues({}, argv),
603
+ env: __spreadValues({}, process.env)
604
+ });
605
+ const envSource = path4.resolve(process.cwd(), argv.envFile);
339
606
  if (!await fileExists(envSource)) {
340
- console.error(`Could not open ${redBright3(envSource)}`);
607
+ error(`Could not open ${redBright4(envSource)}`);
341
608
  return;
342
609
  }
343
- const parsedEnv = parse3(fs3.readFileSync(envSource, { encoding: "utf8" }));
344
- const kmsClient = new KMSClient3({
345
- credentials: credentialsAndOrigin.value,
346
- region: regionAndOrigin.value
610
+ const parsedEnv = parse3(fs4.readFileSync(envSource, { encoding: "utf8" }));
611
+ const kmsClient = getKMSClient({
612
+ configuration: {
613
+ credentials: credentialsAndOrigin.value,
614
+ region: regionAndOrigin.value
615
+ },
616
+ verbose: argv.verbose
347
617
  });
618
+ if (argv.verbose) {
619
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
620
+ const describeKeyCommand = new DescribeKeyCommand2({
621
+ KeyId: argv.awsKeyAlias
622
+ });
623
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
624
+ console.log("describeKeyResult", { describeKeyResult });
625
+ }
348
626
  const sec = (await Promise.all(Object.entries(parsedEnv).map(async ([key, value]) => {
349
627
  const encryptCommand = new EncryptCommand({
350
628
  KeyId: argv.awsKeyAlias,
@@ -353,17 +631,232 @@ var handler3 = async (argv) => {
353
631
  });
354
632
  const encryptionResult = await kmsClient.send(encryptCommand);
355
633
  if (!encryptionResult.CiphertextBlob) {
356
- throw new Error(`No: ${JSON.stringify({ key, value, encryptCommand })}`);
634
+ throw new Error(`Something bad happened: ${JSON.stringify({
635
+ key,
636
+ value,
637
+ encryptCommand
638
+ })}`);
639
+ }
640
+ if (argv.verbose) {
641
+ info(`Encrypting key ${bold(key)} ${underline("ok")}`);
357
642
  }
358
643
  const cipherText = Buffer.from(encryptionResult.CiphertextBlob).toString("base64");
359
644
  return `${key}="${cipherText}"`;
360
645
  }))).join("\n");
361
- fs3.writeFileSync(path3.resolve(process.cwd(), argv.secFile), sec);
646
+ fs4.writeFileSync(path4.resolve(process.cwd(), argv.secFile), sec);
362
647
  } catch (e) {
363
- console.error(e);
648
+ error(e);
649
+ }
650
+ };
651
+
652
+ // src/commands/encryptSecretsJson.ts
653
+ var encryptSecretsJson_exports = {};
654
+ __export(encryptSecretsJson_exports, {
655
+ builder: () => builder6,
656
+ command: () => command6,
657
+ desc: () => desc6,
658
+ handler: () => handler6
659
+ });
660
+ import { DescribeKeyCommand as DescribeKeyCommand3, EncryptCommand as EncryptCommand2 } from "@aws-sdk/client-kms";
661
+ import { redBright as redBright5 } from "chalk";
662
+ import flat2 from "flat";
663
+ import fs5 from "node:fs";
664
+ import path5 from "node:path";
665
+ var command6 = "encrypt-secrets-json";
666
+ var desc6 = "Encrypts an unencrypted file";
667
+ var builder6 = {
668
+ "aws-profile": commonCliOptions.awsProfile,
669
+ "aws-region": commonCliOptions.awsRegion,
670
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
671
+ "secrets-file": {
672
+ string: true,
673
+ describe: "filename of json file reading secrets",
674
+ default: "secrets.json"
675
+ },
676
+ "encrypted-secrets-file": {
677
+ string: true,
678
+ describe: "filename of json file for writing encrypted secrets",
679
+ default: "secrets.encrypted.json"
680
+ },
681
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
682
+ verbose: commonCliOptions.verbose,
683
+ yes: __spreadValues({}, commonCliOptions.yes)
684
+ };
685
+ var handler6 = async (argv) => {
686
+ const { info, error } = getLogger();
687
+ try {
688
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
689
+ argv: __spreadValues({}, argv),
690
+ env: __spreadValues({}, process.env)
691
+ });
692
+ const secretsPath = path5.resolve(process.cwd(), argv.secretsFile);
693
+ if (!await fileExists(secretsPath)) {
694
+ error(`Could not open ${redBright5(secretsPath)}`);
695
+ return;
696
+ }
697
+ const secrets = JSON.parse(fs5.readFileSync(secretsPath, { encoding: "utf8" }));
698
+ if (!secrets.parameters) {
699
+ throw new Error(`Expected 'parameters' property, but got none`);
700
+ }
701
+ const flatParameters = flat2(secrets.parameters, { delimiter: "/" });
702
+ if (argv.verbose) {
703
+ console.log(flatParameters);
704
+ }
705
+ const kmsClient = getKMSClient({
706
+ configuration: {
707
+ credentials: credentialsAndOrigin.value,
708
+ region: regionAndOrigin.value
709
+ },
710
+ verbose: argv.verbose
711
+ });
712
+ if (argv.verbose) {
713
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
714
+ const describeKeyCommand = new DescribeKeyCommand3({
715
+ KeyId: argv.awsKeyAlias
716
+ });
717
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
718
+ console.log("describeKeyResult", { describeKeyResult });
719
+ }
720
+ const encryptedFlatParameters = Object.fromEntries(await Promise.all(Object.entries(flatParameters).map(async ([parameterName, parameter]) => {
721
+ const encryptCommand = new EncryptCommand2({
722
+ KeyId: argv.awsKeyAlias,
723
+ Plaintext: Buffer.from(parameter),
724
+ EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
725
+ });
726
+ const encryptionResult = await kmsClient.send(encryptCommand);
727
+ if (!encryptionResult.CiphertextBlob) {
728
+ throw new Error(`Something bad happened: ${JSON.stringify({
729
+ key: parameterName,
730
+ value: parameter,
731
+ encryptCommand
732
+ })}`);
733
+ }
734
+ if (argv.verbose) {
735
+ info(`Encrypting key ${bold(parameterName)} ${underline("ok")}`);
736
+ }
737
+ const cipherText = Buffer.from(encryptionResult.CiphertextBlob).toString("base64");
738
+ return [parameterName, cipherText];
739
+ })));
740
+ const encryptedParameters = flat2.unflatten(encryptedFlatParameters, { delimiter: "/" });
741
+ const encryptedSecrets = {
742
+ config: secrets.config,
743
+ encryptedParameters
744
+ };
745
+ const encryptedSecretsPath = path5.resolve(process.cwd(), argv.encryptedSecretsFile);
746
+ const overwriteResponse = await promptOverwriteIfFileExists({
747
+ filePath: encryptedSecretsPath,
748
+ skip: argv.yes
749
+ });
750
+ if (overwriteResponse === void 0 || overwriteResponse.overwrite === true) {
751
+ fs5.writeFileSync(encryptedSecretsPath, JSON.stringify(encryptedSecrets, null, 4));
752
+ }
753
+ } catch (e) {
754
+ error(e);
755
+ }
756
+ };
757
+
758
+ // src/commands/offloadToSSMCommand.ts
759
+ var offloadToSSMCommand_exports = {};
760
+ __export(offloadToSSMCommand_exports, {
761
+ builder: () => builder7,
762
+ command: () => command7,
763
+ desc: () => desc7,
764
+ handler: () => handler7
765
+ });
766
+ import { DecryptCommand as DecryptCommand4, DescribeKeyCommand as DescribeKeyCommand4 } from "@aws-sdk/client-kms";
767
+ import { PutParameterCommand } from "@aws-sdk/client-ssm";
768
+ import { redBright as redBright6 } from "chalk";
769
+ import flat3 from "flat";
770
+ import fs6 from "node:fs";
771
+ import path6 from "node:path";
772
+ var command7 = "offload-secrets-json-to-ssm";
773
+ var desc7 = "Sends decrypted values of secrets.encrypted.json file to SSM parameter store";
774
+ var builder7 = {
775
+ "aws-profile": commonCliOptions.awsProfile,
776
+ "aws-region": commonCliOptions.awsRegion,
777
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
778
+ "encrypted-secrets-file": {
779
+ string: true,
780
+ describe: "filename of json file for reading encrypted secrets",
781
+ default: "secrets.encrypted.json"
782
+ },
783
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
784
+ verbose: commonCliOptions.verbose,
785
+ yes: __spreadValues({}, commonCliOptions.yes)
786
+ };
787
+ var handler7 = async (argv) => {
788
+ const { info, error } = getLogger();
789
+ try {
790
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
791
+ argv: __spreadValues({}, argv),
792
+ env: __spreadValues({}, process.env)
793
+ });
794
+ const encryptedSecretsPath = path6.resolve(process.cwd(), argv.encryptedSecretsFile);
795
+ if (!await fileExists(encryptedSecretsPath)) {
796
+ error(`Could not open ${redBright6(encryptedSecretsPath)}`);
797
+ return;
798
+ }
799
+ const encryptedSecrets = JSON.parse(fs6.readFileSync(encryptedSecretsPath, { encoding: "utf8" }));
800
+ if (!encryptedSecrets.encryptedParameters) {
801
+ throw new Error(`Expected 'encryptedParameters' property, but got none`);
802
+ }
803
+ const flatEncryptedParameters = flat3(encryptedSecrets.encryptedParameters, { delimiter: "/" });
804
+ const kmsClient = getKMSClient({
805
+ configuration: {
806
+ credentials: credentialsAndOrigin.value,
807
+ region: regionAndOrigin.value
808
+ },
809
+ verbose: argv.verbose
810
+ });
811
+ if (argv.verbose) {
812
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
813
+ const describeKeyCommand = new DescribeKeyCommand4({
814
+ KeyId: argv.awsKeyAlias
815
+ });
816
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
817
+ console.log("describeKeyResult", { describeKeyResult });
818
+ }
819
+ const flatParameters = Object.fromEntries(await Promise.all(Object.entries(flatEncryptedParameters).map(async ([parameterName, encryptedParameter]) => {
820
+ const decryptCommand = new DecryptCommand4({
821
+ KeyId: argv.awsKeyAlias,
822
+ CiphertextBlob: Buffer.from(encryptedParameter, "base64"),
823
+ EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
824
+ });
825
+ const decryptionResult = await kmsClient.send(decryptCommand);
826
+ if (!decryptionResult.Plaintext) {
827
+ throw new Error(`Something bad happened: ${JSON.stringify({
828
+ key: parameterName,
829
+ cipherText: encryptedParameter,
830
+ decryptCommand
831
+ })}`);
832
+ }
833
+ if (argv.verbose) {
834
+ info(`Encrypting key ${bold(parameterName)} ${underline("ok")}`);
835
+ }
836
+ const value = Buffer.from(decryptionResult.Plaintext).toString();
837
+ return [parameterName, value];
838
+ })));
839
+ const ssmClient = getSSMClient({
840
+ configuration: {
841
+ credentials: credentialsAndOrigin.value,
842
+ region: regionAndOrigin.value
843
+ },
844
+ verbose: argv.verbose
845
+ });
846
+ await Promise.all(Object.entries(flatParameters).map(([parameterName, value]) => {
847
+ const putParameterCommand = new PutParameterCommand({
848
+ Name: `/${parameterName}`,
849
+ Value: value,
850
+ Type: "String",
851
+ Overwrite: true
852
+ });
853
+ return ssmClient.send(putParameterCommand);
854
+ }));
855
+ } catch (e) {
856
+ error(e);
364
857
  }
365
858
  };
366
859
 
367
860
  // src/cli.ts
368
- void yargs(hideBin(process.argv)).command(defaultCommand_exports).command(encryptEnvCommand_exports).command(decryptSecCommand_exports).parse();
861
+ void yargs(hideBin(process.argv)).command(defaultCommand_exports).command(offloadToSSMCommand_exports).command(debugCommand_exports).command(encryptEnvCommand_exports).command(decryptSecCommand_exports).command(encryptSecretsJson_exports).command(decryptSecretsJson_exports).parse();
369
862
  //# sourceMappingURL=cli.js.map