Re-add os.rename and os.remove support

This commit is contained in:
Christian Kaiser 2025-04-19 12:51:32 -03:00 committed by David Capello
parent 4c31c950c5
commit 54ea61fe58
3 changed files with 103 additions and 3 deletions

View File

@ -1692,7 +1692,8 @@ title = Save Selection (.msk file)
[script_access]
title = Security
script_label = The following script:
file_label = wants to access to this file:
file_label = wants to access this file:
file_write_label = wants to write to this file:
command_label = wants to execute the following command:
websocket_label = wants to open a WebSocket connection to this URL:
clipboard_label = wants to access the system clipboard

View File

@ -40,6 +40,8 @@ int secure_io_lines(lua_State* L);
int secure_io_input(lua_State* L);
int secure_io_output(lua_State* L);
int secure_os_execute(lua_State* L);
int secure_os_remove(lua_State* L);
int secure_os_rename(lua_State* L);
int secure_package_loadlib(lua_State* L);
enum {
@ -49,6 +51,8 @@ enum {
io_input,
io_output,
os_execute,
os_remove,
os_rename,
package_loadlib,
};
@ -64,6 +68,8 @@ static struct {
{ "io", "input", secure_io_input },
{ "io", "output", secure_io_output },
{ "os", "execute", secure_os_execute },
{ "os", "remove", secure_os_remove },
{ "os", "rename", secure_os_rename },
{ "package", "loadlib", secure_package_loadlib },
};
@ -185,6 +191,81 @@ int secure_os_execute(lua_State* L)
return replaced_functions[os_execute].origfunc(L);
}
int file_result(lua_State* L, bool result, int errorNo = 0, const std::string& fileName = "")
{
if (result) {
lua_pushboolean(L, 1);
return 1;
}
luaL_pushfail(L);
if (fileName.empty())
lua_pushstring(L, strerror(errorNo));
else
lua_pushfstring(L, "%s: %s", fileName.c_str(), strerror(errorNo));
lua_pushinteger(L, errorNo);
return 3;
}
int secure_os_remove(lua_State* L)
{
const std::string absFilename = base::get_canonical_path(luaL_checkstring(L, 1));
if (absFilename.empty())
return file_result(L, false, ENOENT, absFilename);
if (!ask_access(L, absFilename.data(), FileAccessMode::Write, ResourceType::File))
return file_result(L, false, EACCES, absFilename);
if (base::is_directory(absFilename)) {
try {
base::remove_directory(absFilename);
return file_result(L, true);
}
catch (std::exception& e) {
return file_result(L, false, EIO, absFilename);
}
}
try {
base::delete_file(absFilename);
}
catch (std::exception& e) {
return file_result(L, false, EIO, absFilename);
}
return file_result(L, true);
}
int secure_os_rename(lua_State* L)
{
const std::string absSourceFilename = base::get_canonical_path(luaL_checkstring(L, 1));
const std::string absDestFilename = base::get_absolute_path(luaL_checkstring(L, 2));
lua_pop(L, 2);
if (absSourceFilename.empty())
return file_result(L, false, ENOENT, absSourceFilename);
if (absDestFilename.empty())
return file_result(L, false, EINVAL, absDestFilename);
if (!ask_access(L, absSourceFilename.data(), FileAccessMode::Write, ResourceType::File))
return file_result(L, false, EACCES, absSourceFilename);
try {
// If the destination file already exists, we should ask for permission to overwrite it.
if (!base::get_canonical_path(absDestFilename).empty() &&
!ask_access(L, absDestFilename.data(), FileAccessMode::Write, ResourceType::File)) {
return file_result(L, false, EACCES, absDestFilename);
}
base::move_file(absSourceFilename, absDestFilename);
return file_result(L, true);
}
catch (std::exception& e) {
return file_result(L, false, EIO, absSourceFilename);
}
}
int secure_package_loadlib(lua_State* L)
{
const char* cmd = luaL_checkstring(L, 1);
@ -201,7 +282,7 @@ void overwrite_unsecure_functions(lua_State* L)
{
// Remove unsupported functions
lua_getglobal(L, "os");
for (const char* name : { "remove", "rename", "exit", "tmpname" }) {
for (const char* name : { "exit", "tmpname" }) {
lua_pushcfunction(L, unsupported);
lua_setfield(L, -2, name);
}
@ -280,7 +361,15 @@ bool ask_access(lua_State* L,
{
std::string label;
switch (resourceType) {
case ResourceType::File: label = Strings::script_access_file_label(); break;
case ResourceType::File: {
if (mode == FileAccessMode::Write) {
label = Strings::script_access_file_write_label();
}
else {
label = Strings::script_access_file_label();
}
break;
}
case ResourceType::Command: label = Strings::script_access_command_label(); break;
case ResourceType::WebSocket: label = Strings::script_access_websocket_label(); break;
case ResourceType::Clipboard: label = Strings::script_access_clipboard_label(); break;

View File

@ -12,3 +12,13 @@ print("Start ", start_clock)
local end_clock = os.clock()
print("End ", end_clock, " Elapsed ", end_clock - start_clock)
assert(start_clock < end_clock)
-- os.rename & remove
assert(app.fs.makeDirectory("_os_tmp"))
assert(os.rename("_os_tmp", "_os_tmp_renamed"))
assert(not os.rename("_os_tmp", "_os_tmp_shouldfail"))
assert(not os.remove("_os_tmp_shouldfail"))
assert(not os.rename("_os_tmp_shouldfail", "_test1.png")) -- Should fail, already exists
assert(os.remove("_os_tmp_renamed"))
assert(not app.fs.isDirectory("_os_tmp"))
assert(not app.fs.isDirectory("_os_tmp_renamed"))