@dk/hipp 0.1.12 → 0.1.14

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.
Files changed (3) hide show
  1. package/README.md +3 -11
  2. package/hipp.js +33 -74
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -175,16 +175,8 @@ PERFORMANCE OF THIS SOFTWARE.
175
175
  ```json
176
176
  {
177
177
  "origin": "git@github.com:dmytri/hipp.git",
178
- "tag": "v0.1.12"
178
+ "tag": "v0.1.14",
179
+ "hash": "c2a32be7dbb481c7f9e9444b993616bb1e10d41cf9c0b787642873833ebcc77e",
180
+ "signature": "RsopqB7L4VWwi1jBmG1dG6L+Zo0ZV7m5k6jfA+KwafViXgWw6KQniJcCs8aqgujarAANd5AzyHBdlWCNoIFzBg=="
179
181
  }
180
182
  ```
181
-
182
- ```npx @dk/hipp @dk/hipp@0.1.12```
183
- <!-- HIPP-MANIFEST -->
184
- ```json
185
- {
186
- "hash": "9213a0bc269441f5dc3dc07fe07eba4d127815ae78f0d7e07474547bb342ce1b",
187
- "signature": "Bg5/in81S3ia4x4W2C1WzvXeZPxspCdXEcSHCyLT3aUaEF5JrSANcIerZXrgbAvDyrxsf9O2wDJ/0cZNI4KOAA=="
188
- }
189
- ```
190
- <!-- /HIPP-MANIFEST -->
package/hipp.js CHANGED
@@ -123,50 +123,12 @@ function buildSignData(hash, origin, tag) {
123
123
  return `${hash}\n${origin}\n${tag}\n`;
124
124
  }
125
125
 
126
- const MANIFEST_START = '<!-- HIPP-MANIFEST -->';
127
- const MANIFEST_END = '<!-- /HIPP-MANIFEST -->';
128
-
129
- function appendManifestToReadme(readmeContent, manifest) {
130
- return `${readmeContent}${MANIFEST_START}\n\`\`\`json\n${manifest}\n\`\`\`\n${MANIFEST_END}\n`;
131
- }
132
-
133
- function extractManifestFromReadme(readmeContent) {
134
- const startIdx = readmeContent.indexOf(MANIFEST_START);
135
- if (startIdx === -1) return null;
136
- const endIdx = readmeContent.indexOf(MANIFEST_END, startIdx);
137
- if (endIdx === -1) return null;
138
- const content = readmeContent.slice(startIdx + MANIFEST_START.length, endIdx).trim();
139
- const match = content.match(/^```json\n(.+)\n```$/s);
140
- if (!match) return null;
141
- return match[1];
142
- }
143
-
144
- function stripManifestFromReadme(readmeContent) {
145
- const startIdx = readmeContent.indexOf(MANIFEST_START);
146
- const endIdx = readmeContent.indexOf(MANIFEST_END, startIdx);
147
- if (startIdx === -1 || endIdx === -1) return readmeContent;
148
-
149
- const endLineIdx = readmeContent.indexOf('\n', endIdx);
150
- const endOfManifest = endLineIdx !== -1 ? endLineIdx + 1 : readmeContent.length;
151
-
152
- const beforeWithNewline = readmeContent.slice(0, startIdx);
153
- const lastNewlineBefore = beforeWithNewline.lastIndexOf('\n');
154
- const before = lastNewlineBefore !== -1 ? beforeWithNewline.slice(0, lastNewlineBefore) : beforeWithNewline;
155
-
156
- const after = readmeContent.slice(endOfManifest);
157
- return before + '\n' + after;
158
- }
159
-
160
- function computeReadmeHash(readmeContent) {
161
- const stripped = stripManifestFromReadme(readmeContent);
162
- return sha256(stripped);
163
- }
164
-
165
- function extractJsonMetaFromReadme(readmeContent) {
126
+ function findLastJsonBlock(readmeContent) {
166
127
  const lines = readmeContent.split('\n');
167
128
  let jsonStart = -1;
168
129
  let braceCount = 0;
169
130
  let inJson = false;
131
+ let lastValid = null;
170
132
 
171
133
  for (let i = 0; i < lines.length; i++) {
172
134
  const line = lines[i];
@@ -185,8 +147,8 @@ function extractJsonMetaFromReadme(readmeContent) {
185
147
  const jsonStr = lines.slice(jsonStart, i + 1).join('\n');
186
148
  try {
187
149
  const parsed = JSON.parse(jsonStr);
188
- if (parsed.origin && parsed.tag) {
189
- return parsed;
150
+ if (parsed.origin && parsed.tag && parsed.hash && parsed.signature) {
151
+ lastValid = parsed;
190
152
  }
191
153
  } catch {
192
154
  // continue searching
@@ -195,7 +157,15 @@ function extractJsonMetaFromReadme(readmeContent) {
195
157
  }
196
158
  }
197
159
  }
198
- return null;
160
+ return lastValid;
161
+ }
162
+
163
+ function computeReadmeHash(readmeContent) {
164
+ const jsonBlock = findLastJsonBlock(readmeContent);
165
+ if (!jsonBlock) return sha256(readmeContent);
166
+ const jsonStr = JSON.stringify(jsonBlock, null, 2);
167
+ const beforeJson = readmeContent.split('```json')[0];
168
+ return sha256(beforeJson + '```json\n' + jsonStr + '\n```\n');
199
169
  }
200
170
 
201
171
  function safeStageName(name) {
@@ -489,23 +459,12 @@ async function runVerify(packageSpec) {
489
459
  }
490
460
 
491
461
  const stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
492
- const jsonMeta = extractJsonMetaFromReadme(stagedReadme);
493
- if (!jsonMeta || !jsonMeta.origin || !jsonMeta.tag) {
494
- fail(`❌ JSON meta (origin/tag) not found in README`);
495
- }
496
-
497
- const manifestStr = extractManifestFromReadme(stagedReadme);
498
- if (!manifestStr) {
499
- fail(`❌ Manifest not found in README`);
462
+ const manifest = findLastJsonBlock(stagedReadme);
463
+ if (!manifest || !manifest.origin || !manifest.tag || !manifest.hash || !manifest.signature) {
464
+ fail(`❌ Manifest not found or invalid in README`);
500
465
  }
501
466
 
502
- const manifest = parseManifest(manifestStr);
503
- if (!manifest || !manifest.hash || !manifest.signature) {
504
- fail(`❌ Invalid manifest format`);
505
- }
506
-
507
- const originUrl = jsonMeta.origin;
508
- const tag = jsonMeta.tag;
467
+ const { origin: originUrl, tag, hash: npmHash, signature } = manifest;
509
468
 
510
469
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-git-`));
511
470
  const stageDir = fs.mkdtempSync(path.join(os.tmpdir(), `hipp-verify-stage-`));
@@ -530,21 +489,16 @@ async function runVerify(packageSpec) {
530
489
  fail(`❌ README.md not found in git at tag ${tag}`);
531
490
  }
532
491
 
533
- let stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
534
- const verifyBlock = '```npx @dk/hipp ' + pkgName + '@' + tag + '```';
535
- const jsonMetaStr = '```json\n{\n "origin": "' + originUrl + '",\n "tag": "' + tag + '"\n}\n```';
536
- stagedReadme = stagedReadme.trimEnd() + '\n\n' + jsonMetaStr + '\n\n' + verifyBlock + '\n';
537
-
538
- const stagedHash = computeReadmeHash(stagedReadme);
492
+ const stagedHash = sha256(fs.readFileSync(stagedReadmePath, 'utf8'));
539
493
 
540
- if (stagedHash !== manifest.hash) {
494
+ if (stagedHash !== npmHash) {
541
495
  fail(`❌ Hash mismatch: git content does not match npm manifest`);
542
496
  }
543
497
 
544
- log.success(`🔒 Content hash verified: ${manifest.hash.slice(0, 12)}...`);
498
+ log.success(`🔒 Content hash verified: ${npmHash.slice(0, 12)}...`);
545
499
 
546
- const signData = buildSignData(manifest.hash, originUrl, tag);
547
- const signatureValid = verifySignature(signData, manifest.signature, publicKey);
500
+ const signData = buildSignData(npmHash, originUrl, tag);
501
+ const signatureValid = verifySignature(signData, signature, publicKey);
548
502
 
549
503
  if (!signatureValid) {
550
504
  fail(`❌ Signature verification failed`);
@@ -652,15 +606,20 @@ async function run() {
652
606
  stagedReadme = fs.readFileSync(stagedReadmePath, 'utf8');
653
607
  }
654
608
 
655
- const verifyBlock = '```npx @dk/hipp ' + pkg.name + '@' + version + '```';
656
- const jsonMetaStr = '```json\n{\n "origin": "' + provenance.remoteUrl + '",\n "tag": "' + rawTag + '"\n}\n```';
657
- stagedReadme = stagedReadme.trimEnd() + '\n\n' + jsonMetaStr + '\n\n' + verifyBlock + '\n';
609
+ stagedReadme = stagedReadme.trimEnd() + '\n\n';
658
610
 
659
- const readmeHash = computeReadmeHash(stagedReadme);
611
+ const readmeHash = sha256(stagedReadme);
660
612
  const dataToSign = buildSignData(readmeHash, provenance.remoteUrl, rawTag);
661
613
  const signature = signContent(dataToSign, privateKey);
662
- const manifest = createManifest(readmeHash, signature);
663
- stagedReadme = appendManifestToReadme(stagedReadme, manifest);
614
+
615
+ const manifestJson = {
616
+ origin: provenance.remoteUrl,
617
+ tag: rawTag,
618
+ hash: readmeHash,
619
+ signature: signature,
620
+ };
621
+
622
+ stagedReadme += '```json\n' + JSON.stringify(manifestJson, null, 2) + '\n```\n';
664
623
 
665
624
  fs.writeFileSync(stagedReadmePath, stagedReadme);
666
625
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dk/hipp",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "High Integrity Package Publisher",
5
5
  "main": "hipp.js",
6
6
  "bin": {