diff --git a/VERSION b/VERSION index f6342716..59be5921 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.87.0 +1.88.0 diff --git a/examples/service/go.mod b/examples/service/go.mod index 95376a6b..34ac3c22 100644 --- a/examples/service/go.mod +++ b/examples/service/go.mod @@ -7,7 +7,7 @@ toolchain go1.22.2 replace github.com/Vonage/gosrvlib => ../.. require ( - github.com/Vonage/gosrvlib v1.87.0 + github.com/Vonage/gosrvlib v1.88.0 github.com/golang/mock v1.6.0 github.com/jstemmer/go-junit-report v1.0.0 github.com/prometheus/client_golang v1.19.0 @@ -20,8 +20,8 @@ require ( require ( cloud.google.com/go v0.112.2 // indirect - cloud.google.com/go/auth v0.2.2 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.1 // indirect + cloud.google.com/go/auth v0.3.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.6 // indirect @@ -91,11 +91,11 @@ require ( go.etcd.io/etcd/client/v2 v2.305.13 // indirect go.etcd.io/etcd/client/v3 v3.5.13 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect - go.opentelemetry.io/otel v1.25.0 // indirect - go.opentelemetry.io/otel/metric v1.25.0 // indirect - go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect + go.opentelemetry.io/otel v1.26.0 // indirect + go.opentelemetry.io/otel/metric v1.26.0 // indirect + go.opentelemetry.io/otel/trace v1.26.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect @@ -107,7 +107,7 @@ require ( golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.20.0 // indirect - google.golang.org/api v0.176.0 // indirect + google.golang.org/api v0.176.1 // indirect google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect diff --git a/examples/service/go.sum b/examples/service/go.sum index b97a34b6..eacb0880 100644 --- a/examples/service/go.sum +++ b/examples/service/go.sum @@ -25,10 +25,10 @@ cloud.google.com/go/asset v1.18.1 h1:+NpxL5L53VY91EoJTHeGGXSWEUllf2hhXpCyTnSrd3Q cloud.google.com/go/asset v1.18.1/go.mod h1:QXivw0mVqwrhZyuX6iqFbyfCdzYE9AFCJVG47Eh5dMM= cloud.google.com/go/assuredworkloads v1.11.6 h1:3NlUes0xLN2kcSU24qQADFYsOaetCPg0HSA302AyV5s= cloud.google.com/go/assuredworkloads v1.11.6/go.mod h1:1dlhWKocQorGYkspt+scx11kQCI9qVHOi1Au6Rw9srg= -cloud.google.com/go/auth v0.2.2 h1:gmxNJs4YZYcw6YvKRtVBaF2fyUE6UrWPyzU8jHvYfmI= -cloud.google.com/go/auth v0.2.2/go.mod h1:2bDNJWtWziDT3Pu1URxHHbkHE/BbOCuyUiKIGcNvafo= -cloud.google.com/go/auth/oauth2adapt v0.2.1 h1:VSPmMmUlT8CkIZ2PzD9AlLN+R3+D1clXMWHHa6vG/Ag= -cloud.google.com/go/auth/oauth2adapt v0.2.1/go.mod h1:tOdK/k+D2e4GEwfBRA48dKNQiDsqIXxLh7VU319eV0g= +cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs= +cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= +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.6 h1:NHBO5cjo2IgwaJ5qlez/iA35XI1db87PPlOB0Kjt5RM= cloud.google.com/go/automl v1.13.6/go.mod h1:/0VtkKis6KhFJuPzi45e0E+e9AdQE09SNieChjJqU18= cloud.google.com/go/baremetalsolution v1.2.5 h1:jCR4rnVsG6ocK6ngFr2Z6ugKZfTENmMZkiV6Ma2tEeE= @@ -698,18 +698,18 @@ go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= +go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= +go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -825,8 +825,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.176.0 h1:dHj1/yv5Dm/eQTXiP9hNCRT3xzJHWXeNdRq29XbMxoE= -google.golang.org/api v0.176.0/go.mod h1:Rra+ltKu14pps/4xTycZfobMgLpbosoaaL7c+SEMrO8= +google.golang.org/api v0.176.1 h1:DJSXnV6An+NhJ1J+GWtoF2nHEuqB1VNoTfnIbjNvwD4= +google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg= 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= diff --git a/go.mod b/go.mod index caa374d3..dfe1085f 100644 --- a/go.mod +++ b/go.mod @@ -37,8 +37,8 @@ require ( require ( cloud.google.com/go v0.112.2 // indirect - cloud.google.com/go/auth v0.2.2 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.1 // indirect + cloud.google.com/go/auth v0.3.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.6 // indirect @@ -119,11 +119,11 @@ require ( go.etcd.io/etcd/client/v2 v2.305.13 // indirect go.etcd.io/etcd/client/v3 v3.5.13 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect - go.opentelemetry.io/otel v1.25.0 // indirect - go.opentelemetry.io/otel/metric v1.25.0 // indirect - go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect + go.opentelemetry.io/otel v1.26.0 // indirect + go.opentelemetry.io/otel/metric v1.26.0 // indirect + go.opentelemetry.io/otel/trace v1.26.0 // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/oauth2 v0.19.0 // indirect @@ -131,7 +131,7 @@ require ( golang.org/x/sys v0.19.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.20.0 // indirect - google.golang.org/api v0.176.0 // indirect + google.golang.org/api v0.176.1 // indirect google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect diff --git a/go.sum b/go.sum index 78855067..a601d263 100644 --- a/go.sum +++ b/go.sum @@ -26,10 +26,10 @@ cloud.google.com/go/asset v1.18.1 h1:+NpxL5L53VY91EoJTHeGGXSWEUllf2hhXpCyTnSrd3Q cloud.google.com/go/asset v1.18.1/go.mod h1:QXivw0mVqwrhZyuX6iqFbyfCdzYE9AFCJVG47Eh5dMM= cloud.google.com/go/assuredworkloads v1.11.6 h1:3NlUes0xLN2kcSU24qQADFYsOaetCPg0HSA302AyV5s= cloud.google.com/go/assuredworkloads v1.11.6/go.mod h1:1dlhWKocQorGYkspt+scx11kQCI9qVHOi1Au6Rw9srg= -cloud.google.com/go/auth v0.2.2 h1:gmxNJs4YZYcw6YvKRtVBaF2fyUE6UrWPyzU8jHvYfmI= -cloud.google.com/go/auth v0.2.2/go.mod h1:2bDNJWtWziDT3Pu1URxHHbkHE/BbOCuyUiKIGcNvafo= -cloud.google.com/go/auth/oauth2adapt v0.2.1 h1:VSPmMmUlT8CkIZ2PzD9AlLN+R3+D1clXMWHHa6vG/Ag= -cloud.google.com/go/auth/oauth2adapt v0.2.1/go.mod h1:tOdK/k+D2e4GEwfBRA48dKNQiDsqIXxLh7VU319eV0g= +cloud.google.com/go/auth v0.3.0 h1:PRyzEpGfx/Z9e8+lHsbkoUVXD0gnu4MNmm7Gp8TQNIs= +cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= +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.6 h1:NHBO5cjo2IgwaJ5qlez/iA35XI1db87PPlOB0Kjt5RM= cloud.google.com/go/automl v1.13.6/go.mod h1:/0VtkKis6KhFJuPzi45e0E+e9AdQE09SNieChjJqU18= cloud.google.com/go/baremetalsolution v1.2.5 h1:jCR4rnVsG6ocK6ngFr2Z6ugKZfTENmMZkiV6Ma2tEeE= @@ -795,18 +795,18 @@ go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= +go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= +go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= +go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= +go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= +go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -961,8 +961,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.176.0 h1:dHj1/yv5Dm/eQTXiP9hNCRT3xzJHWXeNdRq29XbMxoE= -google.golang.org/api v0.176.0/go.mod h1:Rra+ltKu14pps/4xTycZfobMgLpbosoaaL7c+SEMrO8= +google.golang.org/api v0.176.1 h1:DJSXnV6An+NhJ1J+GWtoF2nHEuqB1VNoTfnIbjNvwD4= +google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg= 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= diff --git a/pkg/passwordhash/example_passwordhash_test.go b/pkg/passwordhash/example_passwordhash_test.go new file mode 100644 index 00000000..832b0ea0 --- /dev/null +++ b/pkg/passwordhash/example_passwordhash_test.go @@ -0,0 +1,88 @@ +package passwordhash_test + +import ( + "fmt" + "log" + + "github.com/Vonage/gosrvlib/pkg/passwordhash" +) + +func ExampleParams_PasswordVerify() { + opts := []passwordhash.Option{ + passwordhash.WithKeyLen(32), + passwordhash.WithSaltLen(16), + passwordhash.WithTime(3), + passwordhash.WithMemory(16_384), + passwordhash.WithThreads(1), + passwordhash.WithMinPasswordLength(16), + passwordhash.WithMaxPasswordLength(128), + } + + p := passwordhash.New(opts...) + + secret := "Example-Password-01" + + hash, err := p.PasswordHash(secret) + if err != nil { + log.Fatal(err) + } + + ok, err := p.PasswordVerify(secret, hash) + if err != nil { + log.Fatal(err) + } + + fmt.Println(ok) + + ok, err = p.PasswordVerify("Example-Wrong-Password-01", hash) + if err != nil { + log.Fatal(err) + } + + fmt.Println(ok) + + // Output: + // true + // false +} + +func ExampleParams_EncryptPasswordVerify() { + opts := []passwordhash.Option{ + passwordhash.WithKeyLen(32), + passwordhash.WithSaltLen(16), + passwordhash.WithTime(3), + passwordhash.WithMemory(16_384), + passwordhash.WithThreads(1), + passwordhash.WithMinPasswordLength(16), + passwordhash.WithMaxPasswordLength(128), + } + + p := passwordhash.New(opts...) + + key := []byte("0123456789012345") + + secret := "Example-Password-02" + + hash, err := p.EncryptPasswordHash(key, secret) + if err != nil { + log.Fatal(err) + } + + ok, err := p.EncryptPasswordVerify(key, secret, hash) + if err != nil { + log.Fatal(err) + } + + fmt.Println(ok) + + ok, err = p.EncryptPasswordVerify(key, "Example-Wrong-Password-02", hash) + if err != nil { + log.Fatal(err) + } + + fmt.Println(ok) + + // Output: + // true + // false +} diff --git a/pkg/passwordhash/options.go b/pkg/passwordhash/options.go index 5eaba499..aa81d471 100644 --- a/pkg/passwordhash/options.go +++ b/pkg/passwordhash/options.go @@ -3,42 +3,63 @@ package passwordhash // Option is a type alias for a function that configures the password hasher. type Option func(*Params) -// WithKeyLen overwrites the default length of the returned byte-slice that can be used as cryptographic key. +// WithKeyLen overwrites the default length of the returned byte-slice that can be used as cryptographic key (Tag length). +// It must be an integer number of bytes from 4 to 2^(32)-1. // The default value is 32 bytes. func WithKeyLen(v uint32) Option { return func(ph *Params) { - ph.KeyLen = v + ph.KeyLen = max(minKeyLen, v) } } -// WithSaltLen overwrites the default length of the random password salt. -// The default value is 16 bytes. +// WithSaltLen overwrites the default length of the random password salt (Nonce S). +// It must be not greater than 2^(32)-1 bytes. +// The value of 16 bytes is recommended for password hashing. func WithSaltLen(v uint32) Option { return func(ph *Params) { - ph.SaltLen = v + ph.SaltLen = max(minSaltLen, v) } } -// WithTime overwrites the number of passes over the memory. -// The default value is 1. +// WithTime (t) is the default number of passes (iterations) over the memory. +// It must be an integer value from 1 to 2^(32)-1. func WithTime(v uint32) Option { return func(ph *Params) { - ph.Time = v + ph.Time = max(minTime, v) } } -// WithMemory overwrites the size of the memory in KiB. -// The default value is 65_536 KiB. +// WithMemory overwrites the default size of the memory in KiB. +// It must be an integer number of kibibytes from 8*p to 2^(32)-1. +// The actual number of blocks is m', which is m rounded down to the nearest multiple of 4*p. func WithMemory(v uint32) Option { return func(ph *Params) { - ph.Memory = v + ph.Memory = max(minMemory, v) } } -// WithThreads overwrites the number of threads used by the algorithm. -// The default value is the number of available CPUs. +// WithThreads overwrites the default number ot threads (p) +// Threads represents the degree of parallelism p that determines how many independent +// (but synchronizing) computational chains (lanes) can be run. +// According to the RFC9106 it must be an integer value from 1 to 2^(24)-1, but in this implementation is limited to 2^(8)-1. func WithThreads(v uint8) Option { return func(ph *Params) { - ph.Threads = v + ph.Threads = max(minThreads, v) + } +} + +// WithMinPasswordLength overwrites the default maximum length of the input password (Message string P). +// It must have a length not greater than 2^(32)-1 bytes. +func WithMinPasswordLength(v uint32) Option { + return func(ph *Params) { + ph.minPLen = v + } +} + +// WithMaxPasswordLength overwrites the default maximum length of the input password (Message string P). +// It must have a length not greater than 2^(32)-1 bytes. +func WithMaxPasswordLength(v uint32) Option { + return func(ph *Params) { + ph.maxPLen = v } } diff --git a/pkg/passwordhash/options_test.go b/pkg/passwordhash/options_test.go index b2d4e23b..6eba42dc 100644 --- a/pkg/passwordhash/options_test.go +++ b/pkg/passwordhash/options_test.go @@ -60,3 +60,25 @@ func TestWithThreads(t *testing.T) { WithThreads(v)(c) require.Equal(t, v, c.Threads) } + +func TestWithMinPasswordLength(t *testing.T) { + t.Parallel() + + c := defaultParams() + + var v uint32 = 13 + + WithMinPasswordLength(v)(c) + require.Equal(t, v, c.minPLen) +} + +func TestWithMaxPasswordLength(t *testing.T) { + t.Parallel() + + c := defaultParams() + + var v uint32 = 13 + + WithMaxPasswordLength(v)(c) + require.Equal(t, v, c.maxPLen) +} diff --git a/pkg/passwordhash/passwordhash.go b/pkg/passwordhash/passwordhash.go index 6a88d590..67126aad 100644 --- a/pkg/passwordhash/passwordhash.go +++ b/pkg/passwordhash/passwordhash.go @@ -1,9 +1,10 @@ /* -Package passwordhash contains functions to create and verify a password hash using a strong one-way hashing algorithm. +Package passwordhash provides functions to create and verify a password hash using a strong one-way hashing algorithm. It supports "peppering" by encrypting the hashed passwords using a secret key. -It is based on the Argon2id algorithm as recommended by the OWASP Password Storage Cheat Sheet: +It is based on the Argon2id algorithm (https://www.rfc-editor.org/info/rfc9106), +as recommended by the OWASP Password Storage Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html */ package passwordhash @@ -19,43 +20,97 @@ import ( const ( // DefaultAlgo is the default algorithm used to hash the password. + // It corresponds to Type y=2. DefaultAlgo = "argon2id" - // DefaultKeyLen is the default length of the returned byte-slice that can be used as cryptographic key. + // DefaultKeyLen is the default length of the returned byte-slice that can be used as cryptographic key (Tag length). + // It must be an integer number of bytes from 4 to 2^(32)-1. DefaultKeyLen = 32 + minKeyLen = 4 - // DefaultSaltLen is the default length of the random password salt. + // DefaultSaltLen is the default length of the random password salt (Nonce S). + // It must be not greater than 2^(32)-1 bytes. + // The value of 16 bytes is recommended for password hashing. DefaultSaltLen = 16 + minSaltLen = 1 - // DefaultTime is the default number of passes over the memory. - DefaultTime = 1 + // DefaultTime (t) is the default number of passes (iterations) over the memory. + // It must be an integer value from 1 to 2^(32)-1. + DefaultTime = 3 + minTime = 1 // DefaultMemory is the default size of the memory in KiB. - DefaultMemory = 65_536 + // It must be an integer number of kibibytes from 8*p to 2^(32)-1. + // The actual number of blocks is m', which is m rounded down to the nearest multiple of 4*p. + DefaultMemory = 64 * 1024 + minMemory = 8 + memBlock = 4 + + minThreads = 1 + maxThreads = 255 + + // DefaultMinPasswordLength is the default minimum length of the input password (Message string P). + // It must have a length not greater than 2^(32)-1 bytes. + DefaultMinPasswordLength = 8 + + // DefaultMaxPasswordLength is the default maximum length of the input password (Message string P). + // It must have a length not greater than 2^(32)-1 bytes. + DefaultMaxPasswordLength = 4096 ) // Params contains the parameters for hashing the password. type Params struct { // Algo is the algorithm used to hash the password. + // It corresponds to Type y=2. Algo string `json:"A"` - // Version is the algorithm version implemented by the parent package. + // Version is the algorithm version. Version uint8 `json:"V"` - // KeyLen is the length of the returned byte-slice that can be used as cryptographic key. + // KeyLen is the length of the returned byte-slice that can be used as cryptographic key (Tag length). + // It must be an integer number of bytes from 4 to 2^(32)-1. KeyLen uint32 `json:"K"` - // SaltLen is the length of the random password salt. + // SaltLen is the length of the random password salt (Nonce S). + // It must be not greater than 2^(32)-1 bytes. + // The value of 16 bytes is recommended for password hashing. SaltLen uint32 `json:"S"` - // Time is the number of passes over the memory. + // Time (t) is the default number of passes over the memory. + // It must be an integer value from 1 to 2^(32)-1. Time uint32 `json:"T"` // Memory is the size of the memory in KiB. + // It must be an integer number of kibibytes from 8*p to 2^(32)-1. + // The actual number of blocks is m', which is m rounded down to the nearest multiple of 4*p. Memory uint32 `json:"M"` - // Threads is number of threads used by hashing the algorithm. + // Threads (p) is the degree of parallelism p that determines how many independent + // (but synchronizing) computational chains (lanes) can be run. + // According to the RFC9106 it must be an integer value from 1 to 2^(24)-1, + // but in this implementation is limited to 2^(8)-1. Threads uint8 `json:"P"` + + // minPLen is the minimum length of the input password (Message string P). + // It must have a length not greater than 2^(32)-1 bytes. + minPLen uint32 + + // maxPLen is the maximum length of the input password (Message string P). + // It must have a length not greater than 2^(32)-1 bytes. + maxPLen uint32 +} + +// Hashed contains the hashed password key and hashing parameters. +type Hashed struct { + // Params contains the hashing parameters. + Params *Params `json:"P"` + + // Salt is the password salt (Nonce S) of length Params.SaltLen. + // The salt should be unique for each password. + Salt []byte `json:"S"` + + // Key is the hashed password (Tag) of length Params.KeyLen. + Key []byte `json:"K"` } // defaultParams returns the default parameter values. @@ -67,7 +122,9 @@ func defaultParams() *Params { SaltLen: DefaultSaltLen, Time: DefaultTime, Memory: DefaultMemory, - Threads: uint8(runtime.NumCPU()), + Threads: uint8(max(minThreads, min(runtime.NumCPU(), maxThreads))), + minPLen: DefaultMinPasswordLength, + maxPLen: DefaultMaxPasswordLength, } } @@ -79,22 +136,24 @@ func New(opts ...Option) *Params { applyOpt(ph) } + ph.Memory = adjustMemory(ph.Memory, uint32(ph.Threads)) + return ph } -// Hashed contains the hashed password key and hashing parameters. -type Hashed struct { - // Params contains the hashing parameters. - Params *Params `json:"P"` - - // Salt is the password salt. - Salt []byte `json:"S"` +// passwordHashData generates a hashed password using the provided password string. +// It generates a random salt of length ph.SaltLen and uses the argon2id algorithm +// to hash the password with the salt, using the parameters specified in ph. +// The resulting hashed password, the salt and the parameters are returned as a struct. +func (ph *Params) passwordHashData(password string) (*Hashed, error) { + if len(password) < int(ph.minPLen) { + return nil, fmt.Errorf("the password is too short: %d > %d", len(password), ph.minPLen) + } - // Key is the hashed password. - Key []byte `json:"K"` -} + if len(password) > int(ph.maxPLen) { + return nil, fmt.Errorf("the password is too long: %d > %d", len(password), ph.maxPLen) + } -func (ph *Params) passwordHashData(password string) (*Hashed, error) { salt, err := typeutil.RandomBytes(typeutil.RandReader, int(ph.SaltLen)) if err != nil { return nil, err //nolint:wrapcheck @@ -115,6 +174,8 @@ func (ph *Params) passwordHashData(password string) (*Hashed, error) { }, nil } +// passwordVerifyData verifies if a given password matches a hashed password generated with the passwordHashData method. +// It returns true if the password matches the hashed password, otherwise false. func (ph *Params) passwordVerifyData(password string, data *Hashed) (bool, error) { if data.Params.Algo != ph.Algo { return false, fmt.Errorf("different algorithm type: lib=%s, hash=%s", ph.Algo, data.Params.Algo) @@ -177,3 +238,10 @@ func (ph *Params) EncryptPasswordVerify(key []byte, password, hash string) (bool return ph.passwordVerifyData(password, data) } + +// adjustMemory returns the actual number of blocks is m', +// which is m rounded down to the nearest multiple of 4*p. +func adjustMemory(m uint32, p uint32) uint32 { + block := (memBlock * p) + return max((2 * block), ((m / block) * block)) +} diff --git a/pkg/passwordhash/passwordhash_benchmark_test.go b/pkg/passwordhash/passwordhash_benchmark_test.go new file mode 100644 index 00000000..47a41d6d --- /dev/null +++ b/pkg/passwordhash/passwordhash_benchmark_test.go @@ -0,0 +1,40 @@ +package passwordhash + +import ( + "testing" +) + +func BenchmarkPasswordHash(b *testing.B) { + p := New() + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, _ = p.PasswordHash("Benchmark-Password-Hash-Test") + } +} + +func BenchmarkPasswordVerify(b *testing.B) { + p := New() + + hash := "eyJQIjp7IkEiOiJhcmdvbjJpZCIsIlYiOjE5LCJLIjozMiwiUyI6MTYsIlQiOjMsIk0iOjY1NTM2LCJQIjoxNn0sIlMiOiJ3UVltNGJma3RiSHEyb21Jd0Z1KzRRPT0iLCJLIjoiYVU4aE85MDBPZHE2YUt0V2lXejNSVzl5Z243MzRsaUphUHRNNnludmtZST0ifQo=" + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, _ = p.PasswordVerify("Test-Password-01234", hash) + } +} + +func Benchmark_EncryptPasswordHash(b *testing.B) { + p := New() + + key := []byte("abcdefghijklmnopqrstuvwxyz012345") + secret := "Benchmark-Password-Encrypt-Hash-Test" + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + _, _ = p.EncryptPasswordHash(key, secret) + } +} diff --git a/pkg/passwordhash/passwordhash_test.go b/pkg/passwordhash/passwordhash_test.go index 4b565798..b60bccf7 100644 --- a/pkg/passwordhash/passwordhash_test.go +++ b/pkg/passwordhash/passwordhash_test.go @@ -25,6 +25,8 @@ func TestNew(t *testing.T) { WithTime(3), WithMemory(65_537), WithThreads(5), + WithMinPasswordLength(16), + WithMaxPasswordLength(128), } p = New(opts...) @@ -34,19 +36,35 @@ func TestNew(t *testing.T) { require.Equal(t, uint32(31), p.KeyLen) require.Equal(t, uint32(17), p.SaltLen) require.Equal(t, uint32(3), p.Time) - require.Equal(t, uint32(65_537), p.Memory) + require.Equal(t, uint32(0xfff0), p.Memory) require.Equal(t, uint8(5), p.Threads) + require.Equal(t, uint32(16), p.minPLen) + require.Equal(t, uint32(128), p.maxPLen) } //nolint:paralleltest func Test_passwordHashData(t *testing.T) { p := New() - hash, err := p.passwordHashData("test") + hash, err := p.passwordHashData("test-password") require.NoError(t, err) require.NotEmpty(t, hash) + shortPassword := string(make([]byte, p.minPLen-1)) + + hash, err = p.passwordHashData(shortPassword) + + require.Error(t, err) + require.Empty(t, hash) + + longPassword := string(make([]byte, p.maxPLen+1)) + + hash, err = p.passwordHashData(longPassword) + + require.Error(t, err) + require.Empty(t, hash) + rr := typeutil.RandReader defer func() { typeutil.RandReader = rr }() @@ -99,7 +117,7 @@ func Test_passwordHashData_passwordVerifyData(t *testing.T) { func TestPasswordHash(t *testing.T) { p := New() - hash, err := p.PasswordHash("test") + hash, err := p.PasswordHash("TestPasswordString") require.NoError(t, err) require.NotEmpty(t, hash) @@ -135,7 +153,7 @@ func TestPasswordVerify(t *testing.T) { func Test_PasswordHash_PasswordVerify(t *testing.T) { t.Parallel() - secret := "test-secret-string" + secret := "Test-Password-01234" p := New()