Skip to content

Add SatsCard parse tests and URL detection#671

Open
guptapratykshh wants to merge 1 commit intobitcoinppl:masterfrom
guptapratykshh:satscard-parse-tests-and-multiformat
Open

Add SatsCard parse tests and URL detection#671
guptapratykshh wants to merge 1 commit intobitcoinppl:masterfrom
guptapratykshh:satscard-parse-tests-and-multiformat

Conversation

@guptapratykshh
Copy link
Copy Markdown
Contributor

@guptapratykshh guptapratykshh commented Apr 17, 2026

Add seven focused tests for SatsCard URL parsing covering unsealed state, error state, missing fields, unknown state, identity, and invalid domain. Add SatsCard variant to MultiFormat enum and getsatscard.com URL detection branch.

Summary

Testing

Platform Coverage

  • Tested on iOS device
  • Tested on Android device
  • Tested on iOS simulator
  • Tested on Android simulator
  • Not tested

Checklist

Summary by CodeRabbit

  • New Features

    • Added support for SatsCard inputs so NFC/QR SatsCard scans are recognized across the app.
  • Bug Fixes

    • Clearer validation and explicit rejection for wrong-card or invalid-domain URLs.
    • More precise error responses when card inputs are misclassified or unsupported.
  • Tests

    • Expanded automated tests covering SatsCard parsing success, invalid/missing fields, and domain/format rejection.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 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

Walkthrough

Adds SatsCard parsing tests and integrates SATSCARD support into MultiFormat with explicit InvalidSatsCard/InvalidTapSigner error mapping; updates Android FFI bindings to expose the new MultiFormat.SatsCard variant and corresponding error handling and tag adjustments.

Changes

Cohort / File(s) Summary
SatsCard Parsing Tests
rust/crates/cove-tap-card/src/parse.rs
Added unit tests for TapCard::parse covering getsatscard.com SatsCard Unsealed and Error cases, ensuring getsatscard.com is not treated as TapSigner and invalid-host URLs produce Error::InvalidUrl.
MultiFormat SatsCard Support (Rust)
rust/src/multi_format.rs
Added MultiFormat::SatsCard(cove_tap_card::SatsCard) and MultiFormatError::InvalidSatsCard(...); introduced mapping helpers from cove_tap_card::parse::Error; updated domain dispatch to parse getsatscard.com/start and return SatsCard or an explicit InvalidSatsCard on mismatch/parse error; replaced prior unreachable! assumptions for tapsigner handling.
MultiFormat FFI & Errors (Android/Kotlin)
android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
Added FFI handling for MultiFormat.SatsCard (tag 8) and shifted SignedPsbt to tag 9; introduced MultiFormatException.InvalidSatsCard and updated MultiFormatError read/write/tag dispatch and allocation sizing; added custom MultiFormat.equals delegating to Rust FFI equality.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant MultiFormat
    participant TapCardParser as cove_tap_card::TapCard::parse

    Client->>MultiFormat: try_from_string(url)
    MultiFormat-->>MultiFormat: detect domain (getsatscard.com / tapsigner.com)
    alt getsatscard.com
        MultiFormat->>TapCardParser: parse(url)
        TapCardParser-->>MultiFormat: SatsCard(...)
        MultiFormat-->>Client: MultiFormat::SatsCard(...)
        TapCardParser-->>MultiFormat: TapSigner(...)
        MultiFormat-->>Client: Err(InvalidSatsCard(...))
        TapCardParser-->>MultiFormat: Err(parse_error)
        MultiFormat-->>Client: Err(InvalidSatsCard(parse_error))
    else tapsigner.com
        MultiFormat->>TapCardParser: parse(url)
        TapCardParser-->>MultiFormat: TapSigner(...)
        MultiFormat-->>Client: MultiFormat::TapSigner(...)
        TapCardParser-->>MultiFormat: SatsCard(...)
        MultiFormat-->>Client: Err(InvalidTapSigner(...))
        TapCardParser-->>MultiFormat: Err(parse_error)
        MultiFormat-->>Client: Err(InvalidTapSigner(parse_error))
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested reviewers

  • praveenperera

Poem

🐰 I found a sats link in the glade,
Tests hopped in light and never afraid,
New variant tucked in FFI's chest,
Errors named tidy, tags moved to rest,
A tiny rabbit cheers this code parade. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main changes: adding SatsCard parse tests and URL detection logic across the codebase.
Description check ✅ Passed The description includes the required Summary and Testing sections with Platform Coverage checklist, though Testing details are not fully filled in.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 17, 2026

Greptile Summary

This PR adds seven parse.rs tests for SatsCard URL parsing (unsealed/error states, missing fields, unknown state, identity check, invalid domain) and wires up the SatsCard variant in MultiFormat with a getsatscard.com/start detection branch.

  • The new getsatscard.com branch uses unreachable! for the TapSigner arm, but parse_card dispatches on the t=1 query param — not the URL domain — so a crafted URL with getsatscard.com/start and t=1 will parse as TapSigner and panic at runtime instead of returning an error.

