Z. Cliffe Schreuders d3b31b4368 Add comprehensive unlock system tests
Created test suite with 34 tests covering all unlock scenarios and security:

DOOR TESTS (10 tests):
- PIN/password validation (correct/incorrect, case sensitivity)
- Key unlocks (client-validated)
- Unlocked doors (method='unlocked')

CONTAINER TESTS (8 tests):
- PIN/password validation
- Key, lockpick, biometric, bluetooth, RFID unlocks
- Unlocked containers

NPC UNLOCK TESTS (6 tests):
 NPC can unlock door/container if encountered and has permission
🔒 SECURITY: Fails if NPC not encountered
🔒 SECURITY: Fails if NPC lacks permission for that target
🔒 SECURITY: Fails for non-existent NPC
🔒 SECURITY: Fails if unlockable is not an array

SECURITY TESTS - BYPASS PREVENTION (4 tests):
🔒 CRITICAL: Locked door CANNOT be bypassed with method='unlocked'
🔒 CRITICAL: Locked container CANNOT be bypassed with method='unlocked'
 Unlocked door CAN use method='unlocked'
 Unlocked container CAN use method='unlocked'

ERROR CASES (3 tests):
- Non-existent doors/objects return 422
- Invalid methods return 422

DATA FILTERING (2 tests):
- Verify 'requires' field filtered from responses
- Verify recursive filtering of contents

INTEGRATION (1 test):
- Multiple sequential unlocks
- Idempotent operations

Test Results: 34 runs, 115 assertions, 0 failures

Server Implementation:
- validate_npc_unlock: Validates NPC encounter and permission list
- find_npc_in_scenario: Searches all rooms for NPC
- method='npc': New unlock method requiring NPC id as attempt

Client Implementation:
- Updated handleUnlockDoor to call server API with method='npc'
- Server validates all NPC unlock requests
- No client-side lock manipulation

Security Principle: All unlock authorization is server-side.
Client cannot bypass locks by manipulating state or claiming NPC unlocks.
2025-11-22 00:46:56 +00:00
2025-05-16 10:42:42 +01:00
2025-11-22 00:46:56 +00:00
2025-11-21 15:27:53 +00:00
2025-11-21 15:27:53 +00:00
2025-11-14 19:47:54 +00:00

BreakEscape Rails Engine

Cybersecurity training escape room game as a mountable Rails Engine.

Features

  • 24+ cybersecurity escape room scenarios
  • Server-side progress tracking with 2-table schema
  • Randomized passwords per game instance via ERB
  • JIT Ink script compilation for NPC dialogue
  • Polymorphic player support (User/DemoUser)
  • Pundit authorization
  • RESTful API for game state management
  • Session-based state persistence

Installation

In your Gemfile:

gem 'break_escape', path: 'path/to/break_escape'

Then:

bundle install
rails break_escape:install:migrations
rails db:migrate
rails db:seed  # Optional: creates missions from scenarios

Mounting in Host App

In your config/routes.rb:

mount BreakEscape::Engine => "/break_escape"

Usage

Standalone Mode (Development)

export BREAK_ESCAPE_STANDALONE=true
rails server
# Visit http://localhost:3000/break_escape/

Mounted Mode (Production)

Mount in Hacktivity or another Rails app. The engine will use the host app's current_user via Devise.

Configuration

# config/initializers/break_escape.rb
BreakEscape.configure do |config|
  config.standalone_mode = false  # true for development
  config.demo_user_handle = 'demo_player'
end

Database Schema

  • break_escape_missions - Scenario metadata (name, display_name, published, difficulty)
  • break_escape_games - Player state + scenario snapshot (JSONB)
  • break_escape_demo_users - Standalone mode only (optional)

API Endpoints

  • GET /games/:id/scenario - Scenario JSON (ERB-generated)
  • GET /games/:id/ink?npc=X - NPC script (JIT compiled from .ink)
  • GET /games/:id/bootstrap - Initial game data
  • PUT /games/:id/sync_state - Sync player state
  • POST /games/:id/unlock - Validate unlock attempt
  • POST /games/:id/inventory - Update inventory

Architecture

ERB Scenario Generation

Scenarios are stored as .json.erb templates and rendered on-demand with randomized values:

  • <%= random_password %> - Generates unique password per game
  • <%= random_pin %> - Generates unique 4-digit PIN
  • <%= random_code %> - Generates unique hex code

JIT Ink Compilation

NPC dialogue scripts compile on first request (~300ms):

  1. Check if .json exists and is newer than .ink
  2. If needed, run inklecate to compile
  3. Cache compiled JSON for subsequent requests

State Management

Player state stored in JSONB column:

  • Current room and unlocked rooms
  • Inventory and collected items
  • NPC encounters
  • Global variables (synced with client)
  • Health and minigame state

Testing

rails test

License

MIT

Documentation

See HACKTIVITY_INTEGRATION.md for integration guide.

Description
No description provided
Readme 72 MiB
Languages
JavaScript 86.5%
Ink 7%
HTML 2.9%
CSS 2.5%
Ruby 0.9%
Other 0.2%