Skip to content

Add tlsn identity assign and remove logics#664

Merged
tcsenpai merged 8 commits intotestnetfrom
add-tlsn-identity-assign-and-remove-logics
Feb 13, 2026
Merged

Add tlsn identity assign and remove logics#664
tcsenpai merged 8 commits intotestnetfrom
add-tlsn-identity-assign-and-remove-logics

Conversation

@HakobP-Solicy
Copy link
Contributor

@HakobP-Solicy HakobP-Solicy commented Feb 10, 2026

Summary by CodeRabbit

  • New Features

    • TLSNotary identity verification for Web2 (GitHub, Discord, Telegram): add/remove TLSNotary‑verified identities.
    • Identity contexts expanded to include nomis and tlsn.
    • Telegram points awarding extended to support TLSNotary‑verified Telegram links.
  • Documentation

    • Added end-to-end TLSNotary + OAuth flow guide covering verification, payloads, and post‑verification persistence/incentives.
  • Chores

    • Installer PATH and proxy startup adjusted for consistent wstcp binary resolution.

@qodo-code-review
Copy link
Contributor

Review Summary by Qodo

Add TLSNotary identity verification and management

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add TLSNotary identity verification for GitHub, Discord, Telegram
• Implement identity add/remove operations via TLSN proof verification
• Create server-side proof structure validation module with WASM support
• Integrate TLSN identity handling into GCR identity routines and request handlers
Diagram
flowchart LR
  A["TLSNotary Proof"] -->|verifyTLSNotaryPresentation| B["Proof Validation"]
  B -->|parseHttpResponse| C["Extract User Data"]
  C -->|extractUser| D["Verified Identity"]
  D -->|applyTLSNIdentityAdd| E["GCR Storage"]
  E -->|IncentiveManager| F["Award Incentives"]
  G["Remove Request"] -->|applyTLSNIdentityRemove| H["GCR Update"]
  H -->|IncentiveManager| I["Rollback Incentives"]
Loading

Grey Divider

File Changes

1. src/libs/tlsnotary/verifier.ts ✨ Enhancement +336/-0

TLSNotary proof verification and parsing module

• New TLSNotary proof verification module with structure validation
• Implements proof parsing, HTTP response extraction, and user data extraction
• Supports GitHub, Discord, and Telegram identity contexts
• Provides verifyTLSNotaryPresentation, parseHttpResponse, extractUser, and verifyTLSNProof
 functions
• Includes type definitions for TLSNotary presentations and verification results

src/libs/tlsnotary/verifier.ts


2. src/libs/tlsnotary/index.ts ✨ Enhancement +20/-0

TLSNotary module public API exports

• New barrel export file for TLSNotary verification module
• Exports all public functions and types from verifier module
• Provides clean API surface for identity routines and handlers

src/libs/tlsnotary/index.ts


3. src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts ✨ Enhancement +354/-5

TLSN identity add/remove operations and verification

• Import TLSNotary verification functions and types
• Add applyTLSNIdentityAdd method for adding TLSN-verified identities with proof validation
• Add applyTLSNIdentityRemove method for removing TLSN identities
• Define TLSN_EXPECTED_ENDPOINTS mapping for GitHub, Discord, Telegram servers
• Integrate TLSN operations into identity operation dispatcher with tlsnadd and tlsnremove cases
• Implement security checks comparing claimed vs extracted identity values
• Award/rollback incentives for GitHub, Discord, Telegram connections

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts


View more (2)
4. src/libs/network/routines/transactions/handleIdentityRequest.ts ✨ Enhancement +8/-3

TLSN identity request handling integration

• Add tlsn_identity_assign case to identity request handler
• Call verifyTLSNProof for TLSN identity verification
• Add tlsn_identity_remove case to removal handler
• Remove unused imports (log, ensureGCRForUser)
• Import verifyTLSNProof and TLSNIdentityPayload from tlsnotary module

src/libs/network/routines/transactions/handleIdentityRequest.ts


5. src/libs/omniprotocol/protocol/handlers/gcr.ts ✨ Enhancement +6/-4

GCR handler context validation for TLSN support

• Update IdentityAssignRequest interface to include nomis and tlsn contexts
• Update context validation to accept nomis and tlsn in addition to existing contexts
• Add type assertion for editOperation to handle new TLSN context
• Update error messages to reflect new supported contexts

src/libs/omniprotocol/protocol/handlers/gcr.ts


Grey Divider

Qodo Logo

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Node-side TLSNotary verification and exports, integrates tlsnadd/tlsnremove into GCR identity routines and network handlers, persists TLSNotary identity records, links Telegram TLSN incentives, updates tooling/install scripts, adds docs, and bumps a demo SDK dependency.

Changes