Confidence Score: 4/5

Safe to merge after fixing the unreachable! panic in the getsatscard.com branch.

One P1 finding: the new unreachable! arm in the getsatscard.com branch will panic instead of returning an error when a crafted URL (getsatscard.com domain + t=1 param) is parsed. The parse tests are thorough and correct. The SatsCard enum variant and detection branch are otherwise sound.

rust/src/multi_format.rs — the getsatscard.com detection branch at lines 175-177

Important Files Changed

Filename Overview
rust/src/multi_format.rs Adds SatsCard variant to MultiFormat enum and getsatscard.com detection branch; the new unreachable! arm can panic on crafted input where the URL domain is getsatscard.com but the query string includes t=1
rust/crates/cove-tap-card/src/parse.rs Adds seven focused SatsCard URL parsing tests covering unsealed/error states, missing required fields, unknown state, misidentification guard, and invalid domain; tests are correct and well-scoped

Reviews (1): Last reviewed commit: "Add SatsCard parse tests and URL detecti..." | Re-trigger Greptile

Comment thread rust/src/multi_format.rs
Copy link
Copy Markdown

@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.

Caution

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

⚠️ Outside diff range comments (1)
rust/src/multi_format.rs (1)

151-179: ⚠️ Potential issue | 🔴 Critical

Critical: unreachable!() on user-controlled input can panic the process.

Both unreachable! arms are reachable via crafted input because domain detection uses string.contains(...) while variant selection inside TapCard::parse depends on the t=1 param, not the domain:

  • A URL containing tapsigner.com/start but omitting t=1 (and providing o/r) parses as TapCard::SatsCard → hits line 161 unreachable! and panics.
  • A URL containing getsatscard.com/start with t=1 and a c field parses as TapCard::TapSigner → hits line 176 unreachable! and panics.

Since this path is fed by QR/NFC scans (untrusted input), this is a DoS/crash vector. Return a recoverable error instead.

