diff --git a/go.mod b/go.mod index 9de8c8c..9ff83e5 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,24 @@ go 1.24.2 require ( git.mstar.dev/mstar/goutils v1.14.2 github.com/BurntSushi/toml v1.5.0 + github.com/PeerDB-io/gluabit32 v1.0.2 + github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9 + github.com/cosmotek/loguago v1.0.0 github.com/go-acme/lego/v4 v4.23.1 github.com/go-webauthn/webauthn v0.12.3 github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.7.4 + github.com/kohkimakimoto/gluatemplate v0.0.0-20160815033744-d9e2c9d6b00f + github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf github.com/mitchellh/mapstructure v1.5.0 github.com/nrednav/cuid2 v1.0.1 github.com/pquerna/otp v1.4.0 + github.com/quic-go/quic-go v0.52.0 github.com/rs/xid v1.6.0 github.com/rs/zerolog v1.34.0 github.com/yaronf/httpsign v0.3.2 + github.com/yuin/gluare v0.0.0-20170607022532-d7c94f1a80ed + github.com/yuin/gopher-lua v1.1.1 golang.org/x/crypto v0.37.0 golang.org/x/sys v0.32.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -45,6 +53,7 @@ require ( github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/lestrrat-go/blackmagic v1.0.3 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect @@ -54,11 +63,16 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/miekg/dns v1.1.64 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-multihash v0.2.3 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.52.0 // indirect github.com/segmentio/asm v1.2.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 // indirect go.uber.org/mock v0.5.0 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/net v0.39.0 // indirect @@ -68,4 +82,5 @@ require ( gorm.io/datatypes v1.2.5 // indirect gorm.io/driver/mysql v1.5.7 // indirect gorm.io/hints v1.1.2 // indirect + lukechampine.com/blake3 v1.1.6 // indirect ) diff --git a/go.sum b/go.sum index 4cedc56..990926b 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ git.mstar.dev/mstar/goutils v1.14.2 h1:2W9AtsAAGR9OeztPnyVCkxiuZDe7h1DlXzil35wU+ git.mstar.dev/mstar/goutils v1.14.2/go.mod h1:juxY0eZEMnA95fedRp2LVXvUBgEjz66nE8SEdGKcxMA= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/PeerDB-io/gluabit32 v1.0.2 h1:AGI1Z7dwDVotakpuOOuyTX4/QGi5HUYsipL/VfodmO4= +github.com/PeerDB-io/gluabit32 v1.0.2/go.mod h1:tsHStN1XG5uGVWEA8d/RameB7el3PE3sVkvk8e3+FJg= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= @@ -13,7 +15,11 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9 h1:rdWOzitWlNYeUsXmz+IQfa9NkGEq3gA/qQ3mOEqBU6o= +github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9/go.mod h1:X97UjDTXp+7bayQSFZk2hPvCTmTZIicUjZQRtkwgAKY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cosmotek/loguago v1.0.0 h1:cM6xoMPoIL1hRPicMenFNVohylundRIPz+OfpadJyY0= +github.com/cosmotek/loguago v1.0.0/go.mod h1:M/3wRiTLODLY6ufA9sVxOgSvnkYv53sYuDTQEqX0lZ4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -28,6 +34,8 @@ github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= @@ -46,6 +54,8 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc= @@ -67,6 +77,13 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kohkimakimoto/gluatemplate v0.0.0-20160815033744-d9e2c9d6b00f h1:CXJzfe/zhkWjXLAZItKA4BPHo4d8Fh7Hc4gqcLVyrWQ= +github.com/kohkimakimoto/gluatemplate v0.0.0-20160815033744-d9e2c9d6b00f/go.mod h1:mepZlGlueX0FYzgC3KQMEuBBQuaAvdp8RUY+ZEe2fbI= +github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf h1:bg6J/5S/AeTz7K9i/luJRj31BJ8f+LgYwKQBSOZxSEM= +github.com/layeh/gopher-json v0.0.0-20201124131017-552bb3c4c3bf/go.mod h1:E/q28EyUVBgBQnONAVPIdwvEsv4Ve0vaCA9JWim4+3I= github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs= github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= @@ -93,12 +110,22 @@ github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/miekg/dns v1.1.64 h1:wuZgD9wwCE6XMT05UU/mlSko71eRSXEAm2EbjQXLKnQ= github.com/miekg/dns v1.1.64/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/nrednav/cuid2 v1.0.1 h1:aYLDCmGxEij7xCdiV6GVSPSlqFOS6sqHKKvBeKjddVY= github.com/nrednav/cuid2 v1.0.1/go.mod h1:nH9lUYqbtoVsnpy20etw5q1guTjE99Xy4EpmnK5nKm0= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -117,6 +144,8 @@ github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -128,7 +157,13 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yaronf/httpsign v0.3.2 h1:rBYYx9eHm60noI4oC24JAD2tJuM8AUDh9ErJO/FfzBs= github.com/yaronf/httpsign v0.3.2/go.mod h1:cYB/6toJrJnf4JTLVoo6IHzFH9/Zu1dcKmah4xfX2WA= +github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38DwcXWEPldrTjIZ8FPNKx8mYMGnqjs= +github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8= +github.com/yuin/gluare v0.0.0-20170607022532-d7c94f1a80ed h1:I1vcLHWU9m30rA90rMrKPu0eD3NDA4FBlkB8WMaDyUw= +github.com/yuin/gluare v0.0.0-20170607022532-d7c94f1a80ed/go.mod h1:9w6KSdZh23UWqOywWsRLUcJUrUNjRh4Ql3z9uVgnSP4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -179,6 +214,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= @@ -206,3 +243,5 @@ gorm.io/hints v1.1.2 h1:b5j0kwk5p4+3BtDtYqqfY+ATSxjj+6ptPgVveuynn9o= gorm.io/hints v1.1.2/go.mod h1:/ARdpUHAtyEMCh5NNi3tI7FsGh+Cj/MIUlvNxCNCFWg= gorm.io/plugin/dbresolver v1.5.3 h1:wFwINGZZmttuu9h7XpvbDHd8Lf9bb8GNzp/NpAMV2wU= gorm.io/plugin/dbresolver v1.5.3/go.mod h1:TSrVhaUg2DZAWP3PrHlDlITEJmNOkL0tFTjvTEsQ4XE= +lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= +lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= diff --git a/plugins/api.go b/plugins/api.go new file mode 100644 index 0000000..73650ba --- /dev/null +++ b/plugins/api.go @@ -0,0 +1,12 @@ +package plugins + +import lua "github.com/yuin/gopher-lua" + +// TODO: Decide on the API made available to plugins +// Everything has to be a function, assume no internal state +// since the used lua state may vary between calls +type linstromApi struct{} + +func insertLinstromApiIntoState(l *lua.LState) error { + panic("not implemented") +} diff --git a/plugins/init.go b/plugins/init.go new file mode 100644 index 0000000..9556fba --- /dev/null +++ b/plugins/init.go @@ -0,0 +1,62 @@ +package plugins + +import ( + "fmt" + + "git.mstar.dev/mstar/goutils/other" + "github.com/PeerDB-io/gluabit32" + "github.com/cjoudrey/gluahttp" + "github.com/cosmotek/loguago" + "github.com/kohkimakimoto/gluatemplate" + gluajson "github.com/layeh/gopher-json" + "github.com/rs/zerolog/log" + "github.com/yuin/gluare" + lua "github.com/yuin/gopher-lua" + + webshared "git.mstar.dev/mstar/linstrom/web/shared" +) + +// "github.com/CuberL/glua-async" // For async support, see module readme for how to +// Use "github.com/layeh/gopher-luar" for implementing interface + +// Create a new "blank" lua state for future use. +// Each created state has to be properly closed. +// A "blank" state has the base libraries preloaded and is technically ready to use. +// Plugin specific functions and data is not yet included +func NewBlankState() (*lua.LState, error) { + l := lua.NewState() + for _, pair := range []struct { + n string + f lua.LGFunction + }{ + {lua.LoadLibName, lua.OpenPackage}, // Must always be first + {lua.BaseLibName, lua.OpenBase}, + {lua.TabLibName, lua.OpenTable}, + // {lua.IoLibName, lua.OpenIo}, + {lua.OsLibName, lua.OpenOs}, + {lua.StringLibName, lua.OpenString}, + {lua.MathLibName, lua.OpenMath}, + // {lua.DebugLibName, lua.OpenDebug}, + {lua.ChannelLibName, lua.OpenChannel}, + {lua.CoroutineLibName, lua.OpenCoroutine}, + {"bit32", gluabit32.Loader}, + {"json", gluajson.Loader}, + {"log", loguago.NewLogger(log.Logger).Loader}, // TODO: Decide if used logger should be passed in via context + {"http", gluahttp.NewHttpModule(&webshared.RequestClient).Loader}, // TODO: Modify this to support signing + {"re", gluare.Loader}, + {"texttemplate", gluatemplate.Loader}, // TODO: Copy this lib, but modify to use html/template instead + } { + if err := l.CallByParam(lua.P{ + Fn: l.NewFunction(pair.f), + NRet: 0, + Protect: true, + }, lua.LString(pair.n)); err != nil { + return nil, other.Error( + "plugins", + fmt.Sprintf("Failed to preload lua library %q into state", pair.n), + err, + ) + } + } + return l, nil +} diff --git a/plugins/pluginHolder.go b/plugins/pluginHolder.go new file mode 100644 index 0000000..89edbf7 --- /dev/null +++ b/plugins/pluginHolder.go @@ -0,0 +1,67 @@ +package plugins + +import lua "github.com/yuin/gopher-lua" + +/* +Plugin hooks: +- Pre local message +- Post local message +- Pre external message (received but not processed by default stuff) +- Post external message (received, internal processing done) +- Post new local account +- Pre new remote account discovered +- Post new remote account discovered +*/ + +type pluginHolder struct { + meta *PluginMetadata + table *lua.LTable + + // ---- Section hooks + + postLocalMessage *lua.LFunction + postExternalMessage *lua.LFunction + postNewLocalAccount *lua.LFunction + postRemoteAccountDiscovered *lua.LFunction + // preLocalMessage *lua.LFunction + // preExternalMessage *lua.LFunction // Might not want this + // preRemoteAccountDiscovered *lua.LFunction +} + +type PluginMetadata struct { + Name string `json:"name"` + Version string `json:"version"` + // Don't load major and minor versions from meta file, calc from full version instead + Major int `json:"-"` + Minor int `json:"-"` + Source string `json:"source"` + License string `json:"license"` + Hashes map[string]string `json:"hashes"` + EntryFile string `json:"entry"` + HookNames map[string]string `json:"hook_names"` +} + +const ( + HookPostLocalMessage = "post-local-message" + HookPostExternalMessage = "post-external-message" + HookPostNewLocalAccount = "post-new-local-account" + HookPostRemoteAccountDiscovered = "post-remote-account-discovered" +) + +// TODO: Figure out signature +func (p *pluginHolder) PostLocalMessage(l *lua.LState) error { + // Only act on the hook if a hook exists + if p.postLocalMessage != nil { + err := l.CallByParam(lua.P{ + Fn: p.postLocalMessage, + NRet: 1, // TODO: Adjust based on signature + Protect: true, + }) // TODO: Translate signature arguments into LValues and include here + if err != nil { + return err + } + // TODO: Translate args on stack back into whats expected from the signature + panic("not implemented") + } + return nil +} diff --git a/plugins/pluginLoader.go b/plugins/pluginLoader.go new file mode 100644 index 0000000..4a77674 --- /dev/null +++ b/plugins/pluginLoader.go @@ -0,0 +1,200 @@ +package plugins + +import ( + "bufio" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path" + "sync" + + "git.mstar.dev/mstar/goutils/other" + lua "github.com/yuin/gopher-lua" + "github.com/yuin/gopher-lua/parse" +) + +/* +Plugin structure expectation: +- meta.json for plugin metadata: + - version + - name + - source location (where the plugin can be sourced from) + - license + - file hashes (every file in the plugin dir, sha256, hex encoded) + - entry file name + - Hook to table key name list (which function in the returned table is for what hook) +- Entry script returns a table +*/ + +const PluginMetadataFileName = "meta.json" + +var ( + ErrNoHashForFile = errors.New("no hash for file in the metadata") + ErrInvalidHash = errors.New("hashes don't match") + ErrMissingFile = errors.New("a required file is missing") + ErrInvalidEntryReturnValue = errors.New( + "entry script returned an invalid value. Must be a table", + ) +) + +var compCache = map[string]*lua.FunctionProto{} +var compCacheLock = sync.RWMutex{} + +// Load the plugin located in a provided folder into the given state. +// Validates the data, compiles it for future reuse and links up the hooks +func LoadPlugin(location string, lState *lua.LState) (*pluginHolder, error) { + metaFileData, err := os.ReadFile(location + "/" + PluginMetadataFileName) + if err != nil { + return nil, err + } + metadata := PluginMetadata{} + err = json.Unmarshal(metaFileData, &metadata) + if err != nil { + return nil, err + } + compCacheLock.RLock() + precompiled, ok := compCache[metadata.Name+metadata.Version] + compCacheLock.RUnlock() + if !ok { + // This version of a plugin not in the cache yet, validate the plugin dir, compile it and add it to the cache + precompiled, err = compilePluginDir(&metadata, location) + if err != nil { + return nil, err + } + compCacheLock.Lock() + compCache[metadata.Name+metadata.Version] = precompiled + compCacheLock.Unlock() + } + lFunc := lState.NewFunctionFromProto(precompiled) + lState.Push(lFunc) + if err = lState.PCall(0, lua.MultRet, nil); err != nil { + return nil, err + } + return generatePluginHolder(lState, &metadata) +} + +// Compiles a given lua file for future use +func compileFile(filePath string) (*lua.FunctionProto, error) { + file, err := os.Open(filePath) + defer func() { _ = file.Close() }() + if err != nil { + return nil, err + } + reader := bufio.NewReader(file) + chunk, err := parse.Parse(reader, filePath) + if err != nil { + return nil, err + } + proto, err := lua.Compile(chunk, filePath) + if err != nil { + return nil, err + } + return proto, nil +} + +// Validates the given plugin dir and compiles it for future use +func compilePluginDir(metadata *PluginMetadata, location string) (*lua.FunctionProto, error) { + if err := checkDir(location, "", metadata.Hashes); err != nil { + return nil, err + } + entryFileName := path.Join(location, metadata.EntryFile) + if _, err := os.Stat(entryFileName); err != nil { + return nil, other.Error("plugins", fmt.Sprintf("missing entry file %s", entryFileName), err) + } + compiled, err := compileFile(entryFileName) + if err != nil { + return nil, err + } + return compiled, nil +} + +// Ensures that all files in the given root directory (plus suffix) match the expected hashes provided in the metadata +func checkDir(rootPath string, suffix string, expectedHashes map[string]string) error { + rootEntries, err := os.ReadDir(path.Join(rootPath, suffix)) + if err != nil { + return err + } + for _, entry := range rootEntries { + if suffix == "" && entry.Name() == PluginMetadataFileName { + continue + } + if entry.IsDir() { + if err = checkDir(rootPath, path.Join(suffix, entry.Name()), expectedHashes); err != nil { + return err + } + } + fileName := path.Join(rootPath, suffix, entry.Name()) + expectedHash, ok := expectedHashes[fileName] + if !ok { + return other.Error( + "plugins", + fmt.Sprintf("No hash found in metadata for file %s", fileName), + ErrNoHashForFile, + ) + } + f, err := os.Open(fileName) + if err != nil { + return err + } + defer func() { _ = f.Close() }() + if err = checkHash(f, expectedHash); err != nil { + return err + } + } + return nil +} + +// Checks if a hash matches the given file +func checkHash(file *os.File, expected string) error { + hasher := sha256.New() + _, err := io.Copy(hasher, file) + if err != nil { + return err + } + sum := hasher.Sum([]byte{}) + if expected != hex.EncodeToString(sum) { + return ErrInvalidHash + } + return nil +} + +// Properly inserts the plugin into the state's global context. +// Also gets links to all functions found that are named as hook in the metadata. +// Assumptions: Called after the entry file has been run, but before any other operations +func generatePluginHolder(l *lua.LState, meta *PluginMetadata) (*pluginHolder, error) { + pluginTable, ok := l.Get(1).(*lua.LTable) + if !ok || pluginTable.MaxN() != 0 { + return nil, ErrInvalidEntryReturnValue + } + l.SetGlobal(meta.Name, pluginTable) + pMap := lTableToMap(pluginTable) + holder := pluginHolder{ + meta: meta, + table: pluginTable, + } + if postLocalMessageHookName, ok := meta.HookNames[HookPostLocalMessage]; ok { + if lV, ok := pMap[lua.LString(postLocalMessageHookName)].(*lua.LFunction); ok { + holder.postLocalMessage = lV + } + } + if postExternalMessageHookName, ok := meta.HookNames[HookPostExternalMessage]; ok { + if lV, ok := pMap[lua.LString(postExternalMessageHookName)].(*lua.LFunction); ok { + holder.postExternalMessage = lV + } + } + if postNewLocalAccountName, ok := meta.HookNames[HookPostNewLocalAccount]; ok { + if lV, ok := pMap[lua.LString(postNewLocalAccountName)].(*lua.LFunction); ok { + holder.postNewLocalAccount = lV + } + } + if postRemoteAccountDiscoveredName, ok := meta.HookNames[HookPostRemoteAccountDiscovered]; ok { + if lV, ok := pMap[lua.LString(postRemoteAccountDiscoveredName)].(*lua.LFunction); ok { + holder.postRemoteAccountDiscovered = lV + } + } + return &holder, nil +} diff --git a/plugins/runner.go b/plugins/runner.go new file mode 100644 index 0000000..73283e4 --- /dev/null +++ b/plugins/runner.go @@ -0,0 +1,23 @@ +package plugins + +import lua "github.com/yuin/gopher-lua" + +type Runner struct { + state *lua.LState + inUse bool +} + +func NewRunner() (*Runner, error) { + lState, err := NewBlankState() + if err != nil { + return nil, err + } + return &Runner{ + lState, + false, + }, nil +} + +func (r *Runner) IsInUse() bool { + return r.inUse +} diff --git a/plugins/util.go b/plugins/util.go new file mode 100644 index 0000000..e0ee100 --- /dev/null +++ b/plugins/util.go @@ -0,0 +1,11 @@ +package plugins + +import lua "github.com/yuin/gopher-lua" + +func lTableToMap(t *lua.LTable) map[lua.LValue]lua.LValue { + m := map[lua.LValue]lua.LValue{} + t.ForEach(func(l1, l2 lua.LValue) { + m[l1] = l2 + }) + return m +}