mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
docs(rfid): Add corrected scenario patterns and multi-protocol test
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.
This commit is contained in:
264
scenarios/RFID_SCENARIO_PATTERNS.md
Normal file
264
scenarios/RFID_SCENARIO_PATTERNS.md
Normal file
@@ -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
|
||||
105
scenarios/ink/rfid-guard-custom.ink
Normal file
105
scenarios/ink/rfid-guard-custom.ink
Normal file
@@ -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
|
||||
76
scenarios/ink/rfid-guard-low.ink
Normal file
76
scenarios/ink/rfid-guard-low.ink
Normal file
@@ -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
|
||||
133
scenarios/ink/rfid-security-guard-fixed.ink
Normal file
133
scenarios/ink/rfid-security-guard-fixed.ink
Normal file
@@ -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
|
||||
267
scenarios/test-rfid-multiprotocol.json
Normal file
267
scenarios/test-rfid-multiprotocol.json
Normal file
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user