Added some initial work on checking safe files for malicious contents
This commit is contained in:
parent
3080806d8c
commit
266b5b7e4f
@ -2,3 +2,4 @@ class_name SaveData
|
||||
extends Resource
|
||||
|
||||
@export_file("*.tscn", "*.scn") var current_world: String
|
||||
@export var com_hash: int = -1 # computer hash for checking, if this came from another source.
|
||||
|
||||
@ -103,6 +103,8 @@ func update_world_state() -> void:
|
||||
|
||||
world_state.loaded_level_ids = get_loaded_level_ids()
|
||||
|
||||
world_state.com_hash = Game.get_computer_hash()
|
||||
|
||||
|
||||
func get_level_ids_from_streamers(streamers: Array[LevelStreamer]) -> Array[StringName]:
|
||||
var streamer_ids: Array[StringName] = []
|
||||
|
||||
@ -5,3 +5,4 @@ extends Resource
|
||||
@export_file("*.tscn", "*.scn") var world_path: String
|
||||
@export var loaded_level_ids: Array[StringName] = []
|
||||
@export var instance_data: Dictionary[String, Variant] = {}
|
||||
@export var com_hash: int = -1 # computer hash for checking, if this came from another source.
|
||||
|
||||
@ -22,7 +22,7 @@ var main_menu: MainMenu
|
||||
|
||||
var _os_dialog_window_result: int = -1
|
||||
|
||||
@onready var world_holder: Node = %WorldHolder
|
||||
@onready var scene_holder: Node = %SceneHolder
|
||||
@onready var loading_screen: LoadingScreen = %LoadingScreen
|
||||
|
||||
|
||||
@ -34,6 +34,19 @@ static func debug_draw(draw_shape: String, args: Array) -> void:
|
||||
const DD3D: StringName = &"DebugDraw3D"
|
||||
if is_debug and Engine.has_singleton(DD3D):
|
||||
Engine.get_singleton(DD3D).callv("draw_" + draw_shape, args)
|
||||
|
||||
|
||||
static func get_computer_hash() -> int:
|
||||
var combined_str: String = str(
|
||||
OS.get_processor_name(),
|
||||
OS.get_processor_count(),
|
||||
OS.get_model_name(),
|
||||
OS.get_name(),
|
||||
)
|
||||
|
||||
return combined_str.hash()
|
||||
|
||||
|
||||
## Turns res://example.tscn into example.tres (and .scn -> .res) and uid://1234567 into 1234567.tres.
|
||||
static func convert_path_to_resource_filename(path: String) -> String:
|
||||
path = ResourceUID.path_to_uid(path)
|
||||
@ -50,12 +63,37 @@ func _ready() -> void:
|
||||
register_commands()
|
||||
|
||||
|
||||
func check_computer_hash(input_hash: int) -> bool:
|
||||
if input_hash == Game.get_computer_hash():
|
||||
return true
|
||||
|
||||
_os_dialog_window_result = -1
|
||||
|
||||
var _on_dialog_interacted: Callable = func(button_id: int) -> void:
|
||||
_os_dialog_window_result = button_id
|
||||
|
||||
DisplayServer.dialog_show(
|
||||
"Save Hash Mismatch",
|
||||
"The save you are trying to load seems to come from a different computer.\nWe are not responsible for any damages to your computer if the save is malicious.\n\nDo you want to load the save anyway?",
|
||||
["Abort", "Continue"], _on_dialog_interacted)
|
||||
|
||||
get_tree().root.process_mode = Node.PROCESS_MODE_DISABLED
|
||||
|
||||
while _os_dialog_window_result == -1:
|
||||
await get_tree().process_frame
|
||||
|
||||
get_tree().root.process_mode = Node.PROCESS_MODE_PAUSABLE
|
||||
|
||||
return _os_dialog_window_result != 0
|
||||
|
||||
|
||||
func load_game(_save_data: SaveData, _save_slot: int) -> void:
|
||||
if not await check_computer_hash(save_data.com_hash):
|
||||
if not await check_computer_hash(_save_data.com_hash):
|
||||
return
|
||||
|
||||
save_data = _save_data.duplicate()
|
||||
save_slot = _save_slot
|
||||
|
||||
InputManager.capture_mouse()
|
||||
load_world(save_data.current_world, false)
|
||||
|
||||
@ -69,6 +107,8 @@ func save_game() -> Error:
|
||||
if is_instance_valid(world):
|
||||
save_data.current_world = ResourceUID.path_to_uid(world.scene_file_path)
|
||||
|
||||
save_data.com_hash = Game.get_computer_hash()
|
||||
|
||||
DirAccess.make_dir_recursive_absolute(SAVE_DIR % save_slot)
|
||||
return ResourceSaver.save(save_data, SAVE_PATH % [save_slot, file_name])
|
||||
|
||||
@ -97,7 +137,7 @@ func load_world(world_path: String, save_previous: bool = true, load_from_save:
|
||||
world.change_world_requested.connect(load_world)
|
||||
world.world_unload_requested.connect(_on_unload_world_request)
|
||||
|
||||
world_holder.add_child.call_deferred(world)
|
||||
scene_holder.add_child.call_deferred(world)
|
||||
await world.loaded
|
||||
loading_screen.fade_out()
|
||||
return OK
|
||||
@ -144,7 +184,7 @@ func load_main_menu() -> void:
|
||||
_main_menu.load_game_request.connect(load_game)
|
||||
_main_menu.quit_request.connect(quit_game)
|
||||
main_menu = _main_menu
|
||||
world_holder.add_child(main_menu)
|
||||
scene_holder.add_child(main_menu)
|
||||
|
||||
|
||||
func load_startup() -> void:
|
||||
@ -155,7 +195,7 @@ func load_startup() -> void:
|
||||
load_main_menu()
|
||||
loading_screen.fade_out()
|
||||
)
|
||||
add_child(startup)
|
||||
scene_holder.add_child(startup)
|
||||
|
||||
|
||||
func unload_main_menu() -> void:
|
||||
@ -170,12 +210,14 @@ func quit_game() -> void:
|
||||
|
||||
func register_commands() -> void:
|
||||
var load_save_func: Callable = func(save_index: int) -> void:
|
||||
print("Loading Save index ", save_index)
|
||||
var path: String = MainMenu.get_save_path(save_index)
|
||||
if ResourceLoader.exists(path):
|
||||
load_game(load(path), save_index)
|
||||
|
||||
LimboConsole.register_command(load_save_func, "load_save", "Loads the save with the given save slot index.")
|
||||
LimboConsole.register_command(save_game, "save_game", "Saves the game based on the current save slot.")
|
||||
#DebugConsole.register_command("load_save", load_save_func, "Loads the save with the given save slot index.")
|
||||
|
||||
|
||||
func _on_unload_world_request(do_save: bool) -> void:
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
script = ExtResource("1_7uq6d")
|
||||
metadata/_custom_type_script = "uid://cl1u038dbrou2"
|
||||
|
||||
[node name="WorldHolder" type="Node" parent="." unique_id=1835125942]
|
||||
[node name="SceneHolder" type="Node" parent="." unique_id=1835125942]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="CanvasLayer" type="CanvasLayer" parent="." unique_id=919699501]
|
||||
|
||||
@ -49,6 +49,16 @@ static func get_save_path(slot_index: int) -> String:
|
||||
return SAVE_DATA_PATH % slot_index
|
||||
|
||||
|
||||
static func does_save_contents_contain_code(save_path: String) -> bool:
|
||||
var file := FileAccess.open(save_path, FileAccess.READ)
|
||||
var contents: String = file.get_as_text()
|
||||
if contents.containsn("func") or contents.containsn("script/source") or contents.containsn("_init"):
|
||||
OS.alert("The save you are trying to load contains malicious code.\nAborting...", "Save File Warning")
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
continue_button.pressed.connect(_on_continue_pressed)
|
||||
load_button.pressed.connect(_on_load_pressed)
|
||||
@ -98,6 +108,9 @@ func _on_continue_pressed() -> void:
|
||||
_on_new_game_pressed()
|
||||
return
|
||||
|
||||
if does_save_contents_contain_code(path):
|
||||
return
|
||||
|
||||
config.set_value("save", "last_slot", slot)
|
||||
config.save(Game.USER_SETTINGS_PATH)
|
||||
|
||||
@ -112,6 +125,8 @@ func _on_load_pressed() -> void:
|
||||
|
||||
func _on_new_game_pressed() -> void:
|
||||
var save_data: SaveData = Game.INITIAL_SAVE_DATA.duplicate()
|
||||
save_data.com_hash = Game.get_computer_hash()
|
||||
print("Save hash: ", save_data.com_hash, " Computer hash: ", Game.get_computer_hash())
|
||||
var slot_index: int = get_unique_save_slot_index()
|
||||
load_game_request.emit(save_data, slot_index)
|
||||
|
||||
@ -139,6 +154,15 @@ func _on_save_entry_pressed(save_slot: int) -> void:
|
||||
_on_new_game_pressed()
|
||||
return
|
||||
|
||||
# TODO: Check for hash before loading the file via 'load'
|
||||
if does_save_contents_contain_code(save_path):
|
||||
return
|
||||
#var file := FileAccess.open(save_path, FileAccess.READ)
|
||||
#var contents: String = file.get_as_text()
|
||||
#var index: int = contents.find("com_hash = ")
|
||||
#var hash_str: String = contents.get_slice("\n", 1)
|
||||
#print("Hash: ", hash_str, " Index: ", index, "\nContents: ", contents)
|
||||
|
||||
var save_data: SaveData = load(save_path)
|
||||
load_game_request.emit(save_data, save_slot)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user