diff --git a/go.mod b/go.mod index ea71417..da5380f 100644 --- a/go.mod +++ b/go.mod @@ -1,39 +1,39 @@ module github.com/DIMO-Network/shared -go 1.22.3 +go 1.24 -toolchain go1.22.6 +toolchain go1.24.0 require ( github.com/IBM/sarama v1.43.3 github.com/avast/retry-go/v4 v4.5.1 - github.com/aws/aws-sdk-go-v2 v1.25.0 + github.com/aws/aws-sdk-go-v2 v1.32.7 github.com/aws/aws-sdk-go-v2/service/kms v1.28.1 github.com/ericlagergren/decimal v0.0.0-20190420051523-6335edbaa640 // Do not upgrade this package. It will drag up the version used by SQLBoiler and break things. - github.com/ethereum/go-ethereum v1.14.0 + github.com/ethereum/go-ethereum v1.14.13 github.com/go-redis/redis/v8 v8.11.5 - github.com/gofiber/fiber/v2 v2.52.5 - github.com/golang-jwt/jwt/v5 v5.2.0 + github.com/gofiber/fiber/v2 v2.52.6 + github.com/golang-jwt/jwt/v5 v5.2.2 github.com/jarcoal/httpmock v1.1.0 github.com/lib/pq v1.10.9 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 github.com/rs/zerolog v1.32.0 - github.com/stretchr/testify v1.9.0 - go.uber.org/mock v0.4.0 + github.com/stretchr/testify v1.10.0 + go.uber.org/mock v0.5.0 golang.org/x/exp v0.0.0-20240213143201-ec583247a57a google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 ) require ( + github.com/DIMO-Network/cloudevent v0.0.4 github.com/DIMO-Network/yaml v0.1.0 golang.org/x/time v0.5.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect @@ -44,7 +44,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/holiman/uint256 v1.2.4 // indirect + github.com/holiman/uint256 v1.3.1 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect @@ -55,21 +55,24 @@ require ( github.com/prometheus/common v0.47.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/sjson v1.2.5 // indirect github.com/volatiletech/inflect v0.0.1 // indirect github.com/volatiletech/null/v8 v8.1.2 // indirect github.com/volatiletech/randomize v0.0.1 // indirect - github.com/volatiletech/strmangle v0.0.6 // indirect + github.com/volatiletech/strmangle v0.0.7-0.20240503230658-86517898275a // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 // indirect - github.com/aws/smithy-go v1.20.0 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect + github.com/aws/smithy-go v1.22.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -78,15 +81,15 @@ require ( github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.52.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - github.com/volatiletech/sqlboiler/v4 v4.16.2 - golang.org/x/crypto v0.26.0 // indirect + github.com/volatiletech/sqlboiler/v4 v4.17.1 + golang.org/x/crypto v0.31.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/text v0.17.0 + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 ) diff --git a/go.sum b/go.sum index 5ee9b71..09acaf1 100644 --- a/go.sum +++ b/go.sum @@ -61,6 +61,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9s github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DIMO-Network/cloudevent v0.0.4 h1:uAACCZtZhdNYomz+enc1c9CZRDNRpau7jJQEwmvd0LA= +github.com/DIMO-Network/cloudevent v0.0.4/go.mod h1:uY68qV/p18qtbMzLpBCci3QrJzhDPlDt+QcMrh5XY2s= github.com/DIMO-Network/yaml v0.1.0 h1:KQ3oKHUZETchR6Pxbmmol3e4ewrPv/q8cEwqxfwyZbU= github.com/DIMO-Network/yaml v0.1.0/go.mod h1:KkiehcbkVzH8Pf8f9dja8B2aW81gYYZSqfwzSj9yN68= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -75,8 +77,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apmckinlay/gsuneido v0.0.0-20190404155041-0b6cd442a18f/go.mod h1:JU2DOj5Fc6rol0yaT79Csr47QR0vONGwJtBNGRD7jmc= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -86,25 +88,21 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= -github.com/aws/aws-sdk-go-v2 v1.25.0 h1:sv7+1JVJxOu/dD/sz/csHX7jFqmP001TIY7aytBWDSQ= -github.com/aws/aws-sdk-go-v2 v1.25.0/go.mod h1:G104G1Aho5WqF+SR3mDIobTABQzpYV0WxMsKxlMggOA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 h1:NPs/EqVO+ajwOoq56EfcGKa3L3ruWuazkIw1BqxwOPw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0/go.mod h1:D+duLy2ylgatV+yTlQ8JTuLfDD0BnFvnQRc+o6tbZ4M= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 h1:ks7KGMVUMoDzcxNWUlEdI+/lokMFD136EL6DWmUOV80= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0/go.mod h1:hL6BWM/d/qz113fVitZjbXR0E+RCTU1+x+1Idyn5NgE= +github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= +github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8= github.com/aws/aws-sdk-go-v2/service/kms v1.28.1 h1:+KE6+fDNH9gwg/t6DRddIZW7MJVqf3/IdZqeNTFehuA= github.com/aws/aws-sdk-go-v2/service/kms v1.28.1/go.mod h1:Y/mkxhbaWCswchbBBLRwet6uYKl/026DZXS87c0DmuU= -github.com/aws/smithy-go v1.20.0 h1:6+kZsCXZwKxZS9RfISnPc4EXlHoyAkm2hPuM8X2BrrQ= -github.com/aws/smithy-go v1.20.0/go.mod h1:uo5RKksAl4PzhqaAbjd4rLgFoq5koTsQKYuGe7dklGc= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= -github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -161,8 +159,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20190420051523-6335edbaa640 h1:VMAacqPM03GapxpfNORtKNl9o6Uws1BQYL54WjmolN0= github.com/ericlagergren/decimal v0.0.0-20190420051523-6335edbaa640/go.mod h1:mdYyfAkzn9kyJ/kMk/7WE9ufl9lflh+2NvecQ5mAghs= -github.com/ethereum/go-ethereum v1.14.0 h1:xRWC5NlB6g1x7vNy4HDBLuqVNbtLrc7v8S6+Uxim1LU= -github.com/ethereum/go-ethereum v1.14.0/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= +github.com/ethereum/go-ethereum v1.14.13 h1:L81Wmv0OUP6cf4CW6wtXsr23RUrDhKs2+Y9Qto+OgHU= +github.com/ethereum/go-ethereum v1.14.13/go.mod h1:RAC2gVMWJ6FkxSPESfbshrcKpIokgQKsVKmAuqdekDY= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= @@ -191,8 +189,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= -github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= +github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= @@ -202,8 +200,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= -github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= @@ -332,8 +330,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -366,7 +364,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12/go.mod h1:u9MdXq/QageOOSGp7qG4XAQsYUMP+V5zEel/Vrl6OOc= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -408,8 +405,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= @@ -513,8 +510,9 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -533,10 +531,19 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -550,11 +557,13 @@ github.com/volatiletech/null/v8 v8.1.2 h1:kiTiX1PpwvuugKwfvUNX/SU/5A2KGZMXfGD0DU github.com/volatiletech/null/v8 v8.1.2/go.mod h1:98DbwNoKEpRrYtGjWFctievIfm4n4MxG0A6EBUcoS5g= github.com/volatiletech/randomize v0.0.1 h1:eE5yajattWqTB2/eN8df4dw+8jwAzBtbdo5sbWC4nMk= github.com/volatiletech/randomize v0.0.1/go.mod h1:GN3U0QYqfZ9FOJ67bzax1cqZ5q2xuj2mXrXBjWaRTlY= -github.com/volatiletech/sqlboiler/v4 v4.16.2 h1:PcV2bxjE+S+GwPKCyX7/AjlY3aiTKsOEjciLhpWQImc= -github.com/volatiletech/sqlboiler/v4 v4.16.2/go.mod h1:B14BPBGTrJ2X6l7lwnvV/iXgYR48+ozGSlzHI3frl6U= +github.com/volatiletech/sqlboiler/v4 v4.17.1 h1:3AggaTfY9SLBp7m3H0X2qMXN4OZzGGtCm20BfQ7O88g= +github.com/volatiletech/sqlboiler/v4 v4.17.1/go.mod h1:XgPlHwMabot/eOqvsRnzc4Bw84BJNzizr+ac+T9LTic= github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= -github.com/volatiletech/strmangle v0.0.6 h1:AdOYE3B2ygRDq4rXDij/MMwq6KVK/pWAYxpC7CLrkKQ= -github.com/volatiletech/strmangle v0.0.6/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0= +github.com/volatiletech/strmangle v0.0.7-0.20240503230658-86517898275a h1:3lAqrOZ7LWBar9Fgh0F5p7DAf4iTw31/Im8BtqpFt1Q= +github.com/volatiletech/strmangle v0.0.7-0.20240503230658-86517898275a/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -574,8 +583,8 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -593,8 +602,8 @@ golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -719,8 +728,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -807,8 +816,8 @@ golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -822,8 +831,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/middleware/privilegetoken/claims.go b/pkg/middleware/privilegetoken/claims.go index 0b6a76a..e2bb9af 100644 --- a/pkg/middleware/privilegetoken/claims.go +++ b/pkg/middleware/privilegetoken/claims.go @@ -1,63 +1,22 @@ package privilegetoken import ( - "encoding/json" - "fmt" + "math/big" "github.com/DIMO-Network/shared/pkg/privileges" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/gofiber/fiber/v2" "github.com/golang-jwt/jwt/v5" - "google.golang.org/protobuf/types/known/structpb" ) +// TODO: move this to token-exchanges type CustomClaims struct { ContractAddress common.Address `json:"contract_address"` - TokenID string `json:"token_id"` + TokenID *big.Int `json:"token_id"` PrivilegeIDs []privileges.Privilege `json:"privilege_ids"` } +// TODO: move this to token-exchange type Token struct { jwt.RegisteredClaims CustomClaims } - -func (c *CustomClaims) Proto() (*structpb.Struct, error) { - ap := make([]any, len(c.PrivilegeIDs)) - - for i := range c.PrivilegeIDs { - ap[i] = int64(c.PrivilegeIDs[i]) - } - - return structpb.NewStruct( - map[string]any{ - "contract_address": hexutil.Encode(c.ContractAddress[:]), - "token_id": c.TokenID, - "privilege_ids": ap, - }, - ) -} - -// Conflicts with the field, whoops. -func (c *CustomClaims) Sub() string { - return fmt.Sprintf("%s/%s", c.ContractAddress, c.TokenID) -} - -func getTokenClaims(c *fiber.Ctx) (CustomClaims, error) { - token := c.Locals("user").(*jwt.Token) - claims := token.Claims.(jwt.MapClaims) - - jsonbody, err := json.Marshal(claims) - if err != nil { - return CustomClaims{}, err - } - - var t Token - err = json.Unmarshal(jsonbody, &t) - if err != nil { - return CustomClaims{}, err - } - - return t.CustomClaims, nil -} diff --git a/pkg/middleware/privilegetoken/main.go b/pkg/middleware/privilegetoken/main.go deleted file mode 100644 index bcad73f..0000000 --- a/pkg/middleware/privilegetoken/main.go +++ /dev/null @@ -1,93 +0,0 @@ -package privilegetoken - -import ( - "fmt" - - "github.com/DIMO-Network/shared/pkg/privileges" - "github.com/ethereum/go-ethereum/common" - "github.com/gofiber/fiber/v2" - "github.com/rs/zerolog" - "golang.org/x/exp/slices" -) - -type IVerifyPrivilegeToken interface { - OneOf(contract common.Address, privilegeIDs []privileges.Privilege) fiber.Handler -} - -type Config struct { - Log *zerolog.Logger -} - -type verifyPrivilegeToken struct { - cfg Config -} - -func New(cfg Config) IVerifyPrivilegeToken { - return &verifyPrivilegeToken{ - cfg: cfg, - } -} - -func (p *verifyPrivilegeToken) OneOf(contract common.Address, privilegeIDs []privileges.Privilege) fiber.Handler { - return func(c *fiber.Ctx) error { - return p.checkPrivilege(c, contract, privilegeIDs) - } -} - -func (p *verifyPrivilegeToken) getClaims(c *fiber.Ctx, logger zerolog.Logger) (CustomClaims, error) { - - claims, err := getTokenClaims(c) - if err != nil { - logger.Debug().Str("TokenID In Request", c.Params("tokenID")). - Str("TokenID in bearer token", claims.Sub()). - Msg(err.Error()) - return CustomClaims{}, fiber.NewError(fiber.StatusUnauthorized, "Error verifying user privilege!") - } - - tkID := c.Params("tokenID") - - if tkID != claims.TokenID { - logger.Debug().Str("DeviceTokenID", tkID). - Str("jwtTokenID", claims.TokenID). - Msg("Mismatched token ids") - return CustomClaims{}, fiber.NewError(fiber.StatusUnauthorized, "Unauthorized! Wrong device token provided") - } - - return claims, nil -} - -func (p *verifyPrivilegeToken) checkPrivilege(c *fiber.Ctx, contract common.Address, privilegeIDs []privileges.Privilege) error { - logger := p.cfg.Log.With().Str("src", "mw.shared.privilegetoken").Logger() - - // This checks that the privileges are for the token specified by the path variable :tokenID - claims, err := p.getClaims(c, logger) - if err != nil { - return err - } - - if claims.ContractAddress != contract { - return fiber.NewError(fiber.StatusUnauthorized, fmt.Sprintf("Provided token is for the wrong contract: %s", claims.ContractAddress)) - } - - tkID := c.Params("tokenID") - - privilegeFound := false - - for _, v := range privilegeIDs { - pf := slices.Contains(claims.PrivilegeIDs, v) - if pf { - privilegeFound = true - break - } - } - - if !privilegeFound { - logger.Debug().Str("tokenId", tkID).Interface("requiredPrivilege", privilegeIDs).Interface("jwtPrivileges", claims.PrivilegeIDs).Msg("Token lacks the required privilege.") - return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized! Token does not contain required privileges") - } - - // Verify privilege is correct - c.Locals("tokenClaims", claims) - - return c.Next() -} diff --git a/pkg/middleware/privilegetoken/main_test.go b/pkg/middleware/privilegetoken/main_test.go deleted file mode 100644 index ad9bcd7..0000000 --- a/pkg/middleware/privilegetoken/main_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package privilegetoken - -import ( - "fmt" - "net/http/httptest" - "os" - "testing" - - "github.com/DIMO-Network/shared/pkg/privileges" - "github.com/ethereum/go-ethereum/common" - "github.com/gofiber/fiber/v2" - "github.com/golang-jwt/jwt/v5" - "github.com/rs/zerolog" - "github.com/stretchr/testify/assert" -) - -type httpTestTemplate struct { - description string // description of the test case - route string // route path to test - expectedCode int // expected HTTP status code -} - -type testHelper struct { - app *fiber.App - t *testing.T - assert *assert.Assertions - logger zerolog.Logger - privilegeMiddleware IVerifyPrivilegeToken -} - -func initTestHelper(t *testing.T) testHelper { - assert := assert.New(t) - app := fiber.New() // This can be moved into a new var to avoid re-initializing TBD. - logger := zerolog.New(os.Stdout).With().Timestamp().Logger() - - return testHelper{ - assert: assert, - t: t, - app: app, - logger: logger, - privilegeMiddleware: New(Config{ - Log: &logger, - }), - } -} - -func (t testHelper) signToken(p jwt.MapClaims) *jwt.Token { - return jwt.NewWithClaims(jwt.SigningMethodHS256, p) -} -func TestSuccessOnValidSinglePrivilege(t *testing.T) { - th := initTestHelper(t) - - test := httpTestTemplate{ - description: "Test success response when token contains at only allowed privilege on endpoint", - route: fmt.Sprintf("/v1/test/%d", 1), - expectedCode: fiber.StatusOK, - } - - vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) - - th.app.Use(func(c *fiber.Ctx) error { - token := th.signToken((jwt.MapClaims{ - "token_id": "1", - "contract_address": vehicleAddr, - "privilege_ids": []int64{int64(privileges.VehicleCommands)}, - })) - - c.Locals("user", token) - return c.Next() - }) - - th.app.Get("/v1/test/:tokenID", th.privilegeMiddleware.OneOf(vehicleAddr, []privileges.Privilege{privileges.VehicleCommands}), func(c *fiber.Ctx) error { - return c.SendString("Ok") - }) - - req := httptest.NewRequest("GET", test.route, nil) - - resp, _ := th.app.Test(req, 1) - - // Verify, if the status code is as expected - th.assert.Equalf(test.expectedCode, resp.StatusCode, test.description) -} - -func TestSuccessOnValidTokenPrivilegeOnMany(t *testing.T) { - th := initTestHelper(t) - - test := httpTestTemplate{ - description: "Test success response when token contains at least 1 of allowed privileges on endpoint", - route: fmt.Sprintf("/v1/test/%d", 1), - expectedCode: fiber.StatusOK, - } - - vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) - - th.app.Use(func(c *fiber.Ctx) error { - token := th.signToken((jwt.MapClaims{ - "token_id": "1", - "contract_address": vehicleAddr, - "privilege_ids": []int64{int64(privileges.VehicleCommands)}, - })) - - c.Locals("user", token) - return c.Next() - }) - - th.app.Get("/v1/test/:tokenID", th.privilegeMiddleware.OneOf(vehicleAddr, []privileges.Privilege{privileges.VehicleCommands, privileges.VehicleAllTimeLocation}), func(c *fiber.Ctx) error { - - return c.SendString("Ok") - }) - - req := httptest.NewRequest("GET", test.route, nil) - - resp, _ := th.app.Test(req, 1) - - // Verify, if the status code is as expected - th.assert.Equalf(test.expectedCode, resp.StatusCode, test.description) -} - -func TestMiddlewareWriteClaimsToContext(t *testing.T) { - th := initTestHelper(t) - - test := httpTestTemplate{ - description: "Test success response when token contains at least 1 of allowed privileges on endpoint", - route: fmt.Sprintf("/v1/test/%d", 1), - expectedCode: fiber.StatusOK, - } - - vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) - cClaims := CustomClaims{ - ContractAddress: vehicleAddr, - TokenID: "1", - PrivilegeIDs: []privileges.Privilege{privileges.VehicleCommands}, - } - th.app.Use(func(c *fiber.Ctx) error { - token := th.signToken((jwt.MapClaims{ - "token_id": cClaims.TokenID, - "contract_address": cClaims.ContractAddress, - "privilege_ids": cClaims.PrivilegeIDs, - })) - - c.Locals("user", token) - return c.Next() - }) - - th.app.Get("/v1/test/:tokenID", th.privilegeMiddleware.OneOf(vehicleAddr, []privileges.Privilege{privileges.VehicleAllTimeLocation, privileges.VehicleCommands}), func(c *fiber.Ctx) error { - cl := c.Locals("tokenClaims").(CustomClaims) - th.assert.Equal(cl, cClaims) - return c.SendString("Ok") - }) - - req := httptest.NewRequest("GET", test.route, nil) - - resp, _ := th.app.Test(req, 1) - - // Verify, if the status code is as expected - th.assert.Equalf(test.expectedCode, resp.StatusCode, test.description) -} - -func TestFailureOnInvalidPrivilegeInToken(t *testing.T) { - th := initTestHelper(t) - - test := httpTestTemplate{ - description: "Test unauthorized response when token does not contain at least 1 of allowed privileges on endpoint", - route: fmt.Sprintf("/v1/test/%d", 1), - expectedCode: fiber.StatusUnauthorized, - } - - vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) - - th.app.Use(func(c *fiber.Ctx) error { - token := th.signToken((jwt.MapClaims{ - "token_id": "1", - "contract_address": vehicleAddr, - "privilege_ids": []int64{int64(privileges.VehicleCommands)}, - })) - - c.Locals("user", token) - return c.Next() - }) - - th.app.Get("/v1/test/:tokenID", th.privilegeMiddleware.OneOf(vehicleAddr, []privileges.Privilege{privileges.VehicleAllTimeLocation}), func(c *fiber.Ctx) error { - return c.SendString("Ok") - }) - - req := httptest.NewRequest("GET", test.route, nil) - - resp, _ := th.app.Test(req, 1) - - // Verify, if the status code is as expected - th.assert.Equalf(test.expectedCode, resp.StatusCode, test.description) -} - -func TestFailureOnInvalidContractAddress(t *testing.T) { - th := initTestHelper(t) - - test := httpTestTemplate{ - description: "Test unauthorized response when token does not contain at least 1 of allowed privileges on endpoint", - route: fmt.Sprintf("/v1/test/%d", 1), - expectedCode: fiber.StatusUnauthorized, - } - - vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) - - th.app.Use(func(c *fiber.Ctx) error { - token := th.signToken((jwt.MapClaims{ - "token_id": "1", - "contract_address": common.BytesToAddress([]byte{uint8(2)}), - "privilege_ids": []int64{int64(privileges.VehicleCommands)}, - })) - - c.Locals("user", token) - return c.Next() - }) - - th.app.Get("/v1/test/:tokenID", th.privilegeMiddleware.OneOf(vehicleAddr, []privileges.Privilege{privileges.VehicleAllTimeLocation}), func(c *fiber.Ctx) error { - return c.SendString("Ok") - }) - - req := httptest.NewRequest("GET", test.route, nil) - - resp, _ := th.app.Test(req, 1) - - // Verify, if the status code is as expected - th.assert.Equalf(test.expectedCode, resp.StatusCode, test.description) -} diff --git a/pkg/middleware/privilegetoken/privilegetoken.go b/pkg/middleware/privilegetoken/privilegetoken.go new file mode 100644 index 0000000..428b0df --- /dev/null +++ b/pkg/middleware/privilegetoken/privilegetoken.go @@ -0,0 +1,152 @@ +// Package privilegetoken provides a middleware that verifies the privileges of a token. +package privilegetoken + +import ( + "math/big" + + "github.com/DIMO-Network/cloudevent" + "github.com/DIMO-Network/shared/pkg/privileges" + "github.com/ethereum/go-ethereum/common" + "github.com/gofiber/fiber/v2" + "github.com/golang-jwt/jwt/v5" + "github.com/rs/zerolog" + "golang.org/x/exp/slices" +) + +const ( + tokenIDKey = "tokenId" +) + +// VerifyPrivilegeToken is a middleware that verifies the privileges of a token. +type VerifyPrivilegeToken struct { + Contract common.Address + ChainID uint64 + PathParam string +} + +// OneOf verifies that the token contains at least one of the specified privileges. +func (v *VerifyPrivilegeToken) OneOf(privilegeIDs []privileges.Privilege) fiber.Handler { + return func(c *fiber.Ctx) error { + return v.verifyPrivileges(c, privilegeIDs, false) + } +} + +// AllOf verifies that the token contains all of the specified privileges. +func (v *VerifyPrivilegeToken) AllOf(privilegeIDs []privileges.Privilege) fiber.Handler { + return func(c *fiber.Ctx) error { + return v.verifyPrivileges(c, privilegeIDs, true) + } +} + +// verifyPrivileges verifies the privileges of a token. +func (v *VerifyPrivilegeToken) verifyPrivileges(c *fiber.Ctx, privilegeIDs []privileges.Privilege, requireAll bool) error { + claims, err := getTokenClaims(c) + if err != nil { + return err + } + + tokenID, err := validateTokenParams(c, v.PathParam) + if err != nil { + return err + } + + if err := validateTokenDetails(c, claims, tokenID, v.Contract, v.ChainID); err != nil { + return err + } + + return checkPrivileges(c, claims, tokenID, privilegeIDs, requireAll) +} + +// validateTokenParams validates the token ID from the path parameters. +func validateTokenParams(c *fiber.Ctx, pathParam string) (*big.Int, error) { + if pathParam == "" { + pathParam = "tokenID" + } + tokenParam := c.Params(pathParam) + tokenID, ok := big.NewInt(0).SetString(tokenParam, 10) + if !ok { + return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid token ID") + } + return tokenID, nil +} + +// validateTokenDetails validates the token details. +func validateTokenDetails(c *fiber.Ctx, claims Token, tokenID *big.Int, contract common.Address, chainID uint64) error { + expectedSubject := cloudevent.NFTDID{ + ChainID: chainID, + ContractAddress: contract, + TokenID: uint32(tokenID.Uint64()), //TODO: Update this when cloudevent uses big.Int + }.String() + + if claims.Subject != expectedSubject { + logger(c).Debug(). + Str("tokenId", tokenID.String()). + Str("jwtSubject", claims.Subject). + Msg("Mismatched token subject") + return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized: Invalid token subject") + } + if claims.ContractAddress != contract { + logger(c).Debug(). + Str(tokenIDKey, tokenID.String()). + Str("jwtContractAddress", claims.ContractAddress.String()). + Msg("Mismatched contract addresses") + return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized: Invalid contract address") + } + if claims.TokenID.Cmp(tokenID) != 0 { + logger(c).Debug(). + Str(tokenIDKey, tokenID.String()). + Str("jwtTokenId", claims.TokenID.String()). + Msg("Mismatched token Ids") + return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized: Invalid token ID") + } + return nil +} + +// checkPrivileges checks the privileges of a token. +func checkPrivileges(c *fiber.Ctx, claims Token, tokenID *big.Int, privilegeIDs []privileges.Privilege, requireAll bool) error { + if requireAll { + for _, privilege := range privilegeIDs { + if !slices.Contains(claims.PrivilegeIDs, privilege) { + logger(c).Debug(). + Str(tokenIDKey, tokenID.String()). + Interface("requiredPrivileges", privilegeIDs). + Interface("actualPrivileges", claims.PrivilegeIDs). + Msg("Token privilege verification failed: missing all required") + return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized: Token does not contain all required privileges") + } + } + c.Locals("tokenClaims", claims) + return c.Next() + } + + // If not all, then at least one is required + for _, privilege := range privilegeIDs { + if slices.Contains(claims.PrivilegeIDs, privilege) { + c.Locals("tokenClaims", claims) + return c.Next() + } + } + logger(c).Debug(). + Str(tokenIDKey, tokenID.String()). + Interface("requiredPrivileges", privilegeIDs). + Interface("actualPrivileges", claims.PrivilegeIDs). + Msg("Token privilege verification failed: missing any required") + return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized: Token does not contain any of the required privileges") +} + +func getTokenClaims(c *fiber.Ctx) (Token, error) { + token, ok := c.Locals("user").(*jwt.Token) + if !ok { + return Token{}, fiber.NewError(fiber.StatusUnauthorized, "Invalid token in context") + } + claims, ok := token.Claims.(Token) + if !ok { + return Token{}, fiber.NewError(fiber.StatusUnauthorized, "Invalid token claims") + } + return claims, nil +} + +func logger(c *fiber.Ctx) *zerolog.Logger { + logger := zerolog.Ctx(c.UserContext()).With().Str("src", "mw.shared.privilegetoken").Logger() + return &logger +} diff --git a/pkg/middleware/privilegetoken/privilegetoken_test.go b/pkg/middleware/privilegetoken/privilegetoken_test.go new file mode 100644 index 0000000..9327471 --- /dev/null +++ b/pkg/middleware/privilegetoken/privilegetoken_test.go @@ -0,0 +1,214 @@ +package privilegetoken + +import ( + "fmt" + "io" + "math/big" + "net/http/httptest" + "testing" + + "github.com/DIMO-Network/cloudevent" + "github.com/DIMO-Network/shared/pkg/privileges" + "github.com/ethereum/go-ethereum/common" + "github.com/gofiber/fiber/v2" + "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type httpTestTemplate struct { + description string // description of the test case + route string // route path to test + expectedCode int // expected HTTP status code +} + +func signToken(p jwt.Claims) *jwt.Token { + return jwt.NewWithClaims(jwt.SigningMethodHS256, p) +} +func TestSuccessOnValidSinglePrivilege(t *testing.T) { + vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) + privilegeMiddleware := VerifyPrivilegeToken{ + Contract: vehicleAddr, + ChainID: 1, + PathParam: "tokenID", + } + app := fiber.New() + + test := httpTestTemplate{ + description: "Test success response when token contains at only allowed privilege on endpoint", + route: fmt.Sprintf("/v1/test/%d", 1), + expectedCode: fiber.StatusOK, + } + + app.Use(func(c *fiber.Ctx) error { + token := signToken(Token{ + CustomClaims: CustomClaims{ + ContractAddress: vehicleAddr, + TokenID: big.NewInt(1), + PrivilegeIDs: []privileges.Privilege{privileges.VehicleCommands}, + }, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: cloudevent.NFTDID{ + ChainID: 1, + ContractAddress: vehicleAddr, + TokenID: 1, + }.String(), + }, + }) + + c.Locals("user", token) + return c.Next() + }) + + app.Get("/v1/test/:tokenID", privilegeMiddleware.OneOf([]privileges.Privilege{privileges.VehicleCommands}), func(c *fiber.Ctx) error { + return c.SendString("Ok") + }) + + req := httptest.NewRequest("GET", test.route, nil) + + resp, err := app.Test(req) + require.NoError(t, err) + body, _ := io.ReadAll(resp.Body) + // Verify, if the status code is as expected + assert.Equalf(t, test.expectedCode, resp.StatusCode, string(body)) +} + +func TestSuccessOnValidTokenPrivilegeOnMany(t *testing.T) { + app := fiber.New() + vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) + privilegeMiddleware := VerifyPrivilegeToken{ + Contract: vehicleAddr, + ChainID: 1, + PathParam: "tokenID", + } + + test := httpTestTemplate{ + description: "Test success response when token contains at least 1 of allowed privileges on endpoint", + route: fmt.Sprintf("/v1/test/%d", 1), + expectedCode: fiber.StatusOK, + } + + app.Use(func(c *fiber.Ctx) error { + token := signToken(Token{ + CustomClaims: CustomClaims{ + ContractAddress: vehicleAddr, + TokenID: big.NewInt(1), + PrivilegeIDs: []privileges.Privilege{privileges.VehicleCommands}, + }, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: cloudevent.NFTDID{ + ChainID: 1, + ContractAddress: vehicleAddr, + TokenID: 1, + }.String(), + }, + }) + + c.Locals("user", token) + return c.Next() + }) + + app.Get("/v1/test/:tokenID", privilegeMiddleware.OneOf([]privileges.Privilege{privileges.VehicleCommands, privileges.VehicleAllTimeLocation}), func(c *fiber.Ctx) error { + return c.SendString("Ok") + }) + + req := httptest.NewRequest("GET", test.route, nil) + + resp, _ := app.Test(req, 1) + + // Verify, if the status code is as expected + assert.Equalf(t, test.expectedCode, resp.StatusCode, test.description) +} + +func TestFailureOnInvalidPrivilegeInToken(t *testing.T) { + app := fiber.New() + vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) + privilegeMiddleware := VerifyPrivilegeToken{ + Contract: vehicleAddr, + ChainID: 1, + PathParam: "tokenID", + } + + test := httpTestTemplate{ + description: "Test unauthorized response when token does not contain at least 1 of allowed privileges on endpoint", + route: fmt.Sprintf("/v1/test/%d", 1), + expectedCode: fiber.StatusUnauthorized, + } + + app.Use(func(c *fiber.Ctx) error { + token := signToken(Token{ + CustomClaims: CustomClaims{ + ContractAddress: vehicleAddr, + TokenID: big.NewInt(1), + PrivilegeIDs: []privileges.Privilege{privileges.VehicleCommands}, + }, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: cloudevent.NFTDID{ + ChainID: 1, + ContractAddress: vehicleAddr, + TokenID: 1, + }.String(), + }, + }) + + c.Locals("user", token) + return c.Next() + }) + + app.Get("/v1/test/:tokenID", privilegeMiddleware.OneOf([]privileges.Privilege{privileges.VehicleAllTimeLocation}), func(c *fiber.Ctx) error { + return c.SendString("Ok") + }) + + req := httptest.NewRequest("GET", test.route, nil) + + resp, _ := app.Test(req, 1) + + // Verify, if the status code is as expected + assert.Equalf(t, test.expectedCode, resp.StatusCode, test.description) +} + +func TestFailureOnInvalidContractAddress(t *testing.T) { + app := fiber.New() + vehicleAddr := common.BytesToAddress([]byte{uint8(1)}) + privilegeMiddleware := VerifyPrivilegeToken{ + Contract: vehicleAddr, + ChainID: 1, + PathParam: "tokenID", + } + + test := httpTestTemplate{ + description: "Test unauthorized response when token does not contain at least 1 of allowed privileges on endpoint", + route: fmt.Sprintf("/v1/test/%d", 1), + expectedCode: fiber.StatusUnauthorized, + } + + app.Use(func(c *fiber.Ctx) error { + token := signToken(Token{ + CustomClaims: CustomClaims{ + ContractAddress: vehicleAddr, + TokenID: big.NewInt(1), + PrivilegeIDs: []privileges.Privilege{privileges.VehicleCommands}, + }, + RegisteredClaims: jwt.RegisteredClaims{ + Subject: cloudevent.NFTDID{ + ChainID: 1, + ContractAddress: vehicleAddr, + TokenID: 1, + }.String(), + }, + }) + c.Locals("user", token) + return c.Next() + }) + + app.Get("/v1/test/:tokenID", privilegeMiddleware.OneOf([]privileges.Privilege{privileges.VehicleAllTimeLocation}), func(c *fiber.Ctx) error { + return c.SendString("Ok") + }) + + req := httptest.NewRequest("GET", test.route, nil) + + resp, _ := app.Test(req, 1) + + // Verify, if the status code is as expected + assert.Equalf(t, test.expectedCode, resp.StatusCode, test.description) +} diff --git a/pkg/payloads/cloudevent.go b/pkg/payloads/cloudevent.go index 3e515c8..05acfd8 100644 --- a/pkg/payloads/cloudevent.go +++ b/pkg/payloads/cloudevent.go @@ -4,6 +4,8 @@ import "time" // CloudEvent represents an event according to the CloudEvents spec. // See https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md +// +// Deprecated: Use github.com/DIMO-Network/cloudevent.CloudEvent instead. type CloudEvent[A any] struct { // ID is an identifier for the event. The combination of ID and Source must // be unique. @@ -35,6 +37,8 @@ type CloudEvent[A any] struct { } // CloudEventHeaders contains the fields common to all CloudEvent messages. +// +// Deprecated: Use github.com/DIMO-Network/cloudevent.CloudEventHeaders instead. type CloudEventHeaders struct { ID string `json:"id"` Source string `json:"source"`