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",
|
||||
"dependencies": {
|
||||
"next": "^13.4.12",
|
||||
"nextra": "^2.10.0",
|
||||
"nextra-theme-docs": "^2.10.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"next": "^13.5.6",
|
||||
"nextra": "^2.13.4",
|
||||
"nextra-theme-docs": "^2.13.4",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "18.11.10",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint": "^8.57.0",
|
||||
"next": "^13.4.12",
|
||||
"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",
|
||||
"2-introduction": "Introduction",
|
||||
"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