🛡️ Proposed fix
             match tap_card {
                 cove_tap_card::TapCard::TapSigner(card) => {
                     return Ok(Self::from(card));
                 }
-
-                cove_tap_card::TapCard::SatsCard(_card) => {
-                    unreachable!("tapsigner.com URL should not parse as a sats card");
-                }
+                cove_tap_card::TapCard::SatsCard(_) => {
+                    warn!("tapsigner.com URL parsed as SatsCard; treating as unrecognized");
+                    return Err(MultiFormatError::UnrecognizedFormat);
+                }
             }
         }

         if string.contains("getsatscard.com/start") {
             let tap_card = cove_tap_card::TapCard::parse(string)
                 .map_err(|e| MultiFormatError::InvalidSatsCard(e.into()))?;

             match tap_card {
                 cove_tap_card::TapCard::SatsCard(card) => {
                     return Ok(Self::SatsCard(card));
                 }
-
-                cove_tap_card::TapCard::TapSigner(_card) => {
-                    unreachable!("getsatscard.com URL should not parse as a tap signer");
+                cove_tap_card::TapCard::TapSigner(_) => {
+                    warn!("getsatscard.com URL parsed as TapSigner; treating as unrecognized");
+                    return Err(MultiFormatError::UnrecognizedFormat);
                 }
             }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/multi_format.rs` around lines 151 - 179, The code currently uses
unreachable!() in the TapCard match arms which can panic on crafted input;
replace those unreachable!() calls with recoverable errors by returning Err(...)
instead of panicking. Specifically, in the block that calls
cove_tap_card::TapCard::parse(...) for strings containing "tapsigner.com/start",
change the TapCard::SatsCard(_card) arm to return
Err(MultiFormatError::InvalidTapSigner(...)) (or a new error variant like
UnexpectedTapCardVariant with context) rather than unreachable!; likewise, in
the "getsatscard.com/start" block change the TapCard::TapSigner(_card) arm to
return Err(MultiFormatError::InvalidSatsCard(...)) (or the same new contextual
variant). Keep using the result of TapCard::parse and include clear context
(e.g., expected vs found variant and the original string or parsed fields) when
constructing the error so callers can handle malformed/crafted inputs without
crashing.
🧹 Nitpick comments (1)
rust/src/multi_format.rs (1)

42-43: Wrap SatsCard in Arc for consistency across all MultiFormat variants.

All other variants in MultiFormat use Arc (e.g., Address, HardwareExport, Mnemonic, Transaction, TapSignerReady, TapSignerUnused, SignedPsbt). Storing SatsCard by value means the entire struct is cloned whenever MultiFormat is cloned—this enum derives Clone, crosses FFI boundaries (uniffi), and is compared with Eq. Wrapping SatsCard in Arc keeps cloning costs and ergonomics consistent.

cove_tap_card::SatsCard already implements PartialEq and Eq via its derive macros, so no compilation issues exist.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust/src/multi_format.rs` around lines 42 - 43, MultiFormat's SatsCard
variant should be wrapped in Arc to match the other variants and avoid expensive
by-value clones: change the enum variant from SatsCard(cove_tap_card::SatsCard)
to SatsCard(Arc<cove_tap_card::SatsCard>), add/use std::sync::Arc import, and
update any places constructing or pattern-matching on MultiFormat::SatsCard to
wrap new SatsCard values with Arc::new(...) or clone the Arc when needed; no
changes to derives (Clone/Eq) are required because cove_tap_card::SatsCard
already implements Eq/PartialEq.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@rust/src/multi_format.rs`:
- Around line 151-179: The code currently uses unreachable!() in the TapCard
match arms which can panic on crafted input; replace those unreachable!() calls
with recoverable errors by returning Err(...) instead of panicking.
Specifically, in the block that calls cove_tap_card::TapCard::parse(...) for
strings containing "tapsigner.com/start", change the TapCard::SatsCard(_card)
arm to return Err(MultiFormatError::InvalidTapSigner(...)) (or a new error
variant like UnexpectedTapCardVariant with context) rather than unreachable!;
likewise, in the "getsatscard.com/start" block change the
TapCard::TapSigner(_card) arm to return
Err(MultiFormatError::InvalidSatsCard(...)) (or the same new contextual
variant). Keep using the result of TapCard::parse and include clear context
(e.g., expected vs found variant and the original string or parsed fields) when
constructing the error so callers can handle malformed/crafted inputs without
crashing.

---

Nitpick comments:
In `@rust/src/multi_format.rs`:
- Around line 42-43: MultiFormat's SatsCard variant should be wrapped in Arc to
match the other variants and avoid expensive by-value clones: change the enum
variant from SatsCard(cove_tap_card::SatsCard) to
SatsCard(Arc<cove_tap_card::SatsCard>), add/use std::sync::Arc import, and
update any places constructing or pattern-matching on MultiFormat::SatsCard to
wrap new SatsCard values with Arc::new(...) or clone the Arc when needed; no
changes to derives (Clone/Eq) are required because cove_tap_card::SatsCard
already implements Eq/PartialEq.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c8b05d37-95f1-4836-9efe-f96e5a81cda7

📥 Commits

Reviewing files that changed from the base of the PR and between 3a78f80 and f607bd9.

📒 Files selected for processing (2)
  • rust/crates/cove-tap-card/src/parse.rs
  • rust/src/multi_format.rs

@guptapratykshh guptapratykshh force-pushed the satscard-parse-tests-and-multiformat branch from f607bd9 to 7dec1c4 Compare April 17, 2026 17:37
Comment thread rust/src/multi_format.rs Outdated
Comment thread rust/src/multi_format.rs Outdated
Comment thread rust/src/multi_format.rs Outdated
Comment thread rust/src/multi_format.rs
@guptapratykshh guptapratykshh force-pushed the satscard-parse-tests-and-multiformat branch from 7dec1c4 to c319dc1 Compare April 18, 2026 04:34
@praveenperera praveenperera force-pushed the satscard-parse-tests-and-multiformat branch 2 times, most recently from 6de0e88 to 92257c8 Compare April 21, 2026 17:57
@guptapratykshh guptapratykshh force-pushed the satscard-parse-tests-and-multiformat branch from 92257c8 to e5ee923 Compare April 23, 2026 14:57
Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rust/src/multi_format.rs`:
- Around line 164-196: The code incorrectly uses substring checks
(string.contains) to detect TapSigner vs SatsCard URLs causing
misclassification; update the detection to parse and normalize the URL (e.g.,
with url::Url::parse) and match the host and path prefix exactly (host ==
"tapsigner.com" and path starts_with "/start", or host == "getsatscard.com" and
path starts_with "/start") before calling cove_tap_card::TapCard::parse; replace
the two string.contains branches with host/path checks and keep the same
handling using TapCard::parse, Self::from(card), Self::SatsCard(card), and the
existing Self::invalid_tap_signer / Self::invalid_sats_card error constructors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b42bf06-3e07-4ebf-8721-849eebb7f020

📥 Commits

Reviewing files that changed from the base of the PR and between 92257c8 and e5ee923.

⛔ Files ignored due to path filters (1)
  • ios/CoveCore/Sources/CoveCore/generated/cove.swift is excluded by !**/generated/**
📒 Files selected for processing (3)
  • android/app/src/main/java/org/bitcoinppl/cove_core/cove.kt
  • rust/crates/cove-tap-card/src/parse.rs
  • rust/src/multi_format.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • rust/crates/cove-tap-card/src/parse.rs

Comment thread rust/src/multi_format.rs Outdated
@guptapratykshh guptapratykshh force-pushed the satscard-parse-tests-and-multiformat branch from e5ee923 to 8135fce Compare April 23, 2026 15:10
Add seven focused tests for SatsCard URL parsing covering
unsealed state, error state, missing fields, unknown state,
identity, and invalid domain. Add SatsCard variant to
MultiFormat enum and getsatscard.com URL detection branch.
@guptapratykshh guptapratykshh force-pushed the satscard-parse-tests-and-multiformat branch from 8135fce to 2dda28a Compare April 23, 2026 15:28
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