diff --git a/api/billing/documents/go.mod b/api/billing/documents/go.mod index 65e056d0..f4d2d4d0 100644 --- a/api/billing/documents/go.mod +++ b/api/billing/documents/go.mod @@ -41,9 +41,9 @@ require ( github.com/casbin/govaluate v1.10.0 // indirect github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -63,7 +63,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/protobuf v1.36.11 // indirect diff --git a/api/billing/documents/go.sum b/api/billing/documents/go.sum index 684e5755..c82ace98 100644 --- a/api/billing/documents/go.sum +++ b/api/billing/documents/go.sum @@ -78,8 +78,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -100,8 +100,8 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc= github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -241,8 +241,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/billing/fees/go.mod b/api/billing/fees/go.mod index d976a362..0c1e4d75 100644 --- a/api/billing/fees/go.mod +++ b/api/billing/fees/go.mod @@ -25,9 +25,9 @@ require ( github.com/casbin/casbin/v2 v2.135.0 // indirect github.com/casbin/govaluate v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -48,7 +48,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/protobuf v1.36.11 diff --git a/api/billing/fees/go.sum b/api/billing/fees/go.sum index 4e3f9b6c..58daa9d4 100644 --- a/api/billing/fees/go.sum +++ b/api/billing/fees/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -191,8 +191,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/discovery/go.mod b/api/discovery/go.mod index f6680737..57d0a032 100644 --- a/api/discovery/go.mod +++ b/api/discovery/go.mod @@ -5,7 +5,7 @@ go 1.25.6 replace github.com/tech/sendico/pkg => ../pkg require ( - github.com/go-chi/chi/v5 v5.2.4 + github.com/go-chi/chi/v5 v5.2.5 github.com/prometheus/client_golang v1.23.2 github.com/tech/sendico/pkg v0.1.0 go.uber.org/zap v1.27.1 @@ -20,7 +20,7 @@ require ( github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -41,7 +41,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/grpc v1.78.0 // indirect diff --git a/api/discovery/go.sum b/api/discovery/go.sum index 4e3f9b6c..58daa9d4 100644 --- a/api/discovery/go.sum +++ b/api/discovery/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -191,8 +191,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/fx/ingestor/go.mod b/api/fx/ingestor/go.mod index 95cdcf2b..1d8b2b7c 100644 --- a/api/fx/ingestor/go.mod +++ b/api/fx/ingestor/go.mod @@ -7,7 +7,7 @@ replace github.com/tech/sendico/pkg => ../../pkg replace github.com/tech/sendico/fx/storage => ../storage require ( - github.com/go-chi/chi/v5 v5.2.4 + github.com/go-chi/chi/v5 v5.2.5 github.com/google/go-cmp v0.7.0 github.com/prometheus/client_golang v1.23.2 github.com/tech/sendico/fx/storage v0.0.0 @@ -25,7 +25,7 @@ require ( github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -45,7 +45,7 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/crypto v0.47.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/grpc v1.78.0 // indirect diff --git a/api/fx/ingestor/go.sum b/api/fx/ingestor/go.sum index 4e3f9b6c..58daa9d4 100644 --- a/api/fx/ingestor/go.sum +++ b/api/fx/ingestor/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -191,8 +191,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/fx/oracle/go.mod b/api/fx/oracle/go.mod index edbc9f38..5ed22a67 100644 --- a/api/fx/oracle/go.mod +++ b/api/fx/oracle/go.mod @@ -25,8 +25,8 @@ require ( github.com/casbin/govaluate v1.10.0 // indirect github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -46,7 +46,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect ) diff --git a/api/fx/oracle/go.sum b/api/fx/oracle/go.sum index 4e3f9b6c..58daa9d4 100644 --- a/api/fx/oracle/go.sum +++ b/api/fx/oracle/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -191,8 +191,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/fx/storage/go.mod b/api/fx/storage/go.mod index 4c364ef9..f23c2ea9 100644 --- a/api/fx/storage/go.mod +++ b/api/fx/storage/go.mod @@ -16,7 +16,7 @@ require ( github.com/casbin/govaluate v1.10.0 // indirect github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.2.0 // indirect diff --git a/api/fx/storage/go.sum b/api/fx/storage/go.sum index ae57ca1a..0fe20d5e 100644 --- a/api/fx/storage/go.sum +++ b/api/fx/storage/go.sum @@ -49,8 +49,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/api/gateway/chain/go.mod b/api/gateway/chain/go.mod index 88a789fd..4891049e 100644 --- a/api/gateway/chain/go.mod +++ b/api/gateway/chain/go.mod @@ -22,7 +22,7 @@ require ( require ( github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260204112742-a1cdb34ff7e1 // indirect + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260208002143-2551aa251e34 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect @@ -38,7 +38,7 @@ require ( github.com/deckarep/golang-set/v2 v2.8.0 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -53,7 +53,7 @@ require ( github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/hcl v1.0.1-vault-7 // indirect github.com/holiman/uint256 v1.3.2 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -81,7 +81,7 @@ require ( golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect diff --git a/api/gateway/chain/go.sum b/api/gateway/chain/go.sum index 54666776..4e5ec1e5 100644 --- a/api/gateway/chain/go.sum +++ b/api/gateway/chain/go.sum @@ -6,8 +6,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260204112742-a1cdb34ff7e1 h1:LyoFl70WFSqEQSOky2dlIhjrm5bcliiM7v7e9Y7IFxc= -github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260204112742-a1cdb34ff7e1/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260208002143-2551aa251e34 h1:AyAPL6pTcPPpfZsNtOTFhxyOokKBLnrbbaV42g6Z9v0= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260208002143-2551aa251e34/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -90,8 +90,8 @@ github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeD github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -159,8 +159,8 @@ github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -341,8 +341,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/gateway/chain/internal/service/gateway/service_test.go b/api/gateway/chain/internal/service/gateway/service_test.go index 132bf46f..eb501266 100644 --- a/api/gateway/chain/internal/service/gateway/service_test.go +++ b/api/gateway/chain/internal/service/gateway/service_test.go @@ -337,7 +337,7 @@ func (w *inMemoryWallets) List(ctx context.Context, filter model.ManagedWalletFi continue } } - if wallet.Network != filter.Network { + if filter.Network != "" && wallet.Network != filter.Network { continue } if filter.TokenSymbol != "" && !strings.EqualFold(wallet.TokenSymbol, filter.TokenSymbol) { diff --git a/api/gateway/mntx/go.mod b/api/gateway/mntx/go.mod index 56795bee..5f88b860 100644 --- a/api/gateway/mntx/go.mod +++ b/api/gateway/mntx/go.mod @@ -5,7 +5,7 @@ go 1.25.6 replace github.com/tech/sendico/pkg => ../../pkg require ( - github.com/go-chi/chi/v5 v5.2.4 + github.com/go-chi/chi/v5 v5.2.5 github.com/prometheus/client_golang v1.23.2 github.com/shopspring/decimal v1.4.0 github.com/tech/sendico/pkg v0.1.0 @@ -24,7 +24,7 @@ require ( github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -46,7 +46,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect ) diff --git a/api/gateway/mntx/go.sum b/api/gateway/mntx/go.sum index 9c658f2c..aea5d3cd 100644 --- a/api/gateway/mntx/go.sum +++ b/api/gateway/mntx/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -193,8 +193,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/gateway/tgsettle/go.mod b/api/gateway/tgsettle/go.mod index 073b3bd4..c47607d5 100644 --- a/api/gateway/tgsettle/go.mod +++ b/api/gateway/tgsettle/go.mod @@ -20,9 +20,9 @@ require ( github.com/casbin/govaluate v1.10.0 // indirect github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -43,7 +43,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect ) diff --git a/api/gateway/tgsettle/go.sum b/api/gateway/tgsettle/go.sum index 4e3f9b6c..58daa9d4 100644 --- a/api/gateway/tgsettle/go.sum +++ b/api/gateway/tgsettle/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -191,8 +191,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/gateway/tron/go.mod b/api/gateway/tron/go.mod index 214b70d2..a59bd4bc 100644 --- a/api/gateway/tron/go.mod +++ b/api/gateway/tron/go.mod @@ -24,7 +24,7 @@ require ( require ( github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260204112742-a1cdb34ff7e1 // indirect + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260208002143-2551aa251e34 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect @@ -42,7 +42,7 @@ require ( github.com/deckarep/golang-set/v2 v2.8.0 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -57,7 +57,7 @@ require ( github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/hcl v1.0.1-vault-7 // indirect github.com/holiman/uint256 v1.3.2 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -89,7 +89,7 @@ require ( golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect diff --git a/api/gateway/tron/go.sum b/api/gateway/tron/go.sum index 7ba44d8e..47e7d856 100644 --- a/api/gateway/tron/go.sum +++ b/api/gateway/tron/go.sum @@ -6,8 +6,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260204112742-a1cdb34ff7e1 h1:LyoFl70WFSqEQSOky2dlIhjrm5bcliiM7v7e9Y7IFxc= -github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260204112742-a1cdb34ff7e1/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260208002143-2551aa251e34 h1:AyAPL6pTcPPpfZsNtOTFhxyOokKBLnrbbaV42g6Z9v0= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260208002143-2551aa251e34/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -96,8 +96,8 @@ github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeD github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -166,8 +166,8 @@ github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -360,8 +360,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/gateway/tron/internal/service/gateway/shared/network_registry.go b/api/gateway/tron/shared/network_registry.go similarity index 100% rename from api/gateway/tron/internal/service/gateway/shared/network_registry.go rename to api/gateway/tron/shared/network_registry.go diff --git a/api/ledger/go.mod b/api/ledger/go.mod index 6b39a633..bdc01bed 100644 --- a/api/ledger/go.mod +++ b/api/ledger/go.mod @@ -24,9 +24,9 @@ require ( github.com/casbin/mongodb-adapter/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -47,7 +47,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect ) diff --git a/api/ledger/go.sum b/api/ledger/go.sum index 7df11bbf..b9863090 100644 --- a/api/ledger/go.sum +++ b/api/ledger/go.sum @@ -38,8 +38,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -57,8 +57,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -193,8 +193,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/notification/go.mod b/api/notification/go.mod index bf1efdc6..c3fe6460 100644 --- a/api/notification/go.mod +++ b/api/notification/go.mod @@ -6,7 +6,7 @@ replace github.com/tech/sendico/pkg => ../pkg require ( github.com/amplitude/analytics-go v1.3.0 - github.com/go-chi/chi/v5 v5.2.4 + github.com/go-chi/chi/v5 v5.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/nicksnyder/go-i18n/v2 v2.6.1 github.com/sendgrid/sendgrid-go v3.16.1+incompatible @@ -27,7 +27,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/go-test/deep v1.1.1 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect @@ -49,7 +49,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/grpc v1.78.0 // indirect google.golang.org/protobuf v1.36.11 // indirect diff --git a/api/notification/go.sum b/api/notification/go.sum index db7bb242..b861aaea 100644 --- a/api/notification/go.sum +++ b/api/notification/go.sum @@ -42,8 +42,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -63,8 +63,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -208,8 +208,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/notification/internal/server/notificationimp/accountcreated.go b/api/notification/internal/server/notificationimp/accountcreated.go index a3b29d72..8a36bf07 100644 --- a/api/notification/internal/server/notificationimp/accountcreated.go +++ b/api/notification/internal/server/notificationimp/accountcreated.go @@ -7,10 +7,10 @@ import ( "go.uber.org/zap" ) -func (a *NotificationAPI) onAccount(context context.Context, account *model.Account) error { +func (a *NotificationAPI) onAccount(context context.Context, account *model.Account, token string) error { var link string var err error - if link, err = a.dp.GetFullLink("verify", account.VerifyToken); err != nil { + if link, err = a.dp.GetFullLink("verify", token); err != nil { a.logger.Warn("Failed to generate verification link", zap.Error(err), zap.String("login", account.Login)) return err } diff --git a/api/notification/internal/server/notificationimp/notification_test.go b/api/notification/internal/server/notificationimp/notification_test.go index 76fdbd61..c5052127 100644 --- a/api/notification/internal/server/notificationimp/notification_test.go +++ b/api/notification/internal/server/notificationimp/notification_test.go @@ -188,10 +188,9 @@ func TestOnAccount_ValidAccount_SendsWelcomeEmail(t *testing.T) { Locale: "en-US", }, }, - VerifyToken: "test-verify-token", } - err := api.onAccount(context.Background(), account) + err := api.onAccount(context.Background(), account, "test-verify-token") if err != nil { t.Fatalf("Unexpected error: %v", err) @@ -242,10 +241,9 @@ func TestOnAccount_LinkGenerationFails_ReturnsError(t *testing.T) { Locale: "en-US", }, }, - VerifyToken: "test-verify-token", } - err := api.onAccount(context.Background(), account) + err := api.onAccount(context.Background(), account, "test-verify-token") if err == nil { t.Fatal("Expected error from link generation failure") @@ -285,10 +283,9 @@ func TestOnAccount_SendFails_ReturnsError(t *testing.T) { Locale: "en-US", }, }, - VerifyToken: "test-verify-token", } - err := api.onAccount(context.Background(), account) + err := api.onAccount(context.Background(), account, "test-verify-token") if err == nil { t.Fatal("Expected error from send failure") diff --git a/api/payments/orchestrator/go.mod b/api/payments/orchestrator/go.mod index b6d088d3..b3fe0619 100644 --- a/api/payments/orchestrator/go.mod +++ b/api/payments/orchestrator/go.mod @@ -51,12 +51,12 @@ require ( github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-chi/chi/v5 v5.2.4 // indirect + github.com/go-chi/chi/v5 v5.2.5 // indirect 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/gogo/protobuf v1.3.2 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -104,7 +104,7 @@ require ( golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect ) diff --git a/api/payments/orchestrator/go.sum b/api/payments/orchestrator/go.sum index 21e480dd..a283d207 100644 --- a/api/payments/orchestrator/go.sum +++ b/api/payments/orchestrator/go.sum @@ -43,8 +43,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -70,8 +70,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnV github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -238,8 +238,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= diff --git a/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer.go b/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer.go index 3ef0c74d..76bb34fb 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer.go +++ b/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer.go @@ -196,6 +196,9 @@ func updateExecutionStepsFromGatewayExecution( } setExecutionStepStatus(execStep, status) + if exec.Error != "" && execStep.Error == "" { + execStep.Error = strings.TrimSpace(exec.Error) + } log.Debug("Execution step state updated", zap.Int("step_index", idx), diff --git a/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer_test.go b/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer_test.go index 131af30c..78b0ca79 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer_test.go +++ b/api/payments/orchestrator/internal/service/orchestrator/gateway_execution_consumer_test.go @@ -60,9 +60,17 @@ func TestGatewayExecutionRejectedFailsPayment(t *testing.T) { payment := &paymodel.Payment{ PaymentRef: "pi-2", State: paymodel.PaymentStateSubmitted, IdempotencyKey: "idem-1", + PaymentPlan: &paymodel.PaymentPlan{ + Steps: []*paymodel.PaymentStep{ + {StepID: "crypto_send"}, + }, + }, ExecutionPlan: &paymodel.ExecutionPlan{ Steps: []*paymodel.ExecutionStep{ - {OperationRef: "s1", State: paymodel.OperationStatePlanned, TransferRef: "trn-1"}}}} + {Code: "crypto_send", OperationRef: "s1", State: paymodel.OperationStateWaiting, TransferRef: "trn-1"}, + }, + }, + } if err := store.Create(context.Background(), payment); err != nil { t.Fatalf("failed to seed payment: %v", err) @@ -74,9 +82,11 @@ func TestGatewayExecutionRejectedFailsPayment(t *testing.T) { } exec := &model.PaymentGatewayExecution{ - PaymentRef: "pi-2", - TransferRef: "trn-1", - Status: rail.OperationResultFailed, + PaymentRef: "pi-2", + OperationRef: "s1", + TransferRef: "trn-1", + Status: rail.OperationResultFailed, + Error: "execution_plan_failed", } if err := svc.onGatewayExecution(context.Background(), exec); err != nil { diff --git a/api/payments/orchestrator/internal/service/orchestrator/payment_plan_executor.go b/api/payments/orchestrator/internal/service/orchestrator/payment_plan_executor.go index 51fdedf8..fddf1fd5 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/payment_plan_executor.go +++ b/api/payments/orchestrator/internal/service/orchestrator/payment_plan_executor.go @@ -165,6 +165,7 @@ func (p *paymentExecutor) pickIndependentSteps( if blocked { lg.Debug("Step permanently blocked by dependency failure") + setExecutionStepStatus(execStep, model.OperationStateCancelled) continue } diff --git a/api/payments/orchestrator/internal/service/orchestrator/payment_plan_release_test.go b/api/payments/orchestrator/internal/service/orchestrator/payment_plan_release_test.go index df232a33..a40ba343 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/payment_plan_release_test.go +++ b/api/payments/orchestrator/internal/service/orchestrator/payment_plan_release_test.go @@ -66,8 +66,8 @@ func TestReleasePaymentHold_RejectsLegacyLedgerRelease(t *testing.T) { store.payments[payment.PaymentRef] = payment - execPlan := ensureExecutionPlanForPlan(payment, payment.PaymentPlan) - steps := executionStepsByCode(execPlan) + payment.ExecutionPlan = ensureExecutionPlanForPlan(payment, payment.PaymentPlan) + steps := executionStepsByCode(payment.ExecutionPlan) blockStep := steps["ledger_block"] if blockStep == nil { t.Fatalf("expected block step in execution plan") diff --git a/api/pkg/api/http/response/response.go b/api/pkg/api/http/response/response.go index 55fea994..e76fba54 100644 --- a/api/pkg/api/http/response/response.go +++ b/api/pkg/api/http/response/response.go @@ -152,6 +152,12 @@ func BadRequest(logger mlogger.Logger, source mservice.Type, err, hint string) h } } +func Gone(logger mlogger.Logger, source mservice.Type, err, hint string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + errorf(logger, w, r, source, http.StatusGone, err, hint) + } +} + func BadQueryParam(logger mlogger.Logger, source mservice.Type, param string, err error) http.HandlerFunc { return BadRequest(logger, source, "invalid_query_parameter", fmt.Sprintf("Failed to parse '%s': %v", param, err)) } diff --git a/api/pkg/db/account/account.go b/api/pkg/db/account/account.go index fb705bda..22f6191c 100755 --- a/api/pkg/db/account/account.go +++ b/api/pkg/db/account/account.go @@ -12,6 +12,5 @@ import ( type DB interface { template.DB[*model.Account] GetByEmail(ctx context.Context, email string) (*model.Account, error) - GetByToken(ctx context.Context, email string) (*model.Account, error) GetAccountsByRefs(ctx context.Context, orgRef bson.ObjectID, refs []bson.ObjectID) ([]model.Account, error) } diff --git a/api/pkg/db/internal/mongo/accountdb/token.go b/api/pkg/db/internal/mongo/accountdb/token.go deleted file mode 100644 index d130b5a4..00000000 --- a/api/pkg/db/internal/mongo/accountdb/token.go +++ /dev/null @@ -1,13 +0,0 @@ -package accountdb - -import ( - "context" - - "github.com/tech/sendico/pkg/db/repository" - "github.com/tech/sendico/pkg/model" -) - -func (db *AccountDB) GetByToken(ctx context.Context, email string) (*model.Account, error) { - var account model.Account - return &account, db.FindOne(ctx, repository.Query().Filter(repository.Field("verifyToken"), email), &account) -} diff --git a/api/pkg/db/internal/mongo/verificationimp/consume.go b/api/pkg/db/internal/mongo/verificationimp/consume.go index 941cca91..61357905 100644 --- a/api/pkg/db/internal/mongo/verificationimp/consume.go +++ b/api/pkg/db/internal/mongo/verificationimp/consume.go @@ -6,7 +6,6 @@ import ( "time" "github.com/tech/sendico/pkg/db/repository" - "github.com/tech/sendico/pkg/db/repository/builder" "github.com/tech/sendico/pkg/db/verification" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/model" @@ -21,36 +20,45 @@ func (db *verificationDB) Consume( hash := tokenHash(rawToken) now := time.Now().UTC() - // 1) Пытаемся атомарно использовать токен + // 1) Find token by hash (do NOT filter by usedAt/expiresAt here), + // otherwise you can't distinguish "used/expired" from "not found". filter := repository.Query().And( repository.Filter("verifyTokenHash", hash), - repository.Filter("usedAt", nil), - repository.Query().Comparison(repository.Field("expiresAt"), builder.Gt, now), ) - t, err := db.tf.CreateTransaction().Execute( + t, e := db.tf.CreateTransaction().Execute( ct, func(ctx context.Context) (any, error) { var existing model.VerificationToken if err := db.DBImp.FindOne(ctx, filter, &existing); err != nil { if errors.Is(err, merrors.ErrNoData) { - // normal behaviour db.Logger.Debug("Token hash not found", zap.Error(err), zap.String("hash", hash)) - return nil, wrap(verification.ErrTokenNotFound, err.Error()) + return nil, verification.ErorrTokenNotFound() } db.Logger.Warn("Failed to check token", zap.Error(err), zap.String("hash", hash)) return nil, err } + + // 2) Semantic checks if existing.UsedAt != nil { - db.Logger.Debug("Token has already been used", zap.String("hash", hash), zap.Time("used_at", *existing.UsedAt)) - return nil, wrap(verification.ErrTokenAlreadyUsed, "db: token already used") + db.Logger.Debug( + "Token has already been used", + zap.String("hash", hash), + zap.Time("used_at", *existing.UsedAt), + ) + return nil, verification.ErorrTokenAlreadyUsed() } - if existing.ExpiresAt.Before(now) { - db.Logger.Debug("Token has already expired", zap.String("hash", hash), zap.Time("expired_at", existing.ExpiresAt)) - return nil, wrap(verification.ErrTokenExpired, "db: token expired") + if !existing.ExpiresAt.After(now) { // includes equal time edge-case + db.Logger.Debug( + "Token has already expired", + zap.String("hash", hash), + zap.Time("expired_at", existing.ExpiresAt), + ) + return nil, verification.ErorrTokenExpired() } + // 3) Mark as used existing.UsedAt = &now if err := db.DBImp.Update(ctx, &existing); err != nil { db.Logger.Warn("Failed to consume token", zap.Error(err), zap.String("hash", hash)) @@ -60,12 +68,13 @@ func (db *verificationDB) Consume( return &existing, nil }, ) - if err != nil { - return nil, err + if e != nil { + return nil, e } + res, ok := t.(*model.VerificationToken) if !ok { - return nil, merrors.Internal("unexpexted token type") + return nil, merrors.Internal("unexpected token type") } return res, nil diff --git a/api/pkg/db/internal/mongo/verificationimp/create.go b/api/pkg/db/internal/mongo/verificationimp/create.go index adf2133f..64666af8 100644 --- a/api/pkg/db/internal/mongo/verificationimp/create.go +++ b/api/pkg/db/internal/mongo/verificationimp/create.go @@ -6,6 +6,8 @@ import ( "encoding/base64" "time" + "github.com/tech/sendico/pkg/db/repository" + "github.com/tech/sendico/pkg/db/repository/builder" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mutil/mzap" "go.mongodb.org/mongo-driver/v2/bson" @@ -63,6 +65,26 @@ func (db *verificationDB) Create( return "", err } + // Invalidate any active tokens for the same (accountRef, purpose, target). + now := time.Now().UTC() + invalidated, err := db.DBImp.PatchMany(ctx, + repository.Query().And( + repository.Filter("accountRef", accountRef), + repository.Filter("purpose", purpose), + repository.Filter("target", target), + repository.Filter("usedAt", nil), + repository.Query().Comparison(repository.Field("expiresAt"), builder.Gt, now), + ), + repository.Patch().Set(repository.Field("usedAt"), now), + ) + if err != nil { + db.Logger.Warn("Failed to invalidate previous tokens", append(logFields, zap.Error(err))...) + return "", err + } + if invalidated > 0 { + db.Logger.Debug("Invalidated previous tokens", append(logFields, zap.Int("count", invalidated))...) + } + if err := db.DBImp.Create(ctx, token); err != nil { db.Logger.Warn("Failed to persist verification token", append(logFields, zap.Error(err))...) return "", err diff --git a/api/pkg/db/internal/mongo/verificationimp/error.go b/api/pkg/db/internal/mongo/verificationimp/error.go deleted file mode 100644 index f0d1bf67..00000000 --- a/api/pkg/db/internal/mongo/verificationimp/error.go +++ /dev/null @@ -1,7 +0,0 @@ -package verificationimp - -import "fmt" - -func wrap(err error, msg string) error { - return fmt.Errorf("%s: %w", msg, err) -} diff --git a/api/pkg/db/internal/mongo/verificationimp/verification_test.go b/api/pkg/db/internal/mongo/verificationimp/verification_test.go new file mode 100644 index 00000000..b519c7ca --- /dev/null +++ b/api/pkg/db/internal/mongo/verificationimp/verification_test.go @@ -0,0 +1,621 @@ +package verificationimp + +import ( + "context" + "errors" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tech/sendico/pkg/db/repository/builder" + rd "github.com/tech/sendico/pkg/db/repository/decoder" + ri "github.com/tech/sendico/pkg/db/repository/index" + "github.com/tech/sendico/pkg/db/storable" + "github.com/tech/sendico/pkg/db/template" + "github.com/tech/sendico/pkg/db/transaction" + "github.com/tech/sendico/pkg/db/verification" + "github.com/tech/sendico/pkg/merrors" + "github.com/tech/sendico/pkg/model" + "github.com/tech/sendico/pkg/mservice" + "go.mongodb.org/mongo-driver/v2/bson" + "go.uber.org/zap" +) + +// --------------------------------------------------------------------------- +// helpers +// --------------------------------------------------------------------------- + +func newTestVerificationDB(t *testing.T) *verificationDB { + t.Helper() + repo := newMemoryTokenRepository() + logger := zap.NewNop() + return &verificationDB{ + DBImp: template.DBImp[*model.VerificationToken]{ + Logger: logger, + Repository: repo, + }, + tf: &passthroughTxFactory{}, + } +} + +// passthroughTxFactory executes callbacks directly without a real transaction. +type passthroughTxFactory struct{} + +func (*passthroughTxFactory) CreateTransaction() transaction.Transaction { return &passthroughTx{} } + +type passthroughTx struct{} + +func (*passthroughTx) Execute(ctx context.Context, cb transaction.Callback) (any, error) { + return cb(ctx) +} + +// --------------------------------------------------------------------------- +// in-memory repository for VerificationToken +// --------------------------------------------------------------------------- + +type memoryTokenRepository struct { + mu sync.Mutex + data map[bson.ObjectID]*model.VerificationToken + order []bson.ObjectID + seq int +} + +func newMemoryTokenRepository() *memoryTokenRepository { + return &memoryTokenRepository{data: make(map[bson.ObjectID]*model.VerificationToken)} +} + +func (m *memoryTokenRepository) Insert(_ context.Context, obj storable.Storable, _ builder.Query) error { + m.mu.Lock() + defer m.mu.Unlock() + tok, ok := obj.(*model.VerificationToken) + if !ok { + return merrors.InvalidDataType("expected VerificationToken") + } + id := tok.GetID() + if id == nil || *id == bson.NilObjectID { + m.seq++ + tok.SetID(bson.NewObjectID()) + id = tok.GetID() + } + if _, exists := m.data[*id]; exists { + return merrors.DataConflict("token already exists") + } + m.data[*id] = cloneToken(tok) + m.order = append(m.order, *id) + return nil +} + +func (m *memoryTokenRepository) Get(_ context.Context, id bson.ObjectID, result storable.Storable) error { + m.mu.Lock() + defer m.mu.Unlock() + tok, ok := m.data[id] + if !ok { + return merrors.ErrNoData + } + dst := result.(*model.VerificationToken) + *dst = *cloneToken(tok) + return nil +} + +func (m *memoryTokenRepository) FindOneByFilter(_ context.Context, query builder.Query, result storable.Storable) error { + m.mu.Lock() + defer m.mu.Unlock() + for _, id := range m.order { + tok := m.data[id] + if tok != nil && matchToken(query, tok) { + dst := result.(*model.VerificationToken) + *dst = *cloneToken(tok) + return nil + } + } + return merrors.ErrNoData +} + +func (m *memoryTokenRepository) Update(_ context.Context, obj storable.Storable) error { + m.mu.Lock() + defer m.mu.Unlock() + tok := obj.(*model.VerificationToken) + id := tok.GetID() + if id == nil { + return merrors.InvalidArgument("id required") + } + if _, exists := m.data[*id]; !exists { + return merrors.ErrNoData + } + m.data[*id] = cloneToken(tok) + return nil +} + +func (m *memoryTokenRepository) PatchMany(_ context.Context, filter builder.Query, patch builder.Patch) (int, error) { + m.mu.Lock() + defer m.mu.Unlock() + patchDoc := patch.Build() + count := 0 + for _, id := range m.order { + tok := m.data[id] + if tok != nil && matchToken(filter, tok) { + applyPatch(tok, patchDoc) + count++ + } + } + return count, nil +} + +// stubs — not exercised by verification DB but required by the interface + +func (m *memoryTokenRepository) Aggregate(context.Context, builder.Pipeline, rd.DecodingFunc) error { + return merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) InsertMany(ctx context.Context, objs []storable.Storable) error { + for _, o := range objs { + if err := m.Insert(ctx, o, nil); err != nil { + return err + } + } + return nil +} +func (m *memoryTokenRepository) FindManyByFilter(context.Context, builder.Query, rd.DecodingFunc) error { + return merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) Patch(context.Context, bson.ObjectID, builder.Patch) error { + return merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) Delete(_ context.Context, id bson.ObjectID) error { + m.mu.Lock() + defer m.mu.Unlock() + delete(m.data, id) + return nil +} +func (m *memoryTokenRepository) DeleteMany(context.Context, builder.Query) error { + return merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) CreateIndex(*ri.Definition) error { return nil } +func (m *memoryTokenRepository) ListIDs(context.Context, builder.Query) ([]bson.ObjectID, error) { + return nil, merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) ListPermissionBound(context.Context, builder.Query) ([]model.PermissionBoundStorable, error) { + return nil, merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) ListAccountBound(context.Context, builder.Query) ([]model.AccountBoundStorable, error) { + return nil, merrors.NotImplemented("not needed") +} +func (m *memoryTokenRepository) Collection() string { return mservice.VerificationTokens } + +// --------------------------------------------------------------------------- +// bson.D query evaluation for VerificationToken +// --------------------------------------------------------------------------- + +// tokenFieldValue returns the stored value for a given BSON field name. +func tokenFieldValue(tok *model.VerificationToken, field string) any { + switch field { + case "verifyTokenHash": + return tok.VerifyTokenHash + case "usedAt": + return tok.UsedAt + case "expiresAt": + return tok.ExpiresAt + case "accountRef": + return tok.AccountRef + case "purpose": + return tok.Purpose + case "target": + return tok.Target + default: + return nil + } +} + +// matchToken evaluates a bson.D filter against a token. +func matchToken(query builder.Query, tok *model.VerificationToken) bool { + if query == nil { + return true + } + return matchBsonD(query.BuildQuery(), tok) +} + +func matchBsonD(filter bson.D, tok *model.VerificationToken) bool { + for _, elem := range filter { + if !matchElem(elem, tok) { + return false + } + } + return true +} + +func matchElem(elem bson.E, tok *model.VerificationToken) bool { + switch elem.Key { + + case "$and": + arr, ok := elem.Value.(bson.A) + if !ok { + return false + } + for _, sub := range arr { + d, ok := sub.(bson.D) + if !ok { + return false + } + if !matchBsonD(d, tok) { + return false + } + } + return true + + default: + // Either a direct field match or a comparison operator doc. + stored := tokenFieldValue(tok, elem.Key) + + // Check for operator document like {$gt: value} + if opDoc, ok := elem.Value.(bson.M); ok { + return matchOperator(stored, opDoc) + } + + // Direct equality (including nil check). + return valuesEqual(stored, elem.Value) + } +} + +func matchOperator(stored any, ops bson.M) bool { + for op, cmpVal := range ops { + switch op { + case "$gt": + if !timeGt(stored, cmpVal) { + return false + } + case "$lt": + if !timeLt(stored, cmpVal) { + return false + } + } + } + return true +} + +func valuesEqual(a, b any) bool { + // nil checks: usedAt == nil + if b == nil { + return a == nil || a == (*time.Time)(nil) + } + switch av := a.(type) { + case *time.Time: + if av == nil { + return b == nil + } + if bv, ok := b.(*time.Time); ok { + return av.Equal(*bv) + } + return false + case bson.ObjectID: + if bv, ok := b.(bson.ObjectID); ok { + return av == bv + } + return false + case model.VerificationPurpose: + if bv, ok := b.(model.VerificationPurpose); ok { + return av == bv + } + return false + case string: + if bv, ok := b.(string); ok { + return av == bv + } + return false + } + return false +} + +func timeGt(stored, cmpVal any) bool { + st, ok := toTime(stored) + if !ok { + return false + } + ct, ok := toTime(cmpVal) + if !ok { + return false + } + return st.After(ct) +} + +func timeLt(stored, cmpVal any) bool { + st, ok := toTime(stored) + if !ok { + return false + } + ct, ok := toTime(cmpVal) + if !ok { + return false + } + return st.Before(ct) +} + +func toTime(v any) (time.Time, bool) { + switch tv := v.(type) { + case time.Time: + return tv, true + case *time.Time: + if tv == nil { + return time.Time{}, false + } + return *tv, true + } + return time.Time{}, false +} + +// applyPatch applies $set operations from a patch bson.D to a token. +func applyPatch(tok *model.VerificationToken, patchDoc bson.D) { + for _, op := range patchDoc { + if op.Key != "$set" { + continue + } + fields, ok := op.Value.(bson.D) + if !ok { + continue + } + for _, f := range fields { + switch f.Key { + case "usedAt": + if t, ok := f.Value.(time.Time); ok { + tok.UsedAt = &t + } + } + } + } +} + +func cloneToken(src *model.VerificationToken) *model.VerificationToken { + dst := *src + if src.UsedAt != nil { + t := *src.UsedAt + dst.UsedAt = &t + } + return &dst +} + +// allTokens returns every stored token for inspection in tests. +func (m *memoryTokenRepository) allTokens() []*model.VerificationToken { + m.mu.Lock() + defer m.mu.Unlock() + out := make([]*model.VerificationToken, 0, len(m.data)) + for _, id := range m.order { + if tok, ok := m.data[id]; ok { + out = append(out, cloneToken(tok)) + } + } + return out +} + +// --------------------------------------------------------------------------- +// tests +// --------------------------------------------------------------------------- + +func TestCreate_ReturnsRawToken(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + raw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + assert.NotEmpty(t, raw) +} + +func TestCreate_TokenCanBeConsumed(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + raw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, raw) + require.NoError(t, err) + assert.Equal(t, accountRef, tok.AccountRef) + assert.Equal(t, model.PurposePasswordReset, tok.Purpose) + assert.NotNil(t, tok.UsedAt) +} + +func TestConsume_ReturnsCorrectFields(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + raw, err := db.Create(ctx, accountRef, model.PurposeEmailChange, "new@example.com", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, raw) + require.NoError(t, err) + assert.Equal(t, accountRef, tok.AccountRef) + assert.Equal(t, model.PurposeEmailChange, tok.Purpose) + assert.Equal(t, "new@example.com", tok.Target) +} + +func TestConsume_SecondConsumeFailsAlreadyUsed(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + raw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + _, err = db.Consume(ctx, raw) + require.NoError(t, err) + + _, err = db.Consume(ctx, raw) + require.Error(t, err) + assert.True(t, errors.Is(err, verification.ErrTokenAlreadyUsed), + "second consume should fail because usedAt is set") +} + +func TestConsume_ExpiredTokenFails(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + // Create with a TTL that is already in the past. + raw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", -time.Hour) + require.NoError(t, err) + + _, err = db.Consume(ctx, raw) + require.Error(t, err) + assert.True(t, errors.Is(err, verification.ErrTokenExpired), + "expired token should not be consumable") +} + +func TestConsume_UnknownTokenFails(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + + _, err := db.Consume(ctx, "nonexistent-token-value") + require.Error(t, err) + assert.True(t, errors.Is(err, verification.ErrTokenNotFound)) +} + +func TestCreate_InvalidatesPreviousToken(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + oldRaw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + newRaw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + assert.NotEqual(t, oldRaw, newRaw, "new token should differ from old one") + + // Old token is no longer consumable. + _, err = db.Consume(ctx, oldRaw) + require.Error(t, err) + assert.True(t, errors.Is(err, verification.ErrTokenAlreadyUsed), + "old token should be invalidated (usedAt set) after new token creation") + + // New token works fine. + tok, err := db.Consume(ctx, newRaw) + require.NoError(t, err) + assert.Equal(t, accountRef, tok.AccountRef) +} + +func TestCreate_InvalidatesMultiplePreviousTokens(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + first, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + second, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + third, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + _, err = db.Consume(ctx, first) + assert.True(t, errors.Is(err, verification.ErrTokenAlreadyUsed), "first should be invalidated") + _, err = db.Consume(ctx, second) + assert.True(t, errors.Is(err, verification.ErrTokenAlreadyUsed), "second should be invalidated") + + tok, err := db.Consume(ctx, third) + require.NoError(t, err) + assert.Equal(t, accountRef, tok.AccountRef) +} + +func TestCreate_DifferentPurposeNotInvalidated(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + resetRaw, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + // Creating an activation token should NOT invalidate the password-reset token. + _, err = db.Create(ctx, accountRef, model.PurposeAccountActivation, "", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, resetRaw) + require.NoError(t, err) + assert.Equal(t, model.PurposePasswordReset, tok.Purpose) +} + +func TestCreate_DifferentTargetNotInvalidated(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + firstRaw, err := db.Create(ctx, accountRef, model.PurposeEmailChange, "a@example.com", time.Hour) + require.NoError(t, err) + + // Creating a token for a different target email should NOT invalidate the first. + _, err = db.Create(ctx, accountRef, model.PurposeEmailChange, "b@example.com", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, firstRaw) + require.NoError(t, err) + assert.Equal(t, "a@example.com", tok.Target) +} + +func TestCreate_DifferentAccountNotInvalidated(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + account1 := bson.NewObjectID() + account2 := bson.NewObjectID() + + raw1, err := db.Create(ctx, account1, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + _, err = db.Create(ctx, account2, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, raw1) + require.NoError(t, err) + assert.Equal(t, account1, tok.AccountRef) +} + +func TestCreate_AlreadyUsedTokenNotInvalidatedAgain(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + // Create and consume first token. + raw1, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + _, err = db.Consume(ctx, raw1) + require.NoError(t, err) + + // Create second — the already-consumed token should have usedAt set, + // so the invalidation query (usedAt == nil) should skip it. + // This tests that the PatchMany filter correctly excludes already-used tokens. + raw2, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, raw2) + require.NoError(t, err) + assert.Equal(t, accountRef, tok.AccountRef) +} + +func TestCreate_ExpiredTokenNotInvalidated(t *testing.T) { + db := newTestVerificationDB(t) + ctx := context.Background() + accountRef := bson.NewObjectID() + + // Create a token that is already expired. + _, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", -time.Hour) + require.NoError(t, err) + + // Create a fresh one — invalidation should skip the expired token (expiresAt > now filter). + raw2, err := db.Create(ctx, accountRef, model.PurposePasswordReset, "", time.Hour) + require.NoError(t, err) + + tok, err := db.Consume(ctx, raw2) + require.NoError(t, err) + assert.Equal(t, accountRef, tok.AccountRef) +} + +func TestTokenHash_Deterministic(t *testing.T) { + h1 := tokenHash("same-input") + h2 := tokenHash("same-input") + assert.Equal(t, h1, h2) +} + +func TestTokenHash_DifferentInputs(t *testing.T) { + h1 := tokenHash("input-a") + h2 := tokenHash("input-b") + assert.NotEqual(t, h1, h2) +} diff --git a/api/pkg/db/verification/errors.go b/api/pkg/db/verification/errors.go new file mode 100644 index 00000000..0d0b50d1 --- /dev/null +++ b/api/pkg/db/verification/errors.go @@ -0,0 +1,28 @@ +package verification + +import ( + "errors" + "fmt" +) + +var ( + ErrTokenNotFound = errors.New("vtNotFound") + ErrTokenAlreadyUsed = errors.New("vtAlreadyUsed") + ErrTokenExpired = errors.New("vtExpired") +) + +func wrap(err error, msg string) error { + return fmt.Errorf("%w: %s", err, msg) +} + +func ErorrTokenNotFound() error { + return wrap(ErrTokenNotFound, "verification token not found") +} + +func ErorrTokenAlreadyUsed() error { + return wrap(ErrTokenAlreadyUsed, "verification token has already been used") +} + +func ErorrTokenExpired() error { + return wrap(ErrTokenExpired, "verification token expired") +} diff --git a/api/pkg/db/verification/verification.go b/api/pkg/db/verification/verification.go index a04e86eb..39606720 100644 --- a/api/pkg/db/verification/verification.go +++ b/api/pkg/db/verification/verification.go @@ -2,19 +2,12 @@ package verification import ( "context" - "errors" "time" "github.com/tech/sendico/pkg/model" "go.mongodb.org/mongo-driver/v2/bson" ) -var ( - ErrTokenNotFound = errors.New("verification token not found") - ErrTokenAlreadyUsed = errors.New("verification token already used") - ErrTokenExpired = errors.New("verification token expired") -) - type DB interface { // template.DB[*model.VerificationToken] Create( diff --git a/api/pkg/go.mod b/api/pkg/go.mod index d7053f8d..29e80fd1 100644 --- a/api/pkg/go.mod +++ b/api/pkg/go.mod @@ -5,7 +5,7 @@ go 1.24.0 require ( github.com/casbin/casbin/v2 v2.135.0 github.com/casbin/mongodb-adapter/v4 v4.3.0 - github.com/go-chi/chi/v5 v5.2.4 + github.com/go-chi/chi/v5 v5.2.5 github.com/google/uuid v1.6.0 github.com/mattn/go-colorable v0.1.14 github.com/mitchellh/mapstructure v1.5.0 @@ -45,7 +45,7 @@ require ( github.com/go-ole/go-ole v1.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -89,7 +89,7 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect diff --git a/api/pkg/go.sum b/api/pkg/go.sum index 3b2cb693..92f86cc9 100644 --- a/api/pkg/go.sum +++ b/api/pkg/go.sum @@ -43,8 +43,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -70,8 +70,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rH github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -242,8 +242,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= diff --git a/api/pkg/merrors/errors.go b/api/pkg/merrors/errors.go index 3deef52d..c8acd22d 100644 --- a/api/pkg/merrors/errors.go +++ b/api/pkg/merrors/errors.go @@ -32,7 +32,7 @@ func InvalidArgument(msg string, argumentNames ...string) error { return fmt.Errorf("%w: %s", ErrInvalidArg, invalidArgumentMessage(msg, argumentNames...)) } -var ErrDataConflict = errors.New("DataConflict") +var ErrDataConflict = errors.New("dataConflict") func DataConflict(msg string) error { return fmt.Errorf("%w: %s", ErrDataConflict, msg) diff --git a/api/pkg/messaging/internal/notifications/account/notification.go b/api/pkg/messaging/internal/notifications/account/notification.go index 363b078a..db957a3d 100644 --- a/api/pkg/messaging/internal/notifications/account/notification.go +++ b/api/pkg/messaging/internal/notifications/account/notification.go @@ -12,12 +12,14 @@ import ( type AccountNotification struct { messaging.Envelope - accountRef bson.ObjectID + accountRef bson.ObjectID + verificationToken string } func (acn *AccountNotification) Serialize() ([]byte, error) { var msg gmessaging.AccountCreatedEvent msg.AccountRef = acn.accountRef.Hex() + msg.VerificationToken = acn.verificationToken data, err := proto.Marshal(&msg) if err != nil { return nil, err @@ -29,9 +31,10 @@ func NewAccountNotification(action nm.NotificationAction) model.NotificationEven return model.NewNotification(mservice.Accounts, action) } -func NewAccountImp(sender string, accountRef bson.ObjectID, action nm.NotificationAction) messaging.Envelope { +func NewAccountImp(sender string, accountRef bson.ObjectID, action nm.NotificationAction, verificationToken string) messaging.Envelope { return &AccountNotification{ - Envelope: messaging.CreateEnvelope(sender, NewAccountNotification(action)), - accountRef: accountRef, + Envelope: messaging.CreateEnvelope(sender, NewAccountNotification(action)), + accountRef: accountRef, + verificationToken: verificationToken, } } diff --git a/api/pkg/messaging/internal/notifications/account/processor.go b/api/pkg/messaging/internal/notifications/account/processor.go index 1abb07f1..f580238e 100644 --- a/api/pkg/messaging/internal/notifications/account/processor.go +++ b/api/pkg/messaging/internal/notifications/account/processor.go @@ -34,12 +34,13 @@ func (acnp *AccoountNotificaionProcessor) Process(ctx context.Context, envelope acnp.logger.Warn("Failed to restore object ID", zap.Error(err), zap.String("topic", acnp.event.ToString()), zap.String("account_ref", msg.AccountRef)) return err } + verificationToken := msg.GetVerificationToken() var account model.Account if err := acnp.db.Get(ctx, accountRef, &account); err != nil { acnp.logger.Warn("Failed to fetch account", zap.Error(err), zap.String("topic", acnp.event.ToString()), zap.String("account_ref", msg.AccountRef)) return err } - return acnp.handler(ctx, &account) + return acnp.handler(ctx, &account, verificationToken) } func (acnp *AccoountNotificaionProcessor) GetSubject() model.NotificationEvent { diff --git a/api/pkg/messaging/internal/notifications/notification/notification.go b/api/pkg/messaging/internal/notifications/notification/notification.go index 04c14dd1..3f92d058 100644 --- a/api/pkg/messaging/internal/notifications/notification/notification.go +++ b/api/pkg/messaging/internal/notifications/notification/notification.go @@ -1,8 +1,8 @@ package notifications import ( - messaging "github.com/tech/sendico/pkg/messaging/envelope" gmessaging "github.com/tech/sendico/pkg/generated/gmessaging" + messaging "github.com/tech/sendico/pkg/messaging/envelope" "github.com/tech/sendico/pkg/model" nm "github.com/tech/sendico/pkg/model/notification" "github.com/tech/sendico/pkg/mservice" @@ -16,10 +16,10 @@ type NResultNotification struct { func (nrn *NResultNotification) Serialize() ([]byte, error) { msg := gmessaging.NotificationSentEvent{ - UserID: nrn.result.UserID, + UserId: nrn.result.UserID, Channel: nrn.result.Channel, Locale: nrn.result.Locale, - TemplateID: nrn.result.TemplateID, + TemplateId: nrn.result.TemplateID, Status: &gmessaging.OperationResult{ IsSuccessful: nrn.result.Result.IsSuccessful, ErrorDescription: nrn.result.Result.Error, diff --git a/api/pkg/messaging/internal/notifications/notification/processor.go b/api/pkg/messaging/internal/notifications/notification/processor.go index fae0d0c1..a7627773 100644 --- a/api/pkg/messaging/internal/notifications/notification/processor.go +++ b/api/pkg/messaging/internal/notifications/notification/processor.go @@ -3,8 +3,8 @@ package notifications import ( "context" - me "github.com/tech/sendico/pkg/messaging/envelope" gmessaging "github.com/tech/sendico/pkg/generated/gmessaging" + me "github.com/tech/sendico/pkg/messaging/envelope" nh "github.com/tech/sendico/pkg/messaging/notifications/notification/handler" np "github.com/tech/sendico/pkg/messaging/notifications/processor" "github.com/tech/sendico/pkg/mlogger" @@ -27,10 +27,10 @@ func (nrp *NResultNotificaionProcessor) Process(ctx context.Context, envelope me } nresult := &model.NotificationResult{ AmpliEvent: model.AmpliEvent{ - UserID: msg.UserID, + UserID: msg.UserId, }, Channel: msg.Channel, - TemplateID: msg.TemplateID, + TemplateID: msg.TemplateId, Locale: msg.Locale, Result: model.OperationResult{ IsSuccessful: msg.Status.IsSuccessful, diff --git a/api/pkg/messaging/notifications/account/created.go b/api/pkg/messaging/notifications/account/created.go index fed5a6cb..183c74c4 100644 --- a/api/pkg/messaging/notifications/account/created.go +++ b/api/pkg/messaging/notifications/account/created.go @@ -7,10 +7,10 @@ import ( "go.mongodb.org/mongo-driver/v2/bson" ) -func Account(sender string, accountRef bson.ObjectID, action nm.NotificationAction) messaging.Envelope { - return an.NewAccountImp(sender, accountRef, action) +func Account(sender string, accountRef bson.ObjectID, action nm.NotificationAction, verificationToken string) messaging.Envelope { + return an.NewAccountImp(sender, accountRef, action, verificationToken) } -func AccountCreated(sender string, accountRef bson.ObjectID) messaging.Envelope { - return Account(sender, accountRef, nm.NACreated) +func AccountCreated(sender string, accountRef bson.ObjectID, verificationToken string) messaging.Envelope { + return Account(sender, accountRef, nm.NACreated, verificationToken) } diff --git a/api/pkg/messaging/notifications/account/handler/interface.go b/api/pkg/messaging/notifications/account/handler/interface.go index e6b7533b..d9c86544 100644 --- a/api/pkg/messaging/notifications/account/handler/interface.go +++ b/api/pkg/messaging/notifications/account/handler/interface.go @@ -6,6 +6,6 @@ import ( "github.com/tech/sendico/pkg/model" ) -type AccountHandler = func(context.Context, *model.Account) error +type AccountHandler = func(context.Context, *model.Account, string) error type PasswordResetHandler = func(context.Context, *model.Account, string) error diff --git a/api/pkg/model/account.go b/api/pkg/model/account.go index 48dbb829..f05352aa 100755 --- a/api/pkg/model/account.go +++ b/api/pkg/model/account.go @@ -1,8 +1,6 @@ package model import ( - "time" - "github.com/tech/sendico/pkg/db/storable" "github.com/tech/sendico/pkg/mservice" "go.mongodb.org/mongo-driver/v2/bson" @@ -11,6 +9,14 @@ import ( type Filter int +type AccountStatus string + +const ( + AccountPendingVerification AccountStatus = "pending_verification" + AccountActive AccountStatus = "active" + AccountBlocked AccountStatus = "blocked" +) + type AccountBase struct { storable.Base `bson:",inline" json:",inline"` ArchivableBase `bson:",inline" json:",inline"` @@ -29,10 +35,21 @@ type AccountPublic struct { } type Account struct { - AccountPublic `bson:",inline" json:",inline"` - EmailBackup string `bson:"emailBackup" json:"-"` - Password string `bson:"password" json:"-"` // password hash - EmailVerifiedAt *time.Time `bson:"emailVerifiedAt,omitempty" json:"-"` + AccountPublic `bson:",inline" json:",inline"` + Password string `bson:"password" json:"-"` // password hash + Status AccountStatus `bson:"status" json:"-"` +} + +func (a *Account) Copy() *Account { + return &Account{ + AccountPublic: a.AccountPublic, + Password: a.Password, + Status: a.Status, + } +} + +func (a *Account) IsActive() bool { + return a.Status == AccountActive } func (a *Account) HashPassword() error { diff --git a/api/proto/account_created.proto b/api/proto/account_created.proto index 07d27ddb..bcf2b449 100644 --- a/api/proto/account_created.proto +++ b/api/proto/account_created.proto @@ -3,5 +3,6 @@ syntax = "proto3"; option go_package = "github.com/tech/sendico/pkg/generated/gmessaging"; message AccountCreatedEvent { - string AccountRef = 1; + string account_ref = 1; + string verification_token = 2; } diff --git a/api/proto/notification_sent.proto b/api/proto/notification_sent.proto index 59ad9b17..04205982 100644 --- a/api/proto/notification_sent.proto +++ b/api/proto/notification_sent.proto @@ -5,9 +5,9 @@ option go_package = "github.com/tech/sendico/pkg/generated/gmessaging"; import "operation_result.proto"; message NotificationSentEvent { - string UserID = 1; - string TemplateID = 2; - string Channel = 3; - string Locale = 4; - OperationResult Status = 5; + string user_id = 1; + string template_id = 2; + string channel = 3; + string locale = 4; + OperationResult status = 5; } diff --git a/api/proto/object_updated.proto b/api/proto/object_updated.proto index 5e6ae6e7..8ed84a9f 100644 --- a/api/proto/object_updated.proto +++ b/api/proto/object_updated.proto @@ -3,6 +3,6 @@ syntax = "proto3"; option go_package = "github.com/tech/sendico/pkg/generated/gmessaging"; message ObjectUpdatedEvent { - string ObjectRef = 1; - string ActorAccountRef = 2; + string object_ref = 1; + string actor_account_ref = 2; } diff --git a/api/proto/operation_result.proto b/api/proto/operation_result.proto index b0ccd2cf..a7be7364 100644 --- a/api/proto/operation_result.proto +++ b/api/proto/operation_result.proto @@ -3,6 +3,6 @@ syntax = "proto3"; option go_package = "github.com/tech/sendico/pkg/generated/gmessaging"; message OperationResult { - bool IsSuccessful = 1; - string ErrorDescription = 2; + bool is_successful = 1; + string error_description = 2; } \ No newline at end of file diff --git a/api/proto/password_reset.proto b/api/proto/password_reset.proto index 90b94aef..f3a2ac63 100644 --- a/api/proto/password_reset.proto +++ b/api/proto/password_reset.proto @@ -3,6 +3,6 @@ syntax = "proto3"; option go_package = "github.com/tech/sendico/pkg/generated/gmessaging"; message PasswordResetEvent { - string AccountRef = 1; - string ResetToken = 2; + string account_ref = 1; + string reset_token = 2; } \ No newline at end of file diff --git a/api/server/go.mod b/api/server/go.mod index 56d6c872..080cdacb 100644 --- a/api/server/go.mod +++ b/api/server/go.mod @@ -15,7 +15,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.32.7 github.com/aws/aws-sdk-go-v2/credentials v1.19.7 github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 - github.com/go-chi/chi/v5 v5.2.4 + github.com/go-chi/chi/v5 v5.2.5 github.com/go-chi/cors v1.2.2 github.com/go-chi/jwtauth/v5 v5.3.3 github.com/go-chi/metrics v0.1.1 @@ -84,7 +84,7 @@ require ( github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect @@ -136,7 +136,7 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/crypto v0.47.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.33.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect ) diff --git a/api/server/go.sum b/api/server/go.sum index 7c73e5b2..d64b3d30 100644 --- a/api/server/go.sum +++ b/api/server/go.sum @@ -88,8 +88,8 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= -github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= -github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= +github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE= github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/jwtauth/v5 v5.3.3 h1:50Uzmacu35/ZP9ER2Ht6SazwPsnLQ9LRJy6zTZJpHEo= @@ -123,8 +123,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnV github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -332,8 +332,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= diff --git a/api/server/interface/accountservice/internal/service.go b/api/server/interface/accountservice/internal/service.go index 051788b9..5364e57f 100644 --- a/api/server/interface/accountservice/internal/service.go +++ b/api/server/interface/accountservice/internal/service.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "slices" + "time" "unicode" "github.com/tech/sendico/pkg/auth" @@ -13,13 +14,12 @@ import ( "github.com/tech/sendico/pkg/db/account" "github.com/tech/sendico/pkg/db/organization" "github.com/tech/sendico/pkg/db/policy" - "github.com/tech/sendico/pkg/db/transaction" + "github.com/tech/sendico/pkg/db/verification" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mutil/mzap" "github.com/tech/sendico/server/interface/middleware" - "github.com/tech/sendico/server/internal/mutil/flrstring" "go.mongodb.org/mongo-driver/v2/bson" "go.uber.org/zap" ) @@ -31,9 +31,9 @@ type service struct { enforcer auth.Enforcer roleManager management.Role config *middleware.PasswordConfig - tf transaction.Factory policyDB policy.DB + vdb verification.DB } func validateUserRequest(u *model.Account) error { @@ -112,7 +112,6 @@ func (s *service) ValidateAccount(acct *model.Account) error { return err } - acct.VerifyToken = flrstring.CreateRandString(s.config.TokenLength) return nil } @@ -121,32 +120,50 @@ func (s *service) CreateAccount( org *model.Organization, acct *model.Account, roleDescID bson.ObjectID, -) error { +) (string, error) { if org == nil { - return merrors.InvalidArgument("Organization must not be nil") + return "", merrors.InvalidArgument("Organization must not be nil") } if acct == nil || len(acct.Login) == 0 { - return merrors.InvalidArgument("Account must have a non-empty login") + return "", merrors.InvalidArgument("Account must have a non-empty login") } if roleDescID == bson.NilObjectID { - return merrors.InvalidArgument("Role description must be provided") + return "", merrors.InvalidArgument("Role description must be provided") } + // 1) Create the account + acct.Status = model.AccountPendingVerification if err := s.accountDB.Create(ctx, acct); err != nil { if errors.Is(err, merrors.ErrDataConflict) { s.logger.Info("Username is already taken", zap.String("login", acct.Login)) } else { s.logger.Warn("Failed to signup a user", zap.Error(err), zap.String("login", acct.Login)) } - return err + return "", err } // 2) Add to organization if err := s.JoinOrganization(ctx, org, acct, roleDescID); err != nil { s.logger.Warn("Failed to register new organization member", zap.Error(err), mzap.StorableRef(acct)) - return err + return "", err } - return nil + + // 3) Issue verification token + return s.VerifyAccount(ctx, acct) +} + +func (s *service) VerifyAccount( + ctx context.Context, + acct *model.Account, +) (verificationToken string, err error) { + verificationToken, err = s.vdb.Create(ctx, *acct.GetID(), model.PurposeAccountActivation, "", time.Duration(time.Hour*24)) + if err != nil { + s.logger.Warn("Failed to create verification token for new account", zap.Error(err), mzap.StorableRef(acct)) + return "", err + } + + return verificationToken, nil + } func (s *service) DeleteAccount( @@ -213,20 +230,16 @@ func (s *service) RemoveAccountFromOrganization( func (s *service) ResetPassword( ctx context.Context, acct *model.Account, -) error { - acct.ResetPasswordToken = flrstring.CreateRandString(s.config.TokenLength) - return s.accountDB.Update(ctx, acct) +) (string, error) { + return s.vdb.Create(ctx, *acct.GetID(), model.PurposePasswordReset, "", time.Duration(time.Hour*1)) } func (s *service) UpdateLogin( ctx context.Context, acct *model.Account, newLogin string, -) error { - acct.EmailBackup = acct.Login - acct.Login = newLogin - acct.VerifyToken = flrstring.CreateRandString(s.config.TokenLength) - return s.accountDB.Update(ctx, acct) +) (string, error) { + return s.vdb.Create(ctx, *acct.GetID(), model.PurposeEmailChange, newLogin, time.Duration(time.Hour*1)) } func (s *service) JoinOrganization( @@ -311,27 +324,19 @@ func (s *service) DeleteOrganization( s.logger.Info("Starting organization deletion", mzap.StorableRef(org)) // Use transaction to ensure atomicity - _, err := s.tf.CreateTransaction().Execute(ctx, func(ctx context.Context) (any, error) { - // 8. Delete all roles and role descriptions in the organization - if err := s.deleteOrganizationRoles(ctx, org.ID); err != nil { - return nil, err - } + // 8. Delete all roles and role descriptions in the organization + if err := s.deleteOrganizationRoles(ctx, org.ID); err != nil { + return err + } - // 9. Delete all policies in the organization - if err := s.deleteOrganizationPolicies(ctx, org.ID); err != nil { - return nil, err - } + // 9. Delete all policies in the organization + if err := s.deleteOrganizationPolicies(ctx, org.ID); err != nil { + return err + } - // 10. Finally, delete the organization itself - if err := s.orgDB.Delete(ctx, bson.NilObjectID, org.ID); err != nil { - s.logger.Warn("Failed to delete organization", zap.Error(err), mzap.StorableRef(org)) - return nil, err - } - - return nil, nil - }) - if err != nil { - s.logger.Error("Failed to delete organization", zap.Error(err), mzap.StorableRef(org)) + // 10. Finally, delete the organization itself + if err := s.orgDB.Delete(ctx, bson.NilObjectID, org.ID); err != nil { + s.logger.Warn("Failed to delete organization", zap.Error(err), mzap.StorableRef(org)) return err } @@ -347,23 +352,14 @@ func (s *service) DeleteAll( s.logger.Info("Starting complete deletion (organization + account)", mzap.StorableRef(org), mzap.ObjRef("account_ref", accountRef)) - // Use transaction to ensure atomicity - _, err := s.tf.CreateTransaction().Execute(ctx, func(ctx context.Context) (any, error) { - // 1. First delete the organization and all its data - if err := s.DeleteOrganization(ctx, org); err != nil { - return nil, err - } + // 1. First delete the organization and all its data + if err := s.DeleteOrganization(ctx, org); err != nil { + return err + } - // 2. Then delete the account - if err := s.accountDB.Delete(ctx, accountRef); err != nil { - s.logger.Warn("Failed to delete account", zap.Error(err), mzap.ObjRef("account_ref", accountRef)) - return nil, err - } - - return nil, nil - }) - if err != nil { - s.logger.Error("Failed to delete all data", zap.Error(err), mzap.StorableRef(org), mzap.ObjRef("account_ref", accountRef)) + // 2. Then delete the account + if err := s.accountDB.Delete(ctx, accountRef); err != nil { + s.logger.Warn("Failed to delete account", zap.Error(err), mzap.ObjRef("account_ref", accountRef)) return err } @@ -390,7 +386,6 @@ func NewAccountService( enforcer: enforcer, roleManager: ra, config: config, - tf: dbf.TransactionFactory(), } var err error if res.accountDB, err = dbf.NewAccountDB(); err != nil { @@ -407,6 +402,9 @@ func NewAccountService( logger.Warn("Failed to create policies database", zap.Error(err)) return nil, err } - + if res.vdb, err = dbf.NewVerificationsDB(); err != nil { + logger.Warn("Failed to create verification database", zap.Error(err)) + return nil, err + } return res, nil } diff --git a/api/server/interface/accountservice/internal/service_test.go b/api/server/interface/accountservice/internal/service_test.go index 55708676..5c676f61 100644 --- a/api/server/interface/accountservice/internal/service_test.go +++ b/api/server/interface/accountservice/internal/service_test.go @@ -113,8 +113,6 @@ func TestValidateAccount(t *testing.T) { // Password should be hashed after validation assert.NotEqual(t, originalPassword, account.Password) - assert.NotEmpty(t, account.VerifyToken) - assert.Equal(t, config.TokenLength, len(account.VerifyToken)) }) t.Run("AccountMissingName", func(t *testing.T) { @@ -245,54 +243,3 @@ func TestPasswordConfiguration(t *testing.T) { }) } -// TestTokenGeneration verifies that verification tokens are generated with correct length -func TestTokenGeneration(t *testing.T) { - testCases := []struct { - name string - tokenLength int - }{ - {"Short", 8}, - {"Medium", 32}, - {"Long", 64}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - config := &apiconfig.PasswordConfig{ - Check: apiconfig.PasswordChecks{ - MinLength: 8, - Digit: true, - Upper: true, - Lower: true, - Special: true, - }, - TokenLength: tc.tokenLength, - } - - logger := zap.NewNop() // Use no-op logger for tests - service := &service{ - config: config, - logger: logger, - } - - account := &model.Account{ - AccountPublic: model.AccountPublic{ - AccountBase: model.AccountBase{ - Describable: model.Describable{ - Name: "Test User", - }, - }, - UserDataBase: model.UserDataBase{ - Login: "test@example.com", - }, - }, - Password: "TestPassword123!", - } - - err := service.ValidateAccount(account) - require.NoError(t, err) - - assert.Equal(t, tc.tokenLength, len(account.VerifyToken)) - }) - } -} diff --git a/api/server/interface/accountservice/types.go b/api/server/interface/accountservice/types.go index 243f7ce3..154cc95b 100644 --- a/api/server/interface/accountservice/types.go +++ b/api/server/interface/accountservice/types.go @@ -35,7 +35,7 @@ type AccountService interface { ResetPassword( ctx context.Context, acct *model.Account, - ) error + ) (verificationToken string, err error) // CreateAccount will: // 1) create the account @@ -46,7 +46,12 @@ type AccountService interface { org *model.Organization, acct *model.Account, roleDescID bson.ObjectID, - ) error + ) (verificationToken string, err error) + + VerifyAccount( + ctx context.Context, + acct *model.Account, + ) (verificationToken string, err error) JoinOrganization( ctx context.Context, @@ -59,7 +64,7 @@ type AccountService interface { ctx context.Context, acct *model.Account, newLogin string, - ) error + ) (verificationToken string, err error) // DeleteAccount deletes the account and removes it from the org. DeleteAccount( diff --git a/api/server/internal/api/routers/public/login.go b/api/server/internal/api/routers/public/login.go index ab7c5de3..e6da0423 100644 --- a/api/server/internal/api/routers/public/login.go +++ b/api/server/internal/api/routers/public/login.go @@ -33,7 +33,7 @@ func (pr *PublicRouter) logUserIn(ctx context.Context, _ *http.Request, req *sre return response.Internal(pr.logger, pr.service, err) } - if account.VerifyToken != "" { + if !account.IsActive() { return response.Forbidden(pr.logger, pr.service, "account_not_verified", "Account verification required") } diff --git a/api/server/internal/server/accountapiimp/account.go b/api/server/internal/server/accountapiimp/account.go index df623b41..f968a01e 100755 --- a/api/server/internal/server/accountapiimp/account.go +++ b/api/server/internal/server/accountapiimp/account.go @@ -43,12 +43,8 @@ func (a *AccountAPI) getProfile(_ *http.Request, u *model.Account, token *srespo return sresponse.Account(a.logger, u, token) } -func (a *AccountAPI) reportTokenNotFound() http.HandlerFunc { - return response.NotFound(a.logger, a.Name(), "No account found associated with given verifcation token") -} - -func (a *AccountAPI) sendWelcomeEmail(account *model.Account) error { - if err := a.producer.SendMessage(an.AccountCreated(a.Name(), *account.GetID())); err != nil { +func (a *AccountAPI) sendWelcomeEmail(account *model.Account, token string) error { + if err := a.producer.SendMessage(an.AccountCreated(a.Name(), *account.GetID(), token)); err != nil { a.logger.Warn("Failed to send account creation notification", zap.Error(err)) return err } @@ -63,27 +59,23 @@ func (a *AccountAPI) sendVerificationMail(r *http.Request, paramGetter func(ctx return response.Internal(a.logger, a.Name(), err) } - // Get the account - // accnt, err := a.db.GetByEmail(ctx, paramGetter(u)) - // if err != nil || accnt == nil { - // a.logger.Warn("Failed to ger user from db with", zap.Error(err), mzap.StorableRef(u)) - // return response.Internal(a.logger, a.Name(), err) - // } - accnt, err := paramGetter(r.Context(), a.db, u) + ctx := r.Context() + accnt, err := paramGetter(ctx, a.db, u) if err != nil || accnt == nil { a.logger.Warn("Failed to ger user from db with", zap.Error(err), mzap.StorableRef(u)) return response.Internal(a.logger, a.Name(), err) } - if accnt.VerifyToken == "" { - a.logger.Debug("Verification token is empty", zap.Error(err), mzap.StorableRef(u)) - return a.reportTokenNotFound() + token, err := a.accService.VerifyAccount(ctx, accnt) + if err != nil { + a.logger.Warn("Failed to create verification token for account", zap.Error(err), mzap.StorableRef(accnt)) + return response.Internal(a.logger, a.Name(), err) } // Send welcome email - if err = a.sendWelcomeEmail(accnt); err != nil { + if err = a.sendWelcomeEmail(accnt, token); err != nil { a.logger.Warn("Failed to send verification email", - zap.Error(err), mzap.StorableRef(u), zap.String("email", accnt.Login)) + zap.Error(err), mzap.StorableRef(accnt), zap.String("email", accnt.Login)) return response.Internal(a.logger, a.Name(), err) } return response.Success(a.logger) diff --git a/api/server/internal/server/accountapiimp/delete.go b/api/server/internal/server/accountapiimp/delete.go index 29b0986a..94239332 100644 --- a/api/server/internal/server/accountapiimp/delete.go +++ b/api/server/internal/server/accountapiimp/delete.go @@ -1,6 +1,7 @@ package accountapiimp import ( + "context" "errors" "net/http" @@ -108,8 +109,14 @@ func (a *AccountAPI) deleteAll(r *http.Request, account *model.Account, token *s } // Delete everything (organization + account) - if err := a.accService.DeleteAll(ctx, &org, account.ID); err != nil { - a.logger.Error("Failed to delete all data", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account)) + if _, err := a.tf.CreateTransaction().Execute(ctx, func(c context.Context) (any, error) { + if err := a.accService.DeleteAll(c, &org, account.ID); err != nil { + a.logger.Warn("Failed to delete all data", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account)) + return nil, err + } + return nil, nil + }); err != nil { + a.logger.Warn("Failed to execute delete transaction", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account)) return response.Auto(a.logger, a.Name(), err) } diff --git a/api/server/internal/server/accountapiimp/email.go b/api/server/internal/server/accountapiimp/email.go index ca2beab6..e42be28f 100644 --- a/api/server/internal/server/accountapiimp/email.go +++ b/api/server/internal/server/accountapiimp/email.go @@ -6,6 +6,7 @@ import ( "github.com/tech/sendico/pkg/api/http/response" "github.com/tech/sendico/pkg/merrors" + "github.com/tech/sendico/pkg/model" mutil "github.com/tech/sendico/server/internal/mutil/param" "go.uber.org/zap" ) @@ -15,19 +16,30 @@ func (a *AccountAPI) verify(r *http.Request) http.HandlerFunc { token := mutil.GetToken(r) // Get user ctx := r.Context() - user, err := a.db.GetByToken(ctx, token) - if errors.Is(err, merrors.ErrNoData) { - a.logger.Debug("Verification token not found", zap.Error(err)) - return a.reportTokenNotFound() - } + // Delete verification token to confirm account + t, err := a.vdb.Consume(ctx, token) if err != nil { + a.logger.Debug("Failed to consume verification token", zap.Error(err)) + return a.mapTokenErrorToResponse(err) + } + + if t.Purpose != model.PurposeAccountActivation { + a.logger.Warn("Invalid token purpose", zap.String("expected", string(model.PurposeAccountActivation)), zap.String("actual", string(t.Purpose))) + return response.DataConflict(a.logger, a.Name(), "Invalid token purpose") + } + + var user model.Account + if err := a.db.Get(ctx, t.AccountRef, &user); err != nil { + if errors.Is(err, merrors.ErrNoData) { + a.logger.Debug("Verified user not found", zap.Error(err)) + return response.NotFound(a.logger, a.Name(), "User not found") + } a.logger.Warn("Failed to fetch account", zap.Error(err)) return response.Internal(a.logger, a.Name(), err) } - // Delete verification token to confirm account - user.VerifyToken = "" - if err = a.db.Update(ctx, user); err != nil { + user.Status = model.AccountActive + if err = a.db.Update(ctx, &user); err != nil { a.logger.Warn("Failed to save account while verifying account", zap.Error(err)) return response.Internal(a.logger, a.Name(), err) } diff --git a/api/server/internal/server/accountapiimp/empupdate.go b/api/server/internal/server/accountapiimp/empupdate.go index a0f32c02..1cc6f997 100644 --- a/api/server/internal/server/accountapiimp/empupdate.go +++ b/api/server/internal/server/accountapiimp/empupdate.go @@ -55,7 +55,8 @@ func (a *AccountAPI) updateEmployee(r *http.Request, account *model.Account, tok } if acc.Login != u.Login { // Change email address - if err := a.accService.UpdateLogin(ctx, &acc, u.Login); err != nil { + verificationToken, err := a.accService.UpdateLogin(ctx, &acc, u.Login) + if err != nil { if errors.Is(err, merrors.ErrDataConflict) { a.logger.Debug("Duplicate login, denying change...", zap.Error(err), mzap.ObjRef("employee_ref", u.ID)) return a.reportDuplicateEmail() @@ -65,7 +66,7 @@ func (a *AccountAPI) updateEmployee(r *http.Request, account *model.Account, tok } // Send verification email - if err = a.sendWelcomeEmail(&acc); err != nil { + if err = a.sendWelcomeEmail(&acc, verificationToken); err != nil { a.logger.Warn("Failed to send verification email", zap.Error(err), mzap.StorableRef(&acc)) return response.Internal(a.logger, a.Name(), err) } diff --git a/api/server/internal/server/accountapiimp/password.go b/api/server/internal/server/accountapiimp/password.go index 601b7f30..f635ce25 100644 --- a/api/server/internal/server/accountapiimp/password.go +++ b/api/server/internal/server/accountapiimp/password.go @@ -84,13 +84,14 @@ func (a *AccountAPI) forgotPassword(r *http.Request) http.HandlerFunc { } // Generate reset password token - if err := a.accService.ResetPassword(ctx, user); err != nil { + verificationToken, err := a.accService.ResetPassword(ctx, user) + if err != nil { a.logger.Warn("Failed to generate reset password token", zap.Error(err), mzap.StorableRef(user)) return response.Auto(a.logger, a.Name(), err) } // Send reset password email - if err = a.sendPasswordResetEmail(user, user.ResetPasswordToken); err != nil { + if err = a.sendPasswordResetEmail(user, verificationToken); err != nil { a.logger.Warn("Failed to send reset password email", zap.Error(err), mzap.StorableRef(user)) return response.Auto(a.logger, a.Name(), err) } @@ -127,15 +128,20 @@ func (a *AccountAPI) resetPassword(r *http.Request) http.HandlerFunc { return response.Auto(a.logger, a.Name(), err) } - // Validate reset token - if user.ResetPasswordToken == "" { - a.logger.Debug("No reset token found for user", mzap.StorableRef(&user)) - return response.BadRequest(a.logger, a.Name(), "no_reset_token", "No password reset token found for this user") + t, err := a.vdb.Consume(ctx, token) + if err != nil { + a.logger.Warn("Failed to consume password reset token", zap.Error(err), zap.String("token", token)) + return a.mapTokenErrorToResponse(err) } - if user.ResetPasswordToken != token { - a.logger.Debug("Reset token mismatch", mzap.StorableRef(&user)) - return response.BadRequest(a.logger, a.Name(), "invalid_token", "Invalid or expired reset token") + if t.Purpose != model.PurposePasswordReset { + a.logger.Warn("Invalid token purpose for password reset", zap.String("expected", string(model.PurposePasswordReset)), zap.String("actual", string(t.Purpose))) + return response.DataConflict(a.logger, a.Name(), "Invalid token purpose") + } + + if t.AccountRef != accountRef { + a.logger.Warn("Token account reference does not match request account reference", zap.String("token_account_ref", t.AccountRef.Hex()), zap.String("request_account_ref", accountRef.Hex())) + return response.DataConflict(a.logger, a.Name(), "Token does not match account") } // Parse new password from request body @@ -145,11 +151,6 @@ func (a *AccountAPI) resetPassword(r *http.Request) http.HandlerFunc { return response.BadPayload(a.logger, a.Name(), err) } - if req.Password == "" { - a.logger.Debug("New password is empty") - return response.BadRequest(a.logger, a.Name(), "empty_password", "New password cannot be empty") - } - // Validate new password if err := a.accService.ValidatePassword(req.Password, nil); err != nil { a.logger.Debug("Password validation failed", zap.Error(err), mzap.StorableRef(&user)) @@ -172,7 +173,6 @@ func (a *AccountAPI) resetPassword(r *http.Request) http.HandlerFunc { func (a *AccountAPI) resetPasswordTransactionBody(ctx context.Context, user *model.Account, newPassword string) (any, error) { // Update user with new password and clear reset token user.Password = newPassword - user.ResetPasswordToken = "" // Clear the token after use // Hash the new password if err := user.HashPassword(); err != nil { diff --git a/api/server/internal/server/accountapiimp/password_test.go b/api/server/internal/server/accountapiimp/password_test.go index 130752c5..9ade83ab 100644 --- a/api/server/internal/server/accountapiimp/password_test.go +++ b/api/server/internal/server/accountapiimp/password_test.go @@ -4,92 +4,9 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/tech/sendico/pkg/model" "go.mongodb.org/mongo-driver/v2/bson" ) -// TestPasswordResetTokenGeneration tests the token generation logic -func TestPasswordResetTokenGeneration(t *testing.T) { - // Test that ResetPassword service method generates a token - account := &model.Account{ - AccountPublic: model.AccountPublic{ - AccountBase: model.AccountBase{ - Describable: model.Describable{ - Name: "Test User", - }, - }, - UserDataBase: model.UserDataBase{ - Login: "test@example.com", - }, - }, - } - - // Initially no reset token - assert.Empty(t, account.ResetPasswordToken, "Account should not have reset token initially") - - // Simulate what ResetPassword service method does - account.ResetPasswordToken = "generated-token-123" - assert.NotEmpty(t, account.ResetPasswordToken, "Reset token should be generated") - assert.Equal(t, "generated-token-123", account.ResetPasswordToken, "Reset token should match generated value") -} - -// TestPasswordResetTokenValidation tests token validation logic -func TestPasswordResetTokenValidation(t *testing.T) { - tests := []struct { - name string - storedToken string - providedToken string - shouldBeValid bool - }{ - { - name: "ValidToken_ShouldMatch", - storedToken: "valid-token-123", - providedToken: "valid-token-123", - shouldBeValid: true, - }, - { - name: "InvalidToken_ShouldNotMatch", - storedToken: "valid-token-123", - providedToken: "invalid-token-456", - shouldBeValid: false, - }, - { - name: "EmptyStoredToken_ShouldBeInvalid", - storedToken: "", - providedToken: "any-token", - shouldBeValid: false, - }, - { - name: "EmptyProvidedToken_ShouldBeInvalid", - storedToken: "valid-token-123", - providedToken: "", - shouldBeValid: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - account := &model.Account{ - AccountPublic: model.AccountPublic{ - AccountBase: model.AccountBase{ - Describable: model.Describable{ - Name: "Test User", - }, - }, - UserDataBase: model.UserDataBase{ - Login: "test@example.com", - }, - }, - ResetPasswordToken: tt.storedToken, - } - - // Test token validation logic (what the resetPassword handler does) - isValid := account.ResetPasswordToken != "" && account.ResetPasswordToken == tt.providedToken - assert.Equal(t, tt.shouldBeValid, isValid, "Token validation should match expected result") - }) - } -} - // TestPasswordResetFlowLogic tests the logical flow without database dependencies func TestPasswordResetFlowLogic(t *testing.T) { t.Run("CompleteFlow", func(t *testing.T) { diff --git a/api/server/internal/server/accountapiimp/service.go b/api/server/internal/server/accountapiimp/service.go index 2ba2f8fc..76bdfba7 100644 --- a/api/server/internal/server/accountapiimp/service.go +++ b/api/server/internal/server/accountapiimp/service.go @@ -15,6 +15,7 @@ import ( "github.com/tech/sendico/pkg/db/policy" "github.com/tech/sendico/pkg/db/refreshtokens" "github.com/tech/sendico/pkg/db/transaction" + "github.com/tech/sendico/pkg/db/verification" "github.com/tech/sendico/pkg/domainprovider" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/messaging" @@ -36,6 +37,7 @@ type AccountAPI struct { tf transaction.Factory rtdb refreshtokens.DB plcdb policy.DB + vdb verification.DB domain domainprovider.DomainProvider avatars mservice.MicroService producer messaging.Producer @@ -91,6 +93,10 @@ func CreateAPI(a eapi.API) (*AccountAPI, error) { p.logger.Error("Failed to create policies database", zap.Error(err)) return nil, err } + if p.vdb, err = a.DBFactory().NewVerificationsDB(); err != nil { + p.logger.Error("Failed to create verification database", zap.Error(err)) + return nil, err + } p.domain = a.DomainProvider() p.producer = a.Register().Messaging().Producer() diff --git a/api/server/internal/server/accountapiimp/signup.go b/api/server/internal/server/accountapiimp/signup.go index 631b33ee..532cf703 100644 --- a/api/server/internal/server/accountapiimp/signup.go +++ b/api/server/internal/server/accountapiimp/signup.go @@ -91,7 +91,8 @@ func (a *AccountAPI) signup(r *http.Request) http.HandlerFunc { return response.BadPayload(a.logger, a.Name(), res) } - if err := a.executeSignupTransaction(r.Context(), &sr, newAccount); err != nil { + verificationToken, err := a.executeSignupTransaction(r.Context(), &sr, newAccount) + if err != nil { if errors.Is(err, merrors.ErrDataConflict) { a.logger.Warn("Failed to register account", zap.Error(err), zap.String("login", newAccount.Login)) return response.DataConflict(a.logger, "user_already_registered", "User has already been registered") @@ -100,7 +101,7 @@ func (a *AccountAPI) signup(r *http.Request) http.HandlerFunc { return response.Internal(a.logger, a.Name(), err) } - if err := a.sendWelcomeEmail(newAccount); err != nil { + if err := a.sendWelcomeEmail(newAccount, verificationToken); err != nil { a.logger.Warn("Failed to send welcome email", zap.Error(err), mzap.StorableRef(newAccount)) } @@ -127,11 +128,14 @@ func (a *AccountAPI) signupAvailability(r *http.Request) http.HandlerFunc { } } -func (a *AccountAPI) executeSignupTransaction(ctxt context.Context, sr *srequest.Signup, newAccount *model.Account) error { - _, err := a.tf.CreateTransaction().Execute(ctxt, func(ctx context.Context) (any, error) { +func (a *AccountAPI) executeSignupTransaction(ctxt context.Context, sr *srequest.Signup, newAccount *model.Account) (string, error) { + res, err := a.tf.CreateTransaction().Execute(ctxt, func(ctx context.Context) (any, error) { return a.signupTransactionBody(ctx, sr, newAccount) }) - return err + if token, ok := res.(string); token != "" || ok { + return token, err + } + return "", err } func (a *AccountAPI) signupTransactionBody(ctx context.Context, sr *srequest.Signup, newAccount *model.Account) (any, error) { @@ -165,13 +169,14 @@ func (a *AccountAPI) signupTransactionBody(ctx context.Context, sr *srequest.Sig } a.logger.Info("Organization owner role permissions granted", mzap.StorableRef(org), zap.String("account", sr.Account.Login)) - if err := a.accService.CreateAccount(ctx, org, newAccount, roleDescription.ID); err != nil { + token, err := a.accService.CreateAccount(ctx, org, newAccount, roleDescription.ID) + if err != nil { a.logger.Warn("Failed to create account", zap.Error(err), zap.String("login", newAccount.Login)) return nil, err } a.logger.Info("Organization owner account registered", mzap.StorableRef(org), zap.String("account", sr.Account.Login)) - return nil, nil + return token, nil } func (a *AccountAPI) grantAllPermissions(ctx context.Context, organizationRef bson.ObjectID, roleID bson.ObjectID, newAccount *model.Account) error { diff --git a/api/server/internal/server/accountapiimp/token.go b/api/server/internal/server/accountapiimp/token.go new file mode 100644 index 00000000..6a10f681 --- /dev/null +++ b/api/server/internal/server/accountapiimp/token.go @@ -0,0 +1,31 @@ +package accountapiimp + +import ( + "errors" + "net/http" + + "github.com/tech/sendico/pkg/api/http/response" + "github.com/tech/sendico/pkg/db/verification" + "go.uber.org/zap" +) + +func (a *AccountAPI) mapTokenErrorToResponse(err error) http.HandlerFunc { + if errors.Is(err, verification.ErrTokenNotFound) { + a.logger.Debug("Verification token not found during consume", zap.Error(err)) + return response.NotFound(a.logger, a.Name(), "No account found associated with given verifcation token") + } + if errors.Is(err, verification.ErrTokenExpired) { + a.logger.Debug("Verification token expired during consume", zap.Error(err)) + return response.Gone(a.logger, a.Name(), "token_expired", "verification token has expired") + } + if errors.Is(err, verification.ErrTokenAlreadyUsed) { + a.logger.Debug("Verification token already used during consume", zap.Error(err)) + return response.DataConflict(a.logger, a.Name(), "verification token has already been used") + } + if err != nil { + a.logger.Warn("Uenxpected error during token verification", zap.Error(err)) + return response.Auto(a.logger, a.Name(), err) + } + a.logger.Debug("No token verification error found") + return response.Success(a.logger) +} diff --git a/api/server/internal/server/accountapiimp/update.go b/api/server/internal/server/accountapiimp/update.go index 6236ab3b..0dadaef9 100644 --- a/api/server/internal/server/accountapiimp/update.go +++ b/api/server/internal/server/accountapiimp/update.go @@ -31,7 +31,8 @@ func (a *AccountAPI) updateProfile(r *http.Request, account *model.Account, toke if account.Login != u.Login { // Change email address - if err := a.accService.UpdateLogin(ctx, account, u.Login); err != nil { + verificationToken, err := a.accService.UpdateLogin(ctx, account, u.Login) + if err != nil { if errors.Is(err, merrors.ErrDataConflict) { a.logger.Debug("Duplicate login, denying change...", zap.Error(err), mzap.StorableRef(u)) return a.reportDuplicateEmail() @@ -41,7 +42,7 @@ func (a *AccountAPI) updateProfile(r *http.Request, account *model.Account, toke } // Send verification email - if err = a.sendWelcomeEmail(account); err != nil { + if err = a.sendWelcomeEmail(account, verificationToken); err != nil { a.logger.Warn("Failed to send verification email", zap.Error(err), mzap.StorableRef(account)) return response.Internal(a.logger, a.Name(), err) } @@ -49,8 +50,7 @@ func (a *AccountAPI) updateProfile(r *http.Request, account *model.Account, toke } else { // Save the user u.Password = account.Password - u.ResetPasswordToken = account.ResetPasswordToken - u.VerifyToken = account.VerifyToken + u.Status = account.Status if err = a.db.Update(ctx, u); err != nil { a.logger.Warn("Failed to save account", zap.Error(err), mzap.StorableRef(u)) return response.Internal(a.logger, a.Name(), err) diff --git a/api/server/internal/server/invitationimp/accept.go b/api/server/internal/server/invitationimp/accept.go index 58cc8d20..7705feee 100644 --- a/api/server/internal/server/invitationimp/accept.go +++ b/api/server/internal/server/invitationimp/accept.go @@ -8,6 +8,7 @@ import ( "github.com/tech/sendico/pkg/api/http/response" "github.com/tech/sendico/pkg/merrors" + an "github.com/tech/sendico/pkg/messaging/notifications/account" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mutil/mzap" "github.com/tech/sendico/server/interface/api/srequest" @@ -38,6 +39,14 @@ func (a *InvitationAPI) doAccept(ctx context.Context, invitationRef bson.ObjectI return nil } +func (a *InvitationAPI) sendWelcomeEmail(account *model.Account, token string) error { + if err := a.producer.SendMessage(an.AccountCreated(a.Name(), *account.GetID(), token)); err != nil { + a.Logger.Warn("Failed to send account creation notification", zap.Error(err)) + return err + } + return nil +} + func (a *InvitationAPI) getPendingInvitation(ctx context.Context, invitationRef bson.ObjectID) (*model.Invitation, error) { a.Logger.Debug("Fetching invitation", mzap.ObjRef("invitation_ref", invitationRef)) var inv model.Invitation @@ -79,10 +88,17 @@ func (a *InvitationAPI) fetchOrCreateAccount(ctx context.Context, org *model.Org return nil, err } // creates account and joins organization - if err := a.accService.CreateAccount(ctx, org, account, inv.RoleRef); err != nil { + token, err := a.accService.CreateAccount(ctx, org, account, inv.RoleRef) + if err != nil { a.Logger.Warn("Failed to create account", zap.Error(err), zap.String("email", inv.Content.Email)) return nil, err } + // Send welcome email + if err = a.sendWelcomeEmail(account, token); err != nil { + a.Logger.Warn("Failed to send welcome email for new account created via invitation", + zap.Error(err), zap.String("email", inv.Content.Email)) + return nil, err + } return account, nil } else if err != nil { a.Logger.Warn("Failed to fetch account by email", zap.Error(err), zap.String("email", inv.Content.Email)) diff --git a/api/server/internal/server/invitationimp/service.go b/api/server/internal/server/invitationimp/service.go index ec755ce8..380afa2c 100644 --- a/api/server/internal/server/invitationimp/service.go +++ b/api/server/internal/server/invitationimp/service.go @@ -8,6 +8,7 @@ import ( "github.com/tech/sendico/pkg/db/invitation" "github.com/tech/sendico/pkg/db/organization" "github.com/tech/sendico/pkg/db/transaction" + "github.com/tech/sendico/pkg/messaging" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" "github.com/tech/sendico/server/interface/accountservice" @@ -25,6 +26,7 @@ type InvitationAPI struct { adb account.DB odb organization.DB accService accountservice.AccountService + producer messaging.Producer } func (a *InvitationAPI) Name() mservice.Type { @@ -41,8 +43,9 @@ func CreateAPI(a eapi.API) (*InvitationAPI, error) { } res := &InvitationAPI{ - irh: mutil.CreatePH("invitation"), - tf: a.DBFactory().TransactionFactory(), + irh: mutil.CreatePH("invitation"), + tf: a.DBFactory().TransactionFactory(), + producer: a.Register().Messaging().Producer(), } p, err := papitemplate.CreateAPI(a, dbFactory, mservice.Organizations, mservice.Invitations) diff --git a/ci/dev/.air.toml b/ci/dev/.air.toml index 16f8c34b..c607b2c3 100644 --- a/ci/dev/.air.toml +++ b/ci/dev/.air.toml @@ -7,13 +7,13 @@ tmp_dir = "tmp" entrypoint = "./tmp/main" cmd = "go build -o ./tmp/main ." delay = 1000 - exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_dir = ["assets", "tmp", "vendor", "testdata", "storage"] exclude_file = [] exclude_regex = ["_test.go", "_templ.go"] exclude_unchanged = false follow_symlink = false full_bin = "" - include_dir = [] + include_dir = ["/src/api/pkg"] include_ext = ["go", "tpl", "tmpl", "html"] include_file = [] kill_delay = "0s" diff --git a/ci/dev/bff.dockerfile b/ci/dev/bff.dockerfile index ca14ce7b..61355c54 100644 --- a/ci/dev/bff.dockerfile +++ b/ci/dev/bff.dockerfile @@ -17,7 +17,7 @@ RUN bash ci/scripts/proto/generate.sh # Copy service dependencies (needed for go.mod replace directives) COPY api/ledger ./api/ledger COPY api/payments/orchestrator ./api/payments/orchestrator -COPY api/gateway/chain ./api/gateway/chain +COPY api/gateway/tron ./api/gateway/tron COPY api/billing/fees ./api/billing/fees COPY api/fx/oracle ./api/fx/oracle COPY api/fx/storage ./api/fx/storage @@ -38,7 +38,7 @@ COPY --from=builder /src/api/pkg ./api/pkg # Copy service dependencies COPY --from=builder /src/api/ledger ./api/ledger COPY --from=builder /src/api/payments/orchestrator ./api/payments/orchestrator -COPY --from=builder /src/api/gateway/chain ./api/gateway/chain +COPY --from=builder /src/api/gateway/tron ./api/gateway/tron COPY --from=builder /src/api/billing/fees ./api/billing/fees COPY --from=builder /src/api/fx/oracle ./api/fx/oracle COPY --from=builder /src/api/fx/storage ./api/fx/storage