From bff4a6a31ac7f18ae00a2a5c444ad1eac8ffc185 Mon Sep 17 00:00:00 2001 From: "Z. Cliffe Schreuders" Date: Sat, 15 Nov 2025 23:48:15 +0000 Subject: [PATCH] docs(rfid): Add corrected scenario patterns and multi-protocol test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created proper RFID scenario examples following project patterns (hub structure, #exit_conversation tags, card_id format). ## Issues Found in Existing Files: ### test-rfid.json (Not modified - reference only): ❌ Uses legacy format (rfid_hex, rfid_facility, key_id) ❌ All EM4100 - no protocol variety ❌ Door requires not array format ❌ No protocol testing variety ### rfid-security-guard.ink (Not modified - reference only): ❌ Uses -> END instead of #exit_conversation ❌ Doesn't return to hub after exits ❌ No proper hub pattern ❌ Clone tag uses hex instead of card_id ## New Corrected Files: ### 1. scenarios/RFID_SCENARIO_PATTERNS.md (NEW) Comprehensive guide showing: - ✅ Correct hub pattern with #exit_conversation - ✅ Proper card_id JSON format - ✅ Protocol-specific examples - ❌ Common mistakes to avoid - Complete working examples ### 2. scenarios/test-rfid-multiprotocol.json (NEW) Test scenario with ALL 4 protocols: - EM4100 (instant clone) - MIFARE_Classic_Weak_Defaults (dictionary) - MIFARE_Classic_Custom_Keys (Darkside attack) - MIFARE_DESFire (UID only) Features: - 4 NPCs, each with different protocol - 4 test rooms demonstrating each security level - Proper card_id format throughout - Array-based door requirements - acceptsUIDOnly flag demonstrated ### 3. scenarios/ink/rfid-security-guard-fixed.ink (NEW) Fixed version showing: - Proper hub structure - #exit_conversation on choice lines - All paths return to hub - Card protocol variables declared - Uses {card_card_id} in clone tags ### 4. scenarios/ink/rfid-guard-low.ink (NEW) Simple EM4100 example: - Instant clone pattern - Proper exit handling - Minimal complexity for learning ### 5. scenarios/ink/rfid-guard-custom.ink (NEW) MIFARE Custom Keys example: - Shows attack requirement - Player feedback for encrypted cards - Proper state management ## Key Patterns Documented: ### Correct Ink Pattern: ```ink + [Leave] #exit_conversation # speaker:npc Goodbye! -> hub // Return to hub, NOT END ``` ### Correct JSON Pattern: ```json { "type": "keycard", "card_id": "employee_badge", "rfid_protocol": "EM4100", "name": "Employee Badge" } ``` ### Door Configuration: ```json { "lockType": "rfid", "requires": ["card1", "card2"], "acceptsUIDOnly": false } ``` ## Testing Checklist Added: - [ ] Uses #exit_conversation tag - [ ] All knots return to hub - [ ] Card variables declared - [ ] Uses card_id format - [ ] Door requires is array - [ ] No manual hex entry ## Files Added: - scenarios/RFID_SCENARIO_PATTERNS.md - scenarios/test-rfid-multiprotocol.json - scenarios/ink/rfid-security-guard-fixed.ink - scenarios/ink/rfid-guard-low.ink - scenarios/ink/rfid-guard-custom.ink These serve as reference implementations for scenario designers. Original files (test-rfid.json, rfid-security-guard.ink) left unmodified as they may be in use. --- scenarios/RFID_SCENARIO_PATTERNS.md | 264 +++++++++++++++++++ scenarios/ink/rfid-guard-custom.ink | 105 ++++++++ scenarios/ink/rfid-guard-low.ink | 76 ++++++ scenarios/ink/rfid-security-guard-fixed.ink | 133 ++++++++++ scenarios/test-rfid-multiprotocol.json | 267 ++++++++++++++++++++ 5 files changed, 845 insertions(+) create mode 100644 scenarios/RFID_SCENARIO_PATTERNS.md create mode 100644 scenarios/ink/rfid-guard-custom.ink create mode 100644 scenarios/ink/rfid-guard-low.ink create mode 100644 scenarios/ink/rfid-security-guard-fixed.ink create mode 100644 scenarios/test-rfid-multiprotocol.json diff --git a/scenarios/RFID_SCENARIO_PATTERNS.md b/scenarios/RFID_SCENARIO_PATTERNS.md new file mode 100644 index 0000000..e686a50 --- /dev/null +++ b/scenarios/RFID_SCENARIO_PATTERNS.md @@ -0,0 +1,264 @@ +# RFID Scenario Patterns - Correct Usage + +This document shows the **correct patterns** for creating RFID scenarios and Ink scripts in this project. + +## ✅ Correct Ink Pattern + +### Hub Structure with `#exit_conversation` + +```ink +VAR has_keycard = false +VAR has_rfid_cloner = false + +// Card protocol variables (auto-synced from NPC itemsHeld) +VAR card_protocol = "" +VAR card_instant_clone = false +VAR card_card_id = "" + +=== start === +# speaker:npc +Hello! I'm a guard. +-> hub + +=== hub === +// Main conversation hub + ++ [Option 1] + -> some_knot + ++ [Leave] #exit_conversation + # speaker:npc + Goodbye! + -> hub // Return to hub, not END + +=== some_knot === +# speaker:npc +Some dialogue here. +-> hub // Always return to hub +``` + +### Key Rules: + +1. **Use `#exit_conversation` tag** - NOT `-> END` +2. **Tag goes on the choice line** - `+ [Leave] #exit_conversation` +3. **After exit, return to hub** - `-> hub` (not `-> END`) +4. **Always have a hub knot** - Central return point for all conversations +5. **All paths return to hub** - Enables conversation to resume + +## ✅ Correct Scenario JSON Pattern + +### Use `card_id` Format (New) + +```json +{ + "npcId": "security_guard", + "itemsHeld": [ + { + "type": "keycard", + "card_id": "employee_badge", + "rfid_protocol": "EM4100", + "name": "Employee Badge" + } + ] +} +``` + +**Benefits:** +- No manual hex/UID entry needed +- Deterministic generation from card_id +- Simpler for scenario designers +- Supports all 4 protocols + +### Door Configuration + +```json +{ + "lockType": "rfid", + "requires": ["employee_badge", "master_card"], + "acceptsUIDOnly": false +} +``` + +**Key Points:** +- `requires` is an **array** of card_ids +- `acceptsUIDOnly` for DESFire UID emulation +- Use card_id, not key_id + +## ❌ Incorrect Patterns (DO NOT USE) + +### ❌ Wrong Ink Pattern + +```ink +=== hub === ++ [Leave] + # speaker:npc + Goodbye! + -> END // ❌ WRONG - breaks conversation state +``` + +**Problems:** +- Uses `-> END` - conversation can't be resumed +- Doesn't return to hub +- State isn't saved properly + +### ❌ Wrong Scenario Pattern (Legacy) + +```json +{ + "type": "keycard", + "rfid_hex": "FF4A7B9C21", + "rfid_facility": 255, + "rfid_card_number": 18811, + "key_id": "master_keycard" +} +``` + +**Problems:** +- Manual hex entry required +- Uses old `key_id` instead of `card_id` +- Doesn't work with new protocol system +- More complex for scenario designers + +## Protocol-Specific Examples + +### EM4100 (Instant Clone) + +```ink +{has_keycard and card_instant_clone and card_protocol == "EM4100": + + [Scan badge] #clone_keycard:{card_card_id} + # speaker:player + Quick scan - card cloned! + -> success +} +``` + +### MIFARE Classic - Weak Defaults (Dictionary Attack) + +```ink +{card_instant_clone and card_protocol == "MIFARE_Classic_Weak_Defaults": + + [Scan badge] #clone_keycard:{card_card_id} + # speaker:player + Dictionary attack succeeded instantly! + -> success +} +``` + +### MIFARE Classic - Custom Keys (Needs Attack) + +```ink +{card_needs_attack: + + [Try to scan] + # speaker:player + Encrypted - need Darkside attack (~30 sec) + -> needs_time +} +``` + +### MIFARE DESFire (UID Only) + +```ink +{card_uid_only: + + [Save UID only] + # speaker:player + Saved UID - only works on weak readers + -> uid_saved +} +``` + +## Complete Working Example + +See these files for complete examples: +- `scenarios/test-rfid-multiprotocol.json` - All 4 protocols +- `scenarios/ink/rfid-guard-low.ink` - EM4100 example +- `scenarios/ink/rfid-guard-custom.ink` - Custom keys example +- `scenarios/ink/rfid-security-guard-fixed.ink` - Full featured example + +## Common Mistakes + +### ❌ Mistake 1: Using `-> END` for exits +```ink ++ [Leave] + Goodbye! + -> END // ❌ WRONG +``` + +**✅ Correct:** +```ink ++ [Leave] #exit_conversation + # speaker:npc + Goodbye! + -> hub // ✅ RIGHT +``` + +### ❌ Mistake 2: Not returning to hub +```ink +=== some_knot === +Dialog here. +// ❌ Falls off end of knot +``` + +**✅ Correct:** +```ink +=== some_knot === +Dialog here. +-> hub // ✅ Always return to hub +``` + +### ❌ Mistake 3: Using legacy card format +```json +{ + "rfid_hex": "01AB34CD56", + "key_id": "employee_badge" +} +``` + +**✅ Correct:** +```json +{ + "card_id": "employee_badge", + "rfid_protocol": "EM4100" +} +``` + +### ❌ Mistake 4: Single card_id instead of array +```json +{ + "requires": "employee_badge" // ❌ Works but not preferred +} +``` + +**✅ Correct:** +```json +{ + "requires": ["employee_badge", "master_card"] // ✅ Array format +} +``` + +## Protocol Names (Use These Exact Strings) + +``` +"EM4100" // Low security, instant +"MIFARE_Classic_Weak_Defaults" // Low security, instant dictionary +"MIFARE_Classic_Custom_Keys" // Medium security, 30sec Darkside +"MIFARE_DESFire" // High security, UID only +``` + +## Testing Checklist + +When creating RFID scenarios, verify: + +- [ ] Ink file uses `#exit_conversation` tag +- [ ] All knots return to hub +- [ ] Card variables declared at top +- [ ] Uses `card_id` format in JSON +- [ ] Uses `rfid_protocol` with correct protocol name +- [ ] Door `requires` is an array +- [ ] No manual hex/UID entry +- [ ] Hub pattern implemented correctly +- [ ] #clone_keycard tag uses `{card_card_id}` variable + +## Reference Documentation + +For more details see: +- `scenarios/ink/README_RFID_VARIABLES.md` - Complete Ink variable reference +- `planning_notes/rfid_keycard/protocols_and_interactions/00_IMPLEMENTATION_SUMMARY.md` - Technical implementation details diff --git a/scenarios/ink/rfid-guard-custom.ink b/scenarios/ink/rfid-guard-custom.ink new file mode 100644 index 0000000..145ba27 --- /dev/null +++ b/scenarios/ink/rfid-guard-custom.ink @@ -0,0 +1,105 @@ +// rfid-guard-custom.ink +// Guard with MIFARE Classic (Custom Keys) - requires Darkside attack +// Demonstrates attack requirement pattern + +VAR has_keycard = false +VAR has_rfid_cloner = false + +// Card protocol variables (auto-synced) +VAR card_protocol = "" +VAR card_name = "" +VAR card_card_id = "" +VAR card_needs_attack = false +VAR card_uid = "" + +=== start === +# speaker:npc +Hey. I'm in charge of corporate security. + +{has_keycard: + This badge uses MIFARE Classic with custom encryption keys. + + Much more secure than those old EM4100 cards. +} + +-> hub + +=== hub === + +{has_keycard: + + [Ask about badge security] + -> ask_security +} + +{has_keycard and has_rfid_cloner and card_needs_attack: + + [Try to scan their badge] + # speaker:player + You try to scan, but it's encrypted... + -> needs_attack +} + ++ [Chat about security] + -> chat_security + ++ [Leave] #exit_conversation + # speaker:npc + Stay safe. + -> hub + +=== ask_security === +# speaker:npc +This badge? It's a MIFARE Classic 1K with custom encryption keys. + +Much better than the factory defaults some companies use. + +Can't just clone these with a quick scan. The crypto is... well, it's broken technically, but it takes time to crack. + ++ [How long to crack?] + # speaker:npc + With the right tools? Maybe 30 seconds using a Darkside attack. + + But most people don't have those tools. + -> hub + ++ [Interesting...] + -> hub + +=== chat_security === +# speaker:npc +Corporate security is no joke. We take access control seriously. + +All our badges use custom keys. Random generation, changed quarterly. + +The CEO even has a DESFire card - that's military-grade encryption. + +-> hub + +=== needs_attack === +# speaker:npc +What are you doing? + +# speaker:player +Oh, just... checking my phone! + +# speaker:npc +That looked like you were trying to scan my badge. + +You'd need to run a proper attack to get this one. Can't just quick-clone it. + +* [Play it cool] + # speaker:player + Sorry, my device sometimes picks up NFC signals by accident. + # speaker:npc + Uh huh. Sure. + -> hub + +* [Tell the truth] + # speaker:player + You're right - I was trying to clone it. But it's encrypted. + # speaker:npc + Yeah, that's the point of custom keys. + + You'd need to be close for about 30 seconds to run a Darkside attack. + + Good luck with that while I'm watching! + -> hub diff --git a/scenarios/ink/rfid-guard-low.ink b/scenarios/ink/rfid-guard-low.ink new file mode 100644 index 0000000..ac92296 --- /dev/null +++ b/scenarios/ink/rfid-guard-low.ink @@ -0,0 +1,76 @@ +// rfid-guard-low.ink +// Guard with EM4100 card (instant clone) +// Demonstrates proper hub pattern with #exit_conversation + +VAR has_keycard = false +VAR has_rfid_cloner = false + +// Card protocol variables (auto-synced) +VAR card_protocol = "" +VAR card_name = "" +VAR card_card_id = "" +VAR card_instant_clone = false + +=== start === +# speaker:npc +Hi! I work security here at the building. + +{has_keycard: + This badge on my belt? Just a basic EM4100 card. Nothing fancy. +} + +-> hub + +=== hub === + +{has_keycard: + + [Ask about the badge] + -> ask_badge +} + +{has_keycard and has_rfid_cloner and card_instant_clone: + + [Casually scan their badge] #clone_keycard:{card_card_id} + # speaker:player + You position your Flipper Zero near their badge while chatting... + # speaker:npc + ...and that's when I realized I'd left my lunch at home! + -> cloned +} + ++ [Chat about the job] + -> chat_job + ++ [Leave] #exit_conversation + # speaker:npc + See you around! + -> hub + +=== ask_badge === +# speaker:npc +Oh, this old thing? Yeah, it's one of those 125kHz proximity cards. + +Pretty basic technology. I just wave it at the reader and it opens. + +No PIN or anything - just the card itself. + +-> hub + +=== chat_job === +# speaker:npc +The job's not bad. Mostly just sitting at the desk and checking people in. + +I get to read a lot during my shifts. The night shift especially is pretty quiet. + +-> hub + +=== cloned === +# speaker:player +[You've successfully cloned the {card_name}!] + +# speaker:npc +Anyway, I should probably get back to my post. + ++ [Thanks for chatting] #exit_conversation + # speaker:npc + No problem! Have a good day! + -> hub diff --git a/scenarios/ink/rfid-security-guard-fixed.ink b/scenarios/ink/rfid-security-guard-fixed.ink new file mode 100644 index 0000000..8f9497f --- /dev/null +++ b/scenarios/ink/rfid-security-guard-fixed.ink @@ -0,0 +1,133 @@ +// rfid-security-guard.ink (FIXED) +// Security Guard NPC for RFID test scenario +// Demonstrates proper hub pattern and #exit_conversation usage + +VAR has_keycard = false +VAR has_rfid_cloner = false +VAR conversation_count = 0 + +// Card protocol variables (auto-synced from NPC itemsHeld) +VAR card_protocol = "" +VAR card_name = "" +VAR card_card_id = "" +VAR card_security = "" +VAR card_instant_clone = false +VAR card_needs_attack = false +VAR card_uid_only = false +VAR card_uid = "" +VAR card_hex = "" + +=== start === +~ conversation_count += 1 +# speaker:npc +Hey there. I'm the security guard for this facility. + +{has_keycard: + I've got the master keycard that opens the secure room. + {card_protocol == "EM4100": + It's a basic EM4100 card - nothing fancy. + } + {card_security == "medium": + This one's got proper encryption. Corporate security. + } +} + +-> hub + +=== hub === +// Main conversation hub + +{has_keycard and not card_instant_clone: + + [Ask about the keycard security] + -> ask_security +} + +{has_keycard: + + [Ask about the keycard] + -> ask_keycard +} + +{has_keycard and has_rfid_cloner and card_instant_clone: + + [Subtly scan their badge] #clone_keycard:{card_card_id} + # speaker:player + You casually position your Flipper Zero near their badge... + -> cloned_success +} + +{has_keycard and has_rfid_cloner and card_needs_attack: + + [Scan badge (requires attack)] + # speaker:player + You try to scan their badge, but it's encrypted. + # speaker:player + You'll need to run a Darkside attack - this will take about 30 seconds. + -> needs_attack +} + ++ [Just browsing] #exit_conversation + # speaker:npc + Alright, let me know if you need anything. + -> hub + +=== ask_security === +# speaker:npc +{card_security == "low": + Honestly? It's just a basic proximity card. Nothing special. + + The company's been meaning to upgrade for years... +- else: + This card uses {card_protocol} with custom encryption. + + Pretty secure stuff. Can't just clone these easily. +} +-> hub + +=== ask_keycard === +# speaker:npc +This keycard? Yeah, it's the master access card. Opens everything in the building. + +I can't just hand it to you though - security policy and all that. + ++ [Offer to buy it] + # speaker:npc + Ha! Nice try, but I can't sell company property. I'd lose my job. + -> hub + ++ [Ask if you can borrow it] + # speaker:npc + Sorry, no can do. This thing never leaves my person. + -> hub + ++ [Back] + -> hub + +=== cloned_success === +# speaker:npc +...So anyway, that's why I love working nights. Much quieter, you know? + +The pay's better too. Plus I get to catch up on my podcasts. + ++ [Thanks for the chat!] #exit_conversation + # speaker:npc + No problem! Stay safe out there. + -> hub + ++ [Any other secure areas?] + # speaker:npc + Well, there's the CEO's office, but that's on a different floor entirely. + + This master card works for most areas on this level though. + -> hub + +=== needs_attack === +# speaker:npc +Hey, what are you doing with that device? + +# speaker:player +Oh, just... checking the time! + +# speaker:npc +That didn't look like checking the time... + +You'll need to be more subtle. Or find a way to get the card when they're not looking. + +-> hub diff --git a/scenarios/test-rfid-multiprotocol.json b/scenarios/test-rfid-multiprotocol.json new file mode 100644 index 0000000..99ea3a7 --- /dev/null +++ b/scenarios/test-rfid-multiprotocol.json @@ -0,0 +1,267 @@ +{ + "name": "RFID Multi-Protocol Test", + "description": "Comprehensive test for all 4 RFID protocols with attacks", + "scenario_brief": "Test all RFID protocols: EM4100, MIFARE Classic (weak/custom), and DESFire", + "startRoom": "lobby", + "globalVariables": {}, + "player": { + "id": "player", + "displayName": "Agent 0x00", + "spriteSheet": "hacker", + "startX": 200, + "startY": 200 + }, + "startItemsInInventory": [ + { + "type": "rfid_cloner", + "name": "Flipper Zero", + "saved_cards": [] + } + ], + "rooms": { + "lobby": { + "name": "Test Lobby", + "type": "room_reception", + "connections": { + "north": "low_security", + "east": "medium_security", + "south": "high_security" + }, + "npcs": [ + { + "id": "guard_low", + "displayName": "Guard (Low Security)", + "npcType": "person", + "position": { "x": 3, "y": 3 }, + "spriteSheet": "hacker-red", + "spriteConfig": { + "idleFrameStart": 20, + "idleFrameEnd": 23 + }, + "storyPath": "scenarios/ink/rfid-guard-low.json", + "currentKnot": "start", + "itemsHeld": [ + { + "type": "keycard", + "card_id": "employee_badge", + "rfid_protocol": "EM4100", + "name": "Employee Badge" + } + ] + }, + { + "id": "guard_weak", + "displayName": "Guard (Weak MIFARE)", + "npcType": "person", + "position": { "x": 6, "y": 3 }, + "spriteSheet": "hacker-blue", + "spriteConfig": { + "idleFrameStart": 20, + "idleFrameEnd": 23 + }, + "storyPath": "scenarios/ink/rfid-guard-weak.json", + "currentKnot": "start", + "itemsHeld": [ + { + "type": "keycard", + "card_id": "hotel_keycard", + "rfid_protocol": "MIFARE_Classic_Weak_Defaults", + "name": "Hotel Keycard" + } + ] + }, + { + "id": "guard_custom", + "displayName": "Guard (Custom Keys)", + "npcType": "person", + "position": { "x": 9, "y": 3 }, + "spriteSheet": "hacker-green", + "spriteConfig": { + "idleFrameStart": 20, + "idleFrameEnd": 23 + }, + "storyPath": "scenarios/ink/rfid-guard-custom.json", + "currentKnot": "start", + "itemsHeld": [ + { + "type": "keycard", + "card_id": "corporate_badge", + "rfid_protocol": "MIFARE_Classic_Custom_Keys", + "name": "Corporate Badge" + } + ] + }, + { + "id": "guard_high", + "displayName": "Guard (DESFire)", + "npcType": "person", + "position": { "x": 12, "y": 3 }, + "spriteSheet": "hacker-yellow", + "spriteConfig": { + "idleFrameStart": 20, + "idleFrameEnd": 23 + }, + "storyPath": "scenarios/ink/rfid-guard-desfire.json", + "currentKnot": "start", + "itemsHeld": [ + { + "type": "keycard", + "card_id": "executive_card", + "rfid_protocol": "MIFARE_DESFire", + "name": "Executive Card" + } + ] + } + ], + "objects": [ + { + "type": "notes", + "name": "Protocol Guide", + "x": 250, + "y": 250, + "takeable": true, + "readable": true, + "note_title": "RFID Protocol Security Levels", + "note_content": "🟥 LOW SECURITY (Instant Clone):\n • EM4100 (125kHz) - Old tech, no encryption\n • MIFARE Classic (Default Keys) - Factory defaults\n\n🟦 MEDIUM SECURITY (Requires Attack):\n • MIFARE Classic (Custom Keys) - 30 sec Darkside attack\n\n🟩 HIGH SECURITY (UID Only):\n • MIFARE DESFire - Strong encryption, can't crack\n • Only UID emulation works on weak readers", + "observations": "Guide to the 4 RFID protocols" + } + ], + "doors": [ + { + "roomId": "lobby", + "connectedRoom": "low_security", + "direction": "north", + "x": 300, + "y": 100, + "locked": true, + "lockType": "rfid", + "requires": ["employee_badge"] + }, + { + "roomId": "lobby", + "connectedRoom": "medium_security", + "direction": "east", + "x": 600, + "y": 300, + "locked": true, + "lockType": "rfid", + "requires": ["hotel_keycard"] + }, + { + "roomId": "lobby", + "connectedRoom": "high_security", + "direction": "south", + "x": 300, + "y": 500, + "locked": true, + "lockType": "rfid", + "requires": ["corporate_badge", "executive_card"], + "acceptsUIDOnly": false + } + ] + }, + "low_security": { + "name": "Low Security Room (EM4100)", + "type": "room_office", + "connections": { + "south": "lobby" + }, + "npcs": [], + "objects": [ + { + "type": "notes", + "name": "Success - EM4100", + "x": 300, + "y": 300, + "takeable": true, + "readable": true, + "note_title": "✓ EM4100 Test Passed", + "note_content": "You successfully cloned an EM4100 card!\n\nThis protocol:\n• 125kHz frequency\n• No encryption\n• Instant clone\n• Used in: Old hotels, parking garages", + "observations": "EM4100 test passed" + } + ], + "doors": [ + { + "roomId": "low_security", + "connectedRoom": "lobby", + "direction": "south", + "x": 300, + "y": 500, + "locked": false + } + ] + }, + "medium_security": { + "name": "Medium Security Room (Weak MIFARE)", + "type": "room_office", + "connections": { + "west": "lobby" + }, + "npcs": [], + "objects": [ + { + "type": "notes", + "name": "Success - MIFARE Weak", + "x": 300, + "y": 300, + "takeable": true, + "readable": true, + "note_title": "✓ MIFARE Weak Defaults Test Passed", + "note_content": "You cloned a MIFARE Classic with default keys!\n\nThis protocol:\n• 13.56MHz NFC\n• Encrypted but uses FFFFFFFFFFFF keys\n• Dictionary attack succeeds instantly (~95%)\n• Used in: Cheap hotels, old transit cards", + "observations": "MIFARE weak defaults test passed" + } + ], + "doors": [ + { + "roomId": "medium_security", + "connectedRoom": "lobby", + "direction": "west", + "x": 100, + "y": 300, + "locked": false + } + ] + }, + "high_security": { + "name": "High Security Room (Custom MIFARE / DESFire)", + "type": "room_server", + "connections": { + "north": "lobby" + }, + "npcs": [], + "objects": [ + { + "type": "notes", + "name": "Success - High Security", + "x": 300, + "y": 300, + "takeable": true, + "readable": true, + "note_title": "✓ High Security Protocols Test Passed", + "note_content": "You accessed high security!\n\nMIFARE Classic (Custom Keys):\n• Requires 30-second Darkside attack\n• Used in: Corporate badges, banks\n\nMIFARE DESFire:\n• Can't be cracked - UID only\n• Only works on poorly-configured readers\n• Used in: Government, military", + "observations": "High security test passed" + }, + { + "type": "keycard", + "card_id": "master_override", + "rfid_protocol": "EM4100", + "name": "Master Override Card", + "x": 350, + "y": 300, + "takeable": true, + "observations": "A master override card that opens all doors" + } + ], + "doors": [ + { + "roomId": "high_security", + "connectedRoom": "lobby", + "direction": "north", + "x": 300, + "y": 100, + "locked": false + } + ] + } + } +}