Files
dt-nfc-identifier/CLAUDE.md
2026-01-22 13:55:55 -08:00

12 KiB

CLAUDE.md - Project Intelligence for Dangerous Things NFC Identifier

Project Overview

React Native app that scans NFC transponders and matches them to Dangerous Things implant products. Target users are prospective customers who want to know which implant can replace their existing cards/fobs.

Critical Context

NFC Detection Strategy

The app must identify transponders using a waterfall detection approach:

1. Read basic tag info (UID, ATQA, SAK for 14443-A)
2. Determine tag technology class
3. Run technology-specific identification:
   - NTAG: Send GET_VERSION (0x60) command
   - MIFARE Classic: SAK identifies 1K (0x08) vs 4K (0x18)
   - ISO 14443-4: Parse ATS/historical bytes, then:
     - DESFire: Check for DESFire ATS signature
     - MIFARE Plus: Check for Plus ATS signature
     - JavaCard: GET DATA for CPLC, probe known AIDs
   - ISO 15693: Get system info for SLIX identification

Platform Differences

Android - Full access via NfcA, NfcB, IsoDep, NfcV, MifareClassic tech classes. Can send raw commands.

iOS - CoreNFC with NFCISO7816Tag and NFCISO15693Tag. Provides:

  • historicalBytes (from ATS) - use for card platform identification
  • identifier (UID)
  • APDU commands via sendCommand()
  • NO access to MIFARE Classic sectors (no crypto support)

iOS MIFARE Classic limitation: iOS cannot read MIFARE Classic as a distinct technology. It appears as an ISO 14443-3A tag. Detection relies on SAK value (0x08 or 0x18) but sector-level operations are Android-only.

JavaCard (J3R180) Detection

For JCOP4/J3R180 identification:

  1. Check historicalBytes for JCOP signatures (4A434F50 = "JCOP")
  2. GET DATA for CPLC: 80 CA 9F 7F 00
  3. Parse CPLC for IC fabricator (NXP = 4790), card type, OS ID
  4. Probe AIDs for installed applets (user may provide DT-specific AIDs)

Product Matching Logic

interface Transponder {
  type: ChipType;
  subtype?: string;        // e.g., "NTAG215" vs "NTAG216"
  memorySize?: number;
  isCloneable: boolean;
  rawData: {
    uid: string;
    sak?: number;
    atqa?: string;
    ats?: string;
    historicalBytes?: string;
    cplc?: CPLCData;
  };
}

interface Product {
  id: string;
  name: string;
  compatibleChips: ChipType[];
  description: string;
  features: string[];
}

Cloneable chips:

  • NTAG213/215/216 (data can be written to compatible implant)
  • MIFARE Classic 1K/4K (requires key knowledge; Android only for sector ops)
  • SLIX/SLIX2 (data can be written)

Non-cloneable: DESFire, MIFARE Plus, JavaCard (crypto prevents duplication)

When no match found, direct to: dngr.us/conversion

Design System

Base theme on /home/work/WebstormProjects/dt-shopify-storefront/app/styles/app.css

Colors (CSS variables → RN)

const DTColors = {
  dark: '#000000',
  light: '#FFFFFF',
  modeNormal: '#00FFFF',      // Cyan - primary actions
  modeNormalSelected: 'rgba(0, 255, 255, 0.7)',
  modeEmphasis: '#FFFF00',    // Yellow - highlights
  modeEmphasisSelected: 'rgba(255, 255, 0, 0.7)',
  modeWarning: '#FF0000',     // Red - errors/warnings
  modeSuccess: '#00FF00',     // Green - success states
  modeOther: '#FF00FF',       // Magenta - misc
};

Typography

  • Primary font: "Tektur" (variable font, weights 100-900)
  • Fallback: System default

UI Patterns

  • Beveled corners: Use clip-path equivalent or custom shapes
  • Cards: Black background, colored borders, beveled bottom-right
  • Buttons: Outlined with mode color, filled on hover/press
  • Emphasis: Yellow for important actions, cyan for standard

Tech Stack Decisions

Concern Choice Rationale
NFC react-native-nfc-manager Industry standard, good iOS/Android support
UI React Native Paper Material Design 3, easy theming
State React Context Simple app, no complex state needs
Navigation React Navigation Standard choice
Types TypeScript strict Prevent NFC data handling bugs

File Organization

src/
├── App.tsx                 # Entry point, providers
├── components/
│   ├── ui/                 # Themed RNP components
│   │   ├── DTCard.tsx
│   │   ├── DTButton.tsx
│   │   └── DTChip.tsx
│   ├── scan/               # Scan-related components
│   │   ├── ScanButton.tsx
│   │   └── ScanAnimation.tsx
│   └── results/            # Result display components
│       ├── TransponderInfo.tsx
│       ├── ProductMatch.tsx
│       └── NoMatchFound.tsx
├── screens/
│   ├── HomeScreen.tsx
│   ├── ScanScreen.tsx
│   └── ResultScreen.tsx
├── services/
│   ├── nfc/
│   │   ├── NFCManager.ts       # Wrapper around react-native-nfc-manager
│   │   ├── commands.ts         # APDU command builders
│   │   └── platforms.ts        # Platform-specific logic
│   ├── detection/
│   │   ├── detector.ts         # Main detection orchestrator
│   │   ├── ntag.ts             # NTAG identification
│   │   ├── mifare.ts           # MIFARE Classic/Plus/DESFire
│   │   ├── iso15693.ts         # SLIX detection
│   │   └── javacard.ts         # J3R180/JCOP detection
│   └── matching/
│       └── matcher.ts          # Product matching logic
├── data/
│   ├── products.ts             # Hardcoded product catalog
│   └── chipProfiles.ts         # Chip identification signatures
├── theme/
│   ├── colors.ts
│   ├── typography.ts
│   └── paperTheme.ts           # RNP theme configuration
├── types/
│   ├── nfc.ts                  # NFC-related types
│   ├── products.ts             # Product types
│   └── detection.ts            # Detection result types
├── hooks/
│   ├── useNFC.ts
│   └── useScan.ts
└── utils/
    ├── hex.ts                  # Hex string utilities
    ├── apdu.ts                 # APDU parsing utilities
    └── platform.ts             # Platform detection

Development Phases (Context-Optimized)

Phase 1: Foundation (Single Session)

Goal: Bootable app with theme and navigation

  • Initialize RN project with TypeScript
  • Install dependencies (RNP, react-native-nfc-manager, navigation)
  • Create theme system from DT colors
  • Set up basic navigation (Home → Scan → Results)
  • Create placeholder screens

Deliverable: App runs on both platforms with DT styling

Phase 2: NFC Infrastructure (Single Session)

Goal: NFC scanning works on both platforms

  • Implement NFCManager wrapper
  • Handle permissions (Android manifest, iOS entitlements)
  • Create useScan hook with states (idle, scanning, success, error)
  • Test basic tag detection (just read UID)

Deliverable: App can detect NFC tag presence

Phase 3: Chip Detection - Basic (Single Session)

Goal: Identify common chip types

  • Implement NTAG detection (GET_VERSION)
  • Implement MIFARE Classic detection (SAK-based)
  • Create detection result types
  • Display raw detection results

Deliverable: App identifies NTAG and MIFARE Classic

Phase 4: Chip Detection - Advanced (Single Session)

Goal: Full chip identification suite

  • Implement ISO 14443-4 detection (DESFire, Plus)
  • Implement ISO 15693 detection (SLIX)
  • Implement JavaCard detection (CPLC + AID probing)
  • Handle platform differences gracefully

Deliverable: App identifies all target chip types

Phase 5: Product Matching (Single Session)

Goal: Match transponders to products

  • Create product data structure
  • Populate with DT product catalog
  • Implement matching algorithm
  • Create result UI components
  • Add "no match" handling with conversion link

Deliverable: Full transponder-to-implant flow complete

Phase 6: Polish (Single Session)

Goal: Production-ready UX

  • Add scan animations
  • Implement error handling UI
  • Add educational chip info
  • Test edge cases
  • Performance optimization

Deliverable: App ready for release

Common Patterns

APDU Command Structure

// Command APDU: CLA INS P1 P2 [Lc] [Data] [Le]
const GET_CPLC = [0x80, 0xCA, 0x9F, 0x7F, 0x00];
const SELECT_AID = (aid: number[]) => [0x00, 0xA4, 0x04, 0x00, aid.length, ...aid, 0x00];

// DESFire GET_VERSION (ISO-wrapped for cross-platform support)
// Response byte 3 = HW major: 0x00=EV0, 0x01=EV1, 0x10=EV2, 0x30=EV3
const DESFIRE_GET_VERSION = [0x90, 0x60, 0x00, 0x00, 0x00];

Platform-Safe NFC Code

import { Platform } from 'react-native';
import NfcManager, { NfcTech } from 'react-native-nfc-manager';

async function detectTag() {
  if (Platform.OS === 'ios') {
    // iOS: Use ISO 7816 for everything 14443-4
    await NfcManager.requestTechnology(NfcTech.Iso7816);
  } else {
    // Android: Can be more specific
    await NfcManager.requestTechnology([
      NfcTech.IsoDep,
      NfcTech.NfcA,
      NfcTech.MifareClassic,
    ]);
  }
}

Error Boundaries for NFC

Always wrap NFC operations in try/catch. Common errors:

  • Tag lost during read
  • Unsupported tag type
  • Permission denied
  • NFC disabled on device

Testing Notes

Physical Test Cards Needed

  • NTAG213, NTAG215, NTAG216
  • MIFARE Classic 1K, 4K
  • MIFARE DESFire EV1/EV2/EV3
  • MIFARE Plus
  • SLIX/SLIX2
  • J3R180/JCOP4 card

Simulator Limitations

NFC cannot be tested in simulators. Use physical devices only.

Known Issues & Workarounds

  1. iOS MIFARE Classic: Cannot do sector operations. Only detect via SAK, inform user of Android requirement for cloning.

  2. iOS Background Reading: Not supported. App must be foregrounded.

  3. Android NFC Intent Handling: May need to handle onNewIntent for tags scanned while app is open.

  4. react-native-nfc-manager quirks: Always call NfcManager.cancelTechnologyRequest() in finally blocks.

Commands

# Development
npm start                    # Start Metro bundler
npm run android              # Run on Android
npm run ios                  # Run on iOS

# Type checking
npm run typecheck            # Run TypeScript compiler

# Linting
npm run lint                 # ESLint
npm run lint:fix             # ESLint with auto-fix

# Testing (when tests exist)
npm test                     # Run Jest tests

Environment Setup Checklist

Android

  • android/app/src/main/AndroidManifest.xml has NFC permissions
  • Min SDK 21+ (for robust NFC support)
  • NFC intent filters configured

iOS

  • NFC capability added in Xcode
  • NFCReaderUsageDescription in Info.plist
  • com.apple.developer.nfc.readersession.iso7816.select-identifiers for AID selection
  • com.apple.developer.nfc.readersession.iso15693.select-identifiers for SLIX

AID Reference (For JavaCard Profiling)

Dangerous Things may provide specific AIDs for their applets. Common AIDs:

const KNOWN_AIDS = {
  // Global Platform Card Manager
  cardManager: [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00],

  // VivoKey-specific (placeholder - get actual AIDs from DT)
  // vivoKeyAuth: [...],
  // vivoKeyOTP: [...],

  // Standard applets
  openPGP: [0xD2, 0x76, 0x00, 0x01, 0x24, 0x01],
  fido: [0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01],
};

Conversation Starters for Future Sessions

When resuming work, start with:

  1. "Continue from Phase N of the roadmap"
  2. "The current blocker is..."
  3. "Need to implement [specific detector/component]"

Always check package.json and run npm install if dependencies seem missing.