Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/commands/hook-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,20 +560,28 @@ export async function handleAuthenticateContext(args: string[]): Promise<void> {

if (chittyId) {
// @canon: chittycanon://gov/governance#core-types — contexts are Person (P), not Thing (T)
const entityTypeSegment = chittyId.split("-")[4];
if (entityTypeSegment && entityTypeSegment !== "P") {
console.log(` \x1b[33m⚠ Entity type mismatch: got '${entityTypeSegment}', expected 'P' (Person)\x1b[0m`);
// ChittyMint currently ignores entity_type param; correct it client-side until upstream fix
const segments = chittyId.split("-");
let correctedId = chittyId;
if (segments[4] && segments[4] !== "P") {
console.log(` \x1b[33m⚠ Entity type mismatch: got '${segments[4]}', expected 'P' (Person) — correcting\x1b[0m`);
segments[4] = "P";
// Recalculate checksum (mod-97 of all segments except last)
const baseSegments = segments.slice(0, -1);
const numericStr = baseSegments.join("").replace(/[A-Z]/g, (c) => String(c.charCodeAt(0) - 55));
const checksum = String(98n - (BigInt(numericStr) % 97n)).padStart(2, "0");
segments[segments.length - 1] = checksum;
Comment on lines +564 to +573
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Potential runtime failure in checksum recompute path.

At Line 571–572, BigInt(numericStr) can throw when the minted ID includes non-numeric chars (e.g., did:chitty: prefix/lowercase/:), because only [A-Z] is normalized. This can break context auth even after a successful mint.

Suggested hardening
-          const baseSegments = segments.slice(0, -1);
-          const numericStr = baseSegments.join("").replace(/[A-Z]/g, (c) => String(c.charCodeAt(0) - 55));
-          const checksum = String(98n - (BigInt(numericStr) % 97n)).padStart(2, "0");
+          const baseSegments = segments.slice(0, -1);
+          // Normalize DID prefix + separators before numeric conversion
+          const normalized = baseSegments
+            .join("")
+            .replace(/^did:chitty:/i, "")
+            .replace(/[^a-zA-Z0-9]/g, "")
+            .toUpperCase();
+          const numericStr = normalized.replace(/[A-Z]/g, (c) => String(c.charCodeAt(0) - 55));
+          const checksum = String(98n - (BigInt(numericStr) % 97n)).padStart(2, "0");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/hook-handlers.ts` around lines 564 - 573, The checksum recompute
can throw when numericStr contains unexpected chars; update the correction path
that manipulates chittyId/segments (the block using variables chittyId,
segments, numericStr, checksum) to: strip known prefixes like "did:chitty:" and
any colons, convert to upper case, then build numericStr by removing any
non-alphanumeric characters and mapping A–Z to 10–35 (use /[A-Z]/g and /[0-9]/),
e.g. replace letters with (charCodeAt-55) and keep digits as-is; validate
numericStr is non-empty and wrap the BigInt(...) conversion and mod-97 logic in
a try/catch to handle failures (log an error and skip correction or mark as
invalid) so the code never throws on malformed IDs.

correctedId = segments.join("-");
}

// Create context in database
context = await createContextInDb(chittyId, {
context = await createContextInDb(correctedId, {
projectPath,
workspace,
supportType,
organization,
anchorHash
});
console.log(` \x1b[32m✓ New context minted: ${chittyId}\x1b[0m`);
console.log(` \x1b[32m✓ New context minted: ${correctedId}\x1b[0m`);
} else {
// Fallback: create local-only binding
console.log(` \x1b[33m⚠ Session UNBOUND - ChittyConnect unreachable\x1b[0m`);
Expand Down Expand Up @@ -897,10 +905,10 @@ function createLocalContext(
workspace: string | null,
supportType: string,
organization: string | null,
chittyId: string = "UNBOUND"
mintedChittyId?: string
): ContextBinding {
return {
chittyId,
chittyId: mintedChittyId || "UNBOUND",
contextId: "",
anchorHash,
projectPath,
Expand Down
Loading