mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
Enhance object unlocking logic, add locked field to containers, and validate scenario schema
This commit is contained in:
@@ -274,42 +274,50 @@ module BreakEscape
|
||||
return true
|
||||
end
|
||||
|
||||
# Find object in all rooms - check both id and name
|
||||
scenario_data['rooms'].each do |_room_id, room_data|
|
||||
object = room_data['objects']&.find { |obj|
|
||||
obj['id'] == target_id || obj['name'] == target_id
|
||||
}
|
||||
|
||||
if object
|
||||
Rails.logger.info "[BreakEscape] Found object: id=#{object['id']}, name=#{object['name']}, locked=#{object['locked']}, requires=#{object['requires']}"
|
||||
|
||||
# Handle method='unlocked' - verify against scenario data
|
||||
if method == 'unlocked'
|
||||
if !object['locked']
|
||||
Rails.logger.info "[BreakEscape] Object is unlocked in scenario data, granting access"
|
||||
return true
|
||||
else
|
||||
Rails.logger.warn "[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object: #{target_id}"
|
||||
return false
|
||||
end
|
||||
# Find object in all rooms - check id, name, or generated client ID
|
||||
object = nil
|
||||
scenario_data['rooms'].each do |room_id, room_data|
|
||||
next unless room_data['objects']
|
||||
room_data['objects'].each_with_index do |obj, index|
|
||||
# Client generates IDs as: roomId_type_index
|
||||
client_generated_id = "#{room_id}_#{obj['type']}_#{index}"
|
||||
if obj['id'] == target_id || obj['name'] == target_id || client_generated_id == target_id
|
||||
object = obj
|
||||
break
|
||||
end
|
||||
end
|
||||
break if object
|
||||
end
|
||||
|
||||
# NPC unlock: Validate NPC has been encountered and has permission to unlock this object
|
||||
if method == 'npc'
|
||||
npc_id = attempt # NPC id is passed as 'attempt'
|
||||
return validate_npc_unlock(npc_id, target_id)
|
||||
end
|
||||
if object
|
||||
Rails.logger.info "[BreakEscape] Found object: id=#{object['id']}, name=#{object['name']}, locked=#{object['locked']}, requires=#{object['requires']}"
|
||||
|
||||
case method
|
||||
when 'key', 'lockpick', 'biometric', 'bluetooth', 'rfid'
|
||||
# Client validated the unlock - trust it
|
||||
# Handle method='unlocked' - verify against scenario data
|
||||
if method == 'unlocked'
|
||||
if !object['locked']
|
||||
Rails.logger.info "[BreakEscape] Object is unlocked in scenario data, granting access"
|
||||
return true
|
||||
when 'pin', 'password'
|
||||
result = object['requires'].to_s == attempt.to_s
|
||||
Rails.logger.info "[BreakEscape] Password validation: required='#{object['requires']}', attempt='#{attempt}', result=#{result}"
|
||||
return result
|
||||
else
|
||||
Rails.logger.warn "[BreakEscape] SECURITY VIOLATION: Client sent method='unlocked' for LOCKED object: #{target_id}"
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# NPC unlock: Validate NPC has been encountered and has permission to unlock this object
|
||||
if method == 'npc'
|
||||
npc_id = attempt # NPC id is passed as 'attempt'
|
||||
return validate_npc_unlock(npc_id, target_id)
|
||||
end
|
||||
|
||||
case method
|
||||
when 'key', 'lockpick', 'biometric', 'bluetooth', 'rfid'
|
||||
# Client validated the unlock - trust it
|
||||
return true
|
||||
when 'pin', 'password'
|
||||
result = object['requires'].to_s == attempt.to_s
|
||||
Rails.logger.info "[BreakEscape] Password validation: required='#{object['requires']}', attempt='#{attempt}', result=#{result}"
|
||||
return result
|
||||
end
|
||||
end
|
||||
Rails.logger.warn "[BreakEscape] Object not found: #{target_id}"
|
||||
false
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
{
|
||||
"type": "bag",
|
||||
"name": "Heist Gear Backpack",
|
||||
"locked": false,
|
||||
"contents": [
|
||||
{
|
||||
"type": "lockpick",
|
||||
|
||||
@@ -289,6 +289,8 @@
|
||||
"tablet",
|
||||
"safe",
|
||||
"suitcase",
|
||||
"bag",
|
||||
"briefcase",
|
||||
"bluetooth_scanner",
|
||||
"fingerprint_kit",
|
||||
"pin-cracker",
|
||||
@@ -296,7 +298,8 @@
|
||||
"flag-station",
|
||||
"text_file",
|
||||
"id_badge",
|
||||
"rfid_cloner"
|
||||
"rfid_cloner",
|
||||
"office-misc-hdd4"
|
||||
],
|
||||
"description": "Item type. Custom types (like 'id_badge', 'rfid_cloner') are valid for #give_item tags in Ink scripts."
|
||||
},
|
||||
|
||||
@@ -207,6 +207,14 @@ def check_common_issues(json_data)
|
||||
has_container_with_contents = true
|
||||
end
|
||||
|
||||
# REQUIRED: Containers with contents must specify locked field explicitly
|
||||
container_types = ['briefcase', 'bag', 'bag1', 'suitcase', 'safe', 'pc', 'bin1']
|
||||
if container_types.include?(obj['type']) && obj['contents'] && !obj['contents'].empty?
|
||||
unless obj.key?('locked')
|
||||
issues << "❌ INVALID: '#{path}' is a container with contents but missing required 'locked' field - must be explicitly true or false for server-side validation"
|
||||
end
|
||||
end
|
||||
|
||||
# Track readable items (notes, documents)
|
||||
if obj['readable'] || (obj['type'] == 'notes' && obj['text'])
|
||||
has_readable_items = true
|
||||
|
||||
5
start_server.sh
Executable file
5
start_server.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
# kill any puma processes
|
||||
pkill -9 -f puma; sleep 1
|
||||
# start the server
|
||||
bundle exec rails server -b 0.0.0.0 -p 3000 2>&1 &
|
||||
Reference in New Issue
Block a user