diff --git a/go.mod b/go.mod index 4cec24f..7c75e22 100644 --- a/go.mod +++ b/go.mod @@ -6,16 +6,15 @@ require ( github.com/ClickHouse/clickhouse-go/v2 v2.40.1 github.com/DIMO-Network/clickhouse-infra v0.0.5 github.com/DIMO-Network/cloudevent v0.1.4 - github.com/DIMO-Network/server-garage v0.0.4 + github.com/DIMO-Network/server-garage v0.0.7 github.com/DIMO-Network/shared v1.0.7 github.com/aws/aws-sdk-go-v2 v1.38.3 github.com/aws/aws-sdk-go-v2/credentials v1.18.10 github.com/aws/aws-sdk-go-v2/service/s3 v1.87.3 - github.com/ethereum/go-ethereum v1.16.3 - github.com/gofiber/contrib/jwt v1.1.2 + github.com/ethereum/go-ethereum v1.16.4 github.com/gofiber/fiber/v2 v2.52.9 github.com/gofiber/swagger v1.1.1 - github.com/golang-jwt/jwt/v5 v5.3.0 + github.com/google/go-cmp v0.7.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 @@ -24,20 +23,19 @@ require ( github.com/swaggo/swag v1.16.6 github.com/volatiletech/sqlboiler/v4 v4.19.1 go.uber.org/mock v0.6.0 - golang.org/x/sync v0.16.0 + golang.org/x/sync v0.17.0 google.golang.org/grpc v1.75.0 - google.golang.org/protobuf v1.36.8 + google.golang.org/protobuf v1.36.10 ) require ( dario.cat/mergo v1.0.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/ClickHouse/ch-go v0.67.0 // indirect + github.com/DIMO-Network/token-exchange-api v0.3.7 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.1 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.6 // indirect @@ -72,11 +70,13 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/spec v0.20.4 // indirect - github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-openapi/jsonpointer v0.20.2 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/spec v0.20.14 // indirect + github.com/go-openapi/swag v0.22.9 // indirect + github.com/gofiber/contrib/jwt v1.1.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/joho/godotenv v1.5.1 // indirect @@ -84,7 +84,7 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect github.com/magiconair/properties v1.8.10 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect @@ -130,8 +130,7 @@ require ( github.com/tklauser/numcpus v0.10.0 // indirect github.com/urfave/cli/v2 v2.27.5 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.55.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect + github.com/valyala/fasthttp v1.65.0 // indirect github.com/volatiletech/inflect v0.0.1 // indirect github.com/volatiletech/strmangle v0.0.7-0.20240503230658-86517898275a // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect @@ -142,13 +141,12 @@ require ( go.opentelemetry.io/otel/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.27.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/tools v0.36.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/mod v0.28.0 // indirect + golang.org/x/net v0.45.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/tools v0.37.0 // indirect golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect diff --git a/go.sum b/go.sum index 7f9dd1f..a63ec39 100644 --- a/go.sum +++ b/go.sum @@ -16,20 +16,18 @@ github.com/DIMO-Network/clickhouse-infra v0.0.5 h1:zY1STwb9+vovpYXdjaeakE29pgZPI github.com/DIMO-Network/clickhouse-infra v0.0.5/go.mod h1:XS80lhSJNWBWGgZ+m4j7++zFj1wAXfmtV2gJfhGlabQ= github.com/DIMO-Network/cloudevent v0.1.4 h1:c6Sq4CyHt05V8OtnEXekUCRGfVuR1pFkJevfiKt1sYM= github.com/DIMO-Network/cloudevent v0.1.4/go.mod h1:Q2QpMEDYJ+VX0lz9SK2EUFxkuddV1XeF4aQ8LfegB68= -github.com/DIMO-Network/server-garage v0.0.4 h1:K0wnQ2vJAtyK8lbINxKneVyqELORAu4Ut1ePZ3yb8cI= -github.com/DIMO-Network/server-garage v0.0.4/go.mod h1:bdj0wKTjozjjD2w7Htk/rnzOv+jH+iBrhCuXOP/H00s= +github.com/DIMO-Network/server-garage v0.0.7 h1:kOBVyOtIbxa1x9pAf1epABTb9l/U3khf0PwUaHeHiKs= +github.com/DIMO-Network/server-garage v0.0.7/go.mod h1:7DFor8MMJ8fLv9EB16Z5LrN+ftW3qeIk+swpkT7F2cU= github.com/DIMO-Network/shared v1.0.7 h1:LfSgsqJ6R7EUyfo2GTfuhrCpoDcweJqe7eVOa4j7Xbo= github.com/DIMO-Network/shared v1.0.7/go.mod h1:lDHUKwwT2LW6Zvd42Nb33dXklRNTmfyOlbUNx2dQfGY= +github.com/DIMO-Network/token-exchange-api v0.3.7 h1:i5Ygs9DuPSwE8BC90Q6gnKnfgqw19GseF2x0vZ9sCG8= +github.com/DIMO-Network/token-exchange-api v0.3.7/go.mod h1:gKoB1Zi3EXJqIyfLnTn1GV1NSzTMBDkRleChBU/EQv8= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/aws/aws-sdk-go-v2 v1.38.3 h1:B6cV4oxnMs45fql4yRH+/Po/YU+597zgWqvDpYMturk= @@ -81,7 +79,6 @@ github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GK github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -108,8 +105,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ethereum/go-ethereum v1.16.3 h1:nDoBSrmsrPbrDIVLTkDQCy1U9KdHN+F2PzvMbDoS42Q= -github.com/ethereum/go-ethereum v1.16.3/go.mod h1:Lrsc6bt9Gm9RyvhfFK53vboCia8kpF9nv+2Ukntnl+8= +github.com/ethereum/go-ethereum v1.16.4 h1:H6dU0r2p/amA7cYg6zyG9Nt2JrKKH6oX2utfcqrSpkQ= +github.com/ethereum/go-ethereum v1.16.4/go.mod h1:P7551slMFbjn2zOQaKrJShZVN/d8bGxp4/I6yZVlb5w= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -130,16 +127,14 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= +github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= +github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do= +github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= +github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= +github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/contrib/jwt v1.1.2 h1:GmWnOqT4A15EkA8IPXwSpvNUXZR4u5SMj+geBmyLAjs= @@ -203,10 +198,8 @@ github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr32 github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -243,7 +236,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -335,10 +327,8 @@ github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= -github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/valyala/fasthttp v1.65.0 h1:j/u3uzFEGFfRxw79iYzJN+TteTJwbYkru9uDp3d0Yf8= +github.com/valyala/fasthttp v1.65.0/go.mod h1:P/93/YkKPMsKSnATEeELUCkG8a7Y+k99uxNHVbKINr4= github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= github.com/volatiletech/inflect v0.0.1/go.mod h1:IBti31tG6phkHitLlr5j7shC5SOo//x0AjDzaJU1PLA= github.com/volatiletech/null/v8 v8.1.2 h1:kiTiX1PpwvuugKwfvUNX/SU/5A2KGZMXfGD0DUHdKEI= @@ -396,8 +386,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= @@ -407,8 +397,8 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -417,10 +407,9 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -428,8 +417,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -438,7 +427,6 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -448,17 +436,17 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.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.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/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.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -470,8 +458,8 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -500,11 +488,10 @@ google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOda google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -512,7 +499,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/app/app.go b/internal/app/app.go index c65b05d..18b6b7f 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -8,13 +8,11 @@ import ( "github.com/DIMO-Network/fetch-api/internal/config" "github.com/DIMO-Network/fetch-api/internal/fetch/httphandler" "github.com/DIMO-Network/fetch-api/internal/fetch/rpc" - "github.com/DIMO-Network/fetch-api/pkg/auth" fetchgrpc "github.com/DIMO-Network/fetch-api/pkg/grpc" "github.com/DIMO-Network/server-garage/pkg/fibercommon" + "github.com/DIMO-Network/server-garage/pkg/fibercommon/jwtmiddleware" "github.com/DIMO-Network/shared/pkg/middleware/metrics" - "github.com/DIMO-Network/shared/pkg/middleware/privilegetoken" - "github.com/DIMO-Network/shared/pkg/privileges" - jwtware "github.com/gofiber/contrib/jwt" + "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/recover" @@ -41,10 +39,7 @@ func CreateWebServer(settings *config.Settings) (*fiber.App, error) { }) app.Use(fibercommon.ContextLoggerMiddleware) - jwtAuth := jwtware.New(jwtware.Config{ - JWKSetURLs: []string{settings.TokenExchangeJWTKeySetURL}, - Claims: &privilegetoken.Token{}, - }) + jwtAuth := jwtmiddleware.NewJWTMiddleware(settings.TokenExchangeJWTKeySetURL) app.Use(recover.New(recover.Config{ Next: nil, @@ -66,8 +61,6 @@ func CreateWebServer(settings *config.Settings) (*fiber.App, error) { v1 := app.Group("/v1") vehicleGroup := v1.Group("/vehicle") - vehiclePriv := auth.AllOf(settings.VehicleNFTAddress, "tokenId", []privileges.Privilege{privileges.Privilege(7)}) - chConn, err := chClientFromSettings(settings) if err != nil { return nil, fmt.Errorf("failed to create ClickHouse connection: %w", err) @@ -76,11 +69,14 @@ func CreateWebServer(settings *config.Settings) (*fiber.App, error) { s3Client := s3ClientFromSettings(settings) vehHandler := httphandler.NewHandler(chConn, s3Client, []string{settings.CloudEventBucket, settings.EphemeralBucket, settings.VCBucket}, settings.VehicleNFTAddress, chainId) + + vehicleMiddleware := jwtmiddleware.AllOfPermissions(settings.VehicleNFTAddress, httphandler.TokenIDParam, []string{tokenclaims.PermissionGetRawData}) + // File endpoints - vehicleGroup.Post("/latest-index-key/:tokenId", vehiclePriv, jwtAuth, vehHandler.GetLatestIndexKey) - vehicleGroup.Post("/index-keys/:tokenId", vehiclePriv, jwtAuth, vehHandler.GetIndexKeys) - vehicleGroup.Post("/objects/:tokenId", jwtAuth, vehiclePriv, vehHandler.GetObjects) - vehicleGroup.Post("/latest-object/:tokenId", jwtAuth, vehiclePriv, vehHandler.GetLatestObject) + vehicleGroup.Post("/latest-index-key/:"+httphandler.TokenIDParam, jwtAuth, vehicleMiddleware, vehHandler.GetLatestIndexKey) + vehicleGroup.Post("/index-keys/:"+httphandler.TokenIDParam, jwtAuth, vehicleMiddleware, vehHandler.GetIndexKeys) + vehicleGroup.Post("/objects/:"+httphandler.TokenIDParam, jwtAuth, vehicleMiddleware, vehHandler.GetObjects) + vehicleGroup.Post("/latest-object/:"+httphandler.TokenIDParam, jwtAuth, vehicleMiddleware, vehHandler.GetLatestObject) return app, nil } diff --git a/internal/fetch/httphandler/httphandler.go b/internal/fetch/httphandler/httphandler.go index 9d6a57b..3df5a68 100644 --- a/internal/fetch/httphandler/httphandler.go +++ b/internal/fetch/httphandler/httphandler.go @@ -24,7 +24,8 @@ import ( ) const ( - errTimeout = "request exceeded or is estimated to exceed the maximum execution time" + TokenIDParam = "tokenId" + errTimeout = "request exceeded or is estimated to exceed the maximum execution time" ) type cloudReturn cloudevent.CloudEvent[eventrepo.ObjectInfo] //nolint:unused // Used in OpenAPI docs @@ -98,7 +99,7 @@ func NewHandler(chConn clickhouse.Conn, s3Client *s3.Client, buckets []string, // @Failure 500 {object} map[string]string "Server error" // @Router /v1/vehicle/latest-index-key/{tokenId} [get] func (h *Handler) GetLatestIndexKey(fCtx *fiber.Ctx) error { - tokenID := fCtx.Params("tokenId") + tokenID := fCtx.Params(TokenIDParam) uTokenID, err := strconv.ParseUint(tokenID, 0, 32) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to parse token ID: %v", err)) @@ -133,7 +134,7 @@ func (h *Handler) GetLatestIndexKey(fCtx *fiber.Ctx) error { // @Failure 500 {object} map[string]string "Server error" // @Router /v1/vehicle/index-keys/{tokenId} [get] func (h *Handler) GetIndexKeys(fCtx *fiber.Ctx) error { - tokenID := fCtx.Params("tokenId") + tokenID := fCtx.Params(TokenIDParam) uTokenID, err := strconv.ParseUint(tokenID, 0, 32) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to parse token ID: %v", err)) @@ -168,7 +169,7 @@ func (h *Handler) GetIndexKeys(fCtx *fiber.Ctx) error { // @Failure 500 {object} map[string]string "Server error" // @Router /v1/vehicle/objects/{tokenId} [get] func (h *Handler) GetObjects(fCtx *fiber.Ctx) error { - tokenID := fCtx.Params("tokenId") + tokenID := fCtx.Params(TokenIDParam) uTokenID, err := strconv.ParseUint(tokenID, 0, 32) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to parse token ID: %v", err)) @@ -207,7 +208,7 @@ func (h *Handler) GetObjects(fCtx *fiber.Ctx) error { // @Failure 500 {object} map[string]string "Server error" // @Router /v1/vehicle/latest-object/{tokenId} [get] func (h *Handler) GetLatestObject(fCtx *fiber.Ctx) error { - tokenID := fCtx.Params("tokenId") + tokenID := fCtx.Params(TokenIDParam) uTokenID, err := strconv.ParseUint(tokenID, 0, 32) if err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("failed to parse token ID: %v", err)) diff --git a/internal/fetch/rpc/rpc.go b/internal/fetch/rpc/rpc.go index bdb1aeb..2db206e 100644 --- a/internal/fetch/rpc/rpc.go +++ b/internal/fetch/rpc/rpc.go @@ -4,7 +4,6 @@ package rpc import ( "context" "database/sql" - "encoding/json" "errors" "github.com/ClickHouse/clickhouse-go/v2" @@ -15,7 +14,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/types/known/timestamppb" ) // Server is used to implement grpc.IndexRepoServiceServer. @@ -55,7 +53,7 @@ func (s *Server) GetLatestIndex(ctx context.Context, req *grpc.GetLatestIndexReq Data: &grpc.ObjectInfo{ Key: index.Data.Key, }, - Header: cloudEventHeaderToProto(&index.CloudEventHeader), + Header: grpc.CloudEventHeaderToProto(&index.CloudEventHeader), }, }, nil } @@ -83,7 +81,7 @@ func (s *Server) ListIndexes(ctx context.Context, req *grpc.ListIndexesRequest) Data: &grpc.ObjectInfo{ Key: indexObjs[i].Data.Key, }, - Header: cloudEventHeaderToProto(&indexObjs[i].CloudEventHeader), + Header: grpc.CloudEventHeaderToProto(&indexObjs[i].CloudEventHeader), } } return &grpc.ListIndexesResponse{Indexes: indexList}, nil @@ -113,7 +111,7 @@ func (s *Server) ListCloudEvents(ctx context.Context, req *grpc.ListCloudEventsR events := make([]*grpc.CloudEvent, len(data)) for i, d := range data { - events[i] = cloudEventToProto(d) + events[i] = grpc.CloudEventToProto(d) } return &grpc.ListCloudEventsResponse{CloudEvents: events}, nil } @@ -139,7 +137,7 @@ func (s *Server) GetLatestCloudEvent(ctx context.Context, req *grpc.GetLatestClo if err != nil { return nil, status.Errorf(codes.Internal, "failed to get latest object: %v", err) } - return &grpc.GetLatestCloudEventResponse{CloudEvent: cloudEventToProto(latestData)}, nil + return &grpc.GetLatestCloudEventResponse{CloudEvent: grpc.CloudEventToProto(latestData)}, nil } // ListCloudEventsFromIndex translates the gRPC call to the indexrepo type and fetches data for the given index keys. @@ -164,51 +162,7 @@ func (s *Server) ListCloudEventsFromIndex(ctx context.Context, req *grpc.ListClo } dataObjects := make([]*grpc.CloudEvent, len(data)) for i, d := range data { - dataObjects[i] = cloudEventToProto(d) + dataObjects[i] = grpc.CloudEventToProto(d) } return &grpc.ListCloudEventsFromKeysResponse{CloudEvents: dataObjects}, nil } - -func cloudEventHeaderToProto(event *cloudevent.CloudEventHeader) *grpc.CloudEventHeader { - if event == nil { - return nil - } - extras := make(map[string][]byte) - for k, v := range event.Extras { - v, err := json.Marshal(v) - if err != nil { - // Skip the extra if it can't be marshaled - continue - } - extras[k] = v - } - return &grpc.CloudEventHeader{ - Id: event.ID, - Source: event.Source, - Producer: event.Producer, - Subject: event.Subject, - SpecVersion: event.SpecVersion, - Time: timestamppb.New(event.Time), - Type: event.Type, - DataContentType: event.DataContentType, - DataSchema: event.DataSchema, - DataVersion: event.DataVersion, - Extras: extras, - } -} - -func cloudEventToProto(event cloudevent.CloudEvent[json.RawMessage]) *grpc.CloudEvent { - extras := make(map[string][]byte) - for k, v := range event.Extras { - v, err := json.Marshal(v) - if err != nil { - // Skip the extra if it can't be marshaled - continue - } - extras[k] = v - } - return &grpc.CloudEvent{ - Header: cloudEventHeaderToProto(&event.CloudEventHeader), - Data: event.Data, - } -} diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go deleted file mode 100644 index 1e0b889..0000000 --- a/pkg/auth/auth.go +++ /dev/null @@ -1,59 +0,0 @@ -package auth - -import ( - "fmt" - "slices" - - "github.com/DIMO-Network/shared/pkg/middleware/privilegetoken" - "github.com/DIMO-Network/shared/pkg/privileges" - "github.com/ethereum/go-ethereum/common" - "github.com/gofiber/fiber/v2" - "github.com/golang-jwt/jwt/v5" -) - -// AllOf creates a middleware that checks if the token contains all the required privileges -// this middleware also checks if the token is for the correct contract and token ID -func AllOf(contract common.Address, tokenIDParam string, privilegeIDs []privileges.Privilege) fiber.Handler { - return func(c *fiber.Ctx) error { - return checkAllPrivileges(c, contract, tokenIDParam, privilegeIDs) - } -} - -func checkAllPrivileges(ctx *fiber.Ctx, contract common.Address, tokenIDParam string, privilegeIDs []privileges.Privilege) error { - // This checks that the privileges are for the token specified by the path variable and the contract address is correct. - err := validateTokenIDAndAddress(ctx, contract, tokenIDParam) - if err != nil { - return err - } - - claims := getTokenClaim(ctx) - for _, v := range privilegeIDs { - if !slices.Contains(claims.PrivilegeIDs, v) { - return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized! Token does not contain required privileges") - } - } - - return ctx.Next() -} - -func validateTokenIDAndAddress(ctx *fiber.Ctx, contract common.Address, tokenIDParam string) error { - claims := getTokenClaim(ctx) - tokenID := ctx.Params(tokenIDParam) - - if tokenID != claims.TokenID { - return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized! mismatch token Id provided") - } - if claims.ContractAddress != contract { - return fiber.NewError(fiber.StatusUnauthorized, fmt.Sprintf("Provided token is for the wrong contract: %s", claims.ContractAddress)) - } - return nil -} - -func getTokenClaim(ctx *fiber.Ctx) *privilegetoken.Token { - token := ctx.Locals("user").(*jwt.Token) - claim, ok := token.Claims.(*privilegetoken.Token) - if !ok { - panic("TokenClaimsKey not found in fiber context") - } - return claim -} diff --git a/pkg/auth/auth_test.go b/pkg/auth/auth_test.go deleted file mode 100644 index 294e48d..0000000 --- a/pkg/auth/auth_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package auth_test - -import ( - "io" - "net/http/httptest" - "testing" - - "github.com/DIMO-Network/fetch-api/pkg/auth" - "github.com/DIMO-Network/shared/pkg/middleware/privilegetoken" - "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/require" -) - -func TestAllOf(t *testing.T) { - contract := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") - tokenIDParam := "tokenId" - privilegeIDs := []privileges.Privilege{ - privileges.VehicleNonLocationData, - privileges.VehicleCommands, - } - - tests := []struct { - name string - tokenClaims *privilegetoken.Token - tokenID string - expectedCode int - }{ - { - name: "Valid token with required privileges", - tokenClaims: &privilegetoken.Token{ - CustomClaims: privilegetoken.CustomClaims{ - TokenID: "1", - ContractAddress: contract, - PrivilegeIDs: []privileges.Privilege{privileges.VehicleNonLocationData, privileges.VehicleCommands}, - }, - }, - tokenID: "1", - expectedCode: fiber.StatusOK, - }, - { - name: "Token with missing privileges", - tokenClaims: &privilegetoken.Token{ - CustomClaims: privilegetoken.CustomClaims{ - TokenID: "1", - ContractAddress: contract, - PrivilegeIDs: []privileges.Privilege{privileges.VehicleNonLocationData}, - }, - }, - tokenID: "1", - expectedCode: fiber.StatusUnauthorized, - }, - { - name: "Token with wrong contract address", - tokenClaims: &privilegetoken.Token{ - CustomClaims: privilegetoken.CustomClaims{ - TokenID: "1", - ContractAddress: common.HexToAddress("0xabcdefabcdefabcdefabcdefabcdefabcdef"), - PrivilegeIDs: []privileges.Privilege{privileges.VehicleNonLocationData, privileges.VehicleCommands}, - }, - }, - tokenID: "1", - expectedCode: fiber.StatusUnauthorized, - }, - { - name: "Token with wrong token ID", - tokenClaims: &privilegetoken.Token{ - CustomClaims: privilegetoken.CustomClaims{ - TokenID: "2", - ContractAddress: contract, - PrivilegeIDs: []privileges.Privilege{privileges.VehicleNonLocationData, privileges.VehicleCommands}, - }, - }, - tokenID: "1", - expectedCode: fiber.StatusUnauthorized, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Create a new JWT token with the claims - token := jwt.NewWithClaims(jwt.SigningMethodHS256, tt.tokenClaims) - tokenString, err := token.SignedString([]byte("secret")) - require.NoError(t, err) - - app := fiber.New() - app.Get("/:tokenId", injectToken(token), auth.AllOf(contract, tokenIDParam, privilegeIDs), - func(c *fiber.Ctx) error { - return c.SendString("Success") - }) - - req := httptest.NewRequest("GET", "/"+tt.tokenID, nil) - req.Header.Set("Authorization", "Bearer "+tokenString) - - resp, err := app.Test(req, 1) // 1 means no timeout - require.NoError(t, err) - - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) - require.Equalf(t, tt.expectedCode, resp.StatusCode, "body: %s", string(body)) - - if tt.expectedCode != fiber.StatusOK { - return - } - - require.Equal(t, "Success", string(body)) - }) - } -} - -func injectToken(token *jwt.Token) fiber.Handler { - return func(c *fiber.Ctx) error { - c.Locals("user", token) - return c.Next() - } -} diff --git a/pkg/grpc/cloudevent.pb.go b/pkg/grpc/cloudevent.pb.go index 95a72c7..d8ce0c9 100644 --- a/pkg/grpc/cloudevent.pb.go +++ b/pkg/grpc/cloudevent.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc v5.28.3 // source: pkg/grpc/cloudevent.proto @@ -110,7 +110,9 @@ type CloudEventHeader struct { // Extras contains any additional fields that are not part of the CloudEvent excluding the data field. Extras map[string][]byte `protobuf:"bytes,11,rep,name=extras,proto3" json:"extras,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Tags are a list of tags that can be used to filter the events. - Tags []string `protobuf:"bytes,12,rep,name=tags,proto3" json:"tags,omitempty"` + Tags []string `protobuf:"bytes,12,rep,name=tags,proto3" json:"tags,omitempty"` + // Signature hold the signature of the a cloudevent's data field. + Signature string `protobuf:"bytes,13,opt,name=signature,proto3" json:"signature,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -229,6 +231,13 @@ func (x *CloudEventHeader) GetTags() []string { return nil } +func (x *CloudEventHeader) GetSignature() string { + if x != nil { + return x.Signature + } + return "" +} + var File_pkg_grpc_cloudevent_proto protoreflect.FileDescriptor const file_pkg_grpc_cloudevent_proto_rawDesc = "" + @@ -238,7 +247,7 @@ const file_pkg_grpc_cloudevent_proto_rawDesc = "" + "\n" + "CloudEvent\x124\n" + "\x06header\x18\x01 \x01(\v2\x1c.cloudevent.CloudEventHeaderR\x06header\x12\x12\n" + - "\x04data\x18\x02 \x01(\fR\x04data\"\xd8\x03\n" + + "\x04data\x18\x02 \x01(\fR\x04data\"\xf6\x03\n" + "\x10CloudEventHeader\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x16\n" + "\x06source\x18\x02 \x01(\tR\x06source\x12\x1a\n" + @@ -253,7 +262,8 @@ const file_pkg_grpc_cloudevent_proto_rawDesc = "" + "\fdata_version\x18\n" + " \x01(\tR\vdataVersion\x12@\n" + "\x06extras\x18\v \x03(\v2(.cloudevent.CloudEventHeader.ExtrasEntryR\x06extras\x12\x12\n" + - "\x04tags\x18\f \x03(\tR\x04tags\x1a9\n" + + "\x04tags\x18\f \x03(\tR\x04tags\x12\x1c\n" + + "\tsignature\x18\r \x01(\tR\tsignature\x1a9\n" + "\vExtrasEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\fR\x05value:\x028\x01B,Z*github.com/DIMO-Network/fetch-api/pkg/grpcb\x06proto3" diff --git a/pkg/grpc/cloudevent.proto b/pkg/grpc/cloudevent.proto index 1733d57..c1a96b9 100644 --- a/pkg/grpc/cloudevent.proto +++ b/pkg/grpc/cloudevent.proto @@ -58,5 +58,8 @@ message CloudEventHeader { // Tags are a list of tags that can be used to filter the events. repeated string tags = 12; + + // Signature hold the signature of the a cloudevent's data field. + string signature = 13; } diff --git a/pkg/grpc/common.go b/pkg/grpc/common.go index be851a7..181a0e3 100644 --- a/pkg/grpc/common.go +++ b/pkg/grpc/common.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/DIMO-Network/cloudevent" + "google.golang.org/protobuf/types/known/timestamppb" ) // AsCloudEvent converts the CloudEvent to a cloudevent.CloudEvent[json.RawMessage]. @@ -39,5 +40,46 @@ func (c *CloudEventHeader) AsCloudEventHeader() cloudevent.CloudEventHeader { DataSchema: c.GetDataSchema(), DataVersion: c.GetDataVersion(), Extras: extras, + Signature: c.GetSignature(), + Tags: c.GetTags(), + } +} + +// CloudEventHeaderToProto converts a cloudevent.CloudEventHeader to a grpc.CloudEventHeader. +func CloudEventHeaderToProto(event *cloudevent.CloudEventHeader) *CloudEventHeader { + if event == nil { + return nil + } + extras := make(map[string][]byte) + for k, v := range event.Extras { + v, err := json.Marshal(v) + if err != nil { + // Skip the extra if it can't be marshaled + continue + } + extras[k] = v + } + return &CloudEventHeader{ + Id: event.ID, + Source: event.Source, + Producer: event.Producer, + Subject: event.Subject, + SpecVersion: event.SpecVersion, + Time: timestamppb.New(event.Time), + Type: event.Type, + DataContentType: event.DataContentType, + DataSchema: event.DataSchema, + DataVersion: event.DataVersion, + Extras: extras, + Signature: event.Signature, + Tags: event.Tags, + } +} + +// CloudEventToProto converts a cloudevent.CloudEvent[json.RawMessage] to a grpc.CloudEvent. +func CloudEventToProto(event cloudevent.CloudEvent[json.RawMessage]) *CloudEvent { + return &CloudEvent{ + Header: CloudEventHeaderToProto(&event.CloudEventHeader), + Data: event.Data, } } diff --git a/pkg/grpc/common_test.go b/pkg/grpc/common_test.go new file mode 100644 index 0000000..ad51a72 --- /dev/null +++ b/pkg/grpc/common_test.go @@ -0,0 +1,170 @@ +package grpc + +import ( + "encoding/json" + "math/rand" + "reflect" + "testing" + "time" + + "github.com/DIMO-Network/cloudevent" + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" +) + +const ( + maxRandomHours = 1000 + randStringMin = 5 + randStringRange = 10 + maxMapEntries = 3 + maxExtraParts = 1000 +) + +// TestCloudEventProtoRoundTrip tests that a CloudEvent can be converted to Proto and back without losing data. +// This test uses reflection to fill all fields with random data, ensuring it works regardless of structure changes. +func TestCloudEventProtoRoundTrip(t *testing.T) { + t.Parallel() + + // Create a random CloudEvent by filling all fields with random data + originalEvent := cloudevent.CloudEvent[json.RawMessage]{ + CloudEventHeader: fillRandomCloudEventHeader(t), + Data: json.RawMessage(`{"random": "test data"}`), + } + + // Convert CloudEvent to Proto + protoEvent := CloudEventToProto(originalEvent) + + // Verify Proto was created + require.NotNil(t, protoEvent) + require.NotNil(t, protoEvent.GetHeader()) + + // Convert back from Proto to CloudEvent + convertedEvent := protoEvent.AsCloudEvent() + + // Verify the data is preserved through round-trip conversion using deep equals + require.Empty(t, cmp.Diff(originalEvent.CloudEventHeader, convertedEvent.CloudEventHeader)) + require.Equal(t, originalEvent.Data, convertedEvent.Data) +} + +// TestCloudEventHeaderProtoRoundTrip tests that a CloudEventHeader can be converted to Proto and back without losing data. +func TestCloudEventHeaderProtoRoundTrip(t *testing.T) { + t.Parallel() + + // Create a random header by filling all fields with random data + originalHeader := fillRandomCloudEventHeader(t) + + // Convert to Proto + protoHeader := CloudEventHeaderToProto(&originalHeader) + + // Verify Proto was created + require.NotNil(t, protoHeader) + + // Convert back from Proto + convertedHeader := protoHeader.AsCloudEventHeader() + + // Verify all fields are preserved through round-trip conversion using deep equals + require.Empty(t, cmp.Diff(originalHeader, convertedHeader)) +} + +// TestCloudEventProtoWithNilHeader tests that nil headers are handled correctly. +func TestCloudEventProtoWithNilHeader(t *testing.T) { + t.Parallel() + + originalEvent := cloudevent.CloudEvent[json.RawMessage]{ + CloudEventHeader: cloudevent.CloudEventHeader{}, + Data: json.RawMessage(`{"test": "data"}`), + } + + protoEvent := CloudEventToProto(originalEvent) + require.NotNil(t, protoEvent) + + convertedEvent := protoEvent.AsCloudEvent() + require.Equal(t, originalEvent.Data, convertedEvent.Data) +} + +// TestCloudEventHeaderProtoNil tests that CloudEventHeaderToProto handles nil input. +func TestCloudEventHeaderProtoNil(t *testing.T) { + t.Parallel() + + protoHeader := CloudEventHeaderToProto(nil) + require.Nil(t, protoHeader) +} + +// fillRandomCloudEventHeader fills all fields of CloudEventHeader with random data using reflection. +// It panics if it encounters a type it doesn't know how to handle. +// +//nolint:gocognit,revive,cyclop +func fillRandomCloudEventHeader(t *testing.T) cloudevent.CloudEventHeader { + t.Helper() + + header := cloudevent.CloudEventHeader{} + headerVal := reflect.ValueOf(&header).Elem() + + for i := range headerVal.NumField() { + field := headerVal.Field(i) + if !field.CanSet() { + continue + } + + switch field.Type().Kind() { + case reflect.String: + field.SetString(randomString()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + field.SetInt(int64(rand.Intn(maxExtraParts))) + case reflect.Float32, reflect.Float64: + field.SetFloat(rand.Float64()) + case reflect.Bool: + field.SetBool(rand.Intn(2) == 0) + case reflect.Slice: + if field.Type().Elem().Kind() == reflect.String { + // String slice + slice := make([]string, rand.Intn(maxMapEntries)+1) + for j := range slice { + slice[j] = randomString() + } + field.Set(reflect.ValueOf(slice)) + } else { + panic("unsupported slice type: " + field.Type().String()) + } + case reflect.Struct: + // Handle time.Time - truncate to second precision (what protobuf preserves) + if field.Type() == reflect.TypeOf(time.Time{}) { + t := time.Now().Add(time.Duration(rand.Intn(maxRandomHours)) * time.Hour).Truncate(time.Second) + field.Set(reflect.ValueOf(t)) + } else { + panic("unsupported struct type: " + field.Type().String()) + } + case reflect.Map: + // Handle map[string]any + if field.Type() == reflect.TypeOf(map[string]any{}) { + extrasMap := make(map[string]any) + for j := rand.Intn(maxMapEntries) + 1; j > 0; j-- { + switch rand.Intn(2) { + case 0: + extrasMap[randomString()] = randomString() + case 1: + extrasMap[randomString()] = rand.Float64() + } + } + field.Set(reflect.ValueOf(extrasMap)) + } else { + panic("unsupported map type: " + field.Type().String()) + } + default: + panic("unsupported field type: " + field.Type().String()) + } + } + + return header +} + +// randomString generates a random string. +func randomString() string { + length := rand.Intn(randStringRange) + randStringMin + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + b := make([]byte, length) + for i := range b { + b[i] = charset[rand.Intn(len(charset))] + } + return string(b) +} diff --git a/pkg/grpc/fetch-api.pb.go b/pkg/grpc/fetch-api.pb.go index e4541ce..ea634d9 100644 --- a/pkg/grpc/fetch-api.pb.go +++ b/pkg/grpc/fetch-api.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.8 +// protoc-gen-go v1.36.10 // protoc v5.28.3 // source: pkg/grpc/fetch-api.proto