string, table, crypto and util library changes
This commit is contained in:
parent
861ab73d83
commit
9ea06eb1b4
404
core/runner/crypto.go
Normal file
404
core/runner/crypto.go
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
package runner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"hash"
|
||||||
|
"math"
|
||||||
|
mrand "math/rand/v2"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Map to store state-specific RNGs
|
||||||
|
stateRngs = make(map[*luajit.State]*mrand.PCG)
|
||||||
|
stateRngsMu sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterCryptoFunctions registers all crypto functions with the Lua state
|
||||||
|
func RegisterCryptoFunctions(state *luajit.State) error {
|
||||||
|
// Create a state-specific RNG
|
||||||
|
stateRngsMu.Lock()
|
||||||
|
stateRngs[state] = mrand.NewPCG(uint64(time.Now().UnixNano()), uint64(time.Now().UnixNano()>>32))
|
||||||
|
stateRngsMu.Unlock()
|
||||||
|
|
||||||
|
// Register hash functions
|
||||||
|
if err := state.RegisterGoFunction("__crypto_hash", cryptoHash); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register HMAC functions
|
||||||
|
if err := state.RegisterGoFunction("__crypto_hmac", cryptoHmac); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register UUID generation
|
||||||
|
if err := state.RegisterGoFunction("__crypto_uuid", cryptoUuid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register random functions
|
||||||
|
if err := state.RegisterGoFunction("__crypto_random", cryptoRandom); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := state.RegisterGoFunction("__crypto_random_bytes", cryptoRandomBytes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := state.RegisterGoFunction("__crypto_random_int", cryptoRandomInt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := state.RegisterGoFunction("__crypto_random_seed", cryptoRandomSeed); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override Lua's math.random
|
||||||
|
if err := OverrideLuaRandom(state); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CleanupCrypto cleans up resources when a state is closed
|
||||||
|
func CleanupCrypto(state *luajit.State) {
|
||||||
|
stateRngsMu.Lock()
|
||||||
|
delete(stateRngs, state)
|
||||||
|
stateRngsMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoHash generates hash digests using various algorithms
|
||||||
|
func cryptoHash(state *luajit.State) int {
|
||||||
|
if !state.IsString(1) || !state.IsString(2) {
|
||||||
|
state.PushString("hash: expected (string data, string algorithm)")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
data := state.ToString(1)
|
||||||
|
algorithm := state.ToString(2)
|
||||||
|
|
||||||
|
var h hash.Hash
|
||||||
|
|
||||||
|
switch algorithm {
|
||||||
|
case "md5":
|
||||||
|
h = md5.New()
|
||||||
|
case "sha1":
|
||||||
|
h = sha1.New()
|
||||||
|
case "sha256":
|
||||||
|
h = sha256.New()
|
||||||
|
case "sha512":
|
||||||
|
h = sha512.New()
|
||||||
|
default:
|
||||||
|
state.PushString(fmt.Sprintf("unsupported algorithm: %s", algorithm))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Write([]byte(data))
|
||||||
|
hashBytes := h.Sum(nil)
|
||||||
|
|
||||||
|
// Output format
|
||||||
|
outputFormat := "hex"
|
||||||
|
if state.GetTop() >= 3 && state.IsString(3) {
|
||||||
|
outputFormat = state.ToString(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch outputFormat {
|
||||||
|
case "hex":
|
||||||
|
state.PushString(hex.EncodeToString(hashBytes))
|
||||||
|
case "binary":
|
||||||
|
state.PushString(string(hashBytes))
|
||||||
|
default:
|
||||||
|
state.PushString(hex.EncodeToString(hashBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoHmac generates HMAC using various hash algorithms
|
||||||
|
func cryptoHmac(state *luajit.State) int {
|
||||||
|
if !state.IsString(1) || !state.IsString(2) || !state.IsString(3) {
|
||||||
|
state.PushString("hmac: expected (string data, string key, string algorithm)")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
data := state.ToString(1)
|
||||||
|
key := state.ToString(2)
|
||||||
|
algorithm := state.ToString(3)
|
||||||
|
|
||||||
|
var h func() hash.Hash
|
||||||
|
|
||||||
|
switch algorithm {
|
||||||
|
case "md5":
|
||||||
|
h = md5.New
|
||||||
|
case "sha1":
|
||||||
|
h = sha1.New
|
||||||
|
case "sha256":
|
||||||
|
h = sha256.New
|
||||||
|
case "sha512":
|
||||||
|
h = sha512.New
|
||||||
|
default:
|
||||||
|
state.PushString(fmt.Sprintf("unsupported algorithm: %s", algorithm))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mac := hmac.New(h, []byte(key))
|
||||||
|
mac.Write([]byte(data))
|
||||||
|
macBytes := mac.Sum(nil)
|
||||||
|
|
||||||
|
// Output format
|
||||||
|
outputFormat := "hex"
|
||||||
|
if state.GetTop() >= 4 && state.IsString(4) {
|
||||||
|
outputFormat = state.ToString(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch outputFormat {
|
||||||
|
case "hex":
|
||||||
|
state.PushString(hex.EncodeToString(macBytes))
|
||||||
|
case "binary":
|
||||||
|
state.PushString(string(macBytes))
|
||||||
|
default:
|
||||||
|
state.PushString(hex.EncodeToString(macBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoUuid generates a random UUID v4
|
||||||
|
func cryptoUuid(state *luajit.State) int {
|
||||||
|
uuid := make([]byte, 16)
|
||||||
|
_, err := rand.Read(uuid)
|
||||||
|
if err != nil {
|
||||||
|
state.PushString(fmt.Sprintf("uuid: generation error: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set version (4) and variant (RFC 4122)
|
||||||
|
uuid[6] = (uuid[6] & 0x0F) | 0x40
|
||||||
|
uuid[8] = (uuid[8] & 0x3F) | 0x80
|
||||||
|
|
||||||
|
uuidStr := fmt.Sprintf("%x-%x-%x-%x-%x",
|
||||||
|
uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
|
||||||
|
|
||||||
|
state.PushString(uuidStr)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoRandomBytes generates random bytes
|
||||||
|
func cryptoRandomBytes(state *luajit.State) int {
|
||||||
|
if !state.IsNumber(1) {
|
||||||
|
state.PushString("random_bytes: expected (number length)")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
length := int(state.ToNumber(1))
|
||||||
|
if length <= 0 {
|
||||||
|
state.PushString("random_bytes: length must be positive")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if secure
|
||||||
|
secure := true
|
||||||
|
if state.GetTop() >= 2 && state.IsBoolean(2) {
|
||||||
|
secure = state.ToBoolean(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes := make([]byte, length)
|
||||||
|
|
||||||
|
if secure {
|
||||||
|
_, err := rand.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
state.PushString(fmt.Sprintf("random_bytes: error: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stateRngsMu.Lock()
|
||||||
|
stateRng, ok := stateRngs[state]
|
||||||
|
stateRngsMu.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
state.PushString("random_bytes: RNG not initialized")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[i] = byte(stateRng.Uint64() & 0xFF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output format
|
||||||
|
outputFormat := "binary"
|
||||||
|
if state.GetTop() >= 3 && state.IsString(3) {
|
||||||
|
outputFormat = state.ToString(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch outputFormat {
|
||||||
|
case "binary":
|
||||||
|
state.PushString(string(bytes))
|
||||||
|
case "hex":
|
||||||
|
state.PushString(hex.EncodeToString(bytes))
|
||||||
|
default:
|
||||||
|
state.PushString(string(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoRandomInt generates a random integer in range [min, max]
|
||||||
|
func cryptoRandomInt(state *luajit.State) int {
|
||||||
|
if !state.IsNumber(1) || !state.IsNumber(2) {
|
||||||
|
state.PushString("random_int: expected (number min, number max)")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
min := int64(state.ToNumber(1))
|
||||||
|
max := int64(state.ToNumber(2))
|
||||||
|
|
||||||
|
if max <= min {
|
||||||
|
state.PushString("random_int: max must be greater than min")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if secure
|
||||||
|
secure := true
|
||||||
|
if state.GetTop() >= 3 && state.IsBoolean(3) {
|
||||||
|
secure = state.ToBoolean(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
range_size := max - min + 1
|
||||||
|
|
||||||
|
var result int64
|
||||||
|
|
||||||
|
if secure {
|
||||||
|
bytes := make([]byte, 8)
|
||||||
|
_, err := rand.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
state.PushString(fmt.Sprintf("random_int: error: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
val := binary.BigEndian.Uint64(bytes)
|
||||||
|
result = min + int64(val%uint64(range_size))
|
||||||
|
} else {
|
||||||
|
stateRngsMu.Lock()
|
||||||
|
stateRng, ok := stateRngs[state]
|
||||||
|
stateRngsMu.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
state.PushString("random_int: RNG not initialized")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
result = min + int64(stateRng.Uint64()%uint64(range_size))
|
||||||
|
}
|
||||||
|
|
||||||
|
state.PushNumber(float64(result))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoRandom implements math.random functionality
|
||||||
|
func cryptoRandom(state *luajit.State) int {
|
||||||
|
numArgs := state.GetTop()
|
||||||
|
|
||||||
|
// Check if secure
|
||||||
|
secure := false
|
||||||
|
|
||||||
|
// math.random() - return [0,1)
|
||||||
|
if numArgs == 0 {
|
||||||
|
if secure {
|
||||||
|
bytes := make([]byte, 8)
|
||||||
|
_, err := rand.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
state.PushString(fmt.Sprintf("random: error: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
val := binary.BigEndian.Uint64(bytes)
|
||||||
|
state.PushNumber(float64(val) / float64(math.MaxUint64))
|
||||||
|
} else {
|
||||||
|
stateRngsMu.Lock()
|
||||||
|
stateRng, ok := stateRngs[state]
|
||||||
|
stateRngsMu.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
state.PushString("random: RNG not initialized")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
state.PushNumber(float64(stateRng.Uint64()) / float64(math.MaxUint64))
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// math.random(n) - return integer [1,n]
|
||||||
|
if numArgs == 1 && state.IsNumber(1) {
|
||||||
|
n := int64(state.ToNumber(1))
|
||||||
|
if n < 1 {
|
||||||
|
state.PushString("random: upper bound must be >= 1")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
state.PushNumber(1) // min
|
||||||
|
state.PushNumber(float64(n)) // max
|
||||||
|
state.PushBoolean(secure) // secure flag
|
||||||
|
return cryptoRandomInt(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// math.random(m, n) - return integer [m,n]
|
||||||
|
if numArgs >= 2 && state.IsNumber(1) && state.IsNumber(2) {
|
||||||
|
state.PushBoolean(secure) // secure flag
|
||||||
|
return cryptoRandomInt(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.PushString("random: invalid arguments")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// cryptoRandomSeed sets seed for non-secure RNG
|
||||||
|
func cryptoRandomSeed(state *luajit.State) int {
|
||||||
|
if !state.IsNumber(1) {
|
||||||
|
state.PushString("randomseed: expected (number seed)")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
seed := uint64(state.ToNumber(1))
|
||||||
|
|
||||||
|
stateRngsMu.Lock()
|
||||||
|
stateRngs[state] = mrand.NewPCG(seed, seed>>32)
|
||||||
|
stateRngsMu.Unlock()
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// OverrideLuaRandom replaces Lua's math.random with Go implementation
|
||||||
|
func OverrideLuaRandom(state *luajit.State) error {
|
||||||
|
if err := state.RegisterGoFunction("go_math_random", cryptoRandom); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := state.RegisterGoFunction("go_math_randomseed", cryptoRandomSeed); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace original functions
|
||||||
|
return state.DoString(`
|
||||||
|
-- Save original functions
|
||||||
|
_G._original_math_random = math.random
|
||||||
|
_G._original_math_randomseed = math.randomseed
|
||||||
|
|
||||||
|
-- Replace with Go implementations
|
||||||
|
math.random = go_math_random
|
||||||
|
math.randomseed = go_math_randomseed
|
||||||
|
|
||||||
|
-- Clean up global namespace
|
||||||
|
go_math_random = nil
|
||||||
|
go_math_randomseed = nil
|
||||||
|
`)
|
||||||
|
}
|
148
core/runner/crypto.lua
Normal file
148
core/runner/crypto.lua
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
--[[
|
||||||
|
crypto.lua - Cryptographic functions powered by Go
|
||||||
|
]]--
|
||||||
|
|
||||||
|
local crypto = {}
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- HASHING FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Generate hash digest using various algorithms
|
||||||
|
-- Algorithms: md5, sha1, sha256, sha512
|
||||||
|
-- Formats: hex (default), binary
|
||||||
|
function crypto.hash(data, algorithm, format)
|
||||||
|
if type(data) ~= "string" then
|
||||||
|
error("crypto.hash: data must be a string", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
algorithm = algorithm or "sha256"
|
||||||
|
format = format or "hex"
|
||||||
|
|
||||||
|
return __crypto_hash(data, algorithm, format)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convenience functions for common hash algorithms
|
||||||
|
function crypto.md5(data, format)
|
||||||
|
return crypto.hash(data, "md5", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
function crypto.sha1(data, format)
|
||||||
|
return crypto.hash(data, "sha1", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
function crypto.sha256(data, format)
|
||||||
|
return crypto.hash(data, "sha256", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
function crypto.sha512(data, format)
|
||||||
|
return crypto.hash(data, "sha512", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- HMAC FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Generate HMAC using various algorithms
|
||||||
|
-- Algorithms: md5, sha1, sha256, sha512
|
||||||
|
-- Formats: hex (default), binary
|
||||||
|
function crypto.hmac(data, key, algorithm, format)
|
||||||
|
if type(data) ~= "string" then
|
||||||
|
error("crypto.hmac: data must be a string", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(key) ~= "string" then
|
||||||
|
error("crypto.hmac: key must be a string", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
algorithm = algorithm or "sha256"
|
||||||
|
format = format or "hex"
|
||||||
|
|
||||||
|
return __crypto_hmac(data, key, algorithm, format)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convenience functions for common HMAC algorithms
|
||||||
|
function crypto.hmac_md5(data, key, format)
|
||||||
|
return crypto.hmac(data, key, "md5", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
function crypto.hmac_sha1(data, key, format)
|
||||||
|
return crypto.hmac(data, key, "sha1", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
function crypto.hmac_sha256(data, key, format)
|
||||||
|
return crypto.hmac(data, key, "sha256", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
function crypto.hmac_sha512(data, key, format)
|
||||||
|
return crypto.hmac(data, key, "sha512", format)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- RANDOM FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Generate random bytes
|
||||||
|
-- Formats: binary (default), hex
|
||||||
|
function crypto.random_bytes(length, secure, format)
|
||||||
|
if type(length) ~= "number" or length <= 0 then
|
||||||
|
error("crypto.random_bytes: length must be positive", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
secure = secure ~= false -- Default to secure
|
||||||
|
format = format or "binary"
|
||||||
|
|
||||||
|
return __crypto_random_bytes(length, secure, format)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Generate random integer in range [min, max]
|
||||||
|
function crypto.random_int(min, max, secure)
|
||||||
|
if type(min) ~= "number" or type(max) ~= "number" then
|
||||||
|
error("crypto.random_int: min and max must be numbers", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
if max <= min then
|
||||||
|
error("crypto.random_int: max must be greater than min", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
secure = secure ~= false -- Default to secure
|
||||||
|
|
||||||
|
return __crypto_random_int(min, max, secure)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Generate random string of specified length
|
||||||
|
function crypto.random_string(length, charset, secure)
|
||||||
|
if type(length) ~= "number" or length <= 0 then
|
||||||
|
error("crypto.random_string: length must be positive", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
secure = secure ~= false -- Default to secure
|
||||||
|
|
||||||
|
-- Default character set: alphanumeric
|
||||||
|
charset = charset or "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
|
||||||
|
if type(charset) ~= "string" or #charset == 0 then
|
||||||
|
error("crypto.random_string: charset must be non-empty", 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = ""
|
||||||
|
local charset_length = #charset
|
||||||
|
|
||||||
|
for i = 1, length do
|
||||||
|
local index = crypto.random_int(1, charset_length, secure)
|
||||||
|
result = result .. charset:sub(index, index)
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ======================================================================
|
||||||
|
-- UUID FUNCTIONS
|
||||||
|
-- ======================================================================
|
||||||
|
|
||||||
|
-- Generate random UUID (v4)
|
||||||
|
function crypto.uuid()
|
||||||
|
return __crypto_uuid()
|
||||||
|
end
|
||||||
|
|
||||||
|
return crypto
|
@ -28,6 +28,12 @@ var utilLuaCode string
|
|||||||
//go:embed string.lua
|
//go:embed string.lua
|
||||||
var stringLuaCode string
|
var stringLuaCode string
|
||||||
|
|
||||||
|
//go:embed table.lua
|
||||||
|
var tableLuaCode string
|
||||||
|
|
||||||
|
//go:embed crypto.lua
|
||||||
|
var cryptoLuaCode string
|
||||||
|
|
||||||
// ModuleInfo holds information about an embeddable Lua module
|
// ModuleInfo holds information about an embeddable Lua module
|
||||||
type ModuleInfo struct {
|
type ModuleInfo struct {
|
||||||
Name string // Module name
|
Name string // Module name
|
||||||
@ -44,6 +50,8 @@ var (
|
|||||||
{Name: "fs", Code: fsLuaCode},
|
{Name: "fs", Code: fsLuaCode},
|
||||||
{Name: "util", Code: utilLuaCode},
|
{Name: "util", Code: utilLuaCode},
|
||||||
{Name: "string", Code: stringLuaCode},
|
{Name: "string", Code: stringLuaCode},
|
||||||
|
{Name: "table", Code: tableLuaCode},
|
||||||
|
{Name: "crypto", Code: cryptoLuaCode},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -117,6 +117,10 @@ func (s *Sandbox) registerCoreFunctions(state *luajit.State) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := RegisterCryptoFunctions(state); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,8 +190,8 @@ end
|
|||||||
-- INSTALL EXTENSIONS INTO STRING LIBRARY
|
-- INSTALL EXTENSIONS INTO STRING LIBRARY
|
||||||
-- ======================================================================
|
-- ======================================================================
|
||||||
|
|
||||||
for name, func in pairs(string_ext) do
|
for name, func in pairs(string) do
|
||||||
string[name] = func
|
string_ext[name] = func
|
||||||
end
|
end
|
||||||
|
|
||||||
return string_ext
|
return string_ext
|
1092
core/runner/table.lua
Normal file
1092
core/runner/table.lua
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,31 +14,6 @@ function util.generate_token(length)
|
|||||||
return __generate_token(length or 32)
|
return __generate_token(length or 32)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Deep copy of tables
|
|
||||||
function util.deep_copy(obj)
|
|
||||||
if type(obj) ~= 'table' then return obj end
|
|
||||||
local res = {}
|
|
||||||
for k, v in pairs(obj) do res[k] = util.deep_copy(v) end
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Merge tables
|
|
||||||
function util.merge_tables(t1, t2)
|
|
||||||
if type(t1) ~= 'table' or type(t2) ~= 'table' then
|
|
||||||
error("Both arguments must be tables", 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = util.deep_copy(t1)
|
|
||||||
for k, v in pairs(t2) do
|
|
||||||
if type(v) == 'table' and type(result[k]) == 'table' then
|
|
||||||
result[k] = util.merge_tables(result[k], v)
|
|
||||||
else
|
|
||||||
result[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ======================================================================
|
-- ======================================================================
|
||||||
-- HTML ENTITY FUNCTIONS
|
-- HTML ENTITY FUNCTIONS
|
||||||
-- ======================================================================
|
-- ======================================================================
|
||||||
|
Loading…
x
Reference in New Issue
Block a user