From b27baf5decf179b1bf9936414aeeee4359b641b7 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 26 Jan 2026 12:42:27 -0800 Subject: [PATCH] Fixed UID length bug for product suggestions re: MFC and payment verbiage --- app.json | 3 +- eas.json | 6 ++ src/data/products.ts | 94 ++++------------- src/hooks/useScan.ts | 40 +++++--- src/screens/ResultScreen.tsx | 60 +++++++---- src/screens/ScanScreen.tsx | 27 ++++- src/services/detection/desfire.ts | 155 +++++++++++++++++++++++++---- src/services/detection/detector.ts | 27 +++-- src/services/detection/iso15693.ts | 11 +- src/services/matching/matcher.ts | 14 ++- src/services/nfc/NFCManager.ts | 44 ++++++++ src/types/nfc.ts | 16 +++ 12 files changed, 349 insertions(+), 148 deletions(-) diff --git a/app.json b/app.json index f4df187..7689f54 100644 --- a/app.json +++ b/app.json @@ -14,7 +14,8 @@ "supportsTablet": false, "bundleIdentifier": "com.dangerousthings.nfcidentifier", "infoPlist": { - "NFCReaderUsageDescription": "This app uses NFC to scan transponders and identify compatible Dangerous Things implants." + "NFCReaderUsageDescription": "This app uses NFC to scan transponders and identify compatible Dangerous Things implants.", + "ITSAppUsesNonExemptEncryption": false } }, "android": { diff --git a/eas.json b/eas.json index f4001c5..382762d 100644 --- a/eas.json +++ b/eas.json @@ -11,6 +11,12 @@ "preview": { "distribution": "internal" }, + "preview-apk": { + "distribution": "internal", + "android": { + "buildType": "apk" + } + }, "production": { "autoIncrement": true } diff --git a/src/data/products.ts b/src/data/products.ts index a2c439e..2945a61 100644 --- a/src/data/products.ts +++ b/src/data/products.ts @@ -8,7 +8,7 @@ * Discontinued products removed per https://forum.dangerousthings.com/t/shes-dead-jim/26308 */ -import {ChipType} from '../types/detection'; +import { ChipType } from '../types/detection'; import { Product, FormFactor, @@ -72,7 +72,7 @@ export const PRODUCTS: Product[] = [ id: 'xnt', name: 'xNT', description: - 'NFC Type 2 implant with 888 bytes of user memory. The original and most popular NFC implant.', + 'NFC Type 2 implant with 888 bytes of user memory.', formFactor: FormFactor.X_SERIES, categories: [ProductCategory.NFC], compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE], @@ -96,9 +96,9 @@ export const PRODUCTS: Product[] = [ compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE], features: [ 'NTAG I2C chip', - '888 bytes user memory', - 'Built-in LED indicator', - 'Multiple colors available', + '1kB user memory', + 'URL/contact sharing', + 'Red, Green, Blue, and White LEDs available', ], url: 'https://dangerousthings.com/product/xsiid/', canReceiveClone: true, @@ -107,14 +107,14 @@ export const PRODUCTS: Product[] = [ { id: 'xslx', name: 'xSLX', - description: 'ISO 15693 NFC-V implant using ICODE SLIX chip.', + description: 'NFC Type 5 implant using ICODE SLIX chip.', formFactor: FormFactor.X_SERIES, categories: [ProductCategory.NFC], compatibleChips: [...SLIX_COMPATIBLE], features: [ 'ICODE SLIX chip', - 'ISO 15693 (NFC-V)', - 'Long range capability', + '320 bbytes user memory', + 'URL/contact sharing', ], url: 'https://dangerousthings.com/product/xslx/', canReceiveClone: true, @@ -133,10 +133,11 @@ export const PRODUCTS: Product[] = [ categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS], compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE], features: [ + 'Dual-frequency', 'NTAG216 NFC chip', + '888 bytes user memory', 'T5577 125kHz chip', - 'Dual-frequency capability', - 'HID/EM compatible', + 'LF access control', ], url: 'https://dangerousthings.com/product/next/', canReceiveClone: true, @@ -147,15 +148,17 @@ export const PRODUCTS: Product[] = [ id: 'next-v2', name: 'NExT v2', description: - 'Updated dual-frequency implant with NTAG I2C, T5577, and built-in LED indicator.', + 'Updated dual-frequency implant with NTAG I2C, T5577, and built-in LED.', formFactor: FormFactor.X_SERIES, categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS, ProductCategory.LED], compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE], features: [ 'NTAG I2C NFC chip', + '1kB user memory', + 'URL/contact sharing', + 'Green, Blue, and White LEDs available (HF)', 'T5577 125kHz chip', - 'Built-in LED indicator', - '888 bytes user memory', + 'LF access control', ], url: 'https://dangerousthings.com/product/next-v2/', canReceiveClone: true, @@ -240,38 +243,15 @@ export const PRODUCTS: Product[] = [ categories: [ProductCategory.SECURE], compatibleChips: [ChipType.NTAG424_DNA, ChipType.NTAG424_DNA_TT, ChipType.ICODE_DNA], features: [ - 'Cryptographic authentication', - 'VivoKey identity platform', - 'Secure web login', - 'Digital signatures', + 'Spark Actions', + 'Verify API', ], - url: 'https://dangerousthings.com/product/vivokey-spark-2/', + url: 'https://dangerousthings.com/product/vivokey-spark/', canReceiveClone: false, exactMatch: true, notes: 'Uses cryptographic authentication - cannot clone', }, - // ========================================================================== - // X-Series - LED/Special - // ========================================================================== - { - id: 'xglow', - name: 'xGlow', - description: 'Implant with LED that glows when exposed to NFC field.', - formFactor: FormFactor.X_SERIES, - categories: [ProductCategory.LED], - compatibleChips: [], // No NFC storage - features: [ - 'LED indicator', - 'Multiple colors', - 'Field detection', - ], - url: 'https://dangerousthings.com/product/xglow/', - canReceiveClone: false, - exactMatch: false, - notes: 'LED only - no NFC data storage', - }, - // ========================================================================== // Bioresin Implants - Larger capsules (incision install) // ========================================================================== @@ -313,25 +293,6 @@ export const PRODUCTS: Product[] = [ exactMatch: false, notes: 'Can clone MIFARE Classic cards (requires Android + keys)', }, - { - id: 'dt5', - name: 'dT5', - description: - 'Bioresin 125kHz implant with T5577 chip for access control systems.', - formFactor: FormFactor.BIORESIN, - categories: [ProductCategory.ACCESS], - compatibleChips: [], // 125kHz only, no NFC - features: [ - 'T5577 125kHz chip', - 'EM41xx emulation', - 'HID ProxCard compatible', - 'Bioresin encapsulation', - ], - url: 'https://dangerousthings.com/product/dt5/', - canReceiveClone: false, - exactMatch: false, - notes: '125kHz only - no NFC capability', - }, // ========================================================================== // Flex Implants - NFC @@ -482,23 +443,6 @@ export const PRODUCTS: Product[] = [ exactMatch: false, notes: 'For HID iCLASS systems only', }, - { - id: 'teslaflex', - name: 'TeslaFlex', - description: 'Implant designed to work as a Tesla key card.', - formFactor: FormFactor.FLEX, - categories: [ProductCategory.ACCESS], - compatibleChips: [], // Tesla proprietary - features: [ - 'Tesla key card compatible', - 'Flexible form factor', - 'Direct Tesla integration', - ], - url: 'https://dangerousthings.com/product/teslaflex/', - canReceiveClone: false, - exactMatch: false, - notes: 'Specifically for Tesla vehicles', - }, { id: 'flexug4', name: 'flexUG4', diff --git a/src/hooks/useScan.ts b/src/hooks/useScan.ts index cbe62be..193062f 100644 --- a/src/hooks/useScan.ts +++ b/src/hooks/useScan.ts @@ -25,7 +25,7 @@ export interface UseScanResult { /** Scanned tag data (when state is 'success') */ tag: RawTagData | null; /** Detected transponder info (when detection succeeds) */ - transponder: Transponder | null; + transponder: Transponder | null | undefined; /** Scan error (when state is 'error') */ error: ScanError | null; /** NFC status (supported and enabled) */ @@ -45,10 +45,19 @@ export interface UseScanResult { /** * Hook for managing NFC scanning */ +// Combined scan result to ensure atomic updates +interface ScanResult { + tag: RawTagData | null; + transponder: Transponder | null | undefined; +} + export function useScan(): UseScanResult { const [state, setState] = useState('idle'); - const [tag, setTag] = useState(null); - const [transponder, setTransponder] = useState(null); + // Use combined state to ensure tag and transponder update atomically + const [scanResult, setScanResult] = useState({ + tag: null, + transponder: undefined, + }); const [error, setError] = useState(null); const [nfcStatus, setNfcStatus] = useState({ isSupported: false, @@ -93,8 +102,7 @@ export function useScan(): UseScanResult { scanInProgress.current = true; setState('scanning'); - setTag(null); - setTransponder(null); + setScanResult({ tag: null, transponder: undefined }); setError(null); setScanProgress({step: 'Waiting for tag...', current: 1}); @@ -162,11 +170,18 @@ export function useScan(): UseScanResult { setError(result.error); } } else if (result.tag) { + const detectedTransponder = result.detection ?? null; + console.log('[useScan] Scan complete:', { + hasTag: !!result.tag, + hasDetection: !!result.detection, + transponderType: detectedTransponder?.type, + }); + // Update tag and transponder atomically in a single state update + setScanResult({ + tag: result.tag, + transponder: detectedTransponder, + }); setState('success'); - setTag(result.tag); - if (result.detection) { - setTransponder(result.detection); - } } else { setState('error'); setError({ @@ -201,8 +216,7 @@ export function useScan(): UseScanResult { // Reset state to idle const reset = useCallback(() => { setState('idle'); - setTag(null); - setTransponder(null); + setScanResult({ tag: null, transponder: undefined }); setError(null); setScanProgress(null); }, []); @@ -219,8 +233,8 @@ export function useScan(): UseScanResult { return { state, - tag, - transponder, + tag: scanResult.tag, + transponder: scanResult.transponder, error, nfcStatus, scanProgress, diff --git a/src/screens/ResultScreen.tsx b/src/screens/ResultScreen.tsx index 2940b3f..0d06efa 100644 --- a/src/screens/ResultScreen.tsx +++ b/src/screens/ResultScreen.tsx @@ -15,7 +15,7 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { // Match chip to products const matchResult = useMemo(() => { if (!transponder) return null; - return matchChipToProducts(transponder.type); + return matchChipToProducts(transponder); }, [transponder]); // Get educational chip info @@ -449,32 +449,42 @@ export function ResultScreen({ route, navigation }: ResultScreenProps) { Unable to identify this chip type. It may be unsupported or require advanced detection. - - )} - - {/* Conversion Service Card - show for payment devices, or when recommended and not a real implant */} - {(transponder?.implantName?.includes('Payment Card') || - ((matchResult?.conversionRecommended || !transponder) && !transponder?.implantName)) && ( - - - {transponder?.implantName?.includes('Payment Card') - ? "Payment cards can't be converted to implants due to security restrictions. Our conversion service can help you find an implant that works with your use case." - : !transponder - ? 'Unknown chip? Our conversion service can help.' - : matchResult?.isCloneable === false - ? "This chip uses cryptographic protection and can't be cloned. Our conversion service can help find alternatives." - : "No direct product match found. Our conversion service can help."} + + Need help? Ask on our forum for assistance. )} + {/* Conversion Service Card - show for payment devices, or when recommended (but NOT for unidentified chips) */} + {transponder && (transponder?.implantName?.includes('Payment Card') || + (matchResult?.conversionRecommended && !transponder?.implantName)) && ( + + + {transponder?.implantName?.includes('Payment Card') + ? "Payment cards can't be copied/cloned to implants. Our conversion service might be an option." + : !transponder + ? 'Unknown chip? Our conversion service can help.' + : matchResult?.isCloneable === false + ? "This chip uses cryptographic protection and can't be cloned. Our conversion service can help find alternatives." + : "No direct product match found. Our conversion service can help."} + + + + )} + {/* Action Buttons */}