mirror of
https://github.com/lune-org/docs.git
synced 2024-12-12 04:50:36 +00:00
Include Security Article in Documentation (#10)
This commit is contained in:
parent
712a7b5a5e
commit
4b8ac980ff
5 changed files with 2439 additions and 665 deletions
149
modules/sandbox.luau
Normal file
149
modules/sandbox.luau
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
local datetime = require("@lune/datetime")
|
||||||
|
local fs = require("@lune/fs")
|
||||||
|
local luau = require("@lune/luau")
|
||||||
|
local net = require("@lune/net")
|
||||||
|
local process = require("@lune/process")
|
||||||
|
local regex = require("@lune/regex")
|
||||||
|
local roblox = require("@lune/roblox")
|
||||||
|
local serde = require("@lune/serde")
|
||||||
|
local stdio = require("@lune/stdio")
|
||||||
|
local task = require("@lune/task")
|
||||||
|
|
||||||
|
local processArgs = table.clone(process.args)
|
||||||
|
local filePath: string = table.remove(processArgs, 1)
|
||||||
|
or error("usage: lune run sandbox [SCRIPT_PATH] -- [ARGS]")
|
||||||
|
|
||||||
|
local DEFAULT_PRINT = print
|
||||||
|
local SANDBOXED_ENV = {
|
||||||
|
debugName = filePath,
|
||||||
|
environment = {
|
||||||
|
require = nil,
|
||||||
|
getfenv = nil,
|
||||||
|
setfenv = nil,
|
||||||
|
print = nil,
|
||||||
|
warn = nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local PROMPT_MSG_TMPL = `allow {SANDBOXED_ENV.debugName} to access %s?`
|
||||||
|
local DENIED_ERR_TMPL = `{SANDBOXED_ENV.debugName} tried to access disallowed library %s!`
|
||||||
|
|
||||||
|
local function discoverAndReadScript(filePath: string): string
|
||||||
|
local scriptContents: string
|
||||||
|
|
||||||
|
if fs.isFile(filePath) then
|
||||||
|
scriptContents = fs.readFile(filePath)
|
||||||
|
return scriptContents
|
||||||
|
end
|
||||||
|
|
||||||
|
if fs.isDir(filePath) then
|
||||||
|
if fs.isFile(filePath .. "/init.luau") then
|
||||||
|
scriptContents = fs.readFile(filePath .. "/init.luau")
|
||||||
|
end
|
||||||
|
|
||||||
|
if fs.isFile(filePath .. "/init.lua") then
|
||||||
|
scriptContents = fs.readFile(filePath .. "init.lua")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if scriptContents == nil then
|
||||||
|
for _, ext in { ".luau", ".lua" } do
|
||||||
|
local filePathExt = filePath .. ext
|
||||||
|
if fs.isFile(filePathExt) then
|
||||||
|
scriptContents = fs.readFile(filePathExt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if scriptContents == nil then
|
||||||
|
error(`No such file or directory \`{filePath}\``)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return scriptContents
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxGetfenv(): {}
|
||||||
|
if table.isfrozen(SANDBOXED_ENV) then
|
||||||
|
return SANDBOXED_ENV.environment
|
||||||
|
end
|
||||||
|
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxSetfenv(env: {}): never
|
||||||
|
error("cannot call setfenv from sandbox")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxPrint(...: any)
|
||||||
|
DEFAULT_PRINT(`---- Output from {SANDBOXED_ENV.debugName} ----`)
|
||||||
|
DEFAULT_PRINT(tostring(...))
|
||||||
|
DEFAULT_PRINT(`---------------------------------------`)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function constructProtectedMt<T>(library: T)
|
||||||
|
return {
|
||||||
|
__index = library,
|
||||||
|
__metatable = "Locked",
|
||||||
|
__tostring = function()
|
||||||
|
return stdio.format(library)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local SANDBOXED_LUNE_STD_LIB = {
|
||||||
|
["@lune/fs"] = setmetatable({}, constructProtectedMt(fs)),
|
||||||
|
["@lune/luau"] = setmetatable({}, constructProtectedMt(luau)),
|
||||||
|
["@lune/process"] = setmetatable({}, constructProtectedMt(process)),
|
||||||
|
["@lune/stdio"] = setmetatable({
|
||||||
|
write = sandboxPrint,
|
||||||
|
ewrite = sandboxPrint,
|
||||||
|
}, constructProtectedMt(stdio)),
|
||||||
|
["@lune/net"] = setmetatable({}, constructProtectedMt(net)),
|
||||||
|
["@lune/roblox"] = setmetatable({
|
||||||
|
getAuthCookie = function(...)
|
||||||
|
local allowAuthCookie: boolean = stdio.prompt(
|
||||||
|
"confirm",
|
||||||
|
`allow {SANDBOXED_ENV.debugName} to access your .ROBLOSECURITY token?`
|
||||||
|
)
|
||||||
|
|
||||||
|
if allowAuthCookie then
|
||||||
|
local getAuthCookie = require("@lune/roblox").getAuthCookie
|
||||||
|
return getAuthCookie(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
error(
|
||||||
|
`{SANDBOXED_ENV.debugName} attempted to access .ROBLOSECURITY token even when denied`
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
}, constructProtectedMt(roblox)),
|
||||||
|
["@lune/serde"] = serde,
|
||||||
|
["@lune/task"] = task,
|
||||||
|
["@lune/regex"] = regex,
|
||||||
|
["@lune/datetime"] = datetime,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function sandboxedRequire(path: string)
|
||||||
|
local module = SANDBOXED_LUNE_STD_LIB[path]
|
||||||
|
|
||||||
|
if module then
|
||||||
|
local allowed: boolean = stdio.prompt("confirm", string.format(PROMPT_MSG_TMPL, path))
|
||||||
|
|
||||||
|
if allowed then
|
||||||
|
return module
|
||||||
|
end
|
||||||
|
|
||||||
|
error(string.format(DENIED_ERR_TMPL, path))
|
||||||
|
else
|
||||||
|
local contents = discoverAndReadScript(path)
|
||||||
|
|
||||||
|
local evalChunk = luau.load(contents, SANDBOXED_ENV)
|
||||||
|
return evalChunk()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SANDBOXED_ENV.environment.require = sandboxedRequire
|
||||||
|
SANDBOXED_ENV.environment.getfenv = sandboxGetfenv
|
||||||
|
SANDBOXED_ENV.environment.setfenv = sandboxSetfenv
|
||||||
|
SANDBOXED_ENV.environment.print = sandboxPrint
|
||||||
|
SANDBOXED_ENV.environment.warn = sandboxPrint
|
||||||
|
luau.load(discoverAndReadScript(filePath), table.freeze(SANDBOXED_ENV))()
|
2741
package-lock.json
generated
2741
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
@ -15,15 +15,15 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/lune-orc/docs#readme",
|
"homepage": "https://github.com/lune-orc/docs#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "^13.4.12",
|
"next": "^13.5.6",
|
||||||
"nextra": "^2.10.0",
|
"nextra": "^2.13.4",
|
||||||
"nextra-theme-docs": "^2.10.0",
|
"nextra-theme-docs": "^2.13.4",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.11.10",
|
"@types/node": "18.11.10",
|
||||||
"eslint": "^8.45.0",
|
"eslint": "^8.57.0",
|
||||||
"next": "^13.4.12",
|
"next": "^13.4.12",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
}
|
}
|
||||||
|
|
199
pages/getting-started/5-security.mdx
Normal file
199
pages/getting-started/5-security.mdx
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
import { Steps } from "nextra/components"
|
||||||
|
|
||||||
|
# Security
|
||||||
|
|
||||||
|
When running lune scripts, it is important to note that any scripts you execute have full access to
|
||||||
|
your device, including access to your files, programs, and more. Therefore, it is important to stay
|
||||||
|
cautious when executing a script from a source you don't trust.
|
||||||
|
|
||||||
|
If you are unsure what a script does, it is recommended to run the script in a
|
||||||
|
[sandboxed](https://en.wikipedia.org/wiki/Sandbox_(computer_security)) environment to evaluate what
|
||||||
|
it does.
|
||||||
|
|
||||||
|
Lune does not include a built-in permissions sandbox, but the following luau script, which utilizes
|
||||||
|
the [@lune/luau](/api-reference/luau) library can be used.
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
|
||||||
|
### Step 1
|
||||||
|
|
||||||
|
Copy the source below and place it in a file named `sandbox.luau`:
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click to expand</summary>
|
||||||
|
|
||||||
|
```lua copy
|
||||||
|
local datetime = require("@lune/datetime")
|
||||||
|
local fs = require("@lune/fs")
|
||||||
|
local luau = require("@lune/luau")
|
||||||
|
local net = require("@lune/net")
|
||||||
|
local process = require("@lune/process")
|
||||||
|
local regex = require("@lune/regex")
|
||||||
|
local roblox = require("@lune/roblox")
|
||||||
|
local serde = require("@lune/serde")
|
||||||
|
local stdio = require("@lune/stdio")
|
||||||
|
local task = require("@lune/task")
|
||||||
|
|
||||||
|
local processArgs = table.clone(process.args)
|
||||||
|
local filePath: string = table.remove(processArgs, 1)
|
||||||
|
or error("usage: lune run sandbox [SCRIPT_PATH] -- [ARGS]")
|
||||||
|
|
||||||
|
local DEFAULT_PRINT = print
|
||||||
|
local SANDBOXED_ENV = {
|
||||||
|
debugName = filePath,
|
||||||
|
environment = {
|
||||||
|
require = nil,
|
||||||
|
getfenv = nil,
|
||||||
|
setfenv = nil,
|
||||||
|
print = nil,
|
||||||
|
warn = nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local PROMPT_MSG_TMPL = `allow {SANDBOXED_ENV.debugName} to access %s?`
|
||||||
|
local DENIED_ERR_TMPL = `{SANDBOXED_ENV.debugName} tried to access disallowed library %s!`
|
||||||
|
|
||||||
|
local function discoverAndReadScript(filePath: string): string
|
||||||
|
local scriptContents: string
|
||||||
|
|
||||||
|
if fs.isFile(filePath) then
|
||||||
|
scriptContents = fs.readFile(filePath)
|
||||||
|
return scriptContents
|
||||||
|
end
|
||||||
|
|
||||||
|
if fs.isDir(filePath) then
|
||||||
|
if fs.isFile(filePath .. "/init.luau") then
|
||||||
|
scriptContents = fs.readFile(filePath .. "/init.luau")
|
||||||
|
end
|
||||||
|
|
||||||
|
if fs.isFile(filePath .. "/init.lua") then
|
||||||
|
scriptContents = fs.readFile(filePath .. "init.lua")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if scriptContents == nil then
|
||||||
|
for _, ext in { ".luau", ".lua" } do
|
||||||
|
local filePathExt = filePath .. ext
|
||||||
|
if fs.isFile(filePathExt) then
|
||||||
|
scriptContents = fs.readFile(filePathExt)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if scriptContents == nil then
|
||||||
|
error(`No such file or directory \`{filePath}\``)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return scriptContents
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxGetfenv(): {}
|
||||||
|
if table.isfrozen(SANDBOXED_ENV) then
|
||||||
|
return SANDBOXED_ENV.environment
|
||||||
|
end
|
||||||
|
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxSetfenv(env: {}): never
|
||||||
|
error("cannot call setfenv from sandbox")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxPrint(...: any)
|
||||||
|
DEFAULT_PRINT(`---- Output from {SANDBOXED_ENV.debugName} ----`)
|
||||||
|
DEFAULT_PRINT(tostring(...))
|
||||||
|
DEFAULT_PRINT(`---------------------------------------`)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function constructProtectedMt<T>(library: T)
|
||||||
|
return {
|
||||||
|
__index = library,
|
||||||
|
__metatable = "Locked",
|
||||||
|
__tostring = function()
|
||||||
|
return stdio.format(library)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local SANDBOXED_LUNE_STD_LIB = {
|
||||||
|
["@lune/fs"] = setmetatable({}, constructProtectedMt(fs)),
|
||||||
|
["@lune/luau"] = setmetatable({}, constructProtectedMt(luau)),
|
||||||
|
["@lune/process"] = setmetatable({}, constructProtectedMt(process)),
|
||||||
|
["@lune/stdio"] = setmetatable({
|
||||||
|
write = sandboxPrint,
|
||||||
|
ewrite = sandboxPrint,
|
||||||
|
}, constructProtectedMt(stdio)),
|
||||||
|
["@lune/net"] = setmetatable({}, constructProtectedMt(net)),
|
||||||
|
["@lune/roblox"] = setmetatable({
|
||||||
|
getAuthCookie = function(...)
|
||||||
|
local allowAuthCookie: boolean = stdio.prompt(
|
||||||
|
"confirm",
|
||||||
|
`allow {SANDBOXED_ENV.debugName} to access your .ROBLOSECURITY token?`
|
||||||
|
)
|
||||||
|
|
||||||
|
if allowAuthCookie then
|
||||||
|
local getAuthCookie = require("@lune/roblox").getAuthCookie
|
||||||
|
return getAuthCookie(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
error(
|
||||||
|
`{SANDBOXED_ENV.debugName} attempted to access .ROBLOSECURITY token even when denied`
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
}, constructProtectedMt(roblox)),
|
||||||
|
["@lune/serde"] = serde,
|
||||||
|
["@lune/task"] = task,
|
||||||
|
["@lune/regex"] = regex,
|
||||||
|
["@lune/datetime"] = datetime,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function sandboxedRequire(path: string)
|
||||||
|
local module = SANDBOXED_LUNE_STD_LIB[path]
|
||||||
|
|
||||||
|
if module then
|
||||||
|
local allowed: boolean = stdio.prompt("confirm", string.format(PROMPT_MSG_TMPL, path))
|
||||||
|
|
||||||
|
if allowed then
|
||||||
|
return module
|
||||||
|
end
|
||||||
|
|
||||||
|
error(string.format(DENIED_ERR_TMPL, path))
|
||||||
|
else
|
||||||
|
local contents = discoverAndReadScript(path)
|
||||||
|
|
||||||
|
local evalChunk = luau.load(contents, SANDBOXED_ENV)
|
||||||
|
return evalChunk()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
SANDBOXED_ENV.environment.require = sandboxedRequire
|
||||||
|
SANDBOXED_ENV.environment.getfenv = sandboxGetfenv
|
||||||
|
SANDBOXED_ENV.environment.setfenv = sandboxSetfenv
|
||||||
|
SANDBOXED_ENV.environment.print = sandboxPrint
|
||||||
|
SANDBOXED_ENV.environment.warn = sandboxPrint
|
||||||
|
luau.load(discoverAndReadScript(filePath), table.freeze(SANDBOXED_ENV))()
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Step 2
|
||||||
|
|
||||||
|
Now, place the untrusted script you want to run safely next to the `sandbox.luau` script.
|
||||||
|
|
||||||
|
```sh copy filename="Bash"
|
||||||
|
lune run sandbox.luau script.luau -- [ARGUMENTS_HERE]
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `script.luau` and `[ARGUMENTS_HERE]` with the path to the script and the arguments to run
|
||||||
|
it with.
|
||||||
|
|
||||||
|
### Step 3
|
||||||
|
|
||||||
|
As the script runs, any requires to potentially dangerous modules will require your approval
|
||||||
|
before continuing and any invocations to methods within approved modules will be logged.
|
||||||
|
|
||||||
|
Furthermore, the output of the sandbox script and the script being run will be separated.
|
||||||
|
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,6 @@
|
||||||
"1-installation": "Installation",
|
"1-installation": "Installation",
|
||||||
"2-introduction": "Introduction",
|
"2-introduction": "Introduction",
|
||||||
"3-command-line-usage": "Command-Line Usage",
|
"3-command-line-usage": "Command-Line Usage",
|
||||||
"4-editor-setup": "Editor Setup"
|
"4-editor-setup": "Editor Setup",
|
||||||
|
"5-security": "Security"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue