mirror of
https://github.com/thegatesbrowser/thegates.git
synced 2025-08-23 08:17:34 -04:00
linux sandboxing
This commit is contained in:
parent
2bd2a4ebe9
commit
aa22668fa5
29 changed files with 534 additions and 43 deletions
3
project/.sandbox/kinda-safe-godot/.gitignore
vendored
Normal file
3
project/.sandbox/kinda-safe-godot/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
fakechroot_enviroment/root/home/*
|
||||
fakechroot_enviroment/root/GATES-FILES/game
|
||||
game
|
38
project/.sandbox/kinda-safe-godot/README.md
Normal file
38
project/.sandbox/kinda-safe-godot/README.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Kinda-Safe-Godot
|
||||
|
||||
## Sandbox and File Isolation for Godot
|
||||
|
||||
Kinda-Safe-Godot provides a sandboxed environment with file isolation for running Godot games. Although extensive efforts have been made to prevent sandbox escapes, it is essential to acknowledge that no system can guarantee absolute security.
|
||||
|
||||
The sandboxed environment utilizes symbolic links to expose specific directories on your computer. This method may inadvertently leak some information, such as installed programs and resource usage.
|
||||
|
||||
Running a bash environment inside the sandbox is not possible due to restricted syscalls.
|
||||
|
||||
## Purpose
|
||||
|
||||
The development of Kinda-Safe-Godot was primarily motivated by the [gates](https://flathub.org/apps/io.itch.nordup.TheGates) project. While a typical approach would involve creating a container image or using Flatpak, these solutions introduce significant dependencies, potentially hindering casual users from accessing the game.
|
||||
|
||||
Instead of using this project, I recommend building a Flatpak, which provides finer controls and ensures compatibility across various systems.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Execute the "runner/build.sh" script.
|
||||
2. Export your game as a single file bundle and rename its executable file to "game".
|
||||
3. Move the game executable to the main directory.
|
||||
4. Run the "run_game.sh" script.
|
||||
|
||||
## Generating the List of Syscalls
|
||||
|
||||
To generate the list of syscalls, we suggest using the "strace" tool:
|
||||
|
||||
```
|
||||
strace ./{game} 2> /dev/stdout | sed 's/\([^()]*\).*/\1/' > syscalls.txt
|
||||
```
|
||||
|
||||
Once you have the "syscalls.txt" file, you can sort and deduplicate the entries:
|
||||
|
||||
```
|
||||
cat syscalls.txt | sort | uniq
|
||||
```
|
||||
|
||||
You may need to remove any garbage data.
|
263
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/fakechroot.sh
Executable file
263
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/fakechroot.sh
Executable file
|
@ -0,0 +1,263 @@
|
|||
#!/usr/bin/sh
|
||||
|
||||
# fakechroot
|
||||
#
|
||||
# Script which sets fake chroot environment
|
||||
#
|
||||
# (c) 2011, 2013 Piotr Roszatycki <dexter@debian.org>, LGPL
|
||||
|
||||
|
||||
FAKECHROOT_VERSION=2.20.1
|
||||
|
||||
|
||||
fakechroot_die () {
|
||||
echo "$@" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
fakechroot_usage () {
|
||||
fakechroot_die "Usage:
|
||||
fakechroot [-l|--lib fakechrootlib]
|
||||
[-d|--elfloader ldso]
|
||||
[-s|--use-system-libs]
|
||||
[-e|--environment type]
|
||||
[-c|--config-dir directory]
|
||||
[-b|--bindir directory]
|
||||
[--] [command]
|
||||
fakechroot -v|--version
|
||||
fakechroot -h|--help"
|
||||
}
|
||||
|
||||
|
||||
fakechroot_next_cmd () {
|
||||
if [ "$1" = "fakeroot" ]; then
|
||||
shift
|
||||
# skip the options
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-h|-v)
|
||||
break
|
||||
;;
|
||||
-u|--unknown-is-real)
|
||||
shift
|
||||
;;
|
||||
-l|--lib|--faked|-s|-i|-b)
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$1" -a "$1" != "-v" -a "$1" != "-h" ]; then
|
||||
fakechroot_environment=`basename -- "$1"`
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [ "$FAKECHROOT" = "true" ]; then
|
||||
fakechroot_die "fakechroot: nested operation is not supported"
|
||||
fi
|
||||
|
||||
|
||||
# fakechroot doesn't work with CDPATH correctly
|
||||
unset CDPATH
|
||||
|
||||
|
||||
# Default settings
|
||||
fakechroot_lib=libfakechroot.so
|
||||
fakechroot_paths=$(pwd)/fakechroot_enviroment/fakechroot/
|
||||
fakechroot_sysconfdir=/etc/fakechroot
|
||||
fakechroot_confdir=
|
||||
fakechroot_environment=
|
||||
fakechroot_bindir=
|
||||
|
||||
if [ "$fakechroot_paths" = "no" ]; then
|
||||
fakechroot_paths=
|
||||
fi
|
||||
|
||||
if command -v which >/dev/null; then
|
||||
fakechroot_echo=`which echo`
|
||||
fakechroot_echo=${fakechroot_echo:-/bin/echo}
|
||||
else
|
||||
fakechroot_echo=/bin/echo
|
||||
fi
|
||||
|
||||
|
||||
# Get options
|
||||
fakechroot_getopttest=`getopt --version`
|
||||
case $fakechroot_getopttest in
|
||||
getopt*)
|
||||
# GNU getopt
|
||||
fakechroot_opts=`getopt -q -l lib: -l elfloader: -l use-system-libs -l config-dir: -l environment: -l bindir: -l version -l help -- +l:d:sc:e:b:vh "$@"`
|
||||
;;
|
||||
*)
|
||||
# POSIX getopt ?
|
||||
fakechroot_opts=`getopt l:d:sc:e:b:vh "$@"`
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$?" -ne 0 ]; then
|
||||
fakechroot_usage
|
||||
fi
|
||||
|
||||
eval set -- "$fakechroot_opts"
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
fakechroot_opt=$1
|
||||
shift
|
||||
case "$fakechroot_opt" in
|
||||
-h|--help)
|
||||
fakechroot_usage
|
||||
;;
|
||||
-v|--version)
|
||||
echo "fakechroot version $FAKECHROOT_VERSION"
|
||||
exit 0
|
||||
;;
|
||||
-l|--lib)
|
||||
fakechroot_lib=`eval echo "$1"`
|
||||
fakechroot_paths=
|
||||
shift
|
||||
;;
|
||||
-d|--elfloader)
|
||||
FAKECHROOT_ELFLOADER=$1
|
||||
export FAKECHROOT_ELFLOADER
|
||||
shift
|
||||
;;
|
||||
-s|--use-system-libs)
|
||||
fakechroot_paths="${fakechroot_paths:+$fakechroot_paths:}/usr/lib:/lib"
|
||||
;;
|
||||
-c|--config-dir)
|
||||
fakechroot_confdir=$1
|
||||
shift
|
||||
;;
|
||||
-e|--environment)
|
||||
fakechroot_environment=$1
|
||||
shift
|
||||
;;
|
||||
-b|--bindir)
|
||||
fakechroot_bindir=$1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$fakechroot_environment" ]; then
|
||||
fakechroot_next_cmd "$@"
|
||||
fi
|
||||
|
||||
|
||||
# Autodetect if dynamic linker supports --argv0 option
|
||||
if [ -n "$FAKECHROOT_ELFLOADER" ]; then
|
||||
fakechroot_detect=`$FAKECHROOT_ELFLOADER --argv0 echo $fakechroot_echo yes 2>&1`
|
||||
if [ "$fakechroot_detect" = yes ]; then
|
||||
FAKECHROOT_ELFLOADER_OPT_ARGV0="--argv0"
|
||||
export FAKECHROOT_ELFLOADER_OPT_ARGV0
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# Swap libfakechroot and libfakeroot in LD_PRELOAD if needed
|
||||
# libfakeroot must come first
|
||||
# an alternate fakeroot library may be given
|
||||
# in the FAKEROOT_ALT_LIB environment variable
|
||||
if [ -n "$FAKEROOT_ALT_LIB" ]; then
|
||||
lib_libfakeroot="$FAKEROOT_ALT_LIB"
|
||||
else
|
||||
lib_libfakeroot="libfakeroot-sysv.so"
|
||||
fi
|
||||
|
||||
for preload in $(echo "$LD_PRELOAD" | tr ':' ' '); do
|
||||
case "$preload" in
|
||||
"$lib_libfakeroot")
|
||||
lib_libfakeroot_to_preload="$preload"
|
||||
;;
|
||||
*)
|
||||
lib_to_preload="${lib_to_preload:+${lib_to_preload}:}$preload"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
# Make sure the preload is available
|
||||
fakechroot_paths="$fakechroot_paths${LD_LIBRARY_PATH:+${fakechroot_paths:+:}$LD_LIBRARY_PATH}"
|
||||
fakechroot_lib="${lib_libfakeroot_to_preload:+${lib_libfakeroot_to_preload}:}$fakechroot_lib${lib_to_preload:+:$lib_to_preload}"
|
||||
|
||||
fakechroot_detect=`LD_LIBRARY_PATH="$fakechroot_paths" LD_PRELOAD="$fakechroot_lib" FAKECHROOT_DETECT=1 $fakechroot_echo 2>&1`
|
||||
case "$fakechroot_detect" in
|
||||
fakechroot*)
|
||||
fakechroot_libfound=yes
|
||||
;;
|
||||
*)
|
||||
fakechroot_libfound=no
|
||||
esac
|
||||
|
||||
if [ $fakechroot_libfound = no ]; then
|
||||
fakechroot_die "fakechroot: preload library not found, aborting."
|
||||
fi
|
||||
|
||||
|
||||
# Additional environment setting from configuration file
|
||||
if [ "$fakechroot_environment" != "none" ]; then
|
||||
for fakechroot_e in "$fakechroot_environment" "${fakechroot_environment%.*}" default; do
|
||||
for fakechroot_d in "$fakechroot_confdir" "$HOME/.fakechroot" "$fakechroot_sysconfdir"; do
|
||||
fakechroot_f="$fakechroot_d/$fakechroot_e.env"
|
||||
if [ -f "$fakechroot_f" ]; then
|
||||
. "$fakechroot_f"
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Check if substituted command is called
|
||||
fakechroot_cmd=`command -v "$1"`
|
||||
|
||||
fakechroot_cmd_wrapper=`
|
||||
IFS=:
|
||||
for fakechroot_cmd_subst in $FAKECHROOT_CMD_SUBST; do
|
||||
case "$fakechroot_cmd_subst" in
|
||||
"$fakechroot_cmd="*)
|
||||
echo "${fakechroot_cmd_subst#*=}"
|
||||
break 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
`
|
||||
|
||||
# Set FAKECHROOT_CMD_ORIG if wrapped
|
||||
if [ -n "$fakechroot_cmd_wrapper" ]; then
|
||||
FAKECHROOT_CMD_ORIG="$fakechroot_cmd"
|
||||
export FAKECHROOT_CMD_ORIG
|
||||
fi
|
||||
|
||||
fakechroot_cmd=${fakechroot_cmd_wrapper:-$1}
|
||||
|
||||
|
||||
# Execute command
|
||||
if [ -z "$*" ]; then
|
||||
LD_LIBRARY_PATH="$fakechroot_paths" LD_PRELOAD="$fakechroot_lib" ${SHELL:-/bin/sh}
|
||||
exit $?
|
||||
else
|
||||
if [ -n "$fakechroot_cmd" ]; then
|
||||
# Call substituted command
|
||||
shift
|
||||
LD_LIBRARY_PATH="$fakechroot_paths" LD_PRELOAD="$fakechroot_lib" "$fakechroot_cmd" "$@"
|
||||
exit $?
|
||||
else
|
||||
# Call original command
|
||||
LD_LIBRARY_PATH="$fakechroot_paths" LD_PRELOAD="$fakechroot_lib" "$@"
|
||||
exit $?
|
||||
fi
|
||||
fi
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
chmod +x /GATES-FILES/game
|
||||
/GATES-FILES/game $@
|
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/dev
Symbolic link
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/dev
Symbolic link
|
@ -0,0 +1 @@
|
|||
/dev
|
|
@ -0,0 +1 @@
|
|||
/etc/fonts/
|
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/lib
Symbolic link
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/lib
Symbolic link
|
@ -0,0 +1 @@
|
|||
/lib
|
|
@ -0,0 +1 @@
|
|||
/lib64
|
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/run
Symbolic link
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/run
Symbolic link
|
@ -0,0 +1 @@
|
|||
/run/
|
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/tmp
Symbolic link
1
project/.sandbox/kinda-safe-godot/fakechroot_enviroment/root/tmp
Symbolic link
|
@ -0,0 +1 @@
|
|||
/tmp/
|
|
@ -0,0 +1 @@
|
|||
/usr/lib
|
|
@ -0,0 +1 @@
|
|||
/usr/lib64/
|
|
@ -0,0 +1 @@
|
|||
/usr/share/X11/
|
|
@ -0,0 +1 @@
|
|||
/usr/share/alsa
|
|
@ -0,0 +1 @@
|
|||
/usr/share/locale/
|
|
@ -0,0 +1 @@
|
|||
/usr/share/vulkan/
|
|
@ -0,0 +1 @@
|
|||
/var/lib/alsa/
|
13
project/.sandbox/kinda-safe-godot/list_child_processes.sh
Executable file
13
project/.sandbox/kinda-safe-godot/list_child_processes.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
extract_child_pid() {
|
||||
echo "$(ps --ppid $1)" | grep -oE '^[[:space:]]*[0-9]+' | awk '{print $1}'
|
||||
}
|
||||
|
||||
pid=$1
|
||||
while [[ -n "$pid" ]]; do
|
||||
pid=$(extract_child_pid "$pid")
|
||||
if [[ -n "$pid" ]]; then
|
||||
echo "$pid"
|
||||
fi
|
||||
done
|
5
project/.sandbox/kinda-safe-godot/run_game.sh
Executable file
5
project/.sandbox/kinda-safe-godot/run_game.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd $1
|
||||
sh ./fakechroot_enviroment/fakechroot.sh chroot ./fakechroot_enviroment/root /bin/sh /GATES-FILES/launch.sh ${@:2}
|
||||
rm ./fakechroot_enviroment/root/GATES-FILES/game
|
6
project/.sandbox/kinda-safe-godot/zip.sh
Executable file
6
project/.sandbox/kinda-safe-godot/zip.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
zip=../sandbox/sandbox_env.zip
|
||||
|
||||
rm $zip
|
||||
zip -ry $zip fakechroot_enviroment run_game.sh list_child_processes.sh
|
|
@ -12,6 +12,7 @@ config_version=5
|
|||
|
||||
config/name="TheGates"
|
||||
config/description="Building new Internet"
|
||||
config/tags=PackedStringArray("thegates")
|
||||
run/main_scene="res://scenes/app.tscn"
|
||||
config/features=PackedStringArray("4.1")
|
||||
run/max_fps=60
|
||||
|
|
12
project/resources/sandbox_env.tres
Normal file
12
project/resources/sandbox_env.tres
Normal file
|
@ -0,0 +1,12 @@
|
|||
[gd_resource type="Resource" script_class="SandboxEnv" load_steps=2 format=3 uid="uid://bo6qgr210aamc"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/sandbox/sandbox_env.gd" id="1_2dvtt"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_2dvtt")
|
||||
zip = "sandbox/sandbox_env.zip"
|
||||
the_gates_folder = "fakechroot_enviroment/root/GATES-FILES"
|
||||
the_gates_folder_abs = "/GATES-FILES"
|
||||
snbx_exe_name = "game"
|
||||
start_sh = "run_game.sh"
|
||||
subprocesses_sh = "list_child_processes.sh"
|
|
@ -1,6 +1,6 @@
|
|||
[gd_resource type="Resource" script_class="SandboxExecutable" load_steps=2 format=3 uid="uid://cmb7xvbue74qa"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/loading/sandbox_executable.gd" id="1_q0dqh"]
|
||||
[ext_resource type="Script" path="res://scripts/sandbox/sandbox_executable.gd" id="1_q0dqh"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_q0dqh")
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
[gd_scene load_steps=22 format=3 uid="uid://kywrsqro3d5i"]
|
||||
[gd_scene load_steps=23 format=3 uid="uid://kywrsqro3d5i"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/loading/gate_loader.gd" id="1_uxhy6"]
|
||||
[ext_resource type="Resource" uid="uid://b1xvdym0qh6td" path="res://resources/gate_events.res" id="2_q7cvi"]
|
||||
[ext_resource type="Script" path="res://scripts/loading/sandbox_manager.gd" id="3_0cpfc"]
|
||||
[ext_resource type="Resource" uid="uid://cmb7xvbue74qa" path="res://resources/sandbox_executable.tres" id="4_shus3"]
|
||||
[ext_resource type="Script" path="res://scripts/sandbox/render_result.gd" id="5_nlg2s"]
|
||||
[ext_resource type="Resource" uid="uid://l1quiaghft2f" path="res://resources/command_events.res" id="6_18mgg"]
|
||||
[ext_resource type="Script" path="res://scripts/sandbox/sandbox_manager.gd" id="6_368sj"]
|
||||
[ext_resource type="Texture2D" uid="uid://cykx425p6ylwr" path="res://textures/background.png" id="7_52jgh"]
|
||||
[ext_resource type="Script" path="res://scripts/sandbox/input_sync.gd" id="8_1blsi"]
|
||||
[ext_resource type="Resource" uid="uid://bo6qgr210aamc" path="res://resources/sandbox_env.tres" id="8_a6dvr"]
|
||||
[ext_resource type="Resource" uid="uid://crjhix0osmtnf" path="res://resources/ui_events.res" id="9_ir58h"]
|
||||
[ext_resource type="Script" path="res://scripts/sandbox/command_sync.gd" id="10_cqo55"]
|
||||
[ext_resource type="Script" path="res://scripts/ui/world/world_ui.gd" id="12_jdwjt"]
|
||||
|
@ -281,10 +282,11 @@ gate_events = ExtResource("2_q7cvi")
|
|||
connect_timeout = 10.0
|
||||
|
||||
[node name="SandboxManager" type="Node" parent="." node_paths=PackedStringArray("render_result")]
|
||||
script = ExtResource("3_0cpfc")
|
||||
script = ExtResource("6_368sj")
|
||||
gate_events = ExtResource("2_q7cvi")
|
||||
render_result = NodePath("../HBoxContainer/WorldCanvas/RenderResult")
|
||||
snbx_executable = ExtResource("4_shus3")
|
||||
snbx_env = ExtResource("8_a6dvr")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||
custom_minimum_size = Vector2(0, 700)
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
extends Node
|
||||
class_name SandboxManager
|
||||
|
||||
@export var gate_events: GateEvents
|
||||
@export var render_result: RenderResult
|
||||
@export var snbx_executable: SandboxExecutable
|
||||
|
||||
var sandbox_pid: int
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
gate_events.gate_loaded.connect(create_process)
|
||||
|
||||
|
||||
func create_process(gate: Gate) -> void:
|
||||
if not snbx_executable.exists():
|
||||
Debug.logerr("Sandbox executable not found at " + snbx_executable.path); return
|
||||
|
||||
var pack_file = ProjectSettings.globalize_path(gate.resource_pack)
|
||||
var shared_libs = ProjectSettings.globalize_path(gate.shared_libs_dir)
|
||||
var args = [
|
||||
"--main-pack", pack_file,
|
||||
"--gdext-libs-dir", shared_libs,
|
||||
"--resolution", "%dx%d" % [render_result.width, render_result.height]
|
||||
]
|
||||
Debug.logclr(snbx_executable.path + " " + " ".join(args), Color.DARK_VIOLET)
|
||||
sandbox_pid = OS.create_process(snbx_executable.path, args)
|
||||
|
||||
gate_events.gate_entered_emit()
|
||||
|
||||
|
||||
func kill_process() -> void:
|
||||
if OS.is_process_running(sandbox_pid):
|
||||
OS.kill(sandbox_pid)
|
||||
Debug.logclr("Process killed " + str(sandbox_pid), Color.DIM_GRAY)
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
kill_process()
|
80
project/scripts/sandbox/sandbox_env.gd
Normal file
80
project/scripts/sandbox/sandbox_env.gd
Normal file
|
@ -0,0 +1,80 @@
|
|||
extends Resource
|
||||
class_name SandboxEnv
|
||||
|
||||
@export var zip: String
|
||||
@export var the_gates_folder: String
|
||||
@export var the_gates_folder_abs: String
|
||||
@export var snbx_exe_name: String
|
||||
@export var start_sh: String
|
||||
@export var subprocesses_sh: String
|
||||
|
||||
const ENV_FOLDER := "/tmp/sandbox_env"
|
||||
|
||||
var zip_path: String :
|
||||
get = get_zip_path
|
||||
|
||||
var start: String :
|
||||
get = get_start_sh
|
||||
|
||||
var subprocesses: String :
|
||||
get = get_subprocesses_sh
|
||||
|
||||
|
||||
var main_pack: String
|
||||
|
||||
|
||||
func get_zip_path() -> String:
|
||||
var executable_dir = OS.get_executable_path().get_base_dir() + "/"
|
||||
return executable_dir + zip
|
||||
|
||||
|
||||
func get_start_sh() -> String:
|
||||
return ProjectSettings.globalize_path(ENV_FOLDER + "/" + start_sh)
|
||||
|
||||
|
||||
func get_subprocesses_sh() -> String:
|
||||
return ProjectSettings.globalize_path(ENV_FOLDER + "/" + subprocesses_sh)
|
||||
|
||||
|
||||
func zip_exists() -> bool:
|
||||
return FileAccess.file_exists(zip_path)
|
||||
|
||||
|
||||
func create_env(snbx_executable: String, gate: Gate) -> void:
|
||||
Debug.logclr("create_env %s" % [ENV_FOLDER], Color.DIM_GRAY)
|
||||
UnZip.unzip(zip_path, ENV_FOLDER, true)
|
||||
|
||||
var folder = ENV_FOLDER + "/" + the_gates_folder
|
||||
var executable = folder + "/" + snbx_exe_name
|
||||
DirAccess.copy_absolute(snbx_executable, executable)
|
||||
|
||||
main_pack = executable.get_basename() + "." + gate.resource_pack.get_extension()
|
||||
DirAccess.copy_absolute(gate.resource_pack, main_pack)
|
||||
main_pack = the_gates_folder_abs + "/" + main_pack.get_file()
|
||||
|
||||
if not gate.shared_libs_dir.is_empty() and DirAccess.dir_exists_absolute(gate.shared_libs_dir):
|
||||
for file in DirAccess.get_files_at(gate.shared_libs_dir):
|
||||
var lib = gate.shared_libs_dir + "/" + file
|
||||
var lib_in_folder = folder + "/" + file
|
||||
DirAccess.copy_absolute(lib, lib_in_folder)
|
||||
Debug.logclr(lib_in_folder, Color.DIM_GRAY)
|
||||
|
||||
|
||||
func get_subprocesses(ppid: int) -> Array[int]:
|
||||
var pids: Array[int] = []
|
||||
var output = []
|
||||
|
||||
OS.execute(subprocesses, [str(ppid)], output)
|
||||
if output.is_empty(): return pids
|
||||
|
||||
var s_pids = output[0].split('\n')
|
||||
for s_pid in s_pids:
|
||||
if s_pid.is_empty(): continue
|
||||
var pid = s_pid.to_int()
|
||||
pids.append(pid)
|
||||
|
||||
return pids
|
||||
|
||||
|
||||
func clean() -> void:
|
||||
OS.execute("rm", ["-rf", ProjectSettings.globalize_path(ENV_FOLDER)])
|
52
project/scripts/sandbox/sandbox_manager.gd
Normal file
52
project/scripts/sandbox/sandbox_manager.gd
Normal file
|
@ -0,0 +1,52 @@
|
|||
extends Node
|
||||
class_name SandboxManager
|
||||
|
||||
@export var gate_events: GateEvents
|
||||
@export var render_result: RenderResult
|
||||
@export var snbx_executable: SandboxExecutable
|
||||
@export var snbx_env: SandboxEnv
|
||||
|
||||
var sandbox_pid: int
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
gate_events.gate_loaded.connect(start_sandbox)
|
||||
|
||||
|
||||
func start_sandbox(gate: Gate) -> void:
|
||||
if not snbx_executable.exists():
|
||||
Debug.logerr("Sandbox executable not found at " + snbx_executable.path); return
|
||||
if not snbx_env.zip_exists():
|
||||
Debug.logerr("Sandbox environment not found at " + snbx_env.zip_path); return
|
||||
|
||||
snbx_env.create_env(snbx_executable.path, gate)
|
||||
|
||||
# var pack_file = ProjectSettings.globalize_path(gate.resource_pack)
|
||||
# var shared_libs = ProjectSettings.globalize_path(gate.shared_libs_dir)
|
||||
var args = [
|
||||
snbx_env.start.get_base_dir(), # cd to dir
|
||||
"--main-pack", snbx_env.main_pack,
|
||||
# "--gdext-libs-dir", shared_libs,
|
||||
"--resolution", "%dx%d" % [render_result.width, render_result.height]
|
||||
]
|
||||
Debug.logclr(snbx_env.start + " " + " ".join(args), Color.DARK_VIOLET)
|
||||
sandbox_pid = OS.create_process(snbx_env.start, args)
|
||||
|
||||
gate_events.gate_entered_emit()
|
||||
|
||||
|
||||
func kill_sandbox() -> void:
|
||||
if sandbox_pid == 0: return
|
||||
|
||||
var pids = snbx_env.get_subprocesses(sandbox_pid)
|
||||
pids.append(sandbox_pid)
|
||||
|
||||
for pid in pids:
|
||||
OS.kill(pid)
|
||||
Debug.logclr("Process killed " + str(pid), Color.DIM_GRAY)
|
||||
|
||||
snbx_env.clean()
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
kill_sandbox()
|
38
project/scripts/sandbox/unzip.gd
Normal file
38
project/scripts/sandbox/unzip.gd
Normal file
|
@ -0,0 +1,38 @@
|
|||
extends Node
|
||||
class_name UnZip
|
||||
|
||||
|
||||
static func unzip(zip_path: String, to_folder: String, contains_symlink: bool = false) -> void:
|
||||
var reader = ZIPReader.new()
|
||||
var err = reader.open(zip_path)
|
||||
if err != OK: Debug.logerr("Cannot open file %s to unzip" % [zip_path]); return
|
||||
|
||||
for path in reader.get_files():
|
||||
if path.get_file().is_empty(): # is directory
|
||||
DirAccess.make_dir_recursive_absolute(to_folder + "/" + path)
|
||||
# Debug.logclr("makedir %s" % [to_folder + "/" + path], Color.DIM_GRAY)
|
||||
else:
|
||||
create_file(reader, path, to_folder, contains_symlink)
|
||||
|
||||
|
||||
static func create_file(reader: ZIPReader, path: String, folder: String, contains_symlink: bool) -> void:
|
||||
var data = reader.read_file(path)
|
||||
var symlink = ""
|
||||
|
||||
if contains_symlink:
|
||||
symlink = data.get_string_from_utf8()
|
||||
if symlink.split("\n").size() != 1:
|
||||
symlink = ""
|
||||
|
||||
if contains_symlink and symlink.is_absolute_path():
|
||||
var link_to = ProjectSettings.globalize_path(folder + "/" + path.get_basename())
|
||||
OS.execute("ln", ["-s", symlink, link_to])
|
||||
# Debug.logclr("ln -s %s %s" % [symlink, link_to], Color.DIM_GRAY)
|
||||
else:
|
||||
var file_path = folder + "/" + path
|
||||
var file = FileAccess.open(file_path, FileAccess.WRITE)
|
||||
file.store_buffer(data)
|
||||
file.close()
|
||||
if file_path.get_extension() == "sh":
|
||||
OS.execute("chmod", ["+x", ProjectSettings.globalize_path(file_path)])
|
||||
# Debug.logclr("touch %s" % [folder + "/" + path], Color.DIM_GRAY)
|
Loading…
Add table
Add a link
Reference in a new issue