@dotenc/cli 0.6.1 → 0.7.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/README.md +50 -4
- package/dist/cli.js +516 -277
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ var package_default;
|
|
|
7
7
|
var init_package = __esm(() => {
|
|
8
8
|
package_default = {
|
|
9
9
|
name: "@dotenc/cli",
|
|
10
|
-
version: "0.
|
|
10
|
+
version: "0.7.0",
|
|
11
11
|
description: "🔐 Git-native encrypted environments powered by your SSH keys",
|
|
12
12
|
author: "Ivan Filho <i@ivanfilho.com>",
|
|
13
13
|
license: "MIT",
|
|
@@ -901,11 +901,32 @@ var init_encryptEnvironment = __esm(() => {
|
|
|
901
901
|
init_getPublicKeys();
|
|
902
902
|
});
|
|
903
903
|
|
|
904
|
+
// src/helpers/validateKeyName.ts
|
|
905
|
+
var validateKeyName = (name) => {
|
|
906
|
+
if (!name) {
|
|
907
|
+
return { valid: false, reason: "Key name must not be empty." };
|
|
908
|
+
}
|
|
909
|
+
if (name === "." || name === "..") {
|
|
910
|
+
return { valid: false, reason: `Invalid key name "${name}".` };
|
|
911
|
+
}
|
|
912
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(name)) {
|
|
913
|
+
return {
|
|
914
|
+
valid: false,
|
|
915
|
+
reason: `Invalid key name "${name}". Only letters, numbers, dots, hyphens, and underscores are allowed.`
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
return { valid: true };
|
|
919
|
+
};
|
|
920
|
+
|
|
904
921
|
// src/helpers/getPublicKeyByName.ts
|
|
905
922
|
import crypto8 from "node:crypto";
|
|
906
923
|
import fs5 from "node:fs/promises";
|
|
907
924
|
import path5 from "node:path";
|
|
908
925
|
var getPublicKeyByName = async (name) => {
|
|
926
|
+
const keyNameValidation = validateKeyName(name);
|
|
927
|
+
if (!keyNameValidation.valid) {
|
|
928
|
+
throw new Error(keyNameValidation.reason);
|
|
929
|
+
}
|
|
909
930
|
const filePath = path5.join(process.cwd(), ".dotenc", `${name}.pub`);
|
|
910
931
|
let publicKeyInput;
|
|
911
932
|
try {
|
|
@@ -949,12 +970,16 @@ var init_getEnvironments = () => {};
|
|
|
949
970
|
|
|
950
971
|
// src/prompts/chooseEnvironment.ts
|
|
951
972
|
import inquirer from "inquirer";
|
|
952
|
-
var
|
|
953
|
-
const
|
|
973
|
+
var defaultDeps, _runChooseEnvironmentPrompt = async (message, depsOverrides = {}) => {
|
|
974
|
+
const deps = {
|
|
975
|
+
...defaultDeps,
|
|
976
|
+
...depsOverrides
|
|
977
|
+
};
|
|
978
|
+
const environments = await deps.getEnvironments();
|
|
954
979
|
if (!environments.length) {
|
|
955
|
-
|
|
980
|
+
deps.logInfo('No environment files found. To create a new environment, run "dotenc env create"');
|
|
956
981
|
}
|
|
957
|
-
const result = await
|
|
982
|
+
const result = await deps.prompt([
|
|
958
983
|
{
|
|
959
984
|
type: "list",
|
|
960
985
|
name: "environment",
|
|
@@ -963,25 +988,42 @@ var chooseEnvironmentPrompt = async (message) => {
|
|
|
963
988
|
}
|
|
964
989
|
]);
|
|
965
990
|
return result.environment;
|
|
991
|
+
}, chooseEnvironmentPrompt = async (message) => {
|
|
992
|
+
return _runChooseEnvironmentPrompt(message);
|
|
966
993
|
};
|
|
967
994
|
var init_chooseEnvironment = __esm(() => {
|
|
968
995
|
init_getEnvironments();
|
|
996
|
+
defaultDeps = {
|
|
997
|
+
getEnvironments,
|
|
998
|
+
prompt: inquirer.prompt,
|
|
999
|
+
logInfo: (message) => console.log(message)
|
|
1000
|
+
};
|
|
969
1001
|
});
|
|
970
1002
|
|
|
971
1003
|
// src/prompts/choosePublicKey.ts
|
|
972
1004
|
import inquirer2 from "inquirer";
|
|
973
1005
|
async function _runChoosePublicKeyPrompt(message, multiple, depsOverrides = {}) {
|
|
974
1006
|
const deps = {
|
|
975
|
-
...
|
|
1007
|
+
...defaultDeps2,
|
|
976
1008
|
...depsOverrides
|
|
977
1009
|
};
|
|
978
1010
|
const publicKeys = await deps.getPublicKeys();
|
|
979
|
-
const
|
|
1011
|
+
const prompt = deps.prompt;
|
|
1012
|
+
const result = await prompt([
|
|
980
1013
|
{
|
|
981
1014
|
type: multiple ? "checkbox" : "list",
|
|
982
1015
|
name: "key",
|
|
983
1016
|
message,
|
|
984
|
-
choices: publicKeys.map((key) => key.name.replace(".pub", ""))
|
|
1017
|
+
choices: publicKeys.map((key) => key.name.replace(".pub", "")),
|
|
1018
|
+
validate: (input) => {
|
|
1019
|
+
if (!multiple) {
|
|
1020
|
+
return true;
|
|
1021
|
+
}
|
|
1022
|
+
if (Array.isArray(input) && input.length > 0) {
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
return "Select at least one public key.";
|
|
1026
|
+
}
|
|
985
1027
|
}
|
|
986
1028
|
]);
|
|
987
1029
|
if (multiple) {
|
|
@@ -998,10 +1040,10 @@ async function choosePublicKeyPrompt(message, multiple) {
|
|
|
998
1040
|
}
|
|
999
1041
|
return _runChoosePublicKeyPrompt(message, false);
|
|
1000
1042
|
}
|
|
1001
|
-
var
|
|
1043
|
+
var defaultDeps2;
|
|
1002
1044
|
var init_choosePublicKey = __esm(() => {
|
|
1003
1045
|
init_getPublicKeys();
|
|
1004
|
-
|
|
1046
|
+
defaultDeps2 = {
|
|
1005
1047
|
prompt: inquirer2.prompt,
|
|
1006
1048
|
getPublicKeys
|
|
1007
1049
|
};
|
|
@@ -1148,22 +1190,42 @@ var init_homeConfig = __esm(() => {
|
|
|
1148
1190
|
});
|
|
1149
1191
|
|
|
1150
1192
|
// src/commands/config.ts
|
|
1151
|
-
|
|
1152
|
-
|
|
1193
|
+
import chalk7 from "chalk";
|
|
1194
|
+
var SUPPORTED_CONFIG_KEYS, defaultDeps3, getSupportedConfigKey = (key) => {
|
|
1195
|
+
if (SUPPORTED_CONFIG_KEYS.includes(key)) {
|
|
1196
|
+
return { valid: true, key };
|
|
1197
|
+
}
|
|
1198
|
+
return { valid: false };
|
|
1199
|
+
}, configCommand = async (key, value, options, deps = defaultDeps3) => {
|
|
1200
|
+
const keyValidation = getSupportedConfigKey(key);
|
|
1201
|
+
if (!keyValidation.valid) {
|
|
1202
|
+
deps.logError(`${chalk7.red("Error:")} unsupported config key "${key}". Supported keys: ${SUPPORTED_CONFIG_KEYS.join(", ")}.`);
|
|
1203
|
+
deps.exit(1);
|
|
1204
|
+
}
|
|
1205
|
+
const config = await deps.getHomeConfig();
|
|
1206
|
+
const configKey = keyValidation.key;
|
|
1153
1207
|
if (options.remove) {
|
|
1154
|
-
delete config[
|
|
1155
|
-
await setHomeConfig(config);
|
|
1208
|
+
delete config[configKey];
|
|
1209
|
+
await deps.setHomeConfig(config);
|
|
1156
1210
|
return;
|
|
1157
1211
|
}
|
|
1158
|
-
if (value) {
|
|
1159
|
-
config[
|
|
1160
|
-
await setHomeConfig(config);
|
|
1212
|
+
if (value !== undefined) {
|
|
1213
|
+
config[configKey] = value;
|
|
1214
|
+
await deps.setHomeConfig(config);
|
|
1161
1215
|
return;
|
|
1162
1216
|
}
|
|
1163
|
-
|
|
1217
|
+
deps.log(config[configKey] ?? "");
|
|
1164
1218
|
};
|
|
1165
1219
|
var init_config = __esm(() => {
|
|
1166
1220
|
init_homeConfig();
|
|
1221
|
+
SUPPORTED_CONFIG_KEYS = ["editor"];
|
|
1222
|
+
defaultDeps3 = {
|
|
1223
|
+
getHomeConfig,
|
|
1224
|
+
setHomeConfig,
|
|
1225
|
+
log: (message) => console.log(message),
|
|
1226
|
+
logError: (message) => console.error(message),
|
|
1227
|
+
exit: (code) => process.exit(code)
|
|
1228
|
+
};
|
|
1167
1229
|
});
|
|
1168
1230
|
|
|
1169
1231
|
// src/helpers/getCurrentKeyName.ts
|
|
@@ -1206,19 +1268,19 @@ var init_parseEnv = __esm(() => {
|
|
|
1206
1268
|
|
|
1207
1269
|
// src/commands/run.ts
|
|
1208
1270
|
import { spawn } from "node:child_process";
|
|
1209
|
-
import
|
|
1271
|
+
import chalk8 from "chalk";
|
|
1210
1272
|
var defaultRunCommandDeps, runCommand = async (command, args, options, _command, deps = defaultRunCommandDeps) => {
|
|
1211
1273
|
const environmentName = options.env || process.env.DOTENC_ENV;
|
|
1212
1274
|
if (!environmentName) {
|
|
1213
1275
|
deps.logError(`No environment provided. Use -e or set DOTENC_ENV to the environment you want to run the command in.
|
|
1214
|
-
To
|
|
1276
|
+
To initialize dotenc, run "dotenc init --name <your-name>". To add environments later, use "dotenc env create <environment>".`);
|
|
1215
1277
|
deps.exit(1);
|
|
1216
1278
|
}
|
|
1217
1279
|
const environments = environmentName.split(",");
|
|
1218
1280
|
for (const env of environments) {
|
|
1219
1281
|
const validation = deps.validateEnvironmentName(env);
|
|
1220
1282
|
if (!validation.valid) {
|
|
1221
|
-
deps.logError(`${
|
|
1283
|
+
deps.logError(`${chalk8.red("Error:")} ${validation.reason}`);
|
|
1222
1284
|
deps.exit(1);
|
|
1223
1285
|
}
|
|
1224
1286
|
}
|
|
@@ -1236,11 +1298,15 @@ To start a new environment, use "dotenc init [environment]".`);
|
|
|
1236
1298
|
return decryptedEnv2;
|
|
1237
1299
|
}));
|
|
1238
1300
|
if (failureCount === environments.length) {
|
|
1239
|
-
deps.logError(`${
|
|
1301
|
+
deps.logError(`${chalk8.red("Error:")} All environments failed to load.`);
|
|
1240
1302
|
deps.exit(1);
|
|
1241
1303
|
}
|
|
1242
1304
|
if (failureCount > 0) {
|
|
1243
|
-
|
|
1305
|
+
if (options.strict) {
|
|
1306
|
+
deps.logError(`${chalk8.red("Error:")} ${failureCount} of ${environments.length} environment(s) failed to load and strict mode is enabled.`);
|
|
1307
|
+
deps.exit(1);
|
|
1308
|
+
}
|
|
1309
|
+
deps.logError(`${chalk8.yellow("Warning:")} ${failureCount} of ${environments.length} environment(s) failed to load.`);
|
|
1244
1310
|
}
|
|
1245
1311
|
const decryptedEnv = decryptedEnvs.reduce((acc, env) => {
|
|
1246
1312
|
return { ...acc, ...env };
|
|
@@ -1268,7 +1334,7 @@ var init_run = __esm(() => {
|
|
|
1268
1334
|
});
|
|
1269
1335
|
|
|
1270
1336
|
// src/commands/dev.ts
|
|
1271
|
-
import
|
|
1337
|
+
import chalk9 from "chalk";
|
|
1272
1338
|
import inquirer3 from "inquirer";
|
|
1273
1339
|
var defaultSelect = async (message, choices) => {
|
|
1274
1340
|
const { selected } = await inquirer3.prompt([
|
|
@@ -1283,7 +1349,7 @@ var defaultSelect = async (message, choices) => {
|
|
|
1283
1349
|
}, defaultDevCommandDeps, devCommand = async (command, args, deps = defaultDevCommandDeps) => {
|
|
1284
1350
|
const keyNames = await deps.getCurrentKeyName();
|
|
1285
1351
|
if (keyNames.length === 0) {
|
|
1286
|
-
deps.logError(`${
|
|
1352
|
+
deps.logError(`${chalk9.red("Error:")} could not resolve your identity. Run ${chalk9.gray("dotenc init")} first.`);
|
|
1287
1353
|
deps.exit(1);
|
|
1288
1354
|
}
|
|
1289
1355
|
let keyName;
|
|
@@ -1342,12 +1408,12 @@ var init_createEnvironment = () => {};
|
|
|
1342
1408
|
// src/commands/env/create.ts
|
|
1343
1409
|
import fs8 from "node:fs/promises";
|
|
1344
1410
|
import path8 from "node:path";
|
|
1345
|
-
import
|
|
1411
|
+
import chalk10 from "chalk";
|
|
1346
1412
|
var _getRunUsageHintForEnvironment = (environmentName) => {
|
|
1347
1413
|
if (environmentName === "development") {
|
|
1348
|
-
return
|
|
1414
|
+
return chalk10.gray("dotenc dev <command> [args...]");
|
|
1349
1415
|
}
|
|
1350
|
-
return `${
|
|
1416
|
+
return `${chalk10.gray(`dotenc run -e ${environmentName} <command> [args...]`)} or ${chalk10.gray(`DOTENC_ENV=${environmentName} dotenc run <command> [args...]`)}`;
|
|
1351
1417
|
}, _normalizePublicKeyNamesForCreate = (selection) => {
|
|
1352
1418
|
if (Array.isArray(selection)) {
|
|
1353
1419
|
return selection;
|
|
@@ -1362,25 +1428,29 @@ var _getRunUsageHintForEnvironment = (environmentName) => {
|
|
|
1362
1428
|
environmentName = await createEnvironmentPrompt("What should the environment be named?", getEnvironmentNameSuggestion());
|
|
1363
1429
|
}
|
|
1364
1430
|
if (!environmentName) {
|
|
1365
|
-
console.error(`${
|
|
1431
|
+
console.error(`${chalk10.red("Error:")} no environment name provided`);
|
|
1366
1432
|
process.exit(1);
|
|
1367
1433
|
}
|
|
1368
1434
|
const validation = validateEnvironmentName(environmentName);
|
|
1369
1435
|
if (!validation.valid) {
|
|
1370
|
-
console.error(`${
|
|
1436
|
+
console.error(`${chalk10.red("Error:")} ${validation.reason}`);
|
|
1371
1437
|
process.exit(1);
|
|
1372
1438
|
}
|
|
1373
1439
|
if (environmentExists(environmentName)) {
|
|
1374
|
-
console.error(`${
|
|
1440
|
+
console.error(`${chalk10.red("Error:")} environment ${environmentName} already exists. To edit it, use ${chalk10.gray(`dotenc env edit ${environmentName}`)}`);
|
|
1375
1441
|
process.exit(1);
|
|
1376
1442
|
}
|
|
1377
1443
|
const availablePublicKeys = await getPublicKeys();
|
|
1378
1444
|
if (!availablePublicKeys.length) {
|
|
1379
|
-
console.error(`${
|
|
1445
|
+
console.error(`${chalk10.red("Error:")} no public keys found. Please add a public key using ${chalk10.gray("dotenc key add")}.`);
|
|
1380
1446
|
process.exit(1);
|
|
1381
1447
|
}
|
|
1382
1448
|
const publicKeySelection = publicKeyNameArg ? publicKeyNameArg : await choosePublicKeyPrompt("Which public key(s) do you want to grant access for this environment?", true);
|
|
1383
1449
|
const publicKeys = _normalizePublicKeyNamesForCreate(publicKeySelection);
|
|
1450
|
+
if (publicKeys.length === 0) {
|
|
1451
|
+
console.error(`${chalk10.red("Error:")} select at least one public key before creating an environment.`);
|
|
1452
|
+
process.exit(1);
|
|
1453
|
+
}
|
|
1384
1454
|
const dataKey = createDataKey();
|
|
1385
1455
|
const content = initialContent ?? `# ${environmentName} environment
|
|
1386
1456
|
`;
|
|
@@ -1392,7 +1462,7 @@ var _getRunUsageHintForEnvironment = (environmentName) => {
|
|
|
1392
1462
|
for (const publicKeyName of publicKeys) {
|
|
1393
1463
|
const publicKey = availablePublicKeys.find((key) => key.name === publicKeyName);
|
|
1394
1464
|
if (!publicKey) {
|
|
1395
|
-
console.error(`Public key ${
|
|
1465
|
+
console.error(`Public key ${chalk10.cyan(publicKeyName)} not found or invalid.`);
|
|
1396
1466
|
continue;
|
|
1397
1467
|
}
|
|
1398
1468
|
const encrypted = encryptDataKey(publicKey, dataKey);
|
|
@@ -1403,11 +1473,15 @@ var _getRunUsageHintForEnvironment = (environmentName) => {
|
|
|
1403
1473
|
algorithm: publicKey.algorithm
|
|
1404
1474
|
});
|
|
1405
1475
|
}
|
|
1476
|
+
if (environmentJson.keys.length === 0) {
|
|
1477
|
+
console.error(`${chalk10.red("Error:")} no valid public keys were selected. Environment creation aborted.`);
|
|
1478
|
+
process.exit(1);
|
|
1479
|
+
}
|
|
1406
1480
|
await fs8.writeFile(path8.join(process.cwd(), `.env.${environmentName}.enc`), JSON.stringify(environmentJson, null, 2), "utf-8");
|
|
1407
|
-
console.log(`${
|
|
1481
|
+
console.log(`${chalk10.green("✔")} Environment ${chalk10.cyan(environmentName)} created!`);
|
|
1408
1482
|
console.log(`
|
|
1409
1483
|
Some useful tips:`);
|
|
1410
|
-
const editCommand =
|
|
1484
|
+
const editCommand = chalk10.gray(`dotenc env edit ${environmentName}`);
|
|
1411
1485
|
console.log(`
|
|
1412
1486
|
- To securely edit your environment: ${editCommand}`);
|
|
1413
1487
|
console.log(`- To run your application: ${_getRunUsageHintForEnvironment(environmentName)}`);
|
|
@@ -1542,18 +1616,87 @@ var init_getDefaultEditor = __esm(() => {
|
|
|
1542
1616
|
};
|
|
1543
1617
|
});
|
|
1544
1618
|
|
|
1619
|
+
// src/helpers/splitCommand.ts
|
|
1620
|
+
var splitCommand = (input) => {
|
|
1621
|
+
const trimmed = input.trim();
|
|
1622
|
+
if (!trimmed) {
|
|
1623
|
+
return [];
|
|
1624
|
+
}
|
|
1625
|
+
const tokens = [];
|
|
1626
|
+
let current = "";
|
|
1627
|
+
let quote = null;
|
|
1628
|
+
let escaped = false;
|
|
1629
|
+
for (const char of trimmed) {
|
|
1630
|
+
if (escaped) {
|
|
1631
|
+
current += char;
|
|
1632
|
+
escaped = false;
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
if (char === "\\") {
|
|
1636
|
+
if (quote === null) {
|
|
1637
|
+
escaped = true;
|
|
1638
|
+
} else {
|
|
1639
|
+
current += char;
|
|
1640
|
+
}
|
|
1641
|
+
continue;
|
|
1642
|
+
}
|
|
1643
|
+
if (quote === "single") {
|
|
1644
|
+
if (char === "'") {
|
|
1645
|
+
quote = null;
|
|
1646
|
+
} else {
|
|
1647
|
+
current += char;
|
|
1648
|
+
}
|
|
1649
|
+
continue;
|
|
1650
|
+
}
|
|
1651
|
+
if (quote === "double") {
|
|
1652
|
+
if (char === '"') {
|
|
1653
|
+
quote = null;
|
|
1654
|
+
} else {
|
|
1655
|
+
current += char;
|
|
1656
|
+
}
|
|
1657
|
+
continue;
|
|
1658
|
+
}
|
|
1659
|
+
if (char === "'") {
|
|
1660
|
+
quote = "single";
|
|
1661
|
+
continue;
|
|
1662
|
+
}
|
|
1663
|
+
if (char === '"') {
|
|
1664
|
+
quote = "double";
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1667
|
+
if (/\s/.test(char)) {
|
|
1668
|
+
if (current.length > 0) {
|
|
1669
|
+
tokens.push(current);
|
|
1670
|
+
current = "";
|
|
1671
|
+
}
|
|
1672
|
+
continue;
|
|
1673
|
+
}
|
|
1674
|
+
current += char;
|
|
1675
|
+
}
|
|
1676
|
+
if (escaped) {
|
|
1677
|
+
current += "\\";
|
|
1678
|
+
}
|
|
1679
|
+
if (quote) {
|
|
1680
|
+
throw new Error("Unterminated quote in command.");
|
|
1681
|
+
}
|
|
1682
|
+
if (current.length > 0) {
|
|
1683
|
+
tokens.push(current);
|
|
1684
|
+
}
|
|
1685
|
+
return tokens;
|
|
1686
|
+
};
|
|
1687
|
+
|
|
1545
1688
|
// src/commands/env/edit.ts
|
|
1546
1689
|
import { spawnSync } from "node:child_process";
|
|
1547
1690
|
import { existsSync as existsSync5 } from "node:fs";
|
|
1548
1691
|
import fs9 from "node:fs/promises";
|
|
1549
1692
|
import os3 from "node:os";
|
|
1550
1693
|
import path9 from "node:path";
|
|
1551
|
-
import
|
|
1694
|
+
import chalk11 from "chalk";
|
|
1552
1695
|
var editCommand = async (environmentNameArg) => {
|
|
1553
1696
|
const environmentName = environmentNameArg || await chooseEnvironmentPrompt("What environment do you want to edit?");
|
|
1554
1697
|
const nameValidation = validateEnvironmentName(environmentName);
|
|
1555
1698
|
if (!nameValidation.valid) {
|
|
1556
|
-
console.error(`${
|
|
1699
|
+
console.error(`${chalk11.red("Error:")} ${nameValidation.reason}`);
|
|
1557
1700
|
process.exit(1);
|
|
1558
1701
|
}
|
|
1559
1702
|
const environmentFile = `.env.${environmentName}.enc`;
|
|
@@ -1594,9 +1737,15 @@ ${separator}${content}`;
|
|
|
1594
1737
|
};
|
|
1595
1738
|
process.on("SIGINT", onSignal);
|
|
1596
1739
|
process.on("SIGTERM", onSignal);
|
|
1597
|
-
const
|
|
1740
|
+
const editorCommand = await getDefaultEditor();
|
|
1598
1741
|
try {
|
|
1599
|
-
const
|
|
1742
|
+
const [editorExecutable, ...editorArgs] = splitCommand(editorCommand);
|
|
1743
|
+
if (!editorExecutable) {
|
|
1744
|
+
throw new Error("No editor command configured.");
|
|
1745
|
+
}
|
|
1746
|
+
const result = spawnSync(editorExecutable, [...editorArgs, tempFilePath], {
|
|
1747
|
+
stdio: "inherit"
|
|
1748
|
+
});
|
|
1600
1749
|
if (result.error) {
|
|
1601
1750
|
throw result.error;
|
|
1602
1751
|
}
|
|
@@ -1609,7 +1758,7 @@ Editor exited with code ${result.status}`);
|
|
|
1609
1758
|
const finalHash = createHash(newContent);
|
|
1610
1759
|
if (initialHash === finalHash) {
|
|
1611
1760
|
console.log(`
|
|
1612
|
-
No changes were made to the ${
|
|
1761
|
+
No changes were made to the ${chalk11.cyan(environmentName)} environment.`);
|
|
1613
1762
|
} else {
|
|
1614
1763
|
const separatorIndex = newContent.indexOf(separator);
|
|
1615
1764
|
if (separatorIndex !== -1) {
|
|
@@ -1618,11 +1767,11 @@ No changes were made to the ${chalk10.cyan(environmentName)} environment.`);
|
|
|
1618
1767
|
}
|
|
1619
1768
|
await encryptEnvironment(environmentName, newContent);
|
|
1620
1769
|
console.log(`
|
|
1621
|
-
Encrypted ${
|
|
1770
|
+
Encrypted ${chalk11.cyan(environmentName)} environment and saved it to ${chalk11.gray(environmentFile)}.`);
|
|
1622
1771
|
}
|
|
1623
1772
|
} catch (error) {
|
|
1624
1773
|
console.error(`
|
|
1625
|
-
Failed to open editor: ${
|
|
1774
|
+
Failed to open editor: ${editorCommand}`);
|
|
1626
1775
|
console.error(error instanceof Error ? error.message : error);
|
|
1627
1776
|
} finally {
|
|
1628
1777
|
process.removeListener("SIGINT", onSignal);
|
|
@@ -1766,12 +1915,12 @@ var init_list2 = __esm(() => {
|
|
|
1766
1915
|
});
|
|
1767
1916
|
|
|
1768
1917
|
// src/commands/env/rotate.ts
|
|
1769
|
-
import
|
|
1918
|
+
import chalk12 from "chalk";
|
|
1770
1919
|
var rotateCommand = async (environmentNameArg) => {
|
|
1771
1920
|
const environmentName = environmentNameArg || await chooseEnvironmentPrompt("What environment do you want to rotate the data key for?");
|
|
1772
1921
|
const validation = validateEnvironmentName(environmentName);
|
|
1773
1922
|
if (!validation.valid) {
|
|
1774
|
-
console.error(`${
|
|
1923
|
+
console.error(`${chalk12.red("Error:")} ${validation.reason}`);
|
|
1775
1924
|
process.exit(1);
|
|
1776
1925
|
}
|
|
1777
1926
|
let currentContent;
|
|
@@ -1866,9 +2015,81 @@ var init_createEd25519SshKey = __esm(() => {
|
|
|
1866
2015
|
};
|
|
1867
2016
|
});
|
|
1868
2017
|
|
|
2018
|
+
// src/helpers/validatePublicKey.ts
|
|
2019
|
+
function getRsaModulusLength(key) {
|
|
2020
|
+
const der = key.export({ type: "spki", format: "der" });
|
|
2021
|
+
let i = 0;
|
|
2022
|
+
i += 1;
|
|
2023
|
+
i += der[i] & 128 ? (der[i] & 127) + 1 : 1;
|
|
2024
|
+
i += 1;
|
|
2025
|
+
let algLen = 0;
|
|
2026
|
+
if (der[i] & 128) {
|
|
2027
|
+
const n = der[i] & 127;
|
|
2028
|
+
for (let j = 1;j <= n; j++)
|
|
2029
|
+
algLen = algLen << 8 | der[i + j];
|
|
2030
|
+
i += n + 1;
|
|
2031
|
+
} else {
|
|
2032
|
+
algLen = der[i];
|
|
2033
|
+
i += 1;
|
|
2034
|
+
}
|
|
2035
|
+
i += algLen;
|
|
2036
|
+
i += 1;
|
|
2037
|
+
i += der[i] & 128 ? (der[i] & 127) + 1 : 1;
|
|
2038
|
+
i += 1;
|
|
2039
|
+
i += 1;
|
|
2040
|
+
i += der[i] & 128 ? (der[i] & 127) + 1 : 1;
|
|
2041
|
+
i += 1;
|
|
2042
|
+
let modLen = 0;
|
|
2043
|
+
if (der[i] & 128) {
|
|
2044
|
+
const n = der[i] & 127;
|
|
2045
|
+
for (let j = 1;j <= n; j++)
|
|
2046
|
+
modLen = modLen << 8 | der[i + j];
|
|
2047
|
+
i += n + 1;
|
|
2048
|
+
} else {
|
|
2049
|
+
modLen = der[i];
|
|
2050
|
+
i += 1;
|
|
2051
|
+
}
|
|
2052
|
+
if (der[i] === 0)
|
|
2053
|
+
modLen -= 1;
|
|
2054
|
+
return modLen * 8;
|
|
2055
|
+
}
|
|
2056
|
+
function validatePublicKey(key) {
|
|
2057
|
+
const keyType = key.asymmetricKeyType;
|
|
2058
|
+
switch (keyType) {
|
|
2059
|
+
case "rsa": {
|
|
2060
|
+
const modulusLength = getRsaModulusLength(key);
|
|
2061
|
+
if (modulusLength < 2048) {
|
|
2062
|
+
return {
|
|
2063
|
+
valid: false,
|
|
2064
|
+
reason: `RSA key is ${modulusLength} bits, minimum is 2048 bits.`
|
|
2065
|
+
};
|
|
2066
|
+
}
|
|
2067
|
+
return { valid: true };
|
|
2068
|
+
}
|
|
2069
|
+
case "ed25519":
|
|
2070
|
+
return { valid: true };
|
|
2071
|
+
case "dsa":
|
|
2072
|
+
return {
|
|
2073
|
+
valid: false,
|
|
2074
|
+
reason: "DSA keys are not supported. Use Ed25519 or RSA (2048+ bits)."
|
|
2075
|
+
};
|
|
2076
|
+
case "ec":
|
|
2077
|
+
return {
|
|
2078
|
+
valid: false,
|
|
2079
|
+
reason: "ECDSA keys are not supported. Use Ed25519 or RSA (2048+ bits)."
|
|
2080
|
+
};
|
|
2081
|
+
default:
|
|
2082
|
+
return {
|
|
2083
|
+
valid: false,
|
|
2084
|
+
reason: `Unsupported key type: ${keyType}. Use Ed25519 or RSA (2048+ bits).`
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
|
|
1869
2089
|
// src/prompts/choosePrivateKey.ts
|
|
2090
|
+
import crypto10 from "node:crypto";
|
|
1870
2091
|
import path12 from "node:path";
|
|
1871
|
-
import
|
|
2092
|
+
import chalk13 from "chalk";
|
|
1872
2093
|
import inquirer5 from "inquirer";
|
|
1873
2094
|
function toSupportedChoice(key) {
|
|
1874
2095
|
return {
|
|
@@ -1878,23 +2099,48 @@ function toSupportedChoice(key) {
|
|
|
1878
2099
|
}
|
|
1879
2100
|
function toUnsupportedChoice(key, index) {
|
|
1880
2101
|
return {
|
|
1881
|
-
name: `${
|
|
2102
|
+
name: `${chalk13.gray(key.name)} (${chalk13.yellow(key.reason)})`,
|
|
1882
2103
|
value: `__unsupported_${index}__`,
|
|
1883
2104
|
disabled: true
|
|
1884
2105
|
};
|
|
1885
2106
|
}
|
|
2107
|
+
function classifySupportedKeys(keys) {
|
|
2108
|
+
const supportedKeys = [];
|
|
2109
|
+
const policyUnsupportedKeys = [];
|
|
2110
|
+
for (const key of keys) {
|
|
2111
|
+
try {
|
|
2112
|
+
const publicKey = crypto10.createPublicKey(key.privateKey);
|
|
2113
|
+
const validation = validatePublicKey(publicKey);
|
|
2114
|
+
if (!validation.valid) {
|
|
2115
|
+
policyUnsupportedKeys.push({
|
|
2116
|
+
name: key.name,
|
|
2117
|
+
reason: validation.reason
|
|
2118
|
+
});
|
|
2119
|
+
continue;
|
|
2120
|
+
}
|
|
2121
|
+
} catch {
|
|
2122
|
+
policyUnsupportedKeys.push({
|
|
2123
|
+
name: key.name,
|
|
2124
|
+
reason: "invalid private key format"
|
|
2125
|
+
});
|
|
2126
|
+
continue;
|
|
2127
|
+
}
|
|
2128
|
+
supportedKeys.push(key);
|
|
2129
|
+
}
|
|
2130
|
+
return { supportedKeys, policyUnsupportedKeys };
|
|
2131
|
+
}
|
|
1886
2132
|
var CREATE_NEW_PRIVATE_KEY_CHOICE = "__dotenc_create_new_private_key__", defaultChoosePrivateKeyPromptDeps, buildPromptChoices = (keys, unsupportedKeys) => {
|
|
1887
2133
|
const choices = keys.map(toSupportedChoice);
|
|
1888
2134
|
if (unsupportedKeys.length > 0) {
|
|
1889
2135
|
if (choices.length > 0) {
|
|
1890
2136
|
choices.push({
|
|
1891
|
-
name:
|
|
2137
|
+
name: chalk13.gray("────────"),
|
|
1892
2138
|
value: "__separator_supported_unsupported__",
|
|
1893
2139
|
disabled: true
|
|
1894
2140
|
});
|
|
1895
2141
|
}
|
|
1896
2142
|
choices.push({
|
|
1897
|
-
name:
|
|
2143
|
+
name: chalk13.gray("Unsupported keys (ignored)"),
|
|
1898
2144
|
value: "__unsupported_header__",
|
|
1899
2145
|
disabled: true
|
|
1900
2146
|
});
|
|
@@ -1902,7 +2148,7 @@ var CREATE_NEW_PRIVATE_KEY_CHOICE = "__dotenc_create_new_private_key__", default
|
|
|
1902
2148
|
}
|
|
1903
2149
|
if (choices.length > 0) {
|
|
1904
2150
|
choices.push({
|
|
1905
|
-
name:
|
|
2151
|
+
name: chalk13.gray("────────"),
|
|
1906
2152
|
value: "__separator_create__",
|
|
1907
2153
|
disabled: true
|
|
1908
2154
|
});
|
|
@@ -1919,16 +2165,18 @@ var CREATE_NEW_PRIVATE_KEY_CHOICE = "__dotenc_create_new_private_key__", default
|
|
|
1919
2165
|
passphraseProtectedKeys,
|
|
1920
2166
|
unsupportedKeys = []
|
|
1921
2167
|
} = await deps.getPrivateKeys();
|
|
1922
|
-
const
|
|
2168
|
+
const { supportedKeys, policyUnsupportedKeys } = classifySupportedKeys(keys);
|
|
2169
|
+
const allUnsupportedKeys = [...unsupportedKeys, ...policyUnsupportedKeys];
|
|
2170
|
+
const privateKeyMap = new Map(supportedKeys.map((key) => [key.name, key]));
|
|
1923
2171
|
if (!deps.isInteractive()) {
|
|
1924
|
-
if (
|
|
1925
|
-
return
|
|
2172
|
+
if (supportedKeys.length > 0) {
|
|
2173
|
+
return supportedKeys[0];
|
|
1926
2174
|
}
|
|
1927
2175
|
if (passphraseProtectedKeys.length > 0) {
|
|
1928
2176
|
throw new Error(passphraseProtectedKeyError(passphraseProtectedKeys));
|
|
1929
2177
|
}
|
|
1930
|
-
if (
|
|
1931
|
-
const unsupportedList =
|
|
2178
|
+
if (allUnsupportedKeys.length > 0) {
|
|
2179
|
+
const unsupportedList = allUnsupportedKeys.map((key) => ` - ${key.name}: ${key.reason}`).join(`
|
|
1932
2180
|
`);
|
|
1933
2181
|
throw new Error(`No supported SSH keys found.
|
|
1934
2182
|
|
|
@@ -1945,16 +2193,16 @@ Generate a new key with:
|
|
|
1945
2193
|
type: "list",
|
|
1946
2194
|
name: "key",
|
|
1947
2195
|
message,
|
|
1948
|
-
choices: buildPromptChoices(
|
|
2196
|
+
choices: buildPromptChoices(supportedKeys, allUnsupportedKeys)
|
|
1949
2197
|
}
|
|
1950
2198
|
]);
|
|
1951
2199
|
const selected = String(result.key || "");
|
|
1952
2200
|
if (selected === CREATE_NEW_PRIVATE_KEY_CHOICE) {
|
|
1953
2201
|
try {
|
|
1954
2202
|
const createdPath = await deps.createEd25519SshKey();
|
|
1955
|
-
deps.logInfo(`${
|
|
2203
|
+
deps.logInfo(`${chalk13.green("✔")} Created ${chalk13.cyan(path12.basename(createdPath))} at ${chalk13.gray(createdPath)}.`);
|
|
1956
2204
|
} catch (error) {
|
|
1957
|
-
deps.logWarn(`${
|
|
2205
|
+
deps.logWarn(`${chalk13.yellow("Warning:")} failed to create a new SSH key. ${error instanceof Error ? error.message : String(error)}`);
|
|
1958
2206
|
}
|
|
1959
2207
|
continue;
|
|
1960
2208
|
}
|
|
@@ -1994,77 +2242,6 @@ var inputNamePrompt = async (message, defaultValue) => {
|
|
|
1994
2242
|
};
|
|
1995
2243
|
var init_inputName = () => {};
|
|
1996
2244
|
|
|
1997
|
-
// src/helpers/validatePublicKey.ts
|
|
1998
|
-
function getRsaModulusLength(key) {
|
|
1999
|
-
const der = key.export({ type: "spki", format: "der" });
|
|
2000
|
-
let i = 0;
|
|
2001
|
-
i += 1;
|
|
2002
|
-
i += der[i] & 128 ? (der[i] & 127) + 1 : 1;
|
|
2003
|
-
i += 1;
|
|
2004
|
-
let algLen = 0;
|
|
2005
|
-
if (der[i] & 128) {
|
|
2006
|
-
const n = der[i] & 127;
|
|
2007
|
-
for (let j = 1;j <= n; j++)
|
|
2008
|
-
algLen = algLen << 8 | der[i + j];
|
|
2009
|
-
i += n + 1;
|
|
2010
|
-
} else {
|
|
2011
|
-
algLen = der[i];
|
|
2012
|
-
i += 1;
|
|
2013
|
-
}
|
|
2014
|
-
i += algLen;
|
|
2015
|
-
i += 1;
|
|
2016
|
-
i += der[i] & 128 ? (der[i] & 127) + 1 : 1;
|
|
2017
|
-
i += 1;
|
|
2018
|
-
i += 1;
|
|
2019
|
-
i += der[i] & 128 ? (der[i] & 127) + 1 : 1;
|
|
2020
|
-
i += 1;
|
|
2021
|
-
let modLen = 0;
|
|
2022
|
-
if (der[i] & 128) {
|
|
2023
|
-
const n = der[i] & 127;
|
|
2024
|
-
for (let j = 1;j <= n; j++)
|
|
2025
|
-
modLen = modLen << 8 | der[i + j];
|
|
2026
|
-
i += n + 1;
|
|
2027
|
-
} else {
|
|
2028
|
-
modLen = der[i];
|
|
2029
|
-
i += 1;
|
|
2030
|
-
}
|
|
2031
|
-
if (der[i] === 0)
|
|
2032
|
-
modLen -= 1;
|
|
2033
|
-
return modLen * 8;
|
|
2034
|
-
}
|
|
2035
|
-
function validatePublicKey(key) {
|
|
2036
|
-
const keyType = key.asymmetricKeyType;
|
|
2037
|
-
switch (keyType) {
|
|
2038
|
-
case "rsa": {
|
|
2039
|
-
const modulusLength = getRsaModulusLength(key);
|
|
2040
|
-
if (modulusLength < 2048) {
|
|
2041
|
-
return {
|
|
2042
|
-
valid: false,
|
|
2043
|
-
reason: `RSA key is ${modulusLength} bits, minimum is 2048 bits.`
|
|
2044
|
-
};
|
|
2045
|
-
}
|
|
2046
|
-
return { valid: true };
|
|
2047
|
-
}
|
|
2048
|
-
case "ed25519":
|
|
2049
|
-
return { valid: true };
|
|
2050
|
-
case "dsa":
|
|
2051
|
-
return {
|
|
2052
|
-
valid: false,
|
|
2053
|
-
reason: "DSA keys are not supported. Use Ed25519 or RSA (2048+ bits)."
|
|
2054
|
-
};
|
|
2055
|
-
case "ec":
|
|
2056
|
-
return {
|
|
2057
|
-
valid: false,
|
|
2058
|
-
reason: "ECDSA keys are not supported. Use Ed25519 or RSA (2048+ bits)."
|
|
2059
|
-
};
|
|
2060
|
-
default:
|
|
2061
|
-
return {
|
|
2062
|
-
valid: false,
|
|
2063
|
-
reason: `Unsupported key type: ${keyType}. Use Ed25519 or RSA (2048+ bits).`
|
|
2064
|
-
};
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
|
|
2068
2245
|
// src/prompts/inputKey.ts
|
|
2069
2246
|
import inquirer7 from "inquirer";
|
|
2070
2247
|
var inputKeyPrompt = async (message, defaultValue) => {
|
|
@@ -2082,95 +2259,99 @@ var inputKeyPrompt = async (message, defaultValue) => {
|
|
|
2082
2259
|
var init_inputKey = () => {};
|
|
2083
2260
|
|
|
2084
2261
|
// src/commands/key/add.ts
|
|
2085
|
-
import
|
|
2262
|
+
import crypto11 from "node:crypto";
|
|
2086
2263
|
import { existsSync as existsSync7 } from "node:fs";
|
|
2087
2264
|
import fs12 from "node:fs/promises";
|
|
2088
2265
|
import os5 from "node:os";
|
|
2089
2266
|
import path13 from "node:path";
|
|
2090
|
-
import
|
|
2267
|
+
import chalk14 from "chalk";
|
|
2091
2268
|
import inquirer8 from "inquirer";
|
|
2092
|
-
var
|
|
2269
|
+
var defaultDeps4, _runKeyAddCommand = async (nameArg, options, depsOverrides = {}) => {
|
|
2270
|
+
const deps = {
|
|
2271
|
+
...defaultDeps4,
|
|
2272
|
+
...depsOverrides
|
|
2273
|
+
};
|
|
2093
2274
|
let publicKey;
|
|
2094
2275
|
if (options?.fromSsh) {
|
|
2095
|
-
const sshPath = options.fromSsh.startsWith("~") ? path13.join(
|
|
2096
|
-
if (!
|
|
2097
|
-
|
|
2098
|
-
|
|
2276
|
+
const sshPath = options.fromSsh.startsWith("~") ? path13.join(deps.homedir(), options.fromSsh.slice(1)) : options.fromSsh;
|
|
2277
|
+
if (!deps.existsSync(sshPath)) {
|
|
2278
|
+
deps.logError(`File ${chalk14.cyan(sshPath)} does not exist. Please provide a valid SSH key path.`);
|
|
2279
|
+
deps.exit(1);
|
|
2099
2280
|
}
|
|
2100
|
-
const keyContent = await
|
|
2101
|
-
if (isPassphraseProtected(keyContent)) {
|
|
2102
|
-
|
|
2103
|
-
|
|
2281
|
+
const keyContent = await deps.readFile(sshPath, "utf-8");
|
|
2282
|
+
if (deps.isPassphraseProtected(keyContent)) {
|
|
2283
|
+
deps.logError(`${chalk14.red("Error:")} the provided key is passphrase-protected, which is not currently supported by dotenc.`);
|
|
2284
|
+
deps.exit(1);
|
|
2104
2285
|
}
|
|
2105
2286
|
try {
|
|
2106
|
-
const privateKey =
|
|
2107
|
-
publicKey =
|
|
2287
|
+
const privateKey = deps.createPrivateKey(keyContent);
|
|
2288
|
+
publicKey = deps.createPublicKey(privateKey);
|
|
2108
2289
|
} catch {
|
|
2109
|
-
const parsed = parseOpenSSHPrivateKey(keyContent);
|
|
2290
|
+
const parsed = deps.parseOpenSSHPrivateKey(keyContent);
|
|
2110
2291
|
if (parsed) {
|
|
2111
|
-
publicKey =
|
|
2292
|
+
publicKey = deps.createPublicKey(parsed);
|
|
2112
2293
|
} else {
|
|
2113
2294
|
try {
|
|
2114
|
-
publicKey =
|
|
2295
|
+
publicKey = deps.createPublicKey(keyContent);
|
|
2115
2296
|
} catch (error) {
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2297
|
+
deps.logError("Invalid SSH key format. Please provide a valid SSH key file.");
|
|
2298
|
+
deps.logError(`Details: ${error instanceof Error ? error.message : error}`);
|
|
2299
|
+
deps.exit(1);
|
|
2119
2300
|
}
|
|
2120
2301
|
}
|
|
2121
2302
|
}
|
|
2122
2303
|
}
|
|
2123
2304
|
if (options?.fromFile) {
|
|
2124
|
-
if (!
|
|
2125
|
-
|
|
2126
|
-
|
|
2305
|
+
if (!deps.existsSync(options.fromFile)) {
|
|
2306
|
+
deps.logError(`File ${chalk14.cyan(options.fromFile)} does not exist. Please provide a valid file path.`);
|
|
2307
|
+
deps.exit(1);
|
|
2127
2308
|
}
|
|
2128
|
-
const keyContent = await
|
|
2129
|
-
if (isPassphraseProtected(keyContent)) {
|
|
2130
|
-
|
|
2131
|
-
|
|
2309
|
+
const keyContent = await deps.readFile(options.fromFile, "utf-8");
|
|
2310
|
+
if (deps.isPassphraseProtected(keyContent)) {
|
|
2311
|
+
deps.logError(`${chalk14.red("Error:")} the provided key is passphrase-protected, which is not currently supported by dotenc.`);
|
|
2312
|
+
deps.exit(1);
|
|
2132
2313
|
}
|
|
2133
2314
|
try {
|
|
2134
|
-
publicKey =
|
|
2315
|
+
publicKey = deps.createPublicKey(keyContent);
|
|
2135
2316
|
} catch {
|
|
2136
2317
|
try {
|
|
2137
|
-
const privateKey =
|
|
2138
|
-
publicKey =
|
|
2318
|
+
const privateKey = deps.createPrivateKey(keyContent);
|
|
2319
|
+
publicKey = deps.createPublicKey(privateKey);
|
|
2139
2320
|
} catch {
|
|
2140
|
-
const parsed = parseOpenSSHPrivateKey(keyContent);
|
|
2321
|
+
const parsed = deps.parseOpenSSHPrivateKey(keyContent);
|
|
2141
2322
|
if (parsed) {
|
|
2142
|
-
publicKey =
|
|
2323
|
+
publicKey = deps.createPublicKey(parsed);
|
|
2143
2324
|
} else {
|
|
2144
|
-
|
|
2145
|
-
|
|
2325
|
+
deps.logError("Invalid key format. Please provide a valid PEM formatted public or private key.");
|
|
2326
|
+
deps.exit(1);
|
|
2146
2327
|
}
|
|
2147
2328
|
}
|
|
2148
2329
|
}
|
|
2149
2330
|
}
|
|
2150
2331
|
if (options?.fromString) {
|
|
2151
|
-
if (isPassphraseProtected(options.fromString)) {
|
|
2152
|
-
|
|
2153
|
-
|
|
2332
|
+
if (deps.isPassphraseProtected(options.fromString)) {
|
|
2333
|
+
deps.logError(`${chalk14.red("Error:")} the provided key is passphrase-protected, which is not currently supported by dotenc.`);
|
|
2334
|
+
deps.exit(1);
|
|
2154
2335
|
}
|
|
2155
2336
|
try {
|
|
2156
|
-
publicKey =
|
|
2337
|
+
publicKey = deps.createPublicKey(options.fromString);
|
|
2157
2338
|
} catch {
|
|
2158
2339
|
try {
|
|
2159
|
-
const privateKey =
|
|
2160
|
-
publicKey =
|
|
2340
|
+
const privateKey = deps.createPrivateKey(options.fromString);
|
|
2341
|
+
publicKey = deps.createPublicKey(privateKey);
|
|
2161
2342
|
} catch {
|
|
2162
|
-
const parsed = parseOpenSSHPrivateKey(options.fromString);
|
|
2343
|
+
const parsed = deps.parseOpenSSHPrivateKey(options.fromString);
|
|
2163
2344
|
if (parsed) {
|
|
2164
|
-
publicKey =
|
|
2345
|
+
publicKey = deps.createPublicKey(parsed);
|
|
2165
2346
|
} else {
|
|
2166
|
-
|
|
2167
|
-
|
|
2347
|
+
deps.logError("Invalid key format. Please provide a valid PEM formatted public or private key.");
|
|
2348
|
+
deps.exit(1);
|
|
2168
2349
|
}
|
|
2169
2350
|
}
|
|
2170
2351
|
}
|
|
2171
2352
|
}
|
|
2172
2353
|
if (!publicKey) {
|
|
2173
|
-
const modePrompt = await
|
|
2354
|
+
const modePrompt = await deps.prompt({
|
|
2174
2355
|
type: "list",
|
|
2175
2356
|
name: "mode",
|
|
2176
2357
|
message: "Would you like to add one of your SSH keys or paste a public key?",
|
|
@@ -2180,74 +2361,103 @@ var keyAddCommand = async (nameArg, options) => {
|
|
|
2180
2361
|
]
|
|
2181
2362
|
});
|
|
2182
2363
|
if (modePrompt.mode === "paste") {
|
|
2183
|
-
const publicKeyInput = await inputKeyPrompt("Please paste your public key (PEM format):");
|
|
2364
|
+
const publicKeyInput = await deps.inputKeyPrompt("Please paste your public key (PEM format):");
|
|
2184
2365
|
if (!publicKeyInput) {
|
|
2185
|
-
|
|
2186
|
-
|
|
2366
|
+
deps.logError("No public key provided. Add operation cancelled.");
|
|
2367
|
+
deps.exit(1);
|
|
2187
2368
|
}
|
|
2188
2369
|
try {
|
|
2189
|
-
publicKey =
|
|
2370
|
+
publicKey = deps.createPublicKey(publicKeyInput);
|
|
2190
2371
|
} catch (error) {
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2372
|
+
deps.logError("Invalid public key format. Please provide a valid PEM formatted public key.");
|
|
2373
|
+
deps.logError(`Details: ${error instanceof Error ? error.message : error}`);
|
|
2374
|
+
deps.exit(1);
|
|
2194
2375
|
}
|
|
2195
2376
|
} else {
|
|
2196
2377
|
let selectedKey;
|
|
2197
2378
|
try {
|
|
2198
|
-
selectedKey = await choosePrivateKeyPrompt("Which SSH key do you want to add?");
|
|
2379
|
+
selectedKey = await deps.choosePrivateKeyPrompt("Which SSH key do you want to add?");
|
|
2199
2380
|
} catch (error) {
|
|
2200
|
-
|
|
2201
|
-
|
|
2381
|
+
deps.logError(error instanceof Error ? error.message : String(error));
|
|
2382
|
+
deps.exit(1);
|
|
2202
2383
|
}
|
|
2203
|
-
publicKey =
|
|
2384
|
+
publicKey = deps.createPublicKey(selectedKey.privateKey);
|
|
2204
2385
|
if (!nameArg) {
|
|
2205
2386
|
nameArg = selectedKey.name;
|
|
2206
2387
|
}
|
|
2207
2388
|
}
|
|
2208
2389
|
}
|
|
2209
2390
|
if (!publicKey) {
|
|
2210
|
-
|
|
2211
|
-
|
|
2391
|
+
deps.logError("An unexpected error occurred. No public key was inferred from the provided input.");
|
|
2392
|
+
deps.exit(1);
|
|
2212
2393
|
}
|
|
2213
|
-
const validation = validatePublicKey(publicKey);
|
|
2394
|
+
const validation = deps.validatePublicKey(publicKey);
|
|
2214
2395
|
if (!validation.valid) {
|
|
2215
|
-
|
|
2216
|
-
|
|
2396
|
+
deps.logError(validation.reason);
|
|
2397
|
+
deps.exit(1);
|
|
2217
2398
|
}
|
|
2218
2399
|
const publicKeyOutput = publicKey.export({
|
|
2219
2400
|
type: "spki",
|
|
2220
2401
|
format: "pem"
|
|
2221
2402
|
});
|
|
2222
|
-
if (!
|
|
2223
|
-
await
|
|
2403
|
+
if (!deps.existsSync(path13.join(deps.cwd(), ".dotenc"))) {
|
|
2404
|
+
await deps.mkdir(path13.join(deps.cwd(), ".dotenc"));
|
|
2224
2405
|
}
|
|
2225
2406
|
let name = nameArg;
|
|
2226
2407
|
if (!name) {
|
|
2227
|
-
name = await inputNamePrompt("What name do you want to give to the new public key?");
|
|
2228
|
-
if (existsSync7(path13.join(process.cwd(), ".dotenc", `${name}.pub`))) {
|
|
2229
|
-
console.error(`A public key with name ${chalk13.cyan(name)} already exists. Please choose a different name.`);
|
|
2230
|
-
process.exit(1);
|
|
2231
|
-
}
|
|
2408
|
+
name = await deps.inputNamePrompt("What name do you want to give to the new public key?");
|
|
2232
2409
|
}
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2410
|
+
const keyNameValidation = deps.validateKeyName(name);
|
|
2411
|
+
if (!keyNameValidation.valid) {
|
|
2412
|
+
deps.logError(`${chalk14.red("Error:")} ${keyNameValidation.reason}`);
|
|
2413
|
+
deps.exit(1);
|
|
2414
|
+
}
|
|
2415
|
+
const keyOutputPath = path13.join(deps.cwd(), ".dotenc", `${name}.pub`);
|
|
2416
|
+
if (deps.existsSync(keyOutputPath)) {
|
|
2417
|
+
deps.logError(`A public key with name ${chalk14.cyan(name)} already exists. Please choose a different name.`);
|
|
2418
|
+
deps.exit(1);
|
|
2419
|
+
}
|
|
2420
|
+
await deps.writeFile(keyOutputPath, publicKeyOutput, "utf-8");
|
|
2421
|
+
deps.logInfo(`
|
|
2422
|
+
Public key ${chalk14.cyan(name)} added successfully!`);
|
|
2423
|
+
}, keyAddCommand = async (nameArg, options) => {
|
|
2424
|
+
return _runKeyAddCommand(nameArg, options);
|
|
2236
2425
|
};
|
|
2237
2426
|
var init_add = __esm(() => {
|
|
2238
2427
|
init_parseOpenSSHKey();
|
|
2239
2428
|
init_choosePrivateKey();
|
|
2240
2429
|
init_inputKey();
|
|
2241
2430
|
init_inputName();
|
|
2431
|
+
defaultDeps4 = {
|
|
2432
|
+
createPrivateKey: crypto11.createPrivateKey,
|
|
2433
|
+
createPublicKey: crypto11.createPublicKey,
|
|
2434
|
+
existsSync: existsSync7,
|
|
2435
|
+
readFile: fs12.readFile,
|
|
2436
|
+
mkdir: fs12.mkdir,
|
|
2437
|
+
writeFile: fs12.writeFile,
|
|
2438
|
+
homedir: os5.homedir,
|
|
2439
|
+
cwd: process.cwd,
|
|
2440
|
+
prompt: inquirer8.prompt,
|
|
2441
|
+
isPassphraseProtected,
|
|
2442
|
+
parseOpenSSHPrivateKey,
|
|
2443
|
+
validatePublicKey,
|
|
2444
|
+
validateKeyName,
|
|
2445
|
+
choosePrivateKeyPrompt,
|
|
2446
|
+
inputKeyPrompt,
|
|
2447
|
+
inputNamePrompt,
|
|
2448
|
+
logError: (message) => console.error(message),
|
|
2449
|
+
logInfo: (message) => console.log(message),
|
|
2450
|
+
exit: (code) => process.exit(code)
|
|
2451
|
+
};
|
|
2242
2452
|
});
|
|
2243
2453
|
|
|
2244
2454
|
// src/commands/init.ts
|
|
2245
|
-
import
|
|
2455
|
+
import crypto12 from "node:crypto";
|
|
2246
2456
|
import { existsSync as existsSync8 } from "node:fs";
|
|
2247
2457
|
import fs13 from "node:fs/promises";
|
|
2248
2458
|
import os6 from "node:os";
|
|
2249
2459
|
import path14 from "node:path";
|
|
2250
|
-
import
|
|
2460
|
+
import chalk15 from "chalk";
|
|
2251
2461
|
var _resolveDocsUrl = () => {
|
|
2252
2462
|
if (typeof package_default.homepage === "string" && package_default.homepage.trim().length > 0) {
|
|
2253
2463
|
return package_default.homepage;
|
|
@@ -2257,64 +2467,70 @@ var _resolveDocsUrl = () => {
|
|
|
2257
2467
|
return;
|
|
2258
2468
|
}
|
|
2259
2469
|
return repositoryUrl.replace(/^git\+/, "").replace(/\.git$/, "");
|
|
2260
|
-
},
|
|
2261
|
-
const
|
|
2470
|
+
}, defaultDeps5, _runInitCommand = async (options, depsOverrides = {}) => {
|
|
2471
|
+
const deps = {
|
|
2472
|
+
...defaultDeps5,
|
|
2473
|
+
...depsOverrides
|
|
2474
|
+
};
|
|
2475
|
+
const username = options.name || await deps.inputNamePrompt("What's your name?", deps.userInfo().username);
|
|
2262
2476
|
if (!username) {
|
|
2263
|
-
|
|
2264
|
-
|
|
2477
|
+
deps.logError(`${chalk15.red("Error:")} no name provided.`);
|
|
2478
|
+
deps.exit(1);
|
|
2265
2479
|
}
|
|
2266
2480
|
let keyEntry;
|
|
2267
2481
|
try {
|
|
2268
|
-
keyEntry = await choosePrivateKeyPrompt("Which SSH key would you like to use?");
|
|
2482
|
+
keyEntry = await deps.choosePrivateKeyPrompt("Which SSH key would you like to use?");
|
|
2269
2483
|
} catch (error) {
|
|
2270
|
-
|
|
2271
|
-
|
|
2484
|
+
deps.logError(error instanceof Error ? error.message : String(error));
|
|
2485
|
+
deps.exit(1);
|
|
2272
2486
|
}
|
|
2273
|
-
|
|
2274
|
-
const publicKey =
|
|
2487
|
+
deps.logInfo(`Adding key: ${chalk15.cyan(username)} (${keyEntry.algorithm})`);
|
|
2488
|
+
const publicKey = deps.createPublicKey(keyEntry.privateKey);
|
|
2275
2489
|
const publicKeyPem = publicKey.export({ type: "spki", format: "pem" }).toString();
|
|
2276
|
-
await keyAddCommand(username, {
|
|
2490
|
+
await deps.keyAddCommand(username, {
|
|
2277
2491
|
fromString: publicKeyPem
|
|
2278
2492
|
});
|
|
2279
2493
|
try {
|
|
2280
|
-
setupGitDiff();
|
|
2494
|
+
deps.setupGitDiff();
|
|
2281
2495
|
} catch (_error) {
|
|
2282
|
-
|
|
2496
|
+
deps.logWarn(`${chalk15.yellow("Warning:")} could not set up git diff driver. You can run ${chalk15.gray("dotenc init")} again inside a git repository.`);
|
|
2283
2497
|
}
|
|
2284
2498
|
let initialContent;
|
|
2285
|
-
const envPath = path14.join(
|
|
2286
|
-
if (
|
|
2287
|
-
initialContent = await
|
|
2288
|
-
await
|
|
2289
|
-
|
|
2499
|
+
const envPath = path14.join(deps.cwd(), ".env");
|
|
2500
|
+
if (deps.existsSync(envPath)) {
|
|
2501
|
+
initialContent = await deps.readFile(envPath, "utf-8");
|
|
2502
|
+
await deps.unlink(envPath);
|
|
2503
|
+
deps.logInfo(`Migrated ${chalk15.gray(".env")} contents to ${chalk15.cyan("development")} environment.`);
|
|
2290
2504
|
}
|
|
2291
|
-
await createCommand("development", username, initialContent);
|
|
2505
|
+
await deps.createCommand("development", username, initialContent);
|
|
2292
2506
|
if (username !== "development") {
|
|
2293
|
-
await createCommand(username, username);
|
|
2507
|
+
await deps.createCommand(username, username);
|
|
2294
2508
|
}
|
|
2295
|
-
|
|
2296
|
-
${
|
|
2297
|
-
|
|
2509
|
+
deps.logInfo(`
|
|
2510
|
+
${chalk15.green("✔")} Initialization complete!`);
|
|
2511
|
+
deps.logInfo(`
|
|
2298
2512
|
Some useful tips:`);
|
|
2299
|
-
const developmentEditCmd =
|
|
2300
|
-
const personalEditCmd =
|
|
2301
|
-
|
|
2513
|
+
const developmentEditCmd = chalk15.gray("dotenc env edit development");
|
|
2514
|
+
const personalEditCmd = chalk15.gray(`dotenc env edit ${username}`);
|
|
2515
|
+
deps.logInfo(`- Edit the development environment: ${developmentEditCmd}`);
|
|
2302
2516
|
if (username !== "development") {
|
|
2303
|
-
|
|
2517
|
+
deps.logInfo(`- Edit your personal environment: ${personalEditCmd}`);
|
|
2304
2518
|
}
|
|
2305
2519
|
const devEnvironmentChain = username === "development" ? "development" : `development,${username}`;
|
|
2306
|
-
const devCmd =
|
|
2307
|
-
|
|
2308
|
-
const docsUrl =
|
|
2520
|
+
const devCmd = chalk15.gray("dotenc dev <command>");
|
|
2521
|
+
deps.logInfo(`- Run in development mode: ${devCmd} ${chalk15.gray(`(loads ${devEnvironmentChain})`)}`);
|
|
2522
|
+
const docsUrl = deps.resolveDocsUrl();
|
|
2309
2523
|
if (docsUrl) {
|
|
2310
|
-
|
|
2524
|
+
deps.logInfo(`- Full docs: ${chalk15.gray(docsUrl)}`);
|
|
2311
2525
|
}
|
|
2312
|
-
if (
|
|
2313
|
-
|
|
2526
|
+
if (deps.existsSync(".claude") || deps.existsSync("CLAUDE.md")) {
|
|
2527
|
+
deps.logInfo(`- Install the agent skill: ${chalk15.gray("dotenc tools install-agent-skill")}`);
|
|
2314
2528
|
}
|
|
2315
|
-
if (
|
|
2316
|
-
|
|
2529
|
+
if (deps.existsSync(".vscode") || deps.existsSync(".cursor") || deps.existsSync(".windsurf")) {
|
|
2530
|
+
deps.logInfo(`- Add the editor extension: ${chalk15.gray("dotenc tools install-vscode-extension")}`);
|
|
2317
2531
|
}
|
|
2532
|
+
}, initCommand = async (options) => {
|
|
2533
|
+
return _runInitCommand(options);
|
|
2318
2534
|
};
|
|
2319
2535
|
var init_init = __esm(() => {
|
|
2320
2536
|
init_package();
|
|
@@ -2323,6 +2539,24 @@ var init_init = __esm(() => {
|
|
|
2323
2539
|
init_inputName();
|
|
2324
2540
|
init_create();
|
|
2325
2541
|
init_add();
|
|
2542
|
+
defaultDeps5 = {
|
|
2543
|
+
inputNamePrompt,
|
|
2544
|
+
userInfo: os6.userInfo,
|
|
2545
|
+
choosePrivateKeyPrompt,
|
|
2546
|
+
createPublicKey: crypto12.createPublicKey,
|
|
2547
|
+
keyAddCommand,
|
|
2548
|
+
setupGitDiff,
|
|
2549
|
+
existsSync: existsSync8,
|
|
2550
|
+
readFile: fs13.readFile,
|
|
2551
|
+
unlink: fs13.unlink,
|
|
2552
|
+
cwd: process.cwd,
|
|
2553
|
+
createCommand,
|
|
2554
|
+
logInfo: (message) => console.log(message),
|
|
2555
|
+
logWarn: (message) => console.warn(message),
|
|
2556
|
+
logError: (message) => console.error(message),
|
|
2557
|
+
resolveDocsUrl: _resolveDocsUrl,
|
|
2558
|
+
exit: (code) => process.exit(code)
|
|
2559
|
+
};
|
|
2326
2560
|
});
|
|
2327
2561
|
|
|
2328
2562
|
// src/commands/key/list.ts
|
|
@@ -2358,15 +2592,20 @@ var init_confirm = () => {};
|
|
|
2358
2592
|
import { existsSync as existsSync9 } from "node:fs";
|
|
2359
2593
|
import fs14 from "node:fs/promises";
|
|
2360
2594
|
import path15 from "node:path";
|
|
2361
|
-
import
|
|
2595
|
+
import chalk16 from "chalk";
|
|
2362
2596
|
var keyRemoveCommand = async (nameArg) => {
|
|
2363
2597
|
let name = nameArg;
|
|
2364
2598
|
if (!name) {
|
|
2365
2599
|
name = await choosePublicKeyPrompt("Which public key do you want to remove?");
|
|
2366
2600
|
}
|
|
2601
|
+
const keyNameValidation = validateKeyName(name);
|
|
2602
|
+
if (!keyNameValidation.valid) {
|
|
2603
|
+
console.error(`${chalk16.red("Error:")} ${keyNameValidation.reason}`);
|
|
2604
|
+
process.exit(1);
|
|
2605
|
+
}
|
|
2367
2606
|
const filePath = path15.join(process.cwd(), ".dotenc", `${name}.pub`);
|
|
2368
2607
|
if (!existsSync9(filePath)) {
|
|
2369
|
-
console.error(`Public key ${
|
|
2608
|
+
console.error(`Public key ${chalk16.cyan(name)} not found.`);
|
|
2370
2609
|
process.exit(1);
|
|
2371
2610
|
}
|
|
2372
2611
|
const allEnvironments = await getEnvironments();
|
|
@@ -2380,7 +2619,7 @@ var keyRemoveCommand = async (nameArg) => {
|
|
|
2380
2619
|
} catch {}
|
|
2381
2620
|
}
|
|
2382
2621
|
if (affectedEnvironments.length > 0) {
|
|
2383
|
-
console.log(`Key ${
|
|
2622
|
+
console.log(`Key ${chalk16.cyan(name)} has access to the following environments:`);
|
|
2384
2623
|
for (const env of affectedEnvironments) {
|
|
2385
2624
|
console.log(` - ${env}`);
|
|
2386
2625
|
}
|
|
@@ -2393,7 +2632,7 @@ Access will be revoked from these environments automatically.`);
|
|
|
2393
2632
|
return;
|
|
2394
2633
|
}
|
|
2395
2634
|
await fs14.unlink(filePath);
|
|
2396
|
-
console.log(`Public key ${
|
|
2635
|
+
console.log(`Public key ${chalk16.cyan(name)} removed successfully.`);
|
|
2397
2636
|
for (const envName of affectedEnvironments) {
|
|
2398
2637
|
try {
|
|
2399
2638
|
const envJson = await getEnvironmentByName(envName);
|
|
@@ -2401,9 +2640,9 @@ Access will be revoked from these environments automatically.`);
|
|
|
2401
2640
|
await encryptEnvironment(envName, content, {
|
|
2402
2641
|
revokePublicKeys: [name]
|
|
2403
2642
|
});
|
|
2404
|
-
console.log(`Revoked access from ${
|
|
2643
|
+
console.log(`Revoked access from ${chalk16.cyan(envName)} environment.`);
|
|
2405
2644
|
} catch {
|
|
2406
|
-
console.warn(`${
|
|
2645
|
+
console.warn(`${chalk16.yellow("Warning:")} could not revoke access from ${chalk16.cyan(envName)}. You may need to run ${chalk16.gray(`dotenc auth revoke ${envName} ${name}`)} manually or rotate the environment.`);
|
|
2407
2646
|
}
|
|
2408
2647
|
}
|
|
2409
2648
|
};
|
|
@@ -2437,7 +2676,7 @@ var init_textconv = __esm(() => {
|
|
|
2437
2676
|
|
|
2438
2677
|
// src/commands/tools/install-agent-skill.ts
|
|
2439
2678
|
import { spawn as spawn2 } from "node:child_process";
|
|
2440
|
-
import
|
|
2679
|
+
import chalk17 from "chalk";
|
|
2441
2680
|
import inquirer10 from "inquirer";
|
|
2442
2681
|
var SKILL_SOURCE = "ivanfilhoz/dotenc", SKILL_NAME = "dotenc", runNpx = (args, spawnImpl = spawn2) => new Promise((resolve, reject) => {
|
|
2443
2682
|
const child = spawnImpl("npx", args, {
|
|
@@ -2446,9 +2685,9 @@ var SKILL_SOURCE = "ivanfilhoz/dotenc", SKILL_NAME = "dotenc", runNpx = (args, s
|
|
|
2446
2685
|
});
|
|
2447
2686
|
child.on("error", reject);
|
|
2448
2687
|
child.on("exit", (code) => resolve(code ?? 1));
|
|
2449
|
-
}),
|
|
2688
|
+
}), defaultDeps6, _runInstallAgentSkillCommand = async (options, depsOverrides = {}) => {
|
|
2450
2689
|
const deps = {
|
|
2451
|
-
...
|
|
2690
|
+
...defaultDeps6,
|
|
2452
2691
|
...depsOverrides
|
|
2453
2692
|
};
|
|
2454
2693
|
const { scope } = await deps.prompt([
|
|
@@ -2474,21 +2713,21 @@ var SKILL_SOURCE = "ivanfilhoz/dotenc", SKILL_NAME = "dotenc", runNpx = (args, s
|
|
|
2474
2713
|
try {
|
|
2475
2714
|
exitCode = await deps.runNpx(args);
|
|
2476
2715
|
} catch (error) {
|
|
2477
|
-
deps.logError(`${
|
|
2478
|
-
deps.logError(`${
|
|
2716
|
+
deps.logError(`${chalk17.red("Error:")} failed to run ${chalk17.gray(npxCommand)}.`);
|
|
2717
|
+
deps.logError(`${chalk17.red("Details:")} ${error instanceof Error ? error.message : String(error)}`);
|
|
2479
2718
|
deps.exit(1);
|
|
2480
2719
|
}
|
|
2481
2720
|
if (exitCode !== 0) {
|
|
2482
|
-
deps.logError(`${
|
|
2721
|
+
deps.logError(`${chalk17.red("Error:")} skill installation command exited with code ${exitCode}.`);
|
|
2483
2722
|
deps.exit(exitCode);
|
|
2484
2723
|
}
|
|
2485
|
-
deps.log(`${
|
|
2486
|
-
deps.log(`Run ${
|
|
2724
|
+
deps.log(`${chalk17.green("✓")} Agent skill installation completed via ${chalk17.gray(npxCommand)}.`);
|
|
2725
|
+
deps.log(`Run ${chalk17.gray("/dotenc")} in your agent to use it.`);
|
|
2487
2726
|
}, installAgentSkillCommand = async (options) => {
|
|
2488
2727
|
await _runInstallAgentSkillCommand(options);
|
|
2489
2728
|
};
|
|
2490
2729
|
var init_install_agent_skill = __esm(() => {
|
|
2491
|
-
|
|
2730
|
+
defaultDeps6 = {
|
|
2492
2731
|
prompt: inquirer10.prompt,
|
|
2493
2732
|
runNpx,
|
|
2494
2733
|
log: console.log,
|
|
@@ -2503,7 +2742,7 @@ import { existsSync as existsSync10 } from "node:fs";
|
|
|
2503
2742
|
import fs16 from "node:fs/promises";
|
|
2504
2743
|
import path17 from "node:path";
|
|
2505
2744
|
import { promisify } from "node:util";
|
|
2506
|
-
import
|
|
2745
|
+
import chalk18 from "chalk";
|
|
2507
2746
|
import inquirer11 from "inquirer";
|
|
2508
2747
|
async function addToExtensionsJson() {
|
|
2509
2748
|
const extensionsJsonPath = path17.join(process.cwd(), ".vscode", "extensions.json");
|
|
@@ -2524,9 +2763,9 @@ async function addToExtensionsJson() {
|
|
|
2524
2763
|
if (!json.recommendations.includes(EXTENSION_ID)) {
|
|
2525
2764
|
json.recommendations.push(EXTENSION_ID);
|
|
2526
2765
|
await fs16.writeFile(extensionsJsonPath, JSON.stringify(json, null, 2), "utf-8");
|
|
2527
|
-
console.log(`${
|
|
2766
|
+
console.log(`${chalk18.green("✓")} Added dotenc to ${chalk18.gray(".vscode/extensions.json")}`);
|
|
2528
2767
|
} else {
|
|
2529
|
-
console.log(`${
|
|
2768
|
+
console.log(`${chalk18.green("✓")} dotenc already in ${chalk18.gray(".vscode/extensions.json")}`);
|
|
2530
2769
|
}
|
|
2531
2770
|
}
|
|
2532
2771
|
async function which(bin) {
|
|
@@ -2590,7 +2829,7 @@ async function _runInstallVscodeExtension(getEditors = detectEditors, _openUrl =
|
|
|
2590
2829
|
await addToExtensionsJson();
|
|
2591
2830
|
if (editors.length === 0) {
|
|
2592
2831
|
console.log(`
|
|
2593
|
-
Install the extension in VS Code: ${
|
|
2832
|
+
Install the extension in VS Code: ${chalk18.cyan(EDITOR_PROTOCOL_URLS.vscode)}`);
|
|
2594
2833
|
return;
|
|
2595
2834
|
}
|
|
2596
2835
|
if (editors.length === 1) {
|
|
@@ -2609,10 +2848,10 @@ Install the extension in VS Code: ${chalk17.cyan(EDITOR_PROTOCOL_URLS.vscode)}`)
|
|
|
2609
2848
|
try {
|
|
2610
2849
|
await _openUrl(url);
|
|
2611
2850
|
} catch {
|
|
2612
|
-
console.log(`Open manually: ${
|
|
2851
|
+
console.log(`Open manually: ${chalk18.cyan(url)}`);
|
|
2613
2852
|
}
|
|
2614
2853
|
} else {
|
|
2615
|
-
console.log(`Install manually: ${
|
|
2854
|
+
console.log(`Install manually: ${chalk18.cyan(url)}`);
|
|
2616
2855
|
}
|
|
2617
2856
|
return;
|
|
2618
2857
|
}
|
|
@@ -2621,7 +2860,7 @@ Install the extension in your editor:`);
|
|
|
2621
2860
|
for (const editor of editors) {
|
|
2622
2861
|
const name = EDITOR_NAMES[editor] ?? editor;
|
|
2623
2862
|
const url = EDITOR_PROTOCOL_URLS[editor];
|
|
2624
|
-
console.log(` ${name}: ${
|
|
2863
|
+
console.log(` ${name}: ${chalk18.cyan(url)}`);
|
|
2625
2864
|
}
|
|
2626
2865
|
}
|
|
2627
2866
|
var execFileAsync, execAsync, EXTENSION_ID = "dotenc.dotenc", EDITOR_PROTOCOL_URLS, EDITOR_NAMES, installVscodeExtensionCommand = async () => {
|
|
@@ -2728,7 +2967,7 @@ var init_update = () => {};
|
|
|
2728
2967
|
|
|
2729
2968
|
// src/commands/update.ts
|
|
2730
2969
|
import { spawn as spawn3 } from "node:child_process";
|
|
2731
|
-
import
|
|
2970
|
+
import chalk19 from "chalk";
|
|
2732
2971
|
var runPackageManagerCommand = (command, args, spawnImpl = spawn3) => new Promise((resolve, reject) => {
|
|
2733
2972
|
const child = spawnImpl(command, args, {
|
|
2734
2973
|
stdio: "inherit",
|
|
@@ -2736,23 +2975,23 @@ var runPackageManagerCommand = (command, args, spawnImpl = spawn3) => new Promis
|
|
|
2736
2975
|
});
|
|
2737
2976
|
child.on("error", reject);
|
|
2738
2977
|
child.on("exit", (code) => resolve(code ?? 1));
|
|
2739
|
-
}),
|
|
2978
|
+
}), defaultDeps7, updateCommands, _runUpdateCommand = async (depsOverrides = {}) => {
|
|
2740
2979
|
const deps = {
|
|
2741
|
-
...
|
|
2980
|
+
...defaultDeps7,
|
|
2742
2981
|
...depsOverrides
|
|
2743
2982
|
};
|
|
2744
2983
|
const method = deps.detectInstallMethod();
|
|
2745
2984
|
if (method === "binary") {
|
|
2746
|
-
deps.log(`Standalone binary detected. Download the latest release at ${
|
|
2985
|
+
deps.log(`Standalone binary detected. Download the latest release at ${chalk19.cyan(GITHUB_RELEASES_URL)}.`);
|
|
2747
2986
|
return;
|
|
2748
2987
|
}
|
|
2749
2988
|
if (method === "unknown") {
|
|
2750
2989
|
deps.log("Could not determine installation method automatically.");
|
|
2751
2990
|
deps.log(`Try one of these commands:`);
|
|
2752
|
-
deps.log(` ${
|
|
2753
|
-
deps.log(` ${
|
|
2754
|
-
deps.log(` ${
|
|
2755
|
-
deps.log(`Or download from ${
|
|
2991
|
+
deps.log(` ${chalk19.gray("brew update && brew upgrade dotenc")}`);
|
|
2992
|
+
deps.log(` ${chalk19.gray("scoop update dotenc")}`);
|
|
2993
|
+
deps.log(` ${chalk19.gray("npm install -g @dotenc/cli")}`);
|
|
2994
|
+
deps.log(`Or download from ${chalk19.cyan(GITHUB_RELEASES_URL)}.`);
|
|
2756
2995
|
return;
|
|
2757
2996
|
}
|
|
2758
2997
|
const updater = updateCommands[method];
|
|
@@ -2763,12 +3002,12 @@ var runPackageManagerCommand = (command, args, spawnImpl = spawn3) => new Promis
|
|
|
2763
3002
|
"update"
|
|
2764
3003
|
]);
|
|
2765
3004
|
if (brewUpdateCode !== 0) {
|
|
2766
|
-
deps.logError(`${
|
|
3005
|
+
deps.logError(`${chalk19.red("Error:")} update command exited with code ${brewUpdateCode}.`);
|
|
2767
3006
|
deps.exit(brewUpdateCode);
|
|
2768
3007
|
}
|
|
2769
3008
|
} catch (error) {
|
|
2770
|
-
deps.logError(`${
|
|
2771
|
-
deps.logError(`${
|
|
3009
|
+
deps.logError(`${chalk19.red("Error:")} failed to run ${chalk19.gray("brew update")}.`);
|
|
3010
|
+
deps.logError(`${chalk19.red("Details:")} ${error instanceof Error ? error.message : String(error)}`);
|
|
2772
3011
|
deps.exit(1);
|
|
2773
3012
|
}
|
|
2774
3013
|
}
|
|
@@ -2776,12 +3015,12 @@ var runPackageManagerCommand = (command, args, spawnImpl = spawn3) => new Promis
|
|
|
2776
3015
|
try {
|
|
2777
3016
|
exitCode = await deps.runPackageManagerCommand(updater.command, updater.args);
|
|
2778
3017
|
} catch (error) {
|
|
2779
|
-
deps.logError(`${
|
|
2780
|
-
deps.logError(`${
|
|
3018
|
+
deps.logError(`${chalk19.red("Error:")} failed to run ${chalk19.gray([updater.command, ...updater.args].join(" "))}.`);
|
|
3019
|
+
deps.logError(`${chalk19.red("Details:")} ${error instanceof Error ? error.message : String(error)}`);
|
|
2781
3020
|
deps.exit(1);
|
|
2782
3021
|
}
|
|
2783
3022
|
if (exitCode !== 0) {
|
|
2784
|
-
deps.logError(`${
|
|
3023
|
+
deps.logError(`${chalk19.red("Error:")} update command exited with code ${exitCode}.`);
|
|
2785
3024
|
deps.exit(exitCode);
|
|
2786
3025
|
}
|
|
2787
3026
|
}, updateCommand = async () => {
|
|
@@ -2789,7 +3028,7 @@ var runPackageManagerCommand = (command, args, spawnImpl = spawn3) => new Promis
|
|
|
2789
3028
|
};
|
|
2790
3029
|
var init_update2 = __esm(() => {
|
|
2791
3030
|
init_update();
|
|
2792
|
-
|
|
3031
|
+
defaultDeps7 = {
|
|
2793
3032
|
detectInstallMethod,
|
|
2794
3033
|
runPackageManagerCommand,
|
|
2795
3034
|
log: console.log,
|
|
@@ -2868,8 +3107,8 @@ var init_whoami = __esm(() => {
|
|
|
2868
3107
|
});
|
|
2869
3108
|
|
|
2870
3109
|
// src/helpers/updateNotifier.ts
|
|
2871
|
-
import
|
|
2872
|
-
var CHECK_INTERVAL_MS,
|
|
3110
|
+
import chalk20 from "chalk";
|
|
3111
|
+
var CHECK_INTERVAL_MS, defaultDeps8, shouldSkipCheck = (args, env) => {
|
|
2873
3112
|
if (env.DOTENC_SKIP_UPDATE_CHECK === "1") {
|
|
2874
3113
|
return true;
|
|
2875
3114
|
}
|
|
@@ -2891,7 +3130,7 @@ var CHECK_INTERVAL_MS, defaultDeps4, shouldSkipCheck = (args, env) => {
|
|
|
2891
3130
|
} catch {}
|
|
2892
3131
|
}, maybeNotifyAboutUpdate = async (depsOverrides = {}) => {
|
|
2893
3132
|
const deps = {
|
|
2894
|
-
...
|
|
3133
|
+
...defaultDeps8,
|
|
2895
3134
|
...depsOverrides
|
|
2896
3135
|
};
|
|
2897
3136
|
if (shouldSkipCheck(deps.args, deps.env)) {
|
|
@@ -2924,7 +3163,7 @@ var CHECK_INTERVAL_MS, defaultDeps4, shouldSkipCheck = (args, env) => {
|
|
|
2924
3163
|
if (updateState.notifiedVersion === latestVersion) {
|
|
2925
3164
|
return;
|
|
2926
3165
|
}
|
|
2927
|
-
deps.log(`${
|
|
3166
|
+
deps.log(`${chalk20.yellow("Update available:")} ${chalk20.gray(`dotenc ${deps.currentVersion}`)} -> ${chalk20.cyan(`dotenc ${latestVersion}`)}. Run ${chalk20.gray("dotenc update")}.`);
|
|
2928
3167
|
updateState = {
|
|
2929
3168
|
...updateState,
|
|
2930
3169
|
notifiedVersion: latestVersion
|
|
@@ -2936,7 +3175,7 @@ var init_updateNotifier = __esm(() => {
|
|
|
2936
3175
|
init_homeConfig();
|
|
2937
3176
|
init_update();
|
|
2938
3177
|
CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
2939
|
-
|
|
3178
|
+
defaultDeps8 = {
|
|
2940
3179
|
getHomeConfig,
|
|
2941
3180
|
setHomeConfig,
|
|
2942
3181
|
fetchLatestVersion,
|
|
@@ -2990,7 +3229,7 @@ var init_program = __esm(async () => {
|
|
|
2990
3229
|
auth.command("grant").argument("[environment]", "the environment to grant access to").argument("[publicKey]", "the name of the public key to grant access to the environment").description("grant access to an environment").action(grantCommand);
|
|
2991
3230
|
auth.command("revoke").argument("[environment]", "the environment to revoke access from").argument("[publicKey]", "the name of the public key to revoke access from the environment").description("revoke access from an environment").action(revokeCommand);
|
|
2992
3231
|
auth.command("list").argument("[environment]", "the environment to list access for").description("list keys with access to an environment").action(authListCommand);
|
|
2993
|
-
program.command("run").argument("<command>", "the command to run").argument("[args...]", "the arguments to pass to the command").addOption(new Option("-e, --env <env1>[,env2[,...]]", "the environments to run the command in")).description("run a command in an environment").action(runCommand);
|
|
3232
|
+
program.command("run").argument("<command>", "the command to run").argument("[args...]", "the arguments to pass to the command").addOption(new Option("-e, --env <env1>[,env2[,...]]", "the environments to run the command in")).addOption(new Option("--strict", "fail if any selected environment fails to load")).description("run a command in an environment").action(runCommand);
|
|
2994
3233
|
program.command("dev").argument("<command>", "the command to run").argument("[args...]", "the arguments to pass to the command").description("shortcut for 'run -e development,<yourname> <command>'").action((command, args) => devCommand(command, args));
|
|
2995
3234
|
key = program.command("key").description("manage keys");
|
|
2996
3235
|
key.command("add").argument("[name]", "the name of the public key in the project").addOption(new Option("--from-ssh <path>", "add a public key derived from an SSH key file")).addOption(new Option("-f, --from-file <file>", "add the key from a PEM file")).addOption(new Option("-s, --from-string <string>", "add a public key from a string")).description("add a public key to the project").action(keyAddCommand);
|