Cohort / File(s) Summary
TLSNotary verifier & exports
src/libs/tlsnotary/index.ts, src/libs/tlsnotary/verifier.ts
New TLSNotary verification module: presentation & proof structure checks, HTTP parsing, user extraction, verifyTLSNProof API, and exported types/utilities.
GCR identity routines
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts
Added applyTLSNIdentityAdd and applyTLSNIdentityRemove, TLSN_EXPECTED_ENDPOINTS, and apply switch branches for tlsnadd/tlsnremove; handles validation, dedupe, proofHash, persistence, and incentive linking/unlinking.
Network identity handler
src/libs/network/routines/transactions/handleIdentityRequest.ts
Added tlsn_identity_assign path calling verifyTLSNProof and tlsn_identity_remove removal case; swapped imports to TLSNotary APIs.
OmniProtocol types
src/libs/omniprotocol/protocol/handlers/gcr.ts
Expanded IdentityAssignRequest.context to include nomis and tlsn; updated validation messages.
Incentives / points
src/features/incentive/PointSystem.ts, src/libs/blockchain/gcr/gcr_routines/IncentiveManager.ts
Added awardTelegramTLSNPoints and telegramTLSNLinked to award Telegram LINK points for TLSN-linked identities via existing point flow.
TLSN tooling & deps
src/features/tlsnotary/proxyManager.ts, install-deps.sh, package.json
Resolve wstcp via Cargo bin path, use explicit binary path for spawn/install, prepend Cargo bin to PATH in installer, and bump @kynesyslabs/demosdk version.
GCR model
src/model/entities/GCRv2/GCR_Main.ts
Added optional zkAttestation array to points.breakdown (date, points, nullifier).
Docs
documentation/tlsn-oauth-flow.md
New doc describing TLSNotary+OAuth flow, payload contract, node validation rules, storage schema, and incentive conditions.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Client as Client
    participant Handler as "Identity Request\nHandler"
    participant Verifier as "TLSNotary\nVerifier"
    participant Parser as "HTTP Response\nParser"
    participant GCR as "GCR Identity\nRoutines"
    participant DB as "GCR Database"
    participant Incentive as "Incentive\nManager"

    Client->>Handler: POST tlsn_identity_assign (payload)
    Handler->>Verifier: verifyTLSNProof(payload)
    Verifier->>Parser: parseHttpResponse(revealedRecv)
    Parser-->>Verifier: {statusLine, headers, body}
    Verifier->>Verifier: extractUser(context, body)
    Verifier-->>Handler: {success, extractedUsername, extractedUserId}
    Handler->>GCR: applyTLSNIdentityAdd(editOperation, simulate?)
    GCR->>GCR: validate, dedupe, compute proofHash
    GCR->>DB: persist identity record
    GCR->>Incentive: telegramTLSNLinked(userId, telegramUserId, referralCode?)
    Incentive-->>GCR: award result
    GCR-->>Handler: GCRResult
    Handler-->>Client: response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Integrated Nomis Identity #552 — Adds new identity integrations and modifies the same identity/incentive stack (GCRIdentityRoutines, handleIdentityRequest, PointSystem, IncentiveManager, GCR_Main).
  • Feat zk integration #662 — Modifies GCRIdentityRoutines with new identity-handling routines and apply dispatcher changes.
  • Integrated Discord Identity #464 — Overlapping changes to GCR identity/incentive flows and identity linking logic.

Suggested labels

Possible security concern, Review effort 4/5

Suggested reviewers

  • cwilvx

Poem

🐰 I hopped through TLSN gates tonight,
I parsed the recv and checked the byte,
Matched usernames, hashed the proof,
Linked Telegram and gave a hoof —
A carrot for verified light!

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the primary change: adding TLSNotary identity assign and remove logic across multiple files including GCRIdentityRoutines, handleIdentityRequest, and related modules.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into testnet

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-tlsn-identity-assign-and-remove-logics

No actionable comments were generated in the recent review. 🎉


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Feb 10, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (4) 📎 Requirement gaps (0)

Grey Divider


Action required

✅ 1. PII in TLSN logs 📘 Rule violation ⛨ Security
Description
The new TLSN identity flow logs username and userId, which can be considered personal user
information and must not appear in application logs. These logs are also plain interpolated strings,
making them harder to audit/parse consistently.
Code

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[R1231-1233]

+        log.info(
+            `[TLSN Identity] Verifying proof for ${context} identity: ${username}`,
+        )
Evidence
The Secure Logging Practices rule forbids sensitive/personal user info in logs and requires logs to
be audit-friendly. The added log statements include username/userId directly in log messages.

Rule 5: Generic: Secure Logging Practices
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1231-1233]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1328-1330]
src/libs/tlsnotary/verifier.ts[326-328]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TLSN identity-related log messages include personal user information (`username`, `userId`) and are emitted as unstructured interpolated strings.
## Issue Context
Compliance requires logs to avoid sensitive/personal user data and be useful for auditing. Identity operations are security-sensitive, so logging must be carefully redacted and ideally structured.
## Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1231-1331]
- src/libs/tlsnotary/verifier.ts[326-328]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Internal errors returned to clients 📘 Rule violation ⛨ Security
Description
Several TLSN verification failures return verified.error and other internal details (e.g.,
expected/actual server names) in the message, which can leak implementation details to end-users.
Detailed failure context should be kept in internal logs, while client-facing messages remain
generic.
Code

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[R1238-1245]

+        if (!verified.success) {
+            log.warn(
+                `[TLSN Identity] Proof verification failed: ${verified.error}`,
+            )
+            return {
+                success: false,
+                message: `Proof verification failed: ${verified.error}`,
+            }
Evidence
The Secure Error Handling rule requires user-facing errors to avoid exposing internal details;
however, the new code returns raw verification errors to the caller. The same pattern exists in the
TLSN verifier API used by request handling.

Rule 4: Generic: Secure Error Handling
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1238-1245]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1256-1259]
src/libs/tlsnotary/verifier.ts[319-323]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TLSN-related APIs return internal verification details (`verified.error`, server mismatch specifics) in response messages, risking information leakage.
## Issue Context
Client-facing errors should be generic per secure error-handling requirements; detailed context should be logged internally for debugging.
## Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1238-1260]
- src/libs/tlsnotary/verifier.ts[317-324]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


✅ 3. TLSN add trusts client claims 📘 Rule violation ⛨ Security
Description
When operating in structure-validation-only mode (or when verified.recv is absent), the code
proceeds by trusting client-provided username/userId rather than deriving them from a verified
proof. This is insufficient validation for an externally supplied identity claim and can enable
identity spoofing.
Code

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[R1326-1332]

+            // WASM verification disabled - trust claimed data with warning
+            // NOTE: This is less secure but allows operation until WASM works in Node.js
+            log.warn(
+                `[TLSN Identity] WASM disabled - trusting claimed data for ${context}: ${username} (${userId})`,
+            )
+            extractedUser = { username, userId: String(userId) }
+        }
Evidence
The Security-First Input Validation rule requires validating external inputs; however, the verifier
explicitly only checks structure and the identity add path explicitly "trusts claimed data" in that
mode, meaning claims are not cryptographically validated server-side.

Rule 6: Generic: Security-First Input Validation and Data Handling
src/libs/tlsnotary/verifier.ts[6-9]
src/libs/tlsnotary/verifier.ts[156-160]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1326-1332]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TLSN identity assignment can succeed without server-side cryptographic verification by trusting client claims when running in structure-only verification mode.
## Issue Context
Identity binding is security-sensitive. Validating only proof structure is insufficient to authenticate the claimed `username`/`userId`.
## Fix Focus Areas
- src/libs/tlsnotary/verifier.ts[1-167]
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1230-1332]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
4. TLSN remove lacks audit log 📘 Rule violation ✓ Correctness
Description
The TLSN identity removal operation performs a write (gcrMainRepository.save) without emitting an
audit log capturing who performed the action, what changed, and the outcome. This makes it harder to
reconstruct identity changes during incident response or compliance reviews.
Code

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[R1456-1472]

+        if (!simulate) {
+            await gcrMainRepository.save(accountGCR)
+
+            // Trigger incentive rollback if applicable
+            if (context === "github" && identity.userId) {
+                await IncentiveManager.githubUnlinked(
+                    editOperation.account,
+                    identity.userId,
+                )
+            } else if (context === "discord") {
+                await IncentiveManager.discordUnlinked(editOperation.account)
+            } else if (context === "telegram") {
+                await IncentiveManager.telegramUnlinked(editOperation.account)
+            }
+        }
+
+        return { success: true, message: "TLSN identity removed successfully" }
Evidence
The audit trail rule requires logging critical actions (writes/permission-like changes) with enough
context to reconstruct events. The new TLSN removal path saves changes and returns success but
contains no corresponding audit logging.

Rule 1: Generic: Comprehensive Audit Trails
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1456-1472]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TLSN identity removal writes state without an accompanying audit log entry describing the action and outcome.
## Issue Context
Identity add/remove operations are critical security events and should be traceable without exposing sensitive user data.
## Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1422-1473]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


✅ 5. TLSN remove deletes non-TLSN 🐞 Bug ✓ Correctness
Description
applyTLSNIdentityRemove deletes identities purely by context+username and does not check that the
record was added via TLSN (proofType). This allows a tlsn_remove operation to remove legacy web2
identities and trigger incentive rollback unexpectedly.
Code

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[R1427-1455]

+        const { context, username } = editOperation.data
+
+        if (!context || !username) {
+            return {
+                success: false,
+                message: "Invalid payload: missing context or username",
+            }
+        }
+
+        const accountGCR = await ensureGCRForUser(editOperation.account)
+
+        accountGCR.identities.web2 = accountGCR.identities.web2 || {}
+        accountGCR.identities.web2[context] =
+            accountGCR.identities.web2[context] || []
+
+        // Find the identity to remove
+        const identity = accountGCR.identities.web2[context].find(
+            (id: Web2GCRData["data"]) => id.username === username,
+        )
+
+        if (!identity) {
+            return { success: false, message: "Identity not found" }
+        }
+
+        // Filter out the identity
+        accountGCR.identities.web2[context] = accountGCR.identities.web2[
+            context
+        ].filter((id: Web2GCRData["data"]) => id.username !== username)
+
Evidence
Web2 identities are stored in identities.web2[context] without a proofType field, and removal
for TLSN searches and filters only by username. Because TLSN identities are stored in the same
bucket (identities.web2[context]) and TLSN remove doesn’t validate proof provenance, it can delete
any entry that matches the username, not specifically TLSN-added records.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[197-216]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[277-281]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1427-1455]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`applyTLSNIdentityRemove` removes any web2 identity matching `username` without checking `proofType === "tlsn"`, and without validating `context` is one of the TLSN-supported platforms. This can delete non-TLSN identities.
### Issue Context
TLSN identities are stored in the same `accountGCR.identities.web2[context]` arrays used for regular web2 identities.
### Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1422-1470]
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[197-415]
### Suggested changes
1. Validate `context` in remove (e.g., only `github|discord|telegram`).
2. When finding/filtering, require the record to be TLSN-added, e.g. `(id as any).proofType === "tlsn"`.
3. Prefer removing by `userId` (or both `userId` and `username`) to avoid removing the wrong record when usernames collide or change.
4. Only trigger TLSN incentive rollback when the removed record is confirmed TLSN provenance.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

✅ 6. TLSN add lacks field checks 🐞 Bug ⛯ Reliability
Description
applyTLSNIdentityAdd does not validate that username/userId/proof are present and well-typed before
use, allowing records with userId="undefined" or empty usernames to be stored (especially in the
WASM-disabled fallback). This can break deduplication and lead to corrupted identity data.
Code

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[R1180-1187]

+        // Extract context from editOperation.data (top level)
+        const { context } = editOperation.data
+        // Extract nested data fields (proof, username, userId are inside data.data)
+        const {
+            proof: proofString,
+            username,
+            userId,
+        } = editOperation.data.data || {}
Evidence
The TLSN add routine destructures username/userId from editOperation.data.data || {} without
validating required fields. In the fallback path it uses String(userId) even if userId is
undefined, and deduplication compares against String(userId), enabling storage of invalid
identities and inconsistent behavior.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1180-1187]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1325-1332]
src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1341-1344]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
TLSN identity add accepts missing/invalid `username`, `userId`, and `proof` fields because it destructures from `editOperation.data.data || {}` and later stringifies `userId` without validation.
### Issue Context
This becomes especially problematic in the current fallback path (no `verified.recv`) where claimed values are trusted.
### Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1180-1203]
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1325-1348]
### Suggested changes
1. Early-validate: `context` is supported, `username` is a non-empty string, `userId` is a non-empty string/number, and `proofString` is present.
2. Reject on `userId == null` (avoid `String(undefined)`), and consider normalizing to a canonical string.
3. Consider limiting proof size (to avoid large JSON parse / DB bloat) and rejecting non-object proofs after parse.
4. Use the validated/extracted values (once real verification exists) for storage rather than the raw claimed ones.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +1231 to +1233
log.info(
`[TLSN Identity] Verifying proof for ${context} identity: ${username}`,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

1. Pii in tlsn logs 📘 Rule violation ⛨ Security

The new TLSN identity flow logs username and userId, which can be considered personal user
information and must not appear in application logs. These logs are also plain interpolated strings,
making them harder to audit/parse consistently.
Agent Prompt
## Issue description
TLSN identity-related log messages include personal user information (`username`, `userId`) and are emitted as unstructured interpolated strings.

## Issue Context
Compliance requires logs to avoid sensitive/personal user data and be useful for auditing. Identity operations are security-sensitive, so logging must be carefully redacted and ideally structured.

## Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1231-1331]
- src/libs/tlsnotary/verifier.ts[326-328]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1238 to +1245
if (!verified.success) {
log.warn(
`[TLSN Identity] Proof verification failed: ${verified.error}`,
)
return {
success: false,
message: `Proof verification failed: ${verified.error}`,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

2. Internal errors returned to clients 📘 Rule violation ⛨ Security

Several TLSN verification failures return verified.error and other internal details (e.g.,
expected/actual server names) in the message, which can leak implementation details to end-users.
Detailed failure context should be kept in internal logs, while client-facing messages remain
generic.
Agent Prompt
## Issue description
TLSN-related APIs return internal verification details (`verified.error`, server mismatch specifics) in response messages, risking information leakage.

## Issue Context
Client-facing errors should be generic per secure error-handling requirements; detailed context should be logged internally for debugging.

## Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1238-1260]
- src/libs/tlsnotary/verifier.ts[317-324]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1326 to +1332
// WASM verification disabled - trust claimed data with warning
// NOTE: This is less secure but allows operation until WASM works in Node.js
log.warn(
`[TLSN Identity] WASM disabled - trusting claimed data for ${context}: ${username} (${userId})`,
)
extractedUser = { username, userId: String(userId) }
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

3. Tlsn add trusts client claims 📘 Rule violation ⛨ Security

When operating in structure-validation-only mode (or when verified.recv is absent), the code
proceeds by trusting client-provided username/userId rather than deriving them from a verified
proof. This is insufficient validation for an externally supplied identity claim and can enable
identity spoofing.
Agent Prompt
## Issue description
TLSN identity assignment can succeed without server-side cryptographic verification by trusting client claims when running in structure-only verification mode.

## Issue Context
Identity binding is security-sensitive. Validating only proof structure is insufficient to authenticate the claimed `username`/`userId`.

## Fix Focus Areas
- src/libs/tlsnotary/verifier.ts[1-167]
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1230-1332]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1456 to +1472
if (!simulate) {
await gcrMainRepository.save(accountGCR)

// Trigger incentive rollback if applicable
if (context === "github" && identity.userId) {
await IncentiveManager.githubUnlinked(
editOperation.account,
identity.userId,
)
} else if (context === "discord") {
await IncentiveManager.discordUnlinked(editOperation.account)
} else if (context === "telegram") {
await IncentiveManager.telegramUnlinked(editOperation.account)
}
}

return { success: true, message: "TLSN identity removed successfully" }
Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

4. Tlsn remove lacks audit log 📘 Rule violation ✧ Quality

The TLSN identity removal operation performs a write (gcrMainRepository.save) without emitting an
audit log capturing who performed the action, what changed, and the outcome. This makes it harder to
reconstruct identity changes during incident response or compliance reviews.
Agent Prompt
## Issue description
TLSN identity removal writes state without an accompanying audit log entry describing the action and outcome.

## Issue Context
Identity add/remove operations are critical security events and should be traceable without exposing sensitive user data.

## Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1422-1473]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1427 to +1455
const { context, username } = editOperation.data

if (!context || !username) {
return {
success: false,
message: "Invalid payload: missing context or username",
}
}

const accountGCR = await ensureGCRForUser(editOperation.account)

accountGCR.identities.web2 = accountGCR.identities.web2 || {}
accountGCR.identities.web2[context] =
accountGCR.identities.web2[context] || []

// Find the identity to remove
const identity = accountGCR.identities.web2[context].find(
(id: Web2GCRData["data"]) => id.username === username,
)

if (!identity) {
return { success: false, message: "Identity not found" }
}

// Filter out the identity
accountGCR.identities.web2[context] = accountGCR.identities.web2[
context
].filter((id: Web2GCRData["data"]) => id.username !== username)

Copy link
Contributor

Choose a reason for hiding this comment

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

Action required

5. Tlsn remove deletes non-tlsn 🐞 Bug ✓ Correctness

applyTLSNIdentityRemove deletes identities purely by context+username and does not check that the
record was added via TLSN (proofType). This allows a tlsn_remove operation to remove legacy web2
identities and trigger incentive rollback unexpectedly.
Agent Prompt
### Issue description
`applyTLSNIdentityRemove` removes any web2 identity matching `username` without checking `proofType === "tlsn"`, and without validating `context` is one of the TLSN-supported platforms. This can delete non-TLSN identities.

### Issue Context
TLSN identities are stored in the same `accountGCR.identities.web2[context]` arrays used for regular web2 identities.

### Fix Focus Areas
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[1422-1470]
- src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts[197-415]

### Suggested changes
1. Validate `context` in remove (e.g., only `github|discord|telegram`).
2. When finding/filtering, require the record to be TLSN-added, e.g. `(id as any).proofType === "tlsn"`.
3. Prefer removing by `userId` (or both `userId` and `username`) to avoid removing the wrong record when usernames collide or change.
4. Only trigger TLSN incentive rollback when the removed record is confirmed TLSN provenance.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/libs/omniprotocol/protocol/handlers/gcr.ts (1)

46-49: ⚠️ Potential issue | 🟡 Minor

Stale doc comment — doesn't mention nomis or tlsn contexts.

Line 49 says "apply identity changes (xm, web2, pqc, ud)" but should now include nomis and tlsn.

- * Uses GCRIdentityRoutines to apply identity changes (xm, web2, pqc, ud).
+ * Uses GCRIdentityRoutines to apply identity changes (xm, web2, pqc, ud, nomis, tlsn).
🤖 Fix all issues with AI agents
In `@src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts`:
- Around line 1165-1173: The JSDoc for the "Add an identity via TLSNotary proof
verification" routine is inaccurate: the code path currently falls back to
trusting client-provided claims because verifyTLSNotaryPresentation returns no
recv data, so cryptographic verification is not performed. Update the comment on
the method in GCRIdentityRoutines.ts to state the current behavior: that
verifyTLSNotaryPresentation does not yield cryptographically-extracted recv data
and the implementation therefore accepts client-supplied claims in the fallback
branch (where the code uses the client-provided values), and remove or soften
any absolute statements like "never trusting client-provided claims" and
"performs cryptographic verification."
- Around line 1267-1332: The code block that depends on verified.recv is dead
because verifyTLSNotaryPresentation never returns recv; update the TLSN
verification flow in GCRIdentityRoutines.verify... to avoid implying proof
verification: add a top-of-function TODO comment stating "identity claims are
currently unverified — WASM recv path disabled" and either remove/disable the
entire recv-based branch (the if (verified.recv) block that calls
parseHttpResponse, extractUser, and performs username/userId checks) or gate it
explicitly behind a clearly named feature flag (e.g., ENABLE_WASM_RECV) so it
cannot run accidentally; also update the log messages (the else branch and any
success logs) to make it explicit they are trusting client claims, and keep
references to verifyTLSNotaryPresentation, verified.recv, parseHttpResponse,
extractUser, and TLSNIdentityContext to locate the code.
- Around line 1422-1449: The applyTLSNIdentityRemove function currently calls
ensureGCRForUser which can create a new GCR record; change it to load the record
with gcrMainRepository.findOneBy({ account: editOperation.account }) (same
pattern as applyXmIdentityRemove / applyNomisIdentityRemove), and if no record
is found return { success: false, message: "Account not found" } instead of
proceeding; keep the rest of the logic that accesses accountGCR.identities.web2
the same so you only avoid creating empty GCRs when removing an identity.
- Around line 1180-1212: The destructured fields proofString, username, and
userId (from editOperation.data.data) are not validated and can be undefined;
add explicit checks in the GCRIdentityRoutines method after parsing proof
(and/or immediately after destructuring) to ensure username and userId are
present and non-empty (and that proof was successfully parsed), returning a
failure object with a clear message (e.g., "Missing required field: username" or
"Missing required field: userId") if they are missing; keep existing context
validation (this.TLSN_EXPECTED_ENDPOINTS[context]) but perform these new
validations before any use of username/userId (e.g., before logging or storing
at later lines) to prevent downstream errors.
- Around line 1396-1410: The TLSN branch calling IncentiveManager.telegramLinked
is missing the attestation argument; update the call in GCRIdentityRoutines
(where isFirstConnection is used) to pass data.proof as the fourth parameter so
the call becomes IncentiveManager.telegramLinked(editOperation.account,
String(userId), referralCode, data.proof), matching the Web2 path and allowing
awardTelegramPoints to inspect attestation.payload.group_membership.

In `@src/libs/omniprotocol/protocol/handlers/gcr.ts`:
- Around line 100-107: Update the stale doc comment that enumerates allowed
context types to include "nomis" and "tlsn" and add a short TODO noting the
temporary nature of the `as any` cast; specifically, update the comment near the
use of gcrIdentityRoutines.apply to list "xm, web2, pqc, ud, nomis, tlsn" and
add a note that the editOperation is currently cast to any due to a missing
"tlsn" union member in the SDK's GCREdit type; keep the `as any` for now but add
a TODO referencing `@kynesyslabs/demosdk` and instruct to remove the cast and
restore proper typing of editOperation to GCREdit once the SDK is updated.

In `@src/libs/tlsnotary/index.ts`:
- Around line 1-6: Update the module doc comment to remove the incorrect "using
WASM" claim and clearly state that this TLSNotary Verification Module performs
server-side, structure-only verification without WASM support; reference the
verifier implementation (verifier.ts) and its structure-only verification mode
so readers know where the non-WASM logic lives and that WASM is intentionally
unsupported.

In `@src/libs/tlsnotary/verifier.ts`:
- Around line 264-277: The extractUser logic in extractUser (case "telegram")
currently returns an empty string when both user.username and user.first_name
are missing, which can silently match in applyTLSNIdentityAdd's username
comparison; update extractUser to treat a missing username as an extraction
failure by checking that either user.username or user.first_name exists before
returning, and if neither exists log a clear warning/error (include context like
"Telegram response missing username/first_name") and return null instead of
username:""; ensure callers like applyTLSNIdentityAdd rely on null to indicate
extraction failure.
- Around line 301-335: The function verifyTLSNProof currently returns
caller-supplied username/userId as extractedUsername/extractedUserId which is
misleading; update verifyTLSNProof to either (A) rename the return fields to
claimedUsername and claimedUserId and adjust callers (e.g.,
handleIdentityRequest.ts handling of tlsn_identity_assign) to reflect they are
unverified claims, or (B) implement proof-derived extraction by parsing the
verified proof inside verifyTLSNProof (similar to applyTLSNIdentityAdd) and
compare those extracted values with the supplied username/userId, returning the
extracted values only when they match; choose one approach and update all uses
of extractedUsername/extractedUserId accordingly to avoid implying proof-derived
trust.
🧹 Nitpick comments (4)
src/libs/tlsnotary/verifier.ts (2)

138-152: Consider adding an upper bound on data length before running the regex test.

/^[0-9a-fA-F]+$/.test(presentationJSON.data) will scan the entire string. If data is extremely large (megabytes of hex), this could be expensive. A length ceiling before the regex would be a simple safeguard.

+        // Upper bound check to prevent processing excessively large payloads
+        if (presentationJSON.data.length > 10_000_000) {
+            return {
+                success: false,
+                error: "Invalid presentation: 'data' field exceeds maximum allowed size",
+            }
+        }
+
         // Validate data is hex-encoded (basic check)
         if (!/^[0-9a-fA-F]+$/.test(presentationJSON.data)) {

82-95: initTLSNotaryVerifier and isVerifierInitialized are no-ops — document that clearly or remove the initialization ceremony.

These functions exist "for API compatibility" but serve no purpose. Any caller checking isVerifierInitialized() will always get true, which masks the fact that no real verification infrastructure is running. If these are meant to be a future extension point, the doc comment on isVerifierInitialized should warn that it does not indicate cryptographic readiness.

src/libs/network/routines/transactions/handleIdentityRequest.ts (1)

102-104: Verify the shape of payload.payload matches TLSNIdentityPayload at runtime.

The cast payload.payload as TLSNIdentityPayload assumes the payload contains context, proof, username, and userId fields. If a malformed request omits any of these, verifyTLSNProof will proceed with undefined values — the context validation on line 310 of verifier.ts would catch an invalid context, but undefined proof would still pass the typeof proof !== "object" check (since typeof undefined === "undefined"), leading to a structure validation failure. This works incidentally but is fragile.

Consider adding explicit field presence checks before the cast, consistent with how other cases validate their payloads.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts (1)

1350-1359: Storing the full TLSNotary proof object in the JSONB column could significantly bloat storage.

TLSNotary proofs can contain large hex-encoded data fields. Storing the entire proof per identity in the web2 JSONB column could degrade query performance over time. Consider storing only the proofHash and persisting the full proof in a separate table or blob store if re-verification is needed.

Comment on lines 100 to 107
// Apply the identity operation (simulate = false for actual execution)
// Type assertion needed: local IdentityAssignRequest includes "tlsn" context
// but the GCREdit type from SDK package may not have it yet
const result = await gcrIdentityRoutines.apply(
editOperation,
editOperation as any,
gcrMainRepository,
false, // simulate = false (actually apply changes)
)
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, locate the file and check its size
wc -l src/libs/omniprotocol/protocol/handlers/gcr.ts

Repository: kynesyslabs/node

Length of output: 110


🏁 Script executed:

# Read the relevant sections of the file
sed -n '40,60p' src/libs/omniprotocol/protocol/handlers/gcr.ts

Repository: kynesyslabs/node

Length of output: 834


🏁 Script executed:

# Read the section with the type assertion
sed -n '95,115p' src/libs/omniprotocol/protocol/handlers/gcr.ts

Repository: kynesyslabs/node

Length of output: 993


🏁 Script executed:

# Check package.json for current SDK version
cat package.json | grep -A 2 -B 2 "demosdk"

Repository: kynesyslabs/node

Length of output: 656


🌐 Web query:

@kynesyslabs/demosdk npm package latest version GCREdit type

💡 Result:

  • Latest npm version of @kynesyslabs/demosdk: 2.3.22 (shown as the current version on npm). [1]
  • GCREdit type: I could not find any published API-reference entry or docs page mentioning a GCREdit type for @kynesyslabs/demosdk. [2]

To confirm whether GCREdit exists in the installed typings (and whether it’s exported), search your local install:

npm i `@kynesyslabs/demosdk`@latest
grep -R "GCREdit" node_modules/@kynesyslabs/demosdk -n

Sources: [1] [2]


🏁 Script executed:

# Search for GCREdit type in node_modules
find node_modules/@kynesyslabs/demosdk -name "*.d.ts" 2>/dev/null | head -20

Repository: kynesyslabs/node

Length of output: 42


🏁 Script executed:

# Search for GCREdit in the SDK
grep -r "GCREdit" node_modules/@kynesyslabs/demosdk 2>/dev/null | head -10

Repository: kynesyslabs/node

Length of output: 42


🏁 Script executed:

# Also check if we can find the actual IdentityAssignRequest type in the codebase
rg "IdentityAssignRequest" src/ -A 5 -B 2

Repository: kynesyslabs/node

Length of output: 2041


🏁 Script executed:

# Check what contexts are validated in the code (around line 74-75 mentioned in scratchpad)
sed -n '70,80p' src/libs/omniprotocol/protocol/handlers/gcr.ts

Repository: kynesyslabs/node

Length of output: 635


Update stale doc comment to include new context types, and track as any cast as tech debt.

The doc comment on line 49 lists only "xm, web2, pqc, ud" but should include the newly added "nomis" and "tlsn" contexts. The as any cast on line 104 is a pragmatic workaround for SDK type misalignment—once @kynesyslabs/demosdk is updated to include "tlsn" in GCREdit, remove this assertion and update the comment accordingly.

🤖 Prompt for AI Agents
In `@src/libs/omniprotocol/protocol/handlers/gcr.ts` around lines 100 - 107,
Update the stale doc comment that enumerates allowed context types to include
"nomis" and "tlsn" and add a short TODO noting the temporary nature of the `as
any` cast; specifically, update the comment near the use of
gcrIdentityRoutines.apply to list "xm, web2, pqc, ud, nomis, tlsn" and add a
note that the editOperation is currently cast to any due to a missing "tlsn"
union member in the SDK's GCREdit type; keep the `as any` for now but add a TODO
referencing `@kynesyslabs/demosdk` and instruct to remove the cast and restore
proper typing of editOperation to GCREdit once the SDK is updated.

Comment on lines +1 to +6
/**
* TLSNotary Verification Module
*
* Provides server-side verification of TLSNotary proofs using WASM.
* Used by GCR identity routines to verify TLSN-based identity claims.
*/
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 | 🟡 Minor

Module doc comment is misleading — says "using WASM" but this module explicitly does not use WASM.

Line 4 states "Provides server-side verification of TLSNotary proofs using WASM" but the underlying verifier.ts operates in "structure-only verification mode" with WASM explicitly noted as unsupported. This will confuse future readers.

 /**
  * TLSNotary Verification Module
  *
- * Provides server-side verification of TLSNotary proofs using WASM.
+ * Provides server-side structural validation of TLSNotary proofs.
+ * NOTE: Full cryptographic verification via WASM is not yet supported in Node.js.
  * Used by GCR identity routines to verify TLSN-based identity claims.
  */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* TLSNotary Verification Module
*
* Provides server-side verification of TLSNotary proofs using WASM.
* Used by GCR identity routines to verify TLSN-based identity claims.
*/
/**
* TLSNotary Verification Module
*
* Provides server-side structural validation of TLSNotary proofs.
* NOTE: Full cryptographic verification via WASM is not yet supported in Node.js.
* Used by GCR identity routines to verify TLSN-based identity claims.
*/
🤖 Prompt for AI Agents
In `@src/libs/tlsnotary/index.ts` around lines 1 - 6, Update the module doc
comment to remove the incorrect "using WASM" claim and clearly state that this
TLSNotary Verification Module performs server-side, structure-only verification
without WASM support; reference the verifier implementation (verifier.ts) and
its structure-only verification mode so readers know where the non-WASM logic
lives and that WASM is intentionally unsupported.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/libs/tlsnotary/verifier.ts`:
- Around line 102-140: The fallback extraction in maybeParseJsonText is too
greedy because it uses indexOf("{") and lastIndexOf("}") (and similarly for
"["/"]"); change this to find a properly balanced JSON span by scanning forward
from the first opening brace/bracket and counting nested braces/brackets until
the matching closing character is found (so you return the minimal balanced
substring), and apply the same balanced-scan logic for arrays as well; update
maybeParseJsonText to return the balanced object or array substring (or null if
no matching closer is found) instead of slicing to the last closing character.
- Around line 161-198: The current extractUserFromRawText fallback uses separate
regexes that can match "id" and "username/login" from different JSON objects in
the same text; update extractUserFromRawText (and the github/discord/telegram
branches) to ensure username/login and id are captured from the same JSON object
by either: 1) using a single regex that matches a JSON object/block containing
both fields (e.g. match a { ... "login": ... ... "id": ... } or similar
non-greedy bracketed pattern) and capture both groups, or 2) attempt to parse
the text for JSON objects (split by braces or try JSON.parse on found
substrings) and extract username+id from the same parsed object; replace the
separated regexes (e.g. /"login".../ and /"id".../) with a proximity-scoped
match so you never combine fields from different objects.
🧹 Nitpick comments (2)
src/features/incentive/PointSystem.ts (1)

935-1022: awardTelegramTLSNPoints duplicates ~90% of awardTelegramPoints.

The only behavioral difference is the absence of the group_membership attestation check. Consider extracting the shared logic into a private helper (e.g., _awardTelegramPointsCore) and calling it from both methods, passing a flag or predicate for the group-membership gate.

documentation/tlsn-oauth-flow.md (1)

3-3: Minor: capitalize platform names in prose.

"github" → "GitHub", "discord" → "Discord" per their official names, as flagged by static analysis.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
12.0% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts`:
- Around line 1663-1669: The call to IncentiveManager.telegramTLSNLinked
currently passes (editOperation.account, String(userId), referralCode) but the
method signature is (userId: string, telegramUserId: string, referralCode?:
string); swap the first two arguments so the app userId is passed first and the
telegram account second (e.g. call with String(userId), editOperation.account,
referralCode), and ensure referralCode is passed only when present and types
match the function signature; verify this aligns with the intended semantics in
GCRIdentityRoutines.

In `@src/libs/tlsnotary/verifier.ts`:
- Around line 724-817: The recvHash comparison in verifyTLSNProof
(computedRecvHash vs recvHash after decodeRevealedRecv) is self-referential
because both values come from the client; add a clear inline comment at that
comparison site (near computedRecvHash.toLowerCase() !== recvHash.toLowerCase())
stating this check only ensures internal consistency of the supplied payload and
is NOT a cryptographic authenticity check, and reference the existing TODO about
binding recvHash to the TLSNotary proof.data via WASM verification
(verifyTLSNotaryPresentation / proof.data) so future readers don't treat it as a
security boundary.
🧹 Nitpick comments (4)
src/libs/tlsnotary/verifier.ts (2)

102-164: DRY: findBalancedJsonValue and findBalancedJsonValueAt share identical balanced-brace parsing logic.

findBalancedJsonValue iterates over start positions and delegates to the same brace-matching algorithm duplicated in findBalancedJsonValueAt. Consider implementing findBalancedJsonValue in terms of findBalancedJsonValueAt:

♻️ Proposed refactor
 function findBalancedJsonValue(text: string): string | null {
     for (let start = 0; start < text.length; start++) {
-        const first = text[start]
-        if (first !== "{" && first !== "[") {
+        if (text[start] !== "{" && text[start] !== "[") {
             continue
         }
-
-        const stack: string[] = [first]
-        let inString = false
-        let escaped = false
-
-        for (let i = start + 1; i < text.length; i++) {
-            const ch = text[i]
-            // ... ~60 lines of duplicated logic ...
-        }
+        const match = findBalancedJsonValueAt(text, start)
+        if (match) {
+            return match.value
+        }
     }
-
     return null
 }

Also applies to: 166-229


305-490: Consider extracting per-context extraction logic into a helper map to reduce repetition.

The github/discord/telegram branches are repeated three times (structured parse, regex on candidate, final fallback). A context-to-field-names mapping could reduce ~180 lines to ~60, but this is optional given the code works correctly.

src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts (2)

1450-1460: TLSN_EXPECTED_ENDPOINTS values (server, pathPrefix) are never used.

The map is only accessed to check key existence (line 1548: this.TLSN_EXPECTED_ENDPOINTS[context]). The server and pathPrefix values are never validated against the actual proof content. Either remove the unused values (replace with a Set<string>) or implement the endpoint validation.


1596-1620: TLSN identities co-stored with OAuth identities in web2 — document this design choice.

TLSN-verified identities are stored in the same identities.web2[context] array as OAuth-verified identities, distinguished only by proofType: "tlsn". This works but is a non-obvious design decision. A brief comment at line 1596 explaining why TLSN identities live in web2 (e.g., "TLSN identities share the web2 store so isFirstConnection and incentive deduplication work across both verification paths") would help future maintainers.

Comment on lines +1663 to +1669
if (isFirst) {
await IncentiveManager.telegramTLSNLinked(
editOperation.account,
String(userId),
referralCode,
)
}
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for telegramTLSNLinked definition in IncentiveManager
rg -nP 'telegramTLSNLinked' --type=ts -C5

Repository: kynesyslabs/node

Length of output: 2101


Fix parameter mapping for IncentiveManager.telegramTLSNLinked call.

The method exists but has a signature mismatch. The actual definition expects (userId: string, telegramUserId: string, referralCode?: string), but the call at lines 1664–1668 passes arguments as if the signature were (account, userId, referralCode). The first parameter editOperation.account is passed where userId is expected, and String(userId) is passed where telegramUserId is expected. Verify the parameter order and semantic intent match the method's design.

🤖 Prompt for AI Agents
In `@src/libs/blockchain/gcr/gcr_routines/GCRIdentityRoutines.ts` around lines
1663 - 1669, The call to IncentiveManager.telegramTLSNLinked currently passes
(editOperation.account, String(userId), referralCode) but the method signature
is (userId: string, telegramUserId: string, referralCode?: string); swap the
first two arguments so the app userId is passed first and the telegram account
second (e.g. call with String(userId), editOperation.account, referralCode), and
ensure referralCode is passed only when present and types match the function
signature; verify this aligns with the intended semantics in
GCRIdentityRoutines.

Comment on lines +724 to +817
export async function verifyTLSNProof(payload: TLSNIdentityPayload): Promise<{
success: boolean
message: string
extractedUsername?: string
extractedUserId?: string
}> {
const { context, proof, recvHash, revealedRecv, username, userId } = payload

// Validate context
if (!["github", "discord", "telegram"].includes(context)) {
return {
success: false,
message: `Unsupported TLSN context: ${context}`,
}
}

if (typeof recvHash !== "string" || !/^[0-9a-fA-F]{64}$/.test(recvHash)) {
return {
success: false,
message: "Invalid TLSN recvHash: expected 64-char hex sha256",
}
}

// Verify the proof structure
const verified = await verifyTLSNotaryPresentation(proof)
if (!verified.success) {
return {
success: false,
message: `Proof verification failed: ${verified.error}`,
}
}

const recvBytes = decodeRevealedRecv(revealedRecv)
if (!recvBytes) {
return {
success: false,
message: "Invalid TLSN revealedRecv: expected byte array (0-255)",
}
}

if (recvBytes.length === 0) {
return {
success: false,
message: "Invalid TLSN revealedRecv: empty payload",
}
}

const computedRecvHash = Hashing.sha256Bytes(recvBytes)
if (computedRecvHash.toLowerCase() !== recvHash.toLowerCase()) {
return {
success: false,
message:
"recvHash mismatch: provided hash does not match disclosed recv bytes",
}
}

const responseBody = parseDisclosedRecvBody(recvBytes)
const rawText = new TextDecoder().decode(recvBytes)
const extractedUser =
(responseBody ? extractUser(context, responseBody) : null) ||
extractUserFromRawText(context, rawText)
if (!extractedUser) {
return {
success: false,
message: `Failed to extract user from ${context} revealedRecv payload`,
}
}

if (extractedUser.username !== username) {
return {
success: false,
message: `Username mismatch: claimed '${username}', proof contains '${extractedUser.username}'`,
}
}

if (extractedUser.userId !== String(userId)) {
return {
success: false,
message: `UserId mismatch: claimed '${String(
userId,
)}', proof contains '${extractedUser.userId}'`,
}
}

log.info(
`[TLSNotary Verifier] ${context} proof and recvHash validated for userId=${userId}`,
)

return {
success: true,
message: "Proof and recvHash verified",
extractedUsername: extractedUser.username,
extractedUserId: extractedUser.userId,
}
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 | 🟠 Major

recvHash integrity check is self-referential — both recvHash and revealedRecv are client-supplied.

The function hashes revealedRecv and compares it to recvHash (line 772), but both values come from the same untrusted client payload. A malicious client can submit any revealedRecv with a matching recvHash. Without cryptographic binding of recvHash to the TLSNotary proof data field (which requires WASM verification), this check only validates internal consistency of the client's submission, not authenticity.

This is already acknowledged in the file header's TODO, but consider adding an inline comment at the hash-comparison site so future readers don't mistake this for a security boundary.

🤖 Prompt for AI Agents
In `@src/libs/tlsnotary/verifier.ts` around lines 724 - 817, The recvHash
comparison in verifyTLSNProof (computedRecvHash vs recvHash after
decodeRevealedRecv) is self-referential because both values come from the
client; add a clear inline comment at that comparison site (near
computedRecvHash.toLowerCase() !== recvHash.toLowerCase()) stating this check
only ensures internal consistency of the supplied payload and is NOT a
cryptographic authenticity check, and reference the existing TODO about binding
recvHash to the TLSNotary proof.data via WASM verification
(verifyTLSNotaryPresentation / proof.data) so future readers don't treat it as a
security boundary.

@tcsenpai tcsenpai merged commit 02b1c95 into testnet Feb 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants