@keywaysh/cli 0.1.0 → 0.1.1

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.
@@ -0,0 +1,12 @@
1
+ import {
2
+ clearAuth,
3
+ getAuthFilePath,
4
+ getStoredAuth,
5
+ saveAuthToken
6
+ } from "./chunk-F4C46224.js";
7
+ export {
8
+ clearAuth,
9
+ getAuthFilePath,
10
+ getStoredAuth,
11
+ saveAuthToken
12
+ };
@@ -0,0 +1,102 @@
1
+ // src/utils/auth.ts
2
+ import Conf from "conf";
3
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
4
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from "fs";
5
+ import { join } from "path";
6
+ import { homedir } from "os";
7
+ var store = new Conf({
8
+ projectName: "keyway",
9
+ configName: "config",
10
+ fileMode: 384
11
+ });
12
+ var KEY_DIR = join(homedir(), ".keyway");
13
+ var KEY_FILE = join(KEY_DIR, ".key");
14
+ function getOrCreateEncryptionKey() {
15
+ if (!existsSync(KEY_DIR)) {
16
+ mkdirSync(KEY_DIR, { recursive: true, mode: 448 });
17
+ }
18
+ if (existsSync(KEY_FILE)) {
19
+ const keyHex2 = readFileSync(KEY_FILE, "utf-8").trim();
20
+ if (keyHex2.length === 64) {
21
+ return Buffer.from(keyHex2, "hex");
22
+ }
23
+ }
24
+ const key = randomBytes(32);
25
+ const keyHex = key.toString("hex");
26
+ writeFileSync(KEY_FILE, keyHex, { mode: 384 });
27
+ try {
28
+ chmodSync(KEY_FILE, 384);
29
+ } catch {
30
+ }
31
+ return key;
32
+ }
33
+ function encryptToken(token) {
34
+ const key = getOrCreateEncryptionKey();
35
+ const iv = randomBytes(16);
36
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
37
+ const encrypted = Buffer.concat([cipher.update(token, "utf8"), cipher.final()]);
38
+ const authTag = cipher.getAuthTag();
39
+ return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
40
+ }
41
+ function decryptToken(encryptedData) {
42
+ const key = getOrCreateEncryptionKey();
43
+ const parts = encryptedData.split(":");
44
+ if (parts.length !== 3) {
45
+ throw new Error("Invalid encrypted token format");
46
+ }
47
+ const iv = Buffer.from(parts[0], "hex");
48
+ const authTag = Buffer.from(parts[1], "hex");
49
+ const encrypted = Buffer.from(parts[2], "hex");
50
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
51
+ decipher.setAuthTag(authTag);
52
+ const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
53
+ return decrypted.toString("utf8");
54
+ }
55
+ function isExpired(auth) {
56
+ if (!auth.expiresAt) return false;
57
+ const expires = Date.parse(auth.expiresAt);
58
+ if (Number.isNaN(expires)) return false;
59
+ return expires <= Date.now();
60
+ }
61
+ async function getStoredAuth() {
62
+ const encryptedData = store.get("auth");
63
+ if (!encryptedData) {
64
+ return null;
65
+ }
66
+ try {
67
+ const decrypted = decryptToken(encryptedData);
68
+ const auth = JSON.parse(decrypted);
69
+ if (isExpired(auth)) {
70
+ clearAuth();
71
+ return null;
72
+ }
73
+ return auth;
74
+ } catch {
75
+ console.error("Failed to decrypt stored auth, clearing...");
76
+ clearAuth();
77
+ return null;
78
+ }
79
+ }
80
+ async function saveAuthToken(token, meta) {
81
+ const auth = {
82
+ keywayToken: token,
83
+ githubLogin: meta?.githubLogin,
84
+ expiresAt: meta?.expiresAt,
85
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
86
+ };
87
+ const encrypted = encryptToken(JSON.stringify(auth));
88
+ store.set("auth", encrypted);
89
+ }
90
+ function clearAuth() {
91
+ store.delete("auth");
92
+ }
93
+ function getAuthFilePath() {
94
+ return store.path;
95
+ }
96
+
97
+ export {
98
+ getStoredAuth,
99
+ saveAuthToken,
100
+ clearAuth,
101
+ getAuthFilePath
102
+ };
package/dist/cli.js CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ clearAuth,
4
+ getAuthFilePath,
5
+ getStoredAuth,
6
+ saveAuthToken
7
+ } from "./chunk-F4C46224.js";
2
8
 
3
9
  // src/cli.ts
4
10
  import { Command } from "commander";
@@ -70,7 +76,7 @@ var INTERNAL_POSTHOG_HOST = "https://eu.i.posthog.com";
70
76
  // package.json
71
77
  var package_default = {
72
78
  name: "@keywaysh/cli",
73
- version: "0.1.0",
79
+ version: "0.1.1",
74
80
  description: "One link to all your secrets",
75
81
  type: "module",
76
82
  bin: {
@@ -701,104 +707,6 @@ import pc2 from "picocolors";
701
707
  import readline from "readline";
702
708
  import open from "open";
703
709
  import prompts2 from "prompts";
704
-
705
- // src/utils/auth.ts
706
- import Conf from "conf";
707
- import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
708
- import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from "fs";
709
- import { join } from "path";
710
- import { homedir } from "os";
711
- var store = new Conf({
712
- projectName: "keyway",
713
- configName: "config",
714
- fileMode: 384
715
- });
716
- var KEY_DIR = join(homedir(), ".keyway");
717
- var KEY_FILE = join(KEY_DIR, ".key");
718
- function getOrCreateEncryptionKey() {
719
- if (!existsSync(KEY_DIR)) {
720
- mkdirSync(KEY_DIR, { recursive: true, mode: 448 });
721
- }
722
- if (existsSync(KEY_FILE)) {
723
- const keyHex2 = readFileSync(KEY_FILE, "utf-8").trim();
724
- if (keyHex2.length === 64) {
725
- return Buffer.from(keyHex2, "hex");
726
- }
727
- }
728
- const key = randomBytes(32);
729
- const keyHex = key.toString("hex");
730
- writeFileSync(KEY_FILE, keyHex, { mode: 384 });
731
- try {
732
- chmodSync(KEY_FILE, 384);
733
- } catch {
734
- }
735
- return key;
736
- }
737
- function encryptToken(token) {
738
- const key = getOrCreateEncryptionKey();
739
- const iv = randomBytes(16);
740
- const cipher = createCipheriv("aes-256-gcm", key, iv);
741
- const encrypted = Buffer.concat([cipher.update(token, "utf8"), cipher.final()]);
742
- const authTag = cipher.getAuthTag();
743
- return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
744
- }
745
- function decryptToken(encryptedData) {
746
- const key = getOrCreateEncryptionKey();
747
- const parts = encryptedData.split(":");
748
- if (parts.length !== 3) {
749
- throw new Error("Invalid encrypted token format");
750
- }
751
- const iv = Buffer.from(parts[0], "hex");
752
- const authTag = Buffer.from(parts[1], "hex");
753
- const encrypted = Buffer.from(parts[2], "hex");
754
- const decipher = createDecipheriv("aes-256-gcm", key, iv);
755
- decipher.setAuthTag(authTag);
756
- const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
757
- return decrypted.toString("utf8");
758
- }
759
- function isExpired(auth) {
760
- if (!auth.expiresAt) return false;
761
- const expires = Date.parse(auth.expiresAt);
762
- if (Number.isNaN(expires)) return false;
763
- return expires <= Date.now();
764
- }
765
- async function getStoredAuth() {
766
- const encryptedData = store.get("auth");
767
- if (!encryptedData) {
768
- return null;
769
- }
770
- try {
771
- const decrypted = decryptToken(encryptedData);
772
- const auth = JSON.parse(decrypted);
773
- if (isExpired(auth)) {
774
- clearAuth();
775
- return null;
776
- }
777
- return auth;
778
- } catch {
779
- console.error("Failed to decrypt stored auth, clearing...");
780
- clearAuth();
781
- return null;
782
- }
783
- }
784
- async function saveAuthToken(token, meta) {
785
- const auth = {
786
- keywayToken: token,
787
- githubLogin: meta?.githubLogin,
788
- expiresAt: meta?.expiresAt,
789
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
790
- };
791
- const encrypted = encryptToken(JSON.stringify(auth));
792
- store.set("auth", encrypted);
793
- }
794
- function clearAuth() {
795
- store.delete("auth");
796
- }
797
- function getAuthFilePath() {
798
- return store.path;
799
- }
800
-
801
- // src/cmds/login.ts
802
710
  function sleep(ms) {
803
711
  return new Promise((resolve) => setTimeout(resolve, ms));
804
712
  }
@@ -1213,11 +1121,18 @@ async function ensureLoginAndGitHubApp(repoFullName, options = {}) {
1213
1121
  const [repoOwner, repoName] = repoFullName.split("/");
1214
1122
  const envToken = process.env.KEYWAY_TOKEN;
1215
1123
  if (envToken) {
1216
- return ensureGitHubAppInstalledOnly(repoFullName, envToken);
1124
+ const result = await ensureGitHubAppInstalledOnly(repoFullName, envToken);
1125
+ if (result === null) {
1126
+ throw new Error("KEYWAY_TOKEN is invalid or expired. Please update the token.");
1127
+ }
1128
+ return result;
1217
1129
  }
1218
1130
  const stored = await getStoredAuth();
1219
1131
  if (stored?.keywayToken) {
1220
- return ensureGitHubAppInstalledOnly(repoFullName, stored.keywayToken);
1132
+ const result = await ensureGitHubAppInstalledOnly(repoFullName, stored.keywayToken);
1133
+ if (result !== null) {
1134
+ return result;
1135
+ }
1221
1136
  }
1222
1137
  const allowPrompt = options.allowPrompt !== false;
1223
1138
  if (!allowPrompt || !isInteractive2()) {
@@ -1285,7 +1200,18 @@ async function ensureLoginAndGitHubApp(repoFullName, options = {}) {
1285
1200
  }
1286
1201
  async function ensureGitHubAppInstalledOnly(repoFullName, accessToken) {
1287
1202
  const [repoOwner, repoName] = repoFullName.split("/");
1288
- const status = await checkGitHubAppInstallation(repoOwner, repoName, accessToken);
1203
+ let status;
1204
+ try {
1205
+ status = await checkGitHubAppInstallation(repoOwner, repoName, accessToken);
1206
+ } catch (error) {
1207
+ if (error instanceof APIError && error.statusCode === 401) {
1208
+ console.log(pc4.yellow("\n\u26A0 Session expired or invalid. Clearing credentials..."));
1209
+ const { clearAuth: clearAuth2 } = await import("./auth-QLPQ24HZ.js");
1210
+ clearAuth2();
1211
+ return null;
1212
+ }
1213
+ throw error;
1214
+ }
1289
1215
  if (status.installed) {
1290
1216
  return accessToken;
1291
1217
  }
@@ -1500,9 +1426,9 @@ import pc6 from "picocolors";
1500
1426
 
1501
1427
  // src/core/doctor.ts
1502
1428
  import { execSync as execSync2 } from "child_process";
1503
- import { writeFileSync as writeFileSync2, unlinkSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
1429
+ import { writeFileSync, unlinkSync, readFileSync, existsSync } from "fs";
1504
1430
  import { tmpdir } from "os";
1505
- import { join as join2 } from "path";
1431
+ import { join } from "path";
1506
1432
  var API_HEALTH_URL = `${process.env.KEYWAY_API_URL || INTERNAL_API_URL}/v1/health`;
1507
1433
  async function checkNode() {
1508
1434
  const nodeVersion = process.versions.node;
@@ -1619,9 +1545,9 @@ async function checkNetwork() {
1619
1545
  }
1620
1546
  }
1621
1547
  async function checkFileSystem() {
1622
- const testFile = join2(tmpdir(), `.keyway-test-${Date.now()}.tmp`);
1548
+ const testFile = join(tmpdir(), `.keyway-test-${Date.now()}.tmp`);
1623
1549
  try {
1624
- writeFileSync2(testFile, "test");
1550
+ writeFileSync(testFile, "test");
1625
1551
  unlinkSync(testFile);
1626
1552
  return {
1627
1553
  id: "filesystem",
@@ -1640,7 +1566,7 @@ async function checkFileSystem() {
1640
1566
  }
1641
1567
  async function checkGitignore() {
1642
1568
  try {
1643
- if (!existsSync2(".gitignore")) {
1569
+ if (!existsSync(".gitignore")) {
1644
1570
  return {
1645
1571
  id: "gitignore",
1646
1572
  name: ".gitignore configuration",
@@ -1648,7 +1574,7 @@ async function checkGitignore() {
1648
1574
  detail: "No .gitignore file found"
1649
1575
  };
1650
1576
  }
1651
- const gitignoreContent = readFileSync2(".gitignore", "utf-8");
1577
+ const gitignoreContent = readFileSync(".gitignore", "utf-8");
1652
1578
  const hasEnvPattern = gitignoreContent.includes("*.env") || gitignoreContent.includes(".env*");
1653
1579
  const hasDotEnv = gitignoreContent.includes(".env");
1654
1580
  if (hasEnvPattern || hasDotEnv) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keywaysh/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "One link to all your secrets",
5
5
  "type": "module",
6
6
  "bin": {