@aryaminus/controlkeel 0.3.8 → 0.3.10
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/SECURITY.md +2 -2
- package/lib/install.js +72 -2
- package/package.json +1 -1
- package/server.json +2 -2
package/SECURITY.md
CHANGED
|
@@ -24,7 +24,7 @@ The `postinstall` script (`lib/postinstall.js`) performs the following actions:
|
|
|
24
24
|
### Security considerations
|
|
25
25
|
|
|
26
26
|
- **Source**: Binaries are downloaded exclusively from official GitHub Releases
|
|
27
|
-
- **
|
|
27
|
+
- **Checksum verification**: After download, the installer fetches `SHASUMS256.txt` from the same release and verifies the SHA-256 digest of the downloaded binary before installing it. A mismatch causes the install to fail and the partial download is removed.
|
|
28
28
|
- **Transparency**: The source code for the bootstrap installer is fully visible in this repository
|
|
29
29
|
- **Opt-out**: Users can skip automatic download by setting `CONTROLKEEL_SKIP_DOWNLOAD=1`
|
|
30
30
|
- **No external dependencies**: The bootstrap installer has no runtime dependencies beyond Node.js built-ins
|
|
@@ -60,4 +60,4 @@ This package is designed with supply chain security in mind:
|
|
|
60
60
|
- **Signed releases**: GitHub Releases provide cryptographic verification
|
|
61
61
|
- **Transparent source**: All installer code is open and auditable
|
|
62
62
|
|
|
63
|
-
For detailed information about the native binary build process and security practices, see the main repository's [security documentation](https://github.com/aryaminus/controlkeel/blob/main/SECURITY.md).
|
|
63
|
+
For detailed information about the native binary build process and security practices, see the main repository's [security documentation](https://github.com/aryaminus/controlkeel/blob/main/SECURITY.md).
|
package/lib/install.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const crypto = require("node:crypto");
|
|
3
4
|
const fs = require("node:fs");
|
|
4
5
|
const os = require("node:os");
|
|
5
6
|
const path = require("node:path");
|
|
@@ -85,6 +86,72 @@ function download(url, destination) {
|
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
function downloadText(url) {
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
const request = https.get(url, (response) => {
|
|
92
|
+
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
93
|
+
response.resume();
|
|
94
|
+
downloadText(response.headers.location).then(resolve, reject);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (response.statusCode !== 200) {
|
|
99
|
+
reject(new Error(`Failed to download ${url} (HTTP ${response.statusCode})`));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let data = "";
|
|
104
|
+
response.on("data", (chunk) => { data += chunk; });
|
|
105
|
+
response.on("end", () => resolve(data));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
request.on("error", reject);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function sha256File(filePath) {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
const hash = crypto.createHash("sha256");
|
|
115
|
+
const stream = fs.createReadStream(filePath);
|
|
116
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
117
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
118
|
+
stream.on("error", reject);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function verifyChecksum(filePath, asset) {
|
|
123
|
+
const checksumUrl = `${releaseBaseUrl()}/SHASUMS256.txt`;
|
|
124
|
+
|
|
125
|
+
let checksumText;
|
|
126
|
+
try {
|
|
127
|
+
checksumText = await downloadText(checksumUrl);
|
|
128
|
+
} catch {
|
|
129
|
+
// Checksum file not available for this release — skip verification but warn.
|
|
130
|
+
console.warn(`[controlkeel] Warning: could not download checksum file from ${checksumUrl}. Skipping integrity check.`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const expectedHash = checksumText
|
|
135
|
+
.split("\n")
|
|
136
|
+
.map((line) => line.trim().split(/\s+/))
|
|
137
|
+
.find(([, name]) => name === asset || name === `./${asset}`)?.[0];
|
|
138
|
+
|
|
139
|
+
if (!expectedHash) {
|
|
140
|
+
console.warn(`[controlkeel] Warning: no checksum entry found for ${asset}. Skipping integrity check.`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const actualHash = await sha256File(filePath);
|
|
145
|
+
|
|
146
|
+
if (actualHash !== expectedHash) {
|
|
147
|
+
fs.rmSync(filePath, { force: true });
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Checksum mismatch for ${asset}.\n Expected: ${expectedHash}\n Got: ${actualHash}\n` +
|
|
150
|
+
`The downloaded binary has been removed. Retry the installation or set CONTROLKEEL_SKIP_DOWNLOAD=1 and install manually.`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
88
155
|
async function ensureBinary({ forceDownload = false } = {}) {
|
|
89
156
|
const destination = binaryPath();
|
|
90
157
|
|
|
@@ -93,10 +160,13 @@ async function ensureBinary({ forceDownload = false } = {}) {
|
|
|
93
160
|
}
|
|
94
161
|
|
|
95
162
|
ensureVendorDir();
|
|
96
|
-
const
|
|
97
|
-
const
|
|
163
|
+
const asset = assetName();
|
|
164
|
+
const tempPath = path.join(os.tmpdir(), `${asset}-${Date.now()}`);
|
|
165
|
+
const url = `${releaseBaseUrl()}/${asset}`;
|
|
98
166
|
|
|
99
167
|
await download(url, tempPath);
|
|
168
|
+
await verifyChecksum(tempPath, asset);
|
|
169
|
+
|
|
100
170
|
fs.copyFileSync(tempPath, destination);
|
|
101
171
|
fs.rmSync(tempPath, { force: true });
|
|
102
172
|
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"url": "https://github.com/aryaminus/controlkeel.git",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.10",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@aryaminus/controlkeel",
|
|
15
|
-
"version": "0.3.
|
|
15
|
+
"version": "0.3.10",
|
|
16
16
|
"runtimeHint": "npx",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|