From 61853bdea91dc2edc77507cfbddcd26e06c24637 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Mon, 23 Jun 2025 16:20:01 -0700 Subject: [PATCH 1/8] Add a hex wrapper. --- hex/README.md | 54 ++++++++++++++++++++++++++++ hex/api.go | 84 +++++++++++++++++++++++++++++++++++++++++++ hex/api_test.go | 14 ++++++++ hex/example_test.go | 69 +++++++++++++++++++++++++++++++++++ hex/loader.go | 30 ++++++++++++++++ hex/test/test_api.lua | 43 ++++++++++++++++++++++ plugin/preload.go | 4 ++- 7 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 hex/README.md create mode 100644 hex/api.go create mode 100644 hex/api_test.go create mode 100644 hex/example_test.go create mode 100644 hex/loader.go create mode 100644 hex/test/test_api.lua diff --git a/hex/README.md b/hex/README.md new file mode 100644 index 0000000..d4ecb99 --- /dev/null +++ b/hex/README.md @@ -0,0 +1,54 @@ +# hex [![GoDoc](https://godoc.org/github.com/vadv/gopher-lua-libs/hex?status.svg)](https://godoc.org/github.com/vadv/gopher-lua-libs/hex) + +Lua module for [encoding/hex](https://pkg.go.dev/encoding/hex) + +## Usage + +### Encoding + +```lua +local hex = require("hex") + +s = hex.RawStdEncoding:encode_to_string("foo\01bar") +print(s) +Zm9vAWJhcg + +s = hex.StdEncoding:encode_to_string("foo\01bar") +print(s) +Zm9vAWJhcg== + +s = hex.RawURLEncoding:encode_to_string("this is a and should be encoded") +print(s) +dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA + +s = hex.URLEncoding:encode_to_string("this is a and should be encoded") +print(s) +dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA== + +``` + +### Decoding + +```lua +local hex = require 'hex' + +s, err = hex.decode_string("Zm9vAWJhcg") +assert(not err, err) +print(s) +foobar + +s, err = hex.StdEncoding:decode_string("Zm9vAWJhcg==") +assert(not err, err) +print(s) +foobar + +s, err = hex.RawURLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA") +assert(not err, err) +print(s) +this is a and should be encoded + +s, err = hex.URLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==") +assert(not err, err) +print(s) +this is a and should be encoded +``` diff --git a/hex/api.go b/hex/api.go new file mode 100644 index 0000000..d92fa5c --- /dev/null +++ b/hex/api.go @@ -0,0 +1,84 @@ +// Package hex implements base64 encode/decode functionality for lua. +package hex + +import ( + "encoding/hex" + "io" + + lio "github.com/vadv/gopher-lua-libs/io" + lua "github.com/yuin/gopher-lua" +) + +const ( + hexEncoderType = "hex.Encoder" + hexDecoderType = "hex.Decoder" +) + +// LVHexEncoder creates a new Lua user data for the hex encoder +func LVHexEncoder(L *lua.LState, writer io.Writer) lua.LValue { + ud := L.NewUserData() + ud.Value = writer + L.SetMetatable(ud, L.GetTypeMetatable(hexEncoderType)) + return ud +} + +// LVHexDecoder creates a new Lua user data for the hex decoder +func LVHexDecoder(L *lua.LState, reader io.Reader) lua.LValue { + ud := L.NewUserData() + ud.Value = reader + L.SetMetatable(ud, L.GetTypeMetatable(hexDecoderType)) + return ud +} + +// DecodeString decodes the encoded string with the encoding +func DecodeString(L *lua.LState) int { + encoded := L.CheckString(1) + L.Pop(L.GetTop()) + decoded, err := hex.DecodeString(encoded) + if err != nil { + L.Push(lua.LNil) + L.Push(lua.LString(err.Error())) + return 2 + } + L.Push(lua.LString(decoded)) + return 1 +} + +// EncodeToString decodes the string with the encoding +func EncodeToString(L *lua.LState) int { + decoded := L.CheckString(1) + L.Pop(L.GetTop()) + encoded := hex.EncodeToString([]byte(decoded)) + L.Push(lua.LString(encoded)) + return 1 +} + +// registerHexEncoder Registers the encoder type and its methods +func registerHexEncoder(L *lua.LState) { + mt := L.NewTypeMetatable(hexEncoderType) + L.SetGlobal(hexEncoderType, mt) + L.SetField(mt, "__index", lio.WriterFuncTable(L)) +} + +// registerHexDecoder Registers the decoder type and its methods +func registerHexDecoder(L *lua.LState) { + mt := L.NewTypeMetatable(hexDecoderType) + L.SetGlobal(hexDecoderType, mt) + L.SetField(mt, "__index", lio.ReaderFuncTable(L)) +} + +func NewEncoder(L *lua.LState) int { + writer := lio.CheckIOWriter(L, 1) + L.Pop(L.GetTop()) + encoder := hex.NewEncoder(writer) + L.Push(LVHexEncoder(L, encoder)) + return 1 +} + +func NewDecoder(L *lua.LState) int { + reader := lio.CheckIOReader(L, 1) + L.Pop(L.GetTop()) + decoder := hex.NewDecoder(reader) + L.Push(LVHexDecoder(L, decoder)) + return 1 +} diff --git a/hex/api_test.go b/hex/api_test.go new file mode 100644 index 0000000..0535547 --- /dev/null +++ b/hex/api_test.go @@ -0,0 +1,14 @@ +package hex + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vadv/gopher-lua-libs/strings" + "github.com/vadv/gopher-lua-libs/tests" +) + +func TestApi(t *testing.T) { + preload := tests.SeveralPreloadFuncs(Preload, strings.Preload) + assert.NotZero(t, tests.RunLuaTestFile(t, preload, "./test/test_api.lua")) +} diff --git a/hex/example_test.go b/hex/example_test.go new file mode 100644 index 0000000..43964f8 --- /dev/null +++ b/hex/example_test.go @@ -0,0 +1,69 @@ +package hex + +import ( + "log" + + lua "github.com/yuin/gopher-lua" +) + +func ExampleEncodeToString() { + state := lua.NewState() + defer state.Close() + Preload(state) + source := ` + local base64 = require("base64") + s = base64.RawStdEncoding:encode_to_string("foo\01bar") + print(s) + + s = base64.StdEncoding:encode_to_string("foo\01bar") + print(s) + + s = base64.RawURLEncoding:encode_to_string("this is a and should be encoded") + print(s) + + s = base64.URLEncoding:encode_to_string("this is a and should be encoded") + print(s) + +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // Zm9vAWJhcg + // Zm9vAWJhcg== + // dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA + // dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA== +} + +func ExampleDecodeString() { + state := lua.NewState() + defer state.Close() + Preload(state) + source := ` + local base64 = require("base64") + s, err = base64.RawStdEncoding:decode_string("Zm9vAWJhcg") + assert(not err, err) + print(s) + + s, err = base64.StdEncoding:decode_string("Zm9vAWJhcg==") + assert(not err, err) + print(s) + + s, err = base64.RawURLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA") + assert(not err, err) + print(s) + + s, err = base64.URLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==") + assert(not err, err) + print(s) + +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // foobar + // foobar + // this is a and should be encoded + // this is a and should be encoded +} diff --git a/hex/loader.go b/hex/loader.go new file mode 100644 index 0000000..26ed58c --- /dev/null +++ b/hex/loader.go @@ -0,0 +1,30 @@ +package hex + +import ( + lua "github.com/yuin/gopher-lua" +) + +// Preload adds yaml to the given Lua state's package.preload table. After it +// has been preloaded, it can be loaded using require: +// +// local yaml = require("yaml") +func Preload(L *lua.LState) { + L.PreloadModule("hex", Loader) +} + +// Loader is the module loader function. +func Loader(L *lua.LState) int { + registerHexDecoder(L) + registerHexEncoder(L) + + // Register the encodings offered by base64 go module. + t := L.NewTable() + L.SetFuncs(t, map[string]lua.LGFunction{ + "decode_string": DecodeString, + "encode_to_string": EncodeToString, + "new_encoder": NewEncoder, + "new_decoder": NewDecoder, + }) + L.Push(t) + return 1 +} diff --git a/hex/test/test_api.lua b/hex/test/test_api.lua new file mode 100644 index 0000000..4732430 --- /dev/null +++ b/hex/test/test_api.lua @@ -0,0 +1,43 @@ +local hex = require 'hex' +local strings = require 'strings' +local assert = require 'assert' + +function TestHexCodec(t) + local tests = { + { + encoded = "48656c6c6f20776f726c64", -- "Hello world" in hex + decoded = "Hello world", + }, + { + encoded = "", + decoded = "", + }, + } + for _, tt in ipairs(tests) do + t:Run("hex.decode_string(" .. tostring(tt.encoded) .. ")", function(t) + local got = hex.decode_string(tt.encoded) + assert:Equal(t, tt.decoded, got) + end) + + t:Run("hex.encode_to_string(" .. tostring(tt.decoded) .. ")", function(t) + local got = hex.encode_to_string(tt.decoded) + assert:Equal(t, tt.encoded, got) + end) + end +end + +function TestEncoder(t) + local writer = strings.new_builder() + local encoder = hex.new_encoder(writer) + encoder:write("foo", "bar", "baz") + encoder:close() + local s = writer:string() + assert:Equal(t, "666f6f62617262617a", s) +end + +function TestDecoder(t) + local reader = strings.new_reader("666f6f62617262617a") + local decoder = hex.new_decoder(reader) + local s = decoder:read("*a") + assert:Equal(t, "foobarbaz", s) +end diff --git a/plugin/preload.go b/plugin/preload.go index 8b30441..acc5112 100644 --- a/plugin/preload.go +++ b/plugin/preload.go @@ -12,6 +12,7 @@ import ( "github.com/vadv/gopher-lua-libs/db" "github.com/vadv/gopher-lua-libs/filepath" "github.com/vadv/gopher-lua-libs/goos" + "github.com/vadv/gopher-lua-libs/hex" "github.com/vadv/gopher-lua-libs/http" "github.com/vadv/gopher-lua-libs/humanize" "github.com/vadv/gopher-lua-libs/inspect" @@ -44,6 +45,7 @@ func PreloadAll(L *lua.LState) { argparse.Preload(L) base64.Preload(L) + bit.Preload(L) cert_util.Preload(L) chef.Preload(L) cloudwatch.Preload(L) @@ -52,6 +54,7 @@ func PreloadAll(L *lua.LState) { db.Preload(L) filepath.Preload(L) goos.Preload(L) + hex.Preload(L) http.Preload(L) humanize.Preload(L) inspect.Preload(L) @@ -75,5 +78,4 @@ func PreloadAll(L *lua.LState) { xmlpath.Preload(L) yaml.Preload(L) zabbix.Preload(L) - bit.Preload(L) } From 24bd69b55cfdb4be4b6b6902357edb452d7e2351 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Mon, 23 Jun 2025 16:31:37 -0700 Subject: [PATCH 2/8] Add example tests. --- hex/example_test.go | 74 ++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/hex/example_test.go b/hex/example_test.go index 43964f8..247b567 100644 --- a/hex/example_test.go +++ b/hex/example_test.go @@ -3,6 +3,7 @@ package hex import ( "log" + "github.com/vadv/gopher-lua-libs/strings" lua "github.com/yuin/gopher-lua" ) @@ -11,28 +12,15 @@ func ExampleEncodeToString() { defer state.Close() Preload(state) source := ` - local base64 = require("base64") - s = base64.RawStdEncoding:encode_to_string("foo\01bar") + local hex = require 'hex' + s = hex.encode_to_string("foo\01bar") print(s) - - s = base64.StdEncoding:encode_to_string("foo\01bar") - print(s) - - s = base64.RawURLEncoding:encode_to_string("this is a and should be encoded") - print(s) - - s = base64.URLEncoding:encode_to_string("this is a and should be encoded") - print(s) - ` if err := state.DoString(source); err != nil { log.Fatal(err.Error()) } // Output: - // Zm9vAWJhcg - // Zm9vAWJhcg== - // dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA - // dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA== + // 666f6f01626172 } func ExampleDecodeString() { @@ -40,30 +28,54 @@ func ExampleDecodeString() { defer state.Close() Preload(state) source := ` - local base64 = require("base64") - s, err = base64.RawStdEncoding:decode_string("Zm9vAWJhcg") - assert(not err, err) - print(s) - - s, err = base64.StdEncoding:decode_string("Zm9vAWJhcg==") + local hex = require 'hex' + s, err = hex.decode_string("666f6f01626172") assert(not err, err) print(s) +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // foobar +} - s, err = base64.RawURLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA") - assert(not err, err) - print(s) +func ExampleNewEncoder() { + state := lua.NewState() + defer state.Close() + Preload(state) + strings.Preload(state) + source := ` + local hex = require 'hex' + local strings = require 'strings' + local writer = strings.new_builder() + encoder = hex.new_encoder(writer) + encoder:write("foo\01bar") + print(writer:string()) +` + if err := state.DoString(source); err != nil { + log.Fatal(err.Error()) + } + // Output: + // 666f6f01626172 +} - s, err = base64.URLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==") - assert(not err, err) +func ExampleNewDecoder() { + state := lua.NewState() + defer state.Close() + Preload(state) + strings.Preload(state) + source := ` + local hex = require 'hex' + local strings = require 'strings' + local reader = strings.new_reader('666f6f01626172') + decoder = hex.new_decoder(reader) + local s = decoder:read("*a") print(s) - ` if err := state.DoString(source); err != nil { log.Fatal(err.Error()) } // Output: // foobar - // foobar - // this is a and should be encoded - // this is a and should be encoded } From c509669cd170da3399f83e5b6ea6a3104bfac98b Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Mon, 23 Jun 2025 16:33:35 -0700 Subject: [PATCH 3/8] Update README. --- hex/README.md | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/hex/README.md b/hex/README.md index d4ecb99..cdfa2d5 100644 --- a/hex/README.md +++ b/hex/README.md @@ -32,23 +32,12 @@ dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA== ```lua local hex = require 'hex' -s, err = hex.decode_string("Zm9vAWJhcg") +decoded, err = hex.decode_string("666f6f62617262617a") assert(not err, err) -print(s) -foobar - -s, err = hex.StdEncoding:decode_string("Zm9vAWJhcg==") -assert(not err, err) -print(s) +print(decoded) foobar -s, err = hex.RawURLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA") -assert(not err, err) -print(s) -this is a and should be encoded - -s, err = hex.URLEncoding:decode_string("dGhpcyBpcyBhIDx0YWc-IGFuZCBzaG91bGQgYmUgZW5jb2RlZA==") -assert(not err, err) -print(s) -this is a and should be encoded +encoded = hex.encode_to_string(decoded) +print(encoded) +666f6f62617262617a ``` From 0fa42beb7501ea28eed67cc925c98a0ffa811acf Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Mon, 23 Jun 2025 16:35:58 -0700 Subject: [PATCH 4/8] Add more go versions. --- .github/workflows/ci.yaml | 2 +- .github/workflows/goreleaser.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index dabf209..3eeabf3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.16', '1.17', '1.18', '1.19', '1.20','1.21' ] + go: [ '1.16', '1.17', '1.18', '1.19', '1.20','1.21', '1.22', '1.23', '1.24' ] services: { } steps: diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml index b1bc89f..7457589 100644 --- a/.github/workflows/goreleaser.yaml +++ b/.github/workflows/goreleaser.yaml @@ -15,7 +15,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.14 + go-version: 1.16 - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 From e1e1904e6249699dbb950efc54e8080fe94c8988 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Mon, 23 Jun 2025 16:39:24 -0700 Subject: [PATCH 5/8] Don't bump ci here. --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3eeabf3..dabf209 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go: [ '1.16', '1.17', '1.18', '1.19', '1.20','1.21', '1.22', '1.23', '1.24' ] + go: [ '1.16', '1.17', '1.18', '1.19', '1.20','1.21' ] services: { } steps: From f63197c8d69f6e26751443e3088e7c6f1def4978 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Tue, 24 Jun 2025 09:13:45 -0700 Subject: [PATCH 6/8] NoErrorf should call Failf. --- tests/assertions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/assertions.lua b/tests/assertions.lua index 8b168be..792f451 100644 --- a/tests/assertions.lua +++ b/tests/assertions.lua @@ -152,7 +152,7 @@ function assertions:NoErrorf(t, err, fmt, ...) if not err then return true end - return self:Fail(t, string.format([[ + return self:Failf(t, string.format([[ Error: Received unexpected error: %s From 2f5351e120a9fb524cf2ac3125cf2016bc7a56af Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 25 Jun 2025 09:13:26 -0700 Subject: [PATCH 7/8] Fix review comments. --- hex/api.go | 2 +- hex/loader.go | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hex/api.go b/hex/api.go index d92fa5c..52b54c7 100644 --- a/hex/api.go +++ b/hex/api.go @@ -1,4 +1,4 @@ -// Package hex implements base64 encode/decode functionality for lua. +// Package hex implements hex encode/decode functionality for lua. package hex import ( diff --git a/hex/loader.go b/hex/loader.go index 26ed58c..1c2cad7 100644 --- a/hex/loader.go +++ b/hex/loader.go @@ -1,8 +1,6 @@ package hex -import ( - lua "github.com/yuin/gopher-lua" -) +import lua "github.com/yuin/gopher-lua" // Preload adds yaml to the given Lua state's package.preload table. After it // has been preloaded, it can be loaded using require: @@ -17,7 +15,7 @@ func Loader(L *lua.LState) int { registerHexDecoder(L) registerHexEncoder(L) - // Register the encodings offered by base64 go module. + // Register the encodings offered by hex go module. t := L.NewTable() L.SetFuncs(t, map[string]lua.LGFunction{ "decode_string": DecodeString, From b7e0f598d4f48de74aefcdb3536d55c5874ef6d3 Mon Sep 17 00:00:00 2001 From: Sheridan C Rawlins Date: Wed, 25 Jun 2025 09:15:06 -0700 Subject: [PATCH 8/8] Fix comments. --- base64/loader.go | 5 +++-- hex/loader.go | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/base64/loader.go b/base64/loader.go index 8e4e1e9..ab1ad47 100644 --- a/base64/loader.go +++ b/base64/loader.go @@ -2,13 +2,14 @@ package base64 import ( "encoding/base64" + lua "github.com/yuin/gopher-lua" ) -// Preload adds yaml to the given Lua state's package.preload table. After it +// Preload adds base64 to the given Lua state's package.preload table. After it // has been preloaded, it can be loaded using require: // -// local yaml = require("yaml") +// local base64 = require("base64") func Preload(L *lua.LState) { L.PreloadModule("base64", Loader) } diff --git a/hex/loader.go b/hex/loader.go index 1c2cad7..ec63f44 100644 --- a/hex/loader.go +++ b/hex/loader.go @@ -2,10 +2,10 @@ package hex import lua "github.com/yuin/gopher-lua" -// Preload adds yaml to the given Lua state's package.preload table. After it +// Preload adds hex to the given Lua state's package.preload table. After it // has been preloaded, it can be loaded using require: // -// local yaml = require("yaml") +// local hex = require("hex") func Preload(L *lua.LState) { L.PreloadModule("hex", Loader) }