@dk/hipp 0.1.19 â 0.1.20
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 +23 -16
- package/hipp.js +21 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,32 +109,36 @@ The manifest contains:
|
|
|
109
109
|
{
|
|
110
110
|
"origin": "git@github.com:dk/your-package.git",
|
|
111
111
|
"tag": "v1.0.0",
|
|
112
|
+
"revision": "<git-commit-hash>",
|
|
112
113
|
"hash": "<sha256-of-tarball>",
|
|
113
114
|
"signature": "<base64-ed25519-signature>",
|
|
114
115
|
"name": "Jane Developer",
|
|
115
|
-
"email": "jane@example.com"
|
|
116
|
+
"email": "jane@example.com",
|
|
117
|
+
"npm": "10.2.4",
|
|
118
|
+
"node": "v20.11.0"
|
|
116
119
|
}
|
|
117
120
|
```
|
|
118
121
|
|
|
119
122
|
**Step 2: Clone git and verify**
|
|
120
123
|
|
|
121
124
|
3. Clone the repository at the tagged commit (using origin/tag from manifest)
|
|
122
|
-
4.
|
|
123
|
-
5.
|
|
124
|
-
6.
|
|
125
|
-
7.
|
|
125
|
+
4. Verify the cloned commit hash matches the `revision` field in manifest
|
|
126
|
+
5. Stage all tracked files
|
|
127
|
+
6. Run `npm pack` to create a tarball
|
|
128
|
+
7. Compute SHA256 hash of the clean tarball
|
|
129
|
+
8. Compare with the `hash` field from the npm manifest
|
|
126
130
|
|
|
127
131
|
**Step 3: Verify signature**
|
|
128
132
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
9. Read `hipp.pub` from the cloned repository
|
|
134
|
+
10. Verify the signature was created by signing:
|
|
135
|
+
`hash + "\n" + origin + "\n" + tag + "\n" + revision + "\n" + name + "\n" + email`
|
|
132
136
|
|
|
133
137
|
**Step 4: Rebuild verification**
|
|
134
138
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
11. Append the manifest to the staged README
|
|
140
|
+
12. Update the staged `package.json` version to match the tag
|
|
141
|
+
13. Run `npm pack` again and verify the hash matches the npm tarball
|
|
138
142
|
|
|
139
143
|
### Three Verification Checks
|
|
140
144
|
|
|
@@ -216,16 +220,19 @@ PERFORMANCE OF THIS SOFTWARE.
|
|
|
216
220
|
Verify this package with [@dk/hipp](https://www.npmjs.com/package/@dk/hipp):
|
|
217
221
|
|
|
218
222
|
```bash
|
|
219
|
-
npx @dk/hipp verify @dk/hipp@0.1.
|
|
223
|
+
npx @dk/hipp verify @dk/hipp@0.1.20
|
|
220
224
|
```
|
|
221
225
|
|
|
222
226
|
```json
|
|
223
227
|
{
|
|
224
228
|
"origin": "git@github.com:dmytri/hipp.git",
|
|
225
|
-
"tag": "v0.1.
|
|
226
|
-
"
|
|
227
|
-
"
|
|
229
|
+
"tag": "v0.1.20",
|
|
230
|
+
"revision": "1d5a16d3e837ffd79d4c6704cf1945f6d0b84a60",
|
|
231
|
+
"hash": "71fe169e31a68c92c249ae2a443a4062dc379b36bf854a290576e7b595ca4e58",
|
|
232
|
+
"signature": "UpVrjogkhwUyPvGj6bK4vOUj3p9R/JDvuDaupOibXFyK5FibLWzpMwjQWHJa78wYx4D4f/BmAn99J3Xt4icaDg==",
|
|
228
233
|
"name": "Dmytri Kleiner",
|
|
229
|
-
"email": "dev@dmytri.to"
|
|
234
|
+
"email": "dev@dmytri.to",
|
|
235
|
+
"npm": "11.12.1",
|
|
236
|
+
"node": "v25.8.2"
|
|
230
237
|
}
|
|
231
238
|
```
|
package/hipp.js
CHANGED
|
@@ -121,8 +121,8 @@ function verifySignature(data, signature, publicKey) {
|
|
|
121
121
|
}, Buffer.from(signature, 'base64'));
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
function buildSignData(hash, origin, tag, name, email) {
|
|
125
|
-
return `${hash}\n${origin}\n${tag}\n${name}\n${email}\n`;
|
|
124
|
+
function buildSignData(hash, origin, tag, revision, name, email) {
|
|
125
|
+
return `${hash}\n${origin}\n${tag}\n${revision}\n${name}\n${email}\n`;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
function findLastJsonBlock(readmeContent) {
|
|
@@ -463,11 +463,11 @@ async function runVerify(packageSpec) {
|
|
|
463
463
|
|
|
464
464
|
const npmReadme = fs.readFileSync(npmReadmePath, 'utf8');
|
|
465
465
|
manifest = findLastJsonBlock(npmReadme);
|
|
466
|
-
if (!manifest || !manifest.origin || !manifest.tag || !manifest.hash || !manifest.signature || !manifest.name || !manifest.email) {
|
|
466
|
+
if (!manifest || !manifest.origin || !manifest.tag || !manifest.revision || !manifest.hash || !manifest.signature || !manifest.name || !manifest.email) {
|
|
467
467
|
fail(`â Manifest not found or invalid in README`);
|
|
468
468
|
}
|
|
469
469
|
|
|
470
|
-
const { origin: originUrl, tag, signature, name, email } = manifest;
|
|
470
|
+
const { origin: originUrl, tag, revision, signature, name, email, npm: npmVer, node: nodeVer } = manifest;
|
|
471
471
|
|
|
472
472
|
log.info(`đŋ Cloning git origin at tag ${tag}...`);
|
|
473
473
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-git-`));
|
|
@@ -476,6 +476,12 @@ async function runVerify(packageSpec) {
|
|
|
476
476
|
try {
|
|
477
477
|
git(['clone', '--branch', tag, '--depth', '1', originUrl, tmpDir], { stdio: 'pipe' });
|
|
478
478
|
|
|
479
|
+
const clonedRevision = git(['rev-parse', 'HEAD'], { cwd: tmpDir });
|
|
480
|
+
if (clonedRevision !== revision) {
|
|
481
|
+
fail(`â Revision mismatch: manifest claims ${revision.slice(0, 12)} but tag points to ${clonedRevision.slice(0, 12)}`);
|
|
482
|
+
}
|
|
483
|
+
log.success(`đˇī¸ Revision verified: ${revision.slice(0, 12)}...`);
|
|
484
|
+
|
|
479
485
|
const publicKeyPath = path.join(tmpDir, 'hipp.pub');
|
|
480
486
|
if (!fs.existsSync(publicKeyPath)) {
|
|
481
487
|
fail(`â hipp.pub not found in git at tag ${tag}`);
|
|
@@ -498,7 +504,7 @@ async function runVerify(packageSpec) {
|
|
|
498
504
|
log.success(`đ Manifest hash verified`);
|
|
499
505
|
|
|
500
506
|
log.info(`đ Check 1: Verifying signature...`);
|
|
501
|
-
const signData = buildSignData(manifest.hash, originUrl, tag, name, email);
|
|
507
|
+
const signData = buildSignData(manifest.hash, originUrl, tag, revision, name, email);
|
|
502
508
|
const signatureValid = verifySignature(signData, signature, publicKey);
|
|
503
509
|
if (!signatureValid) {
|
|
504
510
|
fail(`â Signature verification failed`);
|
|
@@ -540,6 +546,9 @@ async function runVerify(packageSpec) {
|
|
|
540
546
|
log.info(`đ Publisher: ${name} <${email}>`);
|
|
541
547
|
log.info(`đ Origin: ${originUrl}`);
|
|
542
548
|
log.info(`đ Tag: ${tag}`);
|
|
549
|
+
if (npmVer && nodeVer) {
|
|
550
|
+
log.info(`âšī¸ npm: ${npmVer} | node: ${nodeVer}`);
|
|
551
|
+
}
|
|
543
552
|
} finally {
|
|
544
553
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
545
554
|
fs.rmSync(stageDir, { recursive: true, force: true });
|
|
@@ -638,16 +647,22 @@ async function run() {
|
|
|
638
647
|
}
|
|
639
648
|
|
|
640
649
|
const { name, email } = getGitUserInfo();
|
|
641
|
-
const
|
|
650
|
+
const revision = refInfo.head;
|
|
651
|
+
const npmVersion = runCmd('npm', ['--version']).stdout.trim();
|
|
652
|
+
const nodeVersion = process.version;
|
|
653
|
+
const dataToSign = buildSignData(tarballHash, provenance.remoteUrl, rawTag, revision, name, email);
|
|
642
654
|
const signature = signContent(dataToSign, privateKey);
|
|
643
655
|
|
|
644
656
|
const manifestJson = {
|
|
645
657
|
origin: provenance.remoteUrl,
|
|
646
658
|
tag: rawTag,
|
|
659
|
+
revision: revision,
|
|
647
660
|
hash: tarballHash,
|
|
648
661
|
signature: signature,
|
|
649
662
|
name: name,
|
|
650
663
|
email: email,
|
|
664
|
+
npm: npmVersion,
|
|
665
|
+
node: nodeVersion,
|
|
651
666
|
};
|
|
652
667
|
|
|
653
668
|
stagedReadme = stagedReadme.trimEnd() + '\n\n## Verify\n\n' +
|