From 86a122a50c3c5519523686004f4b86dbfb26f1ca Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Tue, 3 Jun 2025 11:38:30 -0500 Subject: [PATCH] Move Go lua libs to lualibs --- http/server.go | 5 +- moonshark.go | 5 +- runner/{ => lualibs}/crypto.go | 44 ++++++++++++++- runner/{ => lualibs}/env.go | 2 +- runner/{ => lualibs}/fs.go | 2 +- runner/{ => lualibs}/http.go | 91 +++----------------------------- runner/{ => lualibs}/password.go | 2 +- runner/{ => lualibs}/sqlite.go | 2 +- runner/{ => lualibs}/util.go | 57 +++++++++++++++++++- runner/runner.go | 64 +++++++++++++++++++--- runner/sandbox.go | 74 +++----------------------- 11 files changed, 181 insertions(+), 167 deletions(-) rename runner/{ => lualibs}/crypto.go (89%) rename runner/{ => lualibs}/env.go (99%) rename runner/{ => lualibs}/fs.go (99%) rename runner/{ => lualibs}/http.go (74%) rename runner/{ => lualibs}/password.go (99%) rename runner/{ => lualibs}/sqlite.go (99%) rename runner/{ => lualibs}/util.go (65%) diff --git a/http/server.go b/http/server.go index b6e55fc..465c27e 100644 --- a/http/server.go +++ b/http/server.go @@ -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) diff --git a/moonshark.go b/moonshark.go index 37f793e..a1f8380 100644 --- a/moonshark.go +++ b/moonshark.go @@ -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) } diff --git a/runner/crypto.go b/runner/lualibs/crypto.go similarity index 89% rename from runner/crypto.go rename to runner/lualibs/crypto.go index 5e21fc2..5c81e8b 100644 --- a/runner/crypto.go +++ b/runner/lualibs/crypto.go @@ -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 +} diff --git a/runner/env.go b/runner/lualibs/env.go similarity index 99% rename from runner/env.go rename to runner/lualibs/env.go index 4eeb3d7..e2c220e 100644 --- a/runner/env.go +++ b/runner/lualibs/env.go @@ -1,4 +1,4 @@ -package runner +package lualibs import ( "bufio" diff --git a/runner/fs.go b/runner/lualibs/fs.go similarity index 99% rename from runner/fs.go rename to runner/lualibs/fs.go index a5d6ef1..132da66 100644 --- a/runner/fs.go +++ b/runner/lualibs/fs.go @@ -1,4 +1,4 @@ -package runner +package lualibs import ( "errors" diff --git a/runner/http.go b/runner/lualibs/http.go similarity index 74% rename from runner/http.go rename to runner/lualibs/http.go index 612e3e5..a7302a0 100644 --- a/runner/http.go +++ b/runner/lualibs/http.go @@ -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 -} diff --git a/runner/password.go b/runner/lualibs/password.go similarity index 99% rename from runner/password.go rename to runner/lualibs/password.go index a85105e..aa53c84 100644 --- a/runner/password.go +++ b/runner/lualibs/password.go @@ -1,4 +1,4 @@ -package runner +package lualibs import ( luajit "git.sharkk.net/Sky/LuaJIT-to-Go" diff --git a/runner/sqlite.go b/runner/lualibs/sqlite.go similarity index 99% rename from runner/sqlite.go rename to runner/lualibs/sqlite.go index cb08864..d8d8a41 100644 --- a/runner/sqlite.go +++ b/runner/lualibs/sqlite.go @@ -1,4 +1,4 @@ -package runner +package lualibs import ( "context" diff --git a/runner/util.go b/runner/lualibs/util.go similarity index 65% rename from runner/util.go rename to runner/lualibs/util.go index 7bd2e49..243f247 100644 --- a/runner/util.go +++ b/runner/lualibs/util.go @@ -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 +} diff --git a/runner/runner.go b/runner/runner.go index ea3b478..7a1c268 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -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)) + } +} diff --git a/runner/sandbox.go b/runner/sandbox.go index 5d0b925..ce6a6b2 100644 --- a/runner/sandbox.go +++ b/runner/sandbox.go @@ -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 -}