|
@@ -41,4 +48,4 @@
-
\ No newline at end of file
+
diff --git a/console/src/app/pages/iam/iam-views/iam-views.component.ts b/console/src/app/pages/iam/iam-views/iam-views.component.ts
index 343649a372..c1f07a3fb5 100644
--- a/console/src/app/pages/iam/iam-views/iam-views.component.ts
+++ b/console/src/app/pages/iam/iam-views/iam-views.component.ts
@@ -21,7 +21,7 @@ export class IamViewsComponent implements AfterViewInit {
@ViewChild(MatPaginator) public paginator!: MatPaginator;
public dataSource!: MatTableDataSource;
- public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'timestamp', 'actions'];
+ public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'eventTimestamp', 'lastSuccessfulSpoolerRun', 'actions'];
private loadingSubject: BehaviorSubject = new BehaviorSubject(false);
public loading$: Observable = this.loadingSubject.asObservable();
diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json
index 4feeac9ab1..a003ec328b 100644
--- a/console/src/assets/i18n/de.json
+++ b/console/src/assets/i18n/de.json
@@ -164,8 +164,8 @@
"OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.",
"TYPE": {
"0":"Keine MFA definiert",
- "1":"SMS",
- "2":"OTP"
+ "1":"OTP",
+ "2":"U2F"
},
"STATE": {
"0": "Kein Status",
@@ -392,7 +392,8 @@
"VIEWNAME":"Name",
"DATABASE":"Datenbank",
"SEQUENCE":"Sequenz",
- "TIMESTAMP":"Zeitstempel",
+ "EVENTTIMESTAMP":"Event Zeitstempel",
+ "LASTSPOOL": "Erfolgreicher Durchlauf",
"ACTIONS":"Aktionen",
"CLEAR":"Aufräumen",
"CLEARED":"View wurde erfolgreich zurückgesetzt!",
diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json
index 9fa4a9e2cc..b4f01ba663 100644
--- a/console/src/assets/i18n/en.json
+++ b/console/src/assets/i18n/en.json
@@ -164,8 +164,8 @@
"OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.",
"TYPE": {
"0": "No MFA defined",
- "1": "SMS",
- "2": "OTP"
+ "1": "OTP",
+ "2": "U2F"
},
"STATE": {
"0": "No State",
@@ -392,7 +392,8 @@
"VIEWNAME":"Name",
"DATABASE":"Database",
"SEQUENCE":"Sequence",
- "TIMESTAMP":"Timestamp",
+ "EVENTTIMESTAMP":"Timestamp",
+ "LASTSPOOL": "Successful spool",
"ACTIONS":"Actions",
"CLEAR":"Clear",
"CLEARED":"View was successfully cleared!",
diff --git a/go.mod b/go.mod
index e17500909b..88c19e2625 100644
--- a/go.mod
+++ b/go.mod
@@ -15,14 +15,16 @@ require (
github.com/allegro/bigcache v1.2.1
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
github.com/caos/logging v0.0.2
- github.com/caos/oidc v0.13.0
+ github.com/caos/oidc v0.13.1
github.com/cockroachdb/cockroach-go/v2 v2.0.8
+ github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43
github.com/envoyproxy/protoc-gen-validate v0.4.1
github.com/ghodss/yaml v1.0.0
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.4.3
github.com/golang/snappy v0.0.2 // indirect
+ github.com/google/go-cmp v0.5.3 // indirect
github.com/gorilla/csrf v1.7.0
github.com/gorilla/mux v1.8.0
github.com/gorilla/schema v1.2.0
@@ -45,6 +47,8 @@ require (
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.1.1
github.com/pquerna/otp v1.2.0
+ github.com/prometheus/client_golang v1.8.0 // indirect
+ github.com/prometheus/common v0.15.0 // indirect
github.com/rakyll/statik v0.1.7
github.com/rs/cors v1.7.0
github.com/sony/sonyflake v1.0.0
@@ -54,12 +58,13 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0
go.opentelemetry.io/otel v0.13.0
+ go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0
go.opentelemetry.io/otel/exporters/otlp v0.13.0
go.opentelemetry.io/otel/exporters/stdout v0.13.0
go.opentelemetry.io/otel/sdk v0.13.0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
- golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 // indirect
+ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
golang.org/x/text v0.3.4
golang.org/x/tools v0.0.0-20201103235415-b653051172e4
google.golang.org/appengine v1.6.7 // indirect
diff --git a/go.sum b/go.sum
index bbed0c03a4..4a327f6ca0 100644
--- a/go.sum
+++ b/go.sum
@@ -57,6 +57,7 @@ github.com/DataDog/sketches-go v0.0.1 h1:RtG+76WKgZuz6FIaGsjoPePmadDBkuD/KC6+ZWu
github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v0.13.0 h1:fjKUtfldCPIF4nIzAAj3LzP8Lrd3DuRIMiFdOsj4fLc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v0.13.0/go.mod h1:q/paYxLXKVhwfC3lzLfhtL54fAx14wzMN9DundQOBMc=
+github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg=
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
@@ -65,10 +66,19 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
+github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
+github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb h1:EVl3FJLQCzSbgBezKo/1A4ADnJ4mtJZ0RvnNzDJ44nY=
github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc=
github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
@@ -76,31 +86,67 @@ github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5z
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo=
github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
-github.com/caos/oidc v0.13.0 h1:l1IKrqV3HaS2TfseuC5kOR3DdEPfY9AbJXuZ7dsIEQo=
-github.com/caos/oidc v0.13.0/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY=
+github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0=
+github.com/caos/oidc v0.13.1 h1:8890xd3XJpev5xuU4Dn2l49c1lCA3Qd1xu4KsPSVo38=
+github.com/caos/oidc v0.13.1/go.mod h1:dLvfYUiAt9ORfl77L/KkcWuR/N0ll8Ry1nD2ERsamDY=
+github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
+github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
+github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig=
+github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go/v2 v2.0.8 h1:50C/7ptrrfdxDccCjDU0xsdeBca+S0/AYW4Mo8RyzFE=
github.com/cockroachdb/cockroach-go/v2 v2.0.8/go.mod h1:nkf7rUmgPdawp3EwRjXIumihI2AYg9usGNWbJ2hsJqI=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -108,8 +154,19 @@ github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9r
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 h1:eEEfwrmEwl0LVuWz/VkAefdgtPbX174Huu5dxxceihI=
+github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43/go.mod h1:/X2OJiJxjQ7alqWZqX9EtBTmZc+4qQ0LvZ1k5wP67RM=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
@@ -117,22 +174,44 @@ github.com/envoyproxy/protoc-gen-validate v0.4.1 h1:7dLaJvASGRD7X49jSCSXXHwKPm0Z
github.com/envoyproxy/protoc-gen-validate v0.4.1/go.mod h1:E+IEazqdaWv3FrnGtZIu3b9fPFMK8AzeTTrk9SfVwWs=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
+github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ=
+github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -140,6 +219,7 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZ
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
@@ -149,6 +229,7 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
@@ -162,30 +243,49 @@ github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=
+github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo=
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
+github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0 h1:pMen7vLs8nvgEYhywH3KDWJIJTeEr2ULsVWHWYHQyBs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -194,34 +294,69 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99 h1:Ak8CrdlwwXwAZxzS66vgPt4U8yUZX7JwLvVR58FN5jM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3 h1:eHv/jVY/JNop1xg2J9cBb4EzyMpWZoNCP1BslSAIkOI=
github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3/go.mod h1:h/KNeRx7oYU4SpA4SoY7W2/NxDKEEVuwA6j9A27L4OI=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y=
github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
+github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk=
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
@@ -232,34 +367,49 @@ github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM=
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
+github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.5.0 h1:oFSOilzIZkyg787M1fEmyMfOUUvwj0daqYMfaWwNL4o=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.1 h1:Rdjp4NFjwHnEslx2b66FfCI2S0LhO4itac3hXz6WX9M=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8 h1:Q3tB+ExeflWUW7AFcAhXqk40s9mnNYLk1nOkKNZ5GnU=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.3.0 h1:l8JvKrby3RI7Kg3bYEeU9TA4vqC38QDpFCfcrC7KuN0=
github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik=
+github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.6.0 h1:Fh0O9GdlG4gYpjpwOqjdEodJUQM9jzN3Hdv7PN0xmm0=
github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.0 h1:musOWczZC/rSbqut475Vfcczg7jJsdUQf0D6oKPLgNU=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
@@ -268,9 +418,21 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a h1:Z7+SSApKiwPjNic+NF9+j7h657Uyvdp/jA3iTKhpj4E=
github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a/go.mod h1:/Pk5i/SqYdYv1cie5wGwoZ4P6TpgMi+Yf58mtJSHdOw=
github.com/kevinburke/go.uuid v1.2.0 h1:+1qP8NdkJfgOSTrrrUuA7h0djr1VY77HFXYjR+zUcUo=
@@ -279,20 +441,25 @@ github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 h1:KpuDJTaTPQAyWqE
github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8/go.mod h1:pD+iEcdAGVXld5foVN4e24zb/6fnb60tgZPZ3P/3T/I=
github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac h1:qQ7NAZEHpTyDfmZBH79KEiH3OK47Z+KvYVSR4sS3650=
github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac/go.mod h1:Fm9alkN1/LPVY1eqD/psyMwPWE4VWl4P01/nTYZKzBk=
+github.com/kisielk/errcheck v1.1.0 h1:ZqfnKyx9KGpRcW04j5nnPDgRgoXUeLh2YFBeFzphcA0=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -300,85 +467,213 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
+github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
+github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
+github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
+github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
+github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
+github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
+github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nicksnyder/go-i18n/v2 v2.1.1 h1:ATCOanRDlrfKVB4WHAdJnLEqZtDmKYsweqsOUYflnBU=
github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
+github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
+github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
+github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
+github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
+github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM=
+github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
+github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea h1:jaXWVFZ98/ihXniiDzqNXQgMSgklX4kjfDWZTE3ZtdU=
github.com/shopspring/decimal v0.0.0-20200419222939-1884f454f8ea/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4=
github.com/spf13/afero v1.3.3 h1:p5gZEKLYoL7wh8VrJesMaYeNxdEd1v3cb4irOk9zB54=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.3.4 h1:8q6vk3hthlpb2SouZcnBVKboxWQWMDNF38bwholZrJc=
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
+github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
github.com/ttacon/libphonenumber v1.1.0 h1:tC6kE4t8UI4OqQVQjW5q8gSWhG2wnY5moEpSEORdYm4=
github.com/ttacon/libphonenumber v1.1.0/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32 h1:5tjfNdR2ki3yYQ842+eX2sQHeiwpKJ0RnHO4IYOc4V8=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4 h1:LYy1Hy3MJdrCdMwwzxA/dRok4ejH+RwNGbuoD9fCjto=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
@@ -390,6 +685,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0 h1:dnZy1af
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0/go.mod h1:SeQm4RTCcZ2/hlMSTuHb7nwIROe5odBtgfKx+7MMqEs=
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
+go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0 h1:Jf7AdsEoHKtNTWxXLj/g9XGjsGpdk0otEf0lx00r2Ps=
+go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0/go.mod h1:Tyh3ACxU9a1tu1mF4at7xvNu+BaiPThrr5XZmsoIW7g=
go.opentelemetry.io/otel/exporters/otlp v0.13.0 h1:iithmYmMAfLFgCW5TcRXHpXR5NTWO7nGtX3WcBiusVE=
go.opentelemetry.io/otel/exporters/otlp v0.13.0/go.mod h1:YHH58UrGcqCKtBkY7sl3zPKpxBzfC1HUUYMRQONJJ9E=
go.opentelemetry.io/otel/exporters/stdout v0.13.0 h1:A+XiGIPQbGoJoBOJfKAKnZyiUSjSWvL3XWETUvtom5k=
@@ -397,19 +694,33 @@ go.opentelemetry.io/otel/exporters/stdout v0.13.0/go.mod h1:JJt8RpNY6K+ft9ir3iKp
go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ=
go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -422,9 +733,11 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -434,28 +747,38 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -467,16 +790,22 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -486,6 +815,7 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
@@ -494,16 +824,26 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -517,8 +857,11 @@ golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab h1:FvshnhkKW+LO3HWHodML8kuVX8rnJTxKm9dFPuI68UM=
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -526,30 +869,41 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck=
-golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -557,9 +911,11 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@@ -568,6 +924,8 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -575,16 +933,19 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56 h1:DFtSed2q3HtNuVazwVDZ4nSRS/JrZEig0gz2BY4VNrg=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -595,6 +956,7 @@ golang.org/x/tools v0.0.0-20200701151220-7cb253f4c4f8/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201030143252-cf7a54d06671/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -604,9 +966,11 @@ golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -617,19 +981,28 @@ google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0 h1:J1Pl9P2lnmYFSJvgs70DKELqHNh8CNWXPbud4njEE2s=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0 h1:cG03eaksBzhfSIk7JRGctfp3lanklcOM/mTGvow7BbQ=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0 h1:jMF5hhVfMkTZwHW1SDpKq5CkgWLXOb31Foaca9Zr3oM=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0 h1:BaiDisFir8O4IJxvAabCGGkQ6yCJegNQqSVoYUNAnbk=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0 h1:yfrXXP61wVuLb0vBcG6qaOoIoqYEzOQS8jum51jkv2w=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.34.0 h1:k40adF3uR+6x/+hO5Dh4ZFUqFp67vxvbpafFiJxl10A=
google.golang.org/api v0.34.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@@ -638,6 +1011,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
@@ -653,12 +1027,14 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940 h1:MRHtG0U6SnaUb+s+LhNE1qt1FQ1wlhqr5E4usBKC0uA=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200605102947-12044bf5ea91/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
@@ -666,24 +1042,35 @@ google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6 h1:rMoZiLTOobSD3eg30lPMcFkBFNSyKUQQIQlw/hsAXME=
google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
@@ -691,37 +1078,64 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
diff --git a/internal/admin/repository/administrator.go b/internal/admin/repository/administrator.go
index f091146a0b..026a293c9e 100644
--- a/internal/admin/repository/administrator.go
+++ b/internal/admin/repository/administrator.go
@@ -8,6 +8,7 @@ import (
type AdministratorRepository interface {
GetFailedEvents(context.Context) ([]*model.FailedEvent, error)
RemoveFailedEvent(context.Context, *model.FailedEvent) error
- GetViews(context.Context) ([]*model.View, error)
- ClearView(ctx context.Context, db, view string) error
+ GetViews() ([]*model.View, error)
+ GetSpoolerDiv(db, viewName string) int64
+ ClearView(ctx context.Context, db, viewName string) error
}
diff --git a/internal/admin/repository/eventsourcing/eventstore/administrator.go b/internal/admin/repository/eventsourcing/eventstore/administrator.go
index d0af36284e..52ab002cac 100644
--- a/internal/admin/repository/eventsourcing/eventstore/administrator.go
+++ b/internal/admin/repository/eventsourcing/eventstore/administrator.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
view_model "github.com/caos/zitadel/internal/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
var dbList = []string{"management", "auth", "authz", "adminapi", "notification"}
@@ -31,7 +32,7 @@ func (repo *AdministratorRepo) RemoveFailedEvent(ctx context.Context, failedEven
return repo.View.RemoveFailedEvent(failedEvent.Database, repository.FailedEventFromModel(failedEvent))
}
-func (repo *AdministratorRepo) GetViews(ctx context.Context) ([]*view_model.View, error) {
+func (repo *AdministratorRepo) GetViews() ([]*view_model.View, error) {
views := make([]*view_model.View, 0)
for _, db := range dbList {
sequences, err := repo.View.AllCurrentSequences(db)
@@ -45,6 +46,16 @@ func (repo *AdministratorRepo) GetViews(ctx context.Context) ([]*view_model.View
return views, nil
}
+func (repo *AdministratorRepo) GetSpoolerDiv(database, view string) int64 {
+ sequence, err := repo.View.GetCurrentSequence(database, view)
+ if err != nil {
+
+ return 0
+ }
+ divDuration := time.Now().Sub(sequence.LastSuccessfulSpoolerRun)
+ return divDuration.Milliseconds()
+}
+
func (repo *AdministratorRepo) ClearView(ctx context.Context, database, view string) error {
return repo.View.ClearView(database, view)
}
diff --git a/internal/admin/repository/eventsourcing/eventstore/iam.go b/internal/admin/repository/eventsourcing/eventstore/iam.go
index 37965c768b..7e04972ec8 100644
--- a/internal/admin/repository/eventsourcing/eventstore/iam.go
+++ b/internal/admin/repository/eventsourcing/eventstore/iam.go
@@ -15,7 +15,7 @@ import (
iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
iam_business "github.com/caos/zitadel/internal/v2/business/iam"
@@ -81,7 +81,7 @@ func (repo *IAMRepository) SearchIAMMembers(ctx context.Context, request *iam_mo
}
if err == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -206,7 +206,7 @@ func (repo *IAMRepository) SearchIDPConfigs(ctx context.Context, request *iam_mo
}
if err == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -298,7 +298,7 @@ func (repo *IAMRepository) SearchDefaultIDPProviders(ctx context.Context, reques
}
if err == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
diff --git a/internal/admin/repository/eventsourcing/eventstore/org.go b/internal/admin/repository/eventsourcing/eventstore/org.go
index b0c706b4c6..78400eae29 100644
--- a/internal/admin/repository/eventsourcing/eventstore/org.go
+++ b/internal/admin/repository/eventsourcing/eventstore/org.go
@@ -6,7 +6,7 @@ import (
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/logging"
admin_model "github.com/caos/zitadel/internal/admin/model"
@@ -101,7 +101,7 @@ func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchR
}
if err == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
diff --git a/internal/admin/repository/eventsourcing/handler/handler.go b/internal/admin/repository/eventsourcing/handler/handler.go
index 31115d9878..25f3b69223 100644
--- a/internal/admin/repository/eventsourcing/handler/handler.go
+++ b/internal/admin/repository/eventsourcing/handler/handler.go
@@ -41,7 +41,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
&IDPConfig{handler: handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount}},
&LabelPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount}},
&LoginPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}},
- &IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount},
+ &IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount},
systemDefaults: defaults, iamEvents: repos.IamEvents, orgEvents: repos.OrgEvents},
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
eventstore: eventstore, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults},
@@ -49,7 +49,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
&PasswordAgePolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount}},
&PasswordLockoutPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount}},
&OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
- &ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
+ &ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount},
orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults},
}
}
diff --git a/internal/admin/repository/eventsourcing/handler/iam_member.go b/internal/admin/repository/eventsourcing/handler/iam_member.go
index 906e9f6aa3..d3c9b77bb6 100644
--- a/internal/admin/repository/eventsourcing/handler/iam_member.go
+++ b/internal/admin/repository/eventsourcing/handler/iam_member.go
@@ -72,14 +72,14 @@ func (m *IamMember) processIamMember(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteIAMMember(event.AggregateID, member.UserID, event.Sequence)
+ return m.view.DeleteIAMMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIAMMemberSequence(event.Sequence)
+ return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIAMMember(member, member.Sequence)
+ return m.view.PutIAMMember(member, member.Sequence, event.CreationDate)
}
func (m *IamMember) processUser(event *models.Event) (err error) {
@@ -94,7 +94,7 @@ func (m *IamMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return m.view.ProcessedIAMMemberSequence(event.Sequence)
+ return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
}
user, err := m.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -103,11 +103,11 @@ func (m *IamMember) processUser(event *models.Event) (err error) {
for _, member := range members {
m.fillUserData(member, user)
}
- return m.view.PutIAMMembers(members, event.Sequence)
+ return m.view.PutIAMMembers(members, event.Sequence, event.CreationDate)
case usr_es_model.UserRemoved:
- return m.view.DeleteIAMMembersByUserID(event.AggregateID, event.Sequence)
+ return m.view.DeleteIAMMembersByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIAMMemberSequence(event.Sequence)
+ return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
}
return nil
}
@@ -137,3 +137,7 @@ func (m *IamMember) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ld9ow", "id", event.AggregateID).WithError(err).Warn("something went wrong in iammember handler")
return spooler.HandleError(event, err, m.view.GetLatestIAMMemberFailedEvent, m.view.ProcessedIAMMemberFailedEvent, m.view.ProcessedIAMMemberSequence, m.errorCountUntilSkip)
}
+
+func (m *IamMember) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdateIAMMemberSpoolerRunTimestamp)
+}
diff --git a/internal/admin/repository/eventsourcing/handler/idp_config.go b/internal/admin/repository/eventsourcing/handler/idp_config.go
index 1f6500cc0f..be8d43d7dc 100644
--- a/internal/admin/repository/eventsourcing/handler/idp_config.go
+++ b/internal/admin/repository/eventsourcing/handler/idp_config.go
@@ -19,12 +19,12 @@ const (
idpConfigTable = "adminapi.idp_configs"
)
-func (m *IDPConfig) ViewModel() string {
+func (i *IDPConfig) ViewModel() string {
return idpConfigTable
}
-func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIDPConfigSequence()
+func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestIDPConfigSequence()
if err != nil {
return nil, err
}
@@ -33,15 +33,15 @@ func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IDPConfig) Reduce(event *models.Event) (err error) {
+func (i *IDPConfig) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
- err = m.processIDPConfig(event)
+ err = i.processIDPConfig(event)
}
return err
}
-func (m *IDPConfig) processIDPConfig(event *models.Event) (err error) {
+func (i *IDPConfig) processIDPConfig(event *models.Event) (err error) {
idp := new(iam_view_model.IDPConfigView)
switch event.Type {
case model.IDPConfigAdded:
@@ -53,7 +53,7 @@ func (m *IDPConfig) processIDPConfig(event *models.Event) (err error) {
if err != nil {
return err
}
- idp, err = m.view.IDPConfigByID(idp.IDPConfigID)
+ idp, err = i.view.IDPConfigByID(idp.IDPConfigID)
if err != nil {
return err
}
@@ -63,17 +63,21 @@ func (m *IDPConfig) processIDPConfig(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence)
+ return i.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIDPConfigSequence(event.Sequence)
+ return i.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIDPConfig(idp, idp.Sequence)
+ return i.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
}
-func (m *IDPConfig) OnError(event *models.Event, err error) error {
+func (i *IDPConfig) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Mslo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
- return spooler.HandleError(event, err, m.view.GetLatestIDPConfigFailedEvent, m.view.ProcessedIDPConfigFailedEvent, m.view.ProcessedIDPConfigSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
+}
+
+func (i *IDPConfig) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateIDPConfigSpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/idp_providers.go b/internal/admin/repository/eventsourcing/handler/idp_providers.go
index 0613ae7fa5..0e27ee11ec 100644
--- a/internal/admin/repository/eventsourcing/handler/idp_providers.go
+++ b/internal/admin/repository/eventsourcing/handler/idp_providers.go
@@ -27,12 +27,12 @@ const (
idpProviderTable = "adminapi.idp_providers"
)
-func (m *IDPProvider) ViewModel() string {
+func (i *IDPProvider) ViewModel() string {
return idpProviderTable
}
-func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIDPProviderSequence()
+func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestIDPProviderSequence()
if err != nil {
return nil, err
}
@@ -41,15 +41,15 @@ func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IDPProvider) Reduce(event *models.Event) (err error) {
+func (i *IDPProvider) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate, org_es_model.OrgAggregate:
- err = m.processIdpProvider(event)
+ err = i.processIdpProvider(event)
}
return err
}
-func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
+func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
provider := new(iam_view_model.IDPProviderView)
switch event.Type {
case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded:
@@ -57,64 +57,68 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil {
return err
}
- err = m.fillData(provider)
+ err = i.fillData(provider)
case model.LoginPolicyIDPProviderRemoved, model.LoginPolicyIDPProviderCascadeRemoved,
org_es_model.LoginPolicyIDPProviderRemoved, org_es_model.LoginPolicyIDPProviderCascadeRemoved:
err = provider.SetData(event)
if err != nil {
return err
}
- return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence)
+ return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem
- if event.AggregateID != m.systemDefaults.IamID {
+ if event.AggregateID != i.systemDefaults.IamID {
providerType = iam_model.IDPProviderTypeOrg
}
esConfig.AppendEvent(providerType, event)
- providers, err := m.view.IDPProvidersByIdpConfigID(esConfig.IDPConfigID)
+ providers, err := i.view.IDPProvidersByIdpConfigID(esConfig.IDPConfigID)
if err != nil {
return err
}
- config, err := m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
+ config, err := i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
if err != nil {
return err
}
for _, provider := range providers {
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
}
- return m.view.PutIDPProviders(event.Sequence, providers...)
+ return i.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
default:
- return m.view.ProcessedIDPProviderSequence(event.Sequence)
+ return i.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIDPProvider(provider, provider.Sequence)
+ return i.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
}
-func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
+func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
var config *iam_model.IDPConfig
if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, provider.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, provider.IDPConfigID)
} else {
- config, err = m.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
+ config, err = i.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
}
if err != nil {
return err
}
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
return nil
}
-func (m *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) {
+func (i *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) {
provider.Name = config.Name
provider.StylingType = int32(config.StylingType)
provider.IDPConfigType = int32(config.Type)
provider.IDPState = int32(config.State)
}
-func (m *IDPProvider) OnError(event *models.Event, err error) error {
+func (i *IDPProvider) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Msj8c", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
- return spooler.HandleError(event, err, m.view.GetLatestIDPProviderFailedEvent, m.view.ProcessedIDPProviderFailedEvent, m.view.ProcessedIDPProviderSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestIDPProviderFailedEvent, i.view.ProcessedIDPProviderFailedEvent, i.view.ProcessedIDPProviderSequence, i.errorCountUntilSkip)
+}
+
+func (i *IDPProvider) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/label_policy.go b/internal/admin/repository/eventsourcing/handler/label_policy.go
index 5226b5e3dd..3f81c0060d 100644
--- a/internal/admin/repository/eventsourcing/handler/label_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/label_policy.go
@@ -18,12 +18,12 @@ const (
labelPolicyTable = "adminapi.label_policies"
)
-func (m *LabelPolicy) ViewModel() string {
+func (p *LabelPolicy) ViewModel() string {
return labelPolicyTable
}
-func (m *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestLabelPolicySequence()
+func (p *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestLabelPolicySequence()
if err != nil {
return nil, err
}
@@ -32,35 +32,39 @@ func (m *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *LabelPolicy) Reduce(event *models.Event) (err error) {
+func (p *LabelPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
- err = m.processLabelPolicy(event)
+ err = p.processLabelPolicy(event)
}
return err
}
-func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
+func (p *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
policy := new(iam_model.LabelPolicyView)
switch event.Type {
case model.LabelPolicyAdded:
err = policy.AppendEvent(event)
case model.LabelPolicyChanged:
- policy, err = m.view.LabelPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.LabelPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
default:
- return m.view.ProcessedLabelPolicySequence(event.Sequence)
+ return p.view.ProcessedLabelPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutLabelPolicy(policy, policy.Sequence)
+ return p.view.PutLabelPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *LabelPolicy) OnError(event *models.Event, err error) error {
+func (p *LabelPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestLabelPolicyFailedEvent, p.view.ProcessedLabelPolicyFailedEvent, p.view.ProcessedLabelPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *LabelPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateLabelPolicySpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/login_policy.go b/internal/admin/repository/eventsourcing/handler/login_policy.go
index 9f4a20988f..c24100ca69 100644
--- a/internal/admin/repository/eventsourcing/handler/login_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/login_policy.go
@@ -18,12 +18,12 @@ const (
loginPolicyTable = "adminapi.login_policies"
)
-func (m *LoginPolicy) ViewModel() string {
+func (p *LoginPolicy) ViewModel() string {
return loginPolicyTable
}
-func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestLoginPolicySequence()
+func (p *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestLoginPolicySequence()
if err != nil {
return nil, err
}
@@ -32,15 +32,15 @@ func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *LoginPolicy) Reduce(event *models.Event) (err error) {
+func (p *LoginPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate:
- err = m.processLoginPolicy(event)
+ err = p.processLoginPolicy(event)
}
return err
}
-func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
+func (p *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
policy := new(iam_model.LoginPolicyView)
switch event.Type {
case model.LoginPolicyAdded:
@@ -50,21 +50,25 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
model.LoginPolicySecondFactorRemoved,
model.LoginPolicyMultiFactorAdded,
model.LoginPolicyMultiFactorRemoved:
- policy, err = m.view.LoginPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.LoginPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
default:
- return m.view.ProcessedLoginPolicySequence(event.Sequence)
+ return p.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutLoginPolicy(policy, policy.Sequence)
+ return p.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *LoginPolicy) OnError(event *models.Event, err error) error {
+func (p *LoginPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestLoginPolicyFailedEvent, m.view.ProcessedLoginPolicyFailedEvent, m.view.ProcessedLoginPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestLoginPolicyFailedEvent, p.view.ProcessedLoginPolicyFailedEvent, p.view.ProcessedLoginPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *LoginPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateLoginPolicySpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/org.go b/internal/admin/repository/eventsourcing/handler/org.go
index fafe94a74c..eb64e60ea7 100644
--- a/internal/admin/repository/eventsourcing/handler/org.go
+++ b/internal/admin/repository/eventsourcing/handler/org.go
@@ -53,13 +53,17 @@ func (o *Org) Reduce(event *es_models.Event) error {
return err
}
default:
- return o.view.ProcessedOrgSequence(event.Sequence)
+ return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
}
- return o.view.PutOrg(org)
+ return o.view.PutOrg(org, event.CreationDate)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in project app handler")
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
}
+
+func (o *Org) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgSpoolerRunTimestamp)
+}
diff --git a/internal/admin/repository/eventsourcing/handler/org_iam_policy.go b/internal/admin/repository/eventsourcing/handler/org_iam_policy.go
index cb49e33efb..99c01e73e1 100644
--- a/internal/admin/repository/eventsourcing/handler/org_iam_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/org_iam_policy.go
@@ -19,12 +19,12 @@ const (
orgIAMPolicyTable = "adminapi.org_iam_policies"
)
-func (m *OrgIAMPolicy) ViewModel() string {
+func (p *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable
}
-func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestOrgIAMPolicySequence()
+func (p *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processOrgIAMPolicy(event)
+ err = p.processOrgIAMPolicy(event)
}
return err
}
-func (m *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
policy := new(iam_model.OrgIAMPolicyView)
switch event.Type {
case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged:
- policy, err = m.view.OrgIAMPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.OrgIAMPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved:
- return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedOrgIAMPolicySequence(event.Sequence)
+ return p.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutOrgIAMPolicy(policy, policy.Sequence)
+ return p.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *OrgIAMPolicy) OnError(event *models.Event, err error) error {
+func (p *OrgIAMPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *OrgIAMPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateOrgIAMPolicySpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/password_age_policy.go b/internal/admin/repository/eventsourcing/handler/password_age_policy.go
index bf56af86ef..3608ec446e 100644
--- a/internal/admin/repository/eventsourcing/handler/password_age_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/password_age_policy.go
@@ -19,12 +19,12 @@ const (
passwordAgePolicyTable = "adminapi.password_age_policies"
)
-func (m *PasswordAgePolicy) ViewModel() string {
+func (p *PasswordAgePolicy) ViewModel() string {
return passwordAgePolicyTable
}
-func (m *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordAgePolicySequence()
+func (p *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordAgePolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *PasswordAgePolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordAgePolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processPasswordAgePolicy(event)
+ err = p.processPasswordAgePolicy(event)
}
return err
}
-func (m *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err error) {
+func (p *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordAgePolicyView)
switch event.Type {
case iam_es_model.PasswordAgePolicyAdded, model.PasswordAgePolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.PasswordAgePolicyChanged, model.PasswordAgePolicyChanged:
- policy, err = m.view.PasswordAgePolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.PasswordAgePolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.PasswordAgePolicyRemoved:
- return m.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence)
+ return p.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordAgePolicySequence(event.Sequence)
+ return p.view.ProcessedPasswordAgePolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordAgePolicy(policy, policy.Sequence)
+ return p.view.PutPasswordAgePolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *PasswordAgePolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordAgePolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-nD8sie", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordAge policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestPasswordAgePolicyFailedEvent, m.view.ProcessedPasswordAgePolicyFailedEvent, m.view.ProcessedPasswordAgePolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestPasswordAgePolicyFailedEvent, p.view.ProcessedPasswordAgePolicyFailedEvent, p.view.ProcessedPasswordAgePolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *PasswordAgePolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProcessedPasswordAgePolicySpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go b/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go
index 2eeb6cf759..f1d2898218 100644
--- a/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/password_complexity_policy.go
@@ -19,12 +19,12 @@ const (
passwordComplexityPolicyTable = "adminapi.password_complexity_policies"
)
-func (m *PasswordComplexityPolicy) ViewModel() string {
+func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable
}
-func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordComplexityPolicySequence()
+func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processPasswordComplexityPolicy(event)
+ err = p.processPasswordComplexityPolicy(event)
}
return err
}
-func (m *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordComplexityPolicyView)
switch event.Type {
case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged:
- policy, err = m.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved:
- return m.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordComplexityPolicySequence(event.Sequence)
+ return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordComplexityPolicy(policy, policy.Sequence)
+ return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *PasswordComplexityPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdatePasswordComplexityPolicySpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go b/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go
index bd71ab054d..fd087adda7 100644
--- a/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go
+++ b/internal/admin/repository/eventsourcing/handler/password_lockout_policy.go
@@ -19,12 +19,12 @@ const (
passwordLockoutPolicyTable = "adminapi.password_lockout_policies"
)
-func (m *PasswordLockoutPolicy) ViewModel() string {
+func (p *PasswordLockoutPolicy) ViewModel() string {
return passwordLockoutPolicyTable
}
-func (m *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordLockoutPolicySequence()
+func (p *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordLockoutPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *PasswordLockoutPolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordLockoutPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processPasswordLockoutPolicy(event)
+ err = p.processPasswordLockoutPolicy(event)
}
return err
}
-func (m *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event) (err error) {
+func (p *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordLockoutPolicyView)
switch event.Type {
case iam_es_model.PasswordLockoutPolicyAdded, model.PasswordLockoutPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.PasswordLockoutPolicyChanged, model.PasswordLockoutPolicyChanged:
- policy, err = m.view.PasswordLockoutPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.PasswordLockoutPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.PasswordLockoutPolicyRemoved:
- return m.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordLockoutPolicySequence(event.Sequence)
+ return p.view.ProcessedPasswordLockoutPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordLockoutPolicy(policy, policy.Sequence)
+ return p.view.PutPasswordLockoutPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-nD8sie", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordLockout policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestPasswordLockoutPolicyFailedEvent, m.view.ProcessedPasswordLockoutPolicyFailedEvent, m.view.ProcessedPasswordLockoutPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestPasswordLockoutPolicyFailedEvent, p.view.ProcessedPasswordLockoutPolicyFailedEvent, p.view.ProcessedPasswordLockoutPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *PasswordLockoutPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdatePasswordLockoutPolicySpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/handler/user.go b/internal/admin/repository/eventsourcing/handler/user.go
index 8a4105d131..f0f26afc4f 100644
--- a/internal/admin/repository/eventsourcing/handler/user.go
+++ b/internal/admin/repository/eventsourcing/handler/user.go
@@ -92,6 +92,12 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
es_model.HumanMFAOTPAdded,
es_model.HumanMFAOTPVerified,
es_model.HumanMFAOTPRemoved,
+ es_model.HumanMFAU2FTokenAdded,
+ es_model.HumanMFAU2FTokenVerified,
+ es_model.HumanMFAU2FTokenRemoved,
+ es_model.HumanPasswordlessTokenAdded,
+ es_model.HumanPasswordlessTokenVerified,
+ es_model.HumanPasswordlessTokenRemoved,
es_model.MachineChanged:
user, err = u.view.UserByID(event.AggregateID)
if err != nil {
@@ -110,14 +116,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
}
err = u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteUser(event.AggregateID, event.Sequence)
+ return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserSequence(event.Sequence)
+ return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return u.view.PutUser(user, user.Sequence)
+ return u.view.PutUser(user, user.Sequence, event.CreationDate)
}
func (u *User) ProcessOrg(event *models.Event) (err error) {
@@ -131,7 +137,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedUserSequence(event.Sequence)
+ return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
}
}
@@ -154,7 +160,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
}
- return u.view.PutUsers(users, event.Sequence)
+ return u.view.PutUsers(users, event.Sequence, event.CreationDate)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -179,7 +185,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
}
- return u.view.PutUsers(users, event.Sequence)
+ return u.view.PutUsers(users, event.Sequence, event.CreationDate)
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
@@ -203,3 +209,7 @@ func (u *User) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-vLmwQ", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip)
}
+
+func (u *User) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp)
+}
diff --git a/internal/admin/repository/eventsourcing/handler/user_external_idps.go b/internal/admin/repository/eventsourcing/handler/user_external_idps.go
index b9c74c1c89..cc4d979dc3 100644
--- a/internal/admin/repository/eventsourcing/handler/user_external_idps.go
+++ b/internal/admin/repository/eventsourcing/handler/user_external_idps.go
@@ -30,12 +30,12 @@ const (
externalIDPTable = "adminapi.user_external_idps"
)
-func (m *ExternalIDP) ViewModel() string {
+func (i *ExternalIDP) ViewModel() string {
return externalIDPTable
}
-func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestExternalIDPSequence()
+func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence()
if err != nil {
return nil, err
}
@@ -44,17 +44,17 @@ func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *ExternalIDP) Reduce(event *models.Event) (err error) {
+func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.UserAggregate:
- err = m.processUser(event)
+ err = i.processUser(event)
case iam_es_model.IAMAggregate, org_es_model.OrgAggregate:
- err = m.processIdpConfig(event)
+ err = i.processIdpConfig(event)
}
return err
}
-func (m *ExternalIDP) processUser(event *models.Event) (err error) {
+func (i *ExternalIDP) processUser(event *models.Event) (err error) {
externalIDP := new(usr_view_model.ExternalIDPView)
switch event.Type {
case model.HumanExternalIDPAdded:
@@ -62,25 +62,25 @@ func (m *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil {
return err
}
- err = m.fillData(externalIDP)
+ err = i.fillData(externalIDP)
case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved:
err = externalIDP.SetData(event)
if err != nil {
return err
}
- return m.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence)
+ return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
case model.UserRemoved:
- return m.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence)
+ return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedExternalIDPSequence(event.Sequence)
+ return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutExternalIDP(externalIDP, externalIDP.Sequence)
+ return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
}
-func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
+func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
switch event.Type {
case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged:
configView := new(iam_view_model.IDPConfigView)
@@ -90,45 +90,49 @@ func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
} else {
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
}
- exterinalIDPs, err := m.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
+ exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
if err != nil {
return err
}
if event.AggregateType == iam_es_model.IAMAggregate {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} else {
- config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
+ config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
}
if err != nil {
return err
}
for _, provider := range exterinalIDPs {
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
}
- return m.view.PutExternalIDPs(event.Sequence, exterinalIDPs...)
+ return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
default:
- return m.view.ProcessedExternalIDPSequence(event.Sequence)
+ return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
}
return nil
}
-func (m *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
- config, err := m.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
+func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
+ config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
if caos_errs.IsNotFound(err) {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, externalIDP.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID)
}
if err != nil {
return err
}
- m.fillConfigData(externalIDP, config)
+ i.fillConfigData(externalIDP, config)
return nil
}
-func (m *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
+func (i *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
externalIDP.IDPName = config.Name
}
-func (m *ExternalIDP) OnError(event *models.Event, err error) error {
+func (i *ExternalIDP) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
- return spooler.HandleError(event, err, m.view.GetLatestExternalIDPFailedEvent, m.view.ProcessedExternalIDPFailedEvent, m.view.ProcessedExternalIDPSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestExternalIDPFailedEvent, i.view.ProcessedExternalIDPFailedEvent, i.view.ProcessedExternalIDPSequence, i.errorCountUntilSkip)
+}
+
+func (i *ExternalIDP) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/view/external_idps.go b/internal/admin/repository/eventsourcing/view/external_idps.go
index de919a589a..8f21e7de86 100644
--- a/internal/admin/repository/eventsourcing/view/external_idps.go
+++ b/internal/admin/repository/eventsourcing/view/external_idps.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -32,44 +33,48 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
}
-func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64) error {
+func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence)
+ return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
}
-func (v *View) PutExternalIDPs(sequence uint64, externalIDPs ...*model.ExternalIDPView) error {
+func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence)
+ return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64) error {
+func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence)
+ return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence)
+ return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(externalIDPTable)
}
-func (v *View) ProcessedExternalIDPSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(externalIDPTable, eventSequence)
+func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(externalIDPTable)
}
func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/iam_member.go b/internal/admin/repository/eventsourcing/view/iam_member.go
index 2e27aa4182..250a0042fa 100644
--- a/internal/admin/repository/eventsourcing/view/iam_member.go
+++ b/internal/admin/repository/eventsourcing/view/iam_member.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -24,44 +25,48 @@ func (v *View) IAMMembersByUserID(userID string) ([]*model.IAMMemberView, error)
return view.IAMMembersByUserID(v.Db, iamMemberTable, userID)
}
-func (v *View) PutIAMMember(org *model.IAMMemberView, sequence uint64) error {
+func (v *View) PutIAMMember(org *model.IAMMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIAMMember(v.Db, iamMemberTable, org)
if err != nil {
return err
}
- return v.ProcessedIAMMemberSequence(sequence)
+ return v.ProcessedIAMMemberSequence(sequence, eventTimestamp)
}
-func (v *View) PutIAMMembers(members []*model.IAMMemberView, sequence uint64) error {
+func (v *View) PutIAMMembers(members []*model.IAMMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIAMMembers(v.Db, iamMemberTable, members...)
if err != nil {
return err
}
- return v.ProcessedIAMMemberSequence(sequence)
+ return v.ProcessedIAMMemberSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIAMMember(iamID, userID string, eventSequence uint64) error {
+func (v *View) DeleteIAMMember(iamID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIAMMember(v.Db, iamMemberTable, iamID, userID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIAMMemberSequence(eventSequence)
+ return v.ProcessedIAMMemberSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteIAMMembersByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteIAMMembersByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIAMMembersByUserID(v.Db, iamMemberTable, userID)
if err != nil {
return err
}
- return v.ProcessedIAMMemberSequence(eventSequence)
+ return v.ProcessedIAMMemberSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestIAMMemberSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(iamMemberTable)
}
-func (v *View) ProcessedIAMMemberSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(iamMemberTable, eventSequence)
+func (v *View) ProcessedIAMMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(iamMemberTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateIAMMemberSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(iamMemberTable)
}
func (v *View) GetLatestIAMMemberFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/idp_configs.go b/internal/admin/repository/eventsourcing/view/idp_configs.go
index d6deab1212..197c37d09b 100644
--- a/internal/admin/repository/eventsourcing/view/idp_configs.go
+++ b/internal/admin/repository/eventsourcing/view/idp_configs.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -20,28 +21,32 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*m
return view.SearchIDPs(v.Db, idpConfigTable, request)
}
-func (v *View) PutIDPConfig(idp *model.IDPConfigView, sequence uint64) error {
+func (v *View) PutIDPConfig(idp *model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil {
return err
}
- return v.ProcessedIDPConfigSequence(sequence)
+ return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64) error {
+func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPConfigSequence(eventSequence)
+ return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpConfigTable)
}
-func (v *View) ProcessedIDPConfigSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(idpConfigTable, eventSequence)
+func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(idpConfigTable)
}
func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/idp_providers.go b/internal/admin/repository/eventsourcing/view/idp_providers.go
index 5c4931abf6..10b5886945 100644
--- a/internal/admin/repository/eventsourcing/view/idp_providers.go
+++ b/internal/admin/repository/eventsourcing/view/idp_providers.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -24,36 +25,40 @@ func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) (
return view.SearchIDPProviders(v.Db, idpProviderTable, request)
}
-func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64) error {
+func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence)
+ return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
}
-func (v *View) PutIDPProviders(sequence uint64, providers ...*model.IDPProviderView) error {
+func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence)
+ return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64) error {
+func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence)
+ return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpProviderTable)
}
-func (v *View) ProcessedIDPProviderSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(idpProviderTable, eventSequence)
+func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(idpProviderTable)
}
func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/label_policies.go b/internal/admin/repository/eventsourcing/view/label_policies.go
index 113859894f..f4e921ac1c 100644
--- a/internal/admin/repository/eventsourcing/view/label_policies.go
+++ b/internal/admin/repository/eventsourcing/view/label_policies.go
@@ -4,6 +4,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -14,20 +15,24 @@ func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyV
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
}
-func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64) error {
+func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLabelPolicySequence(sequence)
+ return v.ProcessedLabelPolicySequence(sequence, eventTimestamp)
}
func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(labelPolicyTable)
}
-func (v *View) ProcessedLabelPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(labelPolicyTable, eventSequence)
+func (v *View) ProcessedLabelPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(labelPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateLabelPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(labelPolicyTable)
}
func (v *View) GetLatestLabelPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/login_policies.go b/internal/admin/repository/eventsourcing/view/login_policies.go
index 8e37e57729..03e4451ffb 100644
--- a/internal/admin/repository/eventsourcing/view/login_policies.go
+++ b/internal/admin/repository/eventsourcing/view/login_policies.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
}
-func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64) error {
+func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLoginPolicySequence(sequence)
+ return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLoginPolicySequence(eventSequence)
+ return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(loginPolicyTable)
}
-func (v *View) ProcessedLoginPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(loginPolicyTable, eventSequence)
+func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(loginPolicyTable)
}
func (v *View) GetLatestLoginPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/org.go b/internal/admin/repository/eventsourcing/view/org.go
index 2c580ab012..ee9f9fb113 100644
--- a/internal/admin/repository/eventsourcing/view/org.go
+++ b/internal/admin/repository/eventsourcing/view/org.go
@@ -5,6 +5,7 @@ import (
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -19,12 +20,12 @@ func (v *View) SearchOrgs(query *org_model.OrgSearchRequest) ([]*model.OrgView,
return org_view.SearchOrgs(v.Db, orgTable, query)
}
-func (v *View) PutOrg(org *model.OrgView) error {
+func (v *View) PutOrg(org *model.OrgView, eventTimestamp time.Time) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence)
+ return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -35,10 +36,14 @@ func (v *View) ProcessedOrgFailedEvent(failedEvent *repository.FailedEvent) erro
return v.saveFailedEvent(failedEvent)
}
+func (v *View) UpdateOrgSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgTable)
+}
+
func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgTable)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgTable, eventSequence)
+func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
}
diff --git a/internal/admin/repository/eventsourcing/view/org_iam_policy.go b/internal/admin/repository/eventsourcing/view/org_iam_policy.go
index 57196f7eaf..3168a78152 100644
--- a/internal/admin/repository/eventsourcing/view/org_iam_policy.go
+++ b/internal/admin/repository/eventsourcing/view/org_iam_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
}
-func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64) error {
+func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedOrgIAMPolicySequence(sequence)
+ return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedOrgIAMPolicySequence(eventSequence)
+ return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(orgIAMPolicyTable)
}
-func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence)
+func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgIAMPolicyTable)
}
func (v *View) GetLatestOrgIAMPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/password_age_policy.go b/internal/admin/repository/eventsourcing/view/password_age_policy.go
index 915f2cb50d..419b537830 100644
--- a/internal/admin/repository/eventsourcing/view/password_age_policy.go
+++ b/internal/admin/repository/eventsourcing/view/password_age_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordAgePolicyByAggregateID(aggregateID string) (*model.Passwo
return view.GetPasswordAgePolicyByAggregateID(v.Db, passwordAgePolicyTable, aggregateID)
}
-func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64) error {
+func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordAgePolicy(v.Db, passwordAgePolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordAgePolicySequence(sequence)
+ return v.ProcessedPasswordAgePolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordAgePolicy(v.Db, passwordAgePolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordAgePolicySequence(eventSequence)
+ return v.ProcessedPasswordAgePolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordAgePolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordAgePolicyTable)
}
-func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence)
+func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProcessedPasswordAgePolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordAgePolicyTable)
}
func (v *View) GetLatestPasswordAgePolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/password_complexity_policy.go b/internal/admin/repository/eventsourcing/view/password_complexity_policy.go
index 554a32ca0d..2b1af7d375 100644
--- a/internal/admin/repository/eventsourcing/view/password_complexity_policy.go
+++ b/internal/admin/repository/eventsourcing/view/password_complexity_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
}
-func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64) error {
+func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(sequence)
+ return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(eventSequence)
+ return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordComplexityPolicyTable)
}
-func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence)
+func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordComplexityPolicyTable)
}
func (v *View) GetLatestPasswordComplexityPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/password_lockout_policy.go b/internal/admin/repository/eventsourcing/view/password_lockout_policy.go
index 4ee6d38623..d20643d37c 100644
--- a/internal/admin/repository/eventsourcing/view/password_lockout_policy.go
+++ b/internal/admin/repository/eventsourcing/view/password_lockout_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordLockoutPolicyByAggregateID(aggregateID string) (*model.Pa
return view.GetPasswordLockoutPolicyByAggregateID(v.Db, passwordLockoutPolicyTable, aggregateID)
}
-func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64) error {
+func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(sequence)
+ return v.ProcessedPasswordLockoutPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(eventSequence)
+ return v.ProcessedPasswordLockoutPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordLockoutPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordLockoutPolicyTable)
}
-func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence)
+func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdatePasswordLockoutPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordLockoutPolicyTable)
}
func (v *View) GetLatestPasswordLockoutPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/admin/repository/eventsourcing/view/sequence.go b/internal/admin/repository/eventsourcing/view/sequence.go
index 3d01519477..cda4580a6b 100644
--- a/internal/admin/repository/eventsourcing/view/sequence.go
+++ b/internal/admin/repository/eventsourcing/view/sequence.go
@@ -2,14 +2,15 @@ package view
import (
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
sequencesTable = "adminapi.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence)
+func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimeStamp time.Time) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimeStamp)
}
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
@@ -20,6 +21,24 @@ func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, er
return repository.AllCurrentSequences(v.Db, db+".current_sequences")
}
+func (v *View) updateSpoolerRunSequence(viewName string) error {
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ if err != nil {
+ return err
+ }
+ if currentSequence.ViewName == "" {
+ currentSequence.ViewName = viewName
+ }
+ currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
+}
+
+func (v *View) GetCurrentSequence(db, viewName string) (*repository.CurrentSequence, error) {
+ sequenceTable := db + ".current_sequences"
+ fullView := db + "." + viewName
+ return repository.LatestSequence(v.Db, sequenceTable, fullView)
+}
+
func (v *View) ClearView(db, viewName string) error {
truncateView := db + "." + viewName
sequenceTable := db + ".current_sequences"
diff --git a/internal/admin/repository/eventsourcing/view/user.go b/internal/admin/repository/eventsourcing/view/user.go
index 1dcdcebc5f..3de68472cf 100644
--- a/internal/admin/repository/eventsourcing/view/user.go
+++ b/internal/admin/repository/eventsourcing/view/user.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -35,43 +36,47 @@ func (v *View) IsUserUnique(userName, email string) (bool, error) {
return view.IsUserUnique(v.Db, userTable, userName, email)
}
-func (v *View) UserMfas(userID string) ([]*usr_model.MultiFactor, error) {
- return view.UserMfas(v.Db, userTable, userID)
+func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
+ return view.UserMFAs(v.Db, userTable, userID)
}
-func (v *View) PutUsers(user []*model.UserView, sequence uint64) error {
+func (v *View) PutUsers(user []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUsers(v.Db, userTable, user...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
-func (v *View) PutUser(user *model.UserView, sequence uint64) error {
+func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
if sequence != 0 {
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
return nil
}
-func (v *View) DeleteUser(userID string, eventSequence uint64) error {
+func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUser(v.Db, userTable, userID)
if err != nil {
return nil
}
- return v.ProcessedUserSequence(eventSequence)
+ return v.ProcessedUserSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userTable)
}
-func (v *View) ProcessedUserSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userTable, eventSequence)
+func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userTable)
}
func (v *View) GetLatestUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/api/api.go b/internal/api/api.go
index 7de3ff62ba..a0225af53a 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -2,6 +2,12 @@ package api
import (
"context"
+ admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing"
+ auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+ "github.com/caos/zitadel/internal/telemetry/metrics/otel"
+ view_model "github.com/caos/zitadel/internal/view/model"
+ "go.opentelemetry.io/otel/api/metric"
"net/http"
"github.com/caos/logging"
@@ -16,7 +22,7 @@ import (
"github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type Config struct {
@@ -30,19 +36,33 @@ type API struct {
verifier *authz.TokenVerifier
serverPort string
health health
+ auth auth
+ admin admin
}
+
type health interface {
Health(ctx context.Context) error
IamByID(ctx context.Context) (*iam_model.IAM, error)
VerifierClientID(ctx context.Context, appName string) (string, error)
}
-func Create(config Config, authZ authz.Config, authZRepo *authz_es.EsRepository, sd systemdefaults.SystemDefaults) *API {
+type auth interface {
+ ActiveUserSessionCount() int64
+}
+
+type admin interface {
+ GetViews() ([]*view_model.View, error)
+ GetSpoolerDiv(database, viewName string) int64
+}
+
+func Create(config Config, authZ authz.Config, authZRepo *authz_es.EsRepository, authRepo *auth_es.EsRepository, adminRepo *admin_es.EsRepository, sd systemdefaults.SystemDefaults) *API {
api := &API{
serverPort: config.GRPC.ServerPort,
}
api.verifier = authz.Start(authZRepo)
api.health = authZRepo
+ api.auth = authRepo
+ api.admin = adminRepo
api.grpcServer = server.CreateServer(api.verifier, authZ, sd.DefaultLanguage)
api.gatewayHandler = server.CreateGatewayHandler(config.GRPC)
api.RegisterHandler("", api.healthHandler())
@@ -92,6 +112,7 @@ func (a *API) healthHandler() http.Handler {
handler.HandleFunc("/ready", handleReadiness(checks))
handler.HandleFunc("/validate", handleValidate(checks))
handler.HandleFunc("/clientID", a.handleClientID)
+ handler.Handle("/metrics", a.handleMetrics())
return handler
}
@@ -132,6 +153,48 @@ func (a *API) handleClientID(w http.ResponseWriter, r *http.Request) {
http_util.MarshalJSON(w, id, nil, http.StatusOK)
}
+func (a *API) handleMetrics() http.Handler {
+ a.registerActiveSessionCounters()
+ a.registerSpoolerDivCounters()
+ return metrics.GetExporter()
+}
+
+func (a *API) registerActiveSessionCounters() {
+ metrics.RegisterValueObserver(
+ metrics.ActiveSessionCounter,
+ metrics.ActiveSessionCounterDescription,
+ func(ctx context.Context, result metric.Int64ObserverResult) {
+ result.Observe(
+ a.auth.ActiveUserSessionCount(),
+ )
+ },
+ )
+}
+
+func (a *API) registerSpoolerDivCounters() {
+ views, err := a.admin.GetViews()
+ if err != nil {
+ logging.Log("API-3M8sd").WithError(err).Error("could not read views for metrics")
+ return
+ }
+ metrics.RegisterValueObserver(
+ metrics.SpoolerDivCounter,
+ metrics.SpoolerDivCounterDescription,
+ func(ctx context.Context, result metric.Int64ObserverResult) {
+ for _, view := range views {
+ labels := map[string]interface{}{
+ metrics.Database: view.Database,
+ metrics.ViewName: view.ViewName,
+ }
+ result.Observe(
+ a.admin.GetSpoolerDiv(view.Database, view.ViewName),
+ otel.MapToKeyValue(labels)...,
+ )
+ }
+ },
+ )
+}
+
type ValidationFunction func(ctx context.Context) error
func validate(ctx context.Context, validations []ValidationFunction) []error {
diff --git a/internal/api/authz/authorization.go b/internal/api/authz/authorization.go
index 740bff3431..7ae5e838f4 100644
--- a/internal/api/authz/authorization.go
+++ b/internal/api/authz/authorization.go
@@ -7,7 +7,7 @@ import (
"strings"
"github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
const (
diff --git a/internal/api/authz/context.go b/internal/api/authz/context.go
index 576fe2c13a..4880a7373e 100644
--- a/internal/api/authz/context.go
+++ b/internal/api/authz/context.go
@@ -6,7 +6,7 @@ import (
"github.com/caos/zitadel/internal/api/grpc"
http_util "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type key int
diff --git a/internal/api/authz/permissions.go b/internal/api/authz/permissions.go
index 6147deeac9..8023152ca9 100644
--- a/internal/api/authz/permissions.go
+++ b/internal/api/authz/permissions.go
@@ -4,7 +4,7 @@ import (
"context"
"github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (_ context.Context, _ []string, err error) {
diff --git a/internal/api/authz/token.go b/internal/api/authz/token.go
index a646cdb8ef..463b7396c2 100644
--- a/internal/api/authz/token.go
+++ b/internal/api/authz/token.go
@@ -6,7 +6,7 @@ import (
"sync"
caos_errs "github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
const (
diff --git a/internal/api/grpc/admin/administrator.go b/internal/api/grpc/admin/administrator.go
index 58fbefaf6c..1d855a61f2 100644
--- a/internal/api/grpc/admin/administrator.go
+++ b/internal/api/grpc/admin/administrator.go
@@ -10,7 +10,7 @@ import (
)
func (s *Server) GetViews(ctx context.Context, _ *empty.Empty) (_ *admin.Views, err error) {
- views, err := s.administrator.GetViews(ctx)
+ views, err := s.administrator.GetViews()
if err != nil {
return nil, err
}
diff --git a/internal/api/grpc/admin/administrator_converter.go b/internal/api/grpc/admin/administrator_converter.go
index 7dc640a8a4..1f93d2496c 100644
--- a/internal/api/grpc/admin/administrator_converter.go
+++ b/internal/api/grpc/admin/administrator_converter.go
@@ -26,14 +26,17 @@ func failedEventsFromModel(failedEvents []*view_model.FailedEvent) []*admin.Fail
}
func viewFromModel(view *view_model.View) *admin.View {
- timestamp, err := ptypes.TimestampProto(view.CurrentTimestamp)
+ eventTimestamp, err := ptypes.TimestampProto(view.EventTimestamp)
+ logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp")
+ lastSpool, err := ptypes.TimestampProto(view.EventTimestamp)
logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp")
return &admin.View{
- Database: view.Database,
- ViewName: view.ViewName,
- ProcessedSequence: view.CurrentSequence,
- ViewTimestamp: timestamp,
+ Database: view.Database,
+ ViewName: view.ViewName,
+ ProcessedSequence: view.CurrentSequence,
+ EventTimestamp: eventTimestamp,
+ LastSuccessfulSpoolerRun: lastSpool,
}
}
diff --git a/internal/api/grpc/admin/login_policy_converter.go b/internal/api/grpc/admin/login_policy_converter.go
index 90a5ccc415..d45af029d4 100644
--- a/internal/api/grpc/admin/login_policy_converter.go
+++ b/internal/api/grpc/admin/login_policy_converter.go
@@ -13,6 +13,7 @@ func loginPolicyToModel(policy *admin.DefaultLoginPolicyRequest) *iam_model.Logi
AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister,
ForceMFA: policy.ForceMfa,
+ PasswordlessType: passwordlessTypeToModel(policy.PasswordlessType),
}
}
@@ -28,6 +29,7 @@ func loginPolicyFromModel(policy *iam_model.LoginPolicy) *admin.DefaultLoginPoli
AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister,
ForceMfa: policy.ForceMFA,
+ PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
CreationDate: creationDate,
ChangeDate: changeDate,
}
@@ -45,6 +47,7 @@ func loginPolicyViewFromModel(policy *iam_model.LoginPolicyView) *admin.DefaultL
AllowExternalIdp: policy.AllowExternalIDP,
AllowRegister: policy.AllowRegister,
ForceMfa: policy.ForceMFA,
+ PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
CreationDate: creationDate,
ChangeDate: changeDate,
}
@@ -145,6 +148,24 @@ func secondFactorTypeToModel(mfaType *admin.SecondFactor) iam_model.SecondFactor
}
}
+func passwordlessTypeFromModel(passwordlessType iam_model.PasswordlessType) admin.PasswordlessType {
+ switch passwordlessType {
+ case iam_model.PasswordlessTypeAllowed:
+ return admin.PasswordlessType_PASSWORDLESSTYPE_ALLOWED
+ default:
+ return admin.PasswordlessType_PASSWORDLESSTYPE_NOT_ALLOWED
+ }
+}
+
+func passwordlessTypeToModel(passwordlessType admin.PasswordlessType) iam_model.PasswordlessType {
+ switch passwordlessType {
+ case admin.PasswordlessType_PASSWORDLESSTYPE_ALLOWED:
+ return iam_model.PasswordlessTypeAllowed
+ default:
+ return iam_model.PasswordlessTypeNotAllowed
+ }
+}
+
func multiFactorResultFromModel(result *iam_model.MultiFactorsSearchResponse) *admin.MultiFactorsResult {
converted := make([]admin.MultiFactorType, len(result.Result))
for i, mfaType := range result.Result {
diff --git a/internal/api/grpc/admin/probes.go b/internal/api/grpc/admin/probes.go
index 632471bf2d..0a67a7f967 100644
--- a/internal/api/grpc/admin/probes.go
+++ b/internal/api/grpc/admin/probes.go
@@ -2,7 +2,6 @@ package admin
import (
"context"
-
"github.com/golang/protobuf/ptypes/empty"
)
diff --git a/internal/api/grpc/auth/user.go b/internal/api/grpc/auth/user.go
index ad0dba523f..e2d94e9d47 100644
--- a/internal/api/grpc/auth/user.go
+++ b/internal/api/grpc/auth/user.go
@@ -2,7 +2,6 @@ package auth
import (
"context"
-
"github.com/golang/protobuf/ptypes/empty"
"github.com/caos/zitadel/pkg/grpc/auth"
@@ -54,7 +53,7 @@ func (s *Server) GetMyUserAddress(ctx context.Context, _ *empty.Empty) (*auth.Us
}
func (s *Server) GetMyMfas(ctx context.Context, _ *empty.Empty) (*auth.MultiFactors, error) {
- mfas, err := s.repo.MyUserMfas(ctx)
+ mfas, err := s.repo.MyUserMFAs(ctx)
if err != nil {
return nil, err
}
@@ -144,7 +143,7 @@ func (s *Server) GetMyPasswordComplexityPolicy(ctx context.Context, _ *empty.Emp
}
func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *auth.MfaOtpResponse, err error) {
- otp, err := s.repo.AddMyMfaOTP(ctx)
+ otp, err := s.repo.AddMyMFAOTP(ctx)
if err != nil {
return nil, err
}
@@ -152,12 +151,42 @@ func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *auth.MfaOtpR
}
func (s *Server) VerifyMfaOTP(ctx context.Context, request *auth.VerifyMfaOtp) (*empty.Empty, error) {
- err := s.repo.VerifyMyMfaOTPSetup(ctx, request.Code)
+ err := s.repo.VerifyMyMFAOTPSetup(ctx, request.Code)
return &empty.Empty{}, err
}
func (s *Server) RemoveMfaOTP(ctx context.Context, _ *empty.Empty) (_ *empty.Empty, err error) {
- s.repo.RemoveMyMfaOTP(ctx)
+ err = s.repo.RemoveMyMFAOTP(ctx)
+ return &empty.Empty{}, err
+}
+
+func (s *Server) AddMyMfaU2F(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) {
+ u2f, err := s.repo.AddMyMFAU2F(ctx)
+ return verifyWebAuthNFromModel(u2f), err
+}
+
+func (s *Server) VerifyMyMfaU2F(ctx context.Context, request *auth.VerifyWebAuthN) (*empty.Empty, error) {
+ err := s.repo.VerifyMyMFAU2FSetup(ctx, request.TokenName, request.PublicKeyCredential)
+ return &empty.Empty{}, err
+}
+
+func (s *Server) RemoveMyMfaU2F(ctx context.Context, id *auth.WebAuthNTokenID) (*empty.Empty, error) {
+ err := s.repo.RemoveMyMFAU2F(ctx, id.Id)
+ return &empty.Empty{}, err
+}
+
+func (s *Server) AddMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) {
+ u2f, err := s.repo.AddMyPasswordless(ctx)
+ return verifyWebAuthNFromModel(u2f), err
+}
+
+func (s *Server) VerifyMyPasswordless(ctx context.Context, request *auth.VerifyWebAuthN) (*empty.Empty, error) {
+ err := s.repo.VerifyMyPasswordlessSetup(ctx, request.TokenName, request.PublicKeyCredential)
+ return &empty.Empty{}, err
+}
+
+func (s *Server) RemoveMyPasswordless(ctx context.Context, id *auth.WebAuthNTokenID) (*empty.Empty, error) {
+ err := s.repo.RemoveMyPasswordless(ctx, id.Id)
return &empty.Empty{}, err
}
diff --git a/internal/api/grpc/auth/user_converter.go b/internal/api/grpc/auth/user_converter.go
index 376904b7d8..59b9daa844 100644
--- a/internal/api/grpc/auth/user_converter.go
+++ b/internal/api/grpc/auth/user_converter.go
@@ -12,7 +12,7 @@ import (
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/auth"
"github.com/caos/zitadel/pkg/grpc/message"
@@ -358,11 +358,11 @@ func genderToModel(gender auth.Gender) usr_model.Gender {
}
}
-func mfaStateFromModel(state usr_model.MfaState) auth.MFAState {
+func mfaStateFromModel(state usr_model.MFAState) auth.MFAState {
switch state {
- case usr_model.MfaStateReady:
+ case usr_model.MFAStateReady:
return auth.MFAState_MFASTATE_READY
- case usr_model.MfaStateNotReady:
+ case usr_model.MFAStateNotReady:
return auth.MFAState_MFASTATE_NOT_READY
default:
return auth.MFAState_MFASTATE_UNSPECIFIED
@@ -379,17 +379,18 @@ func mfasFromModel(mfas []*usr_model.MultiFactor) []*auth.MultiFactor {
func mfaFromModel(mfa *usr_model.MultiFactor) *auth.MultiFactor {
return &auth.MultiFactor{
- State: mfaStateFromModel(mfa.State),
- Type: mfaTypeFromModel(mfa.Type),
+ State: mfaStateFromModel(mfa.State),
+ Type: mfaTypeFromModel(mfa.Type),
+ Attribute: mfa.Attribute,
}
}
-func mfaTypeFromModel(mfatype usr_model.MfaType) auth.MfaType {
- switch mfatype {
- case usr_model.MfaTypeOTP:
+func mfaTypeFromModel(mfaType usr_model.MFAType) auth.MfaType {
+ switch mfaType {
+ case usr_model.MFATypeOTP:
return auth.MfaType_MFATYPE_OTP
- case usr_model.MfaTypeSMS:
- return auth.MfaType_MFATYPE_SMS
+ case usr_model.MFATypeU2F:
+ return auth.MfaType_MFATYPE_U2F
default:
return auth.MfaType_MFATYPE_UNSPECIFIED
}
@@ -426,3 +427,11 @@ func userChangesToAPI(changes *usr_model.UserChanges) (_ []*auth.Change) {
return result
}
+
+func verifyWebAuthNFromModel(u2f *usr_model.WebAuthNToken) *auth.WebAuthNResponse {
+ return &auth.WebAuthNResponse{
+ Id: u2f.WebAuthNTokenID,
+ PublicKey: u2f.PublicKey,
+ State: mfaStateFromModel(u2f.State),
+ }
+}
diff --git a/internal/api/grpc/management/login_policy_converter.go b/internal/api/grpc/management/login_policy_converter.go
index f43691e247..6399233a98 100644
--- a/internal/api/grpc/management/login_policy_converter.go
+++ b/internal/api/grpc/management/login_policy_converter.go
@@ -13,6 +13,7 @@ func loginPolicyRequestToModel(policy *management.LoginPolicyRequest) *iam_model
AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister,
ForceMFA: policy.ForceMfa,
+ PasswordlessType: passwordlessTypeToModel(policy.PasswordlessType),
}
}
@@ -30,6 +31,7 @@ func loginPolicyFromModel(policy *iam_model.LoginPolicy) *management.LoginPolicy
CreationDate: creationDate,
ChangeDate: changeDate,
ForceMfa: policy.ForceMFA,
+ PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
}
}
@@ -48,6 +50,7 @@ func loginPolicyViewFromModel(policy *iam_model.LoginPolicyView) *management.Log
CreationDate: creationDate,
ChangeDate: changeDate,
ForceMfa: policy.ForceMFA,
+ PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
}
}
@@ -215,3 +218,21 @@ func multiFactorTypeToModel(mfaType *management.MultiFactor) iam_model.MultiFact
return iam_model.MultiFactorTypeUnspecified
}
}
+
+func passwordlessTypeFromModel(passwordlessType iam_model.PasswordlessType) management.PasswordlessType {
+ switch passwordlessType {
+ case iam_model.PasswordlessTypeAllowed:
+ return management.PasswordlessType_PASSWORDLESSTYPE_ALLOWED
+ default:
+ return management.PasswordlessType_PASSWORDLESSTYPE_NOT_ALLOWED
+ }
+}
+
+func passwordlessTypeToModel(passwordlessType management.PasswordlessType) iam_model.PasswordlessType {
+ switch passwordlessType {
+ case management.PasswordlessType_PASSWORDLESSTYPE_ALLOWED:
+ return iam_model.PasswordlessTypeAllowed
+ default:
+ return iam_model.PasswordlessTypeNotAllowed
+ }
+}
diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go
index bf7f0abbd8..031503118c 100644
--- a/internal/api/grpc/management/user.go
+++ b/internal/api/grpc/management/user.go
@@ -214,7 +214,7 @@ func (s *Server) RemoveExternalIDP(ctx context.Context, request *management.Exte
}
func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.UserMultiFactors, error) {
- mfas, err := s.user.UserMfas(ctx, userID.Id)
+ mfas, err := s.user.UserMFAs(ctx, userID.Id)
if err != nil {
return nil, err
}
diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go
index c1e38301d7..5f10e61a72 100644
--- a/internal/api/grpc/management/user_converter.go
+++ b/internal/api/grpc/management/user_converter.go
@@ -572,22 +572,22 @@ func genderToModel(gender management.Gender) usr_model.Gender {
}
}
-func mfaTypeFromModel(mfatype usr_model.MfaType) management.MfaType {
+func mfaTypeFromModel(mfatype usr_model.MFAType) management.MfaType {
switch mfatype {
- case usr_model.MfaTypeOTP:
+ case usr_model.MFATypeOTP:
return management.MfaType_MFATYPE_OTP
- case usr_model.MfaTypeSMS:
- return management.MfaType_MFATYPE_SMS
+ case usr_model.MFATypeU2F:
+ return management.MfaType_MFATYPE_U2F
default:
return management.MfaType_MFATYPE_UNSPECIFIED
}
}
-func mfaStateFromModel(state usr_model.MfaState) management.MFAState {
+func mfaStateFromModel(state usr_model.MFAState) management.MFAState {
switch state {
- case usr_model.MfaStateReady:
+ case usr_model.MFAStateReady:
return management.MFAState_MFASTATE_READY
- case usr_model.MfaStateNotReady:
+ case usr_model.MFAStateNotReady:
return management.MFAState_MFASTATE_NOT_READY
default:
return management.MFAState_MFASTATE_UNSPECIFIED
diff --git a/internal/api/grpc/server/gateway.go b/internal/api/grpc/server/gateway.go
index 1833e905ff..675b0b41a9 100644
--- a/internal/api/grpc/server/gateway.go
+++ b/internal/api/grpc/server/gateway.go
@@ -14,7 +14,7 @@ import (
client_middleware "github.com/caos/zitadel/internal/api/grpc/client/middleware"
http_util "github.com/caos/zitadel/internal/api/http"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
const (
@@ -129,7 +129,8 @@ func createDialOptions(g Gateway) []grpc.DialOption {
}
func addInterceptors(handler http.Handler, g Gateway) http.Handler {
- handler = http_mw.DefaultTraceHandler(handler)
+ handler = http_mw.DefaultMetricsHandler(handler)
+ handler = http_mw.DefaultTelemetryHandler(handler)
handler = http_mw.NoCacheInterceptor(handler)
if interceptor, ok := g.(grpcGatewayCustomInterceptor); ok {
handler = interceptor.GatewayHTTPInterceptor(handler)
diff --git a/internal/api/grpc/server/middleware/auth_interceptor.go b/internal/api/grpc/server/middleware/auth_interceptor.go
index e46f661098..347e0b18f9 100644
--- a/internal/api/grpc/server/middleware/auth_interceptor.go
+++ b/internal/api/grpc/server/middleware/auth_interceptor.go
@@ -10,7 +10,7 @@ import (
"github.com/caos/zitadel/internal/api/authz"
grpc_util "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/api/http"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor {
diff --git a/internal/api/grpc/server/middleware/metrics_interceptor.go b/internal/api/grpc/server/middleware/metrics_interceptor.go
new file mode 100644
index 0000000000..4dcf6cc8a8
--- /dev/null
+++ b/internal/api/grpc/server/middleware/metrics_interceptor.go
@@ -0,0 +1,86 @@
+package middleware
+
+import (
+ "context"
+ "strings"
+
+ "github.com/grpc-ecosystem/grpc-gateway/runtime"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/status"
+
+ _ "github.com/caos/zitadel/internal/statik"
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+)
+
+const (
+ GrpcMethod = "grpc_method"
+ ReturnCode = "return_code"
+ GrpcRequestCounter = "grpc.server.request_counter"
+ GrpcRequestCounterDescription = "Grpc request counter"
+ TotalGrpcRequestCounter = "grpc.server.total_request_counter"
+ TotalGrpcRequestCounterDescription = "Total grpc request counter"
+ GrpcStatusCodeCounter = "grpc.server.grpc_status_code"
+ GrpcStatusCodeCounterDescription = "Grpc status code counter"
+)
+
+func MetricsHandler(metricTypes []metrics.MetricType, ignoredMethodSuffixes ...string) grpc.UnaryServerInterceptor {
+ return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
+ return RegisterMetrics(ctx, req, info, handler, metricTypes, ignoredMethodSuffixes...)
+ }
+}
+
+func RegisterMetrics(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, metricTypes []metrics.MetricType, ignoredMethodSuffixes ...string) (_ interface{}, err error) {
+ if len(metricTypes) == 0 {
+ return handler(ctx, req)
+ }
+
+ for _, ignore := range ignoredMethodSuffixes {
+ if strings.HasSuffix(info.FullMethod, ignore) {
+ return handler(ctx, req)
+ }
+ }
+
+ resp, err := handler(ctx, req)
+ if containsMetricsMethod(metrics.MetricTypeRequestCount, metricTypes) {
+ RegisterGrpcRequestCounter(ctx, info)
+ }
+ if containsMetricsMethod(metrics.MetricTypeTotalCount, metricTypes) {
+ RegisterGrpcTotalRequestCounter(ctx)
+ }
+ if containsMetricsMethod(metrics.MetricTypeStatusCode, metricTypes) {
+ RegisterGrpcRequestCodeCounter(ctx, info, err)
+ }
+ return resp, err
+}
+
+func RegisterGrpcRequestCounter(ctx context.Context, info *grpc.UnaryServerInfo) {
+ var labels = map[string]interface{}{
+ GrpcMethod: info.FullMethod,
+ }
+ metrics.RegisterCounter(GrpcRequestCounter, GrpcRequestCounterDescription)
+ metrics.AddCount(ctx, GrpcRequestCounter, 1, labels)
+}
+
+func RegisterGrpcTotalRequestCounter(ctx context.Context) {
+ metrics.RegisterCounter(TotalGrpcRequestCounter, TotalGrpcRequestCounterDescription)
+ metrics.AddCount(ctx, TotalGrpcRequestCounter, 1, nil)
+}
+
+func RegisterGrpcRequestCodeCounter(ctx context.Context, info *grpc.UnaryServerInfo, err error) {
+ statusCode := status.Code(err)
+ var labels = map[string]interface{}{
+ GrpcMethod: info.FullMethod,
+ ReturnCode: runtime.HTTPStatusFromCode(statusCode),
+ }
+ metrics.RegisterCounter(GrpcStatusCodeCounter, GrpcStatusCodeCounterDescription)
+ metrics.AddCount(ctx, GrpcStatusCodeCounter, 1, labels)
+}
+
+func containsMetricsMethod(metricType metrics.MetricType, metricTypes []metrics.MetricType) bool {
+ for _, m := range metricTypes {
+ if m == metricType {
+ return true
+ }
+ }
+ return false
+}
diff --git a/internal/api/grpc/server/probes.go b/internal/api/grpc/server/probes.go
index 434c07a1bf..e794a44655 100644
--- a/internal/api/grpc/server/probes.go
+++ b/internal/api/grpc/server/probes.go
@@ -9,7 +9,7 @@ import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/proto"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type ValidationFunction func(ctx context.Context) error
diff --git a/internal/api/grpc/server/server.go b/internal/api/grpc/server/server.go
index e5816ec7d9..ad8bf1699b 100644
--- a/internal/api/grpc/server/server.go
+++ b/internal/api/grpc/server/server.go
@@ -2,6 +2,8 @@ package server
import (
"context"
+ grpc_api "github.com/caos/zitadel/internal/api/grpc"
+ "github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/logging"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
@@ -11,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/grpc/server/middleware"
"github.com/caos/zitadel/internal/api/http"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
const (
@@ -27,10 +29,12 @@ type Server interface {
}
func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, lang language.Tag) *grpc.Server {
+ metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount, metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode}
return grpc.NewServer(
grpc.UnaryInterceptor(
grpc_middleware.ChainUnaryServer(
middleware.DefaultTracingServer(),
+ middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
middleware.ErrorHandler(),
middleware.AuthorizationInterceptor(verifier, authConfig),
middleware.TranslationHandler(lang),
diff --git a/internal/api/http/middleware/metrics_interceptor.go b/internal/api/http/middleware/metrics_interceptor.go
new file mode 100644
index 0000000000..a47f5b32ab
--- /dev/null
+++ b/internal/api/http/middleware/metrics_interceptor.go
@@ -0,0 +1,19 @@
+package middleware
+
+import (
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+ "net/http"
+
+ http_utils "github.com/caos/zitadel/internal/api/http"
+)
+
+func DefaultMetricsHandler(handler http.Handler) http.Handler {
+ metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount}
+ return MetricsHandler(metricTypes, http_utils.Probes...)(handler)
+}
+
+func MetricsHandler(metricTypes []metrics.MetricType, ignoredMethods ...string) func(http.Handler) http.Handler {
+ return func(handler http.Handler) http.Handler {
+ return metrics.NewMetricsHandler(handler, metricTypes, ignoredMethods...)
+ }
+}
diff --git a/internal/api/http/middleware/telemetry_interceptor.go b/internal/api/http/middleware/telemetry_interceptor.go
new file mode 100644
index 0000000000..bc447c0a1d
--- /dev/null
+++ b/internal/api/http/middleware/telemetry_interceptor.go
@@ -0,0 +1,18 @@
+package middleware
+
+import (
+ "github.com/caos/zitadel/internal/telemetry"
+ "net/http"
+
+ http_utils "github.com/caos/zitadel/internal/api/http"
+)
+
+func DefaultTelemetryHandler(handler http.Handler) http.Handler {
+ return TelemetryHandler(http_utils.Probes...)(handler)
+}
+
+func TelemetryHandler(ignoredMethods ...string) func(http.Handler) http.Handler {
+ return func(handler http.Handler) http.Handler {
+ return telemetry.TelemetryHandler(handler, ignoredMethods...)
+ }
+}
diff --git a/internal/api/http/middleware/trace_interceptor.go b/internal/api/http/middleware/trace_interceptor.go
deleted file mode 100644
index af800c95ff..0000000000
--- a/internal/api/http/middleware/trace_interceptor.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package middleware
-
-import (
- "net/http"
-
- http_utils "github.com/caos/zitadel/internal/api/http"
- "github.com/caos/zitadel/internal/tracing"
-)
-
-func DefaultTraceHandler(handler http.Handler) http.Handler {
- return TraceHandler(http_utils.Probes...)(handler)
-}
-
-func TraceHandler(ignoredMethods ...string) func(http.Handler) http.Handler {
- return func(handler http.Handler) http.Handler {
- return tracing.TraceHandler(handler, ignoredMethods...)
- }
-}
diff --git a/internal/api/http/server.go b/internal/api/http/server.go
index f663b2acd0..489fcc7ec9 100644
--- a/internal/api/http/server.go
+++ b/internal/api/http/server.go
@@ -5,7 +5,7 @@ import (
"net/http"
"github.com/caos/logging"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
func Serve(ctx context.Context, handler http.Handler, port, servername string) {
diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go
index 07e2f497b0..e1c57c64b5 100644
--- a/internal/api/oidc/auth_request.go
+++ b/internal/api/oidc/auth_request.go
@@ -13,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
)
diff --git a/internal/api/oidc/auth_request_converter.go b/internal/api/oidc/auth_request_converter.go
index 06dba25dfe..5dd4dc15b6 100644
--- a/internal/api/oidc/auth_request_converter.go
+++ b/internal/api/oidc/auth_request_converter.go
@@ -15,9 +15,10 @@ import (
)
const (
- amrPassword = "password"
- amrMFA = "mfa"
- amrOTP = "otp"
+ amrPassword = "password"
+ amrMFA = "mfa"
+ amrOTP = "otp"
+ amrUserPresence = "user"
)
type AuthRequest struct {
@@ -38,11 +39,11 @@ func (a *AuthRequest) GetAMR() []string {
if a.PasswordVerified {
amr = append(amr, amrPassword)
}
- if len(a.MfasVerified) > 0 {
+ if len(a.MFAsVerified) > 0 {
amr = append(amr, amrMFA)
- for _, mfa := range a.MfasVerified {
- if amrMfa := AMRFromMFAType(mfa); amrMfa != "" {
- amr = append(amr, amrMfa)
+ for _, mfa := range a.MFAsVerified {
+ if amrMFA := AMRFromMFAType(mfa); amrMFA != "" {
+ amr = append(amr, amrMFA)
}
}
}
@@ -247,6 +248,9 @@ func AMRFromMFAType(mfaType model.MFAType) string {
switch mfaType {
case model.MFATypeOTP:
return amrOTP
+ case model.MFATypeU2F,
+ model.MFATypeU2FUserVerification:
+ return amrUserPresence
default:
return ""
}
diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go
index a59176b66a..760c8a007d 100644
--- a/internal/api/oidc/client.go
+++ b/internal/api/oidc/client.go
@@ -16,7 +16,7 @@ import (
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
)
diff --git a/internal/api/oidc/op.go b/internal/api/oidc/op.go
index d3ba142264..f5a11012bf 100644
--- a/internal/api/oidc/op.go
+++ b/internal/api/oidc/op.go
@@ -2,6 +2,7 @@ package oidc
import (
"context"
+ "github.com/caos/zitadel/internal/telemetry/metrics"
"time"
"github.com/caos/logging"
@@ -12,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/auth/repository"
"github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/id"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type OPHandlerConfig struct {
@@ -55,12 +56,14 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re
cookieHandler, err := middleware.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator, localDevMode)
logging.Log("OIDC-sd4fd").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Panic("cannot user agent handler")
config.OPConfig.CodeMethodS256 = true
+ metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount}
provider, err := op.NewOpenIDProvider(
ctx,
config.OPConfig,
newStorage(config.StorageConfig, repo),
op.WithHttpInterceptors(
- middleware.TraceHandler(),
+ middleware.MetricsHandler(metricTypes),
+ middleware.TelemetryHandler(),
middleware.NoCacheInterceptor,
cookieHandler,
http_utils.CopyHeadersToContext,
diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go
index c3301296a6..3aaab44596 100644
--- a/internal/auth/repository/auth_request.go
+++ b/internal/auth/repository/auth_request.go
@@ -2,10 +2,9 @@ package repository
import (
"context"
+ "github.com/caos/zitadel/internal/auth_request/model"
org_model "github.com/caos/zitadel/internal/org/model"
user_model "github.com/caos/zitadel/internal/user/model"
-
- "github.com/caos/zitadel/internal/auth_request/model"
)
type AuthRequestRepository interface {
@@ -15,14 +14,22 @@ type AuthRequestRepository interface {
AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error)
SaveAuthCode(ctx context.Context, id, code, userAgentID string) error
DeleteAuthRequest(ctx context.Context, id string) error
+
CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error
CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *model.ExternalUser, info *model.BrowserInfo) error
SelectUser(ctx context.Context, id, userID, userAgentID string) error
SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error
VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) error
- VerifyMfaOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error
+
+ VerifyMFAOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error
+ BeginMFAU2FLogin(ctx context.Context, userID, authRequestID, userAgentID string) (*user_model.WebAuthNLogin, error)
+ VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) error
+ BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (*user_model.WebAuthNLogin, error)
+ VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) error
+
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) error
AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) error
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
+
GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error)
}
diff --git a/internal/auth/repository/eventsourcing/eventstore/application.go b/internal/auth/repository/eventsourcing/eventstore/application.go
index 5d5bc76102..95540846fb 100644
--- a/internal/auth/repository/eventsourcing/eventstore/application.go
+++ b/internal/auth/repository/eventsourcing/eventstore/application.go
@@ -7,6 +7,7 @@ import (
"github.com/caos/zitadel/internal/project/model"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type ApplicationRepo struct {
@@ -22,7 +23,10 @@ func (a *ApplicationRepo) ApplicationByClientID(ctx context.Context, clientID st
return proj_view_model.ApplicationViewToModel(app), nil
}
-func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) error {
+func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) (err error) {
+ ctx, span := tracing.NewSpan(ctx)
+ defer func() { span.EndWithError(err) }()
+
app, err := a.View.ApplicationByClientID(ctx, clientID)
if err != nil {
return err
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
index 22e1d73d39..7c7a7bb8ea 100644
--- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go
+++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go
@@ -21,7 +21,7 @@ import (
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
project_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
@@ -47,7 +47,7 @@ type AuthRequestRepo struct {
PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration
- MfaInitSkippedLifeTime time.Duration
+ MFAInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration
@@ -245,27 +245,62 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge
func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
- request, err := repo.getAuthRequest(ctx, id, userAgentID)
+ request, err := repo.getAuthRequestEnsureUser(ctx, id, userAgentID, userID)
if err != nil {
return err
}
- if request.UserID != userID {
- return errors.ThrowPreconditionFailed(nil, "EVENT-ds35D", "Errors.User.NotMatchingUserID")
- }
return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info))
}
-func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) (err error) {
+func (repo *AuthRequestRepo) VerifyMFAOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
- request, err := repo.getAuthRequest(ctx, authRequestID, userAgentID)
+ request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
if err != nil {
return err
}
- if request.UserID != userID {
- return errors.ThrowPreconditionFailed(nil, "EVENT-ADJ26", "Errors.User.NotMatchingUserID")
+ return repo.UserEvents.CheckMFAOTP(ctx, userID, code, request.WithCurrentInfo(info))
+}
+
+func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) {
+ ctx, span := tracing.NewSpan(ctx)
+ defer func() { span.EndWithError(err) }()
+
+ request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
+ if err != nil {
+ return nil, err
}
- return repo.UserEvents.CheckMfaOTP(ctx, userID, code, request.WithCurrentInfo(info))
+ return repo.UserEvents.BeginU2FLogin(ctx, userID, request)
+}
+
+func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) {
+ ctx, span := tracing.NewSpan(ctx)
+ defer func() { span.EndWithError(err) }()
+ request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
+ if err != nil {
+ return err
+ }
+ return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request)
+}
+
+func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) {
+ ctx, span := tracing.NewSpan(ctx)
+ defer func() { span.EndWithError(err) }()
+ request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
+ if err != nil {
+ return nil, err
+ }
+ return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request)
+}
+
+func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) {
+ ctx, span := tracing.NewSpan(ctx)
+ defer func() { span.EndWithError(err) }()
+ request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
+ if err != nil {
+ return err
+ }
+ return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request)
}
func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) {
@@ -365,6 +400,17 @@ func (repo *AuthRequestRepo) getAuthRequestNextSteps(ctx context.Context, id, us
return request, nil
}
+func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authRequestID, userAgentID, userID string) (*model.AuthRequest, error) {
+ request, err := repo.getAuthRequest(ctx, authRequestID, userAgentID)
+ if err != nil {
+ return nil, err
+ }
+ if request.UserID != userID {
+ return nil, errors.ThrowPreconditionFailed(nil, "EVENT-GBH32", "Errors.User.NotMatchingUserID")
+ }
+ return request, nil
+}
+
func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) {
request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id)
if err != nil {
@@ -545,27 +591,19 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
return nil, err
}
- if (request.SelectedIDPConfigID != "" || userSession.SelectedIDPConfigID != "") && (request.LinkingUsers == nil || len(request.LinkingUsers) == 0) {
- if !checkVerificationTime(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime) {
- selectedIDPConfigID := request.SelectedIDPConfigID
- if selectedIDPConfigID == "" {
- selectedIDPConfigID = userSession.SelectedIDPConfigID
- }
- return append(steps, &model.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil
+ isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == ""
+ if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTime(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime) {
+ selectedIDPConfigID := request.SelectedIDPConfigID
+ if selectedIDPConfigID == "" {
+ selectedIDPConfigID = userSession.SelectedIDPConfigID
}
- } else if (request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == "") || (request.SelectedIDPConfigID != "" && request.LinkingUsers != nil && len(request.LinkingUsers) > 0) {
- if user.InitRequired {
- return append(steps, &model.InitUserStep{PasswordSet: user.PasswordSet}), nil
+ return append(steps, &model.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil
+ }
+ if isInternalLogin || (!isInternalLogin && len(request.LinkingUsers) > 0) {
+ step := repo.firstFactorChecked(request, user, userSession)
+ if step != nil {
+ return append(steps, step), nil
}
- if !user.PasswordSet {
- return append(steps, &model.InitPasswordStep{}), nil
- }
-
- if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) {
- return append(steps, &model.PasswordStep{}), nil
- }
- request.PasswordVerified = true
- request.AuthTime = userSession.PasswordVerification
}
step, ok, err := repo.mfaChecked(userSession, request, user)
@@ -624,21 +662,46 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
return users, nil
}
+func (repo *AuthRequestRepo) firstFactorChecked(request *model.AuthRequest, user *user_model.UserView, userSession *user_model.UserSessionView) model.NextStep {
+ if user.InitRequired {
+ return &model.InitUserStep{PasswordSet: user.PasswordSet}
+ }
+
+ if user.IsPasswordlessReady() {
+ if !checkVerificationTime(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime) {
+ return &model.PasswordlessStep{}
+ }
+ request.AuthTime = userSession.PasswordlessVerification
+ return nil
+ }
+
+ if !user.PasswordSet {
+ return &model.InitPasswordStep{}
+ }
+
+ if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) {
+ return &model.PasswordStep{}
+ }
+ request.PasswordVerified = true
+ request.AuthTime = userSession.PasswordVerification
+ return nil
+}
+
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) {
- mfaLevel := request.MfaLevel()
- allowedProviders, required := user.MfaTypesAllowed(mfaLevel, request.LoginPolicy)
- promptRequired := (user.MfaMaxSetUp < mfaLevel) || (len(allowedProviders) == 0 && required)
+ mfaLevel := request.MFALevel()
+ allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy)
+ promptRequired := (user.MFAMaxSetUp < mfaLevel) || (len(allowedProviders) == 0 && required)
if promptRequired || !repo.mfaSkippedOrSetUp(user) {
- types := user.MfaTypesSetupPossible(mfaLevel, request.LoginPolicy)
+ types := user.MFATypesSetupPossible(mfaLevel, request.LoginPolicy)
if promptRequired && len(types) == 0 {
return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured")
}
if len(types) == 0 {
return nil, true, nil
}
- return &model.MfaPromptStep{
+ return &model.MFAPromptStep{
Required: promptRequired,
- MfaProviders: types,
+ MFAProviders: types,
}, false, nil
}
switch mfaLevel {
@@ -651,28 +714,28 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
fallthrough
case model.MFALevelSecondFactor:
if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) {
- request.MfasVerified = append(request.MfasVerified, userSession.SecondFactorVerificationType)
+ request.MFAsVerified = append(request.MFAsVerified, userSession.SecondFactorVerificationType)
request.AuthTime = userSession.SecondFactorVerification
return nil, true, nil
}
fallthrough
case model.MFALevelMultiFactor:
if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) {
- request.MfasVerified = append(request.MfasVerified, userSession.MultiFactorVerificationType)
+ request.MFAsVerified = append(request.MFAsVerified, userSession.MultiFactorVerificationType)
request.AuthTime = userSession.MultiFactorVerification
return nil, true, nil
}
}
- return &model.MfaVerificationStep{
- MfaProviders: allowedProviders,
+ return &model.MFAVerificationStep{
+ MFAProviders: allowedProviders,
}, false, nil
}
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool {
- if user.MfaMaxSetUp > model.MFALevelNotSetUp {
+ if user.MFAMaxSetUp > model.MFALevelNotSetUp {
return true
}
- return checkVerificationTime(user.MfaInitSkipped, repo.MfaInitSkippedLifeTime)
+ return checkVerificationTime(user.MFAInitSkipped, repo.MFAInitSkippedLifeTime)
}
func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) (*iam_model.LoginPolicyView, error) {
@@ -745,7 +808,11 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
es_model.HumanExternalLoginCheckSucceeded,
es_model.HumanMFAOTPCheckSucceeded,
es_model.HumanMFAOTPCheckFailed,
- es_model.HumanSignedOut:
+ es_model.HumanSignedOut,
+ es_model.HumanPasswordlessTokenCheckSucceeded,
+ es_model.HumanPasswordlessTokenCheckFailed,
+ es_model.HumanMFAU2FTokenCheckSucceeded,
+ es_model.HumanMFAU2FTokenCheckFailed:
eventData, err := user_view_model.UserSessionFromEvent(event)
if err != nil {
logging.Log("EVENT-sdgT3").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("error getting event data")
diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go
index e12ea165e5..345bbfc727 100644
--- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go
+++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go
@@ -48,8 +48,10 @@ func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*user_view_mod
type mockViewUserSession struct {
ExternalLoginVerification time.Time
+ PasswordlessVerification time.Time
PasswordVerification time.Time
SecondFactorVerification time.Time
+ MultiFactorVerification time.Time
Users []mockUser
}
@@ -61,8 +63,10 @@ type mockUser struct {
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
return &user_view_model.UserSessionView{
ExternalLoginVerification: m.ExternalLoginVerification,
+ PasswordlessVerification: m.PasswordlessVerification,
PasswordVerification: m.PasswordVerification,
SecondFactorVerification: m.SecondFactorVerification,
+ MultiFactorVerification: m.MultiFactorVerification,
}, nil
}
@@ -115,8 +119,9 @@ type mockViewUser struct {
PasswordChangeRequired bool
IsEmailVerified bool
OTPState int32
- MfaMaxSetUp int32
- MfaInitSkipped time.Time
+ MFAMaxSetUp int32
+ MFAInitSkipped time.Time
+ PasswordlessTokens user_view_model.WebAuthNTokens
}
type mockLoginPolicy struct {
@@ -138,8 +143,9 @@ func (m *mockViewUser) UserByID(string) (*user_view_model.UserView, error) {
PasswordChangeRequired: m.PasswordChangeRequired,
IsEmailVerified: m.IsEmailVerified,
OTPState: m.OTPState,
- MfaMaxSetUp: m.MfaMaxSetUp,
- MfaInitSkipped: m.MfaInitSkipped,
+ MFAMaxSetUp: m.MFAMaxSetUp,
+ MFAInitSkipped: m.MFAInitSkipped,
+ PasswordlessTokens: m.PasswordlessTokens,
},
}, nil
}
@@ -200,7 +206,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
loginPolicyProvider loginPolicyViewProvider
PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration
- MfaInitSkippedLifeTime time.Duration
+ MFAInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration
}
@@ -413,6 +419,49 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}},
nil,
},
+ {
+ "passwordless not verified, passwordless check step",
+ fields{
+ userSessionViewProvider: &mockViewUserSession{},
+ userViewProvider: &mockViewUser{
+ PasswordSet: true,
+ PasswordlessTokens: user_view_model.WebAuthNTokens{&user_view_model.WebAuthNView{ID: "id", State: int32(user_model.MFAStateReady)}},
+ },
+ userEventProvider: &mockEventUser{},
+ orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
+ MultiFactorCheckLifeTime: 10 * time.Hour,
+ },
+ args{&model.AuthRequest{UserID: "UserID"}, false},
+ []model.NextStep{&model.PasswordlessStep{}},
+ nil,
+ },
+ {
+ "passwordless verified, email not verified, email verification step",
+ fields{
+ userSessionViewProvider: &mockViewUserSession{
+ PasswordlessVerification: time.Now().Add(-5 * time.Minute),
+ MultiFactorVerification: time.Now().Add(-5 * time.Minute),
+ },
+ userViewProvider: &mockViewUser{
+ PasswordSet: true,
+ PasswordlessTokens: user_view_model.WebAuthNTokens{&user_view_model.WebAuthNView{ID: "id", State: int32(user_model.MFAStateReady)}},
+ PasswordChangeRequired: false,
+ IsEmailVerified: false,
+ MFAMaxSetUp: int32(model.MFALevelMultiFactor),
+ },
+ userEventProvider: &mockEventUser{},
+ orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
+ MultiFactorCheckLifeTime: 10 * time.Hour,
+ },
+ args{&model.AuthRequest{
+ UserID: "UserID",
+ LoginPolicy: &iam_model.LoginPolicyView{
+ MultiFactors: []iam_model.MultiFactorType{iam_model.MultiFactorTypeU2FWithPIN},
+ },
+ }, false},
+ []model.NextStep{&model.VerifyEMailStep{}},
+ nil,
+ },
{
"password not set, init password step",
fields{
@@ -433,7 +482,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userViewProvider: &mockViewUser{
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -452,7 +501,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userViewProvider: &mockViewUser{
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -499,7 +548,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -525,8 +574,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userViewProvider: &mockViewUser{
PasswordSet: true,
- OTPState: int32(user_model.MfaStateReady),
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ OTPState: int32(user_model.MFAStateReady),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -540,8 +589,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
- []model.NextStep{&model.MfaVerificationStep{
- MfaProviders: []model.MFAType{model.MFATypeOTP},
+ []model.NextStep{&model.MFAVerificationStep{
+ MFAProviders: []model.MFAType{model.MFATypeOTP},
}},
nil,
},
@@ -554,8 +603,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userViewProvider: &mockViewUser{
PasswordSet: true,
- OTPState: int32(user_model.MfaStateReady),
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ OTPState: int32(user_model.MFAStateReady),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -571,8 +620,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
},
}, false},
- []model.NextStep{&model.MfaVerificationStep{
- MfaProviders: []model.MFAType{model.MFATypeOTP},
+ []model.NextStep{&model.MFAVerificationStep{
+ MFAProviders: []model.MFAType{model.MFATypeOTP},
}},
nil,
},
@@ -587,7 +636,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
PasswordSet: true,
PasswordChangeRequired: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -613,7 +662,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userViewProvider: &mockViewUser{
PasswordSet: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -639,7 +688,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
PasswordChangeRequired: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -665,7 +714,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -693,7 +742,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -722,7 +771,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -754,7 +803,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -785,7 +834,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -810,7 +859,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
- MfaMaxSetUp: int32(model.MFALevelSecondFactor),
+ MFAMaxSetUp: int32(model.MFALevelSecondFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@@ -844,7 +893,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
- MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
+ MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
}
@@ -860,7 +909,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
func TestAuthRequestRepo_mfaChecked(t *testing.T) {
type fields struct {
- MfaInitSkippedLifeTime time.Duration
+ MFAInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration
}
@@ -884,7 +933,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
// args{
// request: &model.AuthRequest{PossibleLOAs: []model.LevelOfAssurance{}},
// user: &user_model.UserView{
- // OTPState: user_model.MfaStateReady,
+ // OTPState: user_model.MFAStateReady,
// },
// },
// false,
@@ -892,7 +941,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{
"not set up, forced by policy, no mfas configured, error",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
@@ -902,7 +951,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelNotSetUp,
+ MFAMaxSetUp: model.MFALevelNotSetUp,
},
},
},
@@ -913,7 +962,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{
"not set up, no mfas configured, no prompt and true",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
@@ -921,7 +970,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelNotSetUp,
+ MFAMaxSetUp: model.MFALevelNotSetUp,
},
},
},
@@ -932,7 +981,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{
"not set up, prompt and false",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
@@ -942,12 +991,12 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelNotSetUp,
+ MFAMaxSetUp: model.MFALevelNotSetUp,
},
},
},
- &model.MfaPromptStep{
- MfaProviders: []model.MFAType{
+ &model.MFAPromptStep{
+ MFAProviders: []model.MFAType{
model.MFATypeOTP,
},
},
@@ -957,7 +1006,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{
"not set up, forced by org, true",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
@@ -968,13 +1017,13 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelNotSetUp,
+ MFAMaxSetUp: model.MFALevelNotSetUp,
},
},
},
- &model.MfaPromptStep{
+ &model.MFAPromptStep{
Required: true,
- MfaProviders: []model.MFAType{
+ MFAProviders: []model.MFAType{
model.MFATypeOTP,
},
},
@@ -984,7 +1033,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{
"not set up and skipped, true",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
request: &model.AuthRequest{
@@ -992,8 +1041,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelNotSetUp,
- MfaInitSkipped: time.Now().UTC(),
+ MFAMaxSetUp: model.MFALevelNotSetUp,
+ MFAInitSkipped: time.Now().UTC(),
},
},
},
@@ -1014,8 +1063,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelSecondFactor,
- OTPState: user_model.MfaStateReady,
+ MFAMaxSetUp: model.MFALevelSecondFactor,
+ OTPState: user_model.MFAStateReady,
},
},
userSession: &user_model.UserSessionView{SecondFactorVerification: time.Now().UTC().Add(-5 * time.Hour)},
@@ -1037,15 +1086,15 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
},
user: &user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelSecondFactor,
- OTPState: user_model.MfaStateReady,
+ MFAMaxSetUp: model.MFALevelSecondFactor,
+ OTPState: user_model.MFAStateReady,
},
},
userSession: &user_model.UserSessionView{},
},
- &model.MfaVerificationStep{
- MfaProviders: []model.MFAType{model.MFATypeOTP},
+ &model.MFAVerificationStep{
+ MFAProviders: []model.MFAType{model.MFATypeOTP},
},
false,
nil,
@@ -1054,7 +1103,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := &AuthRequestRepo{
- MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
+ MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
}
@@ -1073,7 +1122,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
type fields struct {
- MfaInitSkippedLifeTime time.Duration
+ MFAInitSkippedLifeTime time.Duration
}
type args struct {
user *user_model.UserView
@@ -1090,7 +1139,7 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
args{
&user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: model.MFALevelSecondFactor,
+ MFAMaxSetUp: model.MFALevelSecondFactor,
},
},
},
@@ -1099,13 +1148,13 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
{
"mfa skipped active, true",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
&user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: -1,
- MfaInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
+ MFAMaxSetUp: -1,
+ MFAInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
},
},
},
@@ -1114,13 +1163,13 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
{
"mfa skipped inactive, false",
fields{
- MfaInitSkippedLifeTime: 30 * 24 * time.Hour,
+ MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
},
args{
&user_model.UserView{
HumanView: &user_model.HumanView{
- MfaMaxSetUp: -1,
- MfaInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
+ MFAMaxSetUp: -1,
+ MFAInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
},
},
},
@@ -1130,7 +1179,7 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := &AuthRequestRepo{
- MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,
+ MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
}
if got := repo.mfaSkippedOrSetUp(tt.args.user); got != tt.want {
t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want)
diff --git a/internal/auth/repository/eventsourcing/eventstore/org.go b/internal/auth/repository/eventsourcing/eventstore/org.go
index f521a00a77..c5f3ecced0 100644
--- a/internal/auth/repository/eventsourcing/eventstore/org.go
+++ b/internal/auth/repository/eventsourcing/eventstore/org.go
@@ -9,7 +9,7 @@ import (
"github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
auth_model "github.com/caos/zitadel/internal/auth/model"
auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
@@ -50,7 +50,7 @@ func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.Or
}
if err == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
diff --git a/internal/auth/repository/eventsourcing/eventstore/token.go b/internal/auth/repository/eventsourcing/eventstore/token.go
index 0d7d378bc8..ec3e81aa7b 100644
--- a/internal/auth/repository/eventsourcing/eventstore/token.go
+++ b/internal/auth/repository/eventsourcing/eventstore/token.go
@@ -3,17 +3,18 @@ package eventstore
import (
"context"
"strings"
- "time"
"github.com/caos/logging"
- "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
auth_req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
"github.com/caos/zitadel/internal/user/repository/view/model"
+ "time"
+
+ "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
)
type TokenRepo struct {
diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go
index 9541625986..af6d62b2b1 100644
--- a/internal/auth/repository/eventsourcing/eventstore/user.go
+++ b/internal/auth/repository/eventsourcing/eventstore/user.go
@@ -16,7 +16,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/sdk"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
@@ -124,7 +124,7 @@ func (repo *UserRepo) SearchMyExternalIDPs(ctx context.Context, request *model.E
}
if seqErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -253,18 +253,22 @@ func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new strin
return err
}
-func (repo *UserRepo) MyUserMfas(ctx context.Context) ([]*model.MultiFactor, error) {
+func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, error) {
user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID)
if err != nil {
return nil, err
}
- if user.OTPState == model.MfaStateUnspecified {
- return []*model.MultiFactor{}, nil
+ mfas := make([]*model.MultiFactor, 0)
+ if user.OTPState != model.MFAStateUnspecified {
+ mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeOTP, State: user.OTPState})
}
- return []*model.MultiFactor{{Type: model.MfaTypeOTP, State: user.OTPState}}, nil
+ for _, u2f := range user.U2FTokens {
+ mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name})
+ }
+ return mfas, nil
}
-func (repo *UserRepo) AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) {
+func (repo *UserRepo) AddMFAOTP(ctx context.Context, userID string) (*model.OTP, error) {
accountName := ""
user, err := repo.UserByID(ctx, userID)
if err != nil {
@@ -275,7 +279,7 @@ func (repo *UserRepo) AddMfaOTP(ctx context.Context, userID string) (*model.OTP,
return repo.UserEvents.AddOTP(ctx, userID, accountName)
}
-func (repo *UserRepo) AddMyMfaOTP(ctx context.Context) (*model.OTP, error) {
+func (repo *UserRepo) AddMyMFAOTP(ctx context.Context) (*model.OTP, error) {
accountName := ""
user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID)
if err != nil {
@@ -286,18 +290,66 @@ func (repo *UserRepo) AddMyMfaOTP(ctx context.Context) (*model.OTP, error) {
return repo.UserEvents.AddOTP(ctx, authz.GetCtxData(ctx).UserID, accountName)
}
-func (repo *UserRepo) VerifyMfaOTPSetup(ctx context.Context, userID, code string) error {
- return repo.UserEvents.CheckMfaOTPSetup(ctx, userID, code)
+func (repo *UserRepo) VerifyMFAOTPSetup(ctx context.Context, userID, code string) error {
+ return repo.UserEvents.CheckMFAOTPSetup(ctx, userID, code)
}
-func (repo *UserRepo) VerifyMyMfaOTPSetup(ctx context.Context, code string) error {
- return repo.UserEvents.CheckMfaOTPSetup(ctx, authz.GetCtxData(ctx).UserID, code)
+func (repo *UserRepo) VerifyMyMFAOTPSetup(ctx context.Context, code string) error {
+ return repo.UserEvents.CheckMFAOTPSetup(ctx, authz.GetCtxData(ctx).UserID, code)
}
-func (repo *UserRepo) RemoveMyMfaOTP(ctx context.Context) error {
+func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error {
return repo.UserEvents.RemoveOTP(ctx, authz.GetCtxData(ctx).UserID)
}
+func (repo *UserRepo) AddMFAU2F(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
+ return repo.UserEvents.AddU2F(ctx, userID)
+}
+
+func (repo *UserRepo) AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) {
+ return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID)
+}
+
+func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
+ return repo.UserEvents.VerifyU2FSetup(ctx, userID, tokenName, credentialData)
+}
+
+func (repo *UserRepo) VerifyMyMFAU2FSetup(ctx context.Context, tokenName string, credentialData []byte) error {
+ return repo.UserEvents.VerifyU2FSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, credentialData)
+}
+
+func (repo *UserRepo) RemoveMFAU2F(ctx context.Context, userID, webAuthNTokenID string) error {
+ return repo.UserEvents.RemoveU2FToken(ctx, userID, webAuthNTokenID)
+}
+
+func (repo *UserRepo) RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string) error {
+ return repo.UserEvents.RemoveU2FToken(ctx, authz.GetCtxData(ctx).UserID, webAuthNTokenID)
+}
+
+func (repo *UserRepo) AddPasswordless(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
+ return repo.UserEvents.AddPasswordless(ctx, userID)
+}
+
+func (repo *UserRepo) AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error) {
+ return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID)
+}
+
+func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
+ return repo.UserEvents.VerifyPasswordlessSetup(ctx, userID, tokenName, credentialData)
+}
+
+func (repo *UserRepo) VerifyMyPasswordlessSetup(ctx context.Context, tokenName string, credentialData []byte) error {
+ return repo.UserEvents.VerifyPasswordlessSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, credentialData)
+}
+
+func (repo *UserRepo) RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error {
+ return repo.UserEvents.RemovePasswordlessToken(ctx, userID, webAuthNTokenID)
+}
+
+func (repo *UserRepo) RemoveMyPasswordless(ctx context.Context, webAuthNTokenID string) error {
+ return repo.UserEvents.RemovePasswordlessToken(ctx, authz.GetCtxData(ctx).UserID, webAuthNTokenID)
+}
+
func (repo *UserRepo) ChangeMyUsername(ctx context.Context, username string) error {
ctxData := authz.GetCtxData(ctx)
orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(ctxData.OrgID)
@@ -327,8 +379,8 @@ func (repo *UserRepo) VerifyInitCode(ctx context.Context, userID, code, password
return repo.UserEvents.VerifyInitCode(ctx, pwPolicyView, userID, code, password)
}
-func (repo *UserRepo) SkipMfaInit(ctx context.Context, userID string) error {
- return repo.UserEvents.SkipMfaInit(ctx, userID)
+func (repo *UserRepo) SkipMFAInit(ctx context.Context, userID string) error {
+ return repo.UserEvents.SkipMFAInit(ctx, userID)
}
func (repo *UserRepo) RequestPasswordReset(ctx context.Context, loginname string) error {
diff --git a/internal/auth/repository/eventsourcing/eventstore/user_grant.go b/internal/auth/repository/eventsourcing/eventstore/user_grant.go
index 038d0f0a53..cba39e4314 100644
--- a/internal/auth/repository/eventsourcing/eventstore/user_grant.go
+++ b/internal/auth/repository/eventsourcing/eventstore/user_grant.go
@@ -12,7 +12,7 @@ import (
global_model "github.com/caos/zitadel/internal/model"
org_model "github.com/caos/zitadel/internal/org/model"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
@@ -44,7 +44,7 @@ func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *gran
}
if err == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
diff --git a/internal/auth/repository/eventsourcing/eventstore/user_session.go b/internal/auth/repository/eventsourcing/eventstore/user_session.go
index e3a8b53f6b..28246193c3 100644
--- a/internal/auth/repository/eventsourcing/eventstore/user_session.go
+++ b/internal/auth/repository/eventsourcing/eventstore/user_session.go
@@ -20,3 +20,8 @@ func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_mode
}
return model.UserSessionsToModel(userSessions), nil
}
+
+func (repo *UserSessionRepo) ActiveUserSessionCount() int64 {
+ userSessions, _ := repo.View.ActiveUserSessions()
+ return int64(len(userSessions))
+}
diff --git a/internal/auth/repository/eventsourcing/handler/application.go b/internal/auth/repository/eventsourcing/handler/application.go
index eccd0d36ab..377e0b0499 100644
--- a/internal/auth/repository/eventsourcing/handler/application.go
+++ b/internal/auth/repository/eventsourcing/handler/application.go
@@ -22,12 +22,12 @@ const (
applicationTable = "auth.applications"
)
-func (p *Application) ViewModel() string {
+func (a *Application) ViewModel() string {
return applicationTable
}
-func (p *Application) EventQuery() (*models.SearchQuery, error) {
- sequence, err := p.view.GetLatestApplicationSequence()
+func (a *Application) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := a.view.GetLatestApplicationSequence()
if err != nil {
return nil, err
}
@@ -65,33 +65,37 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return a.view.DeleteApplication(app.ID, event.Sequence)
+ return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
case es_model.ProjectChanged:
apps, err := a.view.ApplicationsByProjectID(event.AggregateID)
if err != nil {
return err
}
if len(apps) == 0 {
- return a.view.ProcessedApplicationSequence(event.Sequence)
+ return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
}
for _, app := range apps {
if err := app.AppendEvent(event); err != nil {
return err
}
}
- return a.view.PutApplications(apps, event.Sequence)
+ return a.view.PutApplications(apps, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved:
return a.view.DeleteApplicationsByProjectID(event.AggregateID)
default:
- return a.view.ProcessedApplicationSequence(event.Sequence)
+ return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return a.view.PutApplication(app)
+ return a.view.PutApplication(app, event.CreationDate)
}
-func (p *Application) OnError(event *models.Event, spoolerError error) error {
+func (a *Application) OnError(event *models.Event, spoolerError error) error {
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerError).Warn("something went wrong in project app handler")
- return spooler.HandleError(event, spoolerError, p.view.GetLatestApplicationFailedEvent, p.view.ProcessedApplicationFailedEvent, p.view.ProcessedApplicationSequence, p.errorCountUntilSkip)
+ return spooler.HandleError(event, spoolerError, a.view.GetLatestApplicationFailedEvent, a.view.ProcessedApplicationFailedEvent, a.view.ProcessedApplicationSequence, a.errorCountUntilSkip)
+}
+
+func (a *Application) OnSuccess() error {
+ return spooler.HandleSuccess(a.view.UpdateApplicationSpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/idp_config.go b/internal/auth/repository/eventsourcing/handler/idp_config.go
index 0460b32a9b..e6c21a6260 100644
--- a/internal/auth/repository/eventsourcing/handler/idp_config.go
+++ b/internal/auth/repository/eventsourcing/handler/idp_config.go
@@ -19,12 +19,12 @@ const (
idpConfigTable = "auth.idp_configs"
)
-func (m *IDPConfig) ViewModel() string {
+func (i *IDPConfig) ViewModel() string {
return idpConfigTable
}
-func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIDPConfigSequence()
+func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestIDPConfigSequence()
if err != nil {
return nil, err
}
@@ -33,17 +33,17 @@ func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IDPConfig) Reduce(event *models.Event) (err error) {
+func (i *IDPConfig) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate:
- err = m.processIdpConfig(iam_model.IDPProviderTypeOrg, event)
+ err = i.processIdpConfig(iam_model.IDPProviderTypeOrg, event)
case iam_es_model.IAMAggregate:
- err = m.processIdpConfig(iam_model.IDPProviderTypeSystem, event)
+ err = i.processIdpConfig(iam_model.IDPProviderTypeSystem, event)
}
return err
}
-func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, event *models.Event) (err error) {
+func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, event *models.Event) (err error) {
idp := new(iam_view_model.IDPConfigView)
switch event.Type {
case model.IDPConfigAdded,
@@ -56,7 +56,7 @@ func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil {
return err
}
- idp, err = m.view.IDPConfigByID(idp.IDPConfigID)
+ idp, err = i.view.IDPConfigByID(idp.IDPConfigID)
if err != nil {
return err
}
@@ -66,17 +66,21 @@ func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil {
return err
}
- return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence)
+ return i.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIDPConfigSequence(event.Sequence)
+ return i.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIDPConfig(idp, idp.Sequence)
+ return i.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
}
-func (m *IDPConfig) OnError(event *models.Event, err error) error {
+func (i *IDPConfig) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ejf8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
- return spooler.HandleError(event, err, m.view.GetLatestIDPConfigFailedEvent, m.view.ProcessedIDPConfigFailedEvent, m.view.ProcessedIDPConfigSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
+}
+
+func (i *IDPConfig) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateIDPConfigSpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/idp_providers.go b/internal/auth/repository/eventsourcing/handler/idp_providers.go
index b4c54a2834..b92a20a3b4 100644
--- a/internal/auth/repository/eventsourcing/handler/idp_providers.go
+++ b/internal/auth/repository/eventsourcing/handler/idp_providers.go
@@ -27,12 +27,12 @@ const (
idpProviderTable = "auth.idp_providers"
)
-func (m *IDPProvider) ViewModel() string {
+func (i *IDPProvider) ViewModel() string {
return idpProviderTable
}
-func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIDPProviderSequence()
+func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestIDPProviderSequence()
if err != nil {
return nil, err
}
@@ -41,15 +41,15 @@ func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *IDPProvider) Reduce(event *models.Event) (err error) {
+func (i *IDPProvider) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.IAMAggregate, org_es_model.OrgAggregate:
- err = m.processIdpProvider(event)
+ err = i.processIdpProvider(event)
}
return err
}
-func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
+func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
provider := new(iam_view_model.IDPProviderView)
switch event.Type {
case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded:
@@ -57,71 +57,75 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil {
return err
}
- err = m.fillData(provider)
+ err = i.fillData(provider)
case model.LoginPolicyIDPProviderRemoved, model.LoginPolicyIDPProviderCascadeRemoved,
org_es_model.LoginPolicyIDPProviderRemoved, org_es_model.LoginPolicyIDPProviderCascadeRemoved:
err = provider.SetData(event)
if err != nil {
return err
}
- return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence)
+ return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem
- if event.AggregateID != m.systemDefaults.IamID {
+ if event.AggregateID != i.systemDefaults.IamID {
providerType = iam_model.IDPProviderTypeOrg
}
esConfig.AppendEvent(providerType, event)
- providers, err := m.view.IDPProvidersByIDPConfigID(esConfig.IDPConfigID)
+ providers, err := i.view.IDPProvidersByIDPConfigID(esConfig.IDPConfigID)
if err != nil {
return err
}
config := new(iam_model.IDPConfig)
- if event.AggregateID == m.systemDefaults.IamID {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
+ if event.AggregateID == i.systemDefaults.IamID {
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
} else {
- config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
+ config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
}
if err != nil {
return err
}
for _, provider := range providers {
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
}
- return m.view.PutIDPProviders(event.Sequence, providers...)
+ return i.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
case org_es_model.LoginPolicyRemoved:
- return m.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence)
+ return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIDPProviderSequence(event.Sequence)
+ return i.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIDPProvider(provider, provider.Sequence)
+ return i.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
}
-func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
+func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
var config *iam_model.IDPConfig
if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, provider.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, provider.IDPConfigID)
} else {
- config, err = m.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
+ config, err = i.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
}
if err != nil {
return err
}
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
return nil
}
-func (m *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) {
+func (i *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) {
provider.Name = config.Name
provider.StylingType = int32(config.StylingType)
provider.IDPConfigType = int32(config.Type)
provider.IDPState = int32(config.State)
}
-func (m *IDPProvider) OnError(event *models.Event, err error) error {
+func (i *IDPProvider) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Fjd89", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
- return spooler.HandleError(event, err, m.view.GetLatestIDPProviderFailedEvent, m.view.ProcessedIDPProviderFailedEvent, m.view.ProcessedIDPProviderSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestIDPProviderFailedEvent, i.view.ProcessedIDPProviderFailedEvent, i.view.ProcessedIDPProviderSequence, i.errorCountUntilSkip)
+}
+
+func (i *IDPProvider) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/key.go b/internal/auth/repository/eventsourcing/handler/key.go
index e56e20d153..48f224cc29 100644
--- a/internal/auth/repository/eventsourcing/handler/key.go
+++ b/internal/auth/repository/eventsourcing/handler/key.go
@@ -41,11 +41,11 @@ func (k *Key) Reduce(event *models.Event) error {
return err
}
if privateKey.Expiry.Before(time.Now()) && publicKey.Expiry.Before(time.Now()) {
- return k.view.ProcessedKeySequence(event.Sequence)
+ return k.view.ProcessedKeySequence(event.Sequence, event.CreationDate)
}
- return k.view.PutKeys(privateKey, publicKey, event.Sequence)
+ return k.view.PutKeys(privateKey, publicKey, event.Sequence, event.CreationDate)
default:
- return k.view.ProcessedKeySequence(event.Sequence)
+ return k.view.ProcessedKeySequence(event.Sequence, event.CreationDate)
}
}
@@ -53,3 +53,9 @@ func (k *Key) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-GHa3a", "id", event.AggregateID).WithError(err).Warn("something went wrong in key handler")
return spooler.HandleError(event, err, k.view.GetLatestKeyFailedEvent, k.view.ProcessedKeyFailedEvent, k.view.ProcessedKeySequence, k.errorCountUntilSkip)
}
+
+func (k *Key) OnSuccess() error {
+ err := spooler.HandleSuccess(k.view.UpdateKeySpoolerRunTimestamp)
+ logging.LogWithFields("SPOOL-vM9sd", "table", keyTable).OnError(err).Warn("could not process on success func")
+ return err
+}
diff --git a/internal/auth/repository/eventsourcing/handler/login_policy.go b/internal/auth/repository/eventsourcing/handler/login_policy.go
index ca01a1ea76..b92dd17a9e 100644
--- a/internal/auth/repository/eventsourcing/handler/login_policy.go
+++ b/internal/auth/repository/eventsourcing/handler/login_policy.go
@@ -19,12 +19,12 @@ const (
loginPolicyTable = "auth.login_policies"
)
-func (m *LoginPolicy) ViewModel() string {
+func (p *LoginPolicy) ViewModel() string {
return loginPolicyTable
}
-func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestLoginPolicySequence()
+func (p *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestLoginPolicySequence()
if err != nil {
return nil, err
}
@@ -33,15 +33,15 @@ func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *LoginPolicy) Reduce(event *models.Event) (err error) {
+func (p *LoginPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processLoginPolicy(event)
+ err = p.processLoginPolicy(event)
}
return err
}
-func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
+func (p *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
policy := new(iam_model.LoginPolicyView)
switch event.Type {
case iam_es_model.LoginPolicyAdded, model.LoginPolicyAdded:
@@ -51,23 +51,27 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
iam_es_model.LoginPolicySecondFactorRemoved, model.LoginPolicySecondFactorRemoved,
iam_es_model.LoginPolicyMultiFactorAdded, model.LoginPolicyMultiFactorAdded,
iam_es_model.LoginPolicyMultiFactorRemoved, model.LoginPolicyMultiFactorRemoved:
- policy, err = m.view.LoginPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.LoginPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.LoginPolicyRemoved:
- return m.view.DeleteLoginPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeleteLoginPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedLoginPolicySequence(event.Sequence)
+ return p.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutLoginPolicy(policy, policy.Sequence)
+ return p.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *LoginPolicy) OnError(event *models.Event, err error) error {
+func (p *LoginPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-5id9s", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestLoginPolicyFailedEvent, m.view.ProcessedLoginPolicyFailedEvent, m.view.ProcessedLoginPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestLoginPolicyFailedEvent, p.view.ProcessedLoginPolicyFailedEvent, p.view.ProcessedLoginPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *LoginPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateLoginPolicySpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/machine_keys.go b/internal/auth/repository/eventsourcing/handler/machine_keys.go
index 84513ae0fa..f9af7e86fb 100644
--- a/internal/auth/repository/eventsourcing/handler/machine_keys.go
+++ b/internal/auth/repository/eventsourcing/handler/machine_keys.go
@@ -48,26 +48,30 @@ func (d *MachineKeys) processMachineKeys(event *models.Event) (err error) {
case model.MachineKeyAdded:
err = key.AppendEvent(event)
if key.ExpirationDate.Before(time.Now()) {
- return d.view.ProcessedMachineKeySequence(event.Sequence)
+ return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
}
case model.MachineKeyRemoved:
err = key.SetData(event)
if err != nil {
return err
}
- return d.view.DeleteMachineKey(key.ID, event.Sequence)
+ return d.view.DeleteMachineKey(key.ID, event.Sequence, event.CreationDate)
case model.UserRemoved:
- return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence)
+ return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return d.view.ProcessedMachineKeySequence(event.Sequence)
+ return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return d.view.PutMachineKey(key, key.Sequence)
+ return d.view.PutMachineKey(key, key.Sequence, event.CreationDate)
}
func (d *MachineKeys) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-S9fe", "id", event.AggregateID).WithError(err).Warn("something went wrong in machine key handler")
return spooler.HandleError(event, err, d.view.GetLatestMachineKeyFailedEvent, d.view.ProcessedMachineKeyFailedEvent, d.view.ProcessedMachineKeySequence, d.errorCountUntilSkip)
}
+
+func (d *MachineKeys) OnSuccess() error {
+ return spooler.HandleSuccess(d.view.UpdateMachineKeySpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/org.go b/internal/auth/repository/eventsourcing/handler/org.go
index 58bafb6ac0..909cfefc4a 100644
--- a/internal/auth/repository/eventsourcing/handler/org.go
+++ b/internal/auth/repository/eventsourcing/handler/org.go
@@ -58,16 +58,20 @@ func (o *Org) Reduce(event *es_models.Event) (err error) {
}
org.Domain = domain.Domain
default:
- return o.view.ProcessedOrgSequence(event.Sequence)
+ return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return o.view.PutOrg(org)
+ return o.view.PutOrg(org, event.CreationDate)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
logging.LogWithFields("SPOOL-8siWS", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in org handler")
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
}
+
+func (o *Org) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgSpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/org_iam_policy.go b/internal/auth/repository/eventsourcing/handler/org_iam_policy.go
index 55f72f74d7..ac28b5c7c4 100644
--- a/internal/auth/repository/eventsourcing/handler/org_iam_policy.go
+++ b/internal/auth/repository/eventsourcing/handler/org_iam_policy.go
@@ -19,12 +19,12 @@ const (
orgIAMPolicyTable = "auth.org_iam_policies"
)
-func (m *OrgIAMPolicy) ViewModel() string {
+func (p *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable
}
-func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestOrgIAMPolicySequence()
+func (p *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestOrgIAMPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processOrgIAMPolicy(event)
+ err = p.processOrgIAMPolicy(event)
}
return err
}
-func (m *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
+func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
policy := new(iam_model.OrgIAMPolicyView)
switch event.Type {
case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged:
- policy, err = m.view.OrgIAMPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.OrgIAMPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved:
- return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedOrgIAMPolicySequence(event.Sequence)
+ return p.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutOrgIAMPolicy(policy, policy.Sequence)
+ return p.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *OrgIAMPolicy) OnError(event *models.Event, err error) error {
+func (p *OrgIAMPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-3Gj8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *OrgIAMPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateOrgIAMPolicySpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go b/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go
index c280615988..d3656a164a 100644
--- a/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go
+++ b/internal/auth/repository/eventsourcing/handler/password_complexity_policy.go
@@ -19,12 +19,12 @@ const (
passwordComplexityPolicyTable = "auth.password_complexity_policies"
)
-func (m *PasswordComplexityPolicy) ViewModel() string {
+func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable
}
-func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordComplexityPolicySequence()
+func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processPasswordComplexityPolicy(event)
+ err = p.processPasswordComplexityPolicy(event)
}
return err
}
-func (m *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordComplexityPolicyView)
switch event.Type {
case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged:
- policy, err = m.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved:
- return m.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordComplexityPolicySequence(event.Sequence)
+ return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordComplexityPolicy(policy, policy.Sequence)
+ return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *PasswordComplexityPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdatePasswordComplexityPolicySpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/project_role.go b/internal/auth/repository/eventsourcing/handler/project_role.go
index e877c867a4..c469019b9f 100644
--- a/internal/auth/repository/eventsourcing/handler/project_role.go
+++ b/internal/auth/repository/eventsourcing/handler/project_role.go
@@ -52,19 +52,23 @@ func (p *ProjectRole) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence)
+ return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved:
return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectRoleSequence(event.Sequence)
+ return p.view.ProcessedProjectRoleSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return p.view.PutProjectRole(role)
+ return p.view.PutProjectRole(role, event.CreationDate)
}
func (p *ProjectRole) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
}
+
+func (p *ProjectRole) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProjectRoleSpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/token.go b/internal/auth/repository/eventsourcing/handler/token.go
index 8fb4c65739..2c056cc064 100644
--- a/internal/auth/repository/eventsourcing/handler/token.go
+++ b/internal/auth/repository/eventsourcing/handler/token.go
@@ -49,7 +49,7 @@ func (t *Token) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return t.view.PutToken(token)
+ return t.view.PutToken(token, event.CreationDate)
case user_es_model.UserProfileChanged,
user_es_model.HumanProfileChanged:
user := new(view_model.UserView)
@@ -61,25 +61,25 @@ func (t *Token) Reduce(event *models.Event) (err error) {
for _, token := range tokens {
token.PreferredLanguage = user.PreferredLanguage
}
- return t.view.PutTokens(tokens, event.Sequence)
+ return t.view.PutTokens(tokens, event.Sequence, event.CreationDate)
case user_es_model.SignedOut,
user_es_model.HumanSignedOut:
id, err := agentIDFromSession(event)
if err != nil {
return err
}
- return t.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence)
+ return t.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence, event.CreationDate)
case user_es_model.UserLocked,
user_es_model.UserDeactivated,
user_es_model.UserRemoved:
- return t.view.DeleteUserTokens(event.AggregateID, event.Sequence)
+ return t.view.DeleteUserTokens(event.AggregateID, event.Sequence, event.CreationDate)
case project_es_model.ApplicationDeactivated,
project_es_model.ApplicationRemoved:
application, err := applicationFromSession(event)
if err != nil {
return err
}
- return t.view.DeleteApplicationTokens(event.Sequence, application.AppID)
+ return t.view.DeleteApplicationTokens(event.Sequence, event.CreationDate, application.AppID)
case project_es_model.ProjectDeactivated,
project_es_model.ProjectRemoved:
project, err := t.ProjectEvents.ProjectByID(context.Background(), event.AggregateID)
@@ -90,9 +90,9 @@ func (t *Token) Reduce(event *models.Event) (err error) {
for _, app := range project.Applications {
applicationsIDs = append(applicationsIDs, app.AppID)
}
- return t.view.DeleteApplicationTokens(event.Sequence, applicationsIDs...)
+ return t.view.DeleteApplicationTokens(event.Sequence, event.CreationDate, applicationsIDs...)
default:
- return t.view.ProcessedTokenSequence(event.Sequence)
+ return t.view.ProcessedTokenSequence(event.Sequence, event.CreationDate)
}
}
@@ -118,3 +118,7 @@ func applicationFromSession(event *models.Event) (*project_es_model.Application,
}
return application, nil
}
+
+func (t *Token) OnSuccess() error {
+ return spooler.HandleSuccess(t.view.UpdateTokenSpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go
index c05c2f0f73..8b1ceb091c 100644
--- a/internal/auth/repository/eventsourcing/handler/user.go
+++ b/internal/auth/repository/eventsourcing/handler/user.go
@@ -67,7 +67,7 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
if err != nil {
return err
}
- u.fillLoginNames(user)
+ err = u.fillLoginNames(user)
case es_model.UserProfileChanged,
es_model.UserEmailChanged,
es_model.UserEmailVerified,
@@ -94,6 +94,12 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
es_model.HumanMFAOTPAdded,
es_model.HumanMFAOTPVerified,
es_model.HumanMFAOTPRemoved,
+ es_model.HumanMFAU2FTokenAdded,
+ es_model.HumanMFAU2FTokenVerified,
+ es_model.HumanMFAU2FTokenRemoved,
+ es_model.HumanPasswordlessTokenAdded,
+ es_model.HumanPasswordlessTokenVerified,
+ es_model.HumanPasswordlessTokenRemoved,
es_model.HumanMFAInitSkipped,
es_model.MachineChanged,
es_model.HumanPasswordChanged:
@@ -114,14 +120,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
}
err = u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteUser(event.AggregateID, event.Sequence)
+ return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserSequence(event.Sequence)
+ return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return u.view.PutUser(user, user.Sequence)
+ return u.view.PutUser(user, user.Sequence, event.CreationDate)
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
@@ -152,7 +158,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedUserSequence(event.Sequence)
+ return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
}
}
@@ -175,7 +181,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
}
- return u.view.PutUsers(users, event.Sequence)
+ return u.view.PutUsers(users, event.Sequence, event.CreationDate)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -200,10 +206,14 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
}
- return u.view.PutUsers(users, 0)
+ return u.view.PutUsers(users, 0, event.CreationDate)
}
func (u *User) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-is8aAWima", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip)
}
+
+func (u *User) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/user_external_idps.go b/internal/auth/repository/eventsourcing/handler/user_external_idps.go
index 5de4130bcf..826d79170c 100644
--- a/internal/auth/repository/eventsourcing/handler/user_external_idps.go
+++ b/internal/auth/repository/eventsourcing/handler/user_external_idps.go
@@ -29,12 +29,12 @@ const (
externalIDPTable = "auth.user_external_idps"
)
-func (m *ExternalIDP) ViewModel() string {
+func (i *ExternalIDP) ViewModel() string {
return externalIDPTable
}
-func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestExternalIDPSequence()
+func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence()
if err != nil {
return nil, err
}
@@ -43,17 +43,17 @@ func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *ExternalIDP) Reduce(event *models.Event) (err error) {
+func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.UserAggregate:
- err = m.processUser(event)
+ err = i.processUser(event)
case iam_es_model.IAMAggregate, org_es_model.OrgAggregate:
- err = m.processIdpConfig(event)
+ err = i.processIdpConfig(event)
}
return err
}
-func (m *ExternalIDP) processUser(event *models.Event) (err error) {
+func (i *ExternalIDP) processUser(event *models.Event) (err error) {
externalIDP := new(usr_view_model.ExternalIDPView)
switch event.Type {
case model.HumanExternalIDPAdded:
@@ -61,25 +61,25 @@ func (m *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil {
return err
}
- err = m.fillData(externalIDP)
+ err = i.fillData(externalIDP)
case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved:
err = externalIDP.SetData(event)
if err != nil {
return err
}
- return m.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence)
+ return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
case model.UserRemoved:
- return m.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence)
+ return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedExternalIDPSequence(event.Sequence)
+ return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutExternalIDP(externalIDP, externalIDP.Sequence)
+ return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
}
-func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
+func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
switch event.Type {
case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged:
configView := new(iam_view_model.IDPConfigView)
@@ -89,45 +89,49 @@ func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
} else {
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
}
- exterinalIDPs, err := m.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
+ exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
if err != nil {
return err
}
if event.AggregateType == iam_es_model.IAMAggregate {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} else {
- config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
+ config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
}
if err != nil {
return err
}
for _, provider := range exterinalIDPs {
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
}
- return m.view.PutExternalIDPs(event.Sequence, exterinalIDPs...)
+ return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
default:
- return m.view.ProcessedExternalIDPSequence(event.Sequence)
+ return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
}
return nil
}
-func (m *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
- config, err := m.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
+func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
+ config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
if caos_errs.IsNotFound(err) {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, externalIDP.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID)
}
if err != nil {
return err
}
- m.fillConfigData(externalIDP, config)
+ i.fillConfigData(externalIDP, config)
return nil
}
-func (m *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
+func (i *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
externalIDP.IDPName = config.Name
}
-func (m *ExternalIDP) OnError(event *models.Event, err error) error {
+func (i *ExternalIDP) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
- return spooler.HandleError(event, err, m.view.GetLatestExternalIDPFailedEvent, m.view.ProcessedExternalIDPFailedEvent, m.view.ProcessedExternalIDPSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestExternalIDPFailedEvent, i.view.ProcessedExternalIDPFailedEvent, i.view.ProcessedExternalIDPSequence, i.errorCountUntilSkip)
+}
+
+func (i *ExternalIDP) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/handler/user_grant.go b/internal/auth/repository/eventsourcing/handler/user_grant.go
index d9ded99e7f..c61f831162 100644
--- a/internal/auth/repository/eventsourcing/handler/user_grant.go
+++ b/internal/auth/repository/eventsourcing/handler/user_grant.go
@@ -97,14 +97,14 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
- return u.view.DeleteUserGrant(event.AggregateID, event.Sequence)
+ return u.view.DeleteUserGrant(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return u.view.PutUserGrant(grant, grant.Sequence)
+ return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
}
func (u *UserGrant) processUser(event *models.Event) (err error) {
@@ -119,7 +119,7 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
return err
}
if len(grants) == 0 {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
user, err := u.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -128,9 +128,9 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
for _, grant := range grants {
u.fillUserData(grant, user)
}
- return u.view.PutUserGrants(grants, event.Sequence)
+ return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -148,7 +148,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
for _, grant := range grants {
u.fillProjectData(grant, project)
}
- return u.view.PutUserGrants(grants, event.Sequence)
+ return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved:
member := new(proj_es_model.ProjectMember)
member.SetData(event)
@@ -158,7 +158,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -169,7 +169,7 @@ func (u *UserGrant) processOrg(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -207,16 +207,16 @@ func (u *UserGrant) processIAMMember(event *models.Event, rolePrefix string, suf
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, grant.Sequence)
+ return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
case iam_es_model.IAMMemberRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
return err
}
- return u.view.DeleteUserGrant(grant.ID, event.Sequence)
+ return u.view.DeleteUserGrant(grant.ID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -252,7 +252,7 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, event.Sequence)
+ return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
case org_es_model.OrgMemberRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved:
@@ -262,18 +262,18 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
return err
}
if errors.IsNotFound(err) {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys)
}
if grant.RoleKeys == nil {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil)
- return u.view.PutUserGrant(grant, event.Sequence)
+ return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -367,3 +367,7 @@ func (u *UserGrant) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-UZmc7", "id", event.AggregateID).WithError(err).Warn("something went wrong in user grant handler")
return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip)
}
+
+func (u *UserGrant) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/user_membership.go b/internal/auth/repository/eventsourcing/handler/user_membership.go
index 7a1145d224..7b231a78b5 100644
--- a/internal/auth/repository/eventsourcing/handler/user_membership.go
+++ b/internal/auth/repository/eventsourcing/handler/user_membership.go
@@ -74,14 +74,14 @@ func (m *UserMembership) processIam(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence)
+ return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
}
func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) {
@@ -105,16 +105,16 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence, event.CreationDate)
case org_es_model.OrgChanged:
return m.updateOrgName(event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence)
+ return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
}
func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) {
@@ -145,7 +145,7 @@ func (m *UserMembership) updateOrgName(event *models.Event) error {
membership.DisplayName = org.Name
}
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence)
+ return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
}
func (m *UserMembership) processProject(event *models.Event) (err error) {
@@ -168,7 +168,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence, event.CreationDate)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
if err != nil {
@@ -176,20 +176,20 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence, event.CreationDate)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)
case proj_es_model.ProjectRemoved:
- return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
+ return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
case proj_es_model.ProjectGrantRemoved:
- return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence)
+ return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence)
+ return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
}
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@@ -214,15 +214,15 @@ func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
for _, membership := range memberships {
membership.DisplayName = project.Name
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence)
+ return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
}
func (m *UserMembership) processUser(event *models.Event) (err error) {
switch event.Type {
case model.UserRemoved:
- return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence)
+ return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
}
@@ -230,3 +230,7 @@ func (m *UserMembership) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler")
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
}
+
+func (m *UserMembership) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp)
+}
diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go
index 305d5cd04d..174a0d8394 100644
--- a/internal/auth/repository/eventsourcing/handler/user_session.go
+++ b/internal/auth/repository/eventsourcing/handler/user_session.go
@@ -48,6 +48,10 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
es_model.HumanExternalLoginCheckSucceeded,
es_model.HumanMFAOTPCheckSucceeded,
es_model.HumanMFAOTPCheckFailed,
+ es_model.HumanMFAU2FTokenCheckSucceeded,
+ es_model.HumanMFAU2FTokenCheckFailed,
+ es_model.HumanPasswordlessTokenCheckSucceeded,
+ es_model.HumanPasswordlessTokenCheckFailed,
es_model.HumanSignedOut:
eventData, err := view_model.UserSessionFromEvent(event)
if err != nil {
@@ -78,13 +82,15 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
es_model.DomainClaimed,
es_model.UserUserNameChanged,
es_model.HumanExternalIDPRemoved,
- es_model.HumanExternalIDPCascadeRemoved:
+ es_model.HumanExternalIDPCascadeRemoved,
+ es_model.HumanPasswordlessTokenRemoved,
+ es_model.HumanMFAU2FTokenRemoved:
sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
if err != nil {
return err
}
if len(sessions) == 0 {
- return u.view.ProcessedUserSessionSequence(event.Sequence)
+ return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
}
for _, session := range sessions {
session.AppendEvent(event)
@@ -92,11 +98,11 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
return err
}
}
- return u.view.PutUserSessions(sessions, event.Sequence)
+ return u.view.PutUserSessions(sessions, event.Sequence, event.CreationDate)
case es_model.UserRemoved:
- return u.view.DeleteUserSessions(event.AggregateID, event.Sequence)
+ return u.view.DeleteUserSessions(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserSessionSequence(event.Sequence)
+ return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
}
}
@@ -105,12 +111,16 @@ func (u *UserSession) OnError(event *models.Event, err error) error {
return spooler.HandleError(event, err, u.view.GetLatestUserSessionFailedEvent, u.view.ProcessedUserSessionFailedEvent, u.view.ProcessedUserSessionSequence, u.errorCountUntilSkip)
}
+func (u *UserSession) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserSessionSpoolerRunTimestamp)
+}
+
func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error {
session.AppendEvent(event)
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
return err
}
- return u.view.PutUserSession(session)
+ return u.view.PutUserSession(session, event.CreationDate)
}
func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error {
diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go
index 89f2fa1569..5903edf52c 100644
--- a/internal/auth/repository/eventsourcing/repository.go
+++ b/internal/auth/repository/eventsourcing/repository.go
@@ -2,7 +2,6 @@ package eventsourcing
import (
"context"
-
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/eventstore"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/handler"
@@ -146,7 +145,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au
IdGenerator: idGenerator,
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
- MfaInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MfaInitSkip.Duration,
+ MFAInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MFAInitSkip.Duration,
SecondFactorCheckLifeTime: systemDefaults.VerificationLifetimes.SecondFactorCheck.Duration,
MultiFactorCheckLifeTime: systemDefaults.VerificationLifetimes.MultiFactorCheck.Duration,
IAMID: systemDefaults.IamID,
diff --git a/internal/auth/repository/eventsourcing/view/application.go b/internal/auth/repository/eventsourcing/view/application.go
index 06e59881eb..556d31d251 100644
--- a/internal/auth/repository/eventsourcing/view/application.go
+++ b/internal/auth/repository/eventsourcing/view/application.go
@@ -8,6 +8,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -26,28 +27,28 @@ func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest)
return view.SearchApplications(v.Db, applicationTable, request)
}
-func (v *View) PutApplication(app *model.ApplicationView) error {
+func (v *View) PutApplication(app *model.ApplicationView, eventTimestamp time.Time) error {
err := view.PutApplication(v.Db, applicationTable, app)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(app.Sequence)
+ return v.ProcessedApplicationSequence(app.Sequence, eventTimestamp)
}
-func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64) error {
+func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutApplications(v.Db, applicationTable, apps...)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(sequence)
+ return v.ProcessedApplicationSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
+func (v *View) DeleteApplication(appID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteApplication(v.Db, applicationTable, appID)
if err != nil {
return nil
}
- return v.ProcessedApplicationSequence(eventSequence)
+ return v.ProcessedApplicationSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
@@ -58,8 +59,12 @@ func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, erro
return v.latestSequence(applicationTable)
}
-func (v *View) ProcessedApplicationSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(applicationTable, eventSequence)
+func (v *View) ProcessedApplicationSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(applicationTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateApplicationSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(applicationTable)
}
func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/external_idps.go b/internal/auth/repository/eventsourcing/view/external_idps.go
index 6050dd73d8..1381611037 100644
--- a/internal/auth/repository/eventsourcing/view/external_idps.go
+++ b/internal/auth/repository/eventsourcing/view/external_idps.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -32,44 +33,48 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
}
-func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64) error {
+func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence)
+ return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
}
-func (v *View) PutExternalIDPs(sequence uint64, externalIDPs ...*model.ExternalIDPView) error {
+func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence)
+ return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64) error {
+func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence)
+ return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence)
+ return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(externalIDPTable)
}
-func (v *View) ProcessedExternalIDPSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(externalIDPTable, eventSequence)
+func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(externalIDPTable)
}
func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/idp_configs.go b/internal/auth/repository/eventsourcing/view/idp_configs.go
index 0a218f08d6..df591a7a00 100644
--- a/internal/auth/repository/eventsourcing/view/idp_configs.go
+++ b/internal/auth/repository/eventsourcing/view/idp_configs.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -24,28 +25,32 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*i
return view.SearchIDPs(v.Db, idpConfigTable, request)
}
-func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, sequence uint64) error {
+func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil {
return err
}
- return v.ProcessedIDPConfigSequence(sequence)
+ return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64) error {
+func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPConfigSequence(eventSequence)
+ return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpConfigTable)
}
-func (v *View) ProcessedIDPConfigSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(idpConfigTable, eventSequence)
+func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(idpConfigTable)
}
func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/idp_providers.go b/internal/auth/repository/eventsourcing/view/idp_providers.go
index d60ef835d0..cf81e63745 100644
--- a/internal/auth/repository/eventsourcing/view/idp_providers.go
+++ b/internal/auth/repository/eventsourcing/view/idp_providers.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -28,44 +29,48 @@ func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) (
return view.SearchIDPProviders(v.Db, idpProviderTable, request)
}
-func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64) error {
+func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence)
+ return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
}
-func (v *View) PutIDPProviders(sequence uint64, providers ...*model.IDPProviderView) error {
+func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil {
return err
}
- return v.ProcessedIDPProviderSequence(sequence)
+ return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64) error {
+func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence)
+ return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDPProvidersByAggregateID(v.Db, idpProviderTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPProviderSequence(eventSequence)
+ return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpProviderTable)
}
-func (v *View) ProcessedIDPProviderSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(idpProviderTable, eventSequence)
+func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(idpProviderTable)
}
func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/key.go b/internal/auth/repository/eventsourcing/view/key.go
index 9a21afc4d0..c0c0f7d357 100644
--- a/internal/auth/repository/eventsourcing/view/key.go
+++ b/internal/auth/repository/eventsourcing/view/key.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/key/repository/view"
"github.com/caos/zitadel/internal/key/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -31,36 +32,40 @@ func (v *View) GetActiveKeySet() ([]*key_model.PublicKey, error) {
return key_model.PublicKeysFromKeyView(model.KeyViewsToModel(keys), v.keyAlgorithm)
}
-func (v *View) PutKeys(privateKey, publicKey *model.KeyView, eventSequence uint64) error {
+func (v *View) PutKeys(privateKey, publicKey *model.KeyView, eventSequence uint64, eventTimestamp time.Time) error {
err := view.PutKeys(v.Db, keyTable, privateKey, publicKey)
if err != nil {
return err
}
- return v.ProcessedKeySequence(eventSequence)
+ return v.ProcessedKeySequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteKey(keyID string, private bool, eventSequence uint64) error {
+func (v *View) DeleteKey(keyID string, private bool, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteKey(v.Db, keyTable, keyID, private)
if err != nil {
return nil
}
- return v.ProcessedKeySequence(eventSequence)
+ return v.ProcessedKeySequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteKeyPair(keyID string, eventSequence uint64) error {
+func (v *View) DeleteKeyPair(keyID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteKeyPair(v.Db, keyTable, keyID)
if err != nil {
return nil
}
- return v.ProcessedKeySequence(eventSequence)
+ return v.ProcessedKeySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestKeySequence() (*repository.CurrentSequence, error) {
return v.latestSequence(keyTable)
}
-func (v *View) ProcessedKeySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(keyTable, eventSequence)
+func (v *View) ProcessedKeySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(keyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateKeySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(keyTable)
}
func (v *View) GetLatestKeyFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/login_policies.go b/internal/auth/repository/eventsourcing/view/login_policies.go
index 3a2133ddee..2da8862129 100644
--- a/internal/auth/repository/eventsourcing/view/login_policies.go
+++ b/internal/auth/repository/eventsourcing/view/login_policies.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
}
-func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64) error {
+func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLoginPolicySequence(sequence)
+ return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLoginPolicySequence(eventSequence)
+ return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(loginPolicyTable)
}
-func (v *View) ProcessedLoginPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(loginPolicyTable, eventSequence)
+func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(loginPolicyTable)
}
func (v *View) GetLatestLoginPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/machine_keys.go b/internal/auth/repository/eventsourcing/view/machine_keys.go
index 03e7c494aa..ac1a442566 100644
--- a/internal/auth/repository/eventsourcing/view/machine_keys.go
+++ b/internal/auth/repository/eventsourcing/view/machine_keys.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -27,39 +28,43 @@ func (v *View) SearchMachineKeys(request *usr_model.MachineKeySearchRequest) ([]
return view.SearchMachineKeys(v.Db, machineKeyTable, request)
}
-func (v *View) PutMachineKey(key *model.MachineKeyView, sequence uint64) error {
+func (v *View) PutMachineKey(key *model.MachineKeyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutMachineKey(v.Db, machineKeyTable, key)
if err != nil {
return err
}
if sequence != 0 {
- return v.ProcessedMachineKeySequence(sequence)
+ return v.ProcessedMachineKeySequence(sequence, eventTimestamp)
}
return nil
}
-func (v *View) DeleteMachineKey(keyID string, eventSequence uint64) error {
+func (v *View) DeleteMachineKey(keyID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, keyID)
if err != nil {
return nil
}
- return v.ProcessedMachineKeySequence(eventSequence)
+ return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteMachineKeysByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteMachineKeysByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, userID)
if err != nil {
return nil
}
- return v.ProcessedMachineKeySequence(eventSequence)
+ return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestMachineKeySequence() (*repository.CurrentSequence, error) {
return v.latestSequence(machineKeyTable)
}
-func (v *View) ProcessedMachineKeySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(machineKeyTable, eventSequence)
+func (v *View) ProcessedMachineKeySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(machineKeyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateMachineKeySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(machineKeyTable)
}
func (v *View) GetLatestMachineKeyFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/org.go b/internal/auth/repository/eventsourcing/view/org.go
index 6383f62398..9f489f5c30 100644
--- a/internal/auth/repository/eventsourcing/view/org.go
+++ b/internal/auth/repository/eventsourcing/view/org.go
@@ -5,6 +5,7 @@ import (
org_view "github.com/caos/zitadel/internal/org/repository/view"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -23,12 +24,12 @@ func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, ui
return org_view.SearchOrgs(v.Db, orgTable, req)
}
-func (v *View) PutOrg(org *org_model.OrgView) error {
+func (v *View) PutOrg(org *org_model.OrgView, eventTimestamp time.Time) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence)
+ return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -39,10 +40,14 @@ func (v *View) ProcessedOrgFailedEvent(failedEvent *repository.FailedEvent) erro
return v.saveFailedEvent(failedEvent)
}
+func (v *View) UpdateOrgSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgTable)
+}
+
func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgTable)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgTable, eventSequence)
+func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
}
diff --git a/internal/auth/repository/eventsourcing/view/org_iam_policy.go b/internal/auth/repository/eventsourcing/view/org_iam_policy.go
index 2d43efc80e..a9ee5a295f 100644
--- a/internal/auth/repository/eventsourcing/view/org_iam_policy.go
+++ b/internal/auth/repository/eventsourcing/view/org_iam_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
}
-func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64) error {
+func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedOrgIAMPolicySequence(sequence)
+ return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedOrgIAMPolicySequence(eventSequence)
+ return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(orgIAMPolicyTable)
}
-func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence)
+func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgIAMPolicyTable)
}
func (v *View) GetLatestOrgIAMPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/password_complexity_policy.go b/internal/auth/repository/eventsourcing/view/password_complexity_policy.go
index 93e28e1eb6..8259c89da0 100644
--- a/internal/auth/repository/eventsourcing/view/password_complexity_policy.go
+++ b/internal/auth/repository/eventsourcing/view/password_complexity_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
}
-func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64) error {
+func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(sequence)
+ return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(eventSequence)
+ return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordComplexityPolicyTable)
}
-func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence)
+func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordComplexityPolicyTable)
}
func (v *View) GetLatestPasswordComplexityPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/project_role.go b/internal/auth/repository/eventsourcing/view/project_role.go
index fdfe4d9dc1..66c287ffa1 100644
--- a/internal/auth/repository/eventsourcing/view/project_role.go
+++ b/internal/auth/repository/eventsourcing/view/project_role.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -31,20 +32,20 @@ func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest)
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
}
-func (v *View) PutProjectRole(project *model.ProjectRoleView) error {
+func (v *View) PutProjectRole(project *model.ProjectRoleView, eventTimestamp time.Time) error {
err := view.PutProjectRole(v.Db, projectRoleTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectRoleSequence(project.Sequence)
+ return v.ProcessedProjectRoleSequence(project.Sequence, eventTimestamp)
}
-func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64) error {
+func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteProjectRole(v.Db, projectRoleTable, projectID, orgID, key)
if err != nil {
return nil
}
- return v.ProcessedProjectRoleSequence(eventSequence)
+ return v.ProcessedProjectRoleSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteProjectRolesByProjectID(projectID string) error {
@@ -55,8 +56,12 @@ func (v *View) GetLatestProjectRoleSequence() (*repository.CurrentSequence, erro
return v.latestSequence(projectRoleTable)
}
-func (v *View) ProcessedProjectRoleSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(projectRoleTable, eventSequence)
+func (v *View) ProcessedProjectRoleSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(projectRoleTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProjectRoleSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(projectRoleTable)
}
func (v *View) GetLatestProjectRoleFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/sequence.go b/internal/auth/repository/eventsourcing/view/sequence.go
index d65b6e4da6..4ac2ab80cc 100644
--- a/internal/auth/repository/eventsourcing/view/sequence.go
+++ b/internal/auth/repository/eventsourcing/view/sequence.go
@@ -2,16 +2,29 @@ package view
import (
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
sequencesTable = "auth.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence)
+func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
}
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
return repository.LatestSequence(v.Db, sequencesTable, viewName)
}
+
+func (v *View) updateSpoolerRunSequence(viewName string) error {
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ if err != nil {
+ return err
+ }
+ if currentSequence.ViewName == "" {
+ currentSequence.ViewName = viewName
+ }
+ currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
+}
diff --git a/internal/auth/repository/eventsourcing/view/token.go b/internal/auth/repository/eventsourcing/view/token.go
index 94ecabd9b3..4cb7c41844 100644
--- a/internal/auth/repository/eventsourcing/view/token.go
+++ b/internal/auth/repository/eventsourcing/view/token.go
@@ -4,6 +4,7 @@ import (
usr_view "github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -18,60 +19,64 @@ func (v *View) TokensByUserID(userID string) ([]*model.TokenView, error) {
return usr_view.TokensByUserID(v.Db, tokenTable, userID)
}
-func (v *View) PutToken(token *model.TokenView) error {
+func (v *View) PutToken(token *model.TokenView, eventTimestamp time.Time) error {
err := usr_view.PutToken(v.Db, tokenTable, token)
if err != nil {
return err
}
- return v.ProcessedTokenSequence(token.Sequence)
+ return v.ProcessedTokenSequence(token.Sequence, eventTimestamp)
}
-func (v *View) PutTokens(token []*model.TokenView, sequence uint64) error {
+func (v *View) PutTokens(token []*model.TokenView, sequence uint64, eventTimestamp time.Time) error {
err := usr_view.PutTokens(v.Db, tokenTable, token...)
if err != nil {
return err
}
- return v.ProcessedTokenSequence(sequence)
+ return v.ProcessedTokenSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteToken(tokenID string, eventSequence uint64) error {
+func (v *View) DeleteToken(tokenID string, eventSequence uint64, eventTimestamp time.Time) error {
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID)
if err != nil {
return nil
}
- return v.ProcessedTokenSequence(eventSequence)
+ return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64) error {
+func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
if err != nil {
return nil
}
- return v.ProcessedTokenSequence(eventSequence)
+ return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserTokens(userID string, eventSequence uint64) error {
+func (v *View) DeleteUserTokens(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := usr_view.DeleteUserTokens(v.Db, tokenTable, userID)
if err != nil {
return nil
}
- return v.ProcessedTokenSequence(eventSequence)
+ return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteApplicationTokens(eventSequence uint64, ids ...string) error {
+func (v *View) DeleteApplicationTokens(eventSequence uint64, eventTimestamp time.Time, ids ...string) error {
err := usr_view.DeleteApplicationTokens(v.Db, tokenTable, ids)
if err != nil {
return nil
}
- return v.ProcessedTokenSequence(eventSequence)
+ return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestTokenSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(tokenTable)
}
-func (v *View) ProcessedTokenSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(tokenTable, eventSequence)
+func (v *View) ProcessedTokenSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(tokenTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateTokenSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(tokenTable)
}
func (v *View) GetLatestTokenFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/user.go b/internal/auth/repository/eventsourcing/view/user.go
index 5472eb628d..e8b0591d22 100644
--- a/internal/auth/repository/eventsourcing/view/user.go
+++ b/internal/auth/repository/eventsourcing/view/user.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -47,40 +48,44 @@ func (v *View) IsUserUnique(userName, email string) (bool, error) {
return view.IsUserUnique(v.Db, userTable, userName, email)
}
-func (v *View) UserMfas(userID string) ([]*usr_model.MultiFactor, error) {
- return view.UserMfas(v.Db, userTable, userID)
+func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
+ return view.UserMFAs(v.Db, userTable, userID)
}
-func (v *View) PutUser(user *model.UserView, sequence uint64) error {
+func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
-func (v *View) PutUsers(users []*model.UserView, sequence uint64) error {
+func (v *View) PutUsers(users []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUsers(v.Db, userTable, users...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUser(userID string, eventSequence uint64) error {
+func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUser(v.Db, userTable, userID)
if err != nil {
return nil
}
- return v.ProcessedUserSequence(eventSequence)
+ return v.ProcessedUserSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userTable)
}
-func (v *View) ProcessedUserSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userTable, eventSequence)
+func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userTable)
}
func (v *View) GetLatestUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/user_grant.go b/internal/auth/repository/eventsourcing/view/user_grant.go
index cc53b97504..230e9f5c8a 100644
--- a/internal/auth/repository/eventsourcing/view/user_grant.go
+++ b/internal/auth/repository/eventsourcing/view/user_grant.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -35,36 +36,40 @@ func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]
return view.SearchUserGrants(v.Db, userGrantTable, request)
}
-func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error {
+func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence)
+ return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
}
-func (v *View) PutUserGrants(grants []*model.UserGrantView, sequence uint64) error {
+func (v *View) PutUserGrants(grants []*model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserGrants(v.Db, userGrantTable, grants...)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence)
+ return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error {
+func (v *View) DeleteUserGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
if err != nil {
return nil
}
- return v.ProcessedUserGrantSequence(eventSequence)
+ return v.ProcessedUserGrantSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userGrantTable)
}
-func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userGrantTable, eventSequence)
+func (v *View) ProcessedUserGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userGrantTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userGrantTable)
}
func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/user_membership.go b/internal/auth/repository/eventsourcing/view/user_membership.go
index cbd241e350..84607584ab 100644
--- a/internal/auth/repository/eventsourcing/view/user_membership.go
+++ b/internal/auth/repository/eventsourcing/view/user_membership.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -27,60 +28,64 @@ func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequ
return view.SearchUserMemberships(v.Db, userMembershipTable, request)
}
-func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64) error {
+func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserMembership(v.Db, userMembershipTable, membership)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence)
+ return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
}
-func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
+func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence)
+ return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64) error {
+func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserMembershipsByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteUserMembershipsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, eventSequence uint64) error {
+func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userMembershipTable)
}
-func (v *View) ProcessedUserMembershipSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userMembershipTable, eventSequence)
+func (v *View) ProcessedUserMembershipSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userMembershipTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserMembershipSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userMembershipTable)
}
func (v *View) GetLatestUserMembershipFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/eventsourcing/view/user_session.go b/internal/auth/repository/eventsourcing/view/user_session.go
index fe9d6b0ec2..805cc04aef 100644
--- a/internal/auth/repository/eventsourcing/view/user_session.go
+++ b/internal/auth/repository/eventsourcing/view/user_session.go
@@ -4,6 +4,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -22,36 +23,44 @@ func (v *View) UserSessionsByAgentID(agentID string) ([]*model.UserSessionView,
return view.UserSessionsByAgentID(v.Db, userSessionTable, agentID)
}
-func (v *View) PutUserSession(userSession *model.UserSessionView) error {
+func (v *View) ActiveUserSessions() ([]*model.UserSessionView, error) {
+ return view.ActiveUserSessions(v.Db, userSessionTable)
+}
+
+func (v *View) PutUserSession(userSession *model.UserSessionView, eventTimestamp time.Time) error {
err := view.PutUserSession(v.Db, userSessionTable, userSession)
if err != nil {
return err
}
- return v.ProcessedUserSessionSequence(userSession.Sequence)
+ return v.ProcessedUserSessionSequence(userSession.Sequence, eventTimestamp)
}
-func (v *View) PutUserSessions(userSession []*model.UserSessionView, sequence uint64) error {
+func (v *View) PutUserSessions(userSession []*model.UserSessionView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserSessions(v.Db, userSessionTable, userSession...)
if err != nil {
return err
}
- return v.ProcessedUserSessionSequence(sequence)
+ return v.ProcessedUserSessionSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUserSessions(userID string, eventSequence uint64) error {
+func (v *View) DeleteUserSessions(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserSessions(v.Db, userSessionTable, userID)
if err != nil {
return nil
}
- return v.ProcessedUserSessionSequence(eventSequence)
+ return v.ProcessedUserSessionSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserSessionSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userSessionTable)
}
-func (v *View) ProcessedUserSessionSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userSessionTable, eventSequence)
+func (v *View) ProcessedUserSessionSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userSessionTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserSessionSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userSessionTable)
}
func (v *View) GetLatestUserSessionFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/auth/repository/user.go b/internal/auth/repository/user.go
index 164ca23c35..81f6084e4c 100644
--- a/internal/auth/repository/user.go
+++ b/internal/auth/repository/user.go
@@ -13,7 +13,7 @@ type UserRepository interface {
RegisterExternalUser(ctx context.Context, user *model.User, externalIDP *model.ExternalIDP, member *org_model.OrgMember, resourceOwner string) (*model.User, error)
myUserRepo
- SkipMfaInit(ctx context.Context, userID string) error
+ SkipMFAInit(ctx context.Context, userID string) error
RequestPasswordReset(ctx context.Context, username string) error
SetPassword(ctx context.Context, userID, code, password string) error
@@ -25,8 +25,16 @@ type UserRepository interface {
VerifyInitCode(ctx context.Context, userID, code, password string) error
ResendInitVerificationMail(ctx context.Context, userID string) error
- AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error)
- VerifyMfaOTPSetup(ctx context.Context, userID, code string) error
+ AddMFAOTP(ctx context.Context, userID string) (*model.OTP, error)
+ VerifyMFAOTPSetup(ctx context.Context, userID, code string) error
+
+ AddMFAU2F(ctx context.Context, id string) (*model.WebAuthNToken, error)
+ VerifyMFAU2FSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error
+ RemoveMFAU2F(ctx context.Context, userID, webAuthNTokenID string) error
+
+ AddPasswordless(ctx context.Context, id string) (*model.WebAuthNToken, error)
+ VerifyPasswordlessSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error
+ RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error
ChangeUsername(ctx context.Context, userID, username string) error
@@ -63,10 +71,18 @@ type myUserRepo interface {
AddMyExternalIDP(ctx context.Context, externalIDP *model.ExternalIDP) (*model.ExternalIDP, error)
RemoveMyExternalIDP(ctx context.Context, externalIDP *model.ExternalIDP) error
- MyUserMfas(ctx context.Context) ([]*model.MultiFactor, error)
- AddMyMfaOTP(ctx context.Context) (*model.OTP, error)
- VerifyMyMfaOTPSetup(ctx context.Context, code string) error
- RemoveMyMfaOTP(ctx context.Context) error
+ MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, error)
+ AddMyMFAOTP(ctx context.Context) (*model.OTP, error)
+ VerifyMyMFAOTPSetup(ctx context.Context, code string) error
+ RemoveMyMFAOTP(ctx context.Context) error
+
+ AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error)
+ VerifyMyMFAU2FSetup(ctx context.Context, tokenName string, data []byte) error
+ RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string) error
+
+ AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error)
+ VerifyMyPasswordlessSetup(ctx context.Context, tokenName string, data []byte) error
+ RemoveMyPasswordless(ctx context.Context, webAuthNTokenID string) error
ChangeMyUsername(ctx context.Context, username string) error
diff --git a/internal/auth/repository/user_session.go b/internal/auth/repository/user_session.go
index 98e8751d07..f6eca64de2 100644
--- a/internal/auth/repository/user_session.go
+++ b/internal/auth/repository/user_session.go
@@ -7,4 +7,5 @@ import (
type UserSessionRepository interface {
GetMyUserSessions(ctx context.Context) ([]*model.UserSessionView, error)
+ ActiveUserSessionCount() int64
}
diff --git a/internal/auth_request/model/auth_request.go b/internal/auth_request/model/auth_request.go
index adf36e27bc..bd51897afd 100644
--- a/internal/auth_request/model/auth_request.go
+++ b/internal/auth_request/model/auth_request.go
@@ -34,7 +34,7 @@ type AuthRequest struct {
LinkingUsers []*ExternalUser
PossibleSteps []NextStep
PasswordVerified bool
- MfasVerified []MFAType
+ MFAsVerified []MFAType
Audience []string
AuthTime time.Time
Code string
@@ -109,7 +109,7 @@ func (a *AuthRequest) IsValid() bool {
a.Request != nil && a.Request.IsValid()
}
-func (a *AuthRequest) MfaLevel() MFALevel {
+func (a *AuthRequest) MFALevel() MFALevel {
return -1
//PLANNED: check a.PossibleLOAs (and Prompt Login?)
}
diff --git a/internal/auth_request/model/auth_request_test.go b/internal/auth_request/model/auth_request_test.go
index 03319938e4..2e16f9b9a6 100644
--- a/internal/auth_request/model/auth_request_test.go
+++ b/internal/auth_request/model/auth_request_test.go
@@ -147,7 +147,7 @@ func TestAuthRequest_IsValid(t *testing.T) {
}
}
-func TestAuthRequest_MfaLevel(t *testing.T) {
+func TestAuthRequest_MFALevel(t *testing.T) {
type fields struct {
Prompt Prompt
PossibleLOAs []LevelOfAssurance
@@ -169,7 +169,7 @@ func TestAuthRequest_MfaLevel(t *testing.T) {
Prompt: tt.fields.Prompt,
PossibleLOAs: tt.fields.PossibleLOAs,
}
- if got := a.MfaLevel(); got != tt.want {
+ if got := a.MFALevel(); got != tt.want {
t.Errorf("MFALevel() = %v, want %v", got, tt.want)
}
})
diff --git a/internal/auth_request/model/next_step.go b/internal/auth_request/model/next_step.go
index 028e367127..3312244e11 100644
--- a/internal/auth_request/model/next_step.go
+++ b/internal/auth_request/model/next_step.go
@@ -15,14 +15,15 @@ const (
NextStepChangePassword
NextStepInitPassword
NextStepVerifyEmail
- NextStepMfaPrompt
- NextStepMfaVerify
+ NextStepMFAPrompt
+ NextStepMFAVerify
NextStepRedirectToCallback
NextStepChangeUsername
NextStepLinkUsers
NextStepExternalNotFoundOption
NextStepExternalLogin
NextStepGrantRequired
+ NextStepPasswordless
)
type UserSessionState int32
@@ -81,6 +82,12 @@ func (s *ExternalLoginStep) Type() NextStepType {
return NextStepExternalLogin
}
+type PasswordlessStep struct{}
+
+func (s *PasswordlessStep) Type() NextStepType {
+ return NextStepPasswordless
+}
+
type ChangePasswordStep struct{}
func (s *ChangePasswordStep) Type() NextStepType {
@@ -105,21 +112,21 @@ func (s *VerifyEMailStep) Type() NextStepType {
return NextStepVerifyEmail
}
-type MfaPromptStep struct {
+type MFAPromptStep struct {
Required bool
- MfaProviders []MFAType
+ MFAProviders []MFAType
}
-func (s *MfaPromptStep) Type() NextStepType {
- return NextStepMfaPrompt
+func (s *MFAPromptStep) Type() NextStepType {
+ return NextStepMFAPrompt
}
-type MfaVerificationStep struct {
- MfaProviders []MFAType
+type MFAVerificationStep struct {
+ MFAProviders []MFAType
}
-func (s *MfaVerificationStep) Type() NextStepType {
- return NextStepMfaVerify
+func (s *MFAVerificationStep) Type() NextStepType {
+ return NextStepMFAVerify
}
type LinkUsersStep struct{}
@@ -145,6 +152,7 @@ type MFAType int
const (
MFATypeOTP MFAType = iota
MFATypeU2F
+ MFATypeU2FUserVerification
)
type MFALevel int
diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go
index 04b6966a97..a6a0160edf 100644
--- a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go
+++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go
@@ -15,7 +15,7 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors"
iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type TokenVerifierRepo struct {
diff --git a/internal/authz/repository/eventsourcing/handler/application.go b/internal/authz/repository/eventsourcing/handler/application.go
index 401f761ad0..4b5773607e 100644
--- a/internal/authz/repository/eventsourcing/handler/application.go
+++ b/internal/authz/repository/eventsourcing/handler/application.go
@@ -54,17 +54,21 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return a.view.DeleteApplication(app.ID, event.Sequence)
+ return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
default:
- return a.view.ProcessedApplicationSequence(event.Sequence)
+ return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return a.view.PutApplication(app)
+ return a.view.PutApplication(app, event.CreationDate)
}
func (a *Application) OnError(event *models.Event, spoolerError error) error {
logging.LogWithFields("SPOOL-sjZw", "id", event.AggregateID).WithError(spoolerError).Warn("something went wrong in project app handler")
return spooler.HandleError(event, spoolerError, a.view.GetLatestApplicationFailedEvent, a.view.ProcessedApplicationFailedEvent, a.view.ProcessedApplicationSequence, a.errorCountUntilSkip)
}
+
+func (a *Application) OnSuccess() error {
+ return spooler.HandleSuccess(a.view.UpdateApplicationSpoolerRunTimestamp)
+}
diff --git a/internal/authz/repository/eventsourcing/handler/org.go b/internal/authz/repository/eventsourcing/handler/org.go
index 79bc52b7b6..e487831f02 100644
--- a/internal/authz/repository/eventsourcing/handler/org.go
+++ b/internal/authz/repository/eventsourcing/handler/org.go
@@ -53,13 +53,17 @@ func (o *Org) Reduce(event *es_models.Event) error {
return err
}
default:
- return o.view.ProcessedOrgSequence(event.Sequence)
+ return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
}
- return o.view.PutOrg(org)
+ return o.view.PutOrg(org, event.CreationDate)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
logging.LogWithFields("SPOOL-8siWS", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in org handler")
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
}
+
+func (o *Org) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgSpoolerRunTimestamp)
+}
diff --git a/internal/authz/repository/eventsourcing/handler/user_grant.go b/internal/authz/repository/eventsourcing/handler/user_grant.go
index 897186b8e8..58cd01d31c 100644
--- a/internal/authz/repository/eventsourcing/handler/user_grant.go
+++ b/internal/authz/repository/eventsourcing/handler/user_grant.go
@@ -75,7 +75,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -86,7 +86,7 @@ func (u *UserGrant) processOrg(event *models.Event) (err error) {
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -124,16 +124,16 @@ func (u *UserGrant) processIAMMember(event *models.Event, rolePrefix string, suf
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, grant.Sequence)
+ return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
case iam_es_model.IAMMemberRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
return err
}
- return u.view.DeleteUserGrant(grant.ID, event.Sequence)
+ return u.view.DeleteUserGrant(grant.ID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -169,7 +169,7 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
- return u.view.PutUserGrant(grant, event.Sequence)
+ return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
case org_es_model.OrgMemberRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved:
@@ -179,18 +179,18 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
return err
}
if errors.IsNotFound(err) {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys)
}
if grant.RoleKeys == nil {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil)
- return u.view.PutUserGrant(grant, event.Sequence)
+ return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
}
@@ -235,3 +235,7 @@ func (u *UserGrant) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-VcVoJ", "id", event.AggregateID).WithError(err).Warn("something went wrong in user grant handler")
return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip)
}
+
+func (u *UserGrant) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp)
+}
diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go
index bb82b4d62f..a8e772b58d 100644
--- a/internal/authz/repository/eventsourcing/view/application.go
+++ b/internal/authz/repository/eventsourcing/view/application.go
@@ -2,11 +2,12 @@ package view
import (
"context"
+ "time"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/view/repository"
)
@@ -33,28 +34,32 @@ func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest)
return view.SearchApplications(v.Db, applicationTable, request)
}
-func (v *View) PutApplication(project *model.ApplicationView) error {
+func (v *View) PutApplication(project *model.ApplicationView, eventTimestamp time.Time) error {
err := view.PutApplication(v.Db, applicationTable, project)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(project.Sequence)
+ return v.ProcessedApplicationSequence(project.Sequence, eventTimestamp)
}
-func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
+func (v *View) DeleteApplication(appID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteApplication(v.Db, applicationTable, appID)
if err != nil {
return nil
}
- return v.ProcessedApplicationSequence(eventSequence)
+ return v.ProcessedApplicationSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(applicationTable)
}
-func (v *View) ProcessedApplicationSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(applicationTable, eventSequence)
+func (v *View) ProcessedApplicationSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(applicationTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateApplicationSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(applicationTable)
}
func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/authz/repository/eventsourcing/view/org.go b/internal/authz/repository/eventsourcing/view/org.go
index fe9d6d51c2..f886123b2e 100644
--- a/internal/authz/repository/eventsourcing/view/org.go
+++ b/internal/authz/repository/eventsourcing/view/org.go
@@ -5,6 +5,7 @@ import (
org_view "github.com/caos/zitadel/internal/org/repository/view"
org_model "github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -19,12 +20,12 @@ func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_model.OrgView, ui
return org_view.SearchOrgs(v.Db, orgTable, req)
}
-func (v *View) PutOrg(org *org_model.OrgView) error {
+func (v *View) PutOrg(org *org_model.OrgView, eventTimestamp time.Time) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence)
+ return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -39,6 +40,10 @@ func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgTable)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgTable, eventSequence)
+func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateOrgSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgTable)
}
diff --git a/internal/authz/repository/eventsourcing/view/sequence.go b/internal/authz/repository/eventsourcing/view/sequence.go
index 815bcfebf8..ad628fbf7b 100644
--- a/internal/authz/repository/eventsourcing/view/sequence.go
+++ b/internal/authz/repository/eventsourcing/view/sequence.go
@@ -2,16 +2,29 @@ package view
import (
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
sequencesTable = "authz.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence)
+func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
}
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
return repository.LatestSequence(v.Db, sequencesTable, viewName)
}
+
+func (v *View) updateSpoolerRunSequence(viewName string) error {
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ if err != nil {
+ return err
+ }
+ if currentSequence.ViewName == "" {
+ currentSequence.ViewName = viewName
+ }
+ currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
+}
diff --git a/internal/authz/repository/eventsourcing/view/token.go b/internal/authz/repository/eventsourcing/view/token.go
index 7c5a7163f6..bab80f238a 100644
--- a/internal/authz/repository/eventsourcing/view/token.go
+++ b/internal/authz/repository/eventsourcing/view/token.go
@@ -4,6 +4,7 @@ import (
usr_view "github.com/caos/zitadel/internal/user/repository/view"
usr_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -14,36 +15,40 @@ func (v *View) TokenByID(tokenID string) (*usr_view_model.TokenView, error) {
return usr_view.TokenByID(v.Db, tokenTable, tokenID)
}
-func (v *View) PutToken(token *usr_view_model.TokenView) error {
+func (v *View) PutToken(token *usr_view_model.TokenView, eventTimestamp time.Time) error {
err := usr_view.PutToken(v.Db, tokenTable, token)
if err != nil {
return err
}
- return v.ProcessedTokenSequence(token.Sequence)
+ return v.ProcessedTokenSequence(token.Sequence, eventTimestamp)
}
-func (v *View) DeleteToken(tokenID string, eventSequence uint64) error {
+func (v *View) DeleteToken(tokenID string, eventSequence uint64, eventTimestamp time.Time) error {
err := usr_view.DeleteToken(v.Db, tokenTable, tokenID)
if err != nil {
return nil
}
- return v.ProcessedTokenSequence(eventSequence)
+ return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64) error {
+func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := usr_view.DeleteSessionTokens(v.Db, tokenTable, agentID, userID)
if err != nil {
return nil
}
- return v.ProcessedTokenSequence(eventSequence)
+ return v.ProcessedTokenSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestTokenSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(tokenTable)
}
-func (v *View) ProcessedTokenSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(tokenTable, eventSequence)
+func (v *View) ProcessedTokenSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(tokenTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateTokenSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(tokenTable)
}
func (v *View) GetLatestTokenFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/authz/repository/eventsourcing/view/user_grant.go b/internal/authz/repository/eventsourcing/view/user_grant.go
index cc44af9a75..68154dc3c9 100644
--- a/internal/authz/repository/eventsourcing/view/user_grant.go
+++ b/internal/authz/repository/eventsourcing/view/user_grant.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -31,28 +32,32 @@ func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]
return view.SearchUserGrants(v.Db, userGrantTable, request)
}
-func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error {
+func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence)
+ return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error {
+func (v *View) DeleteUserGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
if err != nil {
return nil
}
- return v.ProcessedUserGrantSequence(eventSequence)
+ return v.ProcessedUserGrantSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userGrantTable)
}
-func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userGrantTable, eventSequence)
+func (v *View) ProcessedUserGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userGrantTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userGrantTable)
}
func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/config/systemdefaults/system_defaults.go b/internal/config/systemdefaults/system_defaults.go
index 0a5b46c781..c6b582b30d 100644
--- a/internal/config/systemdefaults/system_defaults.go
+++ b/internal/config/systemdefaults/system_defaults.go
@@ -23,6 +23,7 @@ type SystemDefaults struct {
DomainVerification DomainVerification
IamID string
Notifications Notifications
+ WebAuthN WebAuthN
}
type ZitadelDocs struct {
@@ -52,7 +53,7 @@ type OTPConfig struct {
type VerificationLifetimes struct {
PasswordCheck types.Duration
ExternalLoginCheck types.Duration
- MfaInitSkip types.Duration
+ MFAInitSkip types.Duration
SecondFactorCheck types.Duration
MultiFactorCheck types.Duration
}
@@ -89,3 +90,9 @@ type TemplateData struct {
VerifyPhone templates.TemplateData
DomainClaimed templates.TemplateData
}
+
+type WebAuthN struct {
+ ID string
+ Origin string
+ DisplayName string
+}
diff --git a/internal/eventstore/internal/repository/sql/filter.go b/internal/eventstore/internal/repository/sql/filter.go
index 0b393f885f..e9a98939da 100644
--- a/internal/eventstore/internal/repository/sql/filter.go
+++ b/internal/eventstore/internal/repository/sql/filter.go
@@ -8,7 +8,7 @@ import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type Querier interface {
diff --git a/internal/eventstore/internal/repository/sql/push.go b/internal/eventstore/internal/repository/sql/push.go
index b6af36cce0..3a3802ebf2 100644
--- a/internal/eventstore/internal/repository/sql/push.go
+++ b/internal/eventstore/internal/repository/sql/push.go
@@ -8,7 +8,7 @@ import (
"github.com/caos/logging"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/cockroachdb/cockroach-go/v2/crdb"
)
diff --git a/internal/eventstore/query/handler.go b/internal/eventstore/query/handler.go
index 8effb168c0..36bba2547e 100755
--- a/internal/eventstore/query/handler.go
+++ b/internal/eventstore/query/handler.go
@@ -11,6 +11,7 @@ type Handler interface {
EventQuery() (*models.SearchQuery, error)
Reduce(*models.Event) error
OnError(event *models.Event, err error) error
+ OnSuccess() error
MinimumCycleDuration() time.Duration
QueryLimit() uint64
}
diff --git a/internal/eventstore/spooler/config.go b/internal/eventstore/spooler/config.go
index fbad7d0496..fa796f06c3 100644
--- a/internal/eventstore/spooler/config.go
+++ b/internal/eventstore/spooler/config.go
@@ -28,7 +28,7 @@ func (c *Config) New() *Spooler {
lockID: lockID,
eventstore: c.Eventstore,
locker: c.Locker,
- queue: make(chan *spooledHandler),
+ queue: make(chan *spooledHandler, len(c.ViewHandlers)),
workers: c.ConcurrentWorkers,
}
}
diff --git a/internal/eventstore/spooler/spooler.go b/internal/eventstore/spooler/spooler.go
index d95f45ad4a..fb480f7916 100644
--- a/internal/eventstore/spooler/spooler.go
+++ b/internal/eventstore/spooler/spooler.go
@@ -9,7 +9,7 @@ import (
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/query"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/view/repository"
"time"
@@ -52,8 +52,7 @@ func (s *Spooler) Start() {
}
go func() {
for _, handler := range s.handlers {
- handler := &spooledHandler{Handler: handler, locker: s.locker, queuedAt: time.Now(), eventstore: s.eventstore}
- s.queue <- handler
+ s.queue <- &spooledHandler{Handler: handler, locker: s.locker, queuedAt: time.Now(), eventstore: s.eventstore}
}
}()
}
@@ -79,6 +78,7 @@ func (s *spooledHandler) load(workerID string) {
errs <- s.process(ctx, events, workerID)
logging.Log("SPOOL-0pV8o").WithField("view", s.ViewModel()).WithField("worker", workerID).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("process done")
}
+
}
<-ctx.Done()
}
@@ -103,7 +103,9 @@ func (s *spooledHandler) process(ctx context.Context, events []*models.Event, wo
}
}
}
- return nil
+ err := s.OnSuccess()
+ logging.LogWithFields("SPOOL-49ods", "view", s.ViewModel(), "worker", workerID, "traceID", tracing.TraceIDFromCtx(ctx)).OnError(err).Warn("could not process on success func")
+ return err
}
func (s *spooledHandler) query(ctx context.Context) ([]*models.Event, error) {
@@ -165,7 +167,7 @@ func (s *spooledHandler) lock(ctx context.Context, errs chan<- error, workerID s
func HandleError(event *models.Event, failedErr error,
latestFailedEvent func(sequence uint64) (*repository.FailedEvent, error),
processFailedEvent func(*repository.FailedEvent) error,
- processSequence func(uint64) error, errorCountUntilSkip uint64) error {
+ processSequence func(uint64, time.Time) error, errorCountUntilSkip uint64) error {
failedEvent, err := latestFailedEvent(event.Sequence)
if err != nil {
return err
@@ -177,7 +179,11 @@ func HandleError(event *models.Event, failedErr error,
return err
}
if errorCountUntilSkip <= failedEvent.FailureCount {
- return processSequence(event.Sequence)
+ return processSequence(event.Sequence, event.CreationDate)
}
return nil
}
+
+func HandleSuccess(updateSpoolerRunTimestamp func() error) error {
+ return updateSpoolerRunTimestamp()
+}
diff --git a/internal/eventstore/spooler/spooler_test.go b/internal/eventstore/spooler/spooler_test.go
index 7a852ed871..721ad74e26 100644
--- a/internal/eventstore/spooler/spooler_test.go
+++ b/internal/eventstore/spooler/spooler_test.go
@@ -40,6 +40,9 @@ func (h *testHandler) Reduce(*models.Event) error {
func (h *testHandler) OnError(event *models.Event, err error) error {
return err
}
+func (h *testHandler) OnSuccess() error {
+ return nil
+}
func (h *testHandler) MinimumCycleDuration() time.Duration {
return h.cycleDuration
}
@@ -429,7 +432,7 @@ func TestHandleError(t *testing.T) {
func(*repository.FailedEvent) error {
return nil
},
- func(uint64) error {
+ func(uint64, time.Time) error {
processedSequence = true
return nil
},
diff --git a/internal/iam/model/iam.go b/internal/iam/model/iam.go
index 09610a5c89..f80ea3b400 100644
--- a/internal/iam/model/iam.go
+++ b/internal/iam/model/iam.go
@@ -14,6 +14,7 @@ const (
Step5
Step6
Step7
+ Step8
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
StepCount
)
diff --git a/internal/iam/model/login_policy.go b/internal/iam/model/login_policy.go
index 265391b5d8..46751498d9 100644
--- a/internal/iam/model/login_policy.go
+++ b/internal/iam/model/login_policy.go
@@ -16,6 +16,7 @@ type LoginPolicy struct {
ForceMFA bool
SecondFactors []SecondFactorType
MultiFactors []MultiFactorType
+ PasswordlessType PasswordlessType
}
type IDPProvider struct {
@@ -53,6 +54,13 @@ const (
MultiFactorTypeU2FWithPIN
)
+type PasswordlessType int32
+
+const (
+ PasswordlessTypeNotAllowed PasswordlessType = iota
+ PasswordlessTypeAllowed
+)
+
func (p *LoginPolicy) IsValid() bool {
return p.ObjectRoot.AggregateID != ""
}
diff --git a/internal/iam/model/login_policy_view.go b/internal/iam/model/login_policy_view.go
index c41649984d..4bc6d51850 100644
--- a/internal/iam/model/login_policy_view.go
+++ b/internal/iam/model/login_policy_view.go
@@ -11,6 +11,7 @@ type LoginPolicyView struct {
AllowRegister bool
AllowExternalIDP bool
ForceMFA bool
+ PasswordlessType PasswordlessType
SecondFactors []SecondFactorType
MultiFactors []MultiFactorType
Default bool
diff --git a/internal/iam/repository/eventsourcing/eventstore.go b/internal/iam/repository/eventsourcing/eventstore.go
index c2fad65924..e1ed4d2d26 100644
--- a/internal/iam/repository/eventsourcing/eventstore.go
+++ b/internal/iam/repository/eventsourcing/eventstore.go
@@ -14,7 +14,7 @@ import (
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/id"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
type IAMEventstore struct {
diff --git a/internal/iam/repository/eventsourcing/eventstore_mock_test.go b/internal/iam/repository/eventsourcing/eventstore_mock_test.go
index 584e320c45..e41a323014 100644
--- a/internal/iam/repository/eventsourcing/eventstore_mock_test.go
+++ b/internal/iam/repository/eventsourcing/eventstore_mock_test.go
@@ -127,8 +127,8 @@ func GetMockManipulateIAMWithLoginPolicy(ctrl *gomock.Controller) *IAMEventstore
func GetMockManipulateIAMWithLoginPolicyWithMFAs(ctrl *gomock.Controller) *IAMEventstore {
policyData, _ := json.Marshal(model.LoginPolicy{AllowRegister: true, AllowUsernamePassword: true, AllowExternalIdp: true})
idpProviderData, _ := json.Marshal(model.IDPProvider{IDPConfigID: "IDPConfigID", Type: 1})
- secondFactor, _ := json.Marshal(model.MFA{MfaType: int32(model2.SecondFactorTypeOTP)})
- multiFactor, _ := json.Marshal(model.MFA{MfaType: int32(model2.MultiFactorTypeU2FWithPIN)})
+ secondFactor, _ := json.Marshal(model.MFA{MFAType: int32(model2.SecondFactorTypeOTP)})
+ multiFactor, _ := json.Marshal(model.MFA{MFAType: int32(model2.MultiFactorTypeU2FWithPIN)})
events := []*es_models.Event{
{AggregateID: "AggregateID", Sequence: 1, Type: model.IAMSetupStarted},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyAdded, Data: policyData},
diff --git a/internal/iam/repository/eventsourcing/iam.go b/internal/iam/repository/eventsourcing/iam.go
index 2522316602..ba62d70c52 100644
--- a/internal/iam/repository/eventsourcing/iam.go
+++ b/internal/iam/repository/eventsourcing/iam.go
@@ -359,7 +359,7 @@ func LoginPolicySecondFactorAddedAggregate(aggCreator *es_models.AggregateCreato
AggregateTypeFilter(model.IAMAggregate).
AggregateIDFilter(existing.AggregateID)
- validation := checkExistingLoginPolicySecondFactorValidation(mfa.MfaType)
+ validation := checkExistingLoginPolicySecondFactorValidation(mfa.MFAType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicySecondFactorAdded, mfa)
}
@@ -391,7 +391,7 @@ func LoginPolicyMultiFactorAddedAggregate(aggCreator *es_models.AggregateCreator
AggregateTypeFilter(model.IAMAggregate).
AggregateIDFilter(existing.AggregateID)
- validation := checkExistingLoginPolicyMultiFactorValidation(mfa.MfaType)
+ validation := checkExistingLoginPolicyMultiFactorValidation(mfa.MFAType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicyMultiFactorAdded, mfa)
}
@@ -689,7 +689,7 @@ func checkExistingLoginPolicySecondFactorValidation(mfaType int32) func(...*es_m
if err != nil {
return err
}
- mfas = append(mfas, idp.MfaType)
+ mfas = append(mfas, idp.MFAType)
case model.LoginPolicySecondFactorRemoved:
mfa := new(model.MFA)
err := mfa.SetData(event)
@@ -697,7 +697,7 @@ func checkExistingLoginPolicySecondFactorValidation(mfaType int32) func(...*es_m
return err
}
for i := len(mfas) - 1; i >= 0; i-- {
- if mfas[i] == mfa.MfaType {
+ if mfas[i] == mfa.MFAType {
mfas[i] = mfas[len(mfas)-1]
mfas[len(mfas)-1] = 0
mfas = mfas[:len(mfas)-1]
@@ -726,7 +726,7 @@ func checkExistingLoginPolicyMultiFactorValidation(mfaType int32) func(...*es_mo
if err != nil {
return err
}
- mfas = append(mfas, idp.MfaType)
+ mfas = append(mfas, idp.MFAType)
case model.LoginPolicyMultiFactorRemoved:
mfa := new(model.MFA)
err := mfa.SetData(event)
@@ -734,7 +734,7 @@ func checkExistingLoginPolicyMultiFactorValidation(mfaType int32) func(...*es_mo
return err
}
for i := len(mfas) - 1; i >= 0; i-- {
- if mfas[i] == mfa.MfaType {
+ if mfas[i] == mfa.MFAType {
mfas[i] = mfas[len(mfas)-1]
mfas[len(mfas)-1] = 0
mfas = mfas[:len(mfas)-1]
diff --git a/internal/iam/repository/eventsourcing/iam_test.go b/internal/iam/repository/eventsourcing/iam_test.go
index 748c27ff81..bf3625dc8c 100644
--- a/internal/iam/repository/eventsourcing/iam_test.go
+++ b/internal/iam/repository/eventsourcing/iam_test.go
@@ -1497,7 +1497,7 @@ func TestLoginPolicySecondFactorAddedAggregate(t *testing.T) {
AllowUsernamePassword: true,
}},
newMFA: &model.MFA{
- MfaType: int32(iam_model.SecondFactorTypeOTP),
+ MFAType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
@@ -1587,7 +1587,7 @@ func TestLoginPolicySecondFactorRemovedAggregate(t *testing.T) {
},
}},
mfa: &model.MFA{
- MfaType: int32(iam_model.SecondFactorTypeOTP),
+ MFAType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
@@ -1674,7 +1674,7 @@ func TestLoginPolicyMultiFactorAddedAggregate(t *testing.T) {
AllowUsernamePassword: true,
}},
newMFA: &model.MFA{
- MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN),
+ MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN),
},
aggCreator: models.NewAggregateCreator("Test"),
},
@@ -1764,7 +1764,7 @@ func TestLoginPolicyMultiFactorRemovedAggregate(t *testing.T) {
},
}},
mfa: &model.MFA{
- MfaType: int32(iam_model.SecondFactorTypeOTP),
+ MFAType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
diff --git a/internal/iam/repository/eventsourcing/model/login_policy.go b/internal/iam/repository/eventsourcing/model/login_policy.go
index 6421a86747..7b28b18b96 100644
--- a/internal/iam/repository/eventsourcing/model/login_policy.go
+++ b/internal/iam/repository/eventsourcing/model/login_policy.go
@@ -14,7 +14,8 @@ type LoginPolicy struct {
AllowUsernamePassword bool `json:"allowUsernamePassword"`
AllowRegister bool `json:"allowRegister"`
AllowExternalIdp bool `json:"allowExternalIdp"`
- ForceMFA bool `json:"forceMfa"`
+ ForceMFA bool `json:"forceMFA"`
+ PasswordlessType int32 `json:"passwordlessType"`
IDPProviders []*IDPProvider `json:"-"`
SecondFactors []int32 `json:"-"`
MultiFactors []int32 `json:"-"`
@@ -31,7 +32,7 @@ type IDPProviderID struct {
}
type MFA struct {
- MfaType int32 `json:"mfaType"`
+ MFAType int32 `json:"mfaType"`
}
func GetIDPProvider(providers []*IDPProvider, id string) (int, *IDPProvider) {
@@ -65,6 +66,7 @@ func LoginPolicyToModel(policy *LoginPolicy) *iam_model.LoginPolicy {
ForceMFA: policy.ForceMFA,
SecondFactors: secondFactors,
MultiFactors: multiFactors,
+ PasswordlessType: iam_model.PasswordlessType(policy.PasswordlessType),
}
}
@@ -82,6 +84,7 @@ func LoginPolicyFromModel(policy *iam_model.LoginPolicy) *LoginPolicy {
ForceMFA: policy.ForceMFA,
SecondFactors: secondFactors,
MultiFactors: multiFactors,
+ PasswordlessType: int32(policy.PasswordlessType),
}
}
@@ -126,7 +129,7 @@ func SecondFactorsFromModel(mfas []iam_model.SecondFactorType) []int32 {
}
func SecondFactorFromModel(mfa iam_model.SecondFactorType) *MFA {
- return &MFA{MfaType: int32(mfa)}
+ return &MFA{MFAType: int32(mfa)}
}
func SecondFactorsToModel(mfas []int32) []iam_model.SecondFactorType {
@@ -146,7 +149,7 @@ func MultiFactorsFromModel(mfas []iam_model.MultiFactorType) []int32 {
}
func MultiFactorFromModel(mfa iam_model.MultiFactorType) *MFA {
- return &MFA{MfaType: int32(mfa)}
+ return &MFA{MFAType: int32(mfa)}
}
func MultiFactorsToModel(mfas []int32) []iam_model.MultiFactorType {
@@ -172,6 +175,9 @@ func (p *LoginPolicy) Changes(changed *LoginPolicy) map[string]interface{} {
if changed.ForceMFA != p.ForceMFA {
changes["forceMFA"] = changed.ForceMFA
}
+ if changed.PasswordlessType != p.PasswordlessType {
+ changes["passwordlessType"] = changed.PasswordlessType
+ }
return changes
}
@@ -221,7 +227,7 @@ func (iam *IAM) appendAddSecondFactorToLoginPolicyEvent(event *es_models.Event)
if err != nil {
return err
}
- iam.DefaultLoginPolicy.SecondFactors = append(iam.DefaultLoginPolicy.SecondFactors, mfa.MfaType)
+ iam.DefaultLoginPolicy.SecondFactors = append(iam.DefaultLoginPolicy.SecondFactors, mfa.MFAType)
return nil
}
@@ -231,7 +237,7 @@ func (iam *IAM) appendRemoveSecondFactorFromLoginPolicyEvent(event *es_models.Ev
if err != nil {
return err
}
- if i, m := GetMFA(iam.DefaultLoginPolicy.SecondFactors, mfa.MfaType); m != 0 {
+ if i, m := GetMFA(iam.DefaultLoginPolicy.SecondFactors, mfa.MFAType); m != 0 {
iam.DefaultLoginPolicy.SecondFactors[i] = iam.DefaultLoginPolicy.SecondFactors[len(iam.DefaultLoginPolicy.SecondFactors)-1]
iam.DefaultLoginPolicy.SecondFactors[len(iam.DefaultLoginPolicy.SecondFactors)-1] = 0
iam.DefaultLoginPolicy.SecondFactors = iam.DefaultLoginPolicy.SecondFactors[:len(iam.DefaultLoginPolicy.SecondFactors)-1]
@@ -246,7 +252,7 @@ func (iam *IAM) appendAddMultiFactorToLoginPolicyEvent(event *es_models.Event) e
if err != nil {
return err
}
- iam.DefaultLoginPolicy.MultiFactors = append(iam.DefaultLoginPolicy.MultiFactors, mfa.MfaType)
+ iam.DefaultLoginPolicy.MultiFactors = append(iam.DefaultLoginPolicy.MultiFactors, mfa.MFAType)
return nil
}
@@ -256,7 +262,7 @@ func (iam *IAM) appendRemoveMultiFactorFromLoginPolicyEvent(event *es_models.Eve
if err != nil {
return err
}
- if i, m := GetMFA(iam.DefaultLoginPolicy.MultiFactors, mfa.MfaType); m != 0 {
+ if i, m := GetMFA(iam.DefaultLoginPolicy.MultiFactors, mfa.MFAType); m != 0 {
iam.DefaultLoginPolicy.MultiFactors[i] = iam.DefaultLoginPolicy.MultiFactors[len(iam.DefaultLoginPolicy.MultiFactors)-1]
iam.DefaultLoginPolicy.MultiFactors[len(iam.DefaultLoginPolicy.MultiFactors)-1] = 0
iam.DefaultLoginPolicy.MultiFactors = iam.DefaultLoginPolicy.MultiFactors[:len(iam.DefaultLoginPolicy.MultiFactors)-1]
diff --git a/internal/iam/repository/eventsourcing/model/login_policy_test.go b/internal/iam/repository/eventsourcing/model/login_policy_test.go
index cd39fa07e8..a7a9164885 100644
--- a/internal/iam/repository/eventsourcing/model/login_policy_test.go
+++ b/internal/iam/repository/eventsourcing/model/login_policy_test.go
@@ -275,7 +275,7 @@ func TestAppendAddSecondFactorToPolicyEvent(t *testing.T) {
name: "append add second factor to login policy event",
args: args{
iam: &IAM{DefaultLoginPolicy: &LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
- mfa: &MFA{MfaType: int32(model.SecondFactorTypeOTP)},
+ mfa: &MFA{MFAType: int32(model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
@@ -294,7 +294,7 @@ func TestAppendAddSecondFactorToPolicyEvent(t *testing.T) {
if len(tt.result.DefaultLoginPolicy.SecondFactors) != len(tt.args.iam.DefaultLoginPolicy.SecondFactors) {
t.Errorf("got wrong second factors len: expected: %v, actual: %v ", len(tt.result.DefaultLoginPolicy.SecondFactors), len(tt.args.iam.DefaultLoginPolicy.SecondFactors))
}
- if tt.result.DefaultLoginPolicy.SecondFactors[0] != tt.args.mfa.MfaType {
+ if tt.result.DefaultLoginPolicy.SecondFactors[0] != tt.args.mfa.MFAType {
t.Errorf("got wrong second factor: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.SecondFactors[0], tt.args.mfa)
}
})
@@ -320,7 +320,7 @@ func TestRemoveSecondFactorToPolicyEvent(t *testing.T) {
SecondFactors: []int32{
int32(model.SecondFactorTypeOTP),
}}},
- mfa: &MFA{MfaType: int32(model.SecondFactorTypeOTP)},
+ mfa: &MFA{MFAType: int32(model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
@@ -359,7 +359,7 @@ func TestAppendAddMultiFactorToPolicyEvent(t *testing.T) {
name: "append add mfa to login policy event",
args: args{
iam: &IAM{DefaultLoginPolicy: &LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
- mfa: &MFA{MfaType: int32(model.MultiFactorTypeU2FWithPIN)},
+ mfa: &MFA{MFAType: int32(model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
@@ -378,7 +378,7 @@ func TestAppendAddMultiFactorToPolicyEvent(t *testing.T) {
if len(tt.result.DefaultLoginPolicy.MultiFactors) != len(tt.args.iam.DefaultLoginPolicy.MultiFactors) {
t.Errorf("got wrong mfas len: expected: %v, actual: %v ", len(tt.result.DefaultLoginPolicy.MultiFactors), len(tt.args.iam.DefaultLoginPolicy.MultiFactors))
}
- if tt.result.DefaultLoginPolicy.MultiFactors[0] != tt.args.mfa.MfaType {
+ if tt.result.DefaultLoginPolicy.MultiFactors[0] != tt.args.mfa.MFAType {
t.Errorf("got wrong mfa: expected: %v, actual: %v ", tt.result.DefaultLoginPolicy.MultiFactors[0], tt.args.mfa)
}
})
@@ -404,7 +404,7 @@ func TestRemoveMultiFactorToPolicyEvent(t *testing.T) {
MultiFactors: []int32{
int32(model.MultiFactorTypeU2FWithPIN),
}}},
- mfa: &MFA{MfaType: int32(model.MultiFactorTypeU2FWithPIN)},
+ mfa: &MFA{MFAType: int32(model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &IAM{DefaultLoginPolicy: &LoginPolicy{
diff --git a/internal/iam/repository/view/model/login_policy.go b/internal/iam/repository/view/model/login_policy.go
index 9977c637bd..7bdc919a87 100644
--- a/internal/iam/repository/view/model/login_policy.go
+++ b/internal/iam/repository/view/model/login_policy.go
@@ -28,6 +28,7 @@ type LoginPolicyView struct {
AllowUsernamePassword bool `json:"allowUsernamePassword" gorm:"column:allow_username_password"`
AllowExternalIDP bool `json:"allowExternalIdp" gorm:"column:allow_external_idp"`
ForceMFA bool `json:"forceMFA" gorm:"column:force_mfa"`
+ PasswordlessType int32 `json:"passwordlessType" gorm:"column:passwordless_type"`
SecondFactors pq.Int64Array `json:"-" gorm:"column:second_factors"`
MultiFactors pq.Int64Array `json:"-" gorm:"column:multi_factors"`
Default bool `json:"-" gorm:"-"`
@@ -45,6 +46,7 @@ func LoginPolicyViewFromModel(policy *model.LoginPolicyView) *LoginPolicyView {
AllowExternalIDP: policy.AllowExternalIDP,
AllowUsernamePassword: policy.AllowUsernamePassword,
ForceMFA: policy.ForceMFA,
+ PasswordlessType: int32(policy.PasswordlessType),
SecondFactors: secondFactorsFromModel(policy.SecondFactors),
MultiFactors: multiFactorsFromModel(policy.MultiFactors),
Default: policy.Default,
@@ -77,6 +79,7 @@ func LoginPolicyViewToModel(policy *LoginPolicyView) *model.LoginPolicyView {
AllowExternalIDP: policy.AllowExternalIDP,
AllowUsernamePassword: policy.AllowUsernamePassword,
ForceMFA: policy.ForceMFA,
+ PasswordlessType: model.PasswordlessType(policy.PasswordlessType),
SecondFactors: secondFactorsToModel(policy.SecondFactors),
MultiFactors: multiFactorsToToModel(policy.MultiFactors),
Default: policy.Default,
@@ -115,7 +118,7 @@ func (p *LoginPolicyView) AppendEvent(event *models.Event) (err error) {
if err != nil {
return err
}
- p.SecondFactors = append(p.SecondFactors, int64(mfa.MfaType))
+ p.SecondFactors = append(p.SecondFactors, int64(mfa.MFAType))
case es_model.LoginPolicySecondFactorRemoved, org_es_model.LoginPolicySecondFactorRemoved:
err = p.removeSecondFactor(event)
case es_model.LoginPolicyMultiFactorAdded, org_es_model.LoginPolicyMultiFactorAdded:
@@ -124,7 +127,7 @@ func (p *LoginPolicyView) AppendEvent(event *models.Event) (err error) {
if err != nil {
return err
}
- p.MultiFactors = append(p.MultiFactors, int64(mfa.MfaType))
+ p.MultiFactors = append(p.MultiFactors, int64(mfa.MFAType))
case es_model.LoginPolicyMultiFactorRemoved, org_es_model.LoginPolicyMultiFactorRemoved:
err = p.removeMultiFactor(event)
}
@@ -150,7 +153,7 @@ func (p *LoginPolicyView) removeSecondFactor(event *models.Event) error {
return err
}
for i := len(p.SecondFactors) - 1; i >= 0; i-- {
- if p.SecondFactors[i] == int64(mfa.MfaType) {
+ if p.SecondFactors[i] == int64(mfa.MFAType) {
copy(p.SecondFactors[i:], p.SecondFactors[i+1:])
p.SecondFactors[len(p.SecondFactors)-1] = 0
p.SecondFactors = p.SecondFactors[:len(p.SecondFactors)-1]
@@ -167,7 +170,7 @@ func (p *LoginPolicyView) removeMultiFactor(event *models.Event) error {
return err
}
for i := len(p.MultiFactors) - 1; i >= 0; i-- {
- if p.MultiFactors[i] == int64(mfa.MfaType) {
+ if p.MultiFactors[i] == int64(mfa.MFAType) {
copy(p.MultiFactors[i:], p.MultiFactors[i+1:])
p.MultiFactors[len(p.MultiFactors)-1] = 0
p.MultiFactors = p.MultiFactors[:len(p.MultiFactors)-1]
diff --git a/internal/management/repository/eventsourcing/eventstore/org.go b/internal/management/repository/eventsourcing/eventstore/org.go
index ffb6335a28..6bc11af854 100644
--- a/internal/management/repository/eventsourcing/eventstore/org.go
+++ b/internal/management/repository/eventsourcing/eventstore/org.go
@@ -22,7 +22,7 @@ import (
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
"github.com/caos/zitadel/internal/org/repository/view/model"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
@@ -122,7 +122,7 @@ func (repo *OrgRepository) SearchMyOrgDomains(ctx context.Context, request *org_
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -219,7 +219,7 @@ func (repo *OrgRepository) SearchMyOrgMembers(ctx context.Context, request *org_
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -306,7 +306,7 @@ func (repo *OrgRepository) SearchIDPConfigs(ctx context.Context, request *iam_mo
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -414,9 +414,9 @@ func (repo *OrgRepository) SearchIDPProviders(ctx context.Context, request *iam_
request.AppendAggregateIDQuery(authz.GetCtxData(ctx).OrgID)
}
request.EnsureLimit(repo.SearchLimit)
- sequence, sequenceErr := repo.View.GetLatestIdpProviderSequence()
+ sequence, sequenceErr := repo.View.GetLatestIDPProviderSequence()
logging.Log("EVENT-Tuiks").OnError(sequenceErr).Warn("could not read latest iam sequence")
- providers, count, err := repo.View.SearchIdpProviders(request)
+ providers, count, err := repo.View.SearchIDPProviders(request)
if err != nil {
return nil, err
}
@@ -428,7 +428,7 @@ func (repo *OrgRepository) SearchIDPProviders(ctx context.Context, request *iam_
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
diff --git a/internal/management/repository/eventsourcing/eventstore/project.go b/internal/management/repository/eventsourcing/eventstore/project.go
index 432bee10dc..5a9343ff11 100644
--- a/internal/management/repository/eventsourcing/eventstore/project.go
+++ b/internal/management/repository/eventsourcing/eventstore/project.go
@@ -141,7 +141,7 @@ func (repo *ProjectRepo) SearchProjects(ctx context.Context, request *proj_model
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -162,7 +162,7 @@ func (repo *ProjectRepo) SearchProjects(ctx context.Context, request *proj_model
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -212,7 +212,7 @@ func (repo *ProjectRepo) SearchProjectMembers(ctx context.Context, request *proj
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -285,7 +285,7 @@ func (repo *ProjectRepo) SearchProjectRoles(ctx context.Context, projectID strin
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -380,7 +380,7 @@ func (repo *ProjectRepo) SearchApplications(ctx context.Context, request *proj_m
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -437,7 +437,7 @@ func (repo *ProjectRepo) SearchProjectGrants(ctx context.Context, request *proj_
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -467,7 +467,7 @@ func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *pro
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -488,7 +488,7 @@ func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *pro
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -626,7 +626,7 @@ func (repo *ProjectRepo) SearchProjectGrantMembers(ctx context.Context, request
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
diff --git a/internal/management/repository/eventsourcing/eventstore/user.go b/internal/management/repository/eventsourcing/eventstore/user.go
index 3ab8118411..3be494fd68 100644
--- a/internal/management/repository/eventsourcing/eventstore/user.go
+++ b/internal/management/repository/eventsourcing/eventstore/user.go
@@ -172,7 +172,7 @@ func (repo *UserRepo) SearchUsers(ctx context.Context, request *usr_model.UserSe
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -209,7 +209,7 @@ func (repo *UserRepo) IsUserUnique(ctx context.Context, userName, email string)
return repo.View.IsUserUnique(userName, email)
}
-func (repo *UserRepo) UserMfas(ctx context.Context, userID string) ([]*usr_model.MultiFactor, error) {
+func (repo *UserRepo) UserMFAs(ctx context.Context, userID string) ([]*usr_model.MultiFactor, error) {
user, err := repo.UserByID(ctx, userID)
if err != nil {
return nil, err
@@ -217,10 +217,10 @@ func (repo *UserRepo) UserMfas(ctx context.Context, userID string) ([]*usr_model
if user.HumanView == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-xx0hV", "Errors.User.NotHuman")
}
- if user.OTPState == usr_model.MfaStateUnspecified {
+ if user.OTPState == usr_model.MFAStateUnspecified {
return []*usr_model.MultiFactor{}, nil
}
- return []*usr_model.MultiFactor{{Type: usr_model.MfaTypeOTP, State: user.OTPState}}, nil
+ return []*usr_model.MultiFactor{{Type: usr_model.MFATypeOTP, State: user.OTPState}}, nil
}
func (repo *UserRepo) RemoveOTP(ctx context.Context, userID string) error {
@@ -274,7 +274,7 @@ func (repo *UserRepo) SearchExternalIDPs(ctx context.Context, request *usr_model
}
if seqErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -311,7 +311,7 @@ func (repo *UserRepo) SearchMachineKeys(ctx context.Context, request *usr_model.
}
if seqErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -419,7 +419,7 @@ func (repo *UserRepo) SearchUserMemberships(ctx context.Context, request *usr_mo
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -459,7 +459,7 @@ func handleSearchUserMembershipsPermissions(ctx context.Context, request *usr_mo
}
if sequence != nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result
}
diff --git a/internal/management/repository/eventsourcing/eventstore/user_grant.go b/internal/management/repository/eventsourcing/eventstore/user_grant.go
index ddcfedb81d..09568b64fc 100644
--- a/internal/management/repository/eventsourcing/eventstore/user_grant.go
+++ b/internal/management/repository/eventsourcing/eventstore/user_grant.go
@@ -137,7 +137,7 @@ func (repo *UserGrantRepo) SearchUserGrants(ctx context.Context, request *grant_
}
if sequenceErr == nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result, nil
}
@@ -183,7 +183,7 @@ func checkContainsPermID(ids []string, query *grant_model.UserGrantSearchQuery,
}
if sequence != nil {
result.Sequence = sequence.CurrentSequence
- result.Timestamp = sequence.CurrentTimestamp
+ result.Timestamp = sequence.LastSuccessfulSpoolerRun
}
return result
}
diff --git a/internal/management/repository/eventsourcing/handler/application.go b/internal/management/repository/eventsourcing/handler/application.go
index 4395737197..8d1490c433 100644
--- a/internal/management/repository/eventsourcing/handler/application.go
+++ b/internal/management/repository/eventsourcing/handler/application.go
@@ -65,33 +65,37 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return a.view.DeleteApplication(app.ID, event.Sequence)
+ return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
case es_model.ProjectChanged:
apps, err := a.view.ApplicationsByProjectID(event.AggregateID)
if err != nil {
return err
}
if len(apps) == 0 {
- return a.view.ProcessedApplicationSequence(event.Sequence)
+ return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
}
for _, app := range apps {
if err := app.AppendEvent(event); err != nil {
return err
}
}
- return a.view.PutApplications(apps, event.Sequence)
+ return a.view.PutApplications(apps, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved:
return a.view.DeleteApplicationsByProjectID(event.AggregateID)
default:
- return a.view.ProcessedApplicationSequence(event.Sequence)
+ return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return a.view.PutApplication(app)
+ return a.view.PutApplication(app, event.CreationDate)
}
func (a *Application) OnError(event *models.Event, spoolerError error) error {
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerError).Warn("something went wrong in project app handler")
return spooler.HandleError(event, spoolerError, a.view.GetLatestApplicationFailedEvent, a.view.ProcessedApplicationFailedEvent, a.view.ProcessedApplicationSequence, a.errorCountUntilSkip)
}
+
+func (a *Application) OnSuccess() error {
+ return spooler.HandleSuccess(a.view.UpdateApplicationSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/idp_config.go b/internal/management/repository/eventsourcing/handler/idp_config.go
index 7ce0e6c487..07301c71b8 100644
--- a/internal/management/repository/eventsourcing/handler/idp_config.go
+++ b/internal/management/repository/eventsourcing/handler/idp_config.go
@@ -66,17 +66,21 @@ func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil {
return err
}
- return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence)
+ return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIDPConfigSequence(event.Sequence)
+ return m.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIDPConfig(idp, idp.Sequence)
+ return m.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
}
-func (m *IDPConfig) OnError(event *models.Event, err error) error {
+func (i *IDPConfig) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Nxu8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
- return spooler.HandleError(event, err, m.view.GetLatestIDPConfigFailedEvent, m.view.ProcessedIDPConfigFailedEvent, m.view.ProcessedIDPConfigSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
+}
+
+func (i *IDPConfig) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateIDPConfigSpoolerRunTimestamp)
}
diff --git a/internal/management/repository/eventsourcing/handler/idp_providers.go b/internal/management/repository/eventsourcing/handler/idp_providers.go
index 56e8fbc7d2..9d873eed67 100644
--- a/internal/management/repository/eventsourcing/handler/idp_providers.go
+++ b/internal/management/repository/eventsourcing/handler/idp_providers.go
@@ -32,7 +32,7 @@ func (m *IDPProvider) ViewModel() string {
}
func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestIdpProviderSequence()
+ sequence, err := m.view.GetLatestIDPProviderSequence()
if err != nil {
return nil, err
}
@@ -64,7 +64,7 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteIdpProvider(event.AggregateID, provider.IDPConfigID, event.Sequence)
+ return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem
@@ -72,7 +72,7 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
providerType = iam_model.IDPProviderTypeOrg
}
esConfig.AppendEvent(providerType, event)
- providers, err := m.view.IdpProvidersByIdpConfigID(event.AggregateID, esConfig.IDPConfigID)
+ providers, err := m.view.IDPProvidersByIdpConfigID(event.AggregateID, esConfig.IDPConfigID)
if err != nil {
return err
}
@@ -88,16 +88,16 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
for _, provider := range providers {
m.fillConfigData(provider, config)
}
- return m.view.PutIdpProviders(event.Sequence, providers...)
+ return m.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
case org_es_model.LoginPolicyRemoved:
- return m.view.DeleteIdpProvidersByAggregateID(event.AggregateID, event.Sequence)
+ return m.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedIdpProviderSequence(event.Sequence)
+ return m.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutIdpProvider(provider, provider.Sequence)
+ return m.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
}
func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
@@ -123,5 +123,9 @@ func (m *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, c
func (m *IDPProvider) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Msj8c", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
- return spooler.HandleError(event, err, m.view.GetLatestIdpProviderFailedEvent, m.view.ProcessedIdpProviderFailedEvent, m.view.ProcessedIdpProviderSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, m.view.GetLatestIDPProviderFailedEvent, m.view.ProcessedIDPProviderFailedEvent, m.view.ProcessedIDPProviderSequence, m.errorCountUntilSkip)
+}
+
+func (m *IDPProvider) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdateIDPProviderSpoolerRunTimestamp)
}
diff --git a/internal/management/repository/eventsourcing/handler/label_policy.go b/internal/management/repository/eventsourcing/handler/label_policy.go
index 8c3238159f..2c47a03c80 100644
--- a/internal/management/repository/eventsourcing/handler/label_policy.go
+++ b/internal/management/repository/eventsourcing/handler/label_policy.go
@@ -53,15 +53,19 @@ func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
default:
- return m.view.ProcessedLabelPolicySequence(event.Sequence)
+ return m.view.ProcessedLabelPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutLabelPolicy(policy, policy.Sequence)
+ return m.view.PutLabelPolicy(policy, policy.Sequence, event.CreationDate)
}
func (m *LabelPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip)
}
+
+func (m *LabelPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdateLabelPolicySpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/login_policy.go b/internal/management/repository/eventsourcing/handler/login_policy.go
index 305953a7b7..cb6f06c4d2 100644
--- a/internal/management/repository/eventsourcing/handler/login_policy.go
+++ b/internal/management/repository/eventsourcing/handler/login_policy.go
@@ -57,17 +57,21 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
case model.LoginPolicyRemoved:
- return m.view.DeleteLoginPolicy(event.AggregateID, event.Sequence)
+ return m.view.DeleteLoginPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedLoginPolicySequence(event.Sequence)
+ return m.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutLoginPolicy(policy, policy.Sequence)
+ return m.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
}
func (m *LoginPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLoginPolicyFailedEvent, m.view.ProcessedLoginPolicyFailedEvent, m.view.ProcessedLoginPolicySequence, m.errorCountUntilSkip)
}
+
+func (m *LoginPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdateLoginPolicySpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/machine_keys.go b/internal/management/repository/eventsourcing/handler/machine_keys.go
index c09a2bdcf7..cd6b29b6a8 100644
--- a/internal/management/repository/eventsourcing/handler/machine_keys.go
+++ b/internal/management/repository/eventsourcing/handler/machine_keys.go
@@ -48,26 +48,30 @@ func (d *MachineKeys) processMachineKeys(event *models.Event) (err error) {
case model.MachineKeyAdded:
err = key.AppendEvent(event)
if key.ExpirationDate.Before(time.Now()) {
- return d.view.ProcessedMachineKeySequence(event.Sequence)
+ return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
}
case model.MachineKeyRemoved:
err = key.SetData(event)
if err != nil {
return err
}
- return d.view.DeleteMachineKey(key.ID, event.Sequence)
+ return d.view.DeleteMachineKey(key.ID, event.Sequence, event.CreationDate)
case model.UserRemoved:
- return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence)
+ return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return d.view.ProcessedMachineKeySequence(event.Sequence)
+ return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return d.view.PutMachineKey(key, key.Sequence)
+ return d.view.PutMachineKey(key, key.Sequence, event.CreationDate)
}
func (d *MachineKeys) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-S9fe", "id", event.AggregateID).WithError(err).Warn("something went wrong in machine key handler")
return spooler.HandleError(event, err, d.view.GetLatestMachineKeyFailedEvent, d.view.ProcessedMachineKeyFailedEvent, d.view.ProcessedMachineKeySequence, d.errorCountUntilSkip)
}
+
+func (d *MachineKeys) OnSuccess() error {
+ return spooler.HandleSuccess(d.view.UpdateMachineKeySpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/org.go b/internal/management/repository/eventsourcing/handler/org.go
index 1674712059..23155a5c52 100644
--- a/internal/management/repository/eventsourcing/handler/org.go
+++ b/internal/management/repository/eventsourcing/handler/org.go
@@ -47,15 +47,19 @@ func (o *Org) Reduce(event *es_models.Event) (err error) {
}
err = org.AppendEvent(event)
default:
- return o.view.ProcessedOrgSequence(event.Sequence)
+ return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return o.view.PutOrg(org)
+ return o.view.PutOrg(org, event.CreationDate)
}
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in project app handler")
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
}
+
+func (o *Org) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/org_domain.go b/internal/management/repository/eventsourcing/handler/org_domain.go
index d3c21aa63e..9dc6307749 100644
--- a/internal/management/repository/eventsourcing/handler/org_domain.go
+++ b/internal/management/repository/eventsourcing/handler/org_domain.go
@@ -72,7 +72,7 @@ func (d *OrgDomain) processOrgDomain(event *models.Event) (err error) {
for _, existingDomain := range existingDomains {
existingDomain.Primary = false
}
- err = d.view.PutOrgDomains(existingDomains, 0)
+ err = d.view.PutOrgDomains(existingDomains, 0, event.CreationDate)
if err != nil {
return err
}
@@ -82,17 +82,21 @@ func (d *OrgDomain) processOrgDomain(event *models.Event) (err error) {
if err != nil {
return err
}
- return d.view.DeleteOrgDomain(event.AggregateID, domain.Domain, event.Sequence)
+ return d.view.DeleteOrgDomain(event.AggregateID, domain.Domain, event.Sequence, event.CreationDate)
default:
- return d.view.ProcessedOrgDomainSequence(event.Sequence)
+ return d.view.ProcessedOrgDomainSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return d.view.PutOrgDomain(domain, domain.Sequence)
+ return d.view.PutOrgDomain(domain, domain.Sequence, event.CreationDate)
}
func (d *OrgDomain) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-us4sj", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgdomain handler")
return spooler.HandleError(event, err, d.view.GetLatestOrgDomainFailedEvent, d.view.ProcessedOrgDomainFailedEvent, d.view.ProcessedOrgDomainSequence, d.errorCountUntilSkip)
}
+
+func (o *OrgDomain) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgDomainSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/org_iam_policy.go b/internal/management/repository/eventsourcing/handler/org_iam_policy.go
index 7b0b8860ca..fffe08cfec 100644
--- a/internal/management/repository/eventsourcing/handler/org_iam_policy.go
+++ b/internal/management/repository/eventsourcing/handler/org_iam_policy.go
@@ -53,17 +53,21 @@ func (m *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
}
err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved:
- return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence)
+ return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedOrgIAMPolicySequence(event.Sequence)
+ return m.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutOrgIAMPolicy(policy, policy.Sequence)
+ return m.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
}
func (m *OrgIAMPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-3Gf9s", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
return spooler.HandleError(event, err, m.view.GetLatestOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicySequence, m.errorCountUntilSkip)
}
+
+func (o *OrgIAMPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgIAMPolicySpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/org_member.go b/internal/management/repository/eventsourcing/handler/org_member.go
index c238c2363a..26f2b2fb86 100644
--- a/internal/management/repository/eventsourcing/handler/org_member.go
+++ b/internal/management/repository/eventsourcing/handler/org_member.go
@@ -72,14 +72,14 @@ func (m *OrgMember) processOrgMember(event *models.Event) (err error) {
if err != nil {
return err
}
- return m.view.DeleteOrgMember(event.AggregateID, member.UserID, event.Sequence)
+ return m.view.DeleteOrgMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedOrgMemberSequence(event.Sequence)
+ return m.view.ProcessedOrgMemberSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutOrgMember(member, member.Sequence)
+ return m.view.PutOrgMember(member, member.Sequence, event.CreationDate)
}
func (m *OrgMember) processUser(event *models.Event) (err error) {
@@ -94,7 +94,7 @@ func (m *OrgMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return m.view.ProcessedOrgMemberSequence(event.Sequence)
+ return m.view.ProcessedOrgMemberSequence(event.Sequence, event.CreationDate)
}
user, err := m.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -103,11 +103,11 @@ func (m *OrgMember) processUser(event *models.Event) (err error) {
for _, member := range members {
m.fillUserData(member, user)
}
- return m.view.PutOrgMembers(members, event.Sequence)
+ return m.view.PutOrgMembers(members, event.Sequence, event.CreationDate)
case usr_es_model.UserRemoved:
- return m.view.DeleteOrgMembersByUserID(event.AggregateID, event.Sequence)
+ return m.view.DeleteOrgMembersByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedOrgMemberSequence(event.Sequence)
+ return m.view.ProcessedOrgMemberSequence(event.Sequence, event.CreationDate)
}
return nil
}
@@ -137,3 +137,7 @@ func (m *OrgMember) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-u73es", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
return spooler.HandleError(event, err, m.view.GetLatestOrgMemberFailedEvent, m.view.ProcessedOrgMemberFailedEvent, m.view.ProcessedOrgMemberSequence, m.errorCountUntilSkip)
}
+
+func (o *OrgMember) OnSuccess() error {
+ return spooler.HandleSuccess(o.view.UpdateOrgMemberSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/password_age_policy.go b/internal/management/repository/eventsourcing/handler/password_age_policy.go
index ccbb1c85f9..535acf03db 100644
--- a/internal/management/repository/eventsourcing/handler/password_age_policy.go
+++ b/internal/management/repository/eventsourcing/handler/password_age_policy.go
@@ -53,17 +53,21 @@ func (m *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err e
}
err = policy.AppendEvent(event)
case model.PasswordAgePolicyRemoved:
- return m.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence)
+ return m.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordAgePolicySequence(event.Sequence)
+ return m.view.ProcessedPasswordAgePolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordAgePolicy(policy, policy.Sequence)
+ return m.view.PutPasswordAgePolicy(policy, policy.Sequence, event.CreationDate)
}
func (m *PasswordAgePolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Bs89f", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordAge policy handler")
return spooler.HandleError(event, err, m.view.GetLatestPasswordAgePolicyFailedEvent, m.view.ProcessedPasswordAgePolicyFailedEvent, m.view.ProcessedPasswordAgePolicySequence, m.errorCountUntilSkip)
}
+
+func (m *PasswordAgePolicy) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdatePasswordAgePolicySpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/password_complexity_policy.go b/internal/management/repository/eventsourcing/handler/password_complexity_policy.go
index 61020657e4..4ada8b0c95 100644
--- a/internal/management/repository/eventsourcing/handler/password_complexity_policy.go
+++ b/internal/management/repository/eventsourcing/handler/password_complexity_policy.go
@@ -19,12 +19,12 @@ const (
passwordComplexityPolicyTable = "management.password_complexity_policies"
)
-func (m *PasswordComplexityPolicy) ViewModel() string {
+func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable
}
-func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordComplexityPolicySequence()
+func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processPasswordComplexityPolicy(event)
+ err = p.processPasswordComplexityPolicy(event)
}
return err
}
-func (m *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
+func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordComplexityPolicyView)
switch event.Type {
case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged:
- policy, err = m.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved:
- return m.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordComplexityPolicySequence(event.Sequence)
+ return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordComplexityPolicy(policy, policy.Sequence)
+ return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *PasswordComplexityPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdatePasswordComplexityPolicySpoolerRunTimestamp)
}
diff --git a/internal/management/repository/eventsourcing/handler/password_lockout_policy.go b/internal/management/repository/eventsourcing/handler/password_lockout_policy.go
index 0c0f1b93c0..c5a66d9528 100644
--- a/internal/management/repository/eventsourcing/handler/password_lockout_policy.go
+++ b/internal/management/repository/eventsourcing/handler/password_lockout_policy.go
@@ -19,12 +19,12 @@ const (
passwordLockoutPolicyTable = "management.password_lockout_policies"
)
-func (m *PasswordLockoutPolicy) ViewModel() string {
+func (p *PasswordLockoutPolicy) ViewModel() string {
return passwordLockoutPolicyTable
}
-func (m *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestPasswordLockoutPolicySequence()
+func (p *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := p.view.GetLatestPasswordLockoutPolicySequence()
if err != nil {
return nil, err
}
@@ -33,37 +33,41 @@ func (m *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *PasswordLockoutPolicy) Reduce(event *models.Event) (err error) {
+func (p *PasswordLockoutPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
- err = m.processPasswordLockoutPolicy(event)
+ err = p.processPasswordLockoutPolicy(event)
}
return err
}
-func (m *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event) (err error) {
+func (p *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordLockoutPolicyView)
switch event.Type {
case iam_es_model.PasswordLockoutPolicyAdded, model.PasswordLockoutPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.PasswordLockoutPolicyChanged, model.PasswordLockoutPolicyChanged:
- policy, err = m.view.PasswordLockoutPolicyByAggregateID(event.AggregateID)
+ policy, err = p.view.PasswordLockoutPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
case model.PasswordLockoutPolicyRemoved:
- return m.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence)
+ return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedPasswordLockoutPolicySequence(event.Sequence)
+ return p.view.ProcessedPasswordLockoutPolicySequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutPasswordLockoutPolicy(policy, policy.Sequence)
+ return p.view.PutPasswordLockoutPolicy(policy, policy.Sequence, event.CreationDate)
}
-func (m *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
+func (p *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Bms8f", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordLockout policy handler")
- return spooler.HandleError(event, err, m.view.GetLatestPasswordLockoutPolicyFailedEvent, m.view.ProcessedPasswordLockoutPolicyFailedEvent, m.view.ProcessedPasswordLockoutPolicySequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, p.view.GetLatestPasswordLockoutPolicyFailedEvent, p.view.ProcessedPasswordLockoutPolicyFailedEvent, p.view.ProcessedPasswordLockoutPolicySequence, p.errorCountUntilSkip)
+}
+
+func (p *PasswordLockoutPolicy) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdatePasswordLockoutPolicySpoolerRunTimestamp)
}
diff --git a/internal/management/repository/eventsourcing/handler/project.go b/internal/management/repository/eventsourcing/handler/project.go
index 0609d175e3..0536de9ae5 100644
--- a/internal/management/repository/eventsourcing/handler/project.go
+++ b/internal/management/repository/eventsourcing/handler/project.go
@@ -46,17 +46,21 @@ func (p *Project) Reduce(event *models.Event) (err error) {
}
err = project.AppendEvent(event)
case es_model.ProjectRemoved:
- return p.view.DeleteProject(event.AggregateID, event.Sequence)
+ return p.view.DeleteProject(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return p.view.ProcessedProjectSequence(event.Sequence)
+ return p.view.ProcessedProjectSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return p.view.PutProject(project)
+ return p.view.PutProject(project, event.CreationDate)
}
func (p *Project) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-dLsop3", "id", event.AggregateID).WithError(err).Warn("something went wrong in projecthandler")
return spooler.HandleError(event, err, p.view.GetLatestProjectFailedEvent, p.view.ProcessedProjectFailedEvent, p.view.ProcessedProjectSequence, p.errorCountUntilSkip)
}
+
+func (p *Project) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProjectSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/project_grant.go b/internal/management/repository/eventsourcing/handler/project_grant.go
index 3426c40022..1c7306bb21 100644
--- a/internal/management/repository/eventsourcing/handler/project_grant.go
+++ b/internal/management/repository/eventsourcing/handler/project_grant.go
@@ -2,6 +2,7 @@ package handler
import (
"context"
+ "time"
"github.com/caos/logging"
@@ -47,7 +48,7 @@ func (p *ProjectGrant) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.updateExistingProjects(project, event.Sequence)
+ return p.updateExistingProjects(project, event.Sequence, event.CreationDate)
case es_model.ProjectGrantAdded:
err = grantedProject.AppendEvent(event)
if err != nil {
@@ -85,16 +86,16 @@ func (p *ProjectGrant) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectGrant(grant.GrantID, event.Sequence)
+ return p.view.DeleteProjectGrant(grant.GrantID, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved:
return p.view.DeleteProjectGrantsByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectGrantSequence(event.Sequence)
+ return p.view.ProcessedProjectGrantSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return p.view.PutProjectGrant(grantedProject)
+ return p.view.PutProjectGrant(grantedProject, event.CreationDate)
}
func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, org, resourceOwner *org_model.Org) {
@@ -106,7 +107,7 @@ func (p *ProjectGrant) getProject(projectID string) (*proj_model.Project, error)
return p.projectEvents.ProjectByID(context.Background(), projectID)
}
-func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, sequence uint64) error {
+func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, sequence uint64, eventTimestamp time.Time) error {
projectGrants, err := p.view.ProjectGrantsByProjectID(project.ProjectID)
if err != nil {
logging.LogWithFields("SPOOL-los03", "id", project.ProjectID).WithError(err).Warn("could not update existing projects")
@@ -114,10 +115,14 @@ func (p *ProjectGrant) updateExistingProjects(project *view_model.ProjectView, s
for _, existingGrant := range projectGrants {
existingGrant.Name = project.Name
}
- return p.view.PutProjectGrants(projectGrants, sequence)
+ return p.view.PutProjectGrants(projectGrants, sequence, eventTimestamp)
}
func (p *ProjectGrant) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-sQqOg", "id", event.AggregateID).WithError(err).Warn("something went wrong in granted projecthandler")
return spooler.HandleError(event, err, p.view.GetLatestProjectGrantFailedEvent, p.view.ProcessedProjectGrantFailedEvent, p.view.ProcessedProjectGrantSequence, p.errorCountUntilSkip)
}
+
+func (p *ProjectGrant) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProjectGrantSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/project_grant_member.go b/internal/management/repository/eventsourcing/handler/project_grant_member.go
index a95d83c8c4..fb37af782e 100644
--- a/internal/management/repository/eventsourcing/handler/project_grant_member.go
+++ b/internal/management/repository/eventsourcing/handler/project_grant_member.go
@@ -72,16 +72,16 @@ func (p *ProjectGrantMember) processProjectGrantMember(event *models.Event) (err
if err != nil {
return err
}
- return p.view.DeleteProjectGrantMember(member.GrantID, member.UserID, event.Sequence)
+ return p.view.DeleteProjectGrantMember(member.GrantID, member.UserID, event.Sequence, event.CreationDate)
case proj_es_model.ProjectRemoved:
return p.view.DeleteProjectGrantMembersByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectGrantMemberSequence(event.Sequence)
+ return p.view.ProcessedProjectGrantMemberSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return p.view.PutProjectGrantMember(member, member.Sequence)
+ return p.view.PutProjectGrantMember(member, member.Sequence, event.CreationDate)
}
func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
@@ -96,7 +96,7 @@ func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return p.view.ProcessedProjectGrantMemberSequence(event.Sequence)
+ return p.view.ProcessedProjectGrantMemberSequence(event.Sequence, event.CreationDate)
}
user, err := p.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -105,9 +105,9 @@ func (p *ProjectGrantMember) processUser(event *models.Event) (err error) {
for _, member := range members {
p.fillUserData(member, user)
}
- return p.view.PutProjectGrantMembers(members, event.Sequence)
+ return p.view.PutProjectGrantMembers(members, event.Sequence, event.CreationDate)
default:
- return p.view.ProcessedProjectGrantMemberSequence(event.Sequence)
+ return p.view.ProcessedProjectGrantMemberSequence(event.Sequence, event.CreationDate)
}
return nil
}
@@ -138,3 +138,7 @@ func (p *ProjectGrantMember) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-kls93", "id", event.AggregateID).WithError(err).Warn("something went wrong in projectmember handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectGrantMemberFailedEvent, p.view.ProcessedProjectGrantMemberFailedEvent, p.view.ProcessedProjectGrantMemberSequence, p.errorCountUntilSkip)
}
+
+func (p *ProjectGrantMember) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProjectGrantMemberSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/project_member.go b/internal/management/repository/eventsourcing/handler/project_member.go
index f5df96d10b..7de3603f25 100644
--- a/internal/management/repository/eventsourcing/handler/project_member.go
+++ b/internal/management/repository/eventsourcing/handler/project_member.go
@@ -72,16 +72,16 @@ func (p *ProjectMember) processProjectMember(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectMember(event.AggregateID, member.UserID, event.Sequence)
+ return p.view.DeleteProjectMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
case proj_es_model.ProjectRemoved:
return p.view.DeleteProjectMembersByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectMemberSequence(event.Sequence)
+ return p.view.ProcessedProjectMemberSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return p.view.PutProjectMember(member, member.Sequence)
+ return p.view.PutProjectMember(member, member.Sequence, event.CreationDate)
}
func (p *ProjectMember) processUser(event *models.Event) (err error) {
@@ -96,7 +96,7 @@ func (p *ProjectMember) processUser(event *models.Event) (err error) {
return err
}
if len(members) == 0 {
- return p.view.ProcessedProjectMemberSequence(event.Sequence)
+ return p.view.ProcessedProjectMemberSequence(event.Sequence, event.CreationDate)
}
user, err := p.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -105,9 +105,9 @@ func (p *ProjectMember) processUser(event *models.Event) (err error) {
for _, member := range members {
p.fillUserData(member, user)
}
- return p.view.PutProjectMembers(members, event.Sequence)
+ return p.view.PutProjectMembers(members, event.Sequence, event.CreationDate)
default:
- return p.view.ProcessedProjectMemberSequence(event.Sequence)
+ return p.view.ProcessedProjectMemberSequence(event.Sequence, event.CreationDate)
}
return nil
}
@@ -137,3 +137,7 @@ func (p *ProjectMember) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-u73es", "id", event.AggregateID).WithError(err).Warn("something went wrong in projectmember handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectMemberFailedEvent, p.view.ProcessedProjectMemberFailedEvent, p.view.ProcessedProjectMemberSequence, p.errorCountUntilSkip)
}
+
+func (p *ProjectMember) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProjectMemberSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/project_role.go b/internal/management/repository/eventsourcing/handler/project_role.go
index 54ec1f81ea..0dba4b14e8 100644
--- a/internal/management/repository/eventsourcing/handler/project_role.go
+++ b/internal/management/repository/eventsourcing/handler/project_role.go
@@ -52,19 +52,23 @@ func (p *ProjectRole) Reduce(event *models.Event) (err error) {
if err != nil {
return err
}
- return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence)
+ return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved:
return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
default:
- return p.view.ProcessedProjectRoleSequence(event.Sequence)
+ return p.view.ProcessedProjectRoleSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return p.view.PutProjectRole(role)
+ return p.view.PutProjectRole(role, event.CreationDate)
}
func (p *ProjectRole) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
}
+
+func (p *ProjectRole) OnSuccess() error {
+ return spooler.HandleSuccess(p.view.UpdateProjectRoleSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/user.go b/internal/management/repository/eventsourcing/handler/user.go
index daf07e3f0c..0721e0fcd3 100644
--- a/internal/management/repository/eventsourcing/handler/user.go
+++ b/internal/management/repository/eventsourcing/handler/user.go
@@ -91,6 +91,12 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
es_model.HumanMFAOTPAdded,
es_model.HumanMFAOTPVerified,
es_model.HumanMFAOTPRemoved,
+ es_model.HumanMFAU2FTokenAdded,
+ es_model.HumanMFAU2FTokenVerified,
+ es_model.HumanMFAU2FTokenRemoved,
+ es_model.HumanPasswordlessTokenAdded,
+ es_model.HumanPasswordlessTokenVerified,
+ es_model.HumanPasswordlessTokenRemoved,
es_model.MachineChanged:
user, err = u.view.UserByID(event.AggregateID)
if err != nil {
@@ -109,14 +115,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
}
err = u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteUser(event.AggregateID, event.Sequence)
+ return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserSequence(event.Sequence)
+ return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return u.view.PutUser(user, user.Sequence)
+ return u.view.PutUser(user, user.Sequence, event.CreationDate)
}
func (u *User) ProcessOrg(event *models.Event) (err error) {
@@ -130,7 +136,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedUserSequence(event.Sequence)
+ return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
}
}
@@ -153,7 +159,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
}
- return u.view.PutUsers(users, event.Sequence)
+ return u.view.PutUsers(users, event.Sequence, event.CreationDate)
}
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -178,7 +184,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
}
- return u.view.PutUsers(users, event.Sequence)
+ return u.view.PutUsers(users, event.Sequence, event.CreationDate)
}
func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
@@ -202,3 +208,7 @@ func (u *User) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-is8wa", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip)
}
+
+func (u *User) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/user_external_idps.go b/internal/management/repository/eventsourcing/handler/user_external_idps.go
index cfcb8f4885..de57a8f0f2 100644
--- a/internal/management/repository/eventsourcing/handler/user_external_idps.go
+++ b/internal/management/repository/eventsourcing/handler/user_external_idps.go
@@ -30,12 +30,12 @@ const (
externalIDPTable = "management.user_external_idps"
)
-func (m *ExternalIDP) ViewModel() string {
+func (i *ExternalIDP) ViewModel() string {
return externalIDPTable
}
-func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
- sequence, err := m.view.GetLatestExternalIDPSequence()
+func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
+ sequence, err := i.view.GetLatestExternalIDPSequence()
if err != nil {
return nil, err
}
@@ -44,17 +44,17 @@ func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil
}
-func (m *ExternalIDP) Reduce(event *models.Event) (err error) {
+func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.UserAggregate:
- err = m.processUser(event)
+ err = i.processUser(event)
case iam_es_model.IAMAggregate, org_es_model.OrgAggregate:
- err = m.processIdpConfig(event)
+ err = i.processIdpConfig(event)
}
return err
}
-func (m *ExternalIDP) processUser(event *models.Event) (err error) {
+func (i *ExternalIDP) processUser(event *models.Event) (err error) {
externalIDP := new(usr_view_model.ExternalIDPView)
switch event.Type {
case model.HumanExternalIDPAdded:
@@ -62,25 +62,25 @@ func (m *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil {
return err
}
- err = m.fillData(externalIDP)
+ err = i.fillData(externalIDP)
case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved:
err = externalIDP.SetData(event)
if err != nil {
return err
}
- return m.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence)
+ return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
case model.UserRemoved:
- return m.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence)
+ return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedExternalIDPSequence(event.Sequence)
+ return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutExternalIDP(externalIDP, externalIDP.Sequence)
+ return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
}
-func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
+func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
switch event.Type {
case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged:
configView := new(iam_view_model.IDPConfigView)
@@ -90,45 +90,49 @@ func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
} else {
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
}
- exterinalIDPs, err := m.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
+ exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
if err != nil {
return err
}
if event.AggregateType == iam_es_model.IAMAggregate {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} else {
- config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
+ config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
}
if err != nil {
return err
}
for _, provider := range exterinalIDPs {
- m.fillConfigData(provider, config)
+ i.fillConfigData(provider, config)
}
- return m.view.PutExternalIDPs(event.Sequence, exterinalIDPs...)
+ return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
default:
- return m.view.ProcessedExternalIDPSequence(event.Sequence)
+ return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
}
return nil
}
-func (m *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
- config, err := m.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
+func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
+ config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
if caos_errs.IsNotFound(err) {
- config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, externalIDP.IDPConfigID)
+ config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID)
}
if err != nil {
return err
}
- m.fillConfigData(externalIDP, config)
+ i.fillConfigData(externalIDP, config)
return nil
}
-func (m *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
+func (i *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
externalIDP.IDPName = config.Name
}
-func (m *ExternalIDP) OnError(event *models.Event, err error) error {
+func (i *ExternalIDP) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
- return spooler.HandleError(event, err, m.view.GetLatestExternalIDPFailedEvent, m.view.ProcessedExternalIDPFailedEvent, m.view.ProcessedExternalIDPSequence, m.errorCountUntilSkip)
+ return spooler.HandleError(event, err, i.view.GetLatestExternalIDPFailedEvent, i.view.ProcessedExternalIDPFailedEvent, i.view.ProcessedExternalIDPSequence, i.errorCountUntilSkip)
+}
+
+func (i *ExternalIDP) OnSuccess() error {
+ return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
}
diff --git a/internal/management/repository/eventsourcing/handler/user_grant.go b/internal/management/repository/eventsourcing/handler/user_grant.go
index e95b153299..0ffe6955ac 100644
--- a/internal/management/repository/eventsourcing/handler/user_grant.go
+++ b/internal/management/repository/eventsourcing/handler/user_grant.go
@@ -79,14 +79,14 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
- return u.view.DeleteUserGrant(event.AggregateID, event.Sequence)
+ return u.view.DeleteUserGrant(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return u.view.PutUserGrant(grant, grant.Sequence)
+ return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
}
func (u *UserGrant) processUser(event *models.Event) (err error) {
@@ -101,7 +101,7 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
return err
}
if len(grants) == 0 {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
user, err := u.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil {
@@ -110,9 +110,9 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
for _, grant := range grants {
u.fillUserData(grant, user)
}
- return u.view.PutUserGrants(grants, event.Sequence)
+ return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
return nil
}
@@ -125,7 +125,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
return err
}
if len(grants) == 0 {
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
project, err := u.projectEvents.ProjectByID(context.Background(), event.AggregateID)
if err != nil {
@@ -134,9 +134,9 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
for _, grant := range grants {
u.fillProjectData(grant, project)
}
- return u.view.PutUserGrants(grants, event.Sequence)
+ return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedUserGrantSequence(event.Sequence)
+ return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
}
return nil
}
@@ -193,3 +193,7 @@ func (u *UserGrant) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-8is4s", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip)
}
+
+func (u *UserGrant) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/handler/user_membership.go b/internal/management/repository/eventsourcing/handler/user_membership.go
index af19ad9b81..8537905d47 100644
--- a/internal/management/repository/eventsourcing/handler/user_membership.go
+++ b/internal/management/repository/eventsourcing/handler/user_membership.go
@@ -73,14 +73,14 @@ func (m *UserMembership) processIam(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence)
+ return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
}
func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) {
@@ -103,16 +103,16 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence, event.CreationDate)
case org_es_model.OrgChanged:
return m.updateOrgDisplayName(event)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence)
+ return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
}
func (m *UserMembership) fillOrgDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@@ -137,7 +137,7 @@ func (m *UserMembership) updateOrgDisplayName(event *models.Event) error {
for _, membership := range memberships {
membership.DisplayName = org.Name
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence)
+ return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
}
func (m *UserMembership) processProject(event *models.Event) (err error) {
@@ -156,7 +156,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence, event.CreationDate)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
if err != nil {
@@ -164,20 +164,20 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
- return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
+ return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence, event.CreationDate)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)
case proj_es_model.ProjectRemoved:
- return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
+ return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
case proj_es_model.ProjectGrantRemoved:
- return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence)
+ return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return m.view.PutUserMembership(member, event.Sequence)
+ return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
}
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@@ -202,15 +202,15 @@ func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
for _, membership := range memberships {
membership.DisplayName = project.Name
}
- return m.view.BulkPutUserMemberships(memberships, event.Sequence)
+ return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
}
func (m *UserMembership) processUser(event *models.Event) (err error) {
switch event.Type {
case model.UserRemoved:
- return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence)
+ return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return m.view.ProcessedUserMembershipSequence(event.Sequence)
+ return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
}
}
@@ -218,3 +218,7 @@ func (m *UserMembership) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Fwer2", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler")
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
}
+
+func (m *UserMembership) OnSuccess() error {
+ return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp)
+}
diff --git a/internal/management/repository/eventsourcing/view/application.go b/internal/management/repository/eventsourcing/view/application.go
index 3d25e2d1d9..46672fc74a 100644
--- a/internal/management/repository/eventsourcing/view/application.go
+++ b/internal/management/repository/eventsourcing/view/application.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -23,28 +24,28 @@ func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest)
return view.SearchApplications(v.Db, applicationTable, request)
}
-func (v *View) PutApplication(app *model.ApplicationView) error {
+func (v *View) PutApplication(app *model.ApplicationView, eventTimestamp time.Time) error {
err := view.PutApplication(v.Db, applicationTable, app)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(app.Sequence)
+ return v.ProcessedApplicationSequence(app.Sequence, eventTimestamp)
}
-func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64) error {
+func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutApplications(v.Db, applicationTable, apps...)
if err != nil {
return err
}
- return v.ProcessedApplicationSequence(sequence)
+ return v.ProcessedApplicationSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
+func (v *View) DeleteApplication(appID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteApplication(v.Db, applicationTable, appID)
if err != nil {
return nil
}
- return v.ProcessedApplicationSequence(eventSequence)
+ return v.ProcessedApplicationSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
@@ -55,8 +56,12 @@ func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, erro
return v.latestSequence(applicationTable)
}
-func (v *View) ProcessedApplicationSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(applicationTable, eventSequence)
+func (v *View) ProcessedApplicationSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(applicationTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateApplicationSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(applicationTable)
}
func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/external_idps.go b/internal/management/repository/eventsourcing/view/external_idps.go
index e7f9f9fd0b..c2944c7a5f 100644
--- a/internal/management/repository/eventsourcing/view/external_idps.go
+++ b/internal/management/repository/eventsourcing/view/external_idps.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -32,45 +33,48 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
}
-func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64) error {
+func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence)
+ return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
}
-func (v *View) PutExternalIDPs(sequence uint64, externalIDPs ...*model.ExternalIDPView) error {
+func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(sequence)
+ return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64) error {
+func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence)
+ return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil {
return err
}
- return v.ProcessedExternalIDPSequence(eventSequence)
+ return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(externalIDPTable)
}
-func (v *View) ProcessedExternalIDPSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(externalIDPTable, eventSequence)
+func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
}
+func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(externalIDPTable)
+}
func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(externalIDPTable, sequence)
}
diff --git a/internal/management/repository/eventsourcing/view/idp_configs.go b/internal/management/repository/eventsourcing/view/idp_configs.go
index 6a53e228de..a9dfde45da 100644
--- a/internal/management/repository/eventsourcing/view/idp_configs.go
+++ b/internal/management/repository/eventsourcing/view/idp_configs.go
@@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -20,28 +21,32 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*i
return view.SearchIDPs(v.Db, idpConfigTable, request)
}
-func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, sequence uint64) error {
+func (v *View) PutIDPConfig(idp *iam_es_model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil {
return err
}
- return v.ProcessedIDPConfigSequence(sequence)
+ return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64) error {
+func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIDPConfigSequence(eventSequence)
+ return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpConfigTable)
}
-func (v *View) ProcessedIDPConfigSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(idpConfigTable, eventSequence)
+func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(idpConfigTable)
}
func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/idp_providers.go b/internal/management/repository/eventsourcing/view/idp_providers.go
index def9aa78ca..207feb621f 100644
--- a/internal/management/repository/eventsourcing/view/idp_providers.go
+++ b/internal/management/repository/eventsourcing/view/idp_providers.go
@@ -6,68 +6,73 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
idpProviderTable = "management.idp_providers"
)
-func (v *View) IdpProviderByAggregateAndIdpConfigID(aggregateID, idpConfigID string) (*model.IDPProviderView, error) {
+func (v *View) IDPProviderByAggregateAndIdpConfigID(aggregateID, idpConfigID string) (*model.IDPProviderView, error) {
return view.GetIDPProviderByAggregateIDAndConfigID(v.Db, idpProviderTable, aggregateID, idpConfigID)
}
-func (v *View) IdpProvidersByIdpConfigID(aggregateID, idpConfigID string) ([]*model.IDPProviderView, error) {
+func (v *View) IDPProvidersByIdpConfigID(aggregateID, idpConfigID string) ([]*model.IDPProviderView, error) {
return view.IDPProvidersByIdpConfigID(v.Db, idpProviderTable, idpConfigID)
}
-func (v *View) SearchIdpProviders(request *iam_model.IDPProviderSearchRequest) ([]*model.IDPProviderView, uint64, error) {
+func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) ([]*model.IDPProviderView, uint64, error) {
return view.SearchIDPProviders(v.Db, idpProviderTable, request)
}
-func (v *View) PutIdpProvider(provider *model.IDPProviderView, sequence uint64) error {
+func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil {
return err
}
- return v.ProcessedIdpProviderSequence(sequence)
+ return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
}
-func (v *View) PutIdpProviders(sequence uint64, providers ...*model.IDPProviderView) error {
+func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil {
return err
}
- return v.ProcessedIdpProviderSequence(sequence)
+ return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteIdpProvider(aggregateID, idpConfigID string, eventSequence uint64) error {
+func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIdpProviderSequence(eventSequence)
+ return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteIdpProvidersByAggregateID(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteIDPProvidersByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDPProvidersByAggregateID(v.Db, idpProviderTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedIdpProviderSequence(eventSequence)
+ return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
}
-func (v *View) GetLatestIdpProviderSequence() (*global_view.CurrentSequence, error) {
+func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpProviderTable)
}
-func (v *View) ProcessedIdpProviderSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(idpProviderTable, eventSequence)
+func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
}
-func (v *View) GetLatestIdpProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
+func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(idpProviderTable)
+}
+
+func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(idpProviderTable, sequence)
}
-func (v *View) ProcessedIdpProviderFailedEvent(failedEvent *global_view.FailedEvent) error {
+func (v *View) ProcessedIDPProviderFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}
diff --git a/internal/management/repository/eventsourcing/view/label_policies.go b/internal/management/repository/eventsourcing/view/label_policies.go
index 182ca4f368..27b234fc29 100644
--- a/internal/management/repository/eventsourcing/view/label_policies.go
+++ b/internal/management/repository/eventsourcing/view/label_policies.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyV
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
}
-func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64) error {
+func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLabelPolicySequence(sequence)
+ return v.ProcessedLabelPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteLabelPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteLabelPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteLabelPolicy(v.Db, labelPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLabelPolicySequence(eventSequence)
+ return v.ProcessedLabelPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(labelPolicyTable)
}
-func (v *View) ProcessedLabelPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(labelPolicyTable, eventSequence)
+func (v *View) ProcessedLabelPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(labelPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateLabelPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(labelPolicyTable)
}
func (v *View) GetLatestLabelPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/login_policies.go b/internal/management/repository/eventsourcing/view/login_policies.go
index 741dbc9322..c37f4283d6 100644
--- a/internal/management/repository/eventsourcing/view/login_policies.go
+++ b/internal/management/repository/eventsourcing/view/login_policies.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
}
-func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64) error {
+func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedLoginPolicySequence(sequence)
+ return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedLoginPolicySequence(eventSequence)
+ return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(loginPolicyTable)
}
-func (v *View) ProcessedLoginPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(loginPolicyTable, eventSequence)
+func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(loginPolicyTable)
}
func (v *View) GetLatestLoginPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/machine_keys.go b/internal/management/repository/eventsourcing/view/machine_keys.go
index 013183cc64..b037137c82 100644
--- a/internal/management/repository/eventsourcing/view/machine_keys.go
+++ b/internal/management/repository/eventsourcing/view/machine_keys.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -23,39 +24,43 @@ func (v *View) SearchMachineKeys(request *usr_model.MachineKeySearchRequest) ([]
return view.SearchMachineKeys(v.Db, machineKeyTable, request)
}
-func (v *View) PutMachineKey(org *model.MachineKeyView, sequence uint64) error {
+func (v *View) PutMachineKey(org *model.MachineKeyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutMachineKey(v.Db, machineKeyTable, org)
if err != nil {
return err
}
if sequence != 0 {
- return v.ProcessedMachineKeySequence(sequence)
+ return v.ProcessedMachineKeySequence(sequence, eventTimestamp)
}
return nil
}
-func (v *View) DeleteMachineKey(keyID string, eventSequence uint64) error {
+func (v *View) DeleteMachineKey(keyID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, keyID)
if err != nil {
return nil
}
- return v.ProcessedMachineKeySequence(eventSequence)
+ return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteMachineKeysByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteMachineKeysByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteMachineKey(v.Db, machineKeyTable, userID)
if err != nil {
return nil
}
- return v.ProcessedMachineKeySequence(eventSequence)
+ return v.ProcessedMachineKeySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestMachineKeySequence() (*repository.CurrentSequence, error) {
return v.latestSequence(machineKeyTable)
}
-func (v *View) ProcessedMachineKeySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(machineKeyTable, eventSequence)
+func (v *View) ProcessedMachineKeySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(machineKeyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateMachineKeySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(machineKeyTable)
}
func (v *View) GetLatestMachineKeyFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/org.go b/internal/management/repository/eventsourcing/view/org.go
index 80b35435b2..a5de5fdb46 100644
--- a/internal/management/repository/eventsourcing/view/org.go
+++ b/internal/management/repository/eventsourcing/view/org.go
@@ -4,6 +4,7 @@ import (
org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -14,12 +15,12 @@ func (v *View) OrgByID(orgID string) (*model.OrgView, error) {
return org_view.OrgByID(v.Db, orgTable, orgID)
}
-func (v *View) PutOrg(org *model.OrgView) error {
+func (v *View) PutOrg(org *model.OrgView, eventTimestamp time.Time) error {
err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil {
return err
}
- return v.ProcessedOrgSequence(org.Sequence)
+ return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
}
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@@ -30,10 +31,14 @@ func (v *View) ProcessedOrgFailedEvent(failedEvent *repository.FailedEvent) erro
return v.saveFailedEvent(failedEvent)
}
+func (v *View) UpdateOrgSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgTable)
+}
+
func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgTable)
}
-func (v *View) ProcessedOrgSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgTable, eventSequence)
+func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
}
diff --git a/internal/management/repository/eventsourcing/view/org_domain.go b/internal/management/repository/eventsourcing/view/org_domain.go
index 474a481d43..94f3f84c95 100644
--- a/internal/management/repository/eventsourcing/view/org_domain.go
+++ b/internal/management/repository/eventsourcing/view/org_domain.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -27,39 +28,43 @@ func (v *View) SearchOrgDomains(request *org_model.OrgDomainSearchRequest) ([]*m
return view.SearchOrgDomains(v.Db, orgDomainTable, request)
}
-func (v *View) PutOrgDomain(org *model.OrgDomainView, sequence uint64) error {
+func (v *View) PutOrgDomain(org *model.OrgDomainView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgDomain(v.Db, orgDomainTable, org)
if err != nil {
return err
}
if sequence != 0 {
- return v.ProcessedOrgDomainSequence(sequence)
+ return v.ProcessedOrgDomainSequence(sequence, eventTimestamp)
}
return nil
}
-func (v *View) PutOrgDomains(domains []*model.OrgDomainView, sequence uint64) error {
+func (v *View) PutOrgDomains(domains []*model.OrgDomainView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgDomains(v.Db, orgDomainTable, domains...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteOrgDomain(orgID, domain string, eventSequence uint64) error {
+func (v *View) DeleteOrgDomain(orgID, domain string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgDomain(v.Db, orgDomainTable, orgID, domain)
if err != nil {
return nil
}
- return v.ProcessedOrgDomainSequence(eventSequence)
+ return v.ProcessedOrgDomainSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestOrgDomainSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgDomainTable)
}
-func (v *View) ProcessedOrgDomainSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgDomainTable, eventSequence)
+func (v *View) ProcessedOrgDomainSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgDomainTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateOrgDomainSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgDomainTable)
}
func (v *View) GetLatestOrgDomainFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/org_iam_policy.go b/internal/management/repository/eventsourcing/view/org_iam_policy.go
index 81cb67c4ac..db9d113155 100644
--- a/internal/management/repository/eventsourcing/view/org_iam_policy.go
+++ b/internal/management/repository/eventsourcing/view/org_iam_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
}
-func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64) error {
+func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedOrgIAMPolicySequence(sequence)
+ return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedOrgIAMPolicySequence(eventSequence)
+ return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(orgIAMPolicyTable)
}
-func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence)
+func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgIAMPolicyTable)
}
func (v *View) GetLatestOrgIAMPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/org_member.go b/internal/management/repository/eventsourcing/view/org_member.go
index c4396d5a50..d1cb20b3c0 100644
--- a/internal/management/repository/eventsourcing/view/org_member.go
+++ b/internal/management/repository/eventsourcing/view/org_member.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -23,44 +24,48 @@ func (v *View) OrgMembersByUserID(userID string) ([]*model.OrgMemberView, error)
return view.OrgMembersByUserID(v.Db, orgMemberTable, userID)
}
-func (v *View) PutOrgMember(member *model.OrgMemberView, sequence uint64) error {
+func (v *View) PutOrgMember(member *model.OrgMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgMember(v.Db, orgMemberTable, member)
if err != nil {
return err
}
- return v.ProcessedOrgMemberSequence(sequence)
+ return v.ProcessedOrgMemberSequence(sequence, eventTimestamp)
}
-func (v *View) PutOrgMembers(members []*model.OrgMemberView, sequence uint64) error {
+func (v *View) PutOrgMembers(members []*model.OrgMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgMembers(v.Db, orgMemberTable, members...)
if err != nil {
return err
}
- return v.ProcessedOrgMemberSequence(sequence)
+ return v.ProcessedOrgMemberSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteOrgMember(orgID, userID string, eventSequence uint64) error {
+func (v *View) DeleteOrgMember(orgID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgMember(v.Db, orgMemberTable, orgID, userID)
if err != nil {
return nil
}
- return v.ProcessedOrgMemberSequence(eventSequence)
+ return v.ProcessedOrgMemberSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteOrgMembersByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteOrgMembersByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgMembersByUserID(v.Db, orgMemberTable, userID)
if err != nil {
return nil
}
- return v.ProcessedOrgMemberSequence(eventSequence)
+ return v.ProcessedOrgMemberSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestOrgMemberSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgMemberTable)
}
-func (v *View) ProcessedOrgMemberSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(orgMemberTable, eventSequence)
+func (v *View) ProcessedOrgMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(orgMemberTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateOrgMemberSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(orgMemberTable)
}
func (v *View) GetLatestOrgMemberFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/password_age_policy.go b/internal/management/repository/eventsourcing/view/password_age_policy.go
index 3d6caaa8a1..e37d650072 100644
--- a/internal/management/repository/eventsourcing/view/password_age_policy.go
+++ b/internal/management/repository/eventsourcing/view/password_age_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordAgePolicyByAggregateID(aggregateID string) (*model.Passwo
return view.GetPasswordAgePolicyByAggregateID(v.Db, passwordAgePolicyTable, aggregateID)
}
-func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64) error {
+func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordAgePolicy(v.Db, passwordAgePolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordAgePolicySequence(sequence)
+ return v.ProcessedPasswordAgePolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordAgePolicy(v.Db, passwordAgePolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordAgePolicySequence(eventSequence)
+ return v.ProcessedPasswordAgePolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordAgePolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordAgePolicyTable)
}
-func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence)
+func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdatePasswordAgePolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordAgePolicyTable)
}
func (v *View) GetLatestPasswordAgePolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/password_complexity_policy.go b/internal/management/repository/eventsourcing/view/password_complexity_policy.go
index 040eb1d596..70895d13a9 100644
--- a/internal/management/repository/eventsourcing/view/password_complexity_policy.go
+++ b/internal/management/repository/eventsourcing/view/password_complexity_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
}
-func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64) error {
+func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(sequence)
+ return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordComplexityPolicySequence(eventSequence)
+ return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordComplexityPolicyTable)
}
-func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence)
+func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordComplexityPolicyTable)
}
func (v *View) GetLatestPasswordComplexityPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/password_lockout_policy.go b/internal/management/repository/eventsourcing/view/password_lockout_policy.go
index 099b961f57..11e3955720 100644
--- a/internal/management/repository/eventsourcing/view/password_lockout_policy.go
+++ b/internal/management/repository/eventsourcing/view/password_lockout_policy.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -15,28 +16,32 @@ func (v *View) PasswordLockoutPolicyByAggregateID(aggregateID string) (*model.Pa
return view.GetPasswordLockoutPolicyByAggregateID(v.Db, passwordLockoutPolicyTable, aggregateID)
}
-func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64) error {
+func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, policy)
if err != nil {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(sequence)
+ return v.ProcessedPasswordLockoutPolicySequence(sequence, eventTimestamp)
}
-func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64) error {
+func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
- return v.ProcessedPasswordLockoutPolicySequence(eventSequence)
+ return v.ProcessedPasswordLockoutPolicySequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestPasswordLockoutPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordLockoutPolicyTable)
}
-func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64) error {
- return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence)
+func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdatePasswordLockoutPolicySpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(passwordLockoutPolicyTable)
}
func (v *View) GetLatestPasswordLockoutPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/project.go b/internal/management/repository/eventsourcing/view/project.go
index f0f5c7d882..fede8830ee 100644
--- a/internal/management/repository/eventsourcing/view/project.go
+++ b/internal/management/repository/eventsourcing/view/project.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -19,28 +20,32 @@ func (v *View) SearchProjects(request *proj_model.ProjectViewSearchRequest) ([]*
return view.SearchProjects(v.Db, projectTable, request)
}
-func (v *View) PutProject(project *model.ProjectView) error {
+func (v *View) PutProject(project *model.ProjectView, eventTimestamp time.Time) error {
err := view.PutProject(v.Db, projectTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectSequence(project.Sequence)
+ return v.ProcessedProjectSequence(project.Sequence, eventTimestamp)
}
-func (v *View) DeleteProject(projectID string, eventSequence uint64) error {
+func (v *View) DeleteProject(projectID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteProject(v.Db, projectTable, projectID)
if err != nil {
return nil
}
- return v.ProcessedProjectSequence(eventSequence)
+ return v.ProcessedProjectSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestProjectSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(projectTable)
}
-func (v *View) ProcessedProjectSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(projectTable, eventSequence)
+func (v *View) ProcessedProjectSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(projectTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProjectSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(projectTable)
}
func (v *View) GetLatestProjectFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/project_grant.go b/internal/management/repository/eventsourcing/view/project_grant.go
index f0cdd3330a..64f1f6272e 100644
--- a/internal/management/repository/eventsourcing/view/project_grant.go
+++ b/internal/management/repository/eventsourcing/view/project_grant.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -31,28 +32,28 @@ func (v *View) SearchProjectGrants(request *proj_model.ProjectGrantViewSearchReq
return view.SearchProjectGrants(v.Db, grantedProjectTable, request)
}
-func (v *View) PutProjectGrant(grant *model.ProjectGrantView) error {
+func (v *View) PutProjectGrant(grant *model.ProjectGrantView, eventTimestamp time.Time) error {
err := view.PutProjectGrant(v.Db, grantedProjectTable, grant)
if err != nil {
return err
}
- return v.ProcessedProjectGrantSequence(grant.Sequence)
+ return v.ProcessedProjectGrantSequence(grant.Sequence, eventTimestamp)
}
-func (v *View) PutProjectGrants(grants []*model.ProjectGrantView, sequence uint64) error {
+func (v *View) PutProjectGrants(grants []*model.ProjectGrantView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutProjectGrants(v.Db, grantedProjectTable, grants...)
if err != nil {
return err
}
- return v.ProcessedProjectGrantSequence(sequence)
+ return v.ProcessedProjectGrantSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteProjectGrant(grantID string, eventSequence uint64) error {
+func (v *View) DeleteProjectGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteProjectGrant(v.Db, grantedProjectTable, grantID)
if err != nil {
return err
}
- return v.ProcessedProjectGrantSequence(eventSequence)
+ return v.ProcessedProjectGrantSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteProjectGrantsByProjectID(projectID string) error {
@@ -63,8 +64,12 @@ func (v *View) GetLatestProjectGrantSequence() (*repository.CurrentSequence, err
return v.latestSequence(grantedProjectTable)
}
-func (v *View) ProcessedProjectGrantSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(grantedProjectTable, eventSequence)
+func (v *View) ProcessedProjectGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(grantedProjectTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProjectGrantSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(grantedProjectTable)
}
func (v *View) GetLatestProjectGrantFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/project_grant_member.go b/internal/management/repository/eventsourcing/view/project_grant_member.go
index 39e9521a77..b9cf4391ba 100644
--- a/internal/management/repository/eventsourcing/view/project_grant_member.go
+++ b/internal/management/repository/eventsourcing/view/project_grant_member.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -27,28 +28,28 @@ func (v *View) ProjectGrantMembersByUserID(userID string) ([]*model.ProjectGrant
return view.ProjectGrantMembersByUserID(v.Db, projectGrantMemberTable, userID)
}
-func (v *View) PutProjectGrantMember(member *model.ProjectGrantMemberView, sequence uint64) error {
+func (v *View) PutProjectGrantMember(member *model.ProjectGrantMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutProjectGrantMember(v.Db, projectGrantMemberTable, member)
if err != nil {
return err
}
- return v.ProcessedProjectGrantMemberSequence(sequence)
+ return v.ProcessedProjectGrantMemberSequence(sequence, eventTimestamp)
}
-func (v *View) PutProjectGrantMembers(members []*model.ProjectGrantMemberView, sequence uint64) error {
+func (v *View) PutProjectGrantMembers(members []*model.ProjectGrantMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutProjectGrantMembers(v.Db, projectGrantMemberTable, members...)
if err != nil {
return err
}
- return v.ProcessedProjectGrantMemberSequence(sequence)
+ return v.ProcessedProjectGrantMemberSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteProjectGrantMember(grantID, userID string, eventSequence uint64) error {
+func (v *View) DeleteProjectGrantMember(grantID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteProjectGrantMember(v.Db, projectGrantMemberTable, grantID, userID)
if err != nil {
return nil
}
- return v.ProcessedProjectGrantMemberSequence(eventSequence)
+ return v.ProcessedProjectGrantMemberSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteProjectGrantMembersByProjectID(projectID string) error {
@@ -59,8 +60,12 @@ func (v *View) GetLatestProjectGrantMemberSequence() (*repository.CurrentSequenc
return v.latestSequence(projectGrantMemberTable)
}
-func (v *View) ProcessedProjectGrantMemberSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(projectGrantMemberTable, eventSequence)
+func (v *View) ProcessedProjectGrantMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(projectGrantMemberTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProjectGrantMemberSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(projectGrantMemberTable)
}
func (v *View) GetLatestProjectGrantMemberFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/project_member.go b/internal/management/repository/eventsourcing/view/project_member.go
index 717d827d7b..c21dee73e2 100644
--- a/internal/management/repository/eventsourcing/view/project_member.go
+++ b/internal/management/repository/eventsourcing/view/project_member.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -27,28 +28,28 @@ func (v *View) ProjectMembersByUserID(userID string) ([]*model.ProjectMemberView
return view.ProjectMembersByUserID(v.Db, projectMemberTable, userID)
}
-func (v *View) PutProjectMember(project *model.ProjectMemberView, sequence uint64) error {
+func (v *View) PutProjectMember(project *model.ProjectMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutProjectMember(v.Db, projectMemberTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectMemberSequence(sequence)
+ return v.ProcessedProjectMemberSequence(sequence, eventTimestamp)
}
-func (v *View) PutProjectMembers(project []*model.ProjectMemberView, sequence uint64) error {
+func (v *View) PutProjectMembers(project []*model.ProjectMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutProjectMembers(v.Db, projectMemberTable, project...)
if err != nil {
return err
}
- return v.ProcessedProjectMemberSequence(sequence)
+ return v.ProcessedProjectMemberSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteProjectMember(projectID, userID string, eventSequence uint64) error {
+func (v *View) DeleteProjectMember(projectID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteProjectMember(v.Db, projectMemberTable, projectID, userID)
if err != nil {
return nil
}
- return v.ProcessedProjectMemberSequence(eventSequence)
+ return v.ProcessedProjectMemberSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteProjectMembersByProjectID(projectID string) error {
@@ -59,8 +60,12 @@ func (v *View) GetLatestProjectMemberSequence() (*repository.CurrentSequence, er
return v.latestSequence(projectMemberTable)
}
-func (v *View) ProcessedProjectMemberSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(projectMemberTable, eventSequence)
+func (v *View) ProcessedProjectMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(projectMemberTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProjectMemberSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(projectMemberTable)
}
func (v *View) GetLatestProjectMemberFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/project_role.go b/internal/management/repository/eventsourcing/view/project_role.go
index b8276471ed..6703a93efd 100644
--- a/internal/management/repository/eventsourcing/view/project_role.go
+++ b/internal/management/repository/eventsourcing/view/project_role.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -31,20 +32,20 @@ func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest)
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
}
-func (v *View) PutProjectRole(project *model.ProjectRoleView) error {
+func (v *View) PutProjectRole(project *model.ProjectRoleView, eventTimestamp time.Time) error {
err := view.PutProjectRole(v.Db, projectRoleTable, project)
if err != nil {
return err
}
- return v.ProcessedProjectRoleSequence(project.Sequence)
+ return v.ProcessedProjectRoleSequence(project.Sequence, eventTimestamp)
}
-func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64) error {
+func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteProjectRole(v.Db, projectRoleTable, projectID, orgID, key)
if err != nil {
return nil
}
- return v.ProcessedProjectRoleSequence(eventSequence)
+ return v.ProcessedProjectRoleSequence(eventSequence, eventTimestamp)
}
func (v *View) DeleteProjectRolesByProjectID(projectID string) error {
@@ -55,8 +56,12 @@ func (v *View) GetLatestProjectRoleSequence() (*repository.CurrentSequence, erro
return v.latestSequence(projectRoleTable)
}
-func (v *View) ProcessedProjectRoleSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(projectRoleTable, eventSequence)
+func (v *View) ProcessedProjectRoleSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(projectRoleTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateProjectRoleSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(projectRoleTable)
}
func (v *View) GetLatestProjectRoleFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/sequence.go b/internal/management/repository/eventsourcing/view/sequence.go
index 40d5338540..82354c98e4 100644
--- a/internal/management/repository/eventsourcing/view/sequence.go
+++ b/internal/management/repository/eventsourcing/view/sequence.go
@@ -2,16 +2,29 @@ package view
import (
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
sequencesTable = "management.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence)
+func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
}
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
return repository.LatestSequence(v.Db, sequencesTable, viewName)
}
+
+func (v *View) updateSpoolerRunSequence(viewName string) error {
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ if err != nil {
+ return err
+ }
+ if currentSequence.ViewName == "" {
+ currentSequence.ViewName = viewName
+ }
+ currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
+}
diff --git a/internal/management/repository/eventsourcing/view/user.go b/internal/management/repository/eventsourcing/view/user.go
index acc327a3cd..69fc14a270 100644
--- a/internal/management/repository/eventsourcing/view/user.go
+++ b/internal/management/repository/eventsourcing/view/user.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -35,43 +36,47 @@ func (v *View) IsUserUnique(userName, email string) (bool, error) {
return view.IsUserUnique(v.Db, userTable, userName, email)
}
-func (v *View) UserMfas(userID string) ([]*usr_model.MultiFactor, error) {
- return view.UserMfas(v.Db, userTable, userID)
+func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
+ return view.UserMFAs(v.Db, userTable, userID)
}
-func (v *View) PutUsers(user []*model.UserView, sequence uint64) error {
+func (v *View) PutUsers(user []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUsers(v.Db, userTable, user...)
if err != nil {
return err
}
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
-func (v *View) PutUser(user *model.UserView, sequence uint64) error {
+func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUser(v.Db, userTable, user)
if err != nil {
return err
}
if sequence != 0 {
- return v.ProcessedUserSequence(sequence)
+ return v.ProcessedUserSequence(sequence, eventTimestamp)
}
return nil
}
-func (v *View) DeleteUser(userID string, eventSequence uint64) error {
+func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUser(v.Db, userTable, userID)
if err != nil {
return nil
}
- return v.ProcessedUserSequence(eventSequence)
+ return v.ProcessedUserSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userTable)
}
-func (v *View) ProcessedUserSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userTable, eventSequence)
+func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userTable)
}
func (v *View) GetLatestUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/user_grant.go b/internal/management/repository/eventsourcing/view/user_grant.go
index 29e3a2d33a..209fbfe6f4 100644
--- a/internal/management/repository/eventsourcing/view/user_grant.go
+++ b/internal/management/repository/eventsourcing/view/user_grant.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/usergrant/repository/view"
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -39,36 +40,40 @@ func (v *View) UserGrantsByOrgIDAndProjectID(orgID, projectID string) ([]*model.
return view.UserGrantsByOrgIDAndProjectID(v.Db, userGrantTable, orgID, projectID)
}
-func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error {
+func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence)
+ return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
}
-func (v *View) PutUserGrants(grants []*model.UserGrantView, sequence uint64) error {
+func (v *View) PutUserGrants(grants []*model.UserGrantView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserGrants(v.Db, userGrantTable, grants...)
if err != nil {
return err
}
- return v.ProcessedUserGrantSequence(sequence)
+ return v.ProcessedUserGrantSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error {
+func (v *View) DeleteUserGrant(grantID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserGrant(v.Db, userGrantTable, grantID)
if err != nil {
return nil
}
- return v.ProcessedUserGrantSequence(eventSequence)
+ return v.ProcessedUserGrantSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserGrantSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userGrantTable)
}
-func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userGrantTable, eventSequence)
+func (v *View) ProcessedUserGrantSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userGrantTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserGrantSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userGrantTable)
}
func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/eventsourcing/view/user_membership.go b/internal/management/repository/eventsourcing/view/user_membership.go
index 8188437187..4c733dc875 100644
--- a/internal/management/repository/eventsourcing/view/user_membership.go
+++ b/internal/management/repository/eventsourcing/view/user_membership.go
@@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -23,60 +24,64 @@ func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequ
return view.SearchUserMemberships(v.Db, userMembershipTable, request)
}
-func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64) error {
+func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserMembership(v.Db, userMembershipTable, membership)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence)
+ return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
}
-func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
+func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
if err != nil {
return err
}
- return v.ProcessedUserMembershipSequence(sequence)
+ return v.ProcessedUserMembershipSequence(sequence, eventTimestamp)
}
-func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64) error {
+func (v *View) DeleteUserMembership(userID, aggregateID, objectID string, memberType usr_model.MemberType, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembership(v.Db, userMembershipTable, userID, aggregateID, objectID, memberType)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserMembershipsByUserID(userID string, eventSequence uint64) error {
+func (v *View) DeleteUserMembershipsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembershipsByUserID(v.Db, userMembershipTable, userID)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, eventSequence uint64) error {
+func (v *View) DeleteUserMembershipsByAggregateID(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
-func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, eventSequence uint64) error {
+func (v *View) DeleteUserMembershipsByAggregateIDAndObjectID(aggregateID, objectID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUserMembershipsByAggregateIDAndObjectID(v.Db, userMembershipTable, aggregateID, objectID)
if err != nil {
return nil
}
- return v.ProcessedUserMembershipSequence(eventSequence)
+ return v.ProcessedUserMembershipSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestUserMembershipSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userMembershipTable)
}
-func (v *View) ProcessedUserMembershipSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(userMembershipTable, eventSequence)
+func (v *View) ProcessedUserMembershipSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(userMembershipTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateUserMembershipSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(userMembershipTable)
}
func (v *View) GetLatestUserMembershipFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/management/repository/user.go b/internal/management/repository/user.go
index ae035368e7..92a2364c11 100644
--- a/internal/management/repository/user.go
+++ b/internal/management/repository/user.go
@@ -30,7 +30,7 @@ type UserRepository interface {
ProfileByID(ctx context.Context, userID string) (*model.Profile, error)
ChangeProfile(ctx context.Context, profile *model.Profile) (*model.Profile, error)
- UserMfas(ctx context.Context, userID string) ([]*model.MultiFactor, error)
+ UserMFAs(ctx context.Context, userID string) ([]*model.MultiFactor, error)
RemoveOTP(ctx context.Context, userID string) error
SearchExternalIDPs(ctx context.Context, request *model.ExternalIDPSearchRequest) (*model.ExternalIDPSearchResponse, error)
diff --git a/internal/notification/repository/eventsourcing/handler/notification.go b/internal/notification/repository/eventsourcing/handler/notification.go
index e591b2fd15..96ff4ae9ce 100644
--- a/internal/notification/repository/eventsourcing/handler/notification.go
+++ b/internal/notification/repository/eventsourcing/handler/notification.go
@@ -71,12 +71,12 @@ func (n *Notification) Reduce(event *models.Event) (err error) {
case es_model.DomainClaimed:
err = n.handleDomainClaimed(event)
default:
- return n.view.ProcessedNotificationSequence(event.Sequence)
+ return n.view.ProcessedNotificationSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return n.view.ProcessedNotificationSequence(event.Sequence)
+ return n.view.ProcessedNotificationSequence(event.Sequence, event.CreationDate)
}
func (n *Notification) handleInitUserCode(event *models.Event) (err error) {
@@ -242,6 +242,10 @@ func (n *Notification) OnError(event *models.Event, err error) error {
return spooler.HandleError(event, err, n.view.GetLatestNotificationFailedEvent, n.view.ProcessedNotificationFailedEvent, n.view.ProcessedNotificationSequence, n.errorCountUntilSkip)
}
+func (n *Notification) OnSuccess() error {
+ return spooler.HandleSuccess(n.view.UpdateNotificationSpoolerRunTimestamp)
+}
+
func getSetNotifyContextData(orgID string) context.Context {
return authz.SetCtxData(context.Background(), authz.CtxData{UserID: NotifyUserID, OrgID: orgID})
}
diff --git a/internal/notification/repository/eventsourcing/handler/notify_user.go b/internal/notification/repository/eventsourcing/handler/notify_user.go
index e05e624d39..b41cd93ce7 100644
--- a/internal/notification/repository/eventsourcing/handler/notify_user.go
+++ b/internal/notification/repository/eventsourcing/handler/notify_user.go
@@ -93,14 +93,14 @@ func (u *NotifyUser) ProcessUser(event *models.Event) (err error) {
}
u.fillLoginNames(user)
case es_model.UserRemoved:
- return u.view.DeleteNotifyUser(event.AggregateID, event.Sequence)
+ return u.view.DeleteNotifyUser(event.AggregateID, event.Sequence, event.CreationDate)
default:
- return u.view.ProcessedNotifyUserSequence(event.Sequence)
+ return u.view.ProcessedNotifyUserSequence(event.Sequence, event.CreationDate)
}
if err != nil {
return err
}
- return u.view.PutNotifyUser(user, user.Sequence)
+ return u.view.PutNotifyUser(user, user.Sequence, event.CreationDate)
}
func (u *NotifyUser) ProcessOrg(event *models.Event) (err error) {
@@ -114,7 +114,7 @@ func (u *NotifyUser) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event)
default:
- return u.view.ProcessedNotifyUserSequence(event.Sequence)
+ return u.view.ProcessedNotifyUserSequence(event.Sequence, event.CreationDate)
}
}
@@ -136,12 +136,12 @@ func (u *NotifyUser) fillLoginNamesOnOrgUsers(event *models.Event) error {
}
for _, user := range users {
user.SetLoginNames(policy, org.Domains)
- err := u.view.PutNotifyUser(user, 0)
+ err := u.view.PutNotifyUser(user, 0, event.CreationDate)
if err != nil {
return err
}
}
- return u.view.ProcessedNotifyUserSequence(event.Sequence)
+ return u.view.ProcessedNotifyUserSequence(event.Sequence, event.CreationDate)
}
func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@@ -165,7 +165,7 @@ func (u *NotifyUser) fillPreferredLoginNamesOnOrgUsers(event *models.Event) erro
}
for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
- err := u.view.PutNotifyUser(user, 0)
+ err := u.view.PutNotifyUser(user, 0, event.CreationDate)
if err != nil {
return err
}
@@ -194,3 +194,7 @@ func (p *NotifyUser) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-9spwf", "id", event.AggregateID).WithError(err).Warn("something went wrong in notify user handler")
return spooler.HandleError(event, err, p.view.GetLatestNotifyUserFailedEvent, p.view.ProcessedNotifyUserFailedEvent, p.view.ProcessedNotifyUserSequence, p.errorCountUntilSkip)
}
+
+func (u *NotifyUser) OnSuccess() error {
+ return spooler.HandleSuccess(u.view.UpdateNotifyUserSpoolerRunTimestamp)
+}
diff --git a/internal/notification/repository/eventsourcing/view/notification.go b/internal/notification/repository/eventsourcing/view/notification.go
index e44d019ab1..baeb75e162 100644
--- a/internal/notification/repository/eventsourcing/view/notification.go
+++ b/internal/notification/repository/eventsourcing/view/notification.go
@@ -2,6 +2,7 @@ package view
import (
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -12,8 +13,12 @@ func (v *View) GetLatestNotificationSequence() (*repository.CurrentSequence, err
return v.latestSequence(notificationTable)
}
-func (v *View) ProcessedNotificationSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(notificationTable, eventSequence)
+func (v *View) ProcessedNotificationSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(notificationTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateNotificationSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(notificationTable)
}
func (v *View) GetLatestNotificationFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/notification/repository/eventsourcing/view/notify_user.go b/internal/notification/repository/eventsourcing/view/notify_user.go
index 1361ff1486..44d1a1e32b 100644
--- a/internal/notification/repository/eventsourcing/view/notify_user.go
+++ b/internal/notification/repository/eventsourcing/view/notify_user.go
@@ -4,6 +4,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
@@ -14,13 +15,13 @@ func (v *View) NotifyUserByID(userID string) (*model.NotifyUser, error) {
return view.NotifyUserByID(v.Db, notifyUserTable, userID)
}
-func (v *View) PutNotifyUser(user *model.NotifyUser, sequence uint64) error {
+func (v *View) PutNotifyUser(user *model.NotifyUser, sequence uint64, eventTimestamp time.Time) error {
err := view.PutNotifyUser(v.Db, notifyUserTable, user)
if err != nil {
return err
}
if sequence != 0 {
- return v.ProcessedNotifyUserSequence(sequence)
+ return v.ProcessedNotifyUserSequence(sequence, eventTimestamp)
}
return nil
}
@@ -29,20 +30,24 @@ func (v *View) NotifyUsersByOrgID(orgID string) ([]*model.NotifyUser, error) {
return view.NotifyUsersByOrgID(v.Db, notifyUserTable, orgID)
}
-func (v *View) DeleteNotifyUser(userID string, eventSequence uint64) error {
+func (v *View) DeleteNotifyUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteNotifyUser(v.Db, notifyUserTable, userID)
if err != nil {
return nil
}
- return v.ProcessedNotifyUserSequence(eventSequence)
+ return v.ProcessedNotifyUserSequence(eventSequence, eventTimestamp)
}
func (v *View) GetLatestNotifyUserSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(notifyUserTable)
}
-func (v *View) ProcessedNotifyUserSequence(eventSequence uint64) error {
- return v.saveCurrentSequence(notifyUserTable, eventSequence)
+func (v *View) ProcessedNotifyUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
+ return v.saveCurrentSequence(notifyUserTable, eventSequence, eventTimestamp)
+}
+
+func (v *View) UpdateNotifyUserSpoolerRunTimestamp() error {
+ return v.updateSpoolerRunSequence(notifyUserTable)
}
func (v *View) GetLatestNotifyUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
diff --git a/internal/notification/repository/eventsourcing/view/sequence.go b/internal/notification/repository/eventsourcing/view/sequence.go
index 8ad083ab46..f1868e4f44 100644
--- a/internal/notification/repository/eventsourcing/view/sequence.go
+++ b/internal/notification/repository/eventsourcing/view/sequence.go
@@ -2,16 +2,29 @@ package view
import (
"github.com/caos/zitadel/internal/view/repository"
+ "time"
)
const (
sequencesTable = "notification.current_sequences"
)
-func (v *View) saveCurrentSequence(viewName string, sequence uint64) error {
- return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence)
+func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimestamp time.Time) error {
+ return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimestamp)
}
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
return repository.LatestSequence(v.Db, sequencesTable, viewName)
}
+
+func (v *View) updateSpoolerRunSequence(viewName string) error {
+ currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
+ if err != nil {
+ return err
+ }
+ if currentSequence.ViewName == "" {
+ currentSequence.ViewName = viewName
+ }
+ currentSequence.LastSuccessfulSpoolerRun = time.Now()
+ return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
+}
diff --git a/internal/org/repository/eventsourcing/eventstore.go b/internal/org/repository/eventsourcing/eventstore.go
index 8db5c785eb..c312c5e808 100644
--- a/internal/org/repository/eventsourcing/eventstore.go
+++ b/internal/org/repository/eventsourcing/eventstore.go
@@ -905,7 +905,7 @@ func (es *OrgEventstore) AddSecondFactorToLoginPolicy(ctx context.Context, aggre
if err != nil {
return 0, err
}
- if _, m := iam_es_model.GetMFA(repoOrg.LoginPolicy.SecondFactors, repoMFA.MfaType); m != 0 {
+ if _, m := iam_es_model.GetMFA(repoOrg.LoginPolicy.SecondFactors, repoMFA.MFAType); m != 0 {
return iam_model.SecondFactorType(m), nil
}
return 0, errors.ThrowInternal(nil, "EVENT-rM9so", "Errors.Internal")
@@ -950,7 +950,7 @@ func (es *OrgEventstore) AddMultiFactorToLoginPolicy(ctx context.Context, aggreg
if err != nil {
return 0, err
}
- if _, m := iam_es_model.GetMFA(repoOrg.LoginPolicy.MultiFactors, repoMFA.MfaType); m != 0 {
+ if _, m := iam_es_model.GetMFA(repoOrg.LoginPolicy.MultiFactors, repoMFA.MFAType); m != 0 {
return iam_model.MultiFactorType(m), nil
}
return 0, errors.ThrowInternal(nil, "EVENT-2fMo0", "Errors.Internal")
diff --git a/internal/org/repository/eventsourcing/eventstore_mock_test.go b/internal/org/repository/eventsourcing/eventstore_mock_test.go
index f8aa7fb6cb..6d7d175317 100644
--- a/internal/org/repository/eventsourcing/eventstore_mock_test.go
+++ b/internal/org/repository/eventsourcing/eventstore_mock_test.go
@@ -109,8 +109,8 @@ func GetMockChangesOrgWithLoginPolicyWithMFA(ctrl *gomock.Controller) *OrgEvents
orgData, _ := json.Marshal(model.Org{Name: "MusterOrg"})
loginPolicy, _ := json.Marshal(iam_es_model.LoginPolicy{AllowRegister: true, AllowExternalIdp: true, AllowUsernamePassword: true})
idpData, _ := json.Marshal(iam_es_model.IDPProvider{IDPConfigID: "IDPConfigID", Type: int32(iam_model.IDPProviderTypeSystem)})
- secondFactor, _ := json.Marshal(iam_es_model.MFA{MfaType: int32(iam_model.SecondFactorTypeOTP)})
- multiFactor, _ := json.Marshal(iam_es_model.MFA{MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN)})
+ secondFactor, _ := json.Marshal(iam_es_model.MFA{MFAType: int32(iam_model.SecondFactorTypeOTP)})
+ multiFactor, _ := json.Marshal(iam_es_model.MFA{MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN)})
events := []*es_models.Event{
{AggregateID: "AggregateID", Sequence: 1, Type: model.OrgAdded, Data: orgData},
{AggregateID: "AggregateID", Sequence: 1, Type: model.LoginPolicyAdded, Data: loginPolicy},
diff --git a/internal/org/repository/eventsourcing/login_policy.go b/internal/org/repository/eventsourcing/login_policy.go
index bc25997395..def04a04b0 100644
--- a/internal/org/repository/eventsourcing/login_policy.go
+++ b/internal/org/repository/eventsourcing/login_policy.go
@@ -105,7 +105,7 @@ func LoginPolicySecondFactorAddedAggregate(aggCreator *es_models.AggregateCreato
AggregateTypeFilter(model.OrgAggregate).
AggregateIDsFilter(org.AggregateID)
- validation := checkExistingLoginPolicySecondFactorValidation(mfa.MfaType)
+ validation := checkExistingLoginPolicySecondFactorValidation(mfa.MFAType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicySecondFactorAdded, mfa)
}
@@ -137,7 +137,7 @@ func LoginPolicyMultiFactorAddedAggregate(aggCreator *es_models.AggregateCreator
AggregateTypeFilter(model.OrgAggregate).
AggregateIDsFilter(org.AggregateID)
- validation := checkExistingLoginPolicyMultiFactorValidation(mfa.MfaType)
+ validation := checkExistingLoginPolicyMultiFactorValidation(mfa.MFAType)
agg.SetPrecondition(validationQuery, validation)
return agg.AppendEvent(model.LoginPolicyMultiFactorAdded, mfa)
}
@@ -261,7 +261,7 @@ func checkExistingLoginPolicySecondFactorValidation(mfaType int32) func(...*es_m
if err != nil {
return err
}
- mfas = append(mfas, mfa.MfaType)
+ mfas = append(mfas, mfa.MFAType)
case model.LoginPolicySecondFactorRemoved:
idp := new(iam_es_model.IDPProvider)
err := idp.SetData(event)
@@ -301,7 +301,7 @@ func checkExistingLoginPolicyMultiFactorValidation(mfaType int32) func(...*es_mo
if err != nil {
return err
}
- mfas = append(mfas, mfa.MfaType)
+ mfas = append(mfas, mfa.MFAType)
case model.LoginPolicyMultiFactorRemoved:
idp := new(iam_es_model.IDPProvider)
err := idp.SetData(event)
diff --git a/internal/org/repository/eventsourcing/login_policy_test.go b/internal/org/repository/eventsourcing/login_policy_test.go
index 838b8b28c2..fb11d413cb 100644
--- a/internal/org/repository/eventsourcing/login_policy_test.go
+++ b/internal/org/repository/eventsourcing/login_policy_test.go
@@ -472,7 +472,7 @@ func TestLoginPolicySecondFactorAddedAggregate(t *testing.T) {
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
},
new: &iam_es_model.MFA{
- MfaType: int32(iam_model.SecondFactorTypeOTP),
+ MFAType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
@@ -562,7 +562,7 @@ func TestLoginPolicySecondFactorRemovedAggregate(t *testing.T) {
},
}},
new: &iam_es_model.MFA{
- MfaType: int32(iam_model.SecondFactorTypeOTP),
+ MFAType: int32(iam_model.SecondFactorTypeOTP),
},
aggCreator: models.NewAggregateCreator("Test"),
},
@@ -645,7 +645,7 @@ func TestLoginPolicyMultiFactorAddedAggregate(t *testing.T) {
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
},
new: &iam_es_model.MFA{
- MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN),
+ MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN),
},
aggCreator: models.NewAggregateCreator("Test"),
},
@@ -735,7 +735,7 @@ func TestLoginPolicyMultiFactorRemovedAggregate(t *testing.T) {
},
}},
new: &iam_es_model.MFA{
- MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN),
+ MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN),
},
aggCreator: models.NewAggregateCreator("Test"),
},
diff --git a/internal/org/repository/eventsourcing/model/login_policy.go b/internal/org/repository/eventsourcing/model/login_policy.go
index ab1ca319ce..02388669f8 100644
--- a/internal/org/repository/eventsourcing/model/login_policy.go
+++ b/internal/org/repository/eventsourcing/model/login_policy.go
@@ -55,7 +55,7 @@ func (o *Org) appendAddSecondFactorToLoginPolicyEvent(event *es_models.Event) er
if err != nil {
return err
}
- o.LoginPolicy.SecondFactors = append(o.LoginPolicy.SecondFactors, mfa.MfaType)
+ o.LoginPolicy.SecondFactors = append(o.LoginPolicy.SecondFactors, mfa.MFAType)
return nil
}
@@ -65,7 +65,7 @@ func (o *Org) appendRemoveSecondFactorFromLoginPolicyEvent(event *es_models.Even
if err != nil {
return err
}
- if i, m := iam_es_model.GetMFA(o.LoginPolicy.SecondFactors, mfa.MfaType); m != 0 {
+ if i, m := iam_es_model.GetMFA(o.LoginPolicy.SecondFactors, mfa.MFAType); m != 0 {
o.LoginPolicy.SecondFactors[i] = o.LoginPolicy.SecondFactors[len(o.LoginPolicy.SecondFactors)-1]
o.LoginPolicy.SecondFactors[len(o.LoginPolicy.SecondFactors)-1] = 0
o.LoginPolicy.SecondFactors = o.LoginPolicy.SecondFactors[:len(o.LoginPolicy.SecondFactors)-1]
@@ -80,7 +80,7 @@ func (o *Org) appendAddMultiFactorToLoginPolicyEvent(event *es_models.Event) err
if err != nil {
return err
}
- o.LoginPolicy.MultiFactors = append(o.LoginPolicy.MultiFactors, mfa.MfaType)
+ o.LoginPolicy.MultiFactors = append(o.LoginPolicy.MultiFactors, mfa.MFAType)
return nil
}
@@ -90,7 +90,7 @@ func (o *Org) appendRemoveMultiFactorFromLoginPolicyEvent(event *es_models.Event
if err != nil {
return err
}
- if i, m := iam_es_model.GetMFA(o.LoginPolicy.MultiFactors, mfa.MfaType); m != 0 {
+ if i, m := iam_es_model.GetMFA(o.LoginPolicy.MultiFactors, mfa.MFAType); m != 0 {
o.LoginPolicy.MultiFactors[i] = o.LoginPolicy.MultiFactors[len(o.LoginPolicy.MultiFactors)-1]
o.LoginPolicy.MultiFactors[len(o.LoginPolicy.MultiFactors)-1] = 0
o.LoginPolicy.MultiFactors = o.LoginPolicy.MultiFactors[:len(o.LoginPolicy.MultiFactors)-1]
diff --git a/internal/org/repository/eventsourcing/model/login_policy_test.go b/internal/org/repository/eventsourcing/model/login_policy_test.go
index 7ef70e275d..2662cb0910 100644
--- a/internal/org/repository/eventsourcing/model/login_policy_test.go
+++ b/internal/org/repository/eventsourcing/model/login_policy_test.go
@@ -224,7 +224,7 @@ func TestAppendAddSecondFactorToPolicyEvent(t *testing.T) {
name: "append add second factor to login policy event",
args: args{
org: &Org{LoginPolicy: &iam_es_model.LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
- mfa: &iam_es_model.MFA{MfaType: int32(iam_model.SecondFactorTypeOTP)},
+ mfa: &iam_es_model.MFA{MFAType: int32(iam_model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
@@ -246,7 +246,7 @@ func TestAppendAddSecondFactorToPolicyEvent(t *testing.T) {
if len(tt.result.LoginPolicy.SecondFactors) != len(tt.args.org.LoginPolicy.SecondFactors) {
t.Errorf("got wrong second factor len: expected: %v, actual: %v ", len(tt.result.LoginPolicy.SecondFactors), len(tt.args.org.LoginPolicy.SecondFactors))
}
- if tt.result.LoginPolicy.SecondFactors[0] != tt.args.mfa.MfaType {
+ if tt.result.LoginPolicy.SecondFactors[0] != tt.args.mfa.MFAType {
t.Errorf("got wrong second factor: expected: %v, actual: %v ", tt.result.LoginPolicy.SecondFactors[0], tt.args.mfa)
}
})
@@ -275,7 +275,7 @@ func TestRemoveSecondFactorFromPolicyEvent(t *testing.T) {
SecondFactors: []int32{
int32(iam_model.SecondFactorTypeOTP),
}}},
- mfa: &iam_es_model.MFA{MfaType: int32(iam_model.SecondFactorTypeOTP)},
+ mfa: &iam_es_model.MFA{MFAType: int32(iam_model.SecondFactorTypeOTP)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
@@ -314,7 +314,7 @@ func TestAppendAddMultiFactorToPolicyEvent(t *testing.T) {
name: "append add mfa to login policy event",
args: args{
org: &Org{LoginPolicy: &iam_es_model.LoginPolicy{AllowExternalIdp: true, AllowRegister: true, AllowUsernamePassword: true}},
- mfa: &iam_es_model.MFA{MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN)},
+ mfa: &iam_es_model.MFA{MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
@@ -336,7 +336,7 @@ func TestAppendAddMultiFactorToPolicyEvent(t *testing.T) {
if len(tt.result.LoginPolicy.MultiFactors) != len(tt.args.org.LoginPolicy.MultiFactors) {
t.Errorf("got wrong second factor len: expected: %v, actual: %v ", len(tt.result.LoginPolicy.MultiFactors), len(tt.args.org.LoginPolicy.MultiFactors))
}
- if tt.result.LoginPolicy.MultiFactors[0] != tt.args.mfa.MfaType {
+ if tt.result.LoginPolicy.MultiFactors[0] != tt.args.mfa.MFAType {
t.Errorf("got wrong second factor: expected: %v, actual: %v ", tt.result.LoginPolicy.MultiFactors[0], tt.args.mfa)
}
})
@@ -365,7 +365,7 @@ func TestRemoveMultiFactorFromPolicyEvent(t *testing.T) {
MultiFactors: []int32{
int32(iam_model.MultiFactorTypeU2FWithPIN),
}}},
- mfa: &iam_es_model.MFA{MfaType: int32(iam_model.MultiFactorTypeU2FWithPIN)},
+ mfa: &iam_es_model.MFA{MFAType: int32(iam_model.MultiFactorTypeU2FWithPIN)},
event: &es_models.Event{},
},
result: &Org{LoginPolicy: &iam_es_model.LoginPolicy{
diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go
index d9b3f861bb..8967c81389 100644
--- a/internal/project/repository/eventsourcing/eventstore.go
+++ b/internal/project/repository/eventsourcing/eventstore.go
@@ -20,6 +20,7 @@ import (
"github.com/caos/zitadel/internal/id"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
)
const (
@@ -788,7 +789,9 @@ func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, project
return nil, caos_errs.ThrowInternal(nil, "EVENT-dk87s", "Errors.Internal")
}
-func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, projectID, appID string, secret string) error {
+func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, projectID, appID string, secret string) (err error) {
+ ctx, span := tracing.NewSpan(ctx)
+ defer func() { span.EndWithError(err) }()
if appID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-H3RT2", "Errors.Project.RequiredFieldsMissing")
}
@@ -804,7 +807,10 @@ func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, project
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-huywq", "Errors.Project.AppIsNotOIDC")
}
- if err := crypto.CompareHash(app.OIDCConfig.ClientSecret, []byte(secret), es.passwordAlg); err == nil {
+ ctx, spanHash := tracing.NewSpan(ctx)
+ err = crypto.CompareHash(app.OIDCConfig.ClientSecret, []byte(secret), es.passwordAlg)
+ spanHash.EndWithError(err)
+ if err == nil {
return es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckSucceededAggregate)
}
if err := es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckFailedAggregate); err != nil {
diff --git a/internal/setup/config.go b/internal/setup/config.go
index 423b999695..93e0d4926b 100644
--- a/internal/setup/config.go
+++ b/internal/setup/config.go
@@ -13,6 +13,7 @@ type IAMSetUp struct {
Step5 *Step5
Step6 *Step6
Step7 *Step7
+ Step8 *Step8
}
func (setup *IAMSetUp) steps(currentDone iam_model.Step) ([]step, error) {
@@ -27,6 +28,7 @@ func (setup *IAMSetUp) steps(currentDone iam_model.Step) ([]step, error) {
setup.Step5,
setup.Step6,
setup.Step7,
+ setup.Step8,
} {
if step.step() <= currentDone {
continue
diff --git a/internal/setup/step7.go b/internal/setup/step7.go
index 210fa8fb56..99d445911c 100644
--- a/internal/setup/step7.go
+++ b/internal/setup/step7.go
@@ -32,23 +32,23 @@ func (step *Step7) init(setup *Setup) {
func (step *Step7) execute(ctx context.Context) (*iam_model.IAM, error) {
iam, agg, err := step.add2FAToPolicy(ctx, step.DefaultSecondFactor)
if err != nil {
- logging.Log("SETUP-ZTuS1").WithField("step", step.step()).WithError(err).Error("unable to finish setup (add default mfa to login policy)")
+ logging.Log("SETUP-GBD32").WithField("step", step.step()).WithError(err).Error("unable to finish setup (add default mfa to login policy)")
return nil, err
}
iam, agg, push, err := step.setup.IamEvents.PrepareSetupDone(ctx, iam, agg, step.step())
if err != nil {
- logging.Log("SETUP-OkF8o").WithField("step", step.step()).WithError(err).Error("unable to finish setup (prepare setup done)")
+ logging.Log("SETUP-BHrth").WithField("step", step.step()).WithError(err).Error("unable to finish setup (prepare setup done)")
return nil, err
}
err = es_sdk.PushAggregates(ctx, push, iam.AppendEvents, agg)
if err != nil {
- logging.Log("SETUP-YbQ6T").WithField("step", step.step()).WithError(err).Error("unable to finish setup")
+ logging.Log("SETUP-k2fla").WithField("step", step.step()).WithError(err).Error("unable to finish setup")
return nil, err
}
return iam_es_model.IAMToModel(iam), nil
}
func (step *Step7) add2FAToPolicy(ctx context.Context, secondFactor iam_model.SecondFactorType) (*iam_es_model.IAM, *models.Aggregate, error) {
- logging.Log("SETUP-geMGDuZ").Info("adding 2FA to loginPolicy")
+ logging.Log("SETUP-Bew1a").Info("adding 2FA to loginPolicy")
return step.setup.IamEvents.PrepareAddSecondFactorToLoginPolicy(ctx, step.setup.iamID, secondFactor)
}
diff --git a/internal/setup/step8.go b/internal/setup/step8.go
new file mode 100644
index 0000000000..30f70a41fb
--- /dev/null
+++ b/internal/setup/step8.go
@@ -0,0 +1,54 @@
+package setup
+
+import (
+ "context"
+
+ "github.com/caos/logging"
+
+ "github.com/caos/zitadel/internal/eventstore/models"
+ es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
+ iam_model "github.com/caos/zitadel/internal/iam/model"
+ iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
+)
+
+type Step8 struct {
+ DefaultSecondFactor iam_model.SecondFactorType
+
+ setup *Setup
+}
+
+func (step *Step8) isNil() bool {
+ return step == nil
+}
+
+func (step *Step8) step() iam_model.Step {
+ return iam_model.Step8
+}
+
+func (step *Step8) init(setup *Setup) {
+ step.setup = setup
+}
+
+func (step *Step8) execute(ctx context.Context) (*iam_model.IAM, error) {
+ iam, agg, err := step.add2FAToPolicy(ctx, step.DefaultSecondFactor)
+ if err != nil {
+ logging.Log("SETUP-Gdbjq").WithField("step", step.step()).WithError(err).Error("unable to finish setup (add default mfa to login policy)")
+ return nil, err
+ }
+ iam, agg, push, err := step.setup.IamEvents.PrepareSetupDone(ctx, iam, agg, step.step())
+ if err != nil {
+ logging.Log("SETUP-Cnf21").WithField("step", step.step()).WithError(err).Error("unable to finish setup (prepare setup done)")
+ return nil, err
+ }
+ err = es_sdk.PushAggregates(ctx, push, iam.AppendEvents, agg)
+ if err != nil {
+ logging.Log("SETUP-NFq21").WithField("step", step.step()).WithError(err).Error("unable to finish setup")
+ return nil, err
+ }
+ return iam_es_model.IAMToModel(iam), nil
+}
+
+func (step *Step8) add2FAToPolicy(ctx context.Context, secondFactor iam_model.SecondFactorType) (*iam_es_model.IAM, *models.Aggregate, error) {
+ logging.Log("SETUP-Bfhb2").Info("adding 2FA to loginPolicy")
+ return step.setup.IamEvents.PrepareAddSecondFactorToLoginPolicy(ctx, step.setup.iamID, secondFactor)
+}
diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml
index a32ac9f4e3..729e781d98 100644
--- a/internal/static/i18n/de.yaml
+++ b/internal/static/i18n/de.yaml
@@ -53,12 +53,25 @@ Errors:
IDPConfigNotExisting: IDP Provider ungültig für diese Organisation
NotAllowed: Externer IDP ist auf dieser Organisation nicht erlaubt.
MinimumExternalIDPNeeded: Mindestens ein IDP muss hinzugefügt werden.
- Mfa:
- Otp:
+ MFA:
+ OTP:
AlreadyReady: Multifaktor OTP (OneTimePassword) ist bereits eingerichtet
NotExisting: Multifaktor OTP (OneTimePassword) existiert nicht
NotReady: Multifaktor OTP (OneTimePassword) ist nicht bereit
InvalidCode: Code ist ungültig
+ U2F:
+ NotExisting: U2F existiert nicht
+ Passwordless:
+ NotExisting: Passwortlos existiert nicht
+ WebAuthN:
+ NotFound: WebAuthN Token konnte nicht gefunden werden
+ BeginRegisterFailed: Es ist ein Fehler bei der WebAuthN Registrierung aufgetreten
+ MarshalError: Daten konnten nicht umgewandelt werden
+ ErrorOnParseCredential: Zugangsdaten konnten nicht geparsed werden
+ CreateCredentialFailed: Zugangsdaten konnten nicht gespeichert werden
+ BeginLoginFailed: Es ist ein Fehler beim WebAuthN Login aufgetreten
+ ValidateLoginFailed: Zugangsdaten konnten nicht validiert werden
+ CloneWarning: Authentifizierungsdaten wurden möglicherweise geklont
Org:
Invalid: Organisation ist ungültig
AlreadyDeactivated: Organisation ist bereits deaktiviert
diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml
index 08579d24bf..79088a8465 100644
--- a/internal/static/i18n/en.yaml
+++ b/internal/static/i18n/en.yaml
@@ -53,12 +53,25 @@ Errors:
IDPConfigNotExisting: IDP provider invalid for this organisation
NotAllowed: External IDP not allowed on this organisation
MinimumExternalIDPNeeded: At least one IDP must be added
- Mfa:
- Otp:
+ MFA:
+ OTP:
AlreadyReady: Multifactor OTP (OneTimePassword) is already set up
NotExisting: Multifactor OTP (OneTimePassword) doesn't exist
NotReady: Multifactor OTP (OneTimePassword) isn't ready
InvalidCode: Invalid code
+ U2F:
+ NotExisting: U2F does not exist
+ Passwordless:
+ NotExisting: Passwordless does not exist
+ WebAuthN:
+ NotFound: WebAuthN Token could not be found
+ BeginRegisterFailed: WebAuthN begin registration failed
+ MarshalError: Error on marshal data
+ ErrorOnParseCredential: Error on parse credential data
+ CreateCredentialFailed: Error on create credentials
+ BeginLoginFailed: WebAuthN begin login failed
+ ValidateLoginFailed: Error on validate login credentials
+ CloneWarning: Credentials may be cloned
Org:
Invalid: Organisation is invalid
AlreadyDeactivated: Organisation is already deactivated
diff --git a/internal/telemetry/http_handler.go b/internal/telemetry/http_handler.go
new file mode 100644
index 0000000000..6985791954
--- /dev/null
+++ b/internal/telemetry/http_handler.go
@@ -0,0 +1,33 @@
+package telemetry
+
+import (
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+ "net/http"
+ "strings"
+
+ "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
+)
+
+func shouldNotIgnore(endpoints ...string) func(r *http.Request) bool {
+ return func(r *http.Request) bool {
+ for _, endpoint := range endpoints {
+ if strings.HasPrefix(r.URL.RequestURI(), endpoint) {
+ return false
+ }
+ }
+ return true
+ }
+}
+
+func TelemetryHandler(handler http.Handler, ignoredEndpoints ...string) http.Handler {
+ return otelhttp.NewHandler(handler,
+ "zitadel",
+ otelhttp.WithFilter(shouldNotIgnore(ignoredEndpoints...)),
+ otelhttp.WithPublicEndpoint(),
+ otelhttp.WithSpanNameFormatter(spanNameFormatter),
+ otelhttp.WithMeterProvider(metrics.GetMetricsProvider()))
+}
+
+func spanNameFormatter(_ string, r *http.Request) string {
+ return r.Host + r.URL.EscapedPath()
+}
diff --git a/internal/telemetry/metrics/config/config.go b/internal/telemetry/metrics/config/config.go
new file mode 100644
index 0000000000..50bfe3df47
--- /dev/null
+++ b/internal/telemetry/metrics/config/config.go
@@ -0,0 +1,65 @@
+package config
+
+import (
+ "encoding/json"
+
+ "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+ "github.com/caos/zitadel/internal/telemetry/metrics/otel"
+)
+
+type MetricsConfig struct {
+ Type string
+ Config metrics.Config
+}
+
+var meter = map[string]func() metrics.Config{
+ "otel": func() metrics.Config { return &otel.Config{} },
+ "none": func() metrics.Config { return &NoMetrics{} },
+ "": func() metrics.Config { return &NoMetrics{} },
+}
+
+func (c *MetricsConfig) UnmarshalJSON(data []byte) error {
+ var rc struct {
+ Type string
+ Config json.RawMessage
+ }
+
+ if err := json.Unmarshal(data, &rc); err != nil {
+ return errors.ThrowInternal(err, "METER-4M9so", "error parsing config")
+ }
+
+ c.Type = rc.Type
+
+ var err error
+ c.Config, err = newMetricsConfig(c.Type, rc.Config)
+ if err != nil {
+ return err
+ }
+
+ return c.Config.NewMetrics()
+}
+
+func newMetricsConfig(tracerType string, configData []byte) (metrics.Config, error) {
+ t, ok := meter[tracerType]
+ if !ok {
+ return nil, errors.ThrowInternalf(nil, "METER-3M0ps", "config type %s not supported", tracerType)
+ }
+
+ metricsConfig := t()
+ if len(configData) == 0 {
+ return metricsConfig, nil
+ }
+
+ if err := json.Unmarshal(configData, metricsConfig); err != nil {
+ return nil, errors.ThrowInternal(err, "METER-4M9sf", "Could not read config: %v")
+ }
+
+ return metricsConfig, nil
+}
+
+type NoMetrics struct{}
+
+func (_ *NoMetrics) NewMetrics() error {
+ return nil
+}
diff --git a/internal/telemetry/metrics/http_handler.go b/internal/telemetry/metrics/http_handler.go
new file mode 100644
index 0000000000..e9e86e1df6
--- /dev/null
+++ b/internal/telemetry/metrics/http_handler.go
@@ -0,0 +1,128 @@
+package metrics
+
+import (
+ "net/http"
+ "strings"
+)
+
+const (
+ RequestCounter = "http.server.request_count"
+ RequestCountDescription = "Request counter"
+ TotalRequestCounter = "http.server.total_request_count"
+ TotalRequestDescription = "Total return code counter"
+ ReturnCodeCounter = "http.server.return_code_counter"
+ ReturnCodeCounterDescription = "Return code counter"
+ Method = "method"
+ URI = "uri"
+ ReturnCode = "return_code"
+)
+
+type Handler struct {
+ handler http.Handler
+ methods []MetricType
+ filters []Filter
+}
+
+type MetricType int32
+
+const (
+ MetricTypeTotalCount MetricType = iota
+ MetricTypeStatusCode
+ MetricTypeRequestCount
+)
+
+type StatusRecorder struct {
+ http.ResponseWriter
+ Status int
+}
+
+func (r *StatusRecorder) WriteHeader(status int) {
+ r.Status = status
+ r.ResponseWriter.WriteHeader(status)
+}
+
+type Filter func(*http.Request) bool
+
+func NewMetricsHandler(handler http.Handler, metricMethods []MetricType, ignoredEndpoints ...string) http.Handler {
+ h := Handler{
+ handler: handler,
+ methods: metricMethods,
+ }
+ if len(ignoredEndpoints) > 0 {
+ h.filters = append(h.filters, shouldNotIgnore(ignoredEndpoints...))
+ }
+ return &h
+}
+
+// ServeHTTP serves HTTP requests (http.Handler)
+func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if len(h.methods) == 0 {
+ h.handler.ServeHTTP(w, r)
+ return
+ }
+ for _, f := range h.filters {
+ if !f(r) {
+ // Simply pass through to the handler if a filter rejects the request
+ h.handler.ServeHTTP(w, r)
+ return
+ }
+ }
+ recorder := &StatusRecorder{
+ ResponseWriter: w,
+ Status: 200,
+ }
+ h.handler.ServeHTTP(recorder, r)
+ if h.containsMetricsMethod(MetricTypeRequestCount) {
+ RegisterRequestCounter(r)
+ }
+ if h.containsMetricsMethod(MetricTypeTotalCount) {
+ RegisterTotalRequestCounter(r)
+ }
+ if h.containsMetricsMethod(MetricTypeStatusCode) {
+ RegisterRequestCodeCounter(recorder, r)
+ }
+}
+
+func (h *Handler) containsMetricsMethod(method MetricType) bool {
+ for _, m := range h.methods {
+ if m == method {
+ return true
+ }
+ }
+ return false
+}
+
+func RegisterRequestCounter(r *http.Request) {
+ var labels = map[string]interface{}{
+ URI: strings.Split(r.RequestURI, "?")[0],
+ Method: r.Method,
+ }
+ RegisterCounter(RequestCounter, RequestCountDescription)
+ AddCount(r.Context(), RequestCounter, 1, labels)
+}
+
+func RegisterTotalRequestCounter(r *http.Request) {
+ RegisterCounter(TotalRequestCounter, TotalRequestDescription)
+ AddCount(r.Context(), TotalRequestCounter, 1, nil)
+}
+
+func RegisterRequestCodeCounter(recorder *StatusRecorder, r *http.Request) {
+ var labels = map[string]interface{}{
+ URI: strings.Split(r.RequestURI, "?")[0],
+ Method: r.Method,
+ ReturnCode: recorder.Status,
+ }
+ RegisterCounter(ReturnCodeCounter, ReturnCodeCounterDescription)
+ AddCount(r.Context(), ReturnCodeCounter, 1, labels)
+}
+
+func shouldNotIgnore(endpoints ...string) func(r *http.Request) bool {
+ return func(r *http.Request) bool {
+ for _, endpoint := range endpoints {
+ if strings.HasPrefix(r.URL.RequestURI(), endpoint) {
+ return false
+ }
+ }
+ return true
+ }
+}
diff --git a/internal/telemetry/metrics/metrics.go b/internal/telemetry/metrics/metrics.go
new file mode 100644
index 0000000000..4dc3b0675d
--- /dev/null
+++ b/internal/telemetry/metrics/metrics.go
@@ -0,0 +1,73 @@
+package metrics
+
+import (
+ "context"
+ "go.opentelemetry.io/otel/api/metric"
+ "net/http"
+)
+
+const (
+ ActiveSessionCounter = "zitadel.active_session_counter"
+ ActiveSessionCounterDescription = "Active session counter"
+ SpoolerDivCounter = "zitadel.spooler_div_milliseconds"
+ SpoolerDivCounterDescription = "Spooler div from last successful run to now in milliseconds"
+ Database = "database"
+ ViewName = "view_name"
+)
+
+type Metrics interface {
+ GetExporter() http.Handler
+ GetMetricsProvider() metric.MeterProvider
+ RegisterCounter(name, description string) error
+ AddCount(ctx context.Context, name string, value int64, labels map[string]interface{}) error
+ RegisterUpDownSumObserver(name, description string, callbackFunc metric.Int64ObserverFunc) error
+ RegisterValueObserver(name, description string, callbackFunc metric.Int64ObserverFunc) error
+}
+
+type Config interface {
+ NewMetrics() error
+}
+
+var M Metrics
+
+func GetExporter() http.Handler {
+ if M == nil {
+ return nil
+ }
+ return M.GetExporter()
+}
+
+func GetMetricsProvider() metric.MeterProvider {
+ if M == nil {
+ return nil
+ }
+ return M.GetMetricsProvider()
+}
+
+func RegisterCounter(name, description string) error {
+ if M == nil {
+ return nil
+ }
+ return M.RegisterCounter(name, description)
+}
+
+func AddCount(ctx context.Context, name string, value int64, labels map[string]interface{}) error {
+ if M == nil {
+ return nil
+ }
+ return M.AddCount(ctx, name, value, labels)
+}
+
+func RegisterUpDownSumObserver(name, description string, callbackFunc metric.Int64ObserverFunc) error {
+ if M == nil {
+ return nil
+ }
+ return M.RegisterUpDownSumObserver(name, description, callbackFunc)
+}
+
+func RegisterValueObserver(name, description string, callbackFunc metric.Int64ObserverFunc) error {
+ if M == nil {
+ return nil
+ }
+ return M.RegisterValueObserver(name, description, callbackFunc)
+}
diff --git a/internal/telemetry/metrics/otel/config.go b/internal/telemetry/metrics/otel/config.go
new file mode 100644
index 0000000000..8d6718d319
--- /dev/null
+++ b/internal/telemetry/metrics/otel/config.go
@@ -0,0 +1,14 @@
+package otel
+
+import (
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+)
+
+type Config struct {
+ MeterName string
+}
+
+func (c *Config) NewMetrics() (err error) {
+ metrics.M, err = NewMetrics(c.MeterName)
+ return err
+}
diff --git a/internal/telemetry/metrics/otel/open_telemetry.go b/internal/telemetry/metrics/otel/open_telemetry.go
new file mode 100644
index 0000000000..80e04f5ce2
--- /dev/null
+++ b/internal/telemetry/metrics/otel/open_telemetry.go
@@ -0,0 +1,92 @@
+package otel
+
+import (
+ "context"
+ caos_errs "github.com/caos/zitadel/internal/errors"
+ "github.com/caos/zitadel/internal/telemetry/metrics"
+ "go.opentelemetry.io/otel/api/metric"
+ "go.opentelemetry.io/otel/exporters/metric/prometheus"
+ "go.opentelemetry.io/otel/label"
+ "net/http"
+ "sync"
+)
+
+type Metrics struct {
+ Exporter *prometheus.Exporter
+ Meter metric.Meter
+ Counters sync.Map
+ UpDownSumObserver sync.Map
+ ValueObservers sync.Map
+}
+
+func NewMetrics(meterName string) (metrics.Metrics, error) {
+ exporter, err := prometheus.NewExportPipeline(
+ prometheus.Config{},
+ )
+ if err != nil {
+ return &Metrics{}, err
+ }
+ return &Metrics{
+ Exporter: exporter,
+ Meter: exporter.MeterProvider().Meter(meterName),
+ }, nil
+}
+
+func (m *Metrics) GetExporter() http.Handler {
+ return m.Exporter
+}
+
+func (m *Metrics) GetMetricsProvider() metric.MeterProvider {
+ return m.Exporter.MeterProvider()
+}
+
+func (m *Metrics) RegisterCounter(name, description string) error {
+ if _, exists := m.Counters.Load(name); exists {
+ return nil
+ }
+ counter := metric.Must(m.Meter).NewInt64Counter(name, metric.WithDescription(description))
+ m.Counters.Store(name, counter)
+ return nil
+}
+
+func (m *Metrics) AddCount(ctx context.Context, name string, value int64, labels map[string]interface{}) error {
+ counter, exists := m.Counters.Load(name)
+ if !exists {
+ return caos_errs.ThrowNotFound(nil, "METER-4u8fs", "Errors.Metrics.Counter.NotFound")
+ }
+ counter.(metric.Int64Counter).Add(ctx, value, MapToKeyValue(labels)...)
+ return nil
+}
+
+func (m *Metrics) RegisterUpDownSumObserver(name, description string, callbackFunc metric.Int64ObserverFunc) error {
+ if _, exists := m.UpDownSumObserver.Load(name); exists {
+ return nil
+ }
+ sumObserver := metric.Must(m.Meter).NewInt64UpDownSumObserver(
+ name, callbackFunc, metric.WithDescription(description))
+
+ m.UpDownSumObserver.Store(name, sumObserver)
+ return nil
+}
+
+func (m *Metrics) RegisterValueObserver(name, description string, callbackFunc metric.Int64ObserverFunc) error {
+ if _, exists := m.UpDownSumObserver.Load(name); exists {
+ return nil
+ }
+ sumObserver := metric.Must(m.Meter).NewInt64ValueObserver(
+ name, callbackFunc, metric.WithDescription(description))
+
+ m.UpDownSumObserver.Store(name, sumObserver)
+ return nil
+}
+
+func MapToKeyValue(labels map[string]interface{}) []label.KeyValue {
+ if labels == nil {
+ return nil
+ }
+ keyValues := make([]label.KeyValue, 0, len(labels))
+ for key, value := range labels {
+ keyValues = append(keyValues, label.Any(key, value))
+ }
+ return keyValues
+}
diff --git a/internal/tracing/caller.go b/internal/telemetry/tracing/caller.go
similarity index 100%
rename from internal/tracing/caller.go
rename to internal/telemetry/tracing/caller.go
diff --git a/internal/tracing/config/config.go b/internal/telemetry/tracing/config/config.go
similarity index 86%
rename from internal/tracing/config/config.go
rename to internal/telemetry/tracing/config/config.go
index 977f8f9057..70a08be426 100644
--- a/internal/tracing/config/config.go
+++ b/internal/telemetry/tracing/config/config.go
@@ -4,10 +4,10 @@ import (
"encoding/json"
"github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/tracing"
- "github.com/caos/zitadel/internal/tracing/google"
- "github.com/caos/zitadel/internal/tracing/log"
- "github.com/caos/zitadel/internal/tracing/otel"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing/google"
+ "github.com/caos/zitadel/internal/telemetry/tracing/log"
+ "github.com/caos/zitadel/internal/telemetry/tracing/otel"
)
type TracingConfig struct {
diff --git a/internal/tracing/google/google_tracer.go b/internal/telemetry/tracing/google/google_tracer.go
similarity index 89%
rename from internal/tracing/google/google_tracer.go
rename to internal/telemetry/tracing/google/google_tracer.go
index ba57958730..35754a284e 100644
--- a/internal/tracing/google/google_tracer.go
+++ b/internal/telemetry/tracing/google/google_tracer.go
@@ -6,8 +6,8 @@ import (
texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
"github.com/caos/zitadel/internal/errors"
- "github.com/caos/zitadel/internal/tracing"
- "github.com/caos/zitadel/internal/tracing/otel"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing/otel"
sdk_trace "go.opentelemetry.io/otel/sdk/trace"
)
diff --git a/internal/tracing/log/config.go b/internal/telemetry/tracing/log/config.go
similarity index 82%
rename from internal/tracing/log/config.go
rename to internal/telemetry/tracing/log/config.go
index c903a46f14..6fd34559b6 100644
--- a/internal/tracing/log/config.go
+++ b/internal/telemetry/tracing/log/config.go
@@ -1,8 +1,8 @@
package log
import (
- "github.com/caos/zitadel/internal/tracing"
- "github.com/caos/zitadel/internal/tracing/otel"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing/otel"
"go.opentelemetry.io/otel/exporters/stdout"
sdk_trace "go.opentelemetry.io/otel/sdk/trace"
)
diff --git a/internal/tracing/otel/config.go b/internal/telemetry/tracing/otel/config.go
similarity index 90%
rename from internal/tracing/otel/config.go
rename to internal/telemetry/tracing/otel/config.go
index 6f0087dc13..9aa7d43d63 100644
--- a/internal/tracing/otel/config.go
+++ b/internal/telemetry/tracing/otel/config.go
@@ -1,7 +1,7 @@
package otel
import (
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"go.opentelemetry.io/otel/exporters/otlp"
sdk_trace "go.opentelemetry.io/otel/sdk/trace"
)
diff --git a/internal/tracing/otel/open_telemetry.go b/internal/telemetry/tracing/otel/open_telemetry.go
similarity index 97%
rename from internal/tracing/otel/open_telemetry.go
rename to internal/telemetry/tracing/otel/open_telemetry.go
index 12e7b82e72..4524cd0424 100644
--- a/internal/tracing/otel/open_telemetry.go
+++ b/internal/telemetry/tracing/otel/open_telemetry.go
@@ -4,7 +4,7 @@ import (
"context"
"net/http"
- "github.com/caos/zitadel/internal/tracing"
+ "github.com/caos/zitadel/internal/telemetry/tracing"
"go.opentelemetry.io/otel/api/global"
api_trace "go.opentelemetry.io/otel/api/trace"
"go.opentelemetry.io/otel/propagators"
diff --git a/internal/tracing/span.go b/internal/telemetry/tracing/span.go
similarity index 100%
rename from internal/tracing/span.go
rename to internal/telemetry/tracing/span.go
diff --git a/internal/tracing/tracing.go b/internal/telemetry/tracing/tracing.go
similarity index 100%
rename from internal/tracing/tracing.go
rename to internal/telemetry/tracing/tracing.go
diff --git a/internal/tracing/http_handler.go b/internal/tracing/http_handler.go
deleted file mode 100644
index 38c9664a70..0000000000
--- a/internal/tracing/http_handler.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package tracing
-
-import (
- "net/http"
- "strings"
-
- http_trace "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
-)
-
-func shouldNotIgnore(endpoints ...string) func(r *http.Request) bool {
- return func(r *http.Request) bool {
- for _, endpoint := range endpoints {
- if strings.HasPrefix(r.URL.RequestURI(), endpoint) {
- return false
- }
- }
- return true
- }
-}
-
-func TraceHandler(handler http.Handler, ignoredEndpoints ...string) http.Handler {
- return http_trace.NewHandler(handler,
- "zitadel",
- http_trace.WithFilter(shouldNotIgnore(ignoredEndpoints...)),
- http_trace.WithPublicEndpoint(),
- http_trace.WithSpanNameFormatter(spanNameFormatter))
-}
-
-func spanNameFormatter(_ string, r *http.Request) string {
- return r.Host + r.URL.EscapedPath()
-}
diff --git a/internal/ui/login/handler/login.go b/internal/ui/login/handler/login.go
index 149167c418..7da2ea9678 100644
--- a/internal/ui/login/handler/login.go
+++ b/internal/ui/login/handler/login.go
@@ -2,7 +2,6 @@ package handler
import (
"context"
- "github.com/caos/zitadel/internal/config/systemdefaults"
"net"
"net/http"
@@ -16,6 +15,7 @@ import (
"github.com/caos/zitadel/internal/api/http/middleware"
auth_repository "github.com/caos/zitadel/internal/auth/repository"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing"
+ "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/form"
"github.com/caos/zitadel/internal/id"
@@ -82,7 +82,7 @@ func CreateLogin(config Config, authRepo *eventsourcing.EsRepository, systemDefa
security := middleware.SecurityHeaders(csp(), login.cspErrorHandler)
userAgentCookie, err := middleware.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator, localDevMode)
logging.Log("CONFI-Dvwf2").OnError(err).Panic("unable to create userAgentInterceptor")
- login.router = CreateRouter(login, statikFS, csrf, cache, security, userAgentCookie, middleware.TraceHandler(EndpointResources))
+ login.router = CreateRouter(login, statikFS, csrf, cache, security, userAgentCookie, middleware.TelemetryHandler(EndpointResources))
login.renderer = CreateRenderer(prefix, statikFS, config.LanguageCookieName, config.DefaultLanguage)
login.parser = form.NewParser()
return login, handlerPrefix
diff --git a/internal/ui/login/handler/mfa_init_done_handler.go b/internal/ui/login/handler/mfa_init_done_handler.go
index 69f41af2f5..741a010677 100644
--- a/internal/ui/login/handler/mfa_init_done_handler.go
+++ b/internal/ui/login/handler/mfa_init_done_handler.go
@@ -7,15 +7,15 @@ import (
)
const (
- tmplMfaInitDone = "mfainitdone"
+ tmplMFAInitDone = "mfainitdone"
)
type mfaInitDoneData struct {
}
-func (l *Login) renderMfaInitDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaDoneData) {
+func (l *Login) renderMFAInitDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaDoneData) {
var errType, errMessage string
- data.baseData = l.getBaseData(r, authReq, "Mfa Init Done", errType, errMessage)
+ data.baseData = l.getBaseData(r, authReq, "MFA Init Done", errType, errMessage)
data.profileData = l.getProfileData(authReq)
- l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaInitDone], data, nil)
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAInitDone], data, nil)
}
diff --git a/internal/ui/login/handler/mfa_init_u2f.go b/internal/ui/login/handler/mfa_init_u2f.go
new file mode 100644
index 0000000000..dccb3a84d4
--- /dev/null
+++ b/internal/ui/login/handler/mfa_init_u2f.go
@@ -0,0 +1,59 @@
+package handler
+
+import (
+ "encoding/base64"
+ "net/http"
+
+ "github.com/caos/zitadel/internal/auth_request/model"
+ user_model "github.com/caos/zitadel/internal/user/model"
+)
+
+const (
+ tmplMFAU2FInit = "mfainitu2f"
+)
+
+func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
+ var errType, errMessage, credentialData string
+ var u2f *user_model.WebAuthNToken
+ if err == nil {
+ u2f, err = l.authRepo.AddMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID)
+ }
+ if err != nil {
+ errMessage = l.getErrorMessage(r, err)
+ }
+ if u2f != nil {
+ credentialData = base64.RawURLEncoding.EncodeToString(u2f.CredentialCreationData)
+ }
+ data := &webAuthNData{
+ userData: l.getUserData(r, authReq, "Register WebAuthNToken", errType, errMessage),
+ CredentialCreationData: credentialData,
+ }
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAU2FInit], data, nil)
+}
+
+func (l *Login) handleRegisterU2F(w http.ResponseWriter, r *http.Request) {
+ data := new(webAuthNFormData)
+ authReq, err := l.getAuthRequestAndParseData(r, data)
+ if err != nil {
+ l.renderError(w, r, authReq, err)
+ return
+ }
+ if data.Recreate {
+ l.renderRegisterU2F(w, r, authReq, nil)
+ return
+ }
+ credData, err := base64.URLEncoding.DecodeString(data.CredentialData)
+ if err != nil {
+ l.renderRegisterU2F(w, r, authReq, err)
+ return
+ }
+
+ if err = l.authRepo.VerifyMFAU2FSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Name, credData); err != nil {
+ l.renderRegisterU2F(w, r, authReq, err)
+ return
+ }
+ done := &mfaDoneData{
+ MFAType: model.MFATypeU2F,
+ }
+ l.renderMFAInitDone(w, r, authReq, done)
+}
diff --git a/internal/ui/login/handler/mfa_init_verify_handler.go b/internal/ui/login/handler/mfa_init_verify_handler.go
index d043d90ea1..bc07c6ede2 100644
--- a/internal/ui/login/handler/mfa_init_verify_handler.go
+++ b/internal/ui/login/handler/mfa_init_verify_handler.go
@@ -12,17 +12,17 @@ import (
)
const (
- tmplMfaInitVerify = "mfainitverify"
+ tmplMFAInitVerify = "mfainitverify"
)
type mfaInitVerifyData struct {
- MfaType model.MFAType `schema:"mfaType"`
+ MFAType model.MFAType `schema:"mfaType"`
Code string `schema:"code"`
URL string `schema:"url"`
Secret string `schema:"secret"`
}
-func (l *Login) handleMfaInitVerify(w http.ResponseWriter, r *http.Request) {
+func (l *Login) handleMFAInitVerify(w http.ResponseWriter, r *http.Request) {
data := new(mfaInitVerifyData)
authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil {
@@ -30,29 +30,29 @@ func (l *Login) handleMfaInitVerify(w http.ResponseWriter, r *http.Request) {
return
}
var verifyData *mfaVerifyData
- switch data.MfaType {
+ switch data.MFAType {
case model.MFATypeOTP:
- verifyData = l.handleOtpVerify(w, r, authReq, data)
+ verifyData = l.handleOTPVerify(w, r, authReq, data)
}
if verifyData != nil {
- l.renderMfaInitVerify(w, r, authReq, verifyData, err)
+ l.renderMFAInitVerify(w, r, authReq, verifyData, err)
return
}
done := &mfaDoneData{
- MfaType: data.MfaType,
+ MFAType: data.MFAType,
}
- l.renderMfaInitDone(w, r, authReq, done)
+ l.renderMFAInitDone(w, r, authReq, done)
}
-func (l *Login) handleOtpVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaInitVerifyData) *mfaVerifyData {
- err := l.authRepo.VerifyMfaOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code)
+func (l *Login) handleOTPVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaInitVerifyData) *mfaVerifyData {
+ err := l.authRepo.VerifyMFAOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code)
if err == nil {
return nil
}
mfadata := &mfaVerifyData{
- MfaType: data.MfaType,
+ MFAType: data.MFAType,
otpData: otpData{
Secret: data.Secret,
Url: data.URL,
@@ -62,21 +62,21 @@ func (l *Login) handleOtpVerify(w http.ResponseWriter, r *http.Request, authReq
return mfadata
}
-func (l *Login) renderMfaInitVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData, err error) {
+func (l *Login) renderMFAInitVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData, err error) {
var errType, errMessage string
if err != nil {
errMessage = l.getErrorMessage(r, err)
}
- data.baseData = l.getBaseData(r, authReq, "Mfa Init Verify", errType, errMessage)
+ data.baseData = l.getBaseData(r, authReq, "MFA Init Verify", errType, errMessage)
data.profileData = l.getProfileData(authReq)
- if data.MfaType == model.MFATypeOTP {
+ if data.MFAType == model.MFATypeOTP {
code, err := generateQrCode(data.otpData.Url)
if err == nil {
data.otpData.QrCode = code
}
}
- l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaInitVerify], data, nil)
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAInitVerify], data, nil)
}
func generateQrCode(url string) (string, error) {
diff --git a/internal/ui/login/handler/mfa_prompt_handler.go b/internal/ui/login/handler/mfa_prompt_handler.go
index 516d1d04a3..32a32a00db 100644
--- a/internal/ui/login/handler/mfa_prompt_handler.go
+++ b/internal/ui/login/handler/mfa_prompt_handler.go
@@ -8,15 +8,15 @@ import (
)
const (
- tmplMfaPrompt = "mfaprompt"
+ tmplMFAPrompt = "mfaprompt"
)
type mfaPromptData struct {
- MfaProvider model.MFAType `schema:"provider"`
+ MFAProvider model.MFAType `schema:"provider"`
Skip bool `schema:"skip"`
}
-func (l *Login) handleMfaPrompt(w http.ResponseWriter, r *http.Request) {
+func (l *Login) handleMFAPrompt(w http.ResponseWriter, r *http.Request) {
data := new(mfaPromptData)
authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil {
@@ -25,11 +25,11 @@ func (l *Login) handleMfaPrompt(w http.ResponseWriter, r *http.Request) {
}
if !data.Skip {
mfaVerifyData := new(mfaVerifyData)
- mfaVerifyData.MfaType = data.MfaProvider
- l.handleMfaCreation(w, r, authReq, mfaVerifyData)
+ mfaVerifyData.MFAType = data.MFAProvider
+ l.handleMFACreation(w, r, authReq, mfaVerifyData)
return
}
- err = l.authRepo.SkipMfaInit(setContext(r.Context(), authReq.UserOrgID), authReq.UserID)
+ err = l.authRepo.SkipMFAInit(setContext(r.Context(), authReq.UserOrgID), authReq.UserID)
if err != nil {
l.renderError(w, r, authReq, err)
return
@@ -37,7 +37,7 @@ func (l *Login) handleMfaPrompt(w http.ResponseWriter, r *http.Request) {
l.handleLogin(w, r)
}
-func (l *Login) handleMfaPromptSelection(w http.ResponseWriter, r *http.Request) {
+func (l *Login) handleMFAPromptSelection(w http.ResponseWriter, r *http.Request) {
data := new(mfaPromptData)
authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil {
@@ -48,45 +48,48 @@ func (l *Login) handleMfaPromptSelection(w http.ResponseWriter, r *http.Request)
l.renderNextStep(w, r, authReq)
}
-func (l *Login) renderMfaPrompt(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, mfaPromptData *model.MfaPromptStep, err error) {
+func (l *Login) renderMFAPrompt(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, mfaPromptData *model.MFAPromptStep, err error) {
var errType, errMessage string
if err != nil {
errMessage = l.getErrorMessage(r, err)
}
data := mfaData{
- baseData: l.getBaseData(r, authReq, "Mfa Prompt", errType, errMessage),
+ baseData: l.getBaseData(r, authReq, "MFA Prompt", errType, errMessage),
profileData: l.getProfileData(authReq),
}
if mfaPromptData == nil {
- l.renderError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-XU0tj", "Errors.User.Mfa.NoProviders"))
+ l.renderError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-XU0tj", "Errors.User.MFA.NoProviders"))
return
}
- data.MfaProviders = mfaPromptData.MfaProviders
- data.MfaRequired = mfaPromptData.Required
+ data.MFAProviders = mfaPromptData.MFAProviders
+ data.MFARequired = mfaPromptData.Required
- if len(mfaPromptData.MfaProviders) == 1 && mfaPromptData.Required {
+ if len(mfaPromptData.MFAProviders) == 1 && mfaPromptData.Required {
data := &mfaVerifyData{
- MfaType: mfaPromptData.MfaProviders[0],
+ MFAType: mfaPromptData.MFAProviders[0],
}
- l.handleMfaCreation(w, r, authReq, data)
+ l.handleMFACreation(w, r, authReq, data)
return
}
- l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaPrompt], data, nil)
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAPrompt], data, nil)
}
-func (l *Login) handleMfaCreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) {
- switch data.MfaType {
+func (l *Login) handleMFACreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) {
+ switch data.MFAType {
case model.MFATypeOTP:
- l.handleOtpCreation(w, r, authReq, data)
+ l.handleOTPCreation(w, r, authReq, data)
+ return
+ case model.MFATypeU2F:
+ l.renderRegisterU2F(w, r, authReq, nil)
return
}
- l.renderError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-Or3HO", "Errors.User.Mfa.NoProviders"))
+ l.renderError(w, r, authReq, caos_errs.ThrowPreconditionFailed(nil, "APP-Or3HO", "Errors.User.MFA.NoProviders"))
}
-func (l *Login) handleOtpCreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) {
- otp, err := l.authRepo.AddMfaOTP(setContext(r.Context(), authReq.UserOrgID), authReq.UserID)
+func (l *Login) handleOTPCreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) {
+ otp, err := l.authRepo.AddMFAOTP(setContext(r.Context(), authReq.UserOrgID), authReq.UserID)
if err != nil {
l.renderError(w, r, authReq, err)
return
@@ -96,5 +99,5 @@ func (l *Login) handleOtpCreation(w http.ResponseWriter, r *http.Request, authRe
Secret: otp.SecretString,
Url: otp.Url,
}
- l.renderMfaInitVerify(w, r, authReq, data, nil)
+ l.renderMFAInitVerify(w, r, authReq, data, nil)
}
diff --git a/internal/ui/login/handler/mfa_verify_handler.go b/internal/ui/login/handler/mfa_verify_handler.go
index 3c22f854ae..d2819afd1c 100644
--- a/internal/ui/login/handler/mfa_verify_handler.go
+++ b/internal/ui/login/handler/mfa_verify_handler.go
@@ -8,24 +8,24 @@ import (
)
const (
- tmplMfaVerify = "mfaverify"
+ tmplMFAVerify = "mfaverify"
)
type mfaVerifyFormData struct {
- MfaType model.MFAType `schema:"mfaType"`
+ MFAType model.MFAType `schema:"mfaType"`
Code string `schema:"code"`
}
-func (l *Login) handleMfaVerify(w http.ResponseWriter, r *http.Request) {
+func (l *Login) handleMFAVerify(w http.ResponseWriter, r *http.Request) {
data := new(mfaVerifyFormData)
authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil {
l.renderError(w, r, authReq, err)
return
}
- if data.MfaType == model.MFATypeOTP {
+ if data.MFAType == model.MFATypeOTP {
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
- err = l.authRepo.VerifyMfaOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Code, userAgentID, model.BrowserInfoFromRequest(r))
+ err = l.authRepo.VerifyMFAOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Code, userAgentID, model.BrowserInfoFromRequest(r))
}
if err != nil {
l.renderError(w, r, authReq, err)
@@ -34,15 +34,23 @@ func (l *Login) handleMfaVerify(w http.ResponseWriter, r *http.Request) {
l.renderNextStep(w, r, authReq)
}
-func (l *Login) renderMfaVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MfaVerificationStep, err error) {
+func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MFAVerificationStep, err error) {
var errType, errMessage string
if err != nil {
errMessage = l.getErrorMessage(r, err)
}
- data := l.getUserData(r, authReq, "Mfa Verify", errType, errMessage)
- if verificationStep != nil {
- data.MfaProviders = verificationStep.MfaProviders
- data.SelectedMfaProvider = verificationStep.MfaProviders[0]
+ data := l.getUserData(r, authReq, "MFA Verify", errType, errMessage)
+ if verificationStep == nil {
+ l.renderError(w, r, authReq, err)
+ return
}
- l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaVerify], data, nil)
+ switch verificationStep.MFAProviders[len(verificationStep.MFAProviders)-1] {
+ case model.MFATypeU2F:
+ l.renderU2FVerification(w, r, authReq, nil)
+ return
+ case model.MFATypeOTP:
+ data.MFAProviders = verificationStep.MFAProviders
+ data.SelectedMFAProvider = model.MFATypeOTP
+ }
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAVerify], data, nil)
}
diff --git a/internal/ui/login/handler/mfa_verify_u2f_handler.go b/internal/ui/login/handler/mfa_verify_u2f_handler.go
new file mode 100644
index 0000000000..51b734ab0a
--- /dev/null
+++ b/internal/ui/login/handler/mfa_verify_u2f_handler.go
@@ -0,0 +1,59 @@
+package handler
+
+import (
+ "encoding/base64"
+ "net/http"
+
+ http_mw "github.com/caos/zitadel/internal/api/http/middleware"
+ "github.com/caos/zitadel/internal/auth_request/model"
+ user_model "github.com/caos/zitadel/internal/user/model"
+)
+
+const (
+ tmplU2FVerification = "u2fverification"
+)
+
+func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
+ var errType, errMessage, credentialData string
+ var webAuthNLogin *user_model.WebAuthNLogin
+ if err == nil {
+ userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
+ webAuthNLogin, err = l.authRepo.BeginMFAU2FLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID)
+ }
+ if err != nil {
+ errMessage = l.getErrorMessage(r, err)
+ }
+ if webAuthNLogin != nil {
+ credentialData = base64.RawURLEncoding.EncodeToString(webAuthNLogin.CredentialAssertionData)
+ }
+ data := &webAuthNData{
+ userData: l.getUserData(r, authReq, "Login WebAuthNToken", errType, errMessage),
+ CredentialCreationData: credentialData,
+ }
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplU2FVerification], data, nil)
+}
+
+func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) {
+ formData := new(webAuthNFormData)
+ authReq, err := l.getAuthRequestAndParseData(r, formData)
+ if err != nil {
+ l.renderError(w, r, authReq, err)
+ return
+ }
+ if formData.Recreate {
+ l.renderU2FVerification(w, r, authReq, nil)
+ return
+ }
+ credData, err := base64.URLEncoding.DecodeString(formData.CredentialData)
+ if err != nil {
+ l.renderU2FVerification(w, r, authReq, err)
+ return
+ }
+ userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
+ err = l.authRepo.VerifyMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID, credData, model.BrowserInfoFromRequest(r))
+ if err != nil {
+ l.renderU2FVerification(w, r, authReq, err)
+ return
+ }
+ l.renderNextStep(w, r, authReq)
+}
diff --git a/internal/ui/login/handler/passwordless_login_handler.go b/internal/ui/login/handler/passwordless_login_handler.go
new file mode 100644
index 0000000000..116f0b9cbf
--- /dev/null
+++ b/internal/ui/login/handler/passwordless_login_handler.go
@@ -0,0 +1,59 @@
+package handler
+
+import (
+ "encoding/base64"
+ "net/http"
+
+ http_mw "github.com/caos/zitadel/internal/api/http/middleware"
+ "github.com/caos/zitadel/internal/auth_request/model"
+ user_model "github.com/caos/zitadel/internal/user/model"
+)
+
+const (
+ tmplPasswordlessVerification = "passwordlessverification"
+)
+
+func (l *Login) renderPasswordlessVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
+ var errType, errMessage, credentialData string
+ var webAuthNLogin *user_model.WebAuthNLogin
+ if err == nil {
+ userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
+ webAuthNLogin, err = l.authRepo.BeginPasswordlessLogin(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID)
+ }
+ if err != nil {
+ errMessage = l.getErrorMessage(r, err)
+ }
+ if webAuthNLogin != nil {
+ credentialData = base64.RawURLEncoding.EncodeToString(webAuthNLogin.CredentialAssertionData)
+ }
+ data := &webAuthNData{
+ userData: l.getUserData(r, authReq, "Login Passwordless", errType, errMessage),
+ CredentialCreationData: credentialData,
+ }
+ l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordlessVerification], data, nil)
+}
+
+func (l *Login) handlePasswordlessVerification(w http.ResponseWriter, r *http.Request) {
+ formData := new(webAuthNFormData)
+ authReq, err := l.getAuthRequestAndParseData(r, formData)
+ if err != nil {
+ l.renderError(w, r, authReq, err)
+ return
+ }
+ if formData.Recreate {
+ l.renderPasswordlessVerification(w, r, authReq, nil)
+ return
+ }
+ credData, err := base64.URLEncoding.DecodeString(formData.CredentialData)
+ if err != nil {
+ l.renderPasswordlessVerification(w, r, authReq, err)
+ return
+ }
+ userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
+ err = l.authRepo.VerifyPasswordless(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID, credData, model.BrowserInfoFromRequest(r))
+ if err != nil {
+ l.renderPasswordlessVerification(w, r, authReq, err)
+ return
+ }
+ l.renderNextStep(w, r, authReq)
+}
diff --git a/internal/ui/login/handler/renderer.go b/internal/ui/login/handler/renderer.go
index 7b1d563551..dad96049cb 100644
--- a/internal/ui/login/handler/renderer.go
+++ b/internal/ui/login/handler/renderer.go
@@ -3,18 +3,19 @@ package handler
import (
"errors"
"fmt"
- "github.com/caos/logging"
- iam_model "github.com/caos/zitadel/internal/iam/model"
- "github.com/gorilla/csrf"
- "golang.org/x/text/language"
"html/template"
"net/http"
"path"
+ "github.com/caos/logging"
+ "github.com/gorilla/csrf"
+ "golang.org/x/text/language"
+
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/auth_request/model"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/i18n"
+ iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/renderer"
)
@@ -32,31 +33,34 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
pathPrefix: pathPrefix,
}
tmplMapping := map[string]string{
- tmplError: "error.html",
- tmplLogin: "login.html",
- tmplUserSelection: "select_user.html",
- tmplPassword: "password.html",
- tmplMfaVerify: "mfa_verify.html",
- tmplMfaPrompt: "mfa_prompt.html",
- tmplMfaInitVerify: "mfa_init_verify.html",
- tmplMfaInitDone: "mfa_init_done.html",
- tmplMailVerification: "mail_verification.html",
- tmplMailVerified: "mail_verified.html",
- tmplInitPassword: "init_password.html",
- tmplInitPasswordDone: "init_password_done.html",
- tmplInitUser: "init_user.html",
- tmplInitUserDone: "init_user_done.html",
- tmplPasswordResetDone: "password_reset_done.html",
- tmplChangePassword: "change_password.html",
- tmplChangePasswordDone: "change_password_done.html",
- tmplRegisterOption: "register_option.html",
- tmplRegister: "register.html",
- tmplLogoutDone: "logout_done.html",
- tmplRegisterOrg: "register_org.html",
- tmplChangeUsername: "change_username.html",
- tmplChangeUsernameDone: "change_username_done.html",
- tmplLinkUsersDone: "link_users_done.html",
- tmplExternalNotFoundOption: "external_not_found_option.html",
+ tmplError: "error.html",
+ tmplLogin: "login.html",
+ tmplUserSelection: "select_user.html",
+ tmplPassword: "password.html",
+ tmplPasswordlessVerification: "passwordless.html",
+ tmplMFAVerify: "mfa_verify.html",
+ tmplMFAPrompt: "mfa_prompt.html",
+ tmplMFAInitVerify: "mfa_init_verify.html",
+ tmplMFAU2FInit: "mfa_init_u2f.html",
+ tmplU2FVerification: "mfa_verification_u2f.html",
+ tmplMFAInitDone: "mfa_init_done.html",
+ tmplMailVerification: "mail_verification.html",
+ tmplMailVerified: "mail_verified.html",
+ tmplInitPassword: "init_password.html",
+ tmplInitPasswordDone: "init_password_done.html",
+ tmplInitUser: "init_user.html",
+ tmplInitUserDone: "init_user_done.html",
+ tmplPasswordResetDone: "password_reset_done.html",
+ tmplChangePassword: "change_password.html",
+ tmplChangePasswordDone: "change_password_done.html",
+ tmplRegisterOption: "register_option.html",
+ tmplRegister: "register.html",
+ tmplLogoutDone: "logout_done.html",
+ tmplRegisterOrg: "register_org.html",
+ tmplChangeUsername: "change_username.html",
+ tmplChangeUsernameDone: "change_username_done.html",
+ tmplLinkUsersDone: "link_users_done.html",
+ tmplExternalNotFoundOption: "external_not_found_option.html",
}
funcs := map[string]interface{}{
"resourceUrl": func(file string) string {
@@ -86,6 +90,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
"userSelectionUrl": func() string {
return path.Join(r.pathPrefix, EndpointUserSelection)
},
+ "passwordLessVerificationUrl": func() string {
+ return path.Join(r.pathPrefix, EndpointPasswordlessLogin)
+ },
"passwordResetUrl": func(id string) string {
return path.Join(r.pathPrefix, fmt.Sprintf("%s?%s=%s", EndpointPasswordReset, queryAuthRequestID, id))
},
@@ -93,16 +100,22 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, cookieName str
return path.Join(r.pathPrefix, EndpointPassword)
},
"mfaVerifyUrl": func() string {
- return path.Join(r.pathPrefix, EndpointMfaVerify)
+ return path.Join(r.pathPrefix, EndpointMFAVerify)
},
"mfaPromptUrl": func() string {
- return path.Join(r.pathPrefix, EndpointMfaPrompt)
+ return path.Join(r.pathPrefix, EndpointMFAPrompt)
},
"mfaPromptChangeUrl": func(id string, provider model.MFAType) string {
- return path.Join(r.pathPrefix, fmt.Sprintf("%s?%s=%s;%s=%v", EndpointMfaPrompt, queryAuthRequestID, id, "provider", provider))
+ return path.Join(r.pathPrefix, fmt.Sprintf("%s?%s=%s;%s=%v", EndpointMFAPrompt, queryAuthRequestID, id, "provider", provider))
},
"mfaInitVerifyUrl": func() string {
- return path.Join(r.pathPrefix, EndpointMfaInitVerify)
+ return path.Join(r.pathPrefix, EndpointMFAInitVerify)
+ },
+ "mfaInitU2FVerifyUrl": func() string {
+ return path.Join(r.pathPrefix, EndpointMFAInitU2FVerify)
+ },
+ "mfaInitU2FLoginUrl": func() string {
+ return path.Join(r.pathPrefix, EndpointU2FVerification)
},
"mailVerificationUrl": func() string {
return path.Join(r.pathPrefix, EndpointMailVerification)
@@ -190,8 +203,10 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
l.renderInitPassword(w, r, authReq, authReq.UserID, "", err)
case *model.PasswordStep:
l.renderPassword(w, r, authReq, nil)
- case *model.MfaVerificationStep:
- l.renderMfaVerify(w, r, authReq, step, err)
+ case *model.PasswordlessStep:
+ l.renderPasswordlessVerification(w, r, authReq, nil)
+ case *model.MFAVerificationStep:
+ l.renderMFAVerify(w, r, authReq, step, err)
case *model.RedirectToCallbackStep:
if len(authReq.PossibleSteps) > 1 {
l.chooseNextStep(w, r, authReq, 1, err)
@@ -202,8 +217,8 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
l.renderChangePassword(w, r, authReq, err)
case *model.VerifyEMailStep:
l.renderMailVerification(w, r, authReq, "", err)
- case *model.MfaPromptStep:
- l.renderMfaPrompt(w, r, authReq, step, err)
+ case *model.MFAPromptStep:
+ l.renderMFAPrompt(w, r, authReq, step, err)
case *model.InitUserStep:
l.renderInitUser(w, r, authReq, "", "", step.PasswordSet, nil)
case *model.ChangeUsernameStep:
@@ -356,8 +371,8 @@ type userData struct {
baseData
profileData
PasswordChecked string
- MfaProviders []model.MFAType
- SelectedMfaProvider model.MFAType
+ MFAProviders []model.MFAType
+ SelectedMFAProvider model.MFAType
Linking bool
}
@@ -386,21 +401,21 @@ type userSelectionData struct {
type mfaData struct {
baseData
profileData
- MfaProviders []model.MFAType
- MfaRequired bool
+ MFAProviders []model.MFAType
+ MFARequired bool
}
type mfaVerifyData struct {
baseData
profileData
- MfaType model.MFAType
+ MFAType model.MFAType
otpData
}
type mfaDoneData struct {
baseData
profileData
- MfaType model.MFAType
+ MFAType model.MFAType
}
type otpData struct {
diff --git a/internal/ui/login/handler/router.go b/internal/ui/login/handler/router.go
index 7b1651b9eb..6d3b8cde36 100644
--- a/internal/ui/login/handler/router.go
+++ b/internal/ui/login/handler/router.go
@@ -13,6 +13,7 @@ const (
EndpointLogin = "/login"
EndpointExternalLogin = "/login/externalidp"
EndpointExternalLoginCallback = "/login/externalidp/callback"
+ EndpointPasswordlessLogin = "/login/passwordless"
EndpointLoginName = "/loginname"
EndpointUserSelection = "/userselection"
EndpointChangeUsername = "/username/change"
@@ -21,9 +22,11 @@ const (
EndpointChangePassword = "/password/change"
EndpointPasswordReset = "/password/reset"
EndpointInitUser = "/user/init"
- EndpointMfaVerify = "/mfa/verify"
- EndpointMfaPrompt = "/mfa/prompt"
- EndpointMfaInitVerify = "/mfa/init/verify"
+ EndpointMFAVerify = "/mfa/verify"
+ EndpointMFAPrompt = "/mfa/prompt"
+ EndpointMFAInitVerify = "/mfa/init/verify"
+ EndpointMFAInitU2FVerify = "/mfa/init/u2f/verify"
+ EndpointU2FVerification = "/mfa/u2f/verify"
EndpointMailVerification = "/mail/verification"
EndpointMailVerified = "/mail/verified"
EndpointRegisterOption = "/register/option"
@@ -46,6 +49,7 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
router.HandleFunc(EndpointLogin, login.handleLogin).Methods(http.MethodGet, http.MethodPost)
router.HandleFunc(EndpointExternalLogin, login.handleExternalLogin).Methods(http.MethodGet)
router.HandleFunc(EndpointExternalLoginCallback, login.handleExternalLoginCallback).Methods(http.MethodGet)
+ router.HandleFunc(EndpointPasswordlessLogin, login.handlePasswordlessVerification).Methods(http.MethodPost)
router.HandleFunc(EndpointLoginName, login.handleLoginName).Methods(http.MethodGet)
router.HandleFunc(EndpointLoginName, login.handleLoginNameCheck).Methods(http.MethodPost)
router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost)
@@ -56,10 +60,12 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
router.HandleFunc(EndpointPasswordReset, login.handlePasswordReset).Methods(http.MethodGet)
router.HandleFunc(EndpointInitUser, login.handleInitUser).Methods(http.MethodGet)
router.HandleFunc(EndpointInitUser, login.handleInitUserCheck).Methods(http.MethodPost)
- router.HandleFunc(EndpointMfaVerify, login.handleMfaVerify).Methods(http.MethodPost)
- router.HandleFunc(EndpointMfaPrompt, login.handleMfaPromptSelection).Methods(http.MethodGet)
- router.HandleFunc(EndpointMfaPrompt, login.handleMfaPrompt).Methods(http.MethodPost)
- router.HandleFunc(EndpointMfaInitVerify, login.handleMfaInitVerify).Methods(http.MethodPost)
+ router.HandleFunc(EndpointMFAVerify, login.handleMFAVerify).Methods(http.MethodPost)
+ router.HandleFunc(EndpointMFAPrompt, login.handleMFAPromptSelection).Methods(http.MethodGet)
+ router.HandleFunc(EndpointMFAPrompt, login.handleMFAPrompt).Methods(http.MethodPost)
+ router.HandleFunc(EndpointMFAInitVerify, login.handleMFAInitVerify).Methods(http.MethodPost)
+ router.HandleFunc(EndpointMFAInitU2FVerify, login.handleRegisterU2F).Methods(http.MethodPost)
+ router.HandleFunc(EndpointU2FVerification, login.handleU2FVerification).Methods(http.MethodPost)
router.HandleFunc(EndpointMailVerification, login.handleMailVerification).Methods(http.MethodGet)
router.HandleFunc(EndpointMailVerification, login.handleMailVerificationCheck).Methods(http.MethodPost)
router.HandleFunc(EndpointChangePassword, login.handleChangePassword).Methods(http.MethodPost)
diff --git a/internal/ui/login/handler/webauthn.go b/internal/ui/login/handler/webauthn.go
new file mode 100644
index 0000000000..83ade70060
--- /dev/null
+++ b/internal/ui/login/handler/webauthn.go
@@ -0,0 +1,12 @@
+package handler
+
+type webAuthNData struct {
+ userData
+ CredentialCreationData string
+}
+
+type webAuthNFormData struct {
+ CredentialData string `schema:"credentialData"`
+ Name string `schema:"name"`
+ Recreate bool `schema:"recreate"`
+}
diff --git a/internal/ui/login/static/i18n/de.yaml b/internal/ui/login/static/i18n/de.yaml
index 0954839834..165d5eb443 100644
--- a/internal/ui/login/static/i18n/de.yaml
+++ b/internal/ui/login/static/i18n/de.yaml
@@ -35,10 +35,10 @@ UsernameChangeDone:
Title: Username geändert
Description: Der Username wurde erfolgreich geändert.
-MfaVerify:
+MFAVerify:
Title: Multifaktor verifizieren
Description: Verifiziere deinen Multifaktor
- OTP: OTP
+ OTP: OTP (One Time Password)
Code: Code
InitPassword:
@@ -63,23 +63,41 @@ InitUserDone:
Title: User aktiviert
Description: EMail verifiziert und Passwort erfolgreich gesetzt
-MfaPrompt:
+MFAPrompt:
Title: Multifaktor hinzufügen
Description: Möchtest du einen Mulitfaktor hinzufügen?
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
-MfaInitVerify:
+MFAInitVerify:
Title: Multifaktor Verifizierung
Description: Verifiziere deinen Multifaktor
- OtpDescription: Scanne den Code mit einem Authentifizierungs-App (z.B Google Authentificator) oder kopiere das Secret und gib anschliessend den Code ein.
+ OTPDescription: Scanne den Code mit einem Authentifizierungs-App (z.B Google Authenticator) oder kopiere das Secret und gib anschliessend den Code ein.
Secret: Secret
Code: Code
-MfaInitDone:
+MFAInitDone:
Title: Multifaktor Verifizierung erstellt
Description: Multifikator Verifizierung erfolgreich abgeschlossen. Der Multifaktor muss bei jeder Anmeldung eingegeben werden, dies beinhaltet auch den aktuellen Authentifizierungs Prozess.
+MFAInitU2F:
+ Title: Multifaktor U2F / WebAuthN hinzufügen
+ Description: Füge dein Token hinzu, indem du einen Namen eingibst und den 'Token registrieren' Button drückst.
+
+MFAVerifyU2F:
+ Title: Multifaktor Verifizierung
+ Description: Verifiziere deinen Multifaktor U2F / WebAuthN Token
+
+WebAuthN:
+ Name: Name des Tokens / Geräts
+ NotSupported: WebAuthN wird durch deinen Browser nicht unterstützt. Stelle sicher, dass du die aktuelle Version installiert hast oder nutze einen anderen (z.B. Chrome, Safari, Firefox)
+ Error:
+ Retry: Versuche es erneut, erstelle eine neue Abfrage oder wähle einen andere Methode.
+
+Passwordless:
+ Title: Passwortlos einloggen
+ Description: Verifiziere dein Token
+
PasswordChange:
Title: Passwort ändern
Description: Ändere dein Password in dem du dein altes und dann dein neuen Passwort eingibst.
@@ -181,6 +199,9 @@ Actions:
ForgotPassword: Password zurücksetzen
Cancel: Abbrechen
Save: speichern
+ RegisterToken: Token registrieren
+ ValidateToken: Token validieren
+ Recreate: erneut erstellen
Errors:
Internal: Es ist ein interner Fehler aufgetreten
@@ -215,9 +236,9 @@ Errors:
GeneratorAlgNotSupported: Generator Algorithums wird nicht unterstützt
EmailVerify:
UserIDEmpty: UserID ist leer
- Mfa:
+ MFA:
NoProviders: Es stehen keine Multifaktorprovider zur Verfügung
- Otp:
+ OTP:
AlreadyReady: Multifaktor OTP (OneTimePassword) ist bereits eingerichtet
NotExisting: Multifaktor OTP (OneTimePassword) existiert nicht
InvalidCode: Code ist ungültig
diff --git a/internal/ui/login/static/i18n/en.yaml b/internal/ui/login/static/i18n/en.yaml
index ffaff11d73..f1c0d1f555 100644
--- a/internal/ui/login/static/i18n/en.yaml
+++ b/internal/ui/login/static/i18n/en.yaml
@@ -35,10 +35,10 @@ UsernameChangeDone:
Title: Username changed
Description: Your username was changed successfully.
-MfaVerify:
+MFAVerify:
Title: Verify Multificator
Description: Verify your multifactor
- OTP: OTP
+ OTP: OTP (One Time Password)
Code: Code
InitPassword:
@@ -63,23 +63,41 @@ InitUserDone:
Title: User activated
Description: Email verified and Password successfully set
-MfaPrompt:
+MFAPrompt:
Title: Multifactor Setup
Description: Would you like to setup multifactor authentication?
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
-MfaInitVerify:
+MFAInitVerify:
Title: Multifactor Verification
Description: Verify your multifactor.
- OtpDescription: Scan the code with your authenticator app (e.g Google-Authenticator) or copy the secret and insert the generated code below.
+ OTPDescription: Scan the code with your authenticator app (e.g Google Authenticator) or copy the secret and insert the generated code below.
Secret: Secret
Code: Code
-MfaInitDone:
+MFAInitDone:
Title: Multifcator Verification done
Description: Multifactor verification successfully done. The multifactor has to be entered on each login, even in the actual authentification process.
+MFAInitU2F:
+ Title: Multifactor Setup U2F / WebAuthN
+ Description: Add your Token by providing a name and then clicking on the 'Register Token' button below.
+
+MFAVerifyU2F:
+ Title: Multifactor Verification
+ Description: Verify your multifactor U2F / WebAuthN token
+
+WebAuthN:
+ Name: Name of the tokens / machine
+ NotSupported: WebAuthN is not supported by your browser. Please ensure it is up to date or use a different one (e.g. Chrome, Safari, Firefox)
+ Error:
+ Retry: Retry, create a new challenge or choose a different method.
+
+Passwordless:
+ Title: Login passwordles
+ Description: Verify your token
+
PasswordChange:
Title: Change Password
Description: Change your password. Enter your old and new password.
@@ -181,6 +199,9 @@ Actions:
ForgotPassword: reset password
Cancel: cancel
Save: save
+ RegisterToken: Register Token
+ ValidateToken: Validate Token
+ Recreate: recreate
Errors:
Internal: An internal error occured
@@ -215,9 +236,9 @@ Errors:
GeneratorAlgNotSupported: Unsupported generator algorithm
EmailVerify:
UserIDEmpty: UserID is empty
- Mfa:
+ MFA:
NoProviders: No available multifactor providers
- Otp:
+ OTP:
AlreadyReady: Multifactor OTP (OneTimePassword) is already setup
NotExisting: Multifactor OTP (OneTimePassword) doesn't exist
InvalidCode: Invalid code
diff --git a/internal/ui/login/static/resources/scripts/base64.js b/internal/ui/login/static/resources/scripts/base64.js
new file mode 100644
index 0000000000..075fe9d48d
--- /dev/null
+++ b/internal/ui/login/static/resources/scripts/base64.js
@@ -0,0 +1,68 @@
+/*
+ * modified version of:
+ *
+ * base64-arraybuffer
+ * https://github.com/niklasvh/base64-arraybuffer
+ *
+ * Copyright (c) 2012 Niklas von Hertzen
+ * Licensed under the MIT license.
+ */
+
+"use strict";
+
+let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+// Use a lookup table to find the index.
+let lookup = new Uint8Array(256);
+for (var i = 0; i < chars.length; i++) {
+ lookup[chars.charCodeAt(i)] = i;
+}
+
+function encode(arraybuffer) {
+ let bytes = new Uint8Array(arraybuffer),
+ i, len = bytes.length, base64 = "";
+
+ for (i = 0; i < len; i += 3) {
+ base64 += chars[bytes[i] >> 2];
+ base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
+ base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
+ base64 += chars[bytes[i + 2] & 63];
+ }
+
+ if ((len % 3) === 2) {
+ base64 = base64.substring(0, base64.length - 1) + "=";
+ } else if (len % 3 === 1) {
+ base64 = base64.substring(0, base64.length - 2) + "==";
+ }
+
+ return base64;
+}
+
+function decode(base64) {
+ let bufferLength = base64.length * 0.75,
+ len = base64.length, i, p = 0,
+ encoded1, encoded2, encoded3, encoded4;
+
+ if (base64[base64.length - 1] === "=") {
+ bufferLength--;
+ if (base64[base64.length - 2] === "=") {
+ bufferLength--;
+ }
+ }
+
+ let arraybuffer = new ArrayBuffer(bufferLength),
+ bytes = new Uint8Array(arraybuffer);
+
+ for (i = 0; i < len; i += 4) {
+ encoded1 = lookup[base64.charCodeAt(i)];
+ encoded2 = lookup[base64.charCodeAt(i + 1)];
+ encoded3 = lookup[base64.charCodeAt(i + 2)];
+ encoded4 = lookup[base64.charCodeAt(i + 3)];
+
+ bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
+ bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
+ bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
+ }
+
+ return arraybuffer;
+}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/scripts/webauthn.js b/internal/ui/login/static/resources/scripts/webauthn.js
new file mode 100644
index 0000000000..74c54c4db5
--- /dev/null
+++ b/internal/ui/login/static/resources/scripts/webauthn.js
@@ -0,0 +1,31 @@
+function checkWebauthnSupported(button, func) {
+ let support = document.getElementsByClassName("wa-support");
+ let noSupport = document.getElementsByClassName("wa-no-support");
+ if (typeof (PublicKeyCredential) === undefined) {
+ for (let item of noSupport) {
+ item.classList.remove('hidden');
+ }
+ for (let item of support) {
+ item.classList.add('hidden');
+ }
+ return
+ }
+ document.getElementById(button).addEventListener('click', func);
+}
+
+function webauthnError(error) {
+ let err = document.getElementById('wa-error');
+ err.getElementsByClassName('cause')[0].innerText = error.message;
+ err.classList.remove('hidden');
+}
+
+function bufferDecode(value) {
+ return decode(value);
+}
+
+function bufferEncode(value) {
+ return encode(value)
+ .replace(/\+/g, "-")
+ .replace(/\//g, "_")
+ .replace(/=/g, "");
+}
diff --git a/internal/ui/login/static/resources/scripts/webauthn_login.js b/internal/ui/login/static/resources/scripts/webauthn_login.js
new file mode 100644
index 0000000000..a9264ffe1f
--- /dev/null
+++ b/internal/ui/login/static/resources/scripts/webauthn_login.js
@@ -0,0 +1,42 @@
+document.addEventListener('DOMContentLoaded', checkWebauthnSupported('btn-login', login));
+
+function login() {
+ document.getElementById('wa-error').classList.add('hidden');
+
+ let makeAssertionOptions = JSON.parse(atob(document.getElementsByName('credentialAssertionData')[0].value));
+ makeAssertionOptions.publicKey.challenge = bufferDecode(makeAssertionOptions.publicKey.challenge);
+ makeAssertionOptions.publicKey.allowCredentials.forEach(function (listItem) {
+ listItem.id = bufferDecode(listItem.id)
+ });
+ console.log(makeAssertionOptions);
+ navigator.credentials.get({
+ publicKey: makeAssertionOptions.publicKey
+ }).then(function (credential) {
+ verifyAssertion(credential);
+ }).catch(function (err) {
+ webauthnError(err);
+ });
+}
+
+function verifyAssertion(assertedCredential) {
+ let authData = new Uint8Array(assertedCredential.response.authenticatorData);
+ let clientDataJSON = new Uint8Array(assertedCredential.response.clientDataJSON);
+ let rawId = new Uint8Array(assertedCredential.rawId);
+ let sig = new Uint8Array(assertedCredential.response.signature);
+ let userHandle = new Uint8Array(assertedCredential.response.userHandle);
+
+ let data = JSON.stringify({
+ id: assertedCredential.id,
+ rawId: bufferEncode(rawId),
+ type: assertedCredential.type,
+ response: {
+ authenticatorData: bufferEncode(authData),
+ clientDataJSON: bufferEncode(clientDataJSON),
+ signature: bufferEncode(sig),
+ userHandle: bufferEncode(userHandle),
+ },
+ })
+
+ document.getElementsByName('credentialData')[0].value = btoa(data);
+ document.getElementsByTagName('form')[0].submit();
+}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/scripts/webauthn_register.js b/internal/ui/login/static/resources/scripts/webauthn_register.js
new file mode 100644
index 0000000000..153f6f1abf
--- /dev/null
+++ b/internal/ui/login/static/resources/scripts/webauthn_register.js
@@ -0,0 +1,42 @@
+document.addEventListener('DOMContentLoaded', checkWebauthnSupported('btn-register', registerCredential));
+
+function registerCredential() {
+ document.getElementById('wa-error').classList.add('hidden');
+
+ let opt = JSON.parse(atob(document.getElementsByName('credentialCreationData')[0].value));
+ opt.publicKey.challenge = bufferDecode(opt.publicKey.challenge);
+ opt.publicKey.user.id = bufferDecode(opt.publicKey.user.id);
+ if (opt.publicKey.excludeCredentials) {
+ for (let i = 0; i < opt.publicKey.excludeCredentials.length; i++) {
+ if (opt.publicKey.excludeCredentials[i].id !== null) {
+ opt.publicKey.excludeCredentials[i].id = bufferDecode(opt.publicKey.excludeCredentials[i].id);
+ }
+ }
+ }
+ navigator.credentials.create({
+ publicKey: opt.publicKey
+ }).then(function (credential) {
+ createCredential(credential);
+ }).catch(function (err) {
+ webauthnError(err);
+ });
+}
+
+function createCredential(newCredential) {
+ let attestationObject = new Uint8Array(newCredential.response.attestationObject);
+ let clientDataJSON = new Uint8Array(newCredential.response.clientDataJSON);
+ let rawId = new Uint8Array(newCredential.rawId);
+
+ let data = JSON.stringify({
+ id: newCredential.id,
+ rawId: bufferEncode(rawId),
+ type: newCredential.type,
+ response: {
+ attestationObject: bufferEncode(attestationObject),
+ clientDataJSON: bufferEncode(clientDataJSON),
+ },
+ });
+
+ document.getElementsByName('credentialData')[0].value = btoa(data);
+ document.getElementsByTagName('form')[0].submit();
+}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/caos/css/dark.css b/internal/ui/login/static/resources/themes/caos/css/dark.css
index 80a79a848a..d8fd885a54 100644
--- a/internal/ui/login/static/resources/themes/caos/css/dark.css
+++ b/internal/ui/login/static/resources/themes/caos/css/dark.css
@@ -487,4 +487,12 @@ footer {
color: #F20D6B;
}
+.hidden {
+ display: none;
+}
+
+#wa-error {
+ margin-top: 20px;
+}
+
/*# sourceMappingURL=dark.css.map */
diff --git a/internal/ui/login/static/resources/themes/caos/css/dark.css.map b/internal/ui/login/static/resources/themes/caos/css/dark.css.map
index 449a4e6fe6..5890330f09 100644
--- a/internal/ui/login/static/resources/themes/caos/css/dark.css.map
+++ b/internal/ui/login/static/resources/themes/caos/css/dark.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCDc;EDEd,OCDQ;EDER;EACA;EACA;;;AAMJ;EACI,OCXQ;EDYR,aClBS;EDmBT;EACA,WEzBS;EF0BT;;;AAGJ;EACI,OCnBQ;EDoBR,aC1BS;ED2BT;EACA,WEhCU;;;AFmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvDW;EDwDX;EACA;;AAEA;EACI,OC3DY;;AD8DhB;EACI;;;AAIR;EACI,kBCvEc;EDwEd,OCtEW;EDuEX;EACA;EACA;EACA;EACA,QExFU;EFyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCpFY;EDqFZ,OCxFU;EDyFV;;AAGJ;EACI,kBC3FO;ED4FP,OC7FI;ED8FJ;;AACA;EACI,kBC9FQ;;ADkGhB;EACI,kBExFW;EFyFX;;AAEA;EACI,kBE5FO;EF6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEhGa;EFiGb,kBEhGmB;;AFkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBE9HmB;EF+HnB,OC7IQ;ED8IR,QE1JU;EF2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EEzJN;;AACA;EFoJE;IEnJA;IACA;;;AF0JA;EE7JF;;AACA;EF4JE;IE3JA;IACA;;;;AFiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WEvLE;EFwLF;;AAGJ;EACI;EACA;EACA;EACA,OE1KC;;;AFgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC/NA;;ADmOR;EACI,OExNK;EFyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC9PI;ED+PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBExPW;;AF2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEjRO;EFkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE7SP;;AFoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EEvUV;;AACA;EFkUM;IEjUJ;IACA;;;AFyUQ;EACI;EACA;EE9Ud;;AACA;EF2UU;IE1UR;IACA;;;AFgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OErVN;;AF0VE;EACI,OE5VL;;AFiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCxYI;;AD2YR;EACI,MC7YU;;;ADkZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OE5aO","file":"dark.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCDc;EDEd,OCDQ;EDER;EACA;EACA;;;AAMJ;EACI,OCXQ;EDYR,aClBS;EDmBT;EACA,WEzBS;EF0BT;;;AAGJ;EACI,OCnBQ;EDoBR,aC1BS;ED2BT;EACA,WEhCU;;;AFmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvDW;EDwDX;EACA;;AAEA;EACI,OC3DY;;AD8DhB;EACI;;;AAIR;EACI,kBCvEc;EDwEd,OCtEW;EDuEX;EACA;EACA;EACA;EACA,QExFU;EFyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCpFY;EDqFZ,OCxFU;EDyFV;;AAGJ;EACI,kBC3FO;ED4FP,OC7FI;ED8FJ;;AACA;EACI,kBC9FQ;;ADkGhB;EACI,kBExFW;EFyFX;;AAEA;EACI,kBE5FO;EF6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEhGa;EFiGb,kBEhGmB;;AFkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBE9HmB;EF+HnB,OC7IQ;ED8IR,QE1JU;EF2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EEzJN;;AACA;EFoJE;IEnJA;IACA;;;AF0JA;EE7JF;;AACA;EF4JE;IE3JA;IACA;;;;AFiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WEvLE;EFwLF;;AAGJ;EACI;EACA;EACA;EACA,OE1KC;;;AFgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC/NA;;ADmOR;EACI,OExNK;EFyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC9PI;ED+PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBExPW;;AF2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEjRO;EFkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE7SP;;AFoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EEvUV;;AACA;EFkUM;IEjUJ;IACA;;;AFyUQ;EACI;EACA;EE9Ud;;AACA;EF2UU;IE1UR;IACA;;;AFgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OErVN;;AF0VE;EACI,OE5VL;;AFiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCxYI;;AD2YR;EACI,MC7YU;;;ADkZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OE5aO;;;AF+aX;EACI;;;AAGJ;EACI","file":"dark.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/caos/css/light.css b/internal/ui/login/static/resources/themes/caos/css/light.css
index e9168da6da..ed2241a8fe 100644
--- a/internal/ui/login/static/resources/themes/caos/css/light.css
+++ b/internal/ui/login/static/resources/themes/caos/css/light.css
@@ -487,6 +487,14 @@ footer {
color: #F20D6B;
}
+.hidden {
+ display: none;
+}
+
+#wa-error {
+ margin-top: 20px;
+}
+
html {
background-color: white;
color: #282828;
diff --git a/internal/ui/login/static/resources/themes/caos/css/light.css.map b/internal/ui/login/static/resources/themes/caos/css/light.css.map
index aeb7aefcf1..6eb1e80ecf 100644
--- a/internal/ui/login/static/resources/themes/caos/css/light.css.map
+++ b/internal/ui/login/static/resources/themes/caos/css/light.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCDc;EDEd,OCDQ;EDER;EACA;EACA;;;AAMJ;EACI,OCXQ;EDYR,aClBS;EDmBT;EACA,WEzBS;EF0BT;;;AAGJ;EACI,OCnBQ;EDoBR,aC1BS;ED2BT;EACA,WEhCU;;;AFmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvDW;EDwDX;EACA;;AAEA;EACI,OC3DY;;AD8DhB;EACI;;;AAIR;EACI,kBCvEc;EDwEd,OCtEW;EDuEX;EACA;EACA;EACA;EACA,QExFU;EFyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCpFY;EDqFZ,OCxFU;EDyFV;;AAGJ;EACI,kBC3FO;ED4FP,OC7FI;ED8FJ;;AACA;EACI,kBC9FQ;;ADkGhB;EACI,kBExFW;EFyFX;;AAEA;EACI,kBE5FO;EF6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEhGa;EFiGb,kBEhGmB;;AFkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBE9HmB;EF+HnB,OC7IQ;ED8IR,QE1JU;EF2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EEzJN;;AACA;EFoJE;IEnJA;IACA;;;AF0JA;EE7JF;;AACA;EF4JE;IE3JA;IACA;;;;AFiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WEvLE;EFwLF;;AAGJ;EACI;EACA;EACA;EACA,OE1KC;;;AFgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC/NA;;ADmOR;EACI,OExNK;EFyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC9PI;ED+PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBExPW;;AF2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEjRO;EFkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE7SP;;AFoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EEvUV;;AACA;EFkUM;IEjUJ;IACA;;;AFyUQ;EACI;EACA;EE9Ud;;AACA;EF2UU;IE1UR;IACA;;;AFgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OErVN;;AF0VE;EACI,OE5VL;;AFiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCxYI;;AD2YR;EACI,MC7YU;;;ADkZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OE5aO;;;ACrCX;EACI,kBFeQ;EEdR,OFac;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;EACA,ODyBgB;;ACtBpB;EACI,kBFVG;EEWH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBFdI;;AEkBZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,OFhCM;;AEkCN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,OF9EU;;AEkFV;EACI,MFnFM;;AEsFV;EACI,MFtFA;;AE0FR;EAEQ;;;AAMR;EACI,OFpGU;;AEwGb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCMW;EDLX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCDc;EDEd,OCDQ;EDER;EACA;EACA;;;AAMJ;EACI,OCXQ;EDYR,aClBS;EDmBT;EACA,WEzBS;EF0BT;;;AAGJ;EACI,OCnBQ;EDoBR,aC1BS;ED2BT;EACA,WEhCU;;;AFmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvDW;EDwDX;EACA;;AAEA;EACI,OC3DY;;AD8DhB;EACI;;;AAIR;EACI,kBCvEc;EDwEd,OCtEW;EDuEX;EACA;EACA;EACA;EACA,QExFU;EFyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCpFY;EDqFZ,OCxFU;EDyFV;;AAGJ;EACI,kBC3FO;ED4FP,OC7FI;ED8FJ;;AACA;EACI,kBC9FQ;;ADkGhB;EACI,kBExFW;EFyFX;;AAEA;EACI,kBE5FO;EF6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEhGa;EFiGb,kBEhGmB;;AFkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBE9HmB;EF+HnB,OC7IQ;ED8IR,QE1JU;EF2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EEzJN;;AACA;EFoJE;IEnJA;IACA;;;AF0JA;EE7JF;;AACA;EF4JE;IE3JA;IACA;;;;AFiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WEvLE;EFwLF;;AAGJ;EACI;EACA;EACA;EACA,OE1KC;;;AFgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC/NA;;ADmOR;EACI,OExNK;EFyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC9PI;ED+PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBExPW;;AF2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEjRO;EFkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE7SP;;AFoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EEvUV;;AACA;EFkUM;IEjUJ;IACA;;;AFyUQ;EACI;EACA;EE9Ud;;AACA;EF2UU;IE1UR;IACA;;;AFgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OErVN;;AF0VE;EACI,OE5VL;;AFiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCxYI;;AD2YR;EACI,MC7YU;;;ADkZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OE5aO;;;AF+aX;EACI;;;AAGJ;EACI;;;AGzdJ;EACI,kBFeQ;EEdR,OFac;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;EACA,ODyBgB;;ACtBpB;EACI,kBFVG;EEWH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBFdI;;AEkBZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,OFhCM;;AEkCN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,OF9EU;;AEkFV;EACI,MFnFM;;AEsFV;EACI,MFtFA;;AE0FR;EAEQ;;;AAMR;EACI,OFpGU;;AEwGb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/scss/main.scss b/internal/ui/login/static/resources/themes/scss/main.scss
index 2a43896f99..9fb1bf4511 100644
--- a/internal/ui/login/static/resources/themes/scss/main.scss
+++ b/internal/ui/login/static/resources/themes/scss/main.scss
@@ -466,3 +466,11 @@ footer {
.error {
color: $nokColor;
}
+
+.hidden {
+ display: none;
+}
+
+#wa-error {
+ margin-top: 20px;
+}
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/dark.css b/internal/ui/login/static/resources/themes/zitadel/css/dark.css
index 87f37afe9b..f32c2bc0e0 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/dark.css
+++ b/internal/ui/login/static/resources/themes/zitadel/css/dark.css
@@ -487,4 +487,12 @@ footer {
color: #F20D6B;
}
+.hidden {
+ display: none;
+}
+
+#wa-error {
+ margin-top: 20px;
+}
+
/*# sourceMappingURL=dark.css.map */
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map b/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map
index 6bbf67f0ed..3c47167879 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map
+++ b/internal/ui/login/static/resources/themes/zitadel/css/dark.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCQc;EDPd,OCQQ;EDPR;EACA;EACA;EAEI;;;AAIR;EACI,OCFQ;EDGR,aC3BS;ED4BT;EACA,WCzBS;ED0BT;;;AAGJ;EACI,OCVQ;EDWR,aCnCS;EDoCT;EACA,WChCU;;;ADmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC9CW;ED+CX;EACA;;AAEA;EACI,OClDY;;ADqDhB;EACI;;;AAIR;EACI,kBC9Dc;ED+Dd,OC7DW;ED8DX;EACA;EACA;EACA;EACA,QCxFU;EDyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC3EY;ED4EZ,OC/EU;EDgFV;;AAGJ;EACI,kBClFO;EDmFP,OCpFI;EDqFJ;;AACA;EACI,kBCrFQ;;ADyFhB;EACI,kBCxFW;EDyFX;;AAEA;EACI,kBC5FO;ED6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OChGa;EDiGb,kBChGmB;;ADkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBC9HmB;ED+HnB,OCpIQ;EDqIR,QC1JU;ED2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;ECzJN;;AACA;EDoJE;ICnJA;IACA;;;AD0JA;EC7JF;;AACA;ED4JE;IC3JA;IACA;;;;ADiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WCvLE;EDwLF;;AAGJ;EACI;EACA;EACA;EACA,OC1KC;;;ADgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCtNA;;AD0NR;EACI,OCxNK;EDyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCrPI;EDsPJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBCxPW;;AD2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCjRO;EDkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC7SP;;ADoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;ECvUV;;AACA;EDkUM;ICjUJ;IACA;;;ADyUQ;EACI;EACA;EC9Ud;;AACA;ED2UU;IC1UR;IACA;;;ADgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OCrVN;;AD0VE;EACI,OC5VL;;ADiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC/XI;;ADkYR;EACI,MCpYU;;;ADyYd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OC5aO","file":"dark.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCQc;EDPd,OCQQ;EDPR;EACA;EACA;EAEI;;;AAIR;EACI,OCFQ;EDGR,aC3BS;ED4BT;EACA,WCzBS;ED0BT;;;AAGJ;EACI,OCVQ;EDWR,aCnCS;EDoCT;EACA,WChCU;;;ADmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC9CW;ED+CX;EACA;;AAEA;EACI,OClDY;;ADqDhB;EACI;;;AAIR;EACI,kBC9Dc;ED+Dd,OC7DW;ED8DX;EACA;EACA;EACA;EACA,QCxFU;EDyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC3EY;ED4EZ,OC/EU;EDgFV;;AAGJ;EACI,kBClFO;EDmFP,OCpFI;EDqFJ;;AACA;EACI,kBCrFQ;;ADyFhB;EACI,kBCxFW;EDyFX;;AAEA;EACI,kBC5FO;ED6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OChGa;EDiGb,kBChGmB;;ADkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBC9HmB;ED+HnB,OCpIQ;EDqIR,QC1JU;ED2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;ECzJN;;AACA;EDoJE;ICnJA;IACA;;;AD0JA;EC7JF;;AACA;ED4JE;IC3JA;IACA;;;;ADiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WCvLE;EDwLF;;AAGJ;EACI;EACA;EACA;EACA,OC1KC;;;ADgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCtNA;;AD0NR;EACI,OCxNK;EDyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCrPI;EDsPJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBCxPW;;AD2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCjRO;EDkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC7SP;;ADoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;ECvUV;;AACA;EDkUM;ICjUJ;IACA;;;ADyUQ;EACI;EACA;EC9Ud;;AACA;ED2UU;IC1UR;IACA;;;ADgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OCrVN;;AD0VE;EACI,OC5VL;;ADiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC/XI;;ADkYR;EACI,MCpYU;;;ADyYd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OC5aO;;;AD+aX;EACI;;;AAGJ;EACI","file":"dark.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/light.css b/internal/ui/login/static/resources/themes/zitadel/css/light.css
index 4890c85e1b..6d23b14ad5 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/light.css
+++ b/internal/ui/login/static/resources/themes/zitadel/css/light.css
@@ -487,6 +487,14 @@ footer {
color: #F20D6B;
}
+.hidden {
+ display: none;
+}
+
+#wa-error {
+ margin-top: 20px;
+}
+
html {
background-color: #f5f5f5;
color: #282828;
diff --git a/internal/ui/login/static/resources/themes/zitadel/css/light.css.map b/internal/ui/login/static/resources/themes/zitadel/css/light.css.map
index 0383c7d816..28d354b79b 100644
--- a/internal/ui/login/static/resources/themes/zitadel/css/light.css.map
+++ b/internal/ui/login/static/resources/themes/zitadel/css/light.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCQc;EDPd,OCQQ;EDPR;EACA;EACA;EAEI;;;AAIR;EACI,OCFQ;EDGR,aC3BS;ED4BT;EACA,WCzBS;ED0BT;;;AAGJ;EACI,OCVQ;EDWR,aCnCS;EDoCT;EACA,WChCU;;;ADmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC9CW;ED+CX;EACA;;AAEA;EACI,OClDY;;ADqDhB;EACI;;;AAIR;EACI,kBC9Dc;ED+Dd,OC7DW;ED8DX;EACA;EACA;EACA;EACA,QCxFU;EDyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC3EY;ED4EZ,OC/EU;EDgFV;;AAGJ;EACI,kBClFO;EDmFP,OCpFI;EDqFJ;;AACA;EACI,kBCrFQ;;ADyFhB;EACI,kBCxFW;EDyFX;;AAEA;EACI,kBC5FO;ED6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OChGa;EDiGb,kBChGmB;;ADkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBC9HmB;ED+HnB,OCpIQ;EDqIR,QC1JU;ED2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;ECzJN;;AACA;EDoJE;ICnJA;IACA;;;AD0JA;EC7JF;;AACA;ED4JE;IC3JA;IACA;;;;ADiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WCvLE;EDwLF;;AAGJ;EACI;EACA;EACA;EACA,OC1KC;;;ADgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCtNA;;AD0NR;EACI,OCxNK;EDyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCrPI;EDsPJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBCxPW;;AD2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCjRO;EDkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC7SP;;ADoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;ECvUV;;AACA;EDkUM;ICjUJ;IACA;;;ADyUQ;EACI;EACA;EC9Ud;;AACA;ED2UU;IC1UR;IACA;;;ADgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OCrVN;;AD0VE;EACI,OC5VL;;ADiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC/XI;;ADkYR;EACI,MCpYU;;;ADyYd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OC5aO;;;ACrCX;EACI,kBD2CmB;EC1CnB,ODsBc;ECpBV;;AAGJ;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBD4Be;EC3Bf,ODSO;ECRP;;AAEA;EACI,kBD0Ba;ECzBb;EACA,ODyBgB;;ACtBpB;EACI,kBDDG;ECEH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBDLI;;ACSZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,ODvBM;;ACyBN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,ODrEU;;ACyEV;EACI,MD1EM;;AC6EV;EACI,MD1DW;;ACsEnB;EACI,OD3FU;;AC+Fb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCQc;EDPd,OCQQ;EDPR;EACA;EACA;EAEI;;;AAIR;EACI,OCFQ;EDGR,aC3BS;ED4BT;EACA,WCzBS;ED0BT;;;AAGJ;EACI,OCVQ;EDWR,aCnCS;EDoCT;EACA,WChCU;;;ADmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC9CW;ED+CX;EACA;;AAEA;EACI,OClDY;;ADqDhB;EACI;;;AAIR;EACI,kBC9Dc;ED+Dd,OC7DW;ED8DX;EACA;EACA;EACA;EACA,QCxFU;EDyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC3EY;ED4EZ,OC/EU;EDgFV;;AAGJ;EACI,kBClFO;EDmFP,OCpFI;EDqFJ;;AACA;EACI,kBCrFQ;;ADyFhB;EACI,kBCxFW;EDyFX;;AAEA;EACI,kBC5FO;ED6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OChGa;EDiGb,kBChGmB;;ADkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBC9HmB;ED+HnB,OCpIQ;EDqIR,QC1JU;ED2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;ECzJN;;AACA;EDoJE;ICnJA;IACA;;;AD0JA;EC7JF;;AACA;ED4JE;IC3JA;IACA;;;;ADiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WCvLE;EDwLF;;AAGJ;EACI;EACA;EACA;EACA,OC1KC;;;ADgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCtNA;;AD0NR;EACI,OCxNK;EDyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCrPI;EDsPJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBCxPW;;AD2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCjRO;EDkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC7SP;;ADoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;ECvUV;;AACA;EDkUM;ICjUJ;IACA;;;ADyUQ;EACI;EACA;EC9Ud;;AACA;ED2UU;IC1UR;IACA;;;ADgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OCrVN;;AD0VE;EACI,OC5VL;;ADiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC/XI;;ADkYR;EACI,MCpYU;;;ADyYd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OC5aO;;;AD+aX;EACI;;;AAGJ;EACI;;;AEzdJ;EACI,kBD2CmB;EC1CnB,ODsBc;ECpBV;;AAGJ;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBD4Be;EC3Bf,ODSO;ECRP;;AAEA;EACI,kBD0Ba;ECzBb;EACA,ODyBgB;;ACtBpB;EACI,kBDDG;ECEH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBDLI;;ACSZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,ODvBM;;ACyBN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,ODrEU;;ACyEV;EACI,MD1EM;;AC6EV;EACI,MD1DW;;ACsEnB;EACI,OD3FU;;AC+Fb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}
\ No newline at end of file
diff --git a/internal/ui/login/static/templates/mfa_init_done.html b/internal/ui/login/static/templates/mfa_init_done.html
index 0a233c35ba..7b171e6848 100644
--- a/internal/ui/login/static/templates/mfa_init_done.html
+++ b/internal/ui/login/static/templates/mfa_init_done.html
@@ -3,7 +3,7 @@
{{ template "user-profile" . }}
- {{t "MfaInitDone.Description"}}
+ {{t "MFAInitDone.Description"}}
|