Add product matching service with DT implant catalog
- Add product catalog with current DT implants (X-Series, Flex, Bioresin) - Implement chip-to-product matching algorithm - Add DESFire EV level tracking with mismatch warnings - Display compatible implants on ResultScreen with product details - Remove discontinued products: xDF (EV1), xDF2 (EV2), flexDF (EV1) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
571
src/data/products.ts
Normal file
571
src/data/products.ts
Normal file
@@ -0,0 +1,571 @@
|
|||||||
|
/**
|
||||||
|
* Dangerous Things Product Catalog
|
||||||
|
*
|
||||||
|
* This contains the implant products available from Dangerous Things
|
||||||
|
* and their chip compatibility information.
|
||||||
|
*
|
||||||
|
* Updated based on https://dangerousthings.com/category/implants/
|
||||||
|
* Discontinued products removed per https://forum.dangerousthings.com/t/shes-dead-jim/26308
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ChipType} from '../types/detection';
|
||||||
|
import {
|
||||||
|
Product,
|
||||||
|
FormFactor,
|
||||||
|
ProductCategory,
|
||||||
|
ChipProductMap,
|
||||||
|
} from '../types/products';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chip types that can be cloned to NTAG216-based implants
|
||||||
|
* Any NTAG21x data can be written to an NTAG216 (same NFC Type 2 protocol)
|
||||||
|
*/
|
||||||
|
const NTAG21X_COMPATIBLE: ChipType[] = [
|
||||||
|
ChipType.NTAG213,
|
||||||
|
ChipType.NTAG215,
|
||||||
|
ChipType.NTAG216,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NTAG I2C compatible chips
|
||||||
|
*/
|
||||||
|
const NTAG_I2C_COMPATIBLE: ChipType[] = [
|
||||||
|
ChipType.NTAG_I2C_1K,
|
||||||
|
ChipType.NTAG_I2C_2K,
|
||||||
|
ChipType.NTAG_I2C_PLUS_1K,
|
||||||
|
ChipType.NTAG_I2C_PLUS_2K,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MIFARE Classic compatible chips (for magic card cloning)
|
||||||
|
*/
|
||||||
|
const MIFARE_CLASSIC_COMPATIBLE: ChipType[] = [
|
||||||
|
ChipType.MIFARE_CLASSIC_1K,
|
||||||
|
ChipType.MIFARE_CLASSIC_4K,
|
||||||
|
ChipType.MIFARE_CLASSIC_MINI,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All DESFire chips - any DESFire product works with any DESFire chip
|
||||||
|
*/
|
||||||
|
const DESFIRE_ALL: ChipType[] = [
|
||||||
|
ChipType.DESFIRE_EV1,
|
||||||
|
ChipType.DESFIRE_EV2,
|
||||||
|
ChipType.DESFIRE_EV3,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICODE SLIX compatible
|
||||||
|
*/
|
||||||
|
const SLIX_COMPATIBLE: ChipType[] = [
|
||||||
|
ChipType.SLIX,
|
||||||
|
ChipType.SLIX2,
|
||||||
|
ChipType.SLIX_S,
|
||||||
|
ChipType.SLIX_L,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const PRODUCTS: Product[] = [
|
||||||
|
// ==========================================================================
|
||||||
|
// X-Series (Glass Capsule) Implants - NFC
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'xnt',
|
||||||
|
name: 'xNT',
|
||||||
|
description:
|
||||||
|
'NFC Type 2 implant with 888 bytes of user memory. The original and most popular NFC implant.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.NFC],
|
||||||
|
compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'NTAG216 chip',
|
||||||
|
'888 bytes user memory',
|
||||||
|
'NFC Type 2 tag',
|
||||||
|
'URL/contact sharing',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/xnt/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'xsiid',
|
||||||
|
name: 'xSIID',
|
||||||
|
description:
|
||||||
|
'NFC implant with built-in LED that blinks when scanned. Multiple color options available.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.NFC, ProductCategory.LED],
|
||||||
|
compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'NTAG I2C chip',
|
||||||
|
'888 bytes user memory',
|
||||||
|
'Built-in LED indicator',
|
||||||
|
'Multiple colors available',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/xsiid/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'xslx',
|
||||||
|
name: 'xSLX',
|
||||||
|
description: 'ISO 15693 NFC-V 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',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/xslx/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// X-Series - Dual Frequency (NFC + 125kHz)
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'next',
|
||||||
|
name: 'NExT',
|
||||||
|
description:
|
||||||
|
'Original dual-frequency implant combining NTAG216 (NFC) with T5577 (125kHz).',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'NTAG216 NFC chip',
|
||||||
|
'T5577 125kHz chip',
|
||||||
|
'Dual-frequency capability',
|
||||||
|
'HID/EM compatible',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/next/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Also includes T5577 for 125kHz access systems',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'next-v2',
|
||||||
|
name: 'NExT v2',
|
||||||
|
description:
|
||||||
|
'Updated dual-frequency implant with NTAG I2C, T5577, and built-in LED indicator.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS, ProductCategory.LED],
|
||||||
|
compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'NTAG I2C NFC chip',
|
||||||
|
'T5577 125kHz chip',
|
||||||
|
'Built-in LED indicator',
|
||||||
|
'888 bytes user memory',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/next-v2/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Also includes T5577 for 125kHz access systems',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'xmagic',
|
||||||
|
name: 'xMagic',
|
||||||
|
description:
|
||||||
|
'Dual-frequency implant with magic MIFARE Classic (changeable UID) and T5577.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...MIFARE_CLASSIC_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'Magic MIFARE Classic chip',
|
||||||
|
'Changeable UID',
|
||||||
|
'T5577 125kHz chip',
|
||||||
|
'Clone access cards',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/xmagic/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: false,
|
||||||
|
notes: 'Can clone MIFARE Classic cards (requires Android + keys)',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// X-Series - DESFire (Secure NFC)
|
||||||
|
// Note: xDF (EV1) and xDF2 (EV2) discontinued - see flexDF/flexDF2 for those
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'xdf3',
|
||||||
|
name: 'xDF3',
|
||||||
|
description: 'Latest generation secure NFC implant using MIFARE DESFire EV3.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.SECURE, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...DESFIRE_ALL],
|
||||||
|
features: [
|
||||||
|
'DESFire EV3 chip',
|
||||||
|
'8KB memory',
|
||||||
|
'Latest security features',
|
||||||
|
'Transaction MAC',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/xdf3/',
|
||||||
|
canReceiveClone: false,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Cannot clone data due to cryptographic protection',
|
||||||
|
desfireEvLevel: 3,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// X-Series - Magic/Cloning
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'xm1',
|
||||||
|
name: 'xM1',
|
||||||
|
description: 'Magic MIFARE Classic 1K implant with changeable UID for cloning access cards.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
categories: [ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...MIFARE_CLASSIC_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'Magic MIFARE Classic 1K',
|
||||||
|
'Changeable UID',
|
||||||
|
'Clone access cards',
|
||||||
|
'Gen1a compatible',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/xm1/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: false,
|
||||||
|
notes: 'Can clone MIFARE Classic 1K cards (requires Android + keys)',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// X-Series - Cryptographic/Identity
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'spark2',
|
||||||
|
name: 'VivoKey Spark 2',
|
||||||
|
description:
|
||||||
|
'Cryptobionic identity implant for secure authentication and digital identity.',
|
||||||
|
formFactor: FormFactor.X_SERIES,
|
||||||
|
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',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/vivokey-spark-2/',
|
||||||
|
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)
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'dnext',
|
||||||
|
name: 'dNExT',
|
||||||
|
description:
|
||||||
|
'Jumbo-sized bioresin dual-frequency implant with NTAG216 (NFC) and T5577 (125kHz). Enhanced read range.',
|
||||||
|
formFactor: FormFactor.BIORESIN,
|
||||||
|
categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'NTAG216 NFC chip',
|
||||||
|
'T5577 125kHz chip',
|
||||||
|
'Enhanced read range',
|
||||||
|
'Bioresin encapsulation',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/dnext/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Larger size provides improved performance over x-series',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'dug4t',
|
||||||
|
name: 'dUG4T',
|
||||||
|
description:
|
||||||
|
'Bioresin dual-frequency implant with Ultimate Gen4 magic MIFARE and T5577 for maximum compatibility.',
|
||||||
|
formFactor: FormFactor.BIORESIN,
|
||||||
|
categories: [ProductCategory.DUAL_FREQUENCY, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...MIFARE_CLASSIC_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'Ultimate Gen4 magic chip',
|
||||||
|
'T5577 125kHz chip',
|
||||||
|
'Changeable UID',
|
||||||
|
'Enhanced cloning capability',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/dug4t/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
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
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'flexnt',
|
||||||
|
name: 'flexNT',
|
||||||
|
description:
|
||||||
|
'Flexible NTAG216 implant with larger antenna for improved read range.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.NFC],
|
||||||
|
compatibleChips: [...NTAG21X_COMPATIBLE, ...NTAG_I2C_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'NTAG216 chip',
|
||||||
|
'888 bytes user memory',
|
||||||
|
'Flexible form factor',
|
||||||
|
'Extended read range',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexnt/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Flex Implants - DESFire (Secure)
|
||||||
|
// Note: flexDF (EV1) discontinued - flexDF2 is current
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'flexdf2',
|
||||||
|
name: 'flexDF2',
|
||||||
|
description: 'Flexible DESFire EV2 implant with enhanced security.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.SECURE, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...DESFIRE_ALL],
|
||||||
|
features: [
|
||||||
|
'DESFire EV2 chip',
|
||||||
|
'8KB memory',
|
||||||
|
'AES-128 encryption',
|
||||||
|
'Flexible form factor',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexdf2/',
|
||||||
|
canReceiveClone: false,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Cannot clone data due to cryptographic protection',
|
||||||
|
desfireEvLevel: 2,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Flex Implants - Magic/Cloning
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'flexm1',
|
||||||
|
name: 'flexM1',
|
||||||
|
description: 'Flexible magic MIFARE Classic 1K implant for cloning access cards.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...MIFARE_CLASSIC_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'Magic MIFARE Classic 1K',
|
||||||
|
'Changeable UID',
|
||||||
|
'Flexible form factor',
|
||||||
|
'Extended read range',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexm1/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: false,
|
||||||
|
notes: 'Can clone MIFARE Classic 1K cards (requires Android + keys)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'flexm1-v2',
|
||||||
|
name: 'flexM1 v2',
|
||||||
|
description: 'Updated flexible magic MIFARE Classic 1K implant.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...MIFARE_CLASSIC_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'Magic MIFARE Classic 1K',
|
||||||
|
'Improved antenna design',
|
||||||
|
'Changeable UID',
|
||||||
|
'Better compatibility',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexm1-v2/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: false,
|
||||||
|
notes: 'Can clone MIFARE Classic 1K cards (requires Android + keys)',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Flex Implants - Secure Element / JavaCard
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'apex-flex',
|
||||||
|
name: 'Apex Flex',
|
||||||
|
description:
|
||||||
|
'The ultimate subdermal security key for digital identity, cryptography, and blockchain applications.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.SECURE],
|
||||||
|
compatibleChips: [ChipType.JCOP4, ChipType.JAVACARD_UNKNOWN],
|
||||||
|
features: [
|
||||||
|
'JCOP4 secure element',
|
||||||
|
'Fidesmo platform',
|
||||||
|
'Payment capable',
|
||||||
|
'FIDO2/WebAuthn',
|
||||||
|
'OTP support',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/apex-flex/',
|
||||||
|
canReceiveClone: false,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Cannot clone - programmable via Fidesmo app',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'flexsecure',
|
||||||
|
name: 'flexSecure',
|
||||||
|
description:
|
||||||
|
'Developer-friendly JavaCard implant for custom secure applications.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.SECURE],
|
||||||
|
compatibleChips: [ChipType.JCOP4, ChipType.JAVACARD_UNKNOWN],
|
||||||
|
features: [
|
||||||
|
'SmartMX3 P71 chip',
|
||||||
|
'Full JavaCard access',
|
||||||
|
'GlobalPlatformPro compatible',
|
||||||
|
'Custom applet support',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexsecure/',
|
||||||
|
canReceiveClone: false,
|
||||||
|
exactMatch: true,
|
||||||
|
notes: 'Developer-focused - requires technical knowledge',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Flex Implants - Access Control
|
||||||
|
// ==========================================================================
|
||||||
|
{
|
||||||
|
id: 'flexclass',
|
||||||
|
name: 'flexClass',
|
||||||
|
description: 'Flexible HID iCLASS compatible implant for enterprise access control.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.SECURE, ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [], // iCLASS uses proprietary protocol
|
||||||
|
features: [
|
||||||
|
'HID iCLASS SE compatible',
|
||||||
|
'Enterprise access control',
|
||||||
|
'Flexible form factor',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexclass/',
|
||||||
|
canReceiveClone: false,
|
||||||
|
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',
|
||||||
|
description: 'Flexible Ultimate Gen4 magic MIFARE implant for cloning access cards.',
|
||||||
|
formFactor: FormFactor.FLEX,
|
||||||
|
categories: [ProductCategory.ACCESS],
|
||||||
|
compatibleChips: [...MIFARE_CLASSIC_COMPATIBLE],
|
||||||
|
features: [
|
||||||
|
'Ultimate Gen4 magic chip',
|
||||||
|
'Changeable UID',
|
||||||
|
'Flexible form factor',
|
||||||
|
'Enhanced cloning capability',
|
||||||
|
],
|
||||||
|
url: 'https://dangerousthings.com/product/flexug4/',
|
||||||
|
canReceiveClone: true,
|
||||||
|
exactMatch: false,
|
||||||
|
notes: 'Can clone MIFARE Classic cards (requires Android + keys)',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a map of chip types to compatible products
|
||||||
|
*/
|
||||||
|
export function buildChipProductMap(): ChipProductMap {
|
||||||
|
const map: ChipProductMap = new Map();
|
||||||
|
|
||||||
|
for (const product of PRODUCTS) {
|
||||||
|
for (const chipType of product.compatibleChips) {
|
||||||
|
const existing = map.get(chipType) || [];
|
||||||
|
existing.push(product);
|
||||||
|
map.set(chipType, existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached chip-to-product map
|
||||||
|
*/
|
||||||
|
let chipProductMapCache: ChipProductMap | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the chip-to-product map (cached)
|
||||||
|
*/
|
||||||
|
export function getChipProductMap(): ChipProductMap {
|
||||||
|
if (!chipProductMapCache) {
|
||||||
|
chipProductMapCache = buildChipProductMap();
|
||||||
|
}
|
||||||
|
return chipProductMapCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversion service URL for chips that don't have direct matches
|
||||||
|
*/
|
||||||
|
export const CONVERSION_SERVICE_URL = 'https://dngr.us/conversion';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all products
|
||||||
|
*/
|
||||||
|
export function getAllProducts(): Product[] {
|
||||||
|
return PRODUCTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get product by ID
|
||||||
|
*/
|
||||||
|
export function getProductById(id: string): Product | undefined {
|
||||||
|
return PRODUCTS.find(p => p.id === id);
|
||||||
|
}
|
||||||
@@ -1,14 +1,26 @@
|
|||||||
import React from 'react';
|
import React, {useMemo} from 'react';
|
||||||
import {StyleSheet, View, ScrollView, Linking} from 'react-native';
|
import {StyleSheet, View, ScrollView, Linking} from 'react-native';
|
||||||
import {Button, Text, Surface, Divider, Chip} from 'react-native-paper';
|
import {Button, Text, Surface, Divider, Chip} from 'react-native-paper';
|
||||||
import type {ResultScreenProps} from '../types/navigation';
|
import type {ResultScreenProps} from '../types/navigation';
|
||||||
import {DTColors} from '../theme';
|
import {DTColors} from '../theme';
|
||||||
|
import {matchChipToProducts, getMatchSummary, getDesfireEvMismatchWarning} from '../services/matching';
|
||||||
|
import {Product} from '../types/products';
|
||||||
|
|
||||||
export function ResultScreen({route, navigation}: ResultScreenProps) {
|
export function ResultScreen({route, navigation}: ResultScreenProps) {
|
||||||
const {tagData, transponder} = route.params;
|
const {tagData, transponder} = route.params;
|
||||||
|
|
||||||
|
// Match chip to products
|
||||||
|
const matchResult = useMemo(() => {
|
||||||
|
if (!transponder) return null;
|
||||||
|
return matchChipToProducts(transponder.type);
|
||||||
|
}, [transponder]);
|
||||||
|
|
||||||
const handleConversionLink = () => {
|
const handleConversionLink = () => {
|
||||||
Linking.openURL('https://dngr.us/conversion');
|
Linking.openURL(matchResult?.conversionUrl || 'https://dngr.us/conversion');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProductLink = (product: Product) => {
|
||||||
|
Linking.openURL(product.url);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine card colors based on detection
|
// Determine card colors based on detection
|
||||||
@@ -87,6 +99,99 @@ export function ResultScreen({route, navigation}: ResultScreenProps) {
|
|||||||
</Surface>
|
</Surface>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Product Matches Card */}
|
||||||
|
{transponder && matchResult && (matchResult.exactMatches.length > 0 || matchResult.cloneTargets.length > 0) && (
|
||||||
|
<Surface style={styles.productsCard} elevation={1}>
|
||||||
|
<Text variant="labelLarge" style={styles.productsLabel}>
|
||||||
|
COMPATIBLE IMPLANTS
|
||||||
|
</Text>
|
||||||
|
<Divider style={[styles.divider, {backgroundColor: DTColors.modeEmphasis}]} />
|
||||||
|
|
||||||
|
<Text variant="bodyMedium" style={styles.matchSummary}>
|
||||||
|
{getMatchSummary(matchResult, transponder.chipName)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{/* Exact Matches / Clone Targets */}
|
||||||
|
{[...matchResult.exactMatches, ...matchResult.cloneTargets.filter(
|
||||||
|
p => !matchResult.exactMatches.find(e => e.id === p.id)
|
||||||
|
)].map(product => (
|
||||||
|
<Surface key={product.id} style={styles.productItem} elevation={0}>
|
||||||
|
<View style={styles.productHeader}>
|
||||||
|
<Text variant="titleMedium" style={styles.productName}>
|
||||||
|
{product.name}
|
||||||
|
</Text>
|
||||||
|
<Chip
|
||||||
|
style={styles.formFactorChip}
|
||||||
|
textStyle={styles.formFactorChipText}>
|
||||||
|
{product.formFactor.replace('_', ' ')}
|
||||||
|
</Chip>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text variant="bodySmall" style={styles.productDescription}>
|
||||||
|
{product.description}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{product.notes && (
|
||||||
|
<Text variant="bodySmall" style={styles.productNote}>
|
||||||
|
Note: {product.notes}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* DESFire EV mismatch warning */}
|
||||||
|
{getDesfireEvMismatchWarning(transponder.type, product) && (
|
||||||
|
<Text variant="bodySmall" style={styles.evMismatchWarning}>
|
||||||
|
⚠️ {getDesfireEvMismatchWarning(transponder.type, product)}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<View style={styles.productFeatures}>
|
||||||
|
{product.features.slice(0, 3).map((feature, idx) => (
|
||||||
|
<Text key={idx} variant="bodySmall" style={styles.productFeature}>
|
||||||
|
• {feature}
|
||||||
|
</Text>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
mode="outlined"
|
||||||
|
onPress={() => handleProductLink(product)}
|
||||||
|
style={styles.productButton}
|
||||||
|
labelStyle={styles.productButtonLabel}
|
||||||
|
compact>
|
||||||
|
VIEW PRODUCT
|
||||||
|
</Button>
|
||||||
|
</Surface>
|
||||||
|
))}
|
||||||
|
</Surface>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* No Match Card - show when chip detected but no products match */}
|
||||||
|
{transponder && matchResult && matchResult.exactMatches.length === 0 && matchResult.cloneTargets.length === 0 && (
|
||||||
|
<Surface style={styles.noMatchCard} elevation={1}>
|
||||||
|
<Text variant="labelLarge" style={styles.noMatchLabel}>
|
||||||
|
NO DIRECT MATCH
|
||||||
|
</Text>
|
||||||
|
<Divider style={[styles.divider, {backgroundColor: DTColors.modeOther}]} />
|
||||||
|
|
||||||
|
<Text variant="bodyMedium" style={styles.noMatchText}>
|
||||||
|
{getMatchSummary(matchResult, transponder.chipName)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{matchResult.familyMatches.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Text variant="bodySmall" style={styles.familyMatchesLabel}>
|
||||||
|
Related products in the same chip family:
|
||||||
|
</Text>
|
||||||
|
{matchResult.familyMatches.slice(0, 2).map(product => (
|
||||||
|
<Text key={product.id} variant="bodySmall" style={styles.familyMatchItem}>
|
||||||
|
• {product.name}
|
||||||
|
</Text>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Surface>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* SAK Swap Detection Card */}
|
{/* SAK Swap Detection Card */}
|
||||||
{transponder?.sakSwapInfo?.hasSakSwap && (
|
{transponder?.sakSwapInfo?.hasSakSwap && (
|
||||||
<Surface style={styles.sakSwapCard} elevation={1}>
|
<Surface style={styles.sakSwapCard} elevation={1}>
|
||||||
@@ -195,11 +300,15 @@ export function ResultScreen({route, navigation}: ResultScreenProps) {
|
|||||||
</Surface>
|
</Surface>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Conversion Service Card - only show if chip is NOT cloneable */}
|
{/* Conversion Service Card - show when recommended */}
|
||||||
{(!transponder || !transponder.isCloneable) && (
|
{(matchResult?.conversionRecommended || !transponder) && (
|
||||||
<Surface style={styles.conversionCard} elevation={1}>
|
<Surface style={styles.conversionCard} elevation={1}>
|
||||||
<Text variant="bodyMedium" style={styles.conversionText}>
|
<Text variant="bodyMedium" style={styles.conversionText}>
|
||||||
Can't clone this chip? Check out our conversion service.
|
{!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."}
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<Button
|
||||||
mode="outlined"
|
mode="outlined"
|
||||||
@@ -387,6 +496,113 @@ const styles = StyleSheet.create({
|
|||||||
color: DTColors.light,
|
color: DTColors.light,
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
},
|
},
|
||||||
|
// Products Card
|
||||||
|
productsCard: {
|
||||||
|
backgroundColor: '#0a0a0a',
|
||||||
|
borderRadius: 4,
|
||||||
|
borderWidth: 2,
|
||||||
|
borderColor: DTColors.modeEmphasis,
|
||||||
|
padding: 20,
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
productsLabel: {
|
||||||
|
color: DTColors.modeEmphasis,
|
||||||
|
letterSpacing: 2,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
matchSummary: {
|
||||||
|
color: DTColors.light,
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
productItem: {
|
||||||
|
backgroundColor: '#111111',
|
||||||
|
borderRadius: 4,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: DTColors.modeNormal,
|
||||||
|
padding: 16,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
productHeader: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
productName: {
|
||||||
|
color: DTColors.modeEmphasis,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
formFactorChip: {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: DTColors.modeNormal,
|
||||||
|
height: 24,
|
||||||
|
},
|
||||||
|
formFactorChipText: {
|
||||||
|
color: DTColors.modeNormal,
|
||||||
|
fontSize: 10,
|
||||||
|
},
|
||||||
|
productDescription: {
|
||||||
|
color: DTColors.light,
|
||||||
|
opacity: 0.8,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
productNote: {
|
||||||
|
color: DTColors.modeOther,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
evMismatchWarning: {
|
||||||
|
color: DTColors.modeEmphasis,
|
||||||
|
backgroundColor: 'rgba(255, 255, 0, 0.1)',
|
||||||
|
padding: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
productFeatures: {
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
productFeature: {
|
||||||
|
color: DTColors.light,
|
||||||
|
opacity: 0.7,
|
||||||
|
marginBottom: 2,
|
||||||
|
},
|
||||||
|
productButton: {
|
||||||
|
borderColor: DTColors.modeEmphasis,
|
||||||
|
borderWidth: 1,
|
||||||
|
},
|
||||||
|
productButtonLabel: {
|
||||||
|
color: DTColors.modeEmphasis,
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
// No Match Card
|
||||||
|
noMatchCard: {
|
||||||
|
backgroundColor: '#0a0a0a',
|
||||||
|
borderRadius: 4,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: DTColors.modeOther,
|
||||||
|
padding: 20,
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
noMatchLabel: {
|
||||||
|
color: DTColors.modeOther,
|
||||||
|
letterSpacing: 2,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
noMatchText: {
|
||||||
|
color: DTColors.light,
|
||||||
|
opacity: 0.8,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
familyMatchesLabel: {
|
||||||
|
color: DTColors.light,
|
||||||
|
opacity: 0.6,
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
|
familyMatchItem: {
|
||||||
|
color: DTColors.modeNormal,
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
// Conversion Card
|
// Conversion Card
|
||||||
conversionCard: {
|
conversionCard: {
|
||||||
backgroundColor: '#0a0a0a',
|
backgroundColor: '#0a0a0a',
|
||||||
|
|||||||
14
src/services/matching/index.ts
Normal file
14
src/services/matching/index.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Product Matching Service
|
||||||
|
*/
|
||||||
|
|
||||||
|
export {
|
||||||
|
matchChipToProducts,
|
||||||
|
getMatchSummary,
|
||||||
|
getRecommendedAction,
|
||||||
|
formatProductFeatures,
|
||||||
|
getCloneTargetsForChip,
|
||||||
|
canCloneToProduct,
|
||||||
|
getDesfireEvLevel,
|
||||||
|
getDesfireEvMismatchWarning,
|
||||||
|
} from './matcher';
|
||||||
201
src/services/matching/matcher.ts
Normal file
201
src/services/matching/matcher.ts
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/**
|
||||||
|
* Product Matching Service
|
||||||
|
*
|
||||||
|
* Matches detected NFC chips to compatible Dangerous Things products
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ChipType, getChipFamily, CHIP_CLONEABILITY, ChipFamily} from '../../types/detection';
|
||||||
|
import {MatchResult, Product, DesfireEvLevel} from '../../types/products';
|
||||||
|
import {
|
||||||
|
PRODUCTS,
|
||||||
|
getChipProductMap,
|
||||||
|
CONVERSION_SERVICE_URL,
|
||||||
|
} from '../../data/products';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match a detected chip to compatible products
|
||||||
|
*/
|
||||||
|
export function matchChipToProducts(chipType: ChipType): MatchResult {
|
||||||
|
const chipProductMap = getChipProductMap();
|
||||||
|
const cloneability = CHIP_CLONEABILITY[chipType];
|
||||||
|
const chipFamily = getChipFamily(chipType);
|
||||||
|
|
||||||
|
// Get products that directly support this chip
|
||||||
|
const directMatches = chipProductMap.get(chipType) || [];
|
||||||
|
|
||||||
|
// Separate exact matches from clone targets
|
||||||
|
const exactMatches: Product[] = [];
|
||||||
|
const cloneTargets: Product[] = [];
|
||||||
|
|
||||||
|
for (const product of directMatches) {
|
||||||
|
if (product.exactMatch) {
|
||||||
|
exactMatches.push(product);
|
||||||
|
}
|
||||||
|
if (product.canReceiveClone && cloneability?.cloneable) {
|
||||||
|
cloneTargets.push(product);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find products in the same chip family
|
||||||
|
const familyMatches = findFamilyMatches(chipType, chipFamily, directMatches);
|
||||||
|
|
||||||
|
// Determine if conversion is recommended
|
||||||
|
// Conversion is recommended when:
|
||||||
|
// 1. No exact matches AND no clone targets
|
||||||
|
// 2. Chip is not cloneable (crypto protection)
|
||||||
|
const hasMatches = exactMatches.length > 0 || cloneTargets.length > 0;
|
||||||
|
const conversionRecommended = !hasMatches || !cloneability?.cloneable;
|
||||||
|
|
||||||
|
return {
|
||||||
|
exactMatches,
|
||||||
|
cloneTargets,
|
||||||
|
familyMatches,
|
||||||
|
isCloneable: cloneability?.cloneable ?? false,
|
||||||
|
cloneabilityNote: cloneability?.note,
|
||||||
|
conversionRecommended,
|
||||||
|
conversionUrl: CONVERSION_SERVICE_URL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find products in the same chip family that might be of interest
|
||||||
|
*/
|
||||||
|
function findFamilyMatches(
|
||||||
|
chipType: ChipType,
|
||||||
|
chipFamily: ChipFamily,
|
||||||
|
excludeProducts: Product[],
|
||||||
|
): Product[] {
|
||||||
|
const excludeIds = new Set(excludeProducts.map(p => p.id));
|
||||||
|
const familyMatches: Product[] = [];
|
||||||
|
|
||||||
|
for (const product of PRODUCTS) {
|
||||||
|
// Skip already matched products
|
||||||
|
if (excludeIds.has(product.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any of the product's compatible chips are in the same family
|
||||||
|
const productChipFamilies = product.compatibleChips.map(getChipFamily);
|
||||||
|
if (productChipFamilies.includes(chipFamily)) {
|
||||||
|
familyMatches.push(product);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return familyMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a summary message for the match result
|
||||||
|
*/
|
||||||
|
export function getMatchSummary(result: MatchResult, chipName: string): string {
|
||||||
|
if (result.exactMatches.length > 0) {
|
||||||
|
const names = result.exactMatches.map(p => p.name).join(', ');
|
||||||
|
return `Your ${chipName} is compatible with: ${names}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.cloneTargets.length > 0) {
|
||||||
|
const names = result.cloneTargets.map(p => p.name).join(', ');
|
||||||
|
return `Your ${chipName} data can be cloned to: ${names}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.isCloneable) {
|
||||||
|
return `${chipName} uses cryptographic protection and cannot be cloned. Consider our conversion service for compatible options.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `No direct product match found for ${chipName}. Check our conversion service for options.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get recommended action based on match result
|
||||||
|
*/
|
||||||
|
export function getRecommendedAction(
|
||||||
|
result: MatchResult,
|
||||||
|
): 'purchase' | 'clone' | 'conversion' | 'contact' {
|
||||||
|
if (result.exactMatches.length > 0) {
|
||||||
|
return 'purchase';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.cloneTargets.length > 0 && result.isCloneable) {
|
||||||
|
return 'clone';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.conversionRecommended) {
|
||||||
|
return 'conversion';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'contact';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format product features for display
|
||||||
|
*/
|
||||||
|
export function formatProductFeatures(product: Product): string[] {
|
||||||
|
return product.features;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get products that can receive cloned data from a chip type
|
||||||
|
*/
|
||||||
|
export function getCloneTargetsForChip(chipType: ChipType): Product[] {
|
||||||
|
const cloneability = CHIP_CLONEABILITY[chipType];
|
||||||
|
if (!cloneability?.cloneable) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const chipProductMap = getChipProductMap();
|
||||||
|
const directMatches = chipProductMap.get(chipType) || [];
|
||||||
|
|
||||||
|
return directMatches.filter(p => p.canReceiveClone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a chip can be cloned to any product
|
||||||
|
*/
|
||||||
|
export function canCloneToProduct(chipType: ChipType): boolean {
|
||||||
|
return getCloneTargetsForChip(chipType).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get DESFire EV level from chip type
|
||||||
|
*/
|
||||||
|
export function getDesfireEvLevel(chipType: ChipType): DesfireEvLevel | null {
|
||||||
|
switch (chipType) {
|
||||||
|
case ChipType.DESFIRE_EV1:
|
||||||
|
return 1;
|
||||||
|
case ChipType.DESFIRE_EV2:
|
||||||
|
return 2;
|
||||||
|
case ChipType.DESFIRE_EV3:
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there's a DESFire EV mismatch between chip and product
|
||||||
|
* Returns warning message if mismatch, null if no issue
|
||||||
|
*/
|
||||||
|
export function getDesfireEvMismatchWarning(
|
||||||
|
chipType: ChipType,
|
||||||
|
product: Product,
|
||||||
|
): string | null {
|
||||||
|
const chipEvLevel = getDesfireEvLevel(chipType);
|
||||||
|
const productEvLevel = product.desfireEvLevel;
|
||||||
|
|
||||||
|
// Not a DESFire chip or product doesn't have EV level
|
||||||
|
if (chipEvLevel === null || productEvLevel === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perfect match
|
||||||
|
if (chipEvLevel === productEvLevel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mismatch - warn user
|
||||||
|
if (chipEvLevel < productEvLevel) {
|
||||||
|
return `Your card uses DESFire EV${chipEvLevel}, but this implant uses EV${productEvLevel}. Some newer features may not be compatible with your existing system.`;
|
||||||
|
} else {
|
||||||
|
return `Your card uses DESFire EV${chipEvLevel}, but this implant uses EV${productEvLevel}. This should work, but you won't have access to EV${chipEvLevel} features.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
78
src/types/products.ts
Normal file
78
src/types/products.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Product Types for Dangerous Things Implants
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {ChipType} from './detection';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product form factor
|
||||||
|
*/
|
||||||
|
export enum FormFactor {
|
||||||
|
X_SERIES = 'X_SERIES', // 2x12mm injectable capsule (glass or bioresin)
|
||||||
|
FLEX = 'FLEX', // Flexible PCB implant (incision install)
|
||||||
|
BIORESIN = 'BIORESIN', // Larger bioresin capsule (incision install)
|
||||||
|
CARD = 'CARD', // ISO card format
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Product category
|
||||||
|
*/
|
||||||
|
export enum ProductCategory {
|
||||||
|
NFC = 'NFC', // NFC-only implants
|
||||||
|
DUAL_FREQUENCY = 'DUAL_FREQUENCY', // NFC + 125kHz
|
||||||
|
SECURE = 'SECURE', // Cryptographic/secure elements
|
||||||
|
LED = 'LED', // Implants with LED indicators
|
||||||
|
ACCESS = 'ACCESS', // Access control focused
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DESFire EV level for version matching
|
||||||
|
*/
|
||||||
|
export type DesfireEvLevel = 1 | 2 | 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Dangerous Things product
|
||||||
|
*/
|
||||||
|
export interface Product {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
formFactor: FormFactor;
|
||||||
|
categories: ProductCategory[];
|
||||||
|
compatibleChips: ChipType[];
|
||||||
|
features: string[];
|
||||||
|
url: string;
|
||||||
|
/** Whether this product can have data cloned TO it from the scanned chip */
|
||||||
|
canReceiveClone: boolean;
|
||||||
|
/** Whether this product uses the same chip type as scanned */
|
||||||
|
exactMatch: boolean;
|
||||||
|
/** Notes about compatibility or limitations */
|
||||||
|
notes?: string;
|
||||||
|
/** DESFire EV level (1, 2, or 3) for version mismatch warnings */
|
||||||
|
desfireEvLevel?: DesfireEvLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of product matching
|
||||||
|
*/
|
||||||
|
export interface MatchResult {
|
||||||
|
/** Products that use the exact same chip */
|
||||||
|
exactMatches: Product[];
|
||||||
|
/** Products that can receive cloned data from this chip */
|
||||||
|
cloneTargets: Product[];
|
||||||
|
/** Products in the same chip family */
|
||||||
|
familyMatches: Product[];
|
||||||
|
/** Is this chip cloneable at all? */
|
||||||
|
isCloneable: boolean;
|
||||||
|
/** Note about cloneability */
|
||||||
|
cloneabilityNote?: string;
|
||||||
|
/** Conversion service recommendation */
|
||||||
|
conversionRecommended: boolean;
|
||||||
|
/** Conversion URL */
|
||||||
|
conversionUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chip to product mapping for quick lookup
|
||||||
|
*/
|
||||||
|
export type ChipProductMap = Map<ChipType, Product[]>;
|
||||||
Reference in New Issue
Block a user