Move Go lua libs to lualibs

This commit is contained in:
Sky Johnson 2025-06-03 11:38:30 -05:00
parent 61f66d6594
commit 86a122a50c
11 changed files with 181 additions and 167 deletions

View File

@ -9,6 +9,7 @@ import (
"Moonshark/router"
"Moonshark/runner"
"Moonshark/runner/lualibs"
"Moonshark/sessions"
"Moonshark/utils"
"Moonshark/utils/color"
@ -173,8 +174,8 @@ func (s *Server) handleLuaRoute(ctx *fasthttp.RequestCtx, bytecode []byte, scrip
luaCtx := runner.NewHTTPContext(ctx)
defer luaCtx.Release()
if runner.GetGlobalEnvManager() != nil {
luaCtx.Set("env", runner.GetGlobalEnvManager().GetAll())
if lualibs.GetGlobalEnvManager() != nil {
luaCtx.Set("env", lualibs.GetGlobalEnvManager().GetAll())
}
sessionMap := s.ctxPool.Get().(map[string]any)

View File

@ -15,6 +15,7 @@ import (
"Moonshark/http"
"Moonshark/router"
"Moonshark/runner"
"Moonshark/runner/lualibs"
"Moonshark/sessions"
"Moonshark/utils/color"
"Moonshark/utils/config"
@ -144,7 +145,7 @@ func (s *Moonshark) initRunner(poolSize int) error {
}
}
if err := runner.InitEnv(s.Config.Dirs.Data); err != nil {
if err := lualibs.InitEnv(s.Config.Dirs.Data); err != nil {
logger.Warnf("Environment initialization failed: %v", err)
}
@ -287,7 +288,7 @@ func (s *Moonshark) Shutdown() error {
s.LuaRunner.Close()
}
if err := runner.CleanupEnv(); err != nil {
if err := lualibs.CleanupEnv(); err != nil {
logger.Warnf("Environment cleanup failed: %v", err)
}

View File

@ -1,12 +1,14 @@
package runner
package lualibs
import (
"Moonshark/utils/logger"
"crypto/hmac"
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"fmt"
@ -32,6 +34,10 @@ func RegisterCryptoFunctions(state *luajit.State) error {
stateRngs[state] = mrand.NewPCG(uint64(time.Now().UnixNano()), uint64(time.Now().UnixNano()>>32))
stateRngsMu.Unlock()
if err := state.RegisterGoFunction("__generate_token", generateToken); err != nil {
return err
}
// Register hash functions
if err := state.RegisterGoFunction("__crypto_hash", cryptoHash); err != nil {
return err
@ -419,3 +425,39 @@ func OverrideLuaRandom(state *luajit.State) error {
go_math_randomseed = nil
`)
}
// generateToken creates a cryptographically secure random token
func generateToken(state *luajit.State) int {
// Get the length from the Lua arguments (default to 32)
length := 32
if state.GetTop() >= 1 {
if lengthVal, err := state.SafeToNumber(1); err == nil {
length = int(lengthVal)
}
}
// Enforce minimum length for security
if length < 16 {
length = 16
}
// Generate secure random bytes
tokenBytes := make([]byte, length)
if _, err := rand.Read(tokenBytes); err != nil {
logger.Errorf("Failed to generate secure token: %v", err)
state.PushString("")
return 1 // Return empty string on error
}
// Encode as base64
token := base64.RawURLEncoding.EncodeToString(tokenBytes)
// Trim to requested length (base64 might be longer)
if len(token) > length {
token = token[:length]
}
// Push the token to the Lua stack
state.PushString(token)
return 1 // One return value
}

View File

@ -1,4 +1,4 @@
package runner
package lualibs
import (
"bufio"

View File

@ -1,4 +1,4 @@
package runner
package lualibs
import (
"errors"

View File

@ -1,9 +1,7 @@
package runner
package lualibs
import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"net/url"
@ -14,8 +12,6 @@ import (
"github.com/valyala/bytebufferpool"
"github.com/valyala/fasthttp"
"Moonshark/utils/logger"
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
)
@ -44,52 +40,13 @@ var DefaultHTTPClientConfig = HTTPClientConfig{
AllowRemote: true,
}
// ApplyResponse applies a Response to a fasthttp.RequestCtx
func ApplyResponse(resp *Response, ctx *fasthttp.RequestCtx) {
// Set status code
ctx.SetStatusCode(resp.Status)
// Set headers
for name, value := range resp.Headers {
ctx.Response.Header.Set(name, value)
// RegisterHttpFunctions registers HTTP functions with the Lua state
func RegisterHttpFunctions(state *luajit.State) error {
if err := state.RegisterGoFunction("__http_request", httpRequest); err != nil {
return err
}
// Set cookies
for _, cookie := range resp.Cookies {
ctx.Response.Header.SetCookie(cookie)
}
// Process the body based on its type
if resp.Body == nil {
return
}
// Get a buffer from the pool
buf := bytebufferpool.Get()
defer bytebufferpool.Put(buf)
// Set body based on type
switch body := resp.Body.(type) {
case string:
ctx.SetBodyString(body)
case []byte:
ctx.SetBody(body)
case map[string]any, []any, []float64, []string, []int:
// Marshal JSON
if err := json.NewEncoder(buf).Encode(body); err == nil {
// Set content type if not already set
if len(ctx.Response.Header.ContentType()) == 0 {
ctx.Response.Header.SetContentType("application/json")
}
ctx.SetBody(buf.Bytes())
} else {
// Fallback
ctx.SetBodyString(fmt.Sprintf("%v", body))
}
default:
// Default to string representation
ctx.SetBodyString(fmt.Sprintf("%v", body))
}
return nil
}
// httpRequest makes an HTTP request and returns the result to Lua
@ -277,39 +234,3 @@ func httpRequest(state *luajit.State) int {
builder.Build()
return 1
}
// generateToken creates a cryptographically secure random token
func generateToken(state *luajit.State) int {
// Get the length from the Lua arguments (default to 32)
length := 32
if state.GetTop() >= 1 {
if lengthVal, err := state.SafeToNumber(1); err == nil {
length = int(lengthVal)
}
}
// Enforce minimum length for security
if length < 16 {
length = 16
}
// Generate secure random bytes
tokenBytes := make([]byte, length)
if _, err := rand.Read(tokenBytes); err != nil {
logger.Errorf("Failed to generate secure token: %v", err)
state.PushString("")
return 1 // Return empty string on error
}
// Encode as base64
token := base64.RawURLEncoding.EncodeToString(tokenBytes)
// Trim to requested length (base64 might be longer)
if len(token) > length {
token = token[:length]
}
// Push the token to the Lua stack
state.PushString(token)
return 1 // One return value
}

View File

@ -1,4 +1,4 @@
package runner
package lualibs
import (
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"

View File

@ -1,4 +1,4 @@
package runner
package lualibs
import (
"context"

View File

@ -1,7 +1,8 @@
package runner
package lualibs
import (
"encoding/base64"
"encoding/json"
"html"
"strings"
@ -10,6 +11,14 @@ import (
// RegisterUtilFunctions registers utility functions with the Lua state
func RegisterUtilFunctions(state *luajit.State) error {
if err := state.RegisterGoFunction("__json_marshal", jsonMarshal); err != nil {
return err
}
if err := state.RegisterGoFunction("__json_unmarshal", jsonUnmarshal); err != nil {
return err
}
// HTML special chars
if err := state.RegisterGoFunction("__html_special_chars", htmlSpecialChars); err != nil {
return err
@ -134,3 +143,49 @@ func base64Decode(state *luajit.State) int {
state.PushString(string(result))
return 1
}
// jsonMarshal converts a Lua value to a JSON string with validation
func jsonMarshal(state *luajit.State) int {
if err := state.CheckExactArgs(1); err != nil {
return state.PushError("json marshal: %v", err)
}
value, err := state.SafeToTable(1)
if err != nil {
// Try as generic value if not a table
value, err = state.ToValue(1)
if err != nil {
return state.PushError("json marshal error: %v", err)
}
}
bytes, err := json.Marshal(value)
if err != nil {
return state.PushError("json marshal error: %v", err)
}
state.PushString(string(bytes))
return 1
}
// jsonUnmarshal converts a JSON string to a Lua value with validation
func jsonUnmarshal(state *luajit.State) int {
if err := state.CheckExactArgs(1); err != nil {
return state.PushError("json unmarshal: %v", err)
}
jsonStr, err := state.SafeToString(1)
if err != nil {
return state.PushError("json unmarshal: expected string, got %s", state.GetType(1))
}
var value any
if err := json.Unmarshal([]byte(jsonStr), &value); err != nil {
return state.PushError("json unmarshal error: %v", err)
}
if err := state.PushValue(value); err != nil {
return state.PushError("json unmarshal error: %v", err)
}
return 1
}

View File

@ -1,6 +1,7 @@
package runner
import (
"Moonshark/runner/lualibs"
"Moonshark/utils/color"
"Moonshark/utils/logger"
"context"
@ -15,6 +16,9 @@ import (
"time"
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
"github.com/goccy/go-json"
"github.com/valyala/bytebufferpool"
"github.com/valyala/fasthttp"
)
// Common errors
@ -112,10 +116,10 @@ func NewRunner(options ...RunnerOption) (*Runner, error) {
runner.moduleLoader = NewModuleLoader(config)
}
InitSQLite(runner.dataDir)
InitFS(runner.fsDir)
lualibs.InitSQLite(runner.dataDir)
lualibs.InitFS(runner.fsDir)
SetSQLitePoolSize(runner.poolSize)
lualibs.SetSQLitePoolSize(runner.poolSize)
// Initialize states and pool
runner.states = make([]*State, runner.poolSize)
@ -123,7 +127,7 @@ func NewRunner(options ...RunnerOption) (*Runner, error) {
// Create and initialize all states
if err := runner.initializeStates(); err != nil {
CleanupSQLite()
lualibs.CleanupSQLite()
runner.Close()
return nil, err
}
@ -310,8 +314,8 @@ waitForInUse:
}
}
CleanupFS()
CleanupSQLite()
lualibs.CleanupFS()
lualibs.CleanupSQLite()
logger.Debugf("Runner closed")
return nil
@ -564,3 +568,51 @@ func (r *Runner) RunScriptFile(filePath string) (*Response, error) {
return response, nil
}
// ApplyResponse applies a Response to a fasthttp.RequestCtx
func ApplyResponse(resp *Response, ctx *fasthttp.RequestCtx) {
// Set status code
ctx.SetStatusCode(resp.Status)
// Set headers
for name, value := range resp.Headers {
ctx.Response.Header.Set(name, value)
}
// Set cookies
for _, cookie := range resp.Cookies {
ctx.Response.Header.SetCookie(cookie)
}
// Process the body based on its type
if resp.Body == nil {
return
}
// Get a buffer from the pool
buf := bytebufferpool.Get()
defer bytebufferpool.Put(buf)
// Set body based on type
switch body := resp.Body.(type) {
case string:
ctx.SetBodyString(body)
case []byte:
ctx.SetBody(body)
case map[string]any, []any, []float64, []string, []int:
// Marshal JSON
if err := json.NewEncoder(buf).Encode(body); err == nil {
// Set content type if not already set
if len(ctx.Response.Header.ContentType()) == 0 {
ctx.Response.Header.SetContentType("application/json")
}
ctx.SetBody(buf.Bytes())
} else {
// Fallback
ctx.SetBodyString(fmt.Sprintf("%v", body))
}
default:
// Default to string representation
ctx.SetBodyString(fmt.Sprintf("%v", body))
}
}

View File

@ -4,9 +4,9 @@ import (
"fmt"
"sync"
"github.com/goccy/go-json"
"github.com/valyala/fasthttp"
"Moonshark/runner/lualibs"
"Moonshark/utils/logger"
"maps"
@ -85,43 +85,31 @@ func (s *Sandbox) Setup(state *luajit.State, verbose bool) error {
// registerCoreFunctions registers all built-in functions in the Lua state
func (s *Sandbox) registerCoreFunctions(state *luajit.State) error {
if err := state.RegisterGoFunction("__http_request", httpRequest); err != nil {
if err := lualibs.RegisterHttpFunctions(state); err != nil {
return err
}
if err := state.RegisterGoFunction("__generate_token", generateToken); err != nil {
if err := lualibs.RegisterSQLiteFunctions(state); err != nil {
return err
}
if err := state.RegisterGoFunction("__json_marshal", jsonMarshal); err != nil {
if err := lualibs.RegisterFSFunctions(state); err != nil {
return err
}
if err := state.RegisterGoFunction("__json_unmarshal", jsonUnmarshal); err != nil {
if err := lualibs.RegisterPasswordFunctions(state); err != nil {
return err
}
if err := RegisterSQLiteFunctions(state); err != nil {
if err := lualibs.RegisterUtilFunctions(state); err != nil {
return err
}
if err := RegisterFSFunctions(state); err != nil {
if err := lualibs.RegisterCryptoFunctions(state); err != nil {
return err
}
if err := RegisterPasswordFunctions(state); err != nil {
return err
}
if err := RegisterUtilFunctions(state); err != nil {
return err
}
if err := RegisterCryptoFunctions(state); err != nil {
return err
}
if err := RegisterEnvFunctions(state); err != nil {
if err := lualibs.RegisterEnvFunctions(state); err != nil {
return err
}
@ -250,49 +238,3 @@ func extractCookie(state *luajit.State, response *Response) {
response.Cookies = append(response.Cookies, cookie)
}
// jsonMarshal converts a Lua value to a JSON string with validation
func jsonMarshal(state *luajit.State) int {
if err := state.CheckExactArgs(1); err != nil {
return state.PushError("json marshal: %v", err)
}
value, err := state.SafeToTable(1)
if err != nil {
// Try as generic value if not a table
value, err = state.ToValue(1)
if err != nil {
return state.PushError("json marshal error: %v", err)
}
}
bytes, err := json.Marshal(value)
if err != nil {
return state.PushError("json marshal error: %v", err)
}
state.PushString(string(bytes))
return 1
}
// jsonUnmarshal converts a JSON string to a Lua value with validation
func jsonUnmarshal(state *luajit.State) int {
if err := state.CheckExactArgs(1); err != nil {
return state.PushError("json unmarshal: %v", err)
}
jsonStr, err := state.SafeToString(1)
if err != nil {
return state.PushError("json unmarshal: expected string, got %s", state.GetType(1))
}
var value any
if err := json.Unmarshal([]byte(jsonStr), &value); err != nil {
return state.PushError("json unmarshal error: %v", err)
}
if err := state.PushValue(value); err != nil {
return state.PushError("json unmarshal error: %v", err)
}
return 1
}