@askalf/dario
Advanced tools
| /** Verified per-release seeds, keyed on `major.minor.patch`. */ | ||
| export declare const CCH_SEEDS: Record<string, bigint>; | ||
| /** Canonical xxHash64 of `data` with a 64-bit `seed`. */ | ||
| export declare function xxh64(data: Uint8Array, seed: bigint): bigint; | ||
| /** | ||
| * Deterministic 5-hex cch for a serialized body under an EXPLICIT seed, or | ||
| * null if the body carries no `cch=XXXXX` token. Used by `scripts/cch- | ||
| * calibrate.mjs` to test candidate seeds against a live capture without going | ||
| * through the version table. | ||
| */ | ||
| export declare function cchWithSeed(bodyText: string, seed: bigint): string | null; | ||
| /** | ||
| * Deterministic 5-hex `cch` for a serialized request body, or null when: | ||
| * - `version` (major.minor.patch) has no known seed, or | ||
| * - the body carries no `cch=XXXXX` billing token to stamp. | ||
| * A null return means the caller should keep its random placeholder. | ||
| */ | ||
| export declare function cchForBody(bodyText: string, version: string): string | null; |
+139
| // Deterministic Claude Code request-integrity hash (`cch`) — dario#528. | ||
| // | ||
| // Claude Code stamps each /v1/messages request with a 5-hex `cch` token inside | ||
| // the `x-anthropic-billing-header` system block. It is NOT random: it is an | ||
| // xxHash64 over a canonical PROJECTION of the request body, masked to 20 bits. | ||
| // Reverse-engineered by lwsh123k (dario#528) and verified here against live | ||
| // captures on Claude Code 2.1.177: | ||
| // | ||
| // material = the serialized body, transformed by: | ||
| // 1. reset the `cch=XXXXX` token to `cch=00000` | ||
| // 2. blank the "model" VALUE (keep the key) | ||
| // 3. delete "fallbacks", "fallback_credit_token", "max_tokens" | ||
| // 4. re-serialize as compact JSON (JSON.stringify) | ||
| // cch = ( xxHash64(material, SEED[version]) & 0xFFFFF ) as zero-padded 5-hex | ||
| // | ||
| // The excluded fields are exactly the ones a routing proxy rewrites (model, | ||
| // fallbacks, max_tokens), so the value is STABLE across dario's rewrites — the | ||
| // upstream re-derives the same projection from whatever we send and recomputes | ||
| // the identical hash. dario therefore only has to hash its own final body. | ||
| // | ||
| // The seed rotates per Claude Code release and is keyed on major.minor.patch | ||
| // (the build-tag suffix, e.g. ".e2d" vs ".dd9", does NOT change it — verified | ||
| // against two captures with different suffixes, same 2.1.177 seed). An unknown | ||
| // version returns null so the caller falls back to a random value (the | ||
| // pre-dario#528 behavior) rather than emitting a confident-but-wrong hash that | ||
| // a validating server could single out. | ||
| /** Verified per-release seeds, keyed on `major.minor.patch`. */ | ||
| export const CCH_SEEDS = { | ||
| '2.1.177': 0x4d659218e32a3268n, | ||
| }; | ||
| const MASK = 0xfffffn; | ||
| const U64 = (1n << 64n) - 1n; | ||
| // xxHash64 primes. | ||
| const P1 = 0x9e3779b185ebca87n; | ||
| const P2 = 0xc2b2ae3d27d4eb4fn; | ||
| const P3 = 0x165667b19e3779f9n; | ||
| const P4 = 0x85ebca77c2b2ae63n; | ||
| const P5 = 0x27d4eb2f165667c5n; | ||
| const rotl = (x, r) => ((x << r) | (x >> (64n - r))) & U64; | ||
| function round(acc, input) { | ||
| acc = (acc + input * P2) & U64; | ||
| acc = rotl(acc, 31n); | ||
| return (acc * P1) & U64; | ||
| } | ||
| function mergeRound(acc, val) { | ||
| const r = round(0n, val); | ||
| acc = (acc ^ r) & U64; | ||
| return (acc * P1 + P4) & U64; | ||
| } | ||
| /** Canonical xxHash64 of `data` with a 64-bit `seed`. */ | ||
| export function xxh64(data, seed) { | ||
| const len = data.length; | ||
| const dv = new DataView(data.buffer, data.byteOffset, data.byteLength); | ||
| let h; | ||
| let i = 0; | ||
| if (len >= 32) { | ||
| let v1 = (seed + P1 + P2) & U64; | ||
| let v2 = (seed + P2) & U64; | ||
| let v3 = seed & U64; | ||
| let v4 = (seed - P1) & U64; | ||
| const limit = len - 32; | ||
| while (i <= limit) { | ||
| v1 = round(v1, dv.getBigUint64(i, true)); | ||
| i += 8; | ||
| v2 = round(v2, dv.getBigUint64(i, true)); | ||
| i += 8; | ||
| v3 = round(v3, dv.getBigUint64(i, true)); | ||
| i += 8; | ||
| v4 = round(v4, dv.getBigUint64(i, true)); | ||
| i += 8; | ||
| } | ||
| h = (rotl(v1, 1n) + rotl(v2, 7n) + rotl(v3, 12n) + rotl(v4, 18n)) & U64; | ||
| h = mergeRound(h, v1); | ||
| h = mergeRound(h, v2); | ||
| h = mergeRound(h, v3); | ||
| h = mergeRound(h, v4); | ||
| } | ||
| else { | ||
| h = (seed + P5) & U64; | ||
| } | ||
| h = (h + BigInt(len)) & U64; | ||
| while (i + 8 <= len) { | ||
| const k1 = round(0n, dv.getBigUint64(i, true)); | ||
| h = (h ^ k1) & U64; | ||
| h = (rotl(h, 27n) * P1 + P4) & U64; | ||
| i += 8; | ||
| } | ||
| if (i + 4 <= len) { | ||
| h = (h ^ ((BigInt(dv.getUint32(i, true)) * P1) & U64)) & U64; | ||
| h = (rotl(h, 23n) * P2 + P3) & U64; | ||
| i += 4; | ||
| } | ||
| while (i < len) { | ||
| h = (h ^ ((BigInt(data[i]) * P5) & U64)) & U64; | ||
| h = (rotl(h, 11n) * P1) & U64; | ||
| i += 1; | ||
| } | ||
| h = (h ^ (h >> 33n)) & U64; | ||
| h = (h * P2) & U64; | ||
| h = (h ^ (h >> 29n)) & U64; | ||
| h = (h * P3) & U64; | ||
| h = (h ^ (h >> 32n)) & U64; | ||
| return h; | ||
| } | ||
| const CCH_RE = /cch=[0-9a-fA-F]{5}/; | ||
| /** Build the canonical cch pre-image bytes from a serialized request body. */ | ||
| function cchMaterial(bodyText) { | ||
| const zeroed = bodyText.replace(CCH_RE, 'cch=00000'); // first occurrence only | ||
| const body = JSON.parse(zeroed); | ||
| body.model = ''; | ||
| delete body.fallbacks; | ||
| delete body.fallback_credit_token; | ||
| delete body.max_tokens; | ||
| return new TextEncoder().encode(JSON.stringify(body)); | ||
| } | ||
| /** | ||
| * Deterministic 5-hex cch for a serialized body under an EXPLICIT seed, or | ||
| * null if the body carries no `cch=XXXXX` token. Used by `scripts/cch- | ||
| * calibrate.mjs` to test candidate seeds against a live capture without going | ||
| * through the version table. | ||
| */ | ||
| export function cchWithSeed(bodyText, seed) { | ||
| if (!CCH_RE.test(bodyText)) | ||
| return null; | ||
| const h = xxh64(cchMaterial(bodyText), seed) & MASK; | ||
| return h.toString(16).padStart(5, '0'); | ||
| } | ||
| /** | ||
| * Deterministic 5-hex `cch` for a serialized request body, or null when: | ||
| * - `version` (major.minor.patch) has no known seed, or | ||
| * - the body carries no `cch=XXXXX` billing token to stamp. | ||
| * A null return means the caller should keep its random placeholder. | ||
| */ | ||
| export function cchForBody(bodyText, version) { | ||
| const seed = CCH_SEEDS[version]; | ||
| if (seed === undefined) | ||
| return null; | ||
| return cchWithSeed(bodyText, seed); | ||
| } |
@@ -285,3 +285,3 @@ /** | ||
| readonly min: "1.0.0"; | ||
| readonly maxTested: "2.1.177"; | ||
| readonly maxTested: "2.1.178"; | ||
| }; | ||
@@ -288,0 +288,0 @@ /** |
@@ -789,3 +789,3 @@ /** | ||
| min: '1.0.0', | ||
| maxTested: '2.1.177', | ||
| maxTested: '2.1.178', | ||
| }; | ||
@@ -792,0 +792,0 @@ /** |
+2
-1
| { | ||
| "name": "@askalf/dario", | ||
| "version": "4.8.76", | ||
| "version": "4.8.77", | ||
| "description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.", | ||
@@ -35,2 +35,3 @@ "type": "module", | ||
| "drift:sdk": "node scripts/check-sdk-drift.mjs", | ||
| "cch:calibrate": "node scripts/cch-calibrate.mjs", | ||
| "fix:pkg": "node -e \"const fs=require('fs');fs.writeFileSync('package.json',JSON.stringify(JSON.parse(fs.readFileSync('package.json','utf-8')),null,2)+'\\n')\"" | ||
@@ -37,0 +38,0 @@ }, |
Sorry, the diff of this file is too big to display
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1241827
0.59%99
2.06%24397
0.7%99
1.02%