diff --git a/Makefile b/Makefile index 6b742435..c67a7c7c 100644 --- a/Makefile +++ b/Makefile @@ -108,6 +108,7 @@ help: @echo " make qa : Run all tests and static analysis tools" @echo " make tag : Tag the Git repository" @echo " make test : Run unit tests" + @echo " make version : Update this library version in the examples" @echo "" @echo "Use DEVMODE=LOCAL for human friendly output." @echo "" @@ -123,7 +124,7 @@ all: help # Alias to test and build everything from scratch .PHONY: x x: - DEVMODE=LOCAL $(MAKE) format clean mod deps generate qa example + DEVMODE=LOCAL $(MAKE) version format clean mod deps generate qa example # Remove any build artifact .PHONY: clean @@ -246,3 +247,8 @@ test: ensuretarget -coverprofile=$(TARGETDIR)/report/coverage.out \ -v $(GOPKGS) $(TESTEXTRACMD) @echo -e "\n\n>>> END: Unit Tests <<<\n\n" + +# Set the gosrvlib version in the example go.mod +.PHONY: version +version: + sed -i "s|github.com/Vonage/gosrvlib v.*$$|github.com/Vonage/gosrvlib v$(VERSION)|" examples/service/go.mod diff --git a/VERSION b/VERSION index 8d394742..7f229af9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.1 +1.92.0 diff --git a/examples/service/go.mod b/examples/service/go.mod index c74f24d5..ea25079b 100644 --- a/examples/service/go.mod +++ b/examples/service/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.4 replace github.com/Vonage/gosrvlib => ../.. require ( - github.com/Vonage/gosrvlib v1.91.1 + github.com/Vonage/gosrvlib v1.92.0 github.com/golang/mock v1.6.0 github.com/jstemmer/go-junit-report/v2 v2.1.0 github.com/prometheus/client_golang v1.19.1 @@ -20,11 +20,11 @@ require ( require ( cloud.google.com/go v0.115.0 // indirect - cloud.google.com/go/auth v0.5.1 // indirect + cloud.google.com/go/auth v0.6.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/firestore v1.15.0 // indirect - cloud.google.com/go/longrunning v0.5.7 // indirect + cloud.google.com/go/longrunning v0.5.8 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -69,6 +69,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nats.go v1.36.0 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect @@ -76,7 +77,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.54.0 // indirect + github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/sagikazarmark/crypt v0.21.0 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect @@ -107,10 +108,10 @@ require ( golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.22.0 // indirect - google.golang.org/api v0.185.0 // indirect - google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect + google.golang.org/api v0.186.0 // indirect + google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/examples/service/go.sum b/examples/service/go.sum index c119a640..f799a4ee 100644 --- a/examples/service/go.sum +++ b/examples/service/go.sum @@ -25,8 +25,8 @@ cloud.google.com/go/asset v1.19.1 h1:mCqyoaDjDzaW1RqmmQtCJuawb9nca5bEu7HvVcpZDwg cloud.google.com/go/asset v1.19.1/go.mod h1:kGOS8DiCXv6wU/JWmHWCgaErtSZ6uN5noCy0YwVaGfs= cloud.google.com/go/assuredworkloads v1.11.7 h1:xieyFA+JKyTDkO/Z9UyVEpkHW8pDYykU51O4G0pvXEg= cloud.google.com/go/assuredworkloads v1.11.7/go.mod h1:CqXcRH9N0KCDtHhFisv7kk+cl//lyV+pYXGi1h8rCEU= -cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= -cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= +cloud.google.com/go/auth v0.6.0 h1:5x+d6b5zdezZ7gmLWD1m/xNjnaQ2YDhmIz/HH3doy1g= +cloud.google.com/go/auth v0.6.0/go.mod h1:b4acV+jLQDyjwm4OXHYjNvRi4jvGBzHWJRtJcy+2P4g= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.13.7 h1:w9AyogtMLXbcy5kzXPvk/Q3MGQkgJH7ZDB8fAUUxTt8= @@ -73,8 +73,8 @@ cloud.google.com/go/datafusion v1.7.7 h1:ViFnMnUK7LNcWvisZgihxXit76JxSHFeijYI5U/ cloud.google.com/go/datafusion v1.7.7/go.mod h1:qGTtQcUs8l51lFA9ywuxmZJhS4ozxsBSus6ItqCUWMU= cloud.google.com/go/datalabeling v0.8.7 h1:M6irSHns6VxMro+IbvDxDJLD6tkfjlW+mo2MPaM23KA= cloud.google.com/go/datalabeling v0.8.7/go.mod h1:/PPncW5gxrU15UzJEGQoOT3IobeudHGvoExrtZ8ZBwo= -cloud.google.com/go/dataplex v1.16.0 h1:e8SV0yKuSjgHEZaQcZwjKXe0ta1jZrvLxX/2i/IAG+8= -cloud.google.com/go/dataplex v1.16.0/go.mod h1:OlBoytuQ56+7aUCC03D34CtoF/4TJ5SiIrLsBdDu87Q= +cloud.google.com/go/dataplex v1.16.1 h1:vuDBDNOBl75GFLUnFXG/Y10lUtVUx/58vbO+yRQmW+I= +cloud.google.com/go/dataplex v1.16.1/go.mod h1:szV2OpxfbmRBcw1cYq2ln8QsLR3FJq+EwTTIo+0FnyE= cloud.google.com/go/dataproc/v2 v2.4.2 h1:RNMG5ffWKdbWOkwvjC4GqxLaxEaWFpm2hQCF2WFW/vo= cloud.google.com/go/dataproc/v2 v2.4.2/go.mod h1:smGSj1LZP3wtnsM9eyRuDYftNAroAl6gvKp/Wk64XDE= cloud.google.com/go/dataqna v0.8.7 h1:qM60MGNTGsSJuzAziVJjtRA7pGby2dA8OuqdVRe/lYo= @@ -89,8 +89,8 @@ cloud.google.com/go/dialogflow v1.54.0 h1:DgCHYpasCaI3b03X6pxqGmEzX72DAHZhV0f/or cloud.google.com/go/dialogflow v1.54.0/go.mod h1:/YQLqB0bdDJl+zFKN+UNQsYUqLfWZb1HsJUQqMT7Q6k= cloud.google.com/go/dlp v1.14.0 h1:/GQVl5gOPR2dUemrR2YJxZG5D9MCE3AYgmDxjzP54jI= cloud.google.com/go/dlp v1.14.0/go.mod h1:4fvEu3EbLsHrgH3QFdFlTNIiCP5mHwdYhS/8KChDIC4= -cloud.google.com/go/documentai v1.30.0 h1:6KI6P04WExzrfbciW5RTEQScBEY98Fc4VtS04ufT3Js= -cloud.google.com/go/documentai v1.30.0/go.mod h1:3Qt8PMt3S8W6w3VeoYFraaMS2GJRrXFnvkyn+GpB1n0= +cloud.google.com/go/documentai v1.30.1 h1:501VbUcVCg1LaWIsnmNdTsrEsQNTPD086aqejBvvOCc= +cloud.google.com/go/documentai v1.30.1/go.mod h1:RohRpAfvuv3uk3WQtXPpgQ3YABvzacWnasyJQb6AAPk= cloud.google.com/go/domains v0.9.7 h1:IixFIMRzUJWZUAOe8s/K2X4Bvtp0A3xjHLljfNC4aSo= cloud.google.com/go/domains v0.9.7/go.mod h1:u/yVf3BgfPJW3QDZl51qTJcDXo9PLqnEIxfGmGgbHEc= cloud.google.com/go/edgecontainer v1.2.1 h1:xa6MIQhGylE24QdWaxhfIfAJE3Pupcr+i77WEx3NJrg= @@ -125,16 +125,16 @@ cloud.google.com/go/ids v1.4.7 h1:wtd+r415yrfZ8LsB6yH6WrOZ26tYt7w6wy3i5a4HQZ8= cloud.google.com/go/ids v1.4.7/go.mod h1:yUkDC71u73lJoTaoONy0dsA0T7foekvg6ZRg9IJL0AA= cloud.google.com/go/iot v1.7.7 h1:M9SKIj9eoxoXCzytkLZVAuf5wmoui1OeDqEjC97wRbY= cloud.google.com/go/iot v1.7.7/go.mod h1:tr0bCOSPXtsg64TwwZ/1x+ReTWKlQRVXbM+DnrE54yM= -cloud.google.com/go/kms v1.17.1 h1:5k0wXqkxL+YcXd4viQzTqCgzzVKKxzgrK+rCZJytEQs= -cloud.google.com/go/kms v1.17.1/go.mod h1:DCMnCF/apA6fZk5Cj4XsD979OyHAqFasPuA5Sd0kGlQ= +cloud.google.com/go/kms v1.18.0 h1:pqNdaVmZJFP+i8OVLocjfpdTWETTYa20FWOegSCdrRo= +cloud.google.com/go/kms v1.18.0/go.mod h1:DyRBeWD/pYBMeyiaXFa/DGNyxMDL3TslIKb8o/JkLkw= cloud.google.com/go/language v1.12.5 h1:kOYJEcuZgyUX/i/4DFrfXPcrddm1XCQD2lDI5hIFmZQ= cloud.google.com/go/language v1.12.5/go.mod h1:w/6a7+Rhg6Bc2Uzw6thRdKKNjnOzfKTJuxzD0JZZ0nM= cloud.google.com/go/lifesciences v0.9.7 h1:qqEmApr5YFOQjkrU8Jy6o6QpkESqfGbfrE6bnUZZbV8= cloud.google.com/go/lifesciences v0.9.7/go.mod h1:FQ713PhjAOHqUVnuwsCe1KPi9oAdaTfh58h1xPiW13g= cloud.google.com/go/logging v1.10.0 h1:f+ZXMqyrSJ5vZ5pE/zr0xC8y/M9BLNzQeLBwfeZ+wY4= cloud.google.com/go/logging v1.10.0/go.mod h1:EHOwcxlltJrYGqMGfghSet736KR3hX1MAj614mrMk9I= -cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= -cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= +cloud.google.com/go/longrunning v0.5.8 h1:QThI5BFSlYlS7K0wnABCdmKsXbG/htLc3nTPzrfOgeU= +cloud.google.com/go/longrunning v0.5.8/go.mod h1:oJDErR/mm5h44gzsfjQlxd6jyjFvuBPOxR1TLy2+cQk= cloud.google.com/go/managedidentities v1.6.7 h1:uWA9WQyfA0JdkeAFymWUsa3qE9tC33LUElla790Ou1A= cloud.google.com/go/managedidentities v1.6.7/go.mod h1:UzslJgHnc6luoyx2JV19cTCi2Fni/7UtlcLeSYRzTV8= cloud.google.com/go/maps v1.11.1 h1:2U1NB/GIoXhNNmYMlGiLM7juL7nxh51lSkNELbYddB8= @@ -171,8 +171,8 @@ cloud.google.com/go/policytroubleshooter v1.10.5 h1:LGt85MZUKlq9oqsbBL9+M6jAyeuR cloud.google.com/go/policytroubleshooter v1.10.5/go.mod h1:bpOf94YxjWUqsVKokzPBibMSAx937Jp2UNGVoMAtGYI= cloud.google.com/go/privatecatalog v0.9.7 h1:wGZKKJhYyuf4gcAEywQqQ6F19yxhBJGnzgyxOTbJjBw= cloud.google.com/go/privatecatalog v0.9.7/go.mod h1:NWLa8MCL6NkRSt8jhL8Goy2A/oHkvkeAxiA0gv0rIXI= -cloud.google.com/go/pubsub v1.38.0 h1:J1OT7h51ifATIedjqk/uBNPh+1hkvUaH4VKbz4UuAsc= -cloud.google.com/go/pubsub v1.38.0/go.mod h1:IPMJSWSus/cu57UyR01Jqa/bNOQA+XnPF6Z4dKW4fAA= +cloud.google.com/go/pubsub v1.39.0 h1:qt1+S6H+wwW8Q/YvDwM8lJnq+iIFgFEgaD/7h3lMsAI= +cloud.google.com/go/pubsub v1.39.0/go.mod h1:FrEnrSGU6L0Kh3iBaAbIUM8KMR7LqyEkMboVxGXCT+s= cloud.google.com/go/pubsublite v1.8.2 h1:jLQozsEVr+c6tOU13vDugtnaBSUy/PD5zK6mhm+uF1Y= cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0 h1:+QG02kE63W13vXI+rwAxFF3EhGX6K7gXwFz9OKwKcHw= @@ -254,6 +254,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/aperturerobotics/go-brotli-decoder v0.1.1 h1:4+gAyIhICgHgF59q1G8OHRRYzmNkk3u6philYbobUNY= +github.com/aperturerobotics/go-brotli-decoder v0.1.1/go.mod h1:uGcRHycd7rIbt9Uh+6L5UXgWmRTUIE2MA1m0QKrBBQY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -266,10 +268,10 @@ github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6 github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= -github.com/aws/aws-sdk-go-v2/config v1.27.21 h1:yPX3pjGCe2hJsetlmGNB4Mngu7UPmvWPzzWCv1+boeM= -github.com/aws/aws-sdk-go-v2/config v1.27.21/go.mod h1:4XtlEU6DzNai8RMbjSF5MgGZtYvrhBP/aKZcRtZAVdM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.21 h1:pjAqgzfgFhTv5grc7xPHtXCAaMapzmwA7aU+c/SZQGw= -github.com/aws/aws-sdk-go-v2/credentials v1.17.21/go.mod h1:nhK6PtBlfHTUDVmBLr1dg+WHCOCK+1Fu/WQyVHPsgNQ= +github.com/aws/aws-sdk-go-v2/config v1.27.22 h1:TRkQVtpDINt+Na/ToU7iptyW6U0awAwJ24q4XN+59k8= +github.com/aws/aws-sdk-go-v2/config v1.27.22/go.mod h1:EYY3mVgFRUWkh6QNKH64MdyKs1YSUgatc0Zp3MDxi7c= +github.com/aws/aws-sdk-go-v2/credentials v1.17.22 h1:wu9kXQbbt64ul09v3ye4HYleAr4WiGV/uv69EXKDEr0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.22/go.mod h1:pcvMtPcxJn3r2k6mZD9I0EcumLqPLA7V/0iCgOIlY+o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw= @@ -288,18 +290,18 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 h1:zSDPny/p github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14/go.mod h1:3TTcI5JSzda1nw/pkVC9dhgLre0SNBFj2lYS4GctXKI= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12 h1:tzha+v1SCEBpXWEuw6B/+jm4h5z8hZbTpXz0zRZqTnw= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12/go.mod h1:n+nt2qjHGoseWeLHt1vEr6ZRCCxIN2KcNpJxBcYQSwI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1 h1:wsg9Z/vNnCmxWikfGIoOlnExtEU459cR+2d+iDJ8elo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw= -github.com/aws/aws-sdk-go-v2/service/sqs v1.33.1 h1:m/7a5OgAZQDWJlSbZLWg4BAlbXbY6j+dDDjPY8rZ7kA= -github.com/aws/aws-sdk-go-v2/service/sqs v1.33.1/go.mod h1:4kCM5tMCkys9PFbuGHP+LjpxlsA5oMRUs3QvnWo11BM= -github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 h1:sd0BsnAvLH8gsp2e3cbaIr+9D7T1xugueQ7V/zUAsS4= -github.com/aws/aws-sdk-go-v2/service/sso v1.21.1/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 h1:1uEFNNskK/I1KoZ9Q8wJxMz5V9jyBlsiaNrM7vA3YUQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4= -github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 h1:myX5CxqXE0QMZNja6FA1/FSE3Vu1rVmeUmpJMMzeZg0= -github.com/aws/aws-sdk-go-v2/service/sts v1.29.1/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE= -github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= -github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0 h1:v2DWNY6ll3JK62Bx1khUu9fJ4f3TwXllIEJxI7dDv/o= +github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw= +github.com/aws/aws-sdk-go-v2/service/sqs v1.34.0 h1:YWyd8KPykQE9YS7M+RTAlVyOmUxXiesIC2WtMMSEnX4= +github.com/aws/aws-sdk-go-v2/service/sqs v1.34.0/go.mod h1:4kCM5tMCkys9PFbuGHP+LjpxlsA5oMRUs3QvnWo11BM= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.0 h1:lPIAPCRoJkmotLTU/9B6icUFlYDpEuWjKeL79XROv1M= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.0/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0 h1:/4r71ghx+hX9spr884cqXHPEmPzqH/J3K7fkE1yfcmw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.0 h1:9ja34PaKybhCJjVKvxtDsUjbATUJGN+eF6QnO58u5cI= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.0/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE= +github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= +github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= 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= @@ -574,6 +576,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -618,8 +622,8 @@ github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQy github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= -github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -828,8 +832,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.185.0 h1:ENEKk1k4jW8SmmaT6RE+ZasxmxezCrD5Vw4npvr+pAU= -google.golang.org/api v0.185.0/go.mod h1:HNfvIkJGlgrIlrbYkAm9W9IdkmKZjOTVh33YltygGbg= +google.golang.org/api v0.186.0 h1:n2OPp+PPXX0Axh4GuSsL5QL8xQCTb2oDwyzPnQvqUug= +google.golang.org/api v0.186.0/go.mod h1:hvRbBmgoje49RV3xqVXrmP6w93n6ehGgIVPYrGtBFFc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -837,14 +841,14 @@ google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 h1:CUiCqkPw1nNrNQzCCG4WA65m0nAmQiwXHpub3dNyruU= -google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4/go.mod h1:EvuUDCulqGgV80RvP1BHuom+smhX4qtlhnNatHuroGQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d h1:PksQg4dV6Sem3/HkBX+Ltq8T0ke0PKIRBNBatoDTVls= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240617180043-68d350f18fd4 h1:Rie8vnNXn/RjOgFacUrolQKaHsN10UPAXBb3IkfDdE4= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240617180043-68d350f18fd4/go.mod h1:/oe3+SiHAwz6s+M25PyTygWm3lnrhmGqIuIfkoUocqk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= diff --git a/go.mod b/go.mod index 8c3b12c3..a30e2b54 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,12 @@ toolchain go1.22.4 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 + github.com/aperturerobotics/go-brotli-decoder v0.1.1 github.com/aws/aws-sdk-go-v2 v1.30.0 - github.com/aws/aws-sdk-go-v2/config v1.27.21 - github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1 - github.com/aws/aws-sdk-go-v2/service/sqs v1.33.1 - github.com/aws/smithy-go v1.20.2 + github.com/aws/aws-sdk-go-v2/config v1.27.22 + github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0 + github.com/aws/aws-sdk-go-v2/service/sqs v1.34.0 + github.com/aws/smithy-go v1.20.3 github.com/confluentinc/confluent-kafka-go v1.9.2 github.com/dlmiddlecote/sqlstats v1.0.2 github.com/go-playground/validator/v10 v10.22.0 @@ -38,14 +39,14 @@ require ( require ( cloud.google.com/go v0.115.0 // indirect - cloud.google.com/go/auth v0.5.1 // indirect + cloud.google.com/go/auth v0.6.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/firestore v1.15.0 // indirect - cloud.google.com/go/longrunning v0.5.7 // indirect + cloud.google.com/go/longrunning v0.5.8 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.21 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.22 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.12 // indirect @@ -55,9 +56,9 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.14 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect @@ -97,6 +98,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nats-io/nats.go v1.36.0 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect @@ -105,7 +107,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.54.0 // indirect + github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/sagikazarmark/crypt v0.21.0 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect @@ -131,10 +133,10 @@ require ( golang.org/x/sys v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.22.0 // indirect - google.golang.org/api v0.185.0 // indirect - google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect + google.golang.org/api v0.186.0 // indirect + google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 76b216fb..38bd7baf 100644 --- a/go.sum +++ b/go.sum @@ -26,8 +26,8 @@ cloud.google.com/go/asset v1.19.1 h1:mCqyoaDjDzaW1RqmmQtCJuawb9nca5bEu7HvVcpZDwg cloud.google.com/go/asset v1.19.1/go.mod h1:kGOS8DiCXv6wU/JWmHWCgaErtSZ6uN5noCy0YwVaGfs= cloud.google.com/go/assuredworkloads v1.11.7 h1:xieyFA+JKyTDkO/Z9UyVEpkHW8pDYykU51O4G0pvXEg= cloud.google.com/go/assuredworkloads v1.11.7/go.mod h1:CqXcRH9N0KCDtHhFisv7kk+cl//lyV+pYXGi1h8rCEU= -cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= -cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= +cloud.google.com/go/auth v0.6.0 h1:5x+d6b5zdezZ7gmLWD1m/xNjnaQ2YDhmIz/HH3doy1g= +cloud.google.com/go/auth v0.6.0/go.mod h1:b4acV+jLQDyjwm4OXHYjNvRi4jvGBzHWJRtJcy+2P4g= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.13.7 h1:w9AyogtMLXbcy5kzXPvk/Q3MGQkgJH7ZDB8fAUUxTt8= @@ -74,8 +74,8 @@ cloud.google.com/go/datafusion v1.7.7 h1:ViFnMnUK7LNcWvisZgihxXit76JxSHFeijYI5U/ cloud.google.com/go/datafusion v1.7.7/go.mod h1:qGTtQcUs8l51lFA9ywuxmZJhS4ozxsBSus6ItqCUWMU= cloud.google.com/go/datalabeling v0.8.7 h1:M6irSHns6VxMro+IbvDxDJLD6tkfjlW+mo2MPaM23KA= cloud.google.com/go/datalabeling v0.8.7/go.mod h1:/PPncW5gxrU15UzJEGQoOT3IobeudHGvoExrtZ8ZBwo= -cloud.google.com/go/dataplex v1.16.0 h1:e8SV0yKuSjgHEZaQcZwjKXe0ta1jZrvLxX/2i/IAG+8= -cloud.google.com/go/dataplex v1.16.0/go.mod h1:OlBoytuQ56+7aUCC03D34CtoF/4TJ5SiIrLsBdDu87Q= +cloud.google.com/go/dataplex v1.16.1 h1:vuDBDNOBl75GFLUnFXG/Y10lUtVUx/58vbO+yRQmW+I= +cloud.google.com/go/dataplex v1.16.1/go.mod h1:szV2OpxfbmRBcw1cYq2ln8QsLR3FJq+EwTTIo+0FnyE= cloud.google.com/go/dataproc/v2 v2.4.2 h1:RNMG5ffWKdbWOkwvjC4GqxLaxEaWFpm2hQCF2WFW/vo= cloud.google.com/go/dataproc/v2 v2.4.2/go.mod h1:smGSj1LZP3wtnsM9eyRuDYftNAroAl6gvKp/Wk64XDE= cloud.google.com/go/dataqna v0.8.7 h1:qM60MGNTGsSJuzAziVJjtRA7pGby2dA8OuqdVRe/lYo= @@ -90,8 +90,8 @@ cloud.google.com/go/dialogflow v1.54.0 h1:DgCHYpasCaI3b03X6pxqGmEzX72DAHZhV0f/or cloud.google.com/go/dialogflow v1.54.0/go.mod h1:/YQLqB0bdDJl+zFKN+UNQsYUqLfWZb1HsJUQqMT7Q6k= cloud.google.com/go/dlp v1.14.0 h1:/GQVl5gOPR2dUemrR2YJxZG5D9MCE3AYgmDxjzP54jI= cloud.google.com/go/dlp v1.14.0/go.mod h1:4fvEu3EbLsHrgH3QFdFlTNIiCP5mHwdYhS/8KChDIC4= -cloud.google.com/go/documentai v1.30.0 h1:6KI6P04WExzrfbciW5RTEQScBEY98Fc4VtS04ufT3Js= -cloud.google.com/go/documentai v1.30.0/go.mod h1:3Qt8PMt3S8W6w3VeoYFraaMS2GJRrXFnvkyn+GpB1n0= +cloud.google.com/go/documentai v1.30.1 h1:501VbUcVCg1LaWIsnmNdTsrEsQNTPD086aqejBvvOCc= +cloud.google.com/go/documentai v1.30.1/go.mod h1:RohRpAfvuv3uk3WQtXPpgQ3YABvzacWnasyJQb6AAPk= cloud.google.com/go/domains v0.9.7 h1:IixFIMRzUJWZUAOe8s/K2X4Bvtp0A3xjHLljfNC4aSo= cloud.google.com/go/domains v0.9.7/go.mod h1:u/yVf3BgfPJW3QDZl51qTJcDXo9PLqnEIxfGmGgbHEc= cloud.google.com/go/edgecontainer v1.2.1 h1:xa6MIQhGylE24QdWaxhfIfAJE3Pupcr+i77WEx3NJrg= @@ -126,16 +126,16 @@ cloud.google.com/go/ids v1.4.7 h1:wtd+r415yrfZ8LsB6yH6WrOZ26tYt7w6wy3i5a4HQZ8= cloud.google.com/go/ids v1.4.7/go.mod h1:yUkDC71u73lJoTaoONy0dsA0T7foekvg6ZRg9IJL0AA= cloud.google.com/go/iot v1.7.7 h1:M9SKIj9eoxoXCzytkLZVAuf5wmoui1OeDqEjC97wRbY= cloud.google.com/go/iot v1.7.7/go.mod h1:tr0bCOSPXtsg64TwwZ/1x+ReTWKlQRVXbM+DnrE54yM= -cloud.google.com/go/kms v1.17.1 h1:5k0wXqkxL+YcXd4viQzTqCgzzVKKxzgrK+rCZJytEQs= -cloud.google.com/go/kms v1.17.1/go.mod h1:DCMnCF/apA6fZk5Cj4XsD979OyHAqFasPuA5Sd0kGlQ= +cloud.google.com/go/kms v1.18.0 h1:pqNdaVmZJFP+i8OVLocjfpdTWETTYa20FWOegSCdrRo= +cloud.google.com/go/kms v1.18.0/go.mod h1:DyRBeWD/pYBMeyiaXFa/DGNyxMDL3TslIKb8o/JkLkw= cloud.google.com/go/language v1.12.5 h1:kOYJEcuZgyUX/i/4DFrfXPcrddm1XCQD2lDI5hIFmZQ= cloud.google.com/go/language v1.12.5/go.mod h1:w/6a7+Rhg6Bc2Uzw6thRdKKNjnOzfKTJuxzD0JZZ0nM= cloud.google.com/go/lifesciences v0.9.7 h1:qqEmApr5YFOQjkrU8Jy6o6QpkESqfGbfrE6bnUZZbV8= cloud.google.com/go/lifesciences v0.9.7/go.mod h1:FQ713PhjAOHqUVnuwsCe1KPi9oAdaTfh58h1xPiW13g= cloud.google.com/go/logging v1.10.0 h1:f+ZXMqyrSJ5vZ5pE/zr0xC8y/M9BLNzQeLBwfeZ+wY4= cloud.google.com/go/logging v1.10.0/go.mod h1:EHOwcxlltJrYGqMGfghSet736KR3hX1MAj614mrMk9I= -cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= -cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= +cloud.google.com/go/longrunning v0.5.8 h1:QThI5BFSlYlS7K0wnABCdmKsXbG/htLc3nTPzrfOgeU= +cloud.google.com/go/longrunning v0.5.8/go.mod h1:oJDErR/mm5h44gzsfjQlxd6jyjFvuBPOxR1TLy2+cQk= cloud.google.com/go/managedidentities v1.6.7 h1:uWA9WQyfA0JdkeAFymWUsa3qE9tC33LUElla790Ou1A= cloud.google.com/go/managedidentities v1.6.7/go.mod h1:UzslJgHnc6luoyx2JV19cTCi2Fni/7UtlcLeSYRzTV8= cloud.google.com/go/maps v1.11.1 h1:2U1NB/GIoXhNNmYMlGiLM7juL7nxh51lSkNELbYddB8= @@ -172,8 +172,8 @@ cloud.google.com/go/policytroubleshooter v1.10.5 h1:LGt85MZUKlq9oqsbBL9+M6jAyeuR cloud.google.com/go/policytroubleshooter v1.10.5/go.mod h1:bpOf94YxjWUqsVKokzPBibMSAx937Jp2UNGVoMAtGYI= cloud.google.com/go/privatecatalog v0.9.7 h1:wGZKKJhYyuf4gcAEywQqQ6F19yxhBJGnzgyxOTbJjBw= cloud.google.com/go/privatecatalog v0.9.7/go.mod h1:NWLa8MCL6NkRSt8jhL8Goy2A/oHkvkeAxiA0gv0rIXI= -cloud.google.com/go/pubsub v1.38.0 h1:J1OT7h51ifATIedjqk/uBNPh+1hkvUaH4VKbz4UuAsc= -cloud.google.com/go/pubsub v1.38.0/go.mod h1:IPMJSWSus/cu57UyR01Jqa/bNOQA+XnPF6Z4dKW4fAA= +cloud.google.com/go/pubsub v1.39.0 h1:qt1+S6H+wwW8Q/YvDwM8lJnq+iIFgFEgaD/7h3lMsAI= +cloud.google.com/go/pubsub v1.39.0/go.mod h1:FrEnrSGU6L0Kh3iBaAbIUM8KMR7LqyEkMboVxGXCT+s= cloud.google.com/go/pubsublite v1.8.2 h1:jLQozsEVr+c6tOU13vDugtnaBSUy/PD5zK6mhm+uF1Y= cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0 h1:+QG02kE63W13vXI+rwAxFF3EhGX6K7gXwFz9OKwKcHw= @@ -264,6 +264,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aperturerobotics/go-brotli-decoder v0.1.1 h1:4+gAyIhICgHgF59q1G8OHRRYzmNkk3u6philYbobUNY= +github.com/aperturerobotics/go-brotli-decoder v0.1.1/go.mod h1:uGcRHycd7rIbt9Uh+6L5UXgWmRTUIE2MA1m0QKrBBQY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -276,10 +278,10 @@ github.com/aws/aws-sdk-go-v2 v1.30.0 h1:6qAwtzlfcTtcL8NHtbDQAqgM5s6NDipQTkPxyH/6 github.com/aws/aws-sdk-go-v2 v1.30.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 h1:x6xsQXGSmW6frevwDA+vi/wqhp1ct18mVXYN08/93to= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2/go.mod h1:lPprDr1e6cJdyYeGXnRaJoP4Md+cDBvi2eOj00BlGmg= -github.com/aws/aws-sdk-go-v2/config v1.27.21 h1:yPX3pjGCe2hJsetlmGNB4Mngu7UPmvWPzzWCv1+boeM= -github.com/aws/aws-sdk-go-v2/config v1.27.21/go.mod h1:4XtlEU6DzNai8RMbjSF5MgGZtYvrhBP/aKZcRtZAVdM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.21 h1:pjAqgzfgFhTv5grc7xPHtXCAaMapzmwA7aU+c/SZQGw= -github.com/aws/aws-sdk-go-v2/credentials v1.17.21/go.mod h1:nhK6PtBlfHTUDVmBLr1dg+WHCOCK+1Fu/WQyVHPsgNQ= +github.com/aws/aws-sdk-go-v2/config v1.27.22 h1:TRkQVtpDINt+Na/ToU7iptyW6U0awAwJ24q4XN+59k8= +github.com/aws/aws-sdk-go-v2/config v1.27.22/go.mod h1:EYY3mVgFRUWkh6QNKH64MdyKs1YSUgatc0Zp3MDxi7c= +github.com/aws/aws-sdk-go-v2/credentials v1.17.22 h1:wu9kXQbbt64ul09v3ye4HYleAr4WiGV/uv69EXKDEr0= +github.com/aws/aws-sdk-go-v2/credentials v1.17.22/go.mod h1:pcvMtPcxJn3r2k6mZD9I0EcumLqPLA7V/0iCgOIlY+o= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.12 h1:SJ04WXGTwnHlWIODtC5kJzKbeuHt+OUNOgKg7nfnUGw= @@ -298,18 +300,18 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14 h1:zSDPny/p github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.14/go.mod h1:3TTcI5JSzda1nw/pkVC9dhgLre0SNBFj2lYS4GctXKI= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12 h1:tzha+v1SCEBpXWEuw6B/+jm4h5z8hZbTpXz0zRZqTnw= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.12/go.mod h1:n+nt2qjHGoseWeLHt1vEr6ZRCCxIN2KcNpJxBcYQSwI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1 h1:wsg9Z/vNnCmxWikfGIoOlnExtEU459cR+2d+iDJ8elo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.56.1/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw= -github.com/aws/aws-sdk-go-v2/service/sqs v1.33.1 h1:m/7a5OgAZQDWJlSbZLWg4BAlbXbY6j+dDDjPY8rZ7kA= -github.com/aws/aws-sdk-go-v2/service/sqs v1.33.1/go.mod h1:4kCM5tMCkys9PFbuGHP+LjpxlsA5oMRUs3QvnWo11BM= -github.com/aws/aws-sdk-go-v2/service/sso v1.21.1 h1:sd0BsnAvLH8gsp2e3cbaIr+9D7T1xugueQ7V/zUAsS4= -github.com/aws/aws-sdk-go-v2/service/sso v1.21.1/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1 h1:1uEFNNskK/I1KoZ9Q8wJxMz5V9jyBlsiaNrM7vA3YUQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.25.1/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4= -github.com/aws/aws-sdk-go-v2/service/sts v1.29.1 h1:myX5CxqXE0QMZNja6FA1/FSE3Vu1rVmeUmpJMMzeZg0= -github.com/aws/aws-sdk-go-v2/service/sts v1.29.1/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE= -github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= -github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0 h1:v2DWNY6ll3JK62Bx1khUu9fJ4f3TwXllIEJxI7dDv/o= +github.com/aws/aws-sdk-go-v2/service/s3 v1.57.0/go.mod h1:8rDw3mVwmvIWWX/+LWY3PPIMZuwnQdJMCt0iVFVT3qw= +github.com/aws/aws-sdk-go-v2/service/sqs v1.34.0 h1:YWyd8KPykQE9YS7M+RTAlVyOmUxXiesIC2WtMMSEnX4= +github.com/aws/aws-sdk-go-v2/service/sqs v1.34.0/go.mod h1:4kCM5tMCkys9PFbuGHP+LjpxlsA5oMRUs3QvnWo11BM= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.0 h1:lPIAPCRoJkmotLTU/9B6icUFlYDpEuWjKeL79XROv1M= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.0/go.mod h1:lcQG/MmxydijbeTOp04hIuJwXGWPZGI3bwdFDGRTv14= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0 h1:/4r71ghx+hX9spr884cqXHPEmPzqH/J3K7fkE1yfcmw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.0/go.mod h1:z0P8K+cBIsFXUr5rzo/psUeJ20XjPN0+Nn8067Nd+E4= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.0 h1:9ja34PaKybhCJjVKvxtDsUjbATUJGN+eF6QnO58u5cI= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.0/go.mod h1:N2mQiucsO0VwK9CYuS4/c2n6Smeh1v47Rz3dWCPFLdE= +github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= +github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= 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= @@ -653,6 +655,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -702,8 +706,8 @@ github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQy github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= -github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -964,8 +968,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.185.0 h1:ENEKk1k4jW8SmmaT6RE+ZasxmxezCrD5Vw4npvr+pAU= -google.golang.org/api v0.185.0/go.mod h1:HNfvIkJGlgrIlrbYkAm9W9IdkmKZjOTVh33YltygGbg= +google.golang.org/api v0.186.0 h1:n2OPp+PPXX0Axh4GuSsL5QL8xQCTb2oDwyzPnQvqUug= +google.golang.org/api v0.186.0/go.mod h1:hvRbBmgoje49RV3xqVXrmP6w93n6ehGgIVPYrGtBFFc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -975,14 +979,14 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20220503193339-ba3ae3f07e29/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 h1:CUiCqkPw1nNrNQzCCG4WA65m0nAmQiwXHpub3dNyruU= -google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4/go.mod h1:EvuUDCulqGgV80RvP1BHuom+smhX4qtlhnNatHuroGQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 h1:MuYw1wJzT+ZkybKfaOXKp5hJiZDn2iHaXRw0mRYdHSc= -google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d h1:PksQg4dV6Sem3/HkBX+Ltq8T0ke0PKIRBNBatoDTVls= +google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d h1:Aqf0fiIdUQEj0Gn9mKFFXoQfTTEaNopWpfVyYADxiSg= +google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Od4k8V1LQSizPRUK4OzZ7TBE/20k+jPczUDAEyvn69Y= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240617180043-68d350f18fd4 h1:Rie8vnNXn/RjOgFacUrolQKaHsN10UPAXBb3IkfDdE4= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240617180043-68d350f18fd4/go.mod h1:/oe3+SiHAwz6s+M25PyTygWm3lnrhmGqIuIfkoUocqk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d h1:k3zyW3BYYR30e8v3x0bTDdE9vpYFjZHK+HcyqkrppWk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= diff --git a/pkg/passwordpwned/client.go b/pkg/passwordpwned/client.go new file mode 100644 index 00000000..17ba2386 --- /dev/null +++ b/pkg/passwordpwned/client.go @@ -0,0 +1,81 @@ +package passwordpwned + +import ( + "context" + "crypto/sha1" //nolint:gosec + "fmt" + "hash" + "net/http" + "net/url" + "time" + + "github.com/Vonage/gosrvlib/pkg/httpretrier" +) + +const ( + defaultTimeout = 30 * time.Second + defaultAPIURL = "https://api.pwnedpasswords.com" + rangePath = "range" + defaultUserAgent = "gosrvlib.passwordpwned/1" +) + +// HTTPClient contains the function to perform the actual HTTP request. +type HTTPClient interface { + Do(req *http.Request) (*http.Response, error) +} + +// Client represents the config options required by the Accounts client. +type Client struct { + httpClient HTTPClient + timeout time.Duration + retryDelay time.Duration + retryAttempts uint + hashObj hash.Hash + apiURL string + userAgent string +} + +func defaultClient() *Client { + return &Client{ + timeout: defaultTimeout, + retryAttempts: httpretrier.DefaultAttempts, + retryDelay: httpretrier.DefaultDelay, + hashObj: sha1.New(), //nolint:gosec + apiURL: defaultAPIURL, + userAgent: defaultUserAgent, + } +} + +// New creates a new client instance. +func New(opts ...Option) (*Client, error) { + c := defaultClient() + + for _, applyOpt := range opts { + applyOpt(c) + } + + if c.httpClient == nil { + c.httpClient = &http.Client{Timeout: c.timeout} + } + + _, err := url.Parse(c.apiURL) + if err != nil { + return nil, fmt.Errorf("invalid service address: %s", c.apiURL) + } + + return c, nil +} + +// HealthCheck performs a status check on this service. +func (c *Client) HealthCheck(_ context.Context) error { + return nil +} + +func (c *Client) newHTTPRetrier() (*httpretrier.HTTPRetrier, error) { + //nolint:wrapcheck + return httpretrier.New( + c.httpClient, + httpretrier.WithRetryIfFn(httpretrier.RetryIfForReadRequests), + httpretrier.WithAttempts(c.retryAttempts), + ) +} diff --git a/pkg/passwordpwned/client_test.go b/pkg/passwordpwned/client_test.go new file mode 100644 index 00000000..46a02654 --- /dev/null +++ b/pkg/passwordpwned/client_test.go @@ -0,0 +1,58 @@ +package passwordpwned + +import ( + "testing" + + "github.com/Vonage/gosrvlib/pkg/testutil" + "github.com/stretchr/testify/require" +) + +func TestNew(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + opts []Option + wantErr bool + }{ + { + name: "fails with invalid character in URL", + opts: []Option{WithURL("http://invalid-url.domain.invalid\u007F")}, + wantErr: true, + }, + { + name: "succeeds with defaults", + wantErr: false, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + tt.opts = append(tt.opts, WithRetryAttempts(1)) + c, err := New(tt.opts...) + + if tt.wantErr { + require.Nil(t, c, "New() returned client should be nil") + require.Error(t, err, "New() error = %v, wantErr %v", err, tt.wantErr) + + return + } + + require.NotNil(t, c, "New() returned client should not be nil") + require.NoError(t, err, "New() unexpected error = %v", err) + }) + } +} + +func TestClient_HealthCheck(t *testing.T) { + t.Parallel() + + c, err := New() + require.NoError(t, err) + + err = c.HealthCheck(testutil.Context()) + require.NoError(t, err) +} diff --git a/pkg/passwordpwned/mock_test.go b/pkg/passwordpwned/mock_test.go new file mode 100644 index 00000000..4df4ac9f --- /dev/null +++ b/pkg/passwordpwned/mock_test.go @@ -0,0 +1,50 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/Vonage/gosrvlib/pkg/passwordpwned (interfaces: HTTPClient) + +// Package passwordpwned is a generated GoMock package. +package passwordpwned + +import ( + http "net/http" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockHTTPClient is a mock of HTTPClient interface. +type MockHTTPClient struct { + ctrl *gomock.Controller + recorder *MockHTTPClientMockRecorder +} + +// MockHTTPClientMockRecorder is the mock recorder for MockHTTPClient. +type MockHTTPClientMockRecorder struct { + mock *MockHTTPClient +} + +// NewMockHTTPClient creates a new mock instance. +func NewMockHTTPClient(ctrl *gomock.Controller) *MockHTTPClient { + mock := &MockHTTPClient{ctrl: ctrl} + mock.recorder = &MockHTTPClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHTTPClient) EXPECT() *MockHTTPClientMockRecorder { + return m.recorder +} + +// Do mocks base method. +func (m *MockHTTPClient) Do(arg0 *http.Request) (*http.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Do", arg0) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Do indicates an expected call of Do. +func (mr *MockHTTPClientMockRecorder) Do(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Do", reflect.TypeOf((*MockHTTPClient)(nil).Do), arg0) +} diff --git a/pkg/passwordpwned/options.go b/pkg/passwordpwned/options.go new file mode 100644 index 00000000..f613fc36 --- /dev/null +++ b/pkg/passwordpwned/options.go @@ -0,0 +1,50 @@ +package passwordpwned + +import ( + "time" +) + +// Option is the interface that allows to set client options. +type Option func(c *Client) + +// WithURL overrides the default service base URL. +func WithURL(addr string) Option { + return func(c *Client) { + c.apiURL = addr + } +} + +// WithUserAgent overrides the default user-agent for service requests. +func WithUserAgent(s string) Option { + return func(c *Client) { + c.userAgent = s + } +} + +// WithTimeout overrides the default request timeout. +func WithTimeout(timeout time.Duration) Option { + return func(c *Client) { + c.timeout = timeout + } +} + +// WithHTTPClient overrides the default HTTP client. +func WithHTTPClient(hc HTTPClient) Option { + return func(c *Client) { + c.httpClient = hc + } +} + +// WithRetryAttempts overrides the default HTTP client. +func WithRetryAttempts(attempts uint) Option { + return func(c *Client) { + c.retryAttempts = attempts + } +} + +// WithRetryDelay sets the delay to apply after the first failed attempt. +func WithRetryDelay(value time.Duration) Option { + return func(c *Client) { + c.retryDelay = value + } +} diff --git a/pkg/passwordpwned/options_test.go b/pkg/passwordpwned/options_test.go new file mode 100644 index 00000000..80ae19b0 --- /dev/null +++ b/pkg/passwordpwned/options_test.go @@ -0,0 +1,70 @@ +package passwordpwned + +import ( + "net/http" + "reflect" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestWithURL(t *testing.T) { + t.Parallel() + + want := "https://test.haveibeenpwned.invalid" + c := &Client{} + WithURL(want)(c) + require.Equal(t, want, c.apiURL, "WithURL() = %want, want %want", c.apiURL, want) +} + +func TestWithUserAgent(t *testing.T) { + t.Parallel() + + want := "test.user.agent/3" + c := &Client{} + WithUserAgent(want)(c) + require.Equal(t, want, c.userAgent, "WithUserAgent() = %want, want %want", c.userAgent, want) +} + +func TestWithTimeout(t *testing.T) { + t.Parallel() + + want := 17 * time.Second + c := &Client{} + WithTimeout(want)(c) + require.Equal(t, want, c.timeout, "WithTimeout() = %v, want %v", c.timeout, want) +} + +type testHTTPClient struct{} + +func (thc *testHTTPClient) Do(*http.Request) (*http.Response, error) { + return nil, nil //nolint:nilnil +} + +func TestWithHTTPClient(t *testing.T) { + t.Parallel() + + v := &testHTTPClient{} + c := &Client{} + WithHTTPClient(v)(c) + require.Equal(t, reflect.ValueOf(v).Pointer(), reflect.ValueOf(c.httpClient).Pointer()) +} + +func TestWithRetryAttempts(t *testing.T) { + t.Parallel() + + v := uint(3) + c := &Client{} + WithRetryAttempts(v)(c) + require.Equal(t, v, c.retryAttempts, "WithRetryAttempts() = %v, want %v", c.retryAttempts, v) +} + +func TestWithRetryDelay(t *testing.T) { + t.Parallel() + + want := 13 * time.Second + c := &Client{} + WithRetryDelay(want)(c) + require.Equal(t, want, c.retryDelay, "WithRetryDelay() = %v, want %v", c.retryDelay, want) +} diff --git a/pkg/passwordpwned/passwordpwned.go b/pkg/passwordpwned/passwordpwned.go new file mode 100644 index 00000000..d72ce03b --- /dev/null +++ b/pkg/passwordpwned/passwordpwned.go @@ -0,0 +1,74 @@ +/* +Package passwordpwned allows to verify if a password was pwned +via the haveibeenpwned.com (HIBP) service API. + +Ref.: https://haveibeenpwned.com/API/v3#PwnedPasswords +*/ +package passwordpwned + +import ( + "bytes" + "context" + "encoding/hex" + "fmt" + "io" + "net/http" + "strings" + + "github.com/Vonage/gosrvlib/pkg/logging" + brotli "github.com/aperturerobotics/go-brotli-decoder" +) + +// IsPwnedPassword returns true if the password has been found pwned. +func (c *Client) IsPwnedPassword(ctx context.Context, password string) (bool, error) { + c.hashObj.Reset() + + _, err := io.WriteString(c.hashObj, password) + if err != nil { + return false, fmt.Errorf("unable to hash password: %w", err) + } + + hash := strings.ToUpper(hex.EncodeToString(c.hashObj.Sum(nil))) + + r, err := http.NewRequestWithContext(ctx, http.MethodGet, c.apiURL+"/"+rangePath+"/"+hash[:5], nil) + if err != nil { + return false, fmt.Errorf("create request: %w", err) + } + + r.Header.Set("user-agent", c.userAgent) + r.Header.Set("Accept-Encoding", "br") // Responses are brotli-encoded. + r.Header.Set("Add-Padding", "true") // All responses will contain between 800 and 1,000 results regardless of the number of hash suffixes returned by the service. + + hr, err := c.newHTTPRetrier() + if err != nil { + return false, fmt.Errorf("create retrier: %w", err) + } + + resp, err := hr.Do(r) //nolint:bodyclose + if err != nil { + return false, fmt.Errorf("execute request: %w", err) + } + + defer logging.Close(ctx, resp.Body, "error closing response body") + + if resp.StatusCode != http.StatusOK { + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + reader := brotli.NewReader(resp.Body) + + data, err := io.ReadAll(reader) + if err != nil { + return false, fmt.Errorf("error decoding brotli response: %w", err) + } + + idx := bytes.Index(data, []byte(hash[5:])) + + // A password is not pwned if the hash suffix is not found + // or the recurrence is zero. + if (idx < 0) || (data[idx+36] == '0') { + return false, nil + } + + return true, nil +} diff --git a/pkg/passwordpwned/passwordpwned_test.go b/pkg/passwordpwned/passwordpwned_test.go new file mode 100644 index 00000000..f9008af4 --- /dev/null +++ b/pkg/passwordpwned/passwordpwned_test.go @@ -0,0 +1,247 @@ +//go:generate mockgen -package passwordpwned -destination ./mock_test.go . HTTPClient +package passwordpwned + +import ( + "context" + "encoding/base64" + "errors" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/Vonage/gosrvlib/pkg/httpretrier" + "github.com/Vonage/gosrvlib/pkg/httputil" + "github.com/Vonage/gosrvlib/pkg/testutil" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/undefinedlabs/go-mpatch" +) + +//go:noinline +func newRequestWithContextPatch(_ context.Context, _, _ string, _ io.Reader) (*http.Request, error) { + return nil, errors.New("error") +} + +//go:noinline +func newHTTPRetrierPatch(httpretrier.HTTPClient, ...httpretrier.Option) (*httpretrier.HTTPRetrier, error) { + return nil, errors.New("error") +} + +//nolint:gocognit,tparallel +func TestClient_IsPwnedPassword(t *testing.T) { + t.Parallel() + + // pwned.password.1 : AC8A89B5F24DE5F1D9AE8499A204B5098B08DF1B + // pwned.password.2 : 274AC46FA9F7FDDB8AB4A5BB8295A47E3929171E + // pwned.password.3 : C1C39EBC8981022DC3220FF6C17D1933BA5E5061 + // pwned.password.4 : 05955AE4E6ADFB93265CA2BCF0560529CF0BFDC9 + // pwned.password.5 : 34D03CE275F04C48AF10A4E23AB85D27AF3239B0 + // pwned.password.6 : ACE9846F1DC7F76EB2E5D064BDEFE65B712F85D3 + + // body: + // 9B5F24DE5F1D9AE8499A204B5098B08DF1B:1 + // 46FA9F7FDDB8AB4A5BB8295A47E3929171E:2 + // EBC8981022DC3220FF6C17D1933BA5E5061:3 + // AE4E6ADFB93265CA2BCF0560529CF0BFDC9:4 + // CE275F04C48AF10A4E23AB85D27AF3239B0:0 + // 46F1DC7F76EB2E5D064BDEFE65B712F85D3:0 + + // base64 brotli encoded body + retBody, _ := base64.StdEncoding.DecodeString("G+IA+I2ULm8UPTY2L7T4yFAoTZILH26i9Ehm9XAi90lEEkgpxCt4c1gfxS7j/GbqZUlq1aPQFF8OCnTcT1v94iEQTTMR3FmjDwZzpa6C4edcWcu5CibTTqo+UAOl6IO66fjSS64H0vLyEFKWOOvpkOcxcRR8EDuc9nPbotUBk5q9NS1HOvwB") + + mockHandleFn := func(t *testing.T, body []byte) http.HandlerFunc { + t.Helper() + + return func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", httputil.MimeTextPlain) + w.Header().Set("Content-Encoding", "br") + _, err := w.Write(body) + assert.NoError(t, err) + } + } + + tests := []struct { + name string + password string + createMockHandler func(t *testing.T) http.HandlerFunc + setupMocks func(client *MockHTTPClient) + setupPatches func() (*mpatch.Patch, error) + hashError bool + pwned bool + wantErr bool + }{ + { + name: "hash write error", + password: "some.password", + hashError: true, + pwned: false, + wantErr: true, + }, + { + name: "failed to execute request - NewRequest error", + setupPatches: func() (*mpatch.Patch, error) { + patch, err := mpatch.PatchMethod(http.NewRequestWithContext, newRequestWithContextPatch) + if err != nil { + return nil, err //nolint:wrapcheck + } + _ = patch.Patch() + return patch, nil + }, + wantErr: true, + }, + { + name: "failed to execute request - HTTPRetrier error", + setupPatches: func() (*mpatch.Patch, error) { + patch, err := mpatch.PatchMethod(httpretrier.New, newHTTPRetrierPatch) + if err != nil { + return nil, err //nolint:wrapcheck + } + _ = patch.Patch() + return patch, nil + }, + wantErr: true, + }, + { + name: "failed to execute request - transport error", + setupMocks: func(m *MockHTTPClient) { + m.EXPECT().Do(gomock.Any()).Return(nil, errors.New("transport error")).Times(1) + }, + wantErr: true, + }, + { + name: "unexpected http error status code", + createMockHandler: func(t *testing.T) http.HandlerFunc { + t.Helper() + return func(w http.ResponseWriter, r *http.Request) { + httputil.SendStatus(r.Context(), w, http.StatusInternalServerError) + } + }, + wantErr: true, + }, + { + name: "invalid response status < 200", + createMockHandler: func(t *testing.T) http.HandlerFunc { + t.Helper() + return func(w http.ResponseWriter, r *http.Request) { + httputil.SendStatus(r.Context(), w, http.StatusSwitchingProtocols) + } + }, + wantErr: true, + }, + { + name: "invalid brotli encoding", + password: "pwned.password.1", // AC8A89B5F24DE5F1D9AE8499A204B5098B08DF1B + createMockHandler: func(t *testing.T) http.HandlerFunc { + t.Helper() + return mockHandleFn(t, []byte("invalid")) + }, + pwned: false, + wantErr: true, + }, + { + name: "pwned password", + password: "pwned.password.2", // 274AC46FA9F7FDDB8AB4A5BB8295A47E3929171E + createMockHandler: func(t *testing.T) http.HandlerFunc { + t.Helper() + return mockHandleFn(t, retBody) + }, + pwned: true, + wantErr: false, + }, + { + name: "false pwned password because of padding", + password: "pwned.password.6", // ACE9846F1DC7F76EB2E5D064BDEFE65B712F85D3 + createMockHandler: func(t *testing.T) http.HandlerFunc { + t.Helper() + return mockHandleFn(t, retBody) + }, + pwned: false, + wantErr: false, + }, + { + name: "ok password", + password: "not.pwned.password", + createMockHandler: func(t *testing.T) http.HandlerFunc { + t.Helper() + return mockHandleFn(t, retBody) + }, + pwned: false, + wantErr: false, + }, + } + + //nolint:paralleltest + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mux := http.NewServeMux() + if tt.createMockHandler != nil { + mux.HandleFunc("/"+rangePath+"/", tt.createMockHandler(t)) + } + + ts := httptest.NewServer(mux) + defer ts.Close() + + clientOpts := []Option{ + WithURL(ts.URL), + WithRetryAttempts(1), + } + + if tt.setupMocks != nil { + mc := NewMockHTTPClient(ctrl) + tt.setupMocks(mc) + clientOpts = append(clientOpts, WithHTTPClient(mc), WithRetryAttempts(1)) + } + + c, err := New(clientOpts...) + require.NoError(t, err) + + if tt.hashError { + c.hashObj = &mockHashErr{} + } + + if tt.setupPatches != nil { + patch, err := tt.setupPatches() + require.NoError(t, err) + + defer func() { + _ = patch.Unpatch() + }() + } + + got, err := c.IsPwnedPassword(testutil.Context(), tt.password) + + require.Equal(t, tt.wantErr, err != nil, err) + require.Equal(t, tt.pwned, got) + }) + } +} + +type mockWriterErr struct{} + +func (w *mockWriterErr) Write(_ []byte) (int, error) { + return 0, errors.New("write error") +} + +type mockHashErr struct { + mockWriterErr +} + +func (m *mockHashErr) Sum(b []byte) []byte { + return b +} + +func (m *mockHashErr) Reset() {} + +func (m *mockHashErr) Size() int { + return 0 +} + +func (m *mockHashErr) BlockSize() int { + return 0 +}