@keywaysh/cli 0.2.0 → 0.3.2
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 +18 -207
- package/bin/keyway +25 -0
- package/package.json +19 -55
- package/scripts/install.js +216 -0
- package/scripts/postinstall.js +157 -0
- package/dist/auth-64V3RWUK.js +0 -12
- package/dist/chunk-IVZM2JTT.js +0 -101
- package/dist/cli.js +0 -3047
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { execSync } = require("child_process");
|
|
7
|
+
const zlib = require("zlib");
|
|
8
|
+
|
|
9
|
+
const REPO = "keywaysh/cli";
|
|
10
|
+
const BIN_DIR = path.join(__dirname, "..", "bin");
|
|
11
|
+
const BINARY_NAME = process.platform === "win32" ? "keyway.exe" : "keyway";
|
|
12
|
+
|
|
13
|
+
// Platform mapping
|
|
14
|
+
const PLATFORM_MAP = {
|
|
15
|
+
darwin: "darwin",
|
|
16
|
+
linux: "linux",
|
|
17
|
+
win32: "windows",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Architecture mapping
|
|
21
|
+
const ARCH_MAP = {
|
|
22
|
+
x64: "amd64",
|
|
23
|
+
arm64: "arm64",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function getPlatform() {
|
|
27
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
28
|
+
if (!platform) {
|
|
29
|
+
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
30
|
+
}
|
|
31
|
+
return platform;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function getArch() {
|
|
35
|
+
const arch = ARCH_MAP[process.arch];
|
|
36
|
+
if (!arch) {
|
|
37
|
+
throw new Error(`Unsupported architecture: ${process.arch}`);
|
|
38
|
+
}
|
|
39
|
+
return arch;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getVersion() {
|
|
43
|
+
const pkg = require("../package.json");
|
|
44
|
+
return pkg.version;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function httpsGet(url) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
https
|
|
50
|
+
.get(url, { headers: { "User-Agent": "keyway-npm-installer" } }, (res) => {
|
|
51
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
52
|
+
return httpsGet(res.headers.location).then(resolve).catch(reject);
|
|
53
|
+
}
|
|
54
|
+
if (res.statusCode !== 200) {
|
|
55
|
+
reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const chunks = [];
|
|
59
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
60
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
61
|
+
res.on("error", reject);
|
|
62
|
+
})
|
|
63
|
+
.on("error", reject);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function downloadAndExtract(url, destPath) {
|
|
68
|
+
console.log(`Downloading ${url}`);
|
|
69
|
+
const data = await httpsGet(url);
|
|
70
|
+
|
|
71
|
+
// Create bin directory if it doesn't exist
|
|
72
|
+
if (!fs.existsSync(BIN_DIR)) {
|
|
73
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (url.endsWith(".tar.gz")) {
|
|
77
|
+
// Extract tar.gz
|
|
78
|
+
const tmpDir = path.join(__dirname, "..", "tmp");
|
|
79
|
+
if (!fs.existsSync(tmpDir)) {
|
|
80
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const tarPath = path.join(tmpDir, "keyway.tar.gz");
|
|
84
|
+
fs.writeFileSync(tarPath, data);
|
|
85
|
+
|
|
86
|
+
// Use tar command to extract
|
|
87
|
+
execSync(`tar -xzf "${tarPath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
88
|
+
|
|
89
|
+
// Find and move binary
|
|
90
|
+
const extractedBinary = path.join(tmpDir, "keyway");
|
|
91
|
+
if (fs.existsSync(extractedBinary)) {
|
|
92
|
+
fs.copyFileSync(extractedBinary, destPath);
|
|
93
|
+
fs.chmodSync(destPath, 0o755);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Cleanup
|
|
97
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
98
|
+
} else if (url.endsWith(".zip")) {
|
|
99
|
+
// For Windows, use PowerShell to extract
|
|
100
|
+
const tmpDir = path.join(__dirname, "..", "tmp");
|
|
101
|
+
if (!fs.existsSync(tmpDir)) {
|
|
102
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const zipPath = path.join(tmpDir, "keyway.zip");
|
|
106
|
+
fs.writeFileSync(zipPath, data);
|
|
107
|
+
|
|
108
|
+
execSync(
|
|
109
|
+
`powershell -command "Expand-Archive -Path '${zipPath}' -DestinationPath '${tmpDir}' -Force"`,
|
|
110
|
+
{ stdio: "pipe" }
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const extractedBinary = path.join(tmpDir, "keyway.exe");
|
|
114
|
+
if (fs.existsSync(extractedBinary)) {
|
|
115
|
+
fs.copyFileSync(extractedBinary, destPath);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Cleanup
|
|
119
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function main() {
|
|
124
|
+
try {
|
|
125
|
+
const platform = getPlatform();
|
|
126
|
+
const arch = getArch();
|
|
127
|
+
const version = getVersion();
|
|
128
|
+
|
|
129
|
+
// Skip download for version 0.0.0 (development)
|
|
130
|
+
if (version === "0.0.0") {
|
|
131
|
+
console.log("Development version detected, skipping binary download");
|
|
132
|
+
// Create a placeholder script
|
|
133
|
+
const placeholder = `#!/bin/sh
|
|
134
|
+
echo "Keyway CLI not installed. Run 'make build' in the cli-go directory."
|
|
135
|
+
exit 1
|
|
136
|
+
`;
|
|
137
|
+
fs.writeFileSync(path.join(BIN_DIR, "keyway"), placeholder);
|
|
138
|
+
fs.chmodSync(path.join(BIN_DIR, "keyway"), 0o755);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const ext = platform === "windows" ? "zip" : "tar.gz";
|
|
143
|
+
const filename = `keyway_${version}_${platform}_${arch}.${ext}`;
|
|
144
|
+
const url = `https://github.com/${REPO}/releases/download/v${version}/${filename}`;
|
|
145
|
+
|
|
146
|
+
const destPath = path.join(BIN_DIR, BINARY_NAME);
|
|
147
|
+
await downloadAndExtract(url, destPath);
|
|
148
|
+
|
|
149
|
+
console.log(`Keyway CLI v${version} installed successfully!`);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error("Failed to install Keyway CLI:", error.message);
|
|
152
|
+
console.error("You can install manually from: https://github.com/keywaysh/cli/releases");
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
main();
|
package/dist/auth-64V3RWUK.js
DELETED
package/dist/chunk-IVZM2JTT.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
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
|
-
clearAuth();
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
async function saveAuthToken(token, meta) {
|
|
80
|
-
const auth = {
|
|
81
|
-
keywayToken: token,
|
|
82
|
-
githubLogin: meta?.githubLogin,
|
|
83
|
-
expiresAt: meta?.expiresAt,
|
|
84
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
85
|
-
};
|
|
86
|
-
const encrypted = encryptToken(JSON.stringify(auth));
|
|
87
|
-
store.set("auth", encrypted);
|
|
88
|
-
}
|
|
89
|
-
function clearAuth() {
|
|
90
|
-
store.delete("auth");
|
|
91
|
-
}
|
|
92
|
-
function getAuthFilePath() {
|
|
93
|
-
return store.path;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export {
|
|
97
|
-
getStoredAuth,
|
|
98
|
-
saveAuthToken,
|
|
99
|
-
clearAuth,
|
|
100
|
-
getAuthFilePath
|
|
101
|
-
};
|