From a548ecc074343bf5d9b89f565273ae89ffb3445e Mon Sep 17 00:00:00 2001 From: Quentin Date: Sat, 24 Feb 2024 11:10:58 +0100 Subject: [PATCH] lua io.exists (#2771) --- docs/lua/tables/io.md | 27 +++++++++ docs/lua/tables/vehicles.md | 52 +++++++++++----- docs/lua/tables/weapons.md | 114 ++++++++++++++++++++++++++---------- scripts/doc_gen.py | 18 +++--- src/lua/lua_module.cpp | 54 ++++++++++++----- 5 files changed, 196 insertions(+), 69 deletions(-) create mode 100644 docs/lua/tables/io.md diff --git a/docs/lua/tables/io.md b/docs/lua/tables/io.md new file mode 100644 index 00000000..4a048621 --- /dev/null +++ b/docs/lua/tables/io.md @@ -0,0 +1,27 @@ +# Table: io + +Table for file manipulation. Modified for security purposes. + +## Functions (2) + +### `open()` + +- **Returns:** + - `file_handle`: file handle or nil if can't read / write to the given path. + +**Example Usage:** +```lua +file_handle = io.open() +``` + +### `exists()` + +- **Returns:** + - `boolean`: True if the passed file path exists + +**Example Usage:** +```lua +boolean = io.exists() +``` + + diff --git a/docs/lua/tables/vehicles.md b/docs/lua/tables/vehicles.md index 348de54b..870907e4 100644 --- a/docs/lua/tables/vehicles.md +++ b/docs/lua/tables/vehicles.md @@ -6,58 +6,80 @@ Table containing functions for getting information about vehicles in GTA V. ### `get_vehicle_display_name(vehicle_hash)` +- **Example Usage:** +```lua +log.info(vehicles.get_vehicle_display_name('BTYPE2')) +``` + - **Parameters:** - `vehicle_hash` (Hash): JOAAT hash of the vehicle. - **Returns:** - `vehicle_display_string`: String: the in-game display string. If the vehicle is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. +**Example Usage:** +```lua +vehicle_display_string = vehicles.get_vehicle_display_name(vehicle_hash) +``` + +### `get_vehicle_display_name(vehicle_name)` + - **Example Usage:** ```lua log.info(vehicles.get_vehicle_display_name('BTYPE2')) ``` -### `get_vehicle_display_name(vehicle_name)` - - **Parameters:** - `vehicle_name` (String): Name of the vehicle. - **Returns:** - `vehicle_display_string`: String: the in-game display string. If the vehicle is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. -- **Example Usage:** +**Example Usage:** ```lua -log.info(vehicles.get_vehicle_display_name('BTYPE2')) +vehicle_display_string = vehicles.get_vehicle_display_name(vehicle_name) ``` ### `get_all_vehicles_by_class(vehicle_class)` +- **Example Usage:** +```lua +local sports_classics = vehicles.get_all_vehicles_by_class('Sports Classics') +for i = 1, #sports_classics do + log.info(sports_classics[i]) +end +``` + - **Parameters:** - `vehicle_class` (String): The vehicle class. - **Returns:** - `vehicles`: table: a list of all vehicles that match the class passed in. The list can contain anything from 0 to n elements. -- **Example Usage:** +**Example Usage:** ```lua -local sports_classics = vehicles.get_all_vehicles_by_class('Sports Classics') -for i = 1, #sports_classics do - log.info(sports_classics[i]) -end +vehicles = vehicles.get_all_vehicles_by_class(vehicle_class) ``` ### `get_all_vehicles_by_mfr(manufacturer)` +- **Example Usage:** +```lua +local albanies = vehicles.get_all_vehicles_by_mfr('Albany') +for i = 1, #albanies do + log.info(albanies[i]) +end +``` + - **Parameters:** - `manufacturer` (String): The vehicle manufacturer. - **Returns:** - `vehicles`: table: a list of all vehicles that match the manufacturer passed in. The list can contain anything from 0 to n elements. -- **Example Usage:** +**Example Usage:** ```lua -local albanies = vehicles.get_all_vehicles_by_mfr('Albany') -for i = 1, #albanies do - log.info(albanies[i]) -end -``` \ No newline at end of file +vehicles = vehicles.get_all_vehicles_by_mfr(manufacturer) +``` + + diff --git a/docs/lua/tables/weapons.md b/docs/lua/tables/weapons.md index 433da5cb..6c8bd097 100644 --- a/docs/lua/tables/weapons.md +++ b/docs/lua/tables/weapons.md @@ -6,38 +6,42 @@ Table containing functions for getting information about weapons in GTA V. ### `get_weapon_display_name(weapon_hash)` +- **Example Usage:** +```lua +log.info(weapons.get_weapon_display_name(joaat('WEAPON_REVOLVER'))) +``` + - **Parameters:** - `weapon_hash` (Hash): JOAAT hash of the weapon. - **Returns:** - `weapon_display_name`: String: the in-game display string. If the weapon is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. -- **Example Usage:** +**Example Usage:** ```lua -log.info(weapons.get_weapon_display_name(joaat('WEAPON_REVOLVER'))) +weapon_display_name = weapons.get_weapon_display_name(weapon_hash) ``` ### `get_weapon_display_name(weapon_name)` +- **Example Usage:** +```lua +log.info(weapons.get_weapon_display_name('WEAPON_REVOLVER')) +``` + - **Parameters:** - `weapon_name` (String): Name of the weapon. - **Returns:** - `weapon_display_name`: String: the in-game display string. If the weapon is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. -- **Example Usage:** +**Example Usage:** ```lua -log.info(weapons.get_weapon_display_name('WEAPON_REVOLVER')) +weapon_display_name = weapons.get_weapon_display_name(weapon_name) ``` ### `get_all_weapons_of_group_type(group_hash)` -- **Parameters:** - - `group_hash` (Hash): The JOAAT hash of the group the weapon(s) belong to. - -- **Returns:** - - `weapons_of_group_type`: table: a list of all weapons that match the group hash passed in. The list can contain anything from 0 to n elements. - - **Example Usage:** ```lua local pistols = weapons.get_all_weapons_of_group_type(joaat('GROUP_PISTOL')) @@ -46,14 +50,19 @@ for i = 1, #pistols do end ``` -### `get_all_weapons_of_group_type(group_name)` - - **Parameters:** - - `group_name` (String): The group the weapon(s) belong to. Can be in either GROUP_ format or not. Parameter is case-insensitive. + - `group_hash` (Hash): The JOAAT hash of the group the weapon(s) belong to. - **Returns:** - `weapons_of_group_type`: table: a list of all weapons that match the group hash passed in. The list can contain anything from 0 to n elements. +**Example Usage:** +```lua +weapons_of_group_type = weapons.get_all_weapons_of_group_type(group_hash) +``` + +### `get_all_weapons_of_group_type(group_name)` + - **Example Usage:** ```lua local pistols = weapons.get_all_weapons_of_group_type('GROUP_PISTOL') @@ -67,13 +76,18 @@ for i = 1, #pistols do end ``` -### `get_all_weapon_components(weapon_hash)` - - **Parameters:** - - `weapon_hash` (Hash): The JOAAT hash of the weapon the component(s) belong to. + - `group_name` (String): The group the weapon(s) belong to. Can be in either GROUP_ format or not. Parameter is case-insensitive. - **Returns:** - - `weapon_components`: table: a list of all components that match the weapon passed in. The list can contain anything from 0 to n elements. + - `weapons_of_group_type`: table: a list of all weapons that match the group hash passed in. The list can contain anything from 0 to n elements. + +**Example Usage:** +```lua +weapons_of_group_type = weapons.get_all_weapons_of_group_type(group_name) +``` + +### `get_all_weapon_components(weapon_hash)` - **Example Usage:** ```lua @@ -83,14 +97,19 @@ for i = 1, #pistol_attachments do end ``` -### `get_all_weapon_components(weapon_name)` - - **Parameters:** - - `weapon_name` (String): The weapon the component(s) belong to. + - `weapon_hash` (Hash): The JOAAT hash of the weapon the component(s) belong to. - **Returns:** - `weapon_components`: table: a list of all components that match the weapon passed in. The list can contain anything from 0 to n elements. +**Example Usage:** +```lua +weapon_components = weapons.get_all_weapon_components(weapon_hash) +``` + +### `get_all_weapon_components(weapon_name)` + - **Example Usage:** ```lua local pistol_attachments = weapons.get_all_weapon_components('WEAPON_PISTOL') @@ -99,54 +118,87 @@ for i = 1, #pistol_attachments do end ``` -### `get_weapon_component_display_name(weapon_component_hash)` - - **Parameters:** - - `weapon_component_hash` (Hash): JOAAT hash of the weapon component. + - `weapon_name` (String): The weapon the component(s) belong to. - **Returns:** - - `component_display_name`: String: the in-game display string. If the component is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. + - `weapon_components`: table: a list of all components that match the weapon passed in. The list can contain anything from 0 to n elements. + +**Example Usage:** +```lua +weapon_components = weapons.get_all_weapon_components(weapon_name) +``` + +### `get_weapon_component_display_name(weapon_component_hash)` - **Example Usage:** ```lua log.info(weapons.get_weapon_component_display_name(joaat('COMPONENT_PISTOL_CLIP_01'))) ``` +- **Parameters:** + - `weapon_component_hash` (Hash): JOAAT hash of the weapon component. + +- **Returns:** + - `component_display_name`: String: the in-game display string. If the component is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. + +**Example Usage:** +```lua +component_display_name = weapons.get_weapon_component_display_name(weapon_component_hash) +``` + ### `get_weapon_component_display_name(weapon_component)` +- **Example Usage:** +```lua +log.info(weapons.get_weapon_component_display_name('COMPONENT_PISTOL_CLIP_01')) +``` + - **Parameters:** - `weapon_component` (String): The weapon component. - **Returns:** - `component_display_name`: String: the in-game display string. If the component is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. -- **Example Usage:** +**Example Usage:** ```lua -log.info(weapons.get_weapon_component_display_name('COMPONENT_PISTOL_CLIP_01')) +component_display_name = weapons.get_weapon_component_display_name(weapon_component) ``` ### `get_weapon_component_display_desc(weapon_component_hash)` +- **Example Usage:** +```lua +log.info(weapons.get_weapon_component_display_desc(joaat('COMPONENT_PISTOL_CLIP_01'))) +``` + - **Parameters:** - `weapon_component_hash` (Hash): JOAAT hash of the weapon component. - **Returns:** - `component_display_desc`: String: the in-game display string. If the component is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. -- **Example Usage:** +**Example Usage:** ```lua -log.info(weapons.get_weapon_component_display_desc(joaat('COMPONENT_PISTOL_CLIP_01'))) +component_display_desc = weapons.get_weapon_component_display_desc(weapon_component_hash) ``` ### `get_weapon_component_display_desc(weapon_component)` +- **Example Usage:** +```lua +log.info(weapons.get_weapon_component_display_desc('COMPONENT_PISTOL_CLIP_01')) +``` + - **Parameters:** - `weapon_component` (String): The weapon component. - **Returns:** - `component_display_desc`: String: the in-game display string. If the component is not found, or the call is made too early, a blank string will be returned. It is guranteed to return a safe value. -- **Example Usage:** +**Example Usage:** ```lua -log.info(weapons.get_weapon_component_display_desc('COMPONENT_PISTOL_CLIP_01')) -``` \ No newline at end of file +component_display_desc = weapons.get_weapon_component_display_desc(weapon_component) +``` + + diff --git a/scripts/doc_gen.py b/scripts/doc_gen.py index c69bdabd..816e9625 100644 --- a/scripts/doc_gen.py +++ b/scripts/doc_gen.py @@ -1,7 +1,7 @@ import os from enum import Enum -src_folder = "../../src/" +src_folder = "../src/" lua_api_comment_identifier = "lua api" lua_api_comment_separator = ":" @@ -597,19 +597,19 @@ def is_lua_doc_comment_startswith(line_lower, starts_with_text): parse_lua_api_doc(src_folder) try: - os.makedirs("./tables/") + os.makedirs("../docs/lua/tables/") except: pass for table_name, table in tables.items(): - file_name = f"./tables/{table_name}.md" + file_name = f"../docs/lua/tables/{table_name}.md" if os.path.exists(file_name): os.remove(file_name) f = open(file_name, "ba") f.write(bytes(str(table), "UTF8")) f.close() -tabs_file_name = f"./tabs.md" +tabs_file_name = f"../docs/lua/tabs.md" if os.path.exists(tabs_file_name): os.remove(tabs_file_name) f = open(tabs_file_name, "a") @@ -641,7 +641,7 @@ for i in range(1, len(tabs_enum) - 1): f.close() -infraction_file_name = f"../lua/infraction.md" +infraction_file_name = f"../docs/lua/infraction.md" if os.path.exists(infraction_file_name): os.remove(infraction_file_name) f = open(infraction_file_name, "a") @@ -667,12 +667,12 @@ for i in range(0, len(infraction_enum)): f.close() try: - os.makedirs("./classes/") + os.makedirs("../docs/lua/classes/") except: pass for class_name, class_ in classes.items(): - file_name = f"./classes/{class_name}.md" + file_name = f"../docs/lua/classes/{class_name}.md" if os.path.exists(file_name): os.remove(file_name) f = open(file_name, "ba") @@ -680,7 +680,7 @@ for class_name, class_ in classes.items(): f.close() -commands_file_name = f"./commands.md" +commands_file_name = f"../docs/lua/commands.md" if os.path.exists(commands_file_name): os.remove(commands_file_name) f = open(commands_file_name, "a") @@ -704,7 +704,7 @@ For a complete list of available command functions, please refer to the command commands = [] -with open("./commands_dump.txt", "r") as file: +with open("../docs/lua/commands_dump.txt", "r") as file: for line in file: cmd = line.split("|", 1)[1].strip().split("|") commands.append(cmd) diff --git a/src/lua/lua_module.cpp b/src/lua/lua_module.cpp index 34f544b7..5c37e1e7 100644 --- a/src/lua/lua_module.cpp +++ b/src/lua/lua_module.cpp @@ -190,24 +190,34 @@ namespace big m_state["os"] = sandbox_os; } + static std::optional make_absolute(const std::filesystem::path& root, const std::filesystem::path& user_path) + { + auto final_path = std::filesystem::weakly_canonical(root / user_path); + + auto [root_end, nothing] = std::mismatch(root.begin(), root.end(), final_path.begin()); + + if (root_end != root.end()) + return std::nullopt; + + return final_path; + }; + void lua_module::sandbox_lua_io_library() { auto io = m_state["io"]; sol::table sandbox_io(m_state, sol::create); - m_io_open = io["open"]; + m_io_open = io["open"]; + + // Lua API: Table + // Name: io + // Table for file manipulation. Modified for security purposes. + + // Lua API: Function + // Table: io + // Name: open + // Returns: file_handle: file handle or nil if can't read / write to the given path. sandbox_io["open"] = [this](const std::string& filename, const std::string& mode) { - constexpr auto make_absolute = [](const std::filesystem::path& root, const std::filesystem::path& user_path) -> std::optional { - auto final_path = std::filesystem::weakly_canonical(root / user_path); - - auto [root_end, nothing] = std::mismatch(root.begin(), root.end(), final_path.begin()); - - if (root_end != root.end()) - return std::nullopt; - - return final_path; - }; - const auto scripts_config_sub_path = make_absolute(g_lua_manager->get_scripts_config_folder().get_path(), filename); if (!scripts_config_sub_path) { @@ -220,12 +230,28 @@ namespace big if (res.get_type() == sol::type::lua_nil) { - LOG(WARNING) << "Couldn't io.open a file called " << filename << " mode (" << mode << "). Note that io.open is restricted to the scripts_config folder."; + LOG(WARNING) << "Couldn't io.open a file called " << filename << " mode (" << mode << "). Note that io.open is restricted to the scripts_config folder. If you want to check if a file exists, use io.exists"; } return res; }; + // Lua API: Function + // Table: io + // Name: exists + // Returns: boolean: True if the passed file path exists + sandbox_io["exists"] = [](const std::string& filename) -> bool { + const auto scripts_config_sub_path = make_absolute(g_lua_manager->get_scripts_config_folder().get_path(), filename); + if (!scripts_config_sub_path) + { + LOG(WARNING) << "io.open is restricted to the scripts_config folder, and the filename provided (" << filename << ") is outside of it."; + + return false; + } + + return std::filesystem::exists(*scripts_config_sub_path); + }; + m_state["io"] = sandbox_io; } @@ -329,4 +355,4 @@ namespace big return script->is_done(); }); } -} \ No newline at end of file +}