From 8a5badddf602f2894bb8a7b688b7e260528754eb Mon Sep 17 00:00:00 2001 From: Livio Amstutz Date: Fri, 5 Jun 2020 07:50:04 +0200 Subject: [PATCH] feat: Login, OP Support and Auth Queries (#177) * fix: change oidc config * fix: change oidc config secret * begin models * begin repo * fix: implement grpc app funcs * fix: add application requests * fix: converter * fix: converter * fix: converter and generate clientid * fix: tests * feat: project grant aggregate * feat: project grant * fix: project grant check if role existing * fix: project grant requests * fix: project grant fixes * fix: project grant member model * fix: project grant member aggregate * fix: project grant member eventstore * fix: project grant member requests * feat: user model * begin repo * repo models and more * feat: user command side * lots of functions * user command side * profile requests * commit before rebase on user * save * local config with gopass and more * begin new auth command (user centric) * Update internal/user/model/user.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz * Update internal/usergrant/repository/eventsourcing/user_grant.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/user_test.go Co-Authored-By: Livio Amstutz * Update internal/user/repository/eventsourcing/eventstore_mock_test.go Co-Authored-By: Livio Amstutz * changes from mr review * save files into basedir * changes from mr review * changes from mr review * move to auth request * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan * changes requested on mr * fix generate codes * fix return if no events * password code * email verification step * more steps * lot of mfa * begin tests * more next steps * auth api * auth api (user) * auth api (user) * auth api (user) * differ requests * merge * tests * fix compilation error * mock for id generator * Update internal/user/repository/eventsourcing/model/password.go Co-authored-by: Silvan * Update internal/user/repository/eventsourcing/model/user.go Co-authored-by: Silvan * requests of mr * check email * begin separation of command and query * otp * change packages * some cleanup and fixes * tests for auth request / next steps * add VerificationLifetimes to config and make it run * tests * fix code challenge validation * cleanup * fix merge * begin view * repackaging tests and configs * fix startup config for auth * add migration * add PromptSelectAccount * fix copy / paste * remove user_agent files * fixes * fix sequences in user_session * token commands * token queries and signout * fix * fix set password test * add token handler and table * handle session init * add session state * add user view test cases * change VerifyMyMfaOTP * some fixes * fix user repo in auth api * cleanup * add user session view test * fix merge * begin oidc * user agent and more * config * keys * key command and query * add login statics * key handler * start login * login handlers * lot of fixes * merge oidc * add missing exports * add missing exports * fix some bugs * authrequestid in htmls * getrequest * update auth request * fix userid check * add username to authrequest * fix user session and auth request handling * fix UserSessionsByAgentID * fix auth request tests * fix user session on UserPasswordChanged and MfaOtpRemoved * fix MfaTypesSetupPossible * handle mfa * fill username * auth request query checks new events * fix userSessionByIDs * fix tokens * fix userSessionByIDs test * add user selection * init code * user code creation date * add init user step * add verification failed types * add verification failures * verify init code * user init code handle * user init code handle * fix userSessionByIDs * update logging * user agent cookie * browserinfo from request * add DeleteAuthRequest * add static login files to binary * add login statik to build * move generate to separate file and remove statik.go files * remove static dirs from startup.yaml * generate into separate namespaces * merge master * auth request code * auth request type mapping * fix keys * improve tokens * improve register and basic styling * fix ailerons font * improve password reset * add audience to token * all oidc apps as audience * fix test nextStep * fix email texts * remove "not set" * lot of style changes * improve copy to clipboard * fix footer * add cookie handler * remove placeholders * fix compilation after merge * fix auth config * remove comments * typo * use new secrets store * change default pws to match default policy * fixes * add todo * enable login * fix db name * Auth queries (#179) * my usersession * org structure/ auth handlers * working user grant spooler * auth internal user grants * search my project orgs * remove permissions file * my zitadel permissions * my zitadel permissions * remove unused code * authz * app searches in view * token verification * fix user grant load * fix tests * fix tests * read configs * remove unused const * remove todos * env variables * app_name * working authz * search projects * global resourceowner * Update internal/api/auth/permissions.go Co-authored-by: Livio Amstutz * Update internal/api/auth/permissions.go Co-authored-by: Livio Amstutz * model2 rename * at least it works * check token expiry * search my user grants * remove token table from authz Co-authored-by: Livio Amstutz * fix test * fix ports and enable console Co-authored-by: Fabiennne Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com> Co-authored-by: Silvan --- .github/workflows/release.yml | 2 + .gitignore | 2 +- build/console/generate-static.sh | 2 +- build/login/generate-static.sh | 5 + cmd/zitadel/authz.yaml | 2 +- cmd/zitadel/caos_local.sh | 26 +- cmd/zitadel/main.go | 26 +- cmd/zitadel/startup.yaml | 84 +- cmd/zitadel/system-defaults.yaml | 24 +- go.mod | 12 +- go.sum | 30 +- internal/admin/auth/token_verifier.go | 23 +- .../eventsourcing/eventstore/setup_model.go | 9 +- .../repository/eventsourcing/handler/org.go | 6 +- .../repository/eventsourcing/setup/setup.go | 2 +- internal/api/auth/context.go | 8 +- internal/api/auth/permissions.go | 17 +- internal/api/auth/permissions_test.go | 34 +- internal/api/header.go | 2 + internal/api/http/header.go | 71 + internal/api/http/user_agent_cookie.go | 68 + internal/auth/auth/token_verifier.go | 23 +- internal/auth/config.go | 4 - internal/auth/repository/application.go | 12 + internal/auth/repository/auth_request.go | 5 + .../eventsourcing/eventstore/application.go | 31 + .../eventsourcing/eventstore/auth_request.go | 161 +- .../eventstore/auth_request_test.go | 409 +- .../eventsourcing/eventstore/iam.go | 16 + .../eventsourcing/eventstore/key.go | 75 + .../eventsourcing/eventstore/org.go | 29 + .../eventsourcing/eventstore/token.go | 12 +- .../eventsourcing/eventstore/user.go | 44 +- .../eventsourcing/eventstore/user_grant.go | 158 + .../eventsourcing/eventstore/user_session.go | 21 + .../eventsourcing/handler/application.go | 74 + .../eventsourcing/handler/handler.go | 28 +- .../repository/eventsourcing/handler/key.go | 55 + .../repository/eventsourcing/handler/org.go | 64 + .../repository/eventsourcing/handler/user.go | 4 +- .../eventsourcing/handler/user_grant.go | 344 ++ .../eventsourcing/handler/user_session.go | 35 +- .../repository/eventsourcing/repository.go | 87 +- .../eventsourcing/spooler/spooler.go | 5 +- .../eventsourcing/view/application.go | 105 + .../auth/repository/eventsourcing/view/key.go | 72 + .../auth/repository/eventsourcing/view/org.go | 43 + .../repository/eventsourcing/view/token.go | 12 +- .../eventsourcing/view/user_grant.go | 64 + .../eventsourcing/view/user_session.go | 8 +- .../repository/eventsourcing/view/view.go | 13 +- internal/auth/repository/iam.go | 11 + internal/auth/repository/key.go | 14 + internal/auth/repository/repository.go | 4 + internal/auth/repository/token.go | 3 +- internal/auth/repository/user.go | 12 +- internal/auth/repository/user_grant.go | 12 + internal/auth/repository/user_session.go | 10 + internal/auth_request/model/auth_request.go | 85 +- internal/auth_request/model/browser_info.go | 16 +- internal/auth_request/model/next_step.go | 31 +- internal/auth_request/model/request.go | 6 + .../auth_request/repository/cache/cache.go | 47 +- internal/auth_request/repository/gen_mock.go | 2 +- .../repository/mock/repository.go | 12 - .../repository/mock/repository.mock.go | 90 +- .../auth_request/repository/repository.go | 7 +- internal/authz/authz.go | 16 + .../eventsourcing/eventstore/iam.go | 20 + .../eventstore/token_verifier.go | 68 + .../eventsourcing/eventstore/user_grant.go | 102 + .../eventsourcing/handler/application.go | 72 + .../eventsourcing/handler/handler.go | 49 + .../eventsourcing/handler/user_grant.go | 226 + .../repository/eventsourcing/repository.go | 98 + .../repository/eventsourcing/spooler/lock.go | 19 + .../eventsourcing/spooler/lock_test.go | 127 + .../eventsourcing/spooler/spooler.go | 31 + .../eventsourcing/view/application.go | 60 + .../eventsourcing/view/error_event.go | 17 + .../repository/eventsourcing/view/sequence.go | 17 + .../repository/eventsourcing/view/token.go | 59 + .../eventsourcing/view/user_grant.go | 64 + .../repository/eventsourcing/view/view.go | 28 + internal/authz/repository/iam.go | 11 + internal/authz/repository/repository.go | 11 + internal/authz/repository/token_verifier.go | 10 + internal/authz/repository/user_grant.go | 11 + internal/crypto/crypto.go | 20 + internal/crypto/rsa.go | 103 + internal/form/parser.go | 27 + internal/i18n/i18n.go | 128 + .../iam/repository/eventsourcing/model/iam.go | 4 +- .../eventsourcing/model/iam_member.go | 8 +- internal/key/model/key.go | 46 + internal/key/model/key_view.go | 120 + .../repository/eventsourcing/eventstore.go | 84 + internal/key/repository/eventsourcing/key.go | 33 + .../key/repository/eventsourcing/model/key.go | 90 + .../repository/eventsourcing/model/types.go | 9 + internal/key/repository/view/key.go | 70 + internal/key/repository/view/model/key.go | 88 + .../key/repository/view/model/key_query.go | 65 + internal/login/config.go | 4 - internal/login/handler/auth_request.go | 27 + internal/login/handler/callback_handler.go | 11 + .../login/handler/change_password_handler.go | 52 + internal/login/handler/health_handler.go | 18 + .../login/handler/init_password_handler.go | 97 + internal/login/handler/init_user_handler.go | 105 + internal/login/handler/login.go | 92 + internal/login/handler/login_handler.go | 63 + internal/login/handler/logout_handler.go | 20 + internal/login/handler/mail_verify_handler.go | 90 + .../login/handler/mfa_init_done_handler.go | 20 + .../login/handler/mfa_init_verify_handler.go | 95 + internal/login/handler/mfa_prompt_handler.go | 88 + internal/login/handler/mfa_verify_handler.go | 49 + internal/login/handler/password_handler.go | 42 + .../login/handler/password_reset_handler.go | 32 + internal/login/handler/register_handler.go | 119 + internal/login/handler/renderer.go | 260 + internal/login/handler/resources_handler.go | 9 + internal/login/handler/router.go | 58 + internal/login/handler/select_user_handler.go | 42 + internal/login/login.go | 17 + internal/login/static/i18n/de.yaml | 119 + internal/login/static/i18n/en.yaml | 119 + .../resources/fonts/ailerons/ailerons.otf | Bin 0 -> 10676 bytes .../resources/fonts/lato/Lato-Black.ttf | Bin 0 -> 69484 bytes .../resources/fonts/lato/Lato-BlackItalic.ttf | Bin 0 -> 71948 bytes .../static/resources/fonts/lato/Lato-Bold.ttf | Bin 0 -> 73316 bytes .../resources/fonts/lato/Lato-BoldItalic.ttf | Bin 0 -> 77680 bytes .../resources/fonts/lato/Lato-Italic.ttf | Bin 0 -> 75744 bytes .../resources/fonts/lato/Lato-Light.ttf | Bin 0 -> 77192 bytes .../resources/fonts/lato/Lato-LightItalic.ttf | Bin 0 -> 49064 bytes .../resources/fonts/lato/Lato-Regular.ttf | Bin 0 -> 75136 bytes .../static/resources/fonts/lato/Lato-Thin.ttf | Bin 0 -> 69968 bytes .../resources/fonts/lato/Lato-ThinItalic.ttf | Bin 0 -> 48848 bytes .../login/static/resources/fonts/lato/OFL.txt | 93 + .../fonts/material/MaterialIcons-Regular.eot | Bin 0 -> 143258 bytes .../fonts/material/MaterialIcons-Regular.ttf | Bin 0 -> 128180 bytes .../fonts/material/MaterialIcons-Regular.woff | Bin 0 -> 57620 bytes .../material/MaterialIcons-Regular.woff2 | Bin 0 -> 44300 bytes internal/login/static/resources/generate.go | 7 + .../static/resources/themes/caos/css/dark.css | 257 + .../resources/themes/caos/css/dark.css.map | 1 + .../resources/themes/caos/css/light.css | 299 ++ .../resources/themes/caos/css/light.css.map | 1 + .../static/resources/themes/caos/favicon.ico | Bin 0 -> 15086 bytes .../themes/caos/gradientdeco-full.svg | 50 + .../resources/themes/caos/logo-dark.png | Bin 0 -> 32831 bytes .../resources/themes/caos/logo-light.png | Bin 0 -> 33078 bytes .../resources/themes/scss/caos/dark.scss | 3 + .../resources/themes/scss/caos/light.scss | 4 + .../resources/themes/scss/caos/variables.scss | 24 + .../static/resources/themes/scss/fonts.scss | 84 + .../static/resources/themes/scss/light.scss | 53 + .../static/resources/themes/scss/main.scss | 205 + .../resources/themes/scss/variables.scss | 23 + .../resources/themes/scss/zitadel/dark.scss | 3 + .../resources/themes/scss/zitadel/light.scss | 4 + .../themes/scss/zitadel/variables.scss | 5 + .../resources/themes/zitadel/css/dark.css | 257 + .../resources/themes/zitadel/css/dark.css.map | 1 + .../resources/themes/zitadel/css/light.css | 299 ++ .../themes/zitadel/css/light.css.map | 1 + .../resources/themes/zitadel/favicon.ico | Bin 0 -> 15086 bytes .../themes/zitadel/gradientdeco-full.svg | 50 + .../resources/themes/zitadel/logo-dark.png | Bin 0 -> 52154 bytes .../resources/themes/zitadel/logo-light.png | Bin 0 -> 19825 bytes .../static/templates/change_password.html | 32 + .../templates/change_password_done.html | 19 + .../login/static/templates/error-message.html | 9 + internal/login/static/templates/error.html | 9 + internal/login/static/templates/footer.html | 3 + internal/login/static/templates/header.html | 3 + .../login/static/templates/init_password.html | 37 + .../static/templates/init_password_done.html | 17 + .../login/static/templates/init_user.html | 37 + .../static/templates/init_user_done.html | 17 + internal/login/static/templates/login.html | 27 + .../login/static/templates/logout_done.html | 15 + .../static/templates/mail_verification.html | 31 + .../login/static/templates/mail_verified.html | 19 + internal/login/static/templates/main.html | 34 + .../login/static/templates/mfa_init_done.html | 19 + .../static/templates/mfa_init_verify.html | 47 + .../login/static/templates/mfa_prompt.html | 30 + .../login/static/templates/mfa_verify.html | 28 + internal/login/static/templates/password.html | 33 + .../static/templates/password_reset_done.html | 17 + internal/login/static/templates/register.html | 61 + .../login/static/templates/select_user.html | 25 + internal/login/statik/generate.go | 3 + internal/management/auth/token_verifier.go | 23 +- .../eventsourcing/eventstore/project.go | 9 + .../repository/eventsourcing/handler/org.go | 6 +- .../eventsourcing/handler/org_member.go | 12 +- internal/model/search_method.go | 3 + .../types/email_verification_code.go | 2 +- internal/notification/types/init_code.go | 2 +- internal/notification/types/password_code.go | 2 +- internal/notification/types/user_email.go | 4 +- .../repository/eventsourcing/eventstore.go | 35 +- .../eventsourcing/eventstore_test.go | 53 +- .../eventsourcing/{ => model}/member_model.go | 6 +- .../eventsourcing/{ => model}/org_model.go | 19 +- .../{ => model}/org_model_test.go | 14 +- .../eventsourcing}/model/types.go | 0 internal/org/repository/eventsourcing/org.go | 43 +- .../repository/eventsourcing/org_member.go | 28 +- .../eventsourcing/org_member_test.go | 64 +- .../org/repository/eventsourcing/org_test.go | 41 +- internal/org/repository/view/org.go | 10 +- internal/org/repository/view/org_member.go | 5 +- internal/project/model/granted_project.go | 2 +- .../repository/eventsourcing/eventstore.go | 42 +- .../model/project_grant_member.go | 10 +- .../eventsourcing/model/project_member.go | 8 +- .../repository/eventsourcing/model/types.go | 8 +- .../repository/eventsourcing/project.go | 43 +- .../repository/view/application_view.go | 18 + .../repository/view/model/application.go | 2 +- internal/renderer/renderer.go | 120 + internal/token/model/token.go | 2 + internal/token/repository/view/model/token.go | 26 +- internal/user/model/phone.go | 1 - internal/user/model/user_session_view.go | 26 +- internal/user/model/user_view.go | 3 + .../repository/eventsourcing/eventstore.go | 69 +- .../eventsourcing/eventstore_mock_test.go | 26 +- .../eventsourcing/eventstore_test.go | 173 +- .../repository/eventsourcing/model/email.go | 1 + .../eventsourcing/model/password.go | 7 +- .../repository/eventsourcing/model/phone.go | 7 +- .../repository/eventsourcing/model/types.go | 28 +- .../user/repository/eventsourcing/user.go | 57 +- .../repository/eventsourcing/user_test.go | 236 +- internal/user/repository/view/model/user.go | 8 + .../repository/view/model/user_session.go | 52 +- .../view/model/user_session_query.go | 2 - .../user/repository/view/user_session_view.go | 23 +- internal/usergrant/model/project_org.go | 13 + internal/usergrant/model/user_grant_view.go | 1 + .../usergrant/model/zitadel_permission.go | 23 + .../repository/eventsourcing/eventstore.go | 1 - .../repository/eventsourcing/user_grant.go | 10 +- .../repository/view/model/user_grant.go | 1 + .../repository/view/model/user_grant_query.go | 2 + .../repository/view/user_grant_view.go | 11 + internal/view/query.go | 6 + internal/view/requests.go | 2 +- k8s/base/deployment.yaml | 20 +- migrations/cockroach/V1.11__auth_oidc.sql | 56 + .../cockroach/V1.12__auth_user_grant_view.sql | 25 + migrations/cockroach/V1.13__auth_org_view.sql | 17 + migrations/cockroach/V1.14__authz.sql | 94 + pkg/admin/admin.go | 5 +- pkg/admin/api/api.go | 5 +- pkg/admin/api/grpc/server.go | 5 +- pkg/auth/api/api.go | 11 +- pkg/auth/api/grpc/auth.pb.authoptions.go | 4 +- pkg/auth/api/grpc/auth.pb.go | 4683 +++++++++++------ pkg/auth/api/grpc/auth.pb.gw.go | 908 +--- pkg/auth/api/grpc/auth.swagger.json | 211 +- pkg/auth/api/grpc/grant.go | 15 - pkg/auth/api/grpc/mock/auth.proto.mock.go | 38 +- pkg/auth/api/grpc/permissions.go | 50 - pkg/auth/api/grpc/search_converter.go | 22 + pkg/auth/api/grpc/server.go | 7 +- pkg/auth/api/grpc/user.go | 2 +- pkg/auth/api/grpc/user_grant.go | 30 + pkg/auth/api/grpc/user_grant_converter.go | 126 + pkg/auth/api/grpc/user_session.go | 7 +- pkg/auth/api/grpc/user_session_converter.go | 35 + pkg/auth/api/oidc/auth_request.go | 82 + pkg/auth/api/oidc/auth_request_converter.go | 254 + pkg/auth/api/oidc/client.go | 97 + pkg/auth/api/oidc/client_converter.go | 73 + pkg/auth/api/oidc/cookie_interceptor.go | 37 + pkg/auth/api/oidc/op.go | 87 + pkg/auth/api/proto/auth.proto | 54 +- pkg/auth/auth.go | 10 +- pkg/console/console.go | 4 +- pkg/console/statik/generate.go | 3 + pkg/console/statik/statik.go | 1 - pkg/eventstore/eventstore.go | 14 - pkg/login/api/config.go | 4 - pkg/login/login.go | 18 - pkg/management/api/api.go | 5 +- pkg/management/api/grpc/server.go | 5 +- pkg/management/management.go | 5 +- 293 files changed, 14189 insertions(+), 3176 deletions(-) create mode 100755 build/login/generate-static.sh mode change 100644 => 100755 cmd/zitadel/caos_local.sh create mode 100644 internal/api/http/header.go create mode 100644 internal/api/http/user_agent_cookie.go delete mode 100644 internal/auth/config.go create mode 100644 internal/auth/repository/application.go create mode 100644 internal/auth/repository/eventsourcing/eventstore/application.go create mode 100644 internal/auth/repository/eventsourcing/eventstore/iam.go create mode 100644 internal/auth/repository/eventsourcing/eventstore/key.go create mode 100644 internal/auth/repository/eventsourcing/eventstore/org.go create mode 100644 internal/auth/repository/eventsourcing/eventstore/user_grant.go create mode 100644 internal/auth/repository/eventsourcing/eventstore/user_session.go create mode 100644 internal/auth/repository/eventsourcing/handler/application.go create mode 100644 internal/auth/repository/eventsourcing/handler/key.go create mode 100644 internal/auth/repository/eventsourcing/handler/org.go create mode 100644 internal/auth/repository/eventsourcing/handler/user_grant.go create mode 100644 internal/auth/repository/eventsourcing/view/application.go create mode 100644 internal/auth/repository/eventsourcing/view/key.go create mode 100644 internal/auth/repository/eventsourcing/view/org.go create mode 100644 internal/auth/repository/eventsourcing/view/user_grant.go create mode 100644 internal/auth/repository/iam.go create mode 100644 internal/auth/repository/key.go create mode 100644 internal/auth/repository/user_grant.go create mode 100644 internal/auth/repository/user_session.go delete mode 100644 internal/auth_request/repository/mock/repository.go create mode 100644 internal/authz/authz.go create mode 100644 internal/authz/repository/eventsourcing/eventstore/iam.go create mode 100644 internal/authz/repository/eventsourcing/eventstore/token_verifier.go create mode 100644 internal/authz/repository/eventsourcing/eventstore/user_grant.go create mode 100644 internal/authz/repository/eventsourcing/handler/application.go create mode 100644 internal/authz/repository/eventsourcing/handler/handler.go create mode 100644 internal/authz/repository/eventsourcing/handler/user_grant.go create mode 100644 internal/authz/repository/eventsourcing/repository.go create mode 100644 internal/authz/repository/eventsourcing/spooler/lock.go create mode 100644 internal/authz/repository/eventsourcing/spooler/lock_test.go create mode 100644 internal/authz/repository/eventsourcing/spooler/spooler.go create mode 100644 internal/authz/repository/eventsourcing/view/application.go create mode 100644 internal/authz/repository/eventsourcing/view/error_event.go create mode 100644 internal/authz/repository/eventsourcing/view/sequence.go create mode 100644 internal/authz/repository/eventsourcing/view/token.go create mode 100644 internal/authz/repository/eventsourcing/view/user_grant.go create mode 100644 internal/authz/repository/eventsourcing/view/view.go create mode 100644 internal/authz/repository/iam.go create mode 100644 internal/authz/repository/repository.go create mode 100644 internal/authz/repository/token_verifier.go create mode 100644 internal/authz/repository/user_grant.go create mode 100644 internal/crypto/rsa.go create mode 100644 internal/form/parser.go create mode 100644 internal/i18n/i18n.go create mode 100644 internal/key/model/key.go create mode 100644 internal/key/model/key_view.go create mode 100644 internal/key/repository/eventsourcing/eventstore.go create mode 100644 internal/key/repository/eventsourcing/key.go create mode 100644 internal/key/repository/eventsourcing/model/key.go create mode 100644 internal/key/repository/eventsourcing/model/types.go create mode 100644 internal/key/repository/view/key.go create mode 100644 internal/key/repository/view/model/key.go create mode 100644 internal/key/repository/view/model/key_query.go delete mode 100644 internal/login/config.go create mode 100644 internal/login/handler/auth_request.go create mode 100644 internal/login/handler/callback_handler.go create mode 100644 internal/login/handler/change_password_handler.go create mode 100644 internal/login/handler/health_handler.go create mode 100644 internal/login/handler/init_password_handler.go create mode 100644 internal/login/handler/init_user_handler.go create mode 100644 internal/login/handler/login.go create mode 100644 internal/login/handler/login_handler.go create mode 100644 internal/login/handler/logout_handler.go create mode 100644 internal/login/handler/mail_verify_handler.go create mode 100644 internal/login/handler/mfa_init_done_handler.go create mode 100644 internal/login/handler/mfa_init_verify_handler.go create mode 100644 internal/login/handler/mfa_prompt_handler.go create mode 100644 internal/login/handler/mfa_verify_handler.go create mode 100644 internal/login/handler/password_handler.go create mode 100644 internal/login/handler/password_reset_handler.go create mode 100644 internal/login/handler/register_handler.go create mode 100644 internal/login/handler/renderer.go create mode 100644 internal/login/handler/resources_handler.go create mode 100644 internal/login/handler/router.go create mode 100644 internal/login/handler/select_user_handler.go create mode 100644 internal/login/login.go create mode 100644 internal/login/static/i18n/de.yaml create mode 100644 internal/login/static/i18n/en.yaml create mode 100644 internal/login/static/resources/fonts/ailerons/ailerons.otf create mode 100755 internal/login/static/resources/fonts/lato/Lato-Black.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-BlackItalic.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-Bold.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-BoldItalic.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-Italic.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-Light.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-LightItalic.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-Regular.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-Thin.ttf create mode 100755 internal/login/static/resources/fonts/lato/Lato-ThinItalic.ttf create mode 100755 internal/login/static/resources/fonts/lato/OFL.txt create mode 100644 internal/login/static/resources/fonts/material/MaterialIcons-Regular.eot create mode 100644 internal/login/static/resources/fonts/material/MaterialIcons-Regular.ttf create mode 100644 internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff create mode 100644 internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff2 create mode 100644 internal/login/static/resources/generate.go create mode 100644 internal/login/static/resources/themes/caos/css/dark.css create mode 100644 internal/login/static/resources/themes/caos/css/dark.css.map create mode 100644 internal/login/static/resources/themes/caos/css/light.css create mode 100644 internal/login/static/resources/themes/caos/css/light.css.map create mode 100644 internal/login/static/resources/themes/caos/favicon.ico create mode 100644 internal/login/static/resources/themes/caos/gradientdeco-full.svg create mode 100644 internal/login/static/resources/themes/caos/logo-dark.png create mode 100644 internal/login/static/resources/themes/caos/logo-light.png create mode 100644 internal/login/static/resources/themes/scss/caos/dark.scss create mode 100644 internal/login/static/resources/themes/scss/caos/light.scss create mode 100644 internal/login/static/resources/themes/scss/caos/variables.scss create mode 100644 internal/login/static/resources/themes/scss/fonts.scss create mode 100644 internal/login/static/resources/themes/scss/light.scss create mode 100644 internal/login/static/resources/themes/scss/main.scss create mode 100644 internal/login/static/resources/themes/scss/variables.scss create mode 100644 internal/login/static/resources/themes/scss/zitadel/dark.scss create mode 100644 internal/login/static/resources/themes/scss/zitadel/light.scss create mode 100644 internal/login/static/resources/themes/scss/zitadel/variables.scss create mode 100644 internal/login/static/resources/themes/zitadel/css/dark.css create mode 100644 internal/login/static/resources/themes/zitadel/css/dark.css.map create mode 100644 internal/login/static/resources/themes/zitadel/css/light.css create mode 100644 internal/login/static/resources/themes/zitadel/css/light.css.map create mode 100644 internal/login/static/resources/themes/zitadel/favicon.ico create mode 100644 internal/login/static/resources/themes/zitadel/gradientdeco-full.svg create mode 100644 internal/login/static/resources/themes/zitadel/logo-dark.png create mode 100644 internal/login/static/resources/themes/zitadel/logo-light.png create mode 100644 internal/login/static/templates/change_password.html create mode 100644 internal/login/static/templates/change_password_done.html create mode 100644 internal/login/static/templates/error-message.html create mode 100644 internal/login/static/templates/error.html create mode 100644 internal/login/static/templates/footer.html create mode 100644 internal/login/static/templates/header.html create mode 100644 internal/login/static/templates/init_password.html create mode 100644 internal/login/static/templates/init_password_done.html create mode 100644 internal/login/static/templates/init_user.html create mode 100644 internal/login/static/templates/init_user_done.html create mode 100644 internal/login/static/templates/login.html create mode 100644 internal/login/static/templates/logout_done.html create mode 100644 internal/login/static/templates/mail_verification.html create mode 100644 internal/login/static/templates/mail_verified.html create mode 100644 internal/login/static/templates/main.html create mode 100644 internal/login/static/templates/mfa_init_done.html create mode 100644 internal/login/static/templates/mfa_init_verify.html create mode 100644 internal/login/static/templates/mfa_prompt.html create mode 100644 internal/login/static/templates/mfa_verify.html create mode 100644 internal/login/static/templates/password.html create mode 100644 internal/login/static/templates/password_reset_done.html create mode 100644 internal/login/static/templates/register.html create mode 100644 internal/login/static/templates/select_user.html create mode 100644 internal/login/statik/generate.go rename internal/org/repository/eventsourcing/{ => model}/member_model.go (95%) rename internal/org/repository/eventsourcing/{ => model}/org_model.go (92%) rename internal/org/repository/eventsourcing/{ => model}/org_model_test.go (93%) rename internal/org/{ => repository/eventsourcing}/model/types.go (100%) create mode 100644 internal/renderer/renderer.go create mode 100644 internal/usergrant/model/project_org.go create mode 100644 internal/usergrant/model/zitadel_permission.go create mode 100644 migrations/cockroach/V1.11__auth_oidc.sql create mode 100644 migrations/cockroach/V1.12__auth_user_grant_view.sql create mode 100644 migrations/cockroach/V1.13__auth_org_view.sql create mode 100644 migrations/cockroach/V1.14__authz.sql delete mode 100644 pkg/auth/api/grpc/grant.go delete mode 100644 pkg/auth/api/grpc/permissions.go create mode 100644 pkg/auth/api/grpc/search_converter.go create mode 100644 pkg/auth/api/grpc/user_grant.go create mode 100644 pkg/auth/api/grpc/user_grant_converter.go create mode 100644 pkg/auth/api/grpc/user_session_converter.go create mode 100644 pkg/auth/api/oidc/auth_request.go create mode 100644 pkg/auth/api/oidc/auth_request_converter.go create mode 100644 pkg/auth/api/oidc/client.go create mode 100644 pkg/auth/api/oidc/client_converter.go create mode 100644 pkg/auth/api/oidc/cookie_interceptor.go create mode 100644 pkg/auth/api/oidc/op.go create mode 100644 pkg/console/statik/generate.go delete mode 100644 pkg/console/statik/statik.go delete mode 100644 pkg/eventstore/eventstore.go delete mode 100644 pkg/login/api/config.go delete mode 100644 pkg/login/login.go diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9aaf6c4d40..7ddcd7ec7f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -101,6 +101,8 @@ jobs: - run: go get github.com/rakyll/statik - run: ./build/console/generate-static.sh - run: cat pkg/console/statik/statik.go + - run: ./build/login/generate-static.sh + - run: cat internal/login/statik/statik.go - run: CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o zitadel-${{ matrix.goos }}-${{ matrix.goarch }} cmd/zitadel/main.go - uses: actions/upload-artifact@v1 with: diff --git a/.gitignore b/.gitignore index 298e6e97ae..4228421518 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,4 @@ cockroach-data/* #binaries cmd/zitadel/zitadel -zitadel +**/statik/statik.go diff --git a/build/console/generate-static.sh b/build/console/generate-static.sh index 756e9e964a..18632ab241 100755 --- a/build/console/generate-static.sh +++ b/build/console/generate-static.sh @@ -2,4 +2,4 @@ set -eux -go generate pkg/console/console.go \ No newline at end of file +go generate pkg/console/statik/generate.go \ No newline at end of file diff --git a/build/login/generate-static.sh b/build/login/generate-static.sh new file mode 100755 index 0000000000..9e59d27287 --- /dev/null +++ b/build/login/generate-static.sh @@ -0,0 +1,5 @@ +#! /bin/sh + +set -eux + +go generate internal/login/statik/generate.go \ No newline at end of file diff --git a/cmd/zitadel/authz.yaml b/cmd/zitadel/authz.yaml index ac5b8ebd72..979fdbe0ec 100644 --- a/cmd/zitadel/authz.yaml +++ b/cmd/zitadel/authz.yaml @@ -1,4 +1,4 @@ -AuthZ: +InternalAuthZ: RolePermissionMappings: - Role: 'IAM_OWNER' Permissions: diff --git a/cmd/zitadel/caos_local.sh b/cmd/zitadel/caos_local.sh old mode 100644 new mode 100755 index f5444ecd79..7b4451192b --- a/cmd/zitadel/caos_local.sh +++ b/cmd/zitadel/caos_local.sh @@ -1,7 +1,9 @@ BASEDIR=$(dirname "$0") +gopass sync --store zitadel-secrets + # Tracing -gopass citadel-secrets/citadel/developer/default/citadel-svc-account-eventstore-local | base64 -D > "$BASEDIR/local_svc-account-tracing.json" +gopass zitadel-secrets/zitadel/developer/default/zitadel-svc-account-eventstore-local | base64 -D > "$BASEDIR/local_svc-account-tracing.json" export GOOGLE_APPLICATION_CREDENTIALS="$BASEDIR/local_svc-account-tracing.json" export ZITADEL_TRACING_PROJECT_ID=caos-citadel-test @@ -15,24 +17,32 @@ export ZITADEL_EVENTSTORE_HOST=localhost export ZITADEL_EVENTSTORE_PORT=26257 # Keys -gopass citadel-secrets/citadel/developer/default/keys.yaml > "$BASEDIR/local_keys.yaml" +gopass zitadel-secrets/zitadel/developer/default/keys.yaml > "$BASEDIR/local_keys.yaml" export ZITADEL_KEY_PATH="$BASEDIR/local_keys.yaml" export ZITADEL_USER_VERIFICATION_KEY=UserVerificationKey_1 export ZITADEL_OTP_VERIFICATION_KEY=OTPVerificationKey_1 +export ZITADEL_OIDC_KEYS_ID=OIDCKey_1 +export ZITADEL_COOKIE_KEY=CookieKey_1 # Notifications export DEBUG_MODE=TRUE -export TWILIO_SERVICE_SID=$(gopass citadel-secrets/citadel/developer/default/twilio-sid) -export TWILIO_TOKEN=$(gopass citadel-secrets/citadel/developer/default/twilio-auth-token) +export TWILIO_SERVICE_SID=$(gopass zitadel-secrets/zitadel/dev/twilio-sid) +export TWILIO_TOKEN=$(gopass zitadel-secrets/zitadel/dev/twilio-auth-token) export TWILIO_SENDER_NAME=CAOS AG export SMTP_HOST=smtp.gmail.com:465 export SMTP_USER=zitadel@caos.ch -export SMTP_PASSWORD=$(gopass citadel-secrets/citadel/google/emailappkey) +export SMTP_PASSWORD=$(gopass zitadel-secrets/zitadel/google/emailappkey) export EMAIL_SENDER_ADDRESS=noreply@caos.ch export EMAIL_SENDER_NAME=CAOS AG export SMTP_TLS=TRUE -export CHAT_URL=$(gopass citadel-secrets/citadel/developer/default/google-chat-url | base64 -D) +export CHAT_URL=$(gopass zitadel-secrets/zitadel/dev/google-chat-url | base64 -D) -# Zitadel -export ZITADEL_ACCOUNTS=http://localhost:61121 +#OIDC +export ZITADEL_ISSUER=http://localhost:50022 +export ZITADEL_ACCOUNTS=http://localhost:50031 +export ZITADEL_AUTHORIZE=http://localhost:50022 +export ZITADEL_OAUTH=http://localhost:50022 +export ZITADEL_CONSOLE=http://localhost:4200 +export CAOS_OIDC_DEV=true +export ZITADEL_COOKIE_DOMAIN=localhost \ No newline at end of file diff --git a/cmd/zitadel/main.go b/cmd/zitadel/main.go index 76ac81cc06..ec8f83ee3a 100644 --- a/cmd/zitadel/main.go +++ b/cmd/zitadel/main.go @@ -3,18 +3,20 @@ package main import ( "context" "flag" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing" + "github.com/caos/zitadel/internal/authz" sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/login" "github.com/caos/logging" - authz "github.com/caos/zitadel/internal/api/auth" + internal_authz "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/config" "github.com/caos/zitadel/internal/notification" tracing "github.com/caos/zitadel/internal/tracing/config" "github.com/caos/zitadel/pkg/admin" "github.com/caos/zitadel/pkg/auth" "github.com/caos/zitadel/pkg/console" - "github.com/caos/zitadel/pkg/login" "github.com/caos/zitadel/pkg/management" ) @@ -22,13 +24,14 @@ type Config struct { Mgmt management.Config Auth auth.Config Login login.Config + AuthZ authz.Config Admin admin.Config Console console.Config Notification notification.Config Log logging.Config Tracing tracing.TracingConfig - AuthZ authz.Config + InternalAuthZ internal_authz.Config SystemDefaults sd.SystemDefaults } @@ -48,18 +51,25 @@ func main() { logging.Log("MAIN-FaF2r").OnError(err).Fatal("cannot read config") ctx := context.Background() + authZRepo, err := authz.Start(ctx, conf.AuthZ, conf.InternalAuthZ, conf.SystemDefaults) + logging.Log("MAIN-s9KOw").OnError(err).Fatal("error starting authz repo") + if *adminEnabled { - admin.Start(ctx, conf.Admin, conf.AuthZ, conf.SystemDefaults) + admin.Start(ctx, conf.Admin, authZRepo, conf.InternalAuthZ, conf.SystemDefaults) } if *managementEnabled { - management.Start(ctx, conf.Mgmt, conf.AuthZ, conf.SystemDefaults) + management.Start(ctx, conf.Mgmt, authZRepo, conf.InternalAuthZ, conf.SystemDefaults) + } + var authRepo *eventsourcing.EsRepository + if *authEnabled || *loginEnabled { + authRepo, err = eventsourcing.Start(conf.Auth.Repository, conf.InternalAuthZ, conf.SystemDefaults, authZRepo) + logging.Log("MAIN-9oRw6").OnError(err).Fatal("error starting auth repo") } if *authEnabled { - auth.Start(ctx, conf.Auth, conf.AuthZ, conf.SystemDefaults) + auth.Start(ctx, conf.Auth, authZRepo, conf.InternalAuthZ, conf.SystemDefaults, authRepo) } if *loginEnabled { - err = login.Start(ctx, conf.Login) - logging.Log("MAIN-53RF2").OnError(err).Fatal("error starting login ui") + login.Start(ctx, conf.Login, conf.SystemDefaults, authRepo) } if *notificationEnabled { notification.Start(ctx, conf.Notification, conf.SystemDefaults) diff --git a/cmd/zitadel/startup.yaml b/cmd/zitadel/startup.yaml index accf263ef1..318628acad 100644 --- a/cmd/zitadel/startup.yaml +++ b/cmd/zitadel/startup.yaml @@ -50,6 +50,37 @@ Auth: GatewayPort: 50021 CustomHeaders: - x-zitadel- + OIDC: + OPConfig: + Issuer: $ZITADEL_ISSUER + DefaultLogoutRedirectURI: $ZITADEL_ACCOUNTS/logout/done + Port: 50022 + StorageConfig: + DefaultLoginURL: $ZITADEL_ACCOUNTS/login?authRequestID= + DefaultAccessTokenLifetime: 12h + DefaultIdTokenLifetime: 12h + SigningKeyAlgorithm: RS256 + UserAgentCookieConfig: + Name: caos.zitadel.useragent + Domain: $ZITADEL_COOKIE_DOMAIN + Key: + EncryptionKeyID: $ZITADEL_COOKIE_KEY + Endpoints: + Auth: + Path: 'authorize' + URL: '$ZITADEL_AUTHORIZE/authorize' + Token: + Path: 'token' + URL: '$ZITADEL_OAUTH/token' + EndSession: + Path: 'endsession' + URL: '$ZITADEL_AUTHORIZE/endsession' + Userinfo: + Path: 'userinfo' + URL: '$ZITADEL_OAUTH/userinfo' + Keys: + Path: 'keys' + URL: '$ZITADEL_OAUTH/keys' Repository: SearchLimit: 100 Eventstore: @@ -66,11 +97,12 @@ Auth: Config: MaxCacheSizeInByte: 10485760 #10mb AuthRequest: - Host: $ZITADEL_EVENTSTORE_HOST - Port: $ZITADEL_EVENTSTORE_PORT - User: 'auth' - Database: 'auth' - SSLmode: disable + Connection: + Host: $ZITADEL_EVENTSTORE_HOST + Port: $ZITADEL_EVENTSTORE_PORT + User: 'auth' + Database: 'auth' + SSLmode: disable View: Host: $ZITADEL_EVENTSTORE_HOST Port: $ZITADEL_EVENTSTORE_PORT @@ -81,9 +113,48 @@ Auth: ConcurrentTasks: 4 BulkLimit: 100 FailureCountUntilSkip: 5 + KeyConfig: + Size: 2048 + PrivateKeyLifetime: 6h + PublicKeyLifetime: 30h + EncryptionConfig: + EncryptionKeyID: $ZITADEL_OIDC_KEYS_ID + SigningKeyRotation: 10s Login: -# will get port range 5003x + Handler: + Port: 50031 + OidcAuthCallbackURL: '$ZITADEL_AUTHORIZE/authorize/' + ZitadelURL: '$ZITADEL_CONSOLE' + LanguageCookieName: 'caos.zitadel.login.lang' + DefaultLanguage: 'de' + + +AuthZ: + Repository: + Eventstore: + ServiceName: 'AuthZ' + Repository: + SQL: + Host: $ZITADEL_EVENTSTORE_HOST + Port: $ZITADEL_EVENTSTORE_PORT + User: 'authz' + Database: 'eventstore' + SSLmode: disable + Cache: + Type: 'fastcache' + Config: + MaxCacheSizeInByte: 10485760 #10mb + View: + Host: $ZITADEL_EVENTSTORE_HOST + Port: $ZITADEL_EVENTSTORE_PORT + User: 'authz' + Database: 'authz' + SSLmode: disable + Spooler: + ConcurrentTasks: 1 + BulkLimit: 100 + FailureCountUntilSkip: 5 Admin: API: @@ -120,7 +191,6 @@ Admin: Console: Port: 50050 - StaticDir: /app/console/dist Notification: diff --git a/cmd/zitadel/system-defaults.yaml b/cmd/zitadel/system-defaults.yaml index 7bc5b2e2c0..21cbd99403 100644 --- a/cmd/zitadel/system-defaults.yaml +++ b/cmd/zitadel/system-defaults.yaml @@ -76,7 +76,7 @@ SystemDefaults: LastName: 'Administrator' UserName: 'zitadel-global-org-admin@caos.ch' Email: 'zitadel-global-org-admin@caos.ch' - Password: 'Password' + Password: 'Password1!' Owners: - 'zitadel-global-org-admin@caos.ch' - Name: 'CAOS AG' @@ -86,7 +86,7 @@ SystemDefaults: LastName: 'Administrator' UserName: 'zitadel-admin@caos.ch' Email: 'zitadel-admin@caos.ch' - Password: 'Password' + Password: 'Password1!' Owners: - 'zitadel-admin@caos.ch' Projects: @@ -97,9 +97,9 @@ SystemDefaults: - Name: 'Admin-API' - Name: 'Zitadel Console' RedirectUris: - - '$CITADEL_CONSOLE/auth/callback' + - '$ZITADEL_CONSOLE/auth/callback' PostLogoutRedirectUris: - - '$CITADEL_CONSOLE/signedout' + - '$ZITADEL_CONSOLE/signedout' ResponseTypes: - 'CODE' GrantTypes: @@ -133,9 +133,9 @@ SystemDefaults: From: $TWILIO_SENDER_NAME TemplateData: InitCode: - Title: 'Zitadel - User Initialisieren' - PreHeader: 'User Initialisieren' - Subject: 'User Initialisieren' + Title: 'Zitadel - User initialisieren' + PreHeader: 'User initialisieren' + Subject: 'User initialisieren' Greeting: 'Hallo {{.FirstName}} {{.LastName}},' Text: 'Dieser Benutzer wurde soeben im Zitadel erstellt. Du kannst den Button unten verwenden, um die Initialisierung abzuschliesen. Falls du dieses Mail nicht angefordert hast, kannst du es einfach ignorieren.' ButtonText: 'Initialisierung abschliessen' @@ -147,16 +147,16 @@ SystemDefaults: Text: 'Wir haben eine Anfrage für das Zurücksetzen deines Passwortes bekommen. Du kannst den untenstehenden Button verwenden, um dein Passwort zurückzusetzen. Falls du dieses Mail nicht angefordert hast, kannst du es ignorieren.' ButtonText: 'Passwort zurücksetzen' VerifyEmail: - Title: 'Zitadel - Email Verifizieren' + Title: 'Zitadel - Email verifizieren' PreHeader: 'Email verifizieren' Subject: 'Email verifizieren' Greeting: 'Hallo {{.FirstName}} {{.LastName}},' Text: 'Eine neue E-Mail Adresse wurde hinzugefügt. Bitte verwende den untenstehenden Button um diese zu verifizieren. Falls du deine E-Mail Adresse nicht selber hinzugefügt hast, kannst du dieses E-Mail ignorieren.' - ButtonText: 'Passwort zurücksetzen' + ButtonText: 'Email verifizieren' VerifyPhone: - Title: 'Zitadel - Telefonnummer Verifizieren' - PreHeader: 'Telefonnummer Verifizieren' - Subject: 'Telefonnummer Verifizieren' + Title: 'Zitadel - Telefonnummer verifizieren' + PreHeader: 'Telefonnummer verifizieren' + Subject: 'Telefonnummer verifizieren' Greeting: 'Hallo {{.FirstName}} {{.LastName}},' Text: 'Eine Telefonnummer wurde hinzugefügt. Bitte verifiziere diese in dem du folgenden Code eingibst: {{.Code}}' ButtonText: 'Telefon verifizieren' \ No newline at end of file diff --git a/go.mod b/go.mod index 1045c6d3b0..2da16f2b3d 100644 --- a/go.mod +++ b/go.mod @@ -11,16 +11,20 @@ require ( github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible github.com/VictoriaMetrics/fastcache v1.5.7 + github.com/aaronarduino/goqrsvg v0.0.0-20170617203649-603647895681 + github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca github.com/allegro/bigcache v1.2.1 github.com/aws/aws-sdk-go v1.30.25 // indirect - github.com/caos/logging v0.0.1 + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc + github.com/caos/logging v0.0.2 + github.com/caos/oidc v0.6.2 github.com/cockroachdb/cockroach-go v0.0.0-20200504194139-73ffeee90b62 github.com/envoyproxy/protoc-gen-validate v0.1.0 github.com/ghodss/yaml v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/mock v1.4.3 github.com/golang/protobuf v1.4.1 - github.com/google/uuid v1.1.1 // indirect + github.com/gorilla/mux v1.7.4 github.com/gorilla/schema v1.1.0 github.com/gorilla/securecookie v1.1.1 github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 @@ -41,7 +45,6 @@ require ( github.com/pquerna/otp v1.2.0 github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.7.0 - github.com/sirupsen/logrus v1.6.0 // indirect github.com/sony/sonyflake v1.0.0 github.com/stretchr/testify v1.5.1 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect @@ -49,12 +52,13 @@ require ( go.opencensus.io v0.22.3 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect - golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 // indirect + golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect golang.org/x/text v0.3.2 golang.org/x/tools v0.0.0-20200512001501-aaeff5de670a google.golang.org/api v0.24.0 // indirect google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380 google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.22.0 + gopkg.in/square/go-jose.v2 v2.5.1 gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/go.sum b/go.sum index 7825e0a542..05a6fe13bd 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,10 @@ 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/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/aaronarduino/goqrsvg v0.0.0-20170617203649-603647895681 h1:eZrVcUgy0P6+B6Vu7SKPh3UZQS5nEuyjhbkFyfz7I2I= +github.com/aaronarduino/goqrsvg v0.0.0-20170617203649-603647895681/go.mod h1:dytw+5qs+pdi61fO/S4OmXR7AuEq/HvNCuG03KxQHT4= +github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca h1:kWzLcty5V2rzOqJM7Tp/MfSX0RMSI1x4IOLApEefYxA= +github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 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= @@ -56,10 +60,11 @@ github.com/aws/aws-sdk-go v1.30.25 h1:89NXJkfpjnMEnsxkP8MVX+LDsoiLCSqevraLb5y4Mj github.com/aws/aws-sdk-go v1.30.25/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= 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/caos/logging v0.0.1 h1:YSGtO2/+5OWdwilBCou50akoDHAT/OhkbrolkVlR6U0= -github.com/caos/logging v0.0.1 h1:YSGtO2/+5OWdwilBCou50akoDHAT/OhkbrolkVlR6U0= -github.com/caos/logging v0.0.1/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= -github.com/caos/logging v0.0.1/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +github.com/caos/logging v0.0.0-20191210002624-b3260f690a6a/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +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.6.2 h1:ejp6uTepVSlgLoPhXIAqFe8SbCdoxqO4vZv1H4fF0Yk= +github.com/caos/oidc v0.6.2/go.mod h1:ozoi3b+aY33gzdvjz4w90VZShIHGsmDa0goruuV0arQ= 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= @@ -138,6 +143,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw 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-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -152,6 +161,10 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ 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/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= @@ -273,6 +286,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/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-20191128160524-b544559bb6d1/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -320,6 +334,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -333,6 +348,7 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-20191122200657-5d9234df094c/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= @@ -372,8 +388,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w 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-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 h1:OKbAoGs4fGM5cPLlVQLZGYkFC8OnOfgo6tt0Smf9XhM= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/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/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= @@ -498,6 +514,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +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/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= diff --git a/internal/admin/auth/token_verifier.go b/internal/admin/auth/token_verifier.go index 84ba0abe38..a4026591d1 100644 --- a/internal/admin/auth/token_verifier.go +++ b/internal/admin/auth/token_verifier.go @@ -3,23 +3,34 @@ package auth import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" +) + +const ( + adminName = "Admin-API" ) type TokenVerifier struct { + adminID string + authZRepo *authz_repo.EsRepository } -func Start() (v *TokenVerifier) { - return new(TokenVerifier) +func Start(authZRepo *authz_repo.EsRepository) (v *TokenVerifier) { + return &TokenVerifier{authZRepo: authZRepo} } func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { - return "", "", "", nil + userID, clientID, agentID, err := v.authZRepo.VerifyAccessToken(ctx, token, adminName, v.adminID) + if clientID != "" { + v.adminID = clientID + } + return userID, clientID, agentID, err } -func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) { - return nil, nil +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*auth.Grant, error) { + return v.authZRepo.ResolveGrants(ctx) } func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { - return "", nil + return v.authZRepo.ProjectIDByClientID(ctx, clientID) } diff --git a/internal/admin/repository/eventsourcing/eventstore/setup_model.go b/internal/admin/repository/eventsourcing/eventstore/setup_model.go index 98e27199e5..527b514781 100644 --- a/internal/admin/repository/eventsourcing/eventstore/setup_model.go +++ b/internal/admin/repository/eventsourcing/eventstore/setup_model.go @@ -3,13 +3,12 @@ package eventstore import ( admin_model "github.com/caos/zitadel/internal/admin/model" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) type Setup struct { - *org_es.Org + *model.Org *usr_es.User } @@ -17,7 +16,7 @@ func (s *Setup) AppendEvents(events ...*es_models.Event) error { for _, event := range events { var err error switch event.AggregateType { - case org_model.OrgAggregate: + case model.OrgAggregate: err = s.Org.AppendEvent(event) case usr_es.UserAggregate: err = s.User.AppendEvent(event) @@ -31,7 +30,7 @@ func (s *Setup) AppendEvents(events ...*es_models.Event) error { func SetupToModel(setup *Setup) *admin_model.SetupOrg { return &admin_model.SetupOrg{ - Org: org_es.OrgToModel(setup.Org), + Org: model.OrgToModel(setup.Org), User: usr_es.UserToModel(setup.User), } } diff --git a/internal/admin/repository/eventsourcing/handler/org.go b/internal/admin/repository/eventsourcing/handler/org.go index 5564e4eb94..1e7d90764f 100644 --- a/internal/admin/repository/eventsourcing/handler/org.go +++ b/internal/admin/repository/eventsourcing/handler/org.go @@ -1,12 +1,12 @@ package handler import ( + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/spooler" - org_model "github.com/caos/zitadel/internal/org/model" "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/view" ) @@ -37,9 +37,9 @@ func (o *Org) Process(event *es_models.Event) error { org := new(view.OrgView) switch event.Type { - case org_model.OrgAdded: + case model.OrgAdded: org.AppendEvent(event) - case org_model.OrgChanged: + case model.OrgChanged: err := org.SetData(event) if err != nil { return err diff --git a/internal/admin/repository/eventsourcing/setup/setup.go b/internal/admin/repository/eventsourcing/setup/setup.go index 631083c121..fd738c8958 100644 --- a/internal/admin/repository/eventsourcing/setup/setup.go +++ b/internal/admin/repository/eventsourcing/setup/setup.go @@ -125,7 +125,7 @@ func (s *Setup) Execute(ctx context.Context) error { err = setUp.setIamProject(ctx) if err != nil { - logging.Log("SETUP-kaWjq").WithError(err).Error("unable to set citadel project") + logging.Log("SETUP-kaWjq").WithError(err).Error("unable to set zitadel project") return err } diff --git a/internal/api/auth/context.go b/internal/api/auth/context.go index 3d176c31bf..220e647d4c 100644 --- a/internal/api/auth/context.go +++ b/internal/api/auth/context.go @@ -11,9 +11,9 @@ import ( type key int -var ( - permissionsKey key - dataKey key +const ( + permissionsKey key = 1 + dataKey key = 2 ) type CtxData struct { @@ -36,7 +36,7 @@ type Grant struct { type TokenVerifier interface { VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) - ResolveGrants(ctx context.Context, sub, orgID string) ([]*Grant, error) + ResolveGrant(ctx context.Context) (*Grant, error) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) } diff --git a/internal/api/auth/permissions.go b/internal/api/auth/permissions.go index 04c6713915..c0e222c093 100644 --- a/internal/api/auth/permissions.go +++ b/internal/api/auth/permissions.go @@ -11,21 +11,20 @@ func getUserMethodPermissions(ctx context.Context, t TokenVerifier, requiredPerm if ctxData.IsZero() { return nil, nil, errors.ThrowUnauthenticated(nil, "AUTH-rKLWEH", "context missing") } - grants, err := t.ResolveGrants(ctx, ctxData.UserID, ctxData.OrgID) + grant, err := t.ResolveGrant(ctx) if err != nil { return nil, nil, err } - permissions := mapGrantsToPermissions(requiredPerm, grants, authConfig) + permissions := mapGrantToPermissions(requiredPerm, grant, authConfig) return context.WithValue(ctx, permissionsKey, permissions), permissions, nil } -func mapGrantsToPermissions(requiredPerm string, grants []*Grant, authConfig *Config) []string { +func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig *Config) []string { resolvedPermissions := make([]string, 0) - for _, grant := range grants { - for _, role := range grant.Roles { - resolvedPermissions = mapRoleToPerm(requiredPerm, role, authConfig, resolvedPermissions) - } + for _, role := range grant.Roles { + resolvedPermissions = mapRoleToPerm(requiredPerm, role, authConfig, resolvedPermissions) } + return resolvedPermissions } @@ -36,7 +35,7 @@ func mapRoleToPerm(requiredPerm, actualRole string, authConfig *Config, resolved for _, p := range perms { if p == requiredPerm { p = addRoleContextIDToPerm(p, roleContextID) - if !existsPerm(resolvedPermissions, p) { + if !ExistsPerm(resolvedPermissions, p) { resolvedPermissions = append(resolvedPermissions, p) } } @@ -51,7 +50,7 @@ func addRoleContextIDToPerm(perm, roleContextID string) string { return perm } -func existsPerm(existing []string, perm string) bool { +func ExistsPerm(existing []string, perm string) bool { for _, e := range existing { if e == perm { return true diff --git a/internal/api/auth/permissions_test.go b/internal/api/auth/permissions_test.go index fe48172bc7..d4ea7cfb3d 100644 --- a/internal/api/auth/permissions_test.go +++ b/internal/api/auth/permissions_test.go @@ -12,15 +12,15 @@ func getTestCtx(userID, orgID string) context.Context { } type testVerifier struct { - grants []*Grant + grant *Grant } func (v *testVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { return "userID", "clientID", "agentID", nil } -func (v *testVerifier) ResolveGrants(ctx context.Context, sub, orgID string) ([]*Grant, error) { - return v.grants, nil +func (v *testVerifier) ResolveGrant(ctx context.Context) (*Grant, error) { + return v.grant, nil } func (v *testVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { @@ -57,8 +57,8 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "Empty Context", args: args{ ctx: getTestCtx("", ""), - verifier: &testVerifier{grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}}, + verifier: &testVerifier{grant: &Grant{ + Roles: []string{"ORG_OWNER"}}}, requiredPerm: "project.read", authConfig: &Config{ RolePermissionMappings: []RoleMapping{ @@ -81,7 +81,7 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "No Grants", args: args{ ctx: getTestCtx("", ""), - verifier: &testVerifier{grants: []*Grant{}}, + verifier: &testVerifier{grant: &Grant{}}, requiredPerm: "project.read", authConfig: &Config{ RolePermissionMappings: []RoleMapping{ @@ -102,8 +102,8 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "Get Permissions", args: args{ ctx: getTestCtx("userID", "orgID"), - verifier: &testVerifier{grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}}, + verifier: &testVerifier{grant: &Grant{ + Roles: []string{"ORG_OWNER"}}}, requiredPerm: "project.read", authConfig: &Config{ RolePermissionMappings: []RoleMapping{ @@ -143,7 +143,7 @@ func Test_GetUserMethodPermissions(t *testing.T) { func Test_MapGrantsToPermissions(t *testing.T) { type args struct { requiredPerm string - grants []*Grant + grant *Grant authConfig *Config } tests := []struct { @@ -155,8 +155,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "One Role existing perm", args: args{ requiredPerm: "project.read", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -176,8 +175,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "One Role not existing perm", args: args{ requiredPerm: "project.write", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -197,8 +195,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "Multiple Roles one existing", args: args{ requiredPerm: "project.read", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER", "IAM_OWNER"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER", "IAM_OWNER"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -218,8 +215,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "Multiple Roles, global and specific", args: args{ requiredPerm: "project.read", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -238,7 +234,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := mapGrantsToPermissions(tt.args.requiredPerm, tt.args.grants, tt.args.authConfig) + result := mapGrantToPermissions(tt.args.requiredPerm, tt.args.grant, tt.args.authConfig) if !equalStringArray(result, tt.result) { t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result) } @@ -419,7 +415,7 @@ func Test_ExistisPerm(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := existsPerm(tt.args.existing, tt.args.perm) + result := ExistsPerm(tt.args.existing, tt.args.perm) if result != tt.result { t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result) } diff --git a/internal/api/header.go b/internal/api/header.go index bbafe8dd7a..4c2cc77db1 100644 --- a/internal/api/header.go +++ b/internal/api/header.go @@ -7,6 +7,8 @@ const ( ContentType = "content-type" Location = "location" Origin = "origin" + UserAgent = "user-agent" + ForwardedFor = "x-forwarded-for" ZitadelOrgID = "x-zitadel-orgid" //TODO: Remove as soon an authentification is implemented diff --git a/internal/api/http/header.go b/internal/api/http/header.go new file mode 100644 index 0000000000..9df38fce4a --- /dev/null +++ b/internal/api/http/header.go @@ -0,0 +1,71 @@ +package http + +import ( + "context" + "net" + "net/http" + "strings" + + "github.com/caos/zitadel/internal/api" +) + +type key int + +var ( + httpHeaders key + remoteAddr key +) + +func CopyHeadersToContext(h http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), httpHeaders, r.Header) + ctx = context.WithValue(ctx, remoteAddr, r.RemoteAddr) + r = r.WithContext(ctx) + h(w, r) + } +} + +func HeadersFromCtx(ctx context.Context) (http.Header, bool) { + headers, ok := ctx.Value(httpHeaders).(http.Header) + return headers, ok +} + +func RemoteIPFromCtx(ctx context.Context) string { + ctxHeaders, ok := HeadersFromCtx(ctx) + if !ok { + return RemoteAddrFromCtx(ctx) + } + forwarded, ok := ForwardedFor(ctxHeaders) + if ok { + return forwarded + } + return RemoteAddrFromCtx(ctx) +} + +func RemoteIPFromRequest(r *http.Request) net.IP { + return net.ParseIP(RemoteIPStringFromRequest(r)) +} + +func RemoteIPStringFromRequest(r *http.Request) string { + ip, ok := ForwardedFor(r.Header) + if ok { + return ip + } + return r.RemoteAddr +} + +func ForwardedFor(headers http.Header) (string, bool) { + forwarded, ok := headers[api.ForwardedFor] + if ok { + ip := strings.Split(forwarded[0], ", ")[0] + if ip != "" { + return ip, true + } + } + return "", false +} + +func RemoteAddrFromCtx(ctx context.Context) string { + ctxRemoteAddr, _ := ctx.Value(remoteAddr).(string) + return ctxRemoteAddr +} diff --git a/internal/api/http/user_agent_cookie.go b/internal/api/http/user_agent_cookie.go new file mode 100644 index 0000000000..fed230c1a0 --- /dev/null +++ b/internal/api/http/user_agent_cookie.go @@ -0,0 +1,68 @@ +package http + +import ( + "net/http" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/id" +) + +type UserAgent struct { + ID string +} + +type UserAgentHandler struct { + handler *CookieHandler + cookieName string + idGenerator id.Generator +} + +type UserAgentCookieConfig struct { + Name string + Domain string + Key *crypto.KeyConfig +} + +func NewUserAgentHandler(config *UserAgentCookieConfig, idGenerator id.Generator) (*UserAgentHandler, error) { + keys, _, err := crypto.LoadKeys(config.Key) + if err != nil { + return nil, err + } + cookieKey := []byte(keys[config.Key.EncryptionKeyID]) + handler := NewCookieHandler( + WithEncryption(cookieKey, cookieKey), + WithDomain(config.Domain), + WithUnsecure(), + ) + return &UserAgentHandler{ + cookieName: config.Name, + handler: handler, + idGenerator: idGenerator, + }, nil +} + +func (ua *UserAgentHandler) NewUserAgent() (*UserAgent, error) { + agentID, err := ua.idGenerator.Next() + if err != nil { + return nil, err + } + return &UserAgent{ID: agentID}, nil +} + +func (ua *UserAgentHandler) GetUserAgent(r *http.Request) (*UserAgent, error) { + userAgent := new(UserAgent) + err := ua.handler.GetEncryptedCookieValue(r, ua.cookieName, userAgent) + if err != nil { + return nil, errors.ThrowPermissionDenied(err, "HTTP-YULqH4", "cannot read user agent cookie") + } + return userAgent, nil +} + +func (ua *UserAgentHandler) SetUserAgent(w http.ResponseWriter, agent *UserAgent) error { + err := ua.handler.SetEncryptedCookie(w, ua.cookieName, agent) + if err != nil { + return errors.ThrowPermissionDenied(err, "HTTP-AqgqdA", "cannot set user agent cookie") + } + return nil +} diff --git a/internal/auth/auth/token_verifier.go b/internal/auth/auth/token_verifier.go index 84ba0abe38..10dd713abf 100644 --- a/internal/auth/auth/token_verifier.go +++ b/internal/auth/auth/token_verifier.go @@ -3,23 +3,34 @@ package auth import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" +) + +const ( + authName = "Auth-API" ) type TokenVerifier struct { + authID string + authZRepo *authz_repo.EsRepository } -func Start() (v *TokenVerifier) { - return new(TokenVerifier) +func Start(authZRepo *authz_repo.EsRepository) (v *TokenVerifier) { + return &TokenVerifier{authZRepo: authZRepo} } func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { - return "", "", "", nil + userID, clientID, agentID, err := v.authZRepo.VerifyAccessToken(ctx, token, authName, v.authID) + if clientID != "" { + v.authID = clientID + } + return userID, clientID, agentID, err } -func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) { - return nil, nil +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*auth.Grant, error) { + return v.authZRepo.ResolveGrants(ctx) } func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { - return "", nil + return v.authZRepo.ProjectIDByClientID(ctx, clientID) } diff --git a/internal/auth/config.go b/internal/auth/config.go deleted file mode 100644 index bac255b177..0000000000 --- a/internal/auth/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package auth - -type Config struct { -} diff --git a/internal/auth/repository/application.go b/internal/auth/repository/application.go new file mode 100644 index 0000000000..408976a355 --- /dev/null +++ b/internal/auth/repository/application.go @@ -0,0 +1,12 @@ +package repository + +import ( + "context" + + "github.com/caos/zitadel/internal/project/model" +) + +type ApplicationRepository interface { + ApplicationByClientID(ctx context.Context, clientID string) (*model.ApplicationView, error) + AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) error +} diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go index eebdad4cbe..b2e9715ab0 100644 --- a/internal/auth/repository/auth_request.go +++ b/internal/auth/repository/auth_request.go @@ -9,7 +9,12 @@ import ( type AuthRequestRepository interface { CreateAuthRequest(ctx context.Context, request *model.AuthRequest) (*model.AuthRequest, error) AuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) + AuthRequestByIDCheckLoggedIn(ctx context.Context, id string) (*model.AuthRequest, error) + AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) + SaveAuthCode(ctx context.Context, id, code string) error + DeleteAuthRequest(ctx context.Context, id string) error CheckUsername(ctx context.Context, id, username string) error + SelectUser(ctx context.Context, id, userID string) error VerifyPassword(ctx context.Context, id, userID, password string, info *model.BrowserInfo) error VerifyMfaOTP(ctx context.Context, agentID, authRequestID string, code string, info *model.BrowserInfo) error } diff --git a/internal/auth/repository/eventsourcing/eventstore/application.go b/internal/auth/repository/eventsourcing/eventstore/application.go new file mode 100644 index 0000000000..5d5bc76102 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/application.go @@ -0,0 +1,31 @@ +package eventstore + +import ( + "context" + + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + "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" +) + +type ApplicationRepo struct { + View *view.View + ProjectEvents *proj_event.ProjectEventstore +} + +func (a *ApplicationRepo) ApplicationByClientID(ctx context.Context, clientID string) (*model.ApplicationView, error) { + app, err := a.View.ApplicationByClientID(ctx, clientID) + if err != nil { + return nil, err + } + return proj_view_model.ApplicationViewToModel(app), nil +} + +func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) error { + app, err := a.View.ApplicationByClientID(ctx, clientID) + if err != nil { + return err + } + return a.ProjectEvents.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret) +} diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 2cee067357..7063ab8563 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -4,23 +4,28 @@ import ( "context" "time" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/auth_request/model" - "github.com/caos/zitadel/internal/auth_request/repository/cache" + cache "github.com/caos/zitadel/internal/auth_request/repository" "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/id" 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" view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) type AuthRequestRepo struct { UserEvents *user_event.UserEventstore - AuthRequests *cache.AuthRequestCache + AuthRequests cache.AuthRequestCache View *view.View UserSessionViewProvider userSessionViewProvider UserViewProvider userViewProvider + UserEventProvider userEventProvider IdGenerator id.Generator @@ -38,6 +43,10 @@ type userViewProvider interface { UserByID(string) (*view_model.UserView, error) } +type userEventProvider interface { + UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) +} + func (repo *AuthRequestRepo) Health(ctx context.Context) error { if err := repo.UserEvents.Health(ctx); err != nil { return err @@ -51,6 +60,11 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod return nil, err } request.ID = reqID + ids, err := repo.View.AppIDsFromProjectByClientID(ctx, request.ApplicationID) + if err != nil { + return nil, err + } + request.Audience = ids err = repo.AuthRequests.SaveAuthRequest(ctx, request) if err != nil { return nil, err @@ -59,11 +73,28 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod } func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) { + return repo.getAuthRequest(ctx, id, false) +} + +func (repo *AuthRequestRepo) AuthRequestByIDCheckLoggedIn(ctx context.Context, id string) (*model.AuthRequest, error) { + return repo.getAuthRequest(ctx, id, true) +} + +func (repo *AuthRequestRepo) SaveAuthCode(ctx context.Context, id, code string) error { request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) + if err != nil { + return err + } + request.Code = code + return repo.AuthRequests.UpdateAuthRequest(ctx, request) +} + +func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) { + request, err := repo.AuthRequests.GetAuthRequestByCode(ctx, code) if err != nil { return nil, err } - steps, err := repo.nextSteps(request) + steps, err := repo.nextSteps(ctx, request, true) if err != nil { return nil, err } @@ -71,6 +102,10 @@ func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id string) (*m return request, nil } +func (repo *AuthRequestRepo) DeleteAuthRequest(ctx context.Context, id string) error { + return repo.AuthRequests.DeleteAuthRequest(ctx, id) +} + func (repo *AuthRequestRepo) CheckUsername(ctx context.Context, id, username string) error { request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) if err != nil { @@ -80,8 +115,21 @@ func (repo *AuthRequestRepo) CheckUsername(ctx context.Context, id, username str if err != nil { return err } - request.UserID = user.ID - return repo.AuthRequests.SaveAuthRequest(ctx, request) + request.SetUserInfo(user.ID, user.UserName, user.ResourceOwner) + return repo.AuthRequests.UpdateAuthRequest(ctx, request) +} + +func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID string) error { + request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) + if err != nil { + return err + } + user, err := repo.View.UserByID(userID) + if err != nil { + return err + } + request.SetUserInfo(user.ID, user.UserName, user.ResourceOwner) + return repo.AuthRequests.UpdateAuthRequest(ctx, request) } func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password string, info *model.BrowserInfo) error { @@ -89,8 +137,8 @@ func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, pas if err != nil { return err } - if request.UserID == userID { - return errors.ThrowPreconditionFailed(nil, "EVENT-ds35D", "user id does not match request id ") + if request.UserID != userID { + return errors.ThrowPreconditionFailed(nil, "EVENT-ds35D", "user id does not match request id") } return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info)) } @@ -106,15 +154,29 @@ func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, us return repo.UserEvents.CheckMfaOTP(ctx, userID, code, request.WithCurrentInfo(info)) } -func (repo *AuthRequestRepo) nextSteps(request *model.AuthRequest) ([]model.NextStep, error) { +func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id string, checkLoggedIn bool) (*model.AuthRequest, error) { + request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) + if err != nil { + return nil, err + } + steps, err := repo.nextSteps(ctx, request, checkLoggedIn) + if err != nil { + return nil, err + } + request.PossibleSteps = steps + return request, nil +} + +func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthRequest, checkLoggedIn bool) ([]model.NextStep, error) { if request == nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "request must not be nil") } steps := make([]model.NextStep, 0) + if !checkLoggedIn && request.Prompt == model.PromptNone { + return append(steps, &model.RedirectToCallbackStep{}), nil + } if request.UserID == "" { - if request.Prompt != model.PromptNone { - steps = append(steps, &model.LoginStep{}) - } + steps = append(steps, &model.LoginStep{}) if request.Prompt == model.PromptSelectAccount { users, err := repo.usersForUserSelection(request) if err != nil { @@ -124,15 +186,18 @@ func (repo *AuthRequestRepo) nextSteps(request *model.AuthRequest) ([]model.Next } return steps, nil } - userSession, err := userSessionByIDs(repo.UserSessionViewProvider, request.AgentID, request.UserID) + user, err := userByID(ctx, repo.UserViewProvider, repo.UserEventProvider, request.UserID) if err != nil { return nil, err } - user, err := userByID(repo.UserViewProvider, request.UserID) + userSession, err := userSessionByIDs(ctx, repo.UserSessionViewProvider, repo.UserEventProvider, request.AgentID, user) if err != nil { return nil, err } + if user.InitRequired { + return append(steps, &model.InitUserStep{PasswordSet: user.PasswordSet}), nil + } if !user.PasswordSet { return append(steps, &model.InitPasswordStep{}), nil } @@ -140,6 +205,8 @@ func (repo *AuthRequestRepo) nextSteps(request *model.AuthRequest) ([]model.Next if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) { return append(steps, &model.PasswordStep{}), nil } + request.PasswordVerified = true + request.AuthTime = userSession.PasswordVerification if step, ok := repo.mfaChecked(userSession, request, user); !ok { return append(steps, step), nil @@ -178,23 +245,32 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) ( func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool) { mfaLevel := request.MfaLevel() - required := user.MfaMaxSetUp < mfaLevel - if required || !repo.mfaSkippedOrSetUp(user) { + promptRequired := user.MfaMaxSetUp < mfaLevel + if promptRequired || !repo.mfaSkippedOrSetUp(user) { return &model.MfaPromptStep{ - Required: required, + Required: promptRequired, MfaProviders: user.MfaTypesSetupPossible(mfaLevel), }, false } switch mfaLevel { default: fallthrough + case model.MfaLevelNotSetUp: + if user.MfaMaxSetUp == model.MfaLevelNotSetUp { + return nil, true + } + fallthrough case model.MfaLevelSoftware: if checkVerificationTime(userSession.MfaSoftwareVerification, repo.MfaSoftwareCheckLifeTime) { + request.MfasVerified = append(request.MfasVerified, userSession.MfaSoftwareVerificationType) + request.AuthTime = userSession.MfaSoftwareVerification return nil, true } fallthrough case model.MfaLevelHardware: if checkVerificationTime(userSession.MfaHardwareVerification, repo.MfaHardwareCheckLifeTime) { + request.MfasVerified = append(request.MfasVerified, userSession.MfaHardwareVerificationType) + request.AuthTime = userSession.MfaHardwareVerification return nil, true } } @@ -204,7 +280,7 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, } func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool { - if user.MfaMaxSetUp >= 0 { + if user.MfaMaxSetUp > model.MfaLevelNotSetUp { return true } return checkVerificationTime(user.MfaInitSkipped, repo.MfaInitSkippedLifeTime) @@ -222,18 +298,55 @@ func userSessionsByUserAgentID(provider userSessionViewProvider, agentID string) return view_model.UserSessionsToModel(session), nil } -func userSessionByIDs(provider userSessionViewProvider, agentID, userID string) (*user_model.UserSessionView, error) { - session, err := provider.UserSessionByIDs(agentID, userID) +func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eventProvider userEventProvider, agentID string, user *user_model.UserView) (*user_model.UserSessionView, error) { + session, err := provider.UserSessionByIDs(agentID, user.ID) if err != nil { - return nil, err + if !errors.IsNotFound(err) { + return nil, err + } + session = &view_model.UserSessionView{} } - return view_model.UserSessionToModel(session), nil + events, err := eventProvider.UserEventsByID(ctx, user.ID, session.Sequence) + if err != nil { + logging.Log("EVENT-Hse6s").WithError(err).Debug("error retrieving new events") + return view_model.UserSessionToModel(session), nil + } + sessionCopy := *session + for _, event := range events { + switch event.Type { + case es_model.UserPasswordCheckSucceeded, + es_model.UserPasswordCheckFailed, + es_model.MfaOtpCheckSucceeded, + es_model.MfaOtpCheckFailed: + eventData, err := view_model.UserSessionFromEvent(event) + if err != nil { + logging.Log("EVENT-sdgT3").WithError(err).Debug("error getting event data") + return view_model.UserSessionToModel(session), nil + } + if eventData.UserAgentID != agentID { + continue + } + } + sessionCopy.AppendEvent(event) + } + return view_model.UserSessionToModel(&sessionCopy), nil } -func userByID(provider userViewProvider, userID string) (*user_model.UserView, error) { - user, err := provider.UserByID(userID) +func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider userEventProvider, userID string) (*user_model.UserView, error) { + user, err := viewProvider.UserByID(userID) if err != nil { return nil, err } - return view_model.UserToModel(user), nil + events, err := eventProvider.UserEventsByID(ctx, userID, user.Sequence) + if err != nil { + logging.Log("EVENT-dfg42").WithError(err).Debug("error retrieving new events") + return view_model.UserToModel(user), nil + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return view_model.UserToModel(user), nil + } + } + return view_model.UserToModel(&userCopy), nil } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index 9500118d07..a57f63df8e 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -1,6 +1,8 @@ package eventstore import ( + "context" + "encoding/json" "testing" "time" @@ -10,8 +12,10 @@ import ( "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/auth_request/repository/cache" "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" user_model "github.com/caos/zitadel/internal/user/model" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" + user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) @@ -25,6 +29,16 @@ func (m *mockViewNoUserSession) UserSessionsByAgentID(string) ([]*view_model.Use return nil, errors.ThrowInternal(nil, "id", "internal error") } +type mockViewErrUserSession struct{} + +func (m *mockViewErrUserSession) UserSessionByIDs(string, string) (*view_model.UserSessionView, error) { + return nil, errors.ThrowInternal(nil, "id", "internal error") +} + +func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*view_model.UserSessionView, error) { + return nil, errors.ThrowInternal(nil, "id", "internal error") +} + type mockViewUserSession struct { PasswordVerification time.Time MfaSoftwareVerification time.Time @@ -60,7 +74,26 @@ func (m *mockViewNoUser) UserByID(string) (*view_model.UserView, error) { return nil, errors.ThrowNotFound(nil, "id", "user not found") } +type mockEventUser struct { + Event *es_models.Event +} + +func (m *mockEventUser) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + events := make([]*es_models.Event, 0) + if m.Event != nil { + events = append(events, m.Event) + } + return events, nil +} + +type mockEventErrUser struct{} + +func (m *mockEventErrUser) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + return nil, errors.ThrowInternal(nil, "id", "internal error") +} + type mockViewUser struct { + InitRequired bool PasswordSet bool PasswordChangeRequired bool IsEmailVerified bool @@ -71,6 +104,7 @@ type mockViewUser struct { func (m *mockViewUser) UserByID(string) (*view_model.UserView, error) { return &view_model.UserView{ + InitRequired: m.InitRequired, PasswordSet: m.PasswordSet, PasswordChangeRequired: m.PasswordChangeRequired, IsEmailVerified: m.IsEmailVerified, @@ -87,13 +121,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { View *view.View userSessionViewProvider userSessionViewProvider userViewProvider userViewProvider + userEventProvider userEventProvider PasswordCheckLifeTime time.Duration MfaInitSkippedLifeTime time.Duration MfaSoftwareCheckLifeTime time.Duration MfaHardwareCheckLifeTime time.Duration } type args struct { - request *model.AuthRequest + request *model.AuthRequest + checkLoggedIn bool } tests := []struct { name string @@ -105,22 +141,22 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { { "request nil, error", fields{}, - args{nil}, + args{nil, false}, nil, errors.IsErrorInvalidArgument, }, { - "user not set, login step", + "prompt none and checkLoggedIn false, callback step", fields{}, - args{&model.AuthRequest{}}, - []model.NextStep{&model.LoginStep{}}, + args{&model.AuthRequest{Prompt: model.PromptNone}, false}, + []model.NextStep{&model.RedirectToCallbackStep{}}, nil, }, { - "user not set and prompt none, no step", + "user not set, login step", fields{}, - args{&model.AuthRequest{Prompt: model.PromptNone}}, - []model.NextStep{}, + args{&model.AuthRequest{}, false}, + []model.NextStep{&model.LoginStep{}}, nil, }, { @@ -128,7 +164,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { fields{ userSessionViewProvider: &mockViewNoUserSession{}, }, - args{&model.AuthRequest{Prompt: model.PromptSelectAccount}}, + args{&model.AuthRequest{Prompt: model.PromptSelectAccount}, false}, nil, errors.IsInternal, }, @@ -147,8 +183,9 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, }, }, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{Prompt: model.PromptSelectAccount}}, + args{&model.AuthRequest{Prompt: model.PromptSelectAccount}, false}, []model.NextStep{ &model.LoginStep{}, &model.SelectUserStep{ @@ -166,31 +203,63 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { nil, }, { - "usersession not found, not found error", + "user not not found, not found error", fields{ - userSessionViewProvider: &mockViewNoUserSession{}, + userViewProvider: &mockViewNoUser{}, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, nil, errors.IsNotFound, }, { - "user not not found, not found error", + "usersession not found, new user session, password step", + fields{ + userSessionViewProvider: &mockViewNoUserSession{}, + userViewProvider: &mockViewUser{ + PasswordSet: true, + }, + userEventProvider: &mockEventUser{}, + }, + args{&model.AuthRequest{UserID: "UserID"}, false}, + []model.NextStep{&model.PasswordStep{}}, + nil, + }, + { + "usersession error, internal error", + fields{ + userSessionViewProvider: &mockViewErrUserSession{}, + userViewProvider: &mockViewUser{}, + userEventProvider: &mockEventUser{}, + }, + args{&model.AuthRequest{UserID: "UserID"}, false}, + nil, + errors.IsInternal, + }, + { + "user not initialized, init user step", fields{ userSessionViewProvider: &mockViewUserSession{}, - userViewProvider: &mockViewNoUser{}, + userViewProvider: &mockViewUser{ + InitRequired: true, + PasswordSet: true, + }, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, + []model.NextStep{&model.InitUserStep{ + PasswordSet: true, + }}, nil, - errors.IsNotFound, }, { "password not set, init password step", fields{ userSessionViewProvider: &mockViewUserSession{}, userViewProvider: &mockViewUser{}, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.InitPasswordStep{}}, nil, }, @@ -201,9 +270,10 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { userViewProvider: &mockViewUser{ PasswordSet: true, }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.PasswordStep{}}, nil, }, @@ -218,10 +288,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { OTPState: int32(user_model.MFASTATE_READY), MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.MfaVerificationStep{ MfaProviders: []model.MfaType{model.MfaTypeOTP}, }}, @@ -238,11 +309,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { PasswordSet: true, PasswordChangeRequired: true, IsEmailVerified: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.ChangePasswordStep{}}, nil, }, @@ -255,11 +328,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, userViewProvider: &mockViewUser{ PasswordSet: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.VerifyEMailStep{}}, nil, }, @@ -273,11 +348,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { userViewProvider: &mockViewUser{ PasswordSet: true, PasswordChangeRequired: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.ChangePasswordStep{}, &model.VerifyEMailStep{}}, nil, }, @@ -291,11 +368,33 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { userViewProvider: &mockViewUser{ PasswordSet: true, IsEmailVerified: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, + []model.NextStep{&model.RedirectToCallbackStep{}}, + nil, + }, + { + "prompt none, checkLoggedIn true and authenticated, redirect to callback step", + fields{ + userSessionViewProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Add(-5 * time.Minute), + MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute), + }, + userViewProvider: &mockViewUser{ + PasswordSet: true, + IsEmailVerified: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), + }, + userEventProvider: &mockEventUser{}, + PasswordCheckLifeTime: 10 * 24 * time.Hour, + MfaSoftwareCheckLifeTime: 18 * time.Hour, + }, + args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone}, true}, []model.NextStep{&model.RedirectToCallbackStep{}}, nil, }, @@ -308,12 +407,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { View: tt.fields.View, UserSessionViewProvider: tt.fields.userSessionViewProvider, UserViewProvider: tt.fields.userViewProvider, + UserEventProvider: tt.fields.userEventProvider, PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime, MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime, MfaSoftwareCheckLifeTime: tt.fields.MfaSoftwareCheckLifeTime, MfaHardwareCheckLifeTime: tt.fields.MfaHardwareCheckLifeTime, } - got, err := repo.nextSteps(tt.args.request) + got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn) if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) { t.Errorf("nextSteps() wrong error = %v", err) return @@ -360,14 +460,31 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { args{ request: &model.AuthRequest{}, user: &user_model.UserView{ - MfaMaxSetUp: -1, + MfaMaxSetUp: model.MfaLevelNotSetUp, }, }, &model.MfaPromptStep{ - MfaProviders: []model.MfaType{}, + MfaProviders: []model.MfaType{ + model.MfaTypeOTP, + }, }, false, }, + { + "not set up and skipped, true", + fields{ + MfaInitSkippedLifeTime: 30 * 24 * time.Hour, + }, + args{ + request: &model.AuthRequest{}, + user: &user_model.UserView{ + MfaMaxSetUp: model.MfaLevelNotSetUp, + MfaInitSkipped: time.Now().UTC(), + }, + }, + nil, + true, + }, { "checked mfa software, true", fields{ @@ -376,7 +493,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { args{ request: &model.AuthRequest{}, user: &user_model.UserView{ - OTPState: user_model.MFASTATE_READY, + MfaMaxSetUp: model.MfaLevelSoftware, + OTPState: user_model.MFASTATE_READY, }, userSession: &user_model.UserSessionView{MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Hour)}, }, @@ -391,7 +509,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { args{ request: &model.AuthRequest{}, user: &user_model.UserView{ - OTPState: user_model.MFASTATE_READY, + MfaMaxSetUp: model.MfaLevelSoftware, + OTPState: user_model.MFASTATE_READY, }, userSession: &user_model.UserSessionView{}, }, @@ -473,3 +592,235 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) { }) } } + +func Test_userSessionByIDs(t *testing.T) { + type args struct { + userProvider userSessionViewProvider + eventProvider userEventProvider + agentID string + user *user_model.UserView + } + tests := []struct { + name string + args args + want *user_model.UserSessionView + wantErr func(error) bool + }{ + { + "not found, new session", + args{ + userProvider: &mockViewNoUserSession{}, + eventProvider: &mockEventErrUser{}, + user: &user_model.UserView{ID: "id"}, + }, + &user_model.UserSessionView{}, + nil, + }, + { + "internal error, internal error", + args{ + userProvider: &mockViewErrUserSession{}, + user: &user_model.UserView{ID: "id"}, + }, + nil, + errors.IsInternal, + }, + { + "error user events, old view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventErrUser{}, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Time{}, + MfaHardwareVerification: time.Time{}, + }, + nil, + }, + { + "new user events but error, old view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + agentID: "agentID", + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.MfaOtpCheckSucceeded, + CreationDate: time.Now().UTC().Round(1 * time.Second), + }, + }, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Time{}, + MfaHardwareVerification: time.Time{}, + }, + nil, + }, + { + "new user events but other agentID, old view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + agentID: "agentID", + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.MfaOtpCheckSucceeded, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: func() []byte { + data, _ := json.Marshal(&user_es_model.AuthRequest{UserAgentID: "otherID"}) + return data + }(), + }, + }, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Time{}, + MfaHardwareVerification: time.Time{}, + }, + nil, + }, + { + "new user events, new view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + agentID: "agentID", + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.MfaOtpCheckSucceeded, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: func() []byte { + data, _ := json.Marshal(&user_es_model.AuthRequest{UserAgentID: "agentID"}) + return data + }(), + }, + }, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Now().UTC().Round(1 * time.Second), + ChangeDate: time.Now().UTC().Round(1 * time.Second), + }, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := userSessionByIDs(context.Background(), tt.args.userProvider, tt.args.eventProvider, tt.args.agentID, tt.args.user) + if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) { + t.Errorf("nextSteps() wrong error = %v", err) + return + } + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_userByID(t *testing.T) { + type args struct { + ctx context.Context + viewProvider userViewProvider + eventProvider userEventProvider + userID string + } + tests := []struct { + name string + args args + want *user_model.UserView + wantErr func(error) bool + }{ + + { + "not found, not found error", + args{ + viewProvider: &mockViewNoUser{}, + }, + nil, + errors.IsNotFound, + }, + { + "error user events, old view model state", + args{ + viewProvider: &mockViewUser{ + PasswordChangeRequired: true, + }, + eventProvider: &mockEventErrUser{}, + }, + &user_model.UserView{ + PasswordChangeRequired: true, + }, + nil, + }, + { + "new user events but error, old view model state", + args{ + viewProvider: &mockViewUser{ + PasswordChangeRequired: true, + }, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.UserPasswordChanged, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: nil, + }, + }, + }, + &user_model.UserView{ + PasswordChangeRequired: true, + }, + nil, + }, + { + "new user events, new view model state", + args{ + viewProvider: &mockViewUser{ + PasswordChangeRequired: true, + }, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.UserPasswordChanged, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: func() []byte { + data, _ := json.Marshal(user_es_model.Password{ChangeRequired: false}) + return data + }(), + }, + }, + }, + &user_model.UserView{ + PasswordChangeRequired: false, + ChangeDate: time.Now().UTC().Round(1 * time.Second), + State: user_model.USERSTATE_INITIAL, + PasswordChanged: time.Now().UTC().Round(1 * time.Second), + }, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := userByID(tt.args.ctx, tt.args.viewProvider, tt.args.eventProvider, tt.args.userID) + if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) { + t.Errorf("nextSteps() wrong error = %v", err) + return + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/auth/repository/eventsourcing/eventstore/iam.go b/internal/auth/repository/eventsourcing/eventstore/iam.go new file mode 100644 index 0000000000..e27c6a92f4 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/iam.go @@ -0,0 +1,16 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/iam/model" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" +) + +type IamRepository struct { + IamID string + IamEvents *iam_event.IamEventstore +} + +func (repo *IamRepository) GetIam(ctx context.Context) (*model.Iam, error) { + return repo.IamEvents.IamByID(ctx, repo.IamID) +} diff --git a/internal/auth/repository/eventsourcing/eventstore/key.go b/internal/auth/repository/eventsourcing/eventstore/key.go new file mode 100644 index 0000000000..1372d56885 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/key.go @@ -0,0 +1,75 @@ +package eventstore + +import ( + "context" + "time" + + "gopkg.in/square/go-jose.v2" + + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/key/model" + key_event "github.com/caos/zitadel/internal/key/repository/eventsourcing" +) + +const ( + oidcUser = "OIDC" + iamOrg = "IAM" +) + +type KeyRepository struct { + KeyEvents *key_event.KeyEventstore + View *view.View + SigningKeyRotation time.Duration +} + +func (k *KeyRepository) GenerateSigningKeyPair(ctx context.Context, algorithm string) error { + ctx = setOIDCCtx(ctx) + _, err := k.KeyEvents.GenerateKeyPair(ctx, model.KeyUsageSigning, algorithm) + return err +} + +func (k *KeyRepository) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, renewTimer <-chan time.Time) { + go func() { + for { + select { + case <-ctx.Done(): + return + case <-renewTimer: + k.refreshSigningKey(keyCh, errCh) + renewTimer = time.After(k.SigningKeyRotation) + } + } + }() +} + +func (k *KeyRepository) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) { + keys, err := k.View.GetActiveKeySet() + if err != nil { + return nil, err + } + webKeys := make([]jose.JSONWebKey, len(keys)) + for i, key := range keys { + webKeys[i] = jose.JSONWebKey{KeyID: key.ID, Algorithm: key.Algorithm, Use: key.Usage.String(), Key: key.Key} + } + return &jose.JSONWebKeySet{Keys: webKeys}, nil +} + +func (k *KeyRepository) refreshSigningKey(keyCh chan<- jose.SigningKey, errCh chan<- error) { + key, err := k.View.GetSigningKey() + if err != nil { + errCh <- err + return + } + keyCh <- jose.SigningKey{ + Algorithm: jose.SignatureAlgorithm(key.Algorithm), + Key: jose.JSONWebKey{ + KeyID: key.ID, + Key: key.Key, + }, + } +} + +func setOIDCCtx(ctx context.Context) context.Context { + return auth.SetCtxData(ctx, auth.CtxData{UserID: oidcUser, OrgID: iamOrg}) +} diff --git a/internal/auth/repository/eventsourcing/eventstore/org.go b/internal/auth/repository/eventsourcing/eventstore/org.go new file mode 100644 index 0000000000..bcede6a500 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/org.go @@ -0,0 +1,29 @@ +package eventstore + +import ( + "context" + auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + org_model "github.com/caos/zitadel/internal/org/model" + org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/org/repository/view" +) + +type OrgRepository struct { + SearchLimit uint64 + *org_es.OrgEventstore + View *auth_view.View +} + +func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) { + request.EnsureLimit(repo.SearchLimit) + members, count, err := repo.View.SearchOrgs(request) + if err != nil { + return nil, err + } + return &org_model.OrgSearchResult{ + Offset: request.Offset, + Limit: request.Limit, + TotalResult: uint64(count), + Result: view.OrgsToModel(members), + }, nil +} diff --git a/internal/auth/repository/eventsourcing/eventstore/token.go b/internal/auth/repository/eventsourcing/eventstore/token.go index bceae0a43c..0bc4339b93 100644 --- a/internal/auth/repository/eventsourcing/eventstore/token.go +++ b/internal/auth/repository/eventsourcing/eventstore/token.go @@ -13,8 +13,8 @@ type TokenRepo struct { View *view.View } -func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, lifetime time.Duration) (*token_model.Token, error) { - token, err := repo.View.CreateToken(agentID, applicationID, userID, lifetime) +func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*token_model.Token, error) { + token, err := repo.View.CreateToken(agentID, applicationID, userID, audience, scopes, lifetime) if err != nil { return nil, err } @@ -24,3 +24,11 @@ func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, func (repo *TokenRepo) IsTokenValid(ctx context.Context, tokenID string) (bool, error) { return repo.View.IsTokenValid(tokenID) } + +func (repo *TokenRepo) TokenByID(ctx context.Context, tokenID string) (*token_model.Token, error) { + token, err := repo.View.TokenByID(tokenID) + if err != nil { + return nil, err + } + return token_view_model.TokenToModel(token), nil +} diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go index 7ffa707318..05decdf900 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user.go +++ b/internal/auth/repository/eventsourcing/eventstore/user.go @@ -56,10 +56,18 @@ func (repo *UserRepo) ChangeMyEmail(ctx context.Context, email *model.Email) (*m return repo.UserEvents.ChangeEmail(ctx, email) } +func (repo *UserRepo) VerifyEmail(ctx context.Context, userID, code string) error { + return repo.UserEvents.VerifyEmail(ctx, userID, code) +} + func (repo *UserRepo) VerifyMyEmail(ctx context.Context, code string) error { return repo.UserEvents.VerifyEmail(ctx, auth.GetCtxData(ctx).UserID, code) } +func (repo *UserRepo) ResendEmailVerificationMail(ctx context.Context, userID string) error { + return repo.UserEvents.CreateEmailVerificationCode(ctx, userID) +} + func (repo *UserRepo) ResendMyEmailVerificationMail(ctx context.Context) error { return repo.UserEvents.CreateEmailVerificationCode(ctx, auth.GetCtxData(ctx).UserID) } @@ -103,11 +111,28 @@ func (repo *UserRepo) ChangeMyPassword(ctx context.Context, old, new string) err return err } +func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new string) error { + policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID) + if err != nil { + return err + } + _, err = repo.UserEvents.ChangePassword(ctx, policy, userID, old, new) + return err +} + +func (repo *UserRepo) AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) { + return repo.UserEvents.AddOTP(ctx, userID) +} + func (repo *UserRepo) AddMyMfaOTP(ctx context.Context) (*model.OTP, error) { return repo.UserEvents.AddOTP(ctx, auth.GetCtxData(ctx).UserID) } -func (repo *UserRepo) VerifyMyMfaOTP(ctx context.Context, code string) error { +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, auth.GetCtxData(ctx).UserID, code) } @@ -115,6 +140,19 @@ func (repo *UserRepo) RemoveMyMfaOTP(ctx context.Context) error { return repo.UserEvents.RemoveOTP(ctx, auth.GetCtxData(ctx).UserID) } +func (repo *UserRepo) ResendInitVerificationMail(ctx context.Context, userID string) error { + _, err := repo.UserEvents.CreateInitializeUserCodeByID(ctx, userID) + return err +} + +func (repo *UserRepo) VerifyInitCode(ctx context.Context, userID, code, password string) error { + policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID) + if err != nil { + return err + } + return repo.UserEvents.VerifyInitCode(ctx, policy, userID, code, password) +} + func (repo *UserRepo) SkipMfaInit(ctx context.Context, userID string) error { return repo.UserEvents.SkipMfaInit(ctx, userID) } @@ -139,6 +177,10 @@ func (repo *UserRepo) SignOut(ctx context.Context, agentID, userID string) error return repo.UserEvents.SignOut(ctx, agentID, userID) } +func (repo *UserRepo) UserByID(ctx context.Context, userID string) (*model.User, error) { + return repo.UserEvents.UserByID(ctx, userID) +} + func checkIDs(ctx context.Context, obj es_models.ObjectRoot) error { if obj.AggregateID != auth.GetCtxData(ctx).UserID { return errors.ThrowPermissionDenied(nil, "EVENT-kFi9w", "object does not belong to user") diff --git a/internal/auth/repository/eventsourcing/eventstore/user_grant.go b/internal/auth/repository/eventsourcing/eventstore/user_grant.go new file mode 100644 index 0000000000..cad53713c5 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/user_grant.go @@ -0,0 +1,158 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + caos_errs "github.com/caos/zitadel/internal/errors" + global_model "github.com/caos/zitadel/internal/model" + org_model "github.com/caos/zitadel/internal/org/model" + org_view "github.com/caos/zitadel/internal/org/repository/view" + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" +) + +type UserGrantRepo struct { + SearchLimit uint64 + View *view.View + IamID string + Auth auth.Config + AuthZRepo *authz_repo.EsRepository +} + +func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) { + request.EnsureLimit(repo.SearchLimit) + request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_USER_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: auth.GetCtxData(ctx).UserID}) + grants, count, err := repo.View.SearchUserGrants(request) + if err != nil { + return nil, err + } + return &grant_model.UserGrantSearchResponse{ + Offset: request.Offset, + Limit: request.Limit, + TotalResult: uint64(count), + Result: model.UserGrantsToModel(grants), + }, nil +} + +func (repo *UserGrantRepo) SearchMyProjectOrgs(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) { + request.EnsureLimit(repo.SearchLimit) + ctxData := auth.GetCtxData(ctx) + if ctxData.ProjectID == "" { + return nil, caos_errs.ThrowPreconditionFailed(nil, "APP-7lqva", "Could not get ProjectID") + } + if ctxData.ProjectID == repo.AuthZRepo.IamProjectID { + isAdmin, err := repo.IsIamAdmin(ctx) + if err != nil { + return nil, err + } + if isAdmin { + return repo.SearchAdminOrgs(request) + } + } + request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: ctxData.ProjectID}) + + grants, err := repo.SearchMyUserGrants(ctx, request) + if err != nil { + return nil, err + } + return grantRespToOrgResp(grants), nil +} + +func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) { + grant, err := repo.AuthZRepo.ResolveGrants(ctx) + if err != nil { + return nil, err + } + permissions := &grant_model.Permissions{Permissions: []string{}} + for _, role := range grant.Roles { + roleName, ctxID := auth.SplitPermission(role) + for _, mapping := range repo.Auth.RolePermissionMappings { + if mapping.Role == roleName { + permissions.AppendPermissions(ctxID, mapping.Permissions...) + } + } + } + return permissions.Permissions, nil +} + +func (repo *UserGrantRepo) SearchAdminOrgs(request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) { + searchRequest := &org_model.OrgSearchRequest{} + if len(request.Queries) > 0 { + for _, q := range request.Queries { + if q.Key == grant_model.USERGRANTSEARCHKEY_ORG_NAME { + searchRequest.Queries = append(searchRequest.Queries, &org_model.OrgSearchQuery{Key: org_model.ORGSEARCHKEY_ORG_NAME, Method: q.Method, Value: q.Value}) + } + } + } + orgs, count, err := repo.View.SearchOrgs(searchRequest) + if err != nil { + return nil, err + } + return orgRespToOrgResp(orgs, count), nil +} + +func (repo *UserGrantRepo) IsIamAdmin(ctx context.Context) (bool, error) { + grantSearch := &grant_model.UserGrantSearchRequest{ + Queries: []*grant_model.UserGrantSearchQuery{ + &grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, Method: global_model.SEARCHMETHOD_EQUALS, Value: repo.IamID}, + }} + result, err := repo.SearchMyUserGrants(ctx, grantSearch) + if err != nil { + return false, err + } + if result.TotalResult == 0 { + return false, nil + } + return true, nil +} + +func grantRespToOrgResp(grants *grant_model.UserGrantSearchResponse) *grant_model.ProjectOrgSearchResponse { + resp := &grant_model.ProjectOrgSearchResponse{ + TotalResult: grants.TotalResult, + } + resp.Result = make([]*grant_model.Org, len(grants.Result)) + for i, g := range grants.Result { + resp.Result[i] = &grant_model.Org{OrgID: g.ResourceOwner, OrgName: g.OrgName} + } + return resp +} + +func orgRespToOrgResp(orgs []*org_view.OrgView, count int) *grant_model.ProjectOrgSearchResponse { + resp := &grant_model.ProjectOrgSearchResponse{ + TotalResult: uint64(count), + } + resp.Result = make([]*grant_model.Org, len(orgs)) + for i, o := range orgs { + resp.Result[i] = &grant_model.Org{OrgID: o.ID, OrgName: o.Name} + } + return resp +} + +func mergeOrgAndAdminGrant(ctxData auth.CtxData, orgGrant, iamAdminGrant *model.UserGrantView) (grant *auth.Grant) { + if orgGrant != nil { + roles := orgGrant.RoleKeys + if iamAdminGrant != nil { + roles = addIamAdminRoles(roles, iamAdminGrant.RoleKeys) + } + grant = &auth.Grant{OrgID: orgGrant.ResourceOwner, Roles: roles} + } else if iamAdminGrant != nil { + grant = &auth.Grant{ + OrgID: ctxData.OrgID, + Roles: iamAdminGrant.RoleKeys, + } + } + return grant +} + +func addIamAdminRoles(orgRoles, iamAdminRoles []string) []string { + result := make([]string, 0) + result = append(result, iamAdminRoles...) + for _, role := range orgRoles { + if !auth.ExistsPerm(result, role) { + result = append(result, role) + } + } + return result +} diff --git a/internal/auth/repository/eventsourcing/eventstore/user_session.go b/internal/auth/repository/eventsourcing/eventstore/user_session.go new file mode 100644 index 0000000000..897d36fcd5 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/user_session.go @@ -0,0 +1,21 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/user/repository/view/model" +) + +type UserSessionRepo struct { + View *view.View +} + +func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_model.UserSessionView, error) { + userSessions, err := repo.View.UserSessionsByUserID(auth.GetCtxData(ctx).UserID) + if err != nil { + return nil, err + } + return model.UserSessionsToModel(userSessions), nil +} diff --git a/internal/auth/repository/eventsourcing/handler/application.go b/internal/auth/repository/eventsourcing/handler/application.go new file mode 100644 index 0000000000..43b7704340 --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/application.go @@ -0,0 +1,74 @@ +package handler + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/project/repository/view/model" + "time" +) + +type Application struct { + handler + projectEvents *proj_event.ProjectEventstore +} + +const ( + applicationTable = "auth.applications" +) + +func (p *Application) MinimumCycleDuration() time.Duration { return p.cycleDuration } + +func (p *Application) ViewModel() string { + return applicationTable +} + +func (p *Application) EventQuery() (*models.SearchQuery, error) { + sequence, err := p.view.GetLatestApplicationSequence() + if err != nil { + return nil, err + } + return eventsourcing.ProjectQuery(sequence), nil +} + +func (p *Application) Process(event *models.Event) (err error) { + app := new(view_model.ApplicationView) + switch event.Type { + case es_model.ApplicationAdded: + app.AppendEvent(event) + case es_model.ApplicationChanged, + es_model.OIDCConfigAdded, + es_model.OIDCConfigChanged, + es_model.ApplicationDeactivated, + es_model.ApplicationReactivated: + err := app.SetData(event) + if err != nil { + return err + } + app, err = p.view.ApplicationByID(app.ID) + if err != nil { + return err + } + app.AppendEvent(event) + case es_model.ApplicationRemoved: + err := app.SetData(event) + if err != nil { + return err + } + return p.view.DeleteApplication(app.ID, event.Sequence) + default: + return p.view.ProcessedApplicationSequence(event.Sequence) + } + if err != nil { + return err + } + return p.view.PutApplication(app) +} + +func (p *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) +} diff --git a/internal/auth/repository/eventsourcing/handler/handler.go b/internal/auth/repository/eventsourcing/handler/handler.go index 991bc97bd2..bf50a30dd6 100644 --- a/internal/auth/repository/eventsourcing/handler/handler.go +++ b/internal/auth/repository/eventsourcing/handler/handler.go @@ -1,9 +1,15 @@ package handler import ( + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/eventstore" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" "time" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore/spooler" usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) @@ -11,7 +17,7 @@ import ( type Configs map[string]*Config type Config struct { - MinimumCycleDurationMillisecond int + MinimumCycleDuration types.Duration } type handler struct { @@ -22,14 +28,28 @@ type handler struct { } type EventstoreRepos struct { - UserEvents *usr_event.UserEventstore + UserEvents *usr_event.UserEventstore + ProjectEvents *proj_event.ProjectEventstore + OrgEvents *org_events.OrgEventstore + IamEvents *iam_events.IamEventstore } -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, repos EventstoreRepos) []spooler.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []spooler.Handler { return []spooler.Handler{ &User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}}, &UserSession{handler: handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount}, userEvents: repos.UserEvents}, &Token{handler: handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount}}, + &Key{handler: handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount}}, + &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}}, + &Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}}, + &UserGrant{ + handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, + eventstore: eventstore, + userEvents: repos.UserEvents, + orgEvents: repos.OrgEvents, + projectEvents: repos.ProjectEvents, + iamEvents: repos.IamEvents, + iamID: systemDefaults.IamID}, } } @@ -38,5 +58,5 @@ func (configs Configs) cycleDuration(viewModel string) time.Duration { if !ok { return 1 * time.Second } - return time.Duration(c.MinimumCycleDurationMillisecond) * time.Millisecond + return c.MinimumCycleDuration.Duration } diff --git a/internal/auth/repository/eventsourcing/handler/key.go b/internal/auth/repository/eventsourcing/handler/key.go new file mode 100644 index 0000000000..46824e8438 --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/key.go @@ -0,0 +1,55 @@ +package handler + +import ( + "time" + + es_model "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/key/repository/eventsourcing" + view_model "github.com/caos/zitadel/internal/key/repository/view/model" +) + +type Key struct { + handler +} + +const ( + keyTable = "auth.keys" +) + +func (k *Key) MinimumCycleDuration() time.Duration { return k.cycleDuration } + +func (k *Key) ViewModel() string { + return keyTable +} + +func (k *Key) EventQuery() (*models.SearchQuery, error) { + sequence, err := k.view.GetLatestKeySequence() + if err != nil { + return nil, err + } + return eventsourcing.KeyPairQuery(sequence), nil +} + +func (k *Key) Process(event *models.Event) error { + switch event.Type { + case es_model.KeyPairAdded: + privateKey, publicKey, err := view_model.KeysFromPairEvent(event) + if err != nil { + return err + } + return k.view.PutKeys(privateKey, publicKey, event.Sequence) + default: + return k.view.ProcessedKeySequence(event.Sequence) + } + return nil +} + +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) +} diff --git a/internal/auth/repository/eventsourcing/handler/org.go b/internal/auth/repository/eventsourcing/handler/org.go new file mode 100644 index 0000000000..b5b9df0fb6 --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/org.go @@ -0,0 +1,64 @@ +package handler + +import ( + "github.com/caos/logging" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" + "time" +) + +type Org struct { + handler +} + +const ( + orgTable = "auth.orgs" +) + +func (o *Org) MinimumCycleDuration() time.Duration { return o.cycleDuration } + +func (o *Org) ViewModel() string { + return orgTable +} + +func (o *Org) EventQuery() (*es_models.SearchQuery, error) { + sequence, err := o.view.GetLatestOrgSequence() + if err != nil { + return nil, err + } + return eventsourcing.OrgQuery(sequence), nil +} + +func (o *Org) Process(event *es_models.Event) error { + org := new(view.OrgView) + + switch event.Type { + case model.OrgAdded: + org.AppendEvent(event) + case model.OrgChanged: + err := org.SetData(event) + if err != nil { + return err + } + org, err = o.view.OrgByID(org.ID) + if err != nil { + return err + } + err = org.AppendEvent(event) + if err != nil { + return err + } + default: + return o.view.ProcessedOrgSequence(event.Sequence) + } + + return o.view.PutOrg(org) +} + +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) +} diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go index aca0ab265e..8dc50d47d9 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -54,7 +54,9 @@ func (p *User) Process(event *models.Event) (err error) { es_model.UserUnlocked, es_model.MfaOtpAdded, es_model.MfaOtpVerified, - es_model.MfaOtpRemoved: + es_model.MfaOtpRemoved, + es_model.MfaInitSkipped, + es_model.UserPasswordChanged: user, err = p.view.UserByID(event.AggregateID) if err != nil { return err diff --git a/internal/auth/repository/eventsourcing/handler/user_grant.go b/internal/auth/repository/eventsourcing/handler/user_grant.go new file mode 100644 index 0000000000..9878c2392a --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/user_grant.go @@ -0,0 +1,344 @@ +package handler + +import ( + "context" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + org_model "github.com/caos/zitadel/internal/org/model" + org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + proj_model "github.com/caos/zitadel/internal/project/model" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + usr_model "github.com/caos/zitadel/internal/user/model" + usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing" + usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" + "strings" + "time" +) + +type UserGrant struct { + handler + eventstore eventstore.Eventstore + projectEvents *proj_event.ProjectEventstore + userEvents *usr_events.UserEventstore + orgEvents *org_events.OrgEventstore + iamEvents *iam_events.IamEventstore + iamID string + iamProjectID string +} + +const ( + userGrantTable = "auth.user_grants" +) + +func (u *UserGrant) MinimumCycleDuration() time.Duration { return u.cycleDuration } + +func (u *UserGrant) ViewModel() string { + return userGrantTable +} + +func (u *UserGrant) EventQuery() (*models.SearchQuery, error) { + if u.iamProjectID == "" { + err := u.setIamProjectID() + if err != nil { + return nil, err + } + } + sequence, err := u.view.GetLatestUserGrantSequence() + if err != nil { + return nil, err + } + return es_models.NewSearchQuery(). + AggregateTypeFilter(grant_es_model.UserGrantAggregate, iam_es_model.IamAggregate, org_es_model.OrgAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate). + LatestSequenceFilter(sequence), nil +} + +func (u *UserGrant) Process(event *models.Event) (err error) { + switch event.AggregateType { + case grant_es_model.UserGrantAggregate: + err = u.processUserGrant(event) + case usr_es_model.UserAggregate: + err = u.processUser(event) + case proj_es_model.ProjectAggregate: + err = u.processProject(event) + case iam_es_model.IamAggregate: + err = u.processIamMember(event, "IAM", false) + case org_es_model.OrgAggregate: + return u.processOrg(event) + } + return err +} + +func (u *UserGrant) processUserGrant(event *models.Event) (err error) { + grant := new(view_model.UserGrantView) + switch event.Type { + case grant_es_model.UserGrantAdded: + err = grant.AppendEvent(event) + if err != nil { + return err + } + err = u.fillData(grant, event.ResourceOwner) + case grant_es_model.UserGrantChanged, + grant_es_model.UserGrantDeactivated, + grant_es_model.UserGrantReactivated: + grant, err = u.view.UserGrantByID(event.AggregateID) + if err != nil { + return err + } + err = grant.AppendEvent(event) + case grant_es_model.UserGrantRemoved: + err = u.view.DeleteUserGrant(event.AggregateID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + if err != nil { + return err + } + return u.view.PutUserGrant(grant, grant.Sequence) +} + +func (u *UserGrant) processUser(event *models.Event) (err error) { + switch event.Type { + case usr_es_model.UserProfileChanged, + usr_es_model.UserEmailChanged: + grants, err := u.view.UserGrantsByUserID(event.AggregateID) + if err != nil { + return err + } + user, err := u.userEvents.UserByID(context.Background(), event.AggregateID) + if err != nil { + return err + } + for _, grant := range grants { + u.fillUserData(grant, user) + err = u.view.PutUserGrant(grant, event.Sequence) + if err != nil { + return err + } + } + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processProject(event *models.Event) (err error) { + switch event.Type { + case proj_es_model.ProjectChanged: + grants, err := u.view.UserGrantsByProjectID(event.AggregateID) + if err != nil { + return err + } + project, err := u.projectEvents.ProjectByID(context.Background(), event.AggregateID) + if err != nil { + return err + } + for _, grant := range grants { + u.fillProjectData(grant, project) + return u.view.PutUserGrant(grant, event.Sequence) + } + case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved: + member := new(proj_es_model.ProjectMember) + member.SetData(event) + return u.processMember(event, "PROJECT", true, member.UserID, member.Roles) + case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged, proj_es_model.ProjectGrantMemberRemoved: + member := new(proj_es_model.ProjectGrantMember) + member.SetData(event) + return u.processMember(event, "PROJECT_GRANT", true, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processOrg(event *models.Event) (err error) { + switch event.Type { + case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged, org_es_model.OrgMemberRemoved: + member := new(org_es_model.OrgMember) + member.SetData(event) + return u.processMember(event, "ORG", false, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suffix bool) error { + member := new(iam_es_model.IamMember) + + switch event.Type { + case iam_es_model.IamMemberAdded, iam_es_model.IamMemberChanged: + member.SetData(event) + + grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + member.UserID, + ResourceOwner: u.iamID, + OrgName: u.iamID, + OrgDomain: u.iamID, + ProjectID: u.iamProjectID, + UserID: member.UserID, + RoleKeys: member.Roles, + CreationDate: event.CreationDate, + } + if suffix { + grant.RoleKeys = suffixRoles(event.AggregateID, grant.RoleKeys) + } + } else { + newRoles := member.Roles + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, grant.Sequence) + 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) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func (u *UserGrant) processMember(event *models.Event, rolePrefix string, suffix bool, userID string, roleKeys []string) error { + switch event.Type { + case org_es_model.OrgMemberAdded, proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded, + org_es_model.OrgMemberChanged, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectGrantMemberChanged: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if suffix { + roleKeys = suffixRoles(event.AggregateID, roleKeys) + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + event.ResourceOwner + userID, + ResourceOwner: event.ResourceOwner, + ProjectID: u.iamProjectID, + UserID: userID, + RoleKeys: roleKeys, + CreationDate: event.CreationDate, + } + u.fillData(grant, event.ResourceOwner) + } else { + newRoles := roleKeys + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, event.Sequence) + case org_es_model.OrgMemberRemoved, + proj_es_model.ProjectMemberRemoved, + proj_es_model.ProjectGrantMemberRemoved: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil { + return err + } + return u.view.DeleteUserGrant(grant.ID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func suffixRoles(suffix string, roles []string) []string { + suffixedRoles := make([]string, len(roles)) + for i := 0; i < len(roles); i++ { + suffixedRoles[i] = roles[i] + ":" + suffix + } + return suffixedRoles +} + +func mergeExistingRoles(rolePrefix string, existingRoles, newRoles []string) []string { + mergedRoles := make([]string, 0) + for _, existing := range existingRoles { + if !strings.HasPrefix(existing, rolePrefix) { + mergedRoles = append(mergedRoles, existing) + } + } + return append(mergedRoles, newRoles...) +} + +func (u *UserGrant) setIamProjectID() error { + if u.iamProjectID != "" { + return nil + } + iam, err := u.iamEvents.IamByID(context.Background(), u.iamID) + if err != nil { + return err + } + if !iam.SetUpDone { + return caos_errs.ThrowPreconditionFailed(nil, "HANDL-s5DTs", "Setup not done") + } + u.iamProjectID = iam.IamProjectID + return nil +} + +func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) { + user, err := u.userEvents.UserByID(context.Background(), grant.UserID) + if err != nil { + return err + } + u.fillUserData(grant, user) + project, err := u.projectEvents.ProjectByID(context.Background(), grant.ProjectID) + if err != nil { + return err + } + u.fillProjectData(grant, project) + + org, err := u.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(resourceOwner)) + if err != nil { + return err + } + u.fillOrgData(grant, org) + return nil +} + +func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *usr_model.User) { + grant.UserName = user.UserName + grant.FirstName = user.FirstName + grant.LastName = user.LastName + grant.Email = user.EmailAddress +} + +func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *proj_model.Project) { + grant.ProjectName = project.Name +} + +func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) { + grant.OrgDomain = org.Domain + grant.OrgName = org.Name +} + +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) +} diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go index 7581e66365..1c4e698eae 100644 --- a/internal/auth/repository/eventsourcing/handler/user_session.go +++ b/internal/auth/repository/eventsourcing/handler/user_session.go @@ -45,10 +45,8 @@ func (u *UserSession) Process(event *models.Event) (err error) { switch event.Type { case es_model.UserPasswordCheckSucceeded, es_model.UserPasswordCheckFailed, - es_model.UserPasswordChanged, es_model.MfaOtpCheckSucceeded, - es_model.MfaOtpCheckFailed, - es_model.MfaOtpRemoved: + es_model.MfaOtpCheckFailed: eventData, err := view_model.UserSessionFromEvent(event) if err != nil { return err @@ -66,14 +64,22 @@ func (u *UserSession) Process(event *models.Event) (err error) { State: int32(req_model.UserSessionStateActive), } } - session.AppendEvent(event) + return u.updateSession(session, event) + case es_model.UserPasswordChanged, + es_model.MfaOtpRemoved: + sessions, err := u.view.UserSessionsByUserID(event.AggregateID) + if err != nil { + return err + } + for _, session := range sessions { + if err := u.updateSession(session, event); err != nil { + return err + } + } + return nil default: return u.view.ProcessedUserSessionSequence(event.Sequence) } - if err := u.FillUserInfo(session, event.AggregateID); err != nil { - return err - } - return u.view.PutUserSession(session) } func (u *UserSession) OnError(event *models.Event, err error) error { @@ -81,7 +87,18 @@ 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) FillUserInfo(session *view_model.UserSessionView, id string) error { +func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error { + session.Sequence = event.Sequence + session.AppendEvent(event) + if session.UserName == "" { + if err := u.fillUserInfo(session, event.AggregateID); err != nil { + return err + } + } + return u.view.PutUserSession(session) +} + +func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error { user, err := u.userEvents.UserByID(context.Background(), id) if err != nil { return err diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index c988f492db..d1088d9398 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -2,6 +2,10 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/eventstore" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/handler" @@ -10,18 +14,23 @@ import ( "github.com/caos/zitadel/internal/auth_request/repository/cache" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/crypto" es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" "github.com/caos/zitadel/internal/id" + es_key "github.com/caos/zitadel/internal/key/repository/eventsourcing" es_policy "github.com/caos/zitadel/internal/policy/repository/eventsourcing" + es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_user "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Config struct { + SearchLimit uint64 Eventstore es_int.Config AuthRequest cache.Config View types.SQL Spooler spooler.SpoolerConfig + KeyConfig es_key.KeyConfig } type EsRepository struct { @@ -29,9 +38,15 @@ type EsRepository struct { eventstore.UserRepo eventstore.AuthRequestRepo eventstore.TokenRepo + eventstore.KeyRepository + eventstore.ApplicationRepo + eventstore.UserSessionRepo + eventstore.UserGrantRepo + eventstore.OrgRepository + eventstore.IamRepository } -func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) { +func Start(conf Config, authZ auth.Config, systemDefaults sd.SystemDefaults, authZRepo *authz_repo.EsRepository) (*EsRepository, error) { es, err := es_int.Start(conf.Eventstore) if err != nil { return nil, err @@ -41,7 +56,14 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) if err != nil { return nil, err } - view, err := auth_view.StartView(sqlClient) + + keyAlgorithm, err := crypto.NewAESCrypto(conf.KeyConfig.EncryptionConfig) + if err != nil { + return nil, err + } + idGenerator := id.SonyFlakeGenerator + + view, err := auth_view.StartView(sqlClient, keyAlgorithm, idGenerator) if err != nil { return nil, err } @@ -70,8 +92,35 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) return nil, err } - repos := handler.EventstoreRepos{UserEvents: user} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos) + key, err := es_key.StartKey(es, conf.KeyConfig, keyAlgorithm, idGenerator) + if err != nil { + return nil, err + } + + project, err := es_proj.StartProject( + es_proj.ProjectConfig{ + Cache: conf.Eventstore.Cache, + Eventstore: es, + }, + systemDefaults, + ) + if err != nil { + return nil, err + } + iam, err := es_iam.StartIam( + es_iam.IamConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, + systemDefaults, + ) + if err != nil { + return nil, err + } + org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es}) + + repos := handler.EventstoreRepos{UserEvents: user, ProjectEvents: project, OrgEvents: org, IamEvents: iam} + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) return &EsRepository{ spool, @@ -86,13 +135,41 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) View: view, UserSessionViewProvider: view, UserViewProvider: view, - IdGenerator: id.SonyFlakeGenerator, + UserEventProvider: user, + IdGenerator: idGenerator, PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration, MfaInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MfaInitSkip.Duration, MfaSoftwareCheckLifeTime: systemDefaults.VerificationLifetimes.MfaSoftwareCheck.Duration, MfaHardwareCheckLifeTime: systemDefaults.VerificationLifetimes.MfaHardwareCheck.Duration, }, eventstore.TokenRepo{View: view}, + eventstore.KeyRepository{ + KeyEvents: key, + View: view, + SigningKeyRotation: conf.KeyConfig.SigningKeyRotation.Duration, + }, + eventstore.ApplicationRepo{ + View: view, + ProjectEvents: project, + }, + eventstore.UserSessionRepo{ + View: view, + }, + eventstore.UserGrantRepo{ + SearchLimit: conf.SearchLimit, + View: view, + IamID: systemDefaults.IamID, + Auth: authZ, + AuthZRepo: authZRepo, + }, + eventstore.OrgRepository{ + SearchLimit: conf.SearchLimit, + View: view, + }, + eventstore.IamRepository{ + IamEvents: iam, + IamID: systemDefaults.IamID, + }, }, nil } diff --git a/internal/auth/repository/eventsourcing/spooler/spooler.go b/internal/auth/repository/eventsourcing/spooler/spooler.go index 913b96237c..9d5c323a75 100644 --- a/internal/auth/repository/eventsourcing/spooler/spooler.go +++ b/internal/auth/repository/eventsourcing/spooler/spooler.go @@ -2,6 +2,7 @@ package spooler import ( "database/sql" + sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" @@ -17,12 +18,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos, systemDefaults sd.SystemDefaults) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentTasks: c.ConcurrentTasks, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, repos), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, systemDefaults), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/auth/repository/eventsourcing/view/application.go b/internal/auth/repository/eventsourcing/view/application.go new file mode 100644 index 0000000000..60b7f89570 --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/application.go @@ -0,0 +1,105 @@ +package view + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + global_model "github.com/caos/zitadel/internal/model" + 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" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + applicationTable = "auth.applications" +) + +func (v *View) ApplicationByID(appID string) (*model.ApplicationView, error) { + return view.ApplicationByID(v.Db, applicationTable, appID) +} + +func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) { + return view.SearchApplications(v.Db, applicationTable, request) +} + +func (v *View) PutApplication(project *model.ApplicationView) error { + err := view.PutApplication(v.Db, applicationTable, project) + if err != nil { + return err + } + return v.ProcessedApplicationSequence(project.Sequence) +} + +func (v *View) DeleteApplication(appID string, eventSequence uint64) error { + err := view.DeleteApplication(v.Db, applicationTable, appID) + if err != nil { + return nil + } + return v.ProcessedApplicationSequence(eventSequence) +} + +func (v *View) GetLatestApplicationSequence() (uint64, error) { + return v.latestSequence(applicationTable) +} + +func (v *View) ProcessedApplicationSequence(eventSequence uint64) error { + return v.saveCurrentSequence(applicationTable, eventSequence) +} + +func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(applicationTable, sequence) +} + +func (v *View) ProcessedApplicationFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} + +func (v *View) ApplicationByClientID(_ context.Context, clientID string) (*model.ApplicationView, error) { + req := &proj_model.ApplicationSearchRequest{ + Limit: 1, + Queries: []*proj_model.ApplicationSearchQuery{ + { + Key: proj_model.APPLICATIONSEARCHKEY_OIDC_CLIENT_ID, + Method: global_model.SEARCHMETHOD_EQUALS, + Value: clientID, + }, + }, + } + apps, count, err := view.SearchApplications(v.Db, applicationTable, req) + if err != nil { + return nil, errors.ThrowPreconditionFailed(err, "VIEW-sd6JQ", "cannot find client") + } + if count != 1 { + return nil, errors.ThrowPreconditionFailed(nil, "VIEW-dfw3as", "cannot find client") + } + return apps[0], nil +} + +func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string) ([]string, error) { + app, err := v.ApplicationByClientID(ctx, clientID) + if err != nil { + return nil, err + } + req := &proj_model.ApplicationSearchRequest{ + Queries: []*proj_model.ApplicationSearchQuery{ + { + Key: proj_model.APPLICATIONSEARCHKEY_PROJECT_ID, + Method: global_model.SEARCHMETHOD_EQUALS, + Value: app.ProjectID, + }, + }, + } + apps, _, err := view.SearchApplications(v.Db, applicationTable, req) + if err != nil { + return nil, errors.ThrowPreconditionFailed(err, "VIEW-Gd24q", "cannot find applications") + } + ids := make([]string, 0, len(apps)) + for _, app := range apps { + if !app.IsOIDC { + continue + } + ids = append(ids, app.OIDCClientID) + } + return ids, nil +} diff --git a/internal/auth/repository/eventsourcing/view/key.go b/internal/auth/repository/eventsourcing/view/key.go new file mode 100644 index 0000000000..a5b07ff62a --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/key.go @@ -0,0 +1,72 @@ +package view + +import ( + key_model "github.com/caos/zitadel/internal/key/model" + "github.com/caos/zitadel/internal/key/repository/view" + "github.com/caos/zitadel/internal/key/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + keyTable = "auth.keys" +) + +func (v *View) KeyByIDAndType(keyID string, private bool) (*model.KeyView, error) { + return view.KeyByIDAndType(v.Db, keyTable, keyID, private) +} + +func (v *View) GetSigningKey() (*key_model.SigningKey, error) { + key, err := view.GetSigningKey(v.Db, keyTable) + if err != nil { + return nil, err + } + return key_model.SigningKeyFromKeyView(model.KeyViewToModel(key), v.keyAlgorithm) +} + +func (v *View) GetActiveKeySet() ([]*key_model.PublicKey, error) { + keys, err := view.GetActivePublicKeys(v.Db, keyTable) + if err != nil { + return nil, err + } + return key_model.PublicKeysFromKeyView(model.KeyViewsToModel(keys), v.keyAlgorithm) +} + +func (v *View) PutKeys(privateKey, publicKey *model.KeyView, eventSequence uint64) error { + err := view.PutKeys(v.Db, keyTable, privateKey, publicKey) + if err != nil { + return err + } + return v.ProcessedKeySequence(eventSequence) +} + +func (v *View) DeleteKey(keyID string, private bool, eventSequence uint64) error { + err := view.DeleteKey(v.Db, keyTable, keyID, private) + if err != nil { + return nil + } + return v.ProcessedKeySequence(eventSequence) +} + +func (v *View) DeleteKeyPair(keyID string, eventSequence uint64) error { + err := view.DeleteKeyPair(v.Db, keyTable, keyID) + if err != nil { + return nil + } + return v.ProcessedKeySequence(eventSequence) +} + +func (v *View) GetLatestKeySequence() (uint64, error) { + return v.latestSequence(keyTable) +} + +func (v *View) ProcessedKeySequence(eventSequence uint64) error { + return v.saveCurrentSequence(keyTable, eventSequence) +} + +func (v *View) GetLatestKeyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(keyTable, sequence) +} + +func (v *View) ProcessedKeyFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/auth/repository/eventsourcing/view/org.go b/internal/auth/repository/eventsourcing/view/org.go new file mode 100644 index 0000000000..e7d7488760 --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/org.go @@ -0,0 +1,43 @@ +package view + +import ( + "github.com/caos/zitadel/internal/org/model" + org_view "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/view" +) + +const ( + orgTable = "auth.orgs" +) + +func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) { + return org_view.OrgByID(v.Db, orgTable, orgID) +} + +func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_view.OrgView, int, error) { + return org_view.SearchOrgs(v.Db, orgTable, req) +} + +func (v *View) PutOrg(org *org_view.OrgView) error { + err := org_view.PutOrg(v.Db, orgTable, org) + if err != nil { + return err + } + return v.ProcessedOrgSequence(org.Sequence) +} + +func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*view.FailedEvent, error) { + return v.latestFailedEvent(orgTable, sequence) +} + +func (v *View) ProcessedOrgFailedEvent(failedEvent *view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} + +func (v *View) GetLatestOrgSequence() (uint64, error) { + return v.latestSequence(orgTable) +} + +func (v *View) ProcessedOrgSequence(eventSequence uint64) error { + return v.saveCurrentSequence(orgTable, eventSequence) +} diff --git a/internal/auth/repository/eventsourcing/view/token.go b/internal/auth/repository/eventsourcing/view/token.go index adae0900e1..36602d4c98 100644 --- a/internal/auth/repository/eventsourcing/view/token.go +++ b/internal/auth/repository/eventsourcing/view/token.go @@ -20,17 +20,23 @@ func (v *View) IsTokenValid(tokenID string) (bool, error) { return view.IsTokenValid(v.Db, tokenTable, tokenID) } -func (v *View) CreateToken(agentID, applicationID, userID string, lifetime time.Duration) (*model.Token, error) { +func (v *View) CreateToken(agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) { + id, err := v.idGenerator.Next() + if err != nil { + return nil, err + } now := time.Now().UTC() token := &model.Token{ + ID: id, CreationDate: now, UserID: userID, ApplicationID: applicationID, UserAgentID: agentID, + Scopes: scopes, + Audience: audience, Expiration: now.Add(lifetime), } - err := view.PutToken(v.Db, tokenTable, token) - if err != nil { + if err := view.PutToken(v.Db, tokenTable, token); err != nil { return nil, err } return token, nil diff --git a/internal/auth/repository/eventsourcing/view/user_grant.go b/internal/auth/repository/eventsourcing/view/user_grant.go new file mode 100644 index 0000000000..d4f8dd1573 --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/user_grant.go @@ -0,0 +1,64 @@ +package view + +import ( + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + userGrantTable = "auth.user_grants" +) + +func (v *View) UserGrantByID(grantID string) (*model.UserGrantView, error) { + return view.UserGrantByID(v.Db, userGrantTable, grantID) +} + +func (v *View) UserGrantByIDs(resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) { + return view.UserGrantByIDs(v.Db, userGrantTable, resourceOwnerID, projectID, userID) +} + +func (v *View) UserGrantsByUserID(userID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByUserID(v.Db, userGrantTable, userID) +} + +func (v *View) UserGrantsByProjectID(projectID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByProjectID(v.Db, userGrantTable, projectID) +} + +func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) { + return view.SearchUserGrants(v.Db, userGrantTable, request) +} + +func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error { + err := view.PutUserGrant(v.Db, userGrantTable, grant) + if err != nil { + return err + } + return v.ProcessedUserGrantSequence(sequence) +} + +func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error { + err := view.DeleteUserGrant(v.Db, userGrantTable, grantID) + if err != nil { + return nil + } + return v.ProcessedUserGrantSequence(eventSequence) +} + +func (v *View) GetLatestUserGrantSequence() (uint64, error) { + return v.latestSequence(userGrantTable) +} + +func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error { + return v.saveCurrentSequence(userGrantTable, eventSequence) +} + +func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(userGrantTable, sequence) +} + +func (v *View) ProcessedUserGrantFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/auth/repository/eventsourcing/view/user_session.go b/internal/auth/repository/eventsourcing/view/user_session.go index dbbd2d83c6..6882c68464 100644 --- a/internal/auth/repository/eventsourcing/view/user_session.go +++ b/internal/auth/repository/eventsourcing/view/user_session.go @@ -10,14 +10,14 @@ const ( userSessionTable = "auth.user_sessions" ) -func (v *View) UserSessionByID(sessionID string) (*model.UserSessionView, error) { - return view.UserSessionByID(v.Db, userSessionTable, sessionID) -} - func (v *View) UserSessionByIDs(agentID, userID string) (*model.UserSessionView, error) { return view.UserSessionByIDs(v.Db, userSessionTable, agentID, userID) } +func (v *View) UserSessionsByUserID(userID string) ([]*model.UserSessionView, error) { + return view.UserSessionsByUserID(v.Db, userSessionTable, userID) +} + func (v *View) UserSessionsByAgentID(agentID string) ([]*model.UserSessionView, error) { return view.UserSessionsByAgentID(v.Db, userSessionTable, agentID) } diff --git a/internal/auth/repository/eventsourcing/view/view.go b/internal/auth/repository/eventsourcing/view/view.go index 4b8c52392d..fc33fccddf 100644 --- a/internal/auth/repository/eventsourcing/view/view.go +++ b/internal/auth/repository/eventsourcing/view/view.go @@ -4,19 +4,26 @@ import ( "database/sql" "github.com/jinzhu/gorm" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/id" ) type View struct { - Db *gorm.DB + Db *gorm.DB + keyAlgorithm crypto.EncryptionAlgorithm + idGenerator id.Generator } -func StartView(sqlClient *sql.DB) (*View, error) { +func StartView(sqlClient *sql.DB, keyAlgorithm crypto.EncryptionAlgorithm, idGenerator id.Generator) (*View, error) { gorm, err := gorm.Open("postgres", sqlClient) if err != nil { return nil, err } return &View{ - Db: gorm, + Db: gorm, + keyAlgorithm: keyAlgorithm, + idGenerator: idGenerator, }, nil } diff --git a/internal/auth/repository/iam.go b/internal/auth/repository/iam.go new file mode 100644 index 0000000000..3e17aa0971 --- /dev/null +++ b/internal/auth/repository/iam.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" + + "github.com/caos/zitadel/internal/iam/model" +) + +type IamRepository interface { + GetIam(ctx context.Context) (*model.Iam, error) +} diff --git a/internal/auth/repository/key.go b/internal/auth/repository/key.go new file mode 100644 index 0000000000..17623be806 --- /dev/null +++ b/internal/auth/repository/key.go @@ -0,0 +1,14 @@ +package repository + +import ( + "context" + "time" + + "gopkg.in/square/go-jose.v2" +) + +type KeyRepository interface { + GenerateSigningKeyPair(ctx context.Context, algorithm string) error + GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) + GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) +} diff --git a/internal/auth/repository/repository.go b/internal/auth/repository/repository.go index 461fce0c92..6e20219fb4 100644 --- a/internal/auth/repository/repository.go +++ b/internal/auth/repository/repository.go @@ -9,4 +9,8 @@ type Repository interface { UserRepository AuthRequestRepository TokenRepository + ApplicationRepository + KeyRepository + UserSessionRepository + UserGrantRepository } diff --git a/internal/auth/repository/token.go b/internal/auth/repository/token.go index 1de051447d..17db69118e 100644 --- a/internal/auth/repository/token.go +++ b/internal/auth/repository/token.go @@ -8,6 +8,7 @@ import ( ) type TokenRepository interface { - CreateToken(ctx context.Context, agentID, applicationID, userID string, lifetime time.Duration) (*model.Token, error) + CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) IsTokenValid(ctx context.Context, tokenID string) (bool, error) + TokenByID(ctx context.Context, tokenID string) (*model.Token, error) } diff --git a/internal/auth/repository/user.go b/internal/auth/repository/user.go index 7fb0b62615..83d9718553 100644 --- a/internal/auth/repository/user.go +++ b/internal/auth/repository/user.go @@ -11,10 +11,20 @@ type UserRepository interface { myUserRepo SkipMfaInit(ctx context.Context, userID string) error + RequestPasswordReset(ctx context.Context, username string) error SetPassword(ctx context.Context, userID, code, password string) error + ChangePassword(ctx context.Context, userID, old, new string) error + + VerifyEmail(ctx context.Context, userID, code string) error + ResendEmailVerificationMail(ctx context.Context, userID string) error + + AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) + VerifyMfaOTPSetup(ctx context.Context, userID, code string) error SignOut(ctx context.Context, agentID, userID string) error + + UserByID(ctx context.Context, userID string) (*model.User, error) } type myUserRepo interface { @@ -37,6 +47,6 @@ type myUserRepo interface { ChangeMyPassword(ctx context.Context, old, new string) error AddMyMfaOTP(ctx context.Context) (*model.OTP, error) - VerifyMyMfaOTP(ctx context.Context, code string) error + VerifyMyMfaOTPSetup(ctx context.Context, code string) error RemoveMyMfaOTP(ctx context.Context) error } diff --git a/internal/auth/repository/user_grant.go b/internal/auth/repository/user_grant.go new file mode 100644 index 0000000000..f3db22e330 --- /dev/null +++ b/internal/auth/repository/user_grant.go @@ -0,0 +1,12 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/usergrant/model" +) + +type UserGrantRepository interface { + SearchMyUserGrants(ctx context.Context, request *model.UserGrantSearchRequest) (*model.UserGrantSearchResponse, error) + SearchMyProjectOrgs(ctx context.Context, request *model.UserGrantSearchRequest) (*model.ProjectOrgSearchResponse, error) + SearchMyZitadelPermissions(ctx context.Context) ([]string, error) +} diff --git a/internal/auth/repository/user_session.go b/internal/auth/repository/user_session.go new file mode 100644 index 0000000000..98e8751d07 --- /dev/null +++ b/internal/auth/repository/user_session.go @@ -0,0 +1,10 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/user/model" +) + +type UserSessionRepository interface { + GetMyUserSessions(ctx context.Context) ([]*model.UserSessionView, error) +} diff --git a/internal/auth_request/model/auth_request.go b/internal/auth_request/model/auth_request.go index ba95313b87..f76daf2b0f 100644 --- a/internal/auth_request/model/auth_request.go +++ b/internal/auth_request/model/auth_request.go @@ -2,29 +2,36 @@ package model import ( "time" + + "github.com/caos/zitadel/internal/errors" ) type AuthRequest struct { - ID string - AgentID string - CreationDate time.Time - ChangeDate time.Time - BrowserInfo *BrowserInfo - ApplicationID string - CallbackURI string - TransferState string - Prompt Prompt - PossibleLOAs []LevelOfAssurance - UiLocales []string - LoginHint string - PreselectedUserID string - MaxAuthAge uint32 - Request Request + ID string + AgentID string + CreationDate time.Time + ChangeDate time.Time + BrowserInfo *BrowserInfo + ApplicationID string + CallbackURI string + TransferState string + Prompt Prompt + PossibleLOAs []LevelOfAssurance + UiLocales []string + LoginHint string + MaxAuthAge uint32 + Request Request - levelOfAssurance LevelOfAssurance - projectApplicationIDs []string - UserID string - PossibleSteps []NextStep + levelOfAssurance LevelOfAssurance + UserID string + UserName string + UserOrgID string + PossibleSteps []NextStep + PasswordVerified bool + MfasVerified []MfaType + Audience []string + AuthTime time.Time + Code string } type Prompt int32 @@ -46,22 +53,30 @@ const ( func NewAuthRequest(id, agentID string, info *BrowserInfo, applicationID, callbackURI, transferState string, prompt Prompt, possibleLOAs []LevelOfAssurance, uiLocales []string, loginHint, preselectedUserID string, maxAuthAge uint32, request Request) *AuthRequest { return &AuthRequest{ - ID: id, - AgentID: agentID, - BrowserInfo: info, - ApplicationID: applicationID, - CallbackURI: callbackURI, - TransferState: transferState, - Prompt: prompt, - PossibleLOAs: possibleLOAs, - UiLocales: uiLocales, - LoginHint: loginHint, - PreselectedUserID: preselectedUserID, - MaxAuthAge: maxAuthAge, - Request: request, + ID: id, + AgentID: agentID, + BrowserInfo: info, + ApplicationID: applicationID, + CallbackURI: callbackURI, + TransferState: transferState, + Prompt: prompt, + PossibleLOAs: possibleLOAs, + UiLocales: uiLocales, + LoginHint: loginHint, + UserID: preselectedUserID, + MaxAuthAge: maxAuthAge, + Request: request, } } +func NewAuthRequestFromType(requestType AuthRequestType) (*AuthRequest, error) { + request, ok := authRequestTypeMapping[requestType] + if !ok { + return nil, errors.ThrowInvalidArgument(nil, "MODEL-ds2kl", "invalid request type") + } + return &AuthRequest{Request: request}, nil +} + func (a *AuthRequest) IsValid() bool { return a.ID != "" && a.AgentID != "" && @@ -80,3 +95,9 @@ func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest { a.BrowserInfo = info return a } + +func (a *AuthRequest) SetUserInfo(userID string, userName string, userOrgID string) { + a.UserID = userID + a.UserName = userName + a.UserOrgID = userOrgID +} diff --git a/internal/auth_request/model/browser_info.go b/internal/auth_request/model/browser_info.go index 2812b88583..abfbe696f0 100644 --- a/internal/auth_request/model/browser_info.go +++ b/internal/auth_request/model/browser_info.go @@ -1,6 +1,12 @@ package model -import "net" +import ( + "net" + "net/http" + + "github.com/caos/zitadel/internal/api" + http_util "github.com/caos/zitadel/internal/api/http" +) type BrowserInfo struct { UserAgent string @@ -8,6 +14,14 @@ type BrowserInfo struct { RemoteIP net.IP } +func BrowserInfoFromRequest(r *http.Request) *BrowserInfo { + return &BrowserInfo{ + UserAgent: r.Header.Get(api.UserAgent), + AcceptLanguage: r.Header.Get(api.AcceptLanguage), + RemoteIP: http_util.RemoteIPFromRequest(r), + } +} + func (i *BrowserInfo) IsValid() bool { return i.UserAgent != "" && i.AcceptLanguage != "" && diff --git a/internal/auth_request/model/next_step.go b/internal/auth_request/model/next_step.go index 68a9beb7ab..4c60900faa 100644 --- a/internal/auth_request/model/next_step.go +++ b/internal/auth_request/model/next_step.go @@ -10,6 +10,7 @@ const ( NextStepUnspecified NextStepType = iota NextStepLogin NextStepUserSelection + NextStepInitUser NextStepPassword NextStepChangePassword NextStepInitPassword @@ -26,9 +27,7 @@ const ( UserSessionStateTerminated ) -type LoginStep struct { - NotFound bool -} +type LoginStep struct{} func (s *LoginStep) Type() NextStepType { return NextStepLogin @@ -48,30 +47,33 @@ type UserSelection struct { UserSessionState UserSessionState } -type PasswordStep struct { - FailureCount uint16 +type InitUserStep struct { + PasswordSet bool } +func (s *InitUserStep) Type() NextStepType { + return NextStepInitUser +} + +type PasswordStep struct{} + func (s *PasswordStep) Type() NextStepType { return NextStepPassword } -type ChangePasswordStep struct { -} +type ChangePasswordStep struct{} func (s *ChangePasswordStep) Type() NextStepType { return NextStepChangePassword } -type InitPasswordStep struct { -} +type InitPasswordStep struct{} func (s *InitPasswordStep) Type() NextStepType { return NextStepInitPassword } -type VerifyEMailStep struct { -} +type VerifyEMailStep struct{} func (s *VerifyEMailStep) Type() NextStepType { return NextStepVerifyEmail @@ -87,7 +89,6 @@ func (s *MfaPromptStep) Type() NextStepType { } type MfaVerificationStep struct { - FailureCount uint16 MfaProviders []MfaType } @@ -95,8 +96,7 @@ func (s *MfaVerificationStep) Type() NextStepType { return NextStepMfaVerify } -type RedirectToCallbackStep struct { -} +type RedirectToCallbackStep struct{} func (s *RedirectToCallbackStep) Type() NextStepType { return NextStepRedirectToCallback @@ -111,7 +111,8 @@ const ( type MfaLevel int const ( - MfaLevelSoftware MfaLevel = iota + MfaLevelNotSetUp MfaLevel = iota + MfaLevelSoftware MfaLevelHardware MfaLevelHardwareCertified ) diff --git a/internal/auth_request/model/request.go b/internal/auth_request/model/request.go index c90cd52682..1f579d29b7 100644 --- a/internal/auth_request/model/request.go +++ b/internal/auth_request/model/request.go @@ -7,6 +7,12 @@ type Request interface { type AuthRequestType int32 +var ( + authRequestTypeMapping = map[AuthRequestType]Request{ + AuthRequestTypeOIDC: &AuthRequestOIDC{}, + } +) + const ( AuthRequestTypeOIDC AuthRequestType = iota AuthRequestTypeSAML diff --git a/internal/auth_request/repository/cache/cache.go b/internal/auth_request/repository/cache/cache.go index 7f510bfccf..dc930e6d36 100644 --- a/internal/auth_request/repository/cache/cache.go +++ b/internal/auth_request/repository/cache/cache.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/json" "errors" + "fmt" "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/config/types" @@ -34,34 +35,62 @@ func (c *AuthRequestCache) Health(ctx context.Context) error { } func (c *AuthRequestCache) GetAuthRequestByID(_ context.Context, id string) (*model.AuthRequest, error) { + return c.getAuthRequest("id", id) +} + +func (c *AuthRequestCache) GetAuthRequestByCode(_ context.Context, code string) (*model.AuthRequest, error) { + return c.getAuthRequest("code", code) +} + +func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *model.AuthRequest) error { + return c.saveAuthRequest(request, "INSERT INTO auth.auth_requests (id, request, request_type) VALUES($1, $2, $3)", request.Request.Type()) +} + +func (c *AuthRequestCache) UpdateAuthRequest(_ context.Context, request *model.AuthRequest) error { + return c.saveAuthRequest(request, "UPDATE auth.auth_requests SET request = $2, code = $3 WHERE id = $1", request.Code) +} + +func (c *AuthRequestCache) DeleteAuthRequest(_ context.Context, id string) error { + _, err := c.client.Exec("DELETE FROM auth.auth_requests WHERE id = $1", id) + if err != nil { + return caos_errs.ThrowInternal(err, "CACHE-dsHw3", "unable to delete auth request") + } + return nil +} + +func (c *AuthRequestCache) getAuthRequest(key, value string) (*model.AuthRequest, error) { var b []byte - err := c.client.QueryRow("SELECT request FROM auth.authrequests WHERE id = ?", id).Scan(&b) + var requestType model.AuthRequestType + query := fmt.Sprintf("SELECT request, request_type FROM auth.auth_requests WHERE %s = $1", key) + err := c.client.QueryRow(query, value).Scan(&b, &requestType) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, caos_errs.ThrowNotFound(err, "CACHE-d24aD", "auth request not found") } return nil, caos_errs.ThrowInternal(err, "CACHE-as3kj", "unable to get auth request from database") } - request := new(model.AuthRequest) - err = json.Unmarshal(b, &request) + request, err := model.NewAuthRequestFromType(requestType) + if err == nil { + err = json.Unmarshal(b, request) + } if err != nil { return nil, caos_errs.ThrowInternal(err, "CACHE-2wshg", "unable to unmarshal auth request") } return request, nil } -func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *model.AuthRequest) error { +func (c *AuthRequestCache) saveAuthRequest(request *model.AuthRequest, query string, param interface{}) error { b, err := json.Marshal(request) if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-32FH9", "unable to marshal auth request") + return caos_errs.ThrowInternal(err, "CACHE-os0GH", "unable to marshal auth request") } - stmt, err := c.client.Prepare("INSERT INTO auth.authrequests (id, request) VALUES($1, $2)") + stmt, err := c.client.Prepare(query) if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-dswfF", "sql prepare failed") + return caos_errs.ThrowInternal(err, "CACHE-su3GK", "sql prepare failed") } - _, err = stmt.Exec(request.ID, b) + _, err = stmt.Exec(request.ID, b, param) if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-sw4af", "unable to save auth request") + return caos_errs.ThrowInternal(err, "CACHE-sj8iS", "unable to save auth request") } return nil } diff --git a/internal/auth_request/repository/gen_mock.go b/internal/auth_request/repository/gen_mock.go index 1a7097ae95..c904aec4d6 100644 --- a/internal/auth_request/repository/gen_mock.go +++ b/internal/auth_request/repository/gen_mock.go @@ -1,3 +1,3 @@ package repository -//go:generate mockgen -package mock -destination ./mock/repository.mock.go github.com/caos/zitadel/internal/auth_request/repository Repository +//go:generate mockgen -package mock -destination ./mock/repository.mock.go github.com/caos/zitadel/internal/auth_request/repository AuthRequestCache diff --git a/internal/auth_request/repository/mock/repository.go b/internal/auth_request/repository/mock/repository.go deleted file mode 100644 index 0eef6e337e..0000000000 --- a/internal/auth_request/repository/mock/repository.go +++ /dev/null @@ -1,12 +0,0 @@ -package mock - -import ( - "github.com/golang/mock/gomock" - - "github.com/caos/zitadel/internal/auth_request/repository" -) - -func NewMockAuthRequestRepository(ctrl *gomock.Controller) repository.Repository { - repo := NewMockRepository(ctrl) - return repo -} diff --git a/internal/auth_request/repository/mock/repository.mock.go b/internal/auth_request/repository/mock/repository.mock.go index 8ffbf9d4a3..9d23f6e35f 100644 --- a/internal/auth_request/repository/mock/repository.mock.go +++ b/internal/auth_request/repository/mock/repository.mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/caos/zitadel/internal/auth_request/repository (interfaces: Repository) +// Source: github.com/caos/zitadel/internal/auth_request/repository (interfaces: AuthRequestCache) // Package mock is a generated GoMock package. package mock @@ -11,31 +11,60 @@ import ( reflect "reflect" ) -// MockRepository is a mock of Repository interface -type MockRepository struct { +// MockAuthRequestCache is a mock of AuthRequestCache interface +type MockAuthRequestCache struct { ctrl *gomock.Controller - recorder *MockRepositoryMockRecorder + recorder *MockAuthRequestCacheMockRecorder } -// MockRepositoryMockRecorder is the mock recorder for MockRepository -type MockRepositoryMockRecorder struct { - mock *MockRepository +// MockAuthRequestCacheMockRecorder is the mock recorder for MockAuthRequestCache +type MockAuthRequestCacheMockRecorder struct { + mock *MockAuthRequestCache } -// NewMockRepository creates a new mock instance -func NewMockRepository(ctrl *gomock.Controller) *MockRepository { - mock := &MockRepository{ctrl: ctrl} - mock.recorder = &MockRepositoryMockRecorder{mock} +// NewMockAuthRequestCache creates a new mock instance +func NewMockAuthRequestCache(ctrl *gomock.Controller) *MockAuthRequestCache { + mock := &MockAuthRequestCache{ctrl: ctrl} + mock.recorder = &MockAuthRequestCacheMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use -func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { +func (m *MockAuthRequestCache) EXPECT() *MockAuthRequestCacheMockRecorder { return m.recorder } +// DeleteAuthRequest mocks base method +func (m *MockAuthRequestCache) DeleteAuthRequest(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAuthRequest", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAuthRequest indicates an expected call of DeleteAuthRequest +func (mr *MockAuthRequestCacheMockRecorder) DeleteAuthRequest(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAuthRequest", reflect.TypeOf((*MockAuthRequestCache)(nil).DeleteAuthRequest), arg0, arg1) +} + +// GetAuthRequestByCode mocks base method +func (m *MockAuthRequestCache) GetAuthRequestByCode(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthRequestByCode", arg0, arg1) + ret0, _ := ret[0].(*model.AuthRequest) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthRequestByCode indicates an expected call of GetAuthRequestByCode +func (mr *MockAuthRequestCacheMockRecorder) GetAuthRequestByCode(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByCode", reflect.TypeOf((*MockAuthRequestCache)(nil).GetAuthRequestByCode), arg0, arg1) +} + // GetAuthRequestByID mocks base method -func (m *MockRepository) GetAuthRequestByID(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { +func (m *MockAuthRequestCache) GetAuthRequestByID(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAuthRequestByID", arg0, arg1) ret0, _ := ret[0].(*model.AuthRequest) @@ -44,13 +73,13 @@ func (m *MockRepository) GetAuthRequestByID(arg0 context.Context, arg1 string) ( } // GetAuthRequestByID indicates an expected call of GetAuthRequestByID -func (mr *MockRepositoryMockRecorder) GetAuthRequestByID(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthRequestCacheMockRecorder) GetAuthRequestByID(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByID", reflect.TypeOf((*MockRepository)(nil).GetAuthRequestByID), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByID", reflect.TypeOf((*MockAuthRequestCache)(nil).GetAuthRequestByID), arg0, arg1) } // Health mocks base method -func (m *MockRepository) Health(arg0 context.Context) error { +func (m *MockAuthRequestCache) Health(arg0 context.Context) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Health", arg0) ret0, _ := ret[0].(error) @@ -58,22 +87,35 @@ func (m *MockRepository) Health(arg0 context.Context) error { } // Health indicates an expected call of Health -func (mr *MockRepositoryMockRecorder) Health(arg0 interface{}) *gomock.Call { +func (mr *MockAuthRequestCacheMockRecorder) Health(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockRepository)(nil).Health), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockAuthRequestCache)(nil).Health), arg0) } // SaveAuthRequest mocks base method -func (m *MockRepository) SaveAuthRequest(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { +func (m *MockAuthRequestCache) SaveAuthRequest(arg0 context.Context, arg1 *model.AuthRequest) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SaveAuthRequest", arg0, arg1) - ret0, _ := ret[0].(*model.AuthRequest) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // SaveAuthRequest indicates an expected call of SaveAuthRequest -func (mr *MockRepositoryMockRecorder) SaveAuthRequest(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthRequestCacheMockRecorder) SaveAuthRequest(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAuthRequest", reflect.TypeOf((*MockRepository)(nil).SaveAuthRequest), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAuthRequest", reflect.TypeOf((*MockAuthRequestCache)(nil).SaveAuthRequest), arg0, arg1) +} + +// UpdateAuthRequest mocks base method +func (m *MockAuthRequestCache) UpdateAuthRequest(arg0 context.Context, arg1 *model.AuthRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateAuthRequest", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateAuthRequest indicates an expected call of UpdateAuthRequest +func (mr *MockAuthRequestCacheMockRecorder) UpdateAuthRequest(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAuthRequest", reflect.TypeOf((*MockAuthRequestCache)(nil).UpdateAuthRequest), arg0, arg1) } diff --git a/internal/auth_request/repository/repository.go b/internal/auth_request/repository/repository.go index 34e4963f13..f72d2c8fda 100644 --- a/internal/auth_request/repository/repository.go +++ b/internal/auth_request/repository/repository.go @@ -6,9 +6,12 @@ import ( "github.com/caos/zitadel/internal/auth_request/model" ) -type Repository interface { +type AuthRequestCache interface { Health(ctx context.Context) error GetAuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) - SaveAuthRequest(ctx context.Context, id string) (*model.AuthRequest, error) + GetAuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) + SaveAuthRequest(ctx context.Context, request *model.AuthRequest) error + UpdateAuthRequest(ctx context.Context, request *model.AuthRequest) error + DeleteAuthRequest(ctx context.Context, id string) error } diff --git a/internal/authz/authz.go b/internal/authz/authz.go new file mode 100644 index 0000000000..9f2c42da91 --- /dev/null +++ b/internal/authz/authz.go @@ -0,0 +1,16 @@ +package authz + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + sd "github.com/caos/zitadel/internal/config/systemdefaults" +) + +type Config struct { + Repository eventsourcing.Config +} + +func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) (*eventsourcing.EsRepository, error) { + return eventsourcing.Start(config.Repository, authZ, systemDefaults) +} diff --git a/internal/authz/repository/eventsourcing/eventstore/iam.go b/internal/authz/repository/eventsourcing/eventstore/iam.go new file mode 100644 index 0000000000..d0fee2efb3 --- /dev/null +++ b/internal/authz/repository/eventsourcing/eventstore/iam.go @@ -0,0 +1,20 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/iam/model" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" +) + +type IamRepo struct { + IamID string + IamEvents *iam_event.IamEventstore +} + +func (repo *IamRepo) Health(ctx context.Context) error { + return repo.IamEvents.Health(ctx) +} + +func (repo *IamRepo) IamByID(ctx context.Context) (*model.Iam, error) { + return repo.IamEvents.IamByID(ctx, repo.IamID) +} diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go new file mode 100644 index 0000000000..d350070ecc --- /dev/null +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -0,0 +1,68 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/crypto" + 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" + "time" +) + +type TokenVerifierRepo struct { + TokenVerificationKey [32]byte + IamID string + IamEvents *iam_event.IamEventstore + ProjectEvents *proj_event.ProjectEventstore + View *view.View +} + +func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, appName, appID string) (userID string, clientID string, agentID string, err error) { + clientID, err = repo.verifierClientID(ctx, appName, appID) + if err != nil { + return "", "", "", caos_errs.ThrowPermissionDenied(nil, "APP-ptTIF2", "invalid token") + } + //TODO: use real key + tokenID, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32])) + if err != nil { + return "", "", "", caos_errs.ThrowPermissionDenied(nil, "APP-8EF0zZ", "invalid token") + } + token, err := repo.View.TokenByID(tokenID) + if err != nil { + return "", "", "", caos_errs.ThrowPermissionDenied(err, "APP-BxUSiL", "invalid token") + } + if !token.Expiration.After(time.Now().UTC()) { + return "", "", "", caos_errs.ThrowPermissionDenied(err, "APP-k9KS0", "invalid token") + } + + for _, aud := range token.Audience { + if clientID == aud { + return token.UserID, clientID, token.UserAgentID, nil + } + } + return "", "", "", caos_errs.ThrowPermissionDenied(nil, "APP-Zxfako", "invalid audience") +} + +func (repo *TokenVerifierRepo) ProjectIDByClientID(ctx context.Context, clientID string) (projectID string, err error) { + app, err := repo.View.ApplicationByOIDCClientID(clientID) + if err != nil { + return "", err + } + return app.ID, nil +} + +func (repo *TokenVerifierRepo) verifierClientID(ctx context.Context, appName, appClientID string) (string, error) { + if appClientID != "" { + return appClientID, nil + } + iam, err := repo.IamEvents.IamByID(ctx, repo.IamID) + if err != nil { + return "", err + } + app, err := repo.View.ApplicationByProjecIDAndAppName(iam.IamProjectID, appName) + if err != nil { + return "", err + } + return app.OIDCClientID, nil +} diff --git a/internal/authz/repository/eventsourcing/eventstore/user_grant.go b/internal/authz/repository/eventsourcing/eventstore/user_grant.go new file mode 100644 index 0000000000..08a170885c --- /dev/null +++ b/internal/authz/repository/eventsourcing/eventstore/user_grant.go @@ -0,0 +1,102 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + caos_errs "github.com/caos/zitadel/internal/errors" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" +) + +type UserGrantRepo struct { + View *view.View + IamID string + IamProjectID string + Auth auth.Config + IamEvents *iam_event.IamEventstore +} + +func (repo *UserGrantRepo) Health() error { + return repo.View.Health() +} + +func (repo *UserGrantRepo) ResolveGrants(ctx context.Context) (*auth.Grant, error) { + err := repo.fillIamProjectID(ctx) + if err != nil { + return nil, err + } + ctxData := auth.GetCtxData(ctx) + + orgGrant, err := repo.View.UserGrantByIDs(ctxData.OrgID, repo.IamProjectID, ctxData.UserID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + iamAdminGrant, err := repo.View.UserGrantByIDs(repo.IamID, repo.IamProjectID, ctxData.UserID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + + return mergeOrgAndAdminGrant(ctxData, orgGrant, iamAdminGrant), nil +} + +func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) { + grant, err := repo.ResolveGrants(ctx) + if err != nil { + return nil, err + } + + permissions := &grant_model.Permissions{Permissions: []string{}} + for _, role := range grant.Roles { + roleName, ctxID := auth.SplitPermission(role) + for _, mapping := range repo.Auth.RolePermissionMappings { + if mapping.Role == roleName { + permissions.AppendPermissions(ctxID, mapping.Permissions...) + } + } + } + return permissions.Permissions, nil +} + +func (repo *UserGrantRepo) fillIamProjectID(ctx context.Context) error { + if repo.IamProjectID != "" { + return nil + } + iam, err := repo.IamEvents.IamByID(ctx, repo.IamID) + if err != nil { + return err + } + if !iam.SetUpDone { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-skiwS", "Setup not done") + } + repo.IamProjectID = iam.IamProjectID + return nil +} + +func mergeOrgAndAdminGrant(ctxData auth.CtxData, orgGrant, iamAdminGrant *model.UserGrantView) (grant *auth.Grant) { + if orgGrant != nil { + roles := orgGrant.RoleKeys + if iamAdminGrant != nil { + roles = addIamAdminRoles(roles, iamAdminGrant.RoleKeys) + } + grant = &auth.Grant{OrgID: orgGrant.ResourceOwner, Roles: roles} + } else if iamAdminGrant != nil { + grant = &auth.Grant{ + OrgID: ctxData.OrgID, + Roles: iamAdminGrant.RoleKeys, + } + } + return grant +} + +func addIamAdminRoles(orgRoles, iamAdminRoles []string) []string { + result := make([]string, 0) + result = append(result, iamAdminRoles...) + for _, role := range orgRoles { + if !auth.ExistsPerm(result, role) { + result = append(result, role) + } + } + return result +} diff --git a/internal/authz/repository/eventsourcing/handler/application.go b/internal/authz/repository/eventsourcing/handler/application.go new file mode 100644 index 0000000000..ea8708b9ef --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/application.go @@ -0,0 +1,72 @@ +package handler + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/project/repository/eventsourcing" + es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/project/repository/view/model" + "time" +) + +type Application struct { + handler +} + +const ( + applicationTable = "authz.applications" +) + +func (p *Application) MinimumCycleDuration() time.Duration { return p.cycleDuration } + +func (p *Application) ViewModel() string { + return applicationTable +} + +func (p *Application) EventQuery() (*models.SearchQuery, error) { + sequence, err := p.view.GetLatestApplicationSequence() + if err != nil { + return nil, err + } + return eventsourcing.ProjectQuery(sequence), nil +} + +func (p *Application) Process(event *models.Event) (err error) { + app := new(view_model.ApplicationView) + switch event.Type { + case es_model.ApplicationAdded: + app.AppendEvent(event) + case es_model.ApplicationChanged, + es_model.OIDCConfigAdded, + es_model.OIDCConfigChanged, + es_model.ApplicationDeactivated, + es_model.ApplicationReactivated: + err := app.SetData(event) + if err != nil { + return err + } + app, err = p.view.ApplicationByID(app.ID) + if err != nil { + return err + } + app.AppendEvent(event) + case es_model.ApplicationRemoved: + err := app.SetData(event) + if err != nil { + return err + } + return p.view.DeleteApplication(app.ID, event.Sequence) + default: + return p.view.ProcessedApplicationSequence(event.Sequence) + } + if err != nil { + return err + } + return p.view.PutApplication(app) +} + +func (p *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, p.view.GetLatestApplicationFailedEvent, p.view.ProcessedApplicationFailedEvent, p.view.ProcessedApplicationSequence, p.errorCountUntilSkip) +} diff --git a/internal/authz/repository/eventsourcing/handler/handler.go b/internal/authz/repository/eventsourcing/handler/handler.go new file mode 100644 index 0000000000..d5904f0435 --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/handler.go @@ -0,0 +1,49 @@ +package handler + +import ( + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/eventstore" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + "time" + + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/eventstore/spooler" +) + +type Configs map[string]*Config + +type Config struct { + MinimumCycleDuration types.Duration +} + +type handler struct { + view *view.View + bulkLimit uint64 + cycleDuration time.Duration + errorCountUntilSkip uint64 +} + +type EventstoreRepos struct { + IamEvents *iam_events.IamEventstore +} + +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []spooler.Handler { + return []spooler.Handler{ + &UserGrant{ + handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, + eventstore: eventstore, + iamID: systemDefaults.IamID, + iamEvents: repos.IamEvents, + }, + &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}}, + } +} + +func (configs Configs) cycleDuration(viewModel string) time.Duration { + c, ok := configs[viewModel] + if !ok { + return 1 * time.Second + } + return c.MinimumCycleDuration.Duration +} diff --git a/internal/authz/repository/eventsourcing/handler/user_grant.go b/internal/authz/repository/eventsourcing/handler/user_grant.go new file mode 100644 index 0000000000..33990cbf96 --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/user_grant.go @@ -0,0 +1,226 @@ +package handler + +import ( + "context" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" + "strings" + "time" +) + +type UserGrant struct { + handler + eventstore eventstore.Eventstore + iamEvents *iam_events.IamEventstore + iamID string + iamProjectID string +} + +const ( + userGrantTable = "authz.user_grants" +) + +func (u *UserGrant) MinimumCycleDuration() time.Duration { return u.cycleDuration } + +func (u *UserGrant) ViewModel() string { + return userGrantTable +} + +func (u *UserGrant) EventQuery() (*models.SearchQuery, error) { + if u.iamProjectID == "" { + err := u.setIamProjectID() + if err != nil { + return nil, err + } + } + sequence, err := u.view.GetLatestUserGrantSequence() + if err != nil { + return nil, err + } + return es_models.NewSearchQuery(). + AggregateTypeFilter(iam_es_model.IamAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate). + LatestSequenceFilter(sequence), nil +} + +func (u *UserGrant) Process(event *models.Event) (err error) { + switch event.AggregateType { + case proj_es_model.ProjectAggregate: + err = u.processProject(event) + case iam_es_model.IamAggregate: + err = u.processIamMember(event, "IAM", false) + case org_es_model.OrgAggregate: + return u.processOrg(event) + } + return err +} + +func (u *UserGrant) processProject(event *models.Event) (err error) { + switch event.Type { + case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved: + member := new(proj_es_model.ProjectMember) + member.SetData(event) + return u.processMember(event, "PROJECT", true, member.UserID, member.Roles) + case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged, proj_es_model.ProjectGrantMemberRemoved: + member := new(proj_es_model.ProjectGrantMember) + member.SetData(event) + return u.processMember(event, "PROJECT_GRANT", true, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processOrg(event *models.Event) (err error) { + switch event.Type { + case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged, org_es_model.OrgMemberRemoved: + member := new(org_es_model.OrgMember) + member.SetData(event) + return u.processMember(event, "ORG", false, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suffix bool) error { + member := new(iam_es_model.IamMember) + + switch event.Type { + case iam_es_model.IamMemberAdded, iam_es_model.IamMemberChanged: + member.SetData(event) + + grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + member.UserID, + ResourceOwner: u.iamID, + OrgName: u.iamID, + OrgDomain: u.iamID, + ProjectID: u.iamProjectID, + UserID: member.UserID, + RoleKeys: member.Roles, + CreationDate: event.CreationDate, + } + if suffix { + grant.RoleKeys = suffixRoles(event.AggregateID, grant.RoleKeys) + } + } else { + newRoles := member.Roles + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, grant.Sequence) + 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) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func (u *UserGrant) processMember(event *models.Event, rolePrefix string, suffix bool, userID string, roleKeys []string) error { + switch event.Type { + case org_es_model.OrgMemberAdded, proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded, + org_es_model.OrgMemberChanged, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectGrantMemberChanged: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if suffix { + roleKeys = suffixRoles(event.AggregateID, roleKeys) + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + event.ResourceOwner + userID, + ResourceOwner: event.ResourceOwner, + ProjectID: u.iamProjectID, + UserID: userID, + RoleKeys: roleKeys, + CreationDate: event.CreationDate, + } + } else { + newRoles := roleKeys + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, event.Sequence) + case org_es_model.OrgMemberRemoved, + proj_es_model.ProjectMemberRemoved, + proj_es_model.ProjectGrantMemberRemoved: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil { + return err + } + return u.view.DeleteUserGrant(grant.ID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func suffixRoles(suffix string, roles []string) []string { + suffixedRoles := make([]string, len(roles)) + for i := 0; i < len(roles); i++ { + suffixedRoles[i] = roles[i] + ":" + suffix + } + return suffixedRoles +} + +func mergeExistingRoles(rolePrefix string, existingRoles, newRoles []string) []string { + mergedRoles := make([]string, 0) + for _, existing := range existingRoles { + if !strings.HasPrefix(existing, rolePrefix) { + mergedRoles = append(mergedRoles, existing) + } + } + return append(mergedRoles, newRoles...) +} + +func (u *UserGrant) setIamProjectID() error { + if u.iamProjectID != "" { + return nil + } + iam, err := u.iamEvents.IamByID(context.Background(), u.iamID) + if err != nil { + return err + } + if !iam.SetUpDone { + return caos_errs.ThrowPreconditionFailed(nil, "HANDL-s5DTs", "Setup not done") + } + u.iamProjectID = iam.IamProjectID + return nil +} + +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) +} diff --git a/internal/authz/repository/eventsourcing/repository.go b/internal/authz/repository/eventsourcing/repository.go new file mode 100644 index 0000000000..29772e4667 --- /dev/null +++ b/internal/authz/repository/eventsourcing/repository.go @@ -0,0 +1,98 @@ +package eventsourcing + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/handler" + es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + "github.com/caos/zitadel/internal/id" + es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" + + "github.com/caos/zitadel/internal/auth_request/repository/cache" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/eventstore" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/spooler" + authz_view "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/config/types" + es_int "github.com/caos/zitadel/internal/eventstore" + es_spol "github.com/caos/zitadel/internal/eventstore/spooler" + es_key "github.com/caos/zitadel/internal/key/repository/eventsourcing" +) + +type Config struct { + Eventstore es_int.Config + AuthRequest cache.Config + View types.SQL + Spooler spooler.SpoolerConfig + KeyConfig es_key.KeyConfig +} + +type EsRepository struct { + spooler *es_spol.Spooler + eventstore.UserGrantRepo + eventstore.IamRepo + eventstore.TokenVerifierRepo +} + +func Start(conf Config, authZ auth.Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) { + es, err := es_int.Start(conf.Eventstore) + if err != nil { + return nil, err + } + + sqlClient, err := conf.View.Start() + if err != nil { + return nil, err + } + + idGenerator := id.SonyFlakeGenerator + view, err := authz_view.StartView(sqlClient, idGenerator) + if err != nil { + return nil, err + } + + iam, err := es_iam.StartIam(es_iam.IamConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, systemDefaults) + if err != nil { + return nil, err + } + project, err := es_proj.StartProject(es_proj.ProjectConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, systemDefaults) + if err != nil { + return nil, err + } + repos := handler.EventstoreRepos{IamEvents: iam} + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) + + return &EsRepository{ + spool, + eventstore.UserGrantRepo{ + View: view, + IamID: systemDefaults.IamID, + Auth: authZ, + IamEvents: iam, + }, + eventstore.IamRepo{ + IamID: systemDefaults.IamID, + IamEvents: iam, + }, + eventstore.TokenVerifierRepo{ + //TODO: Add Token Verification Key + IamID: systemDefaults.IamID, + IamEvents: iam, + ProjectEvents: project, + View: view, + }, + }, nil +} + +func (repo *EsRepository) Health(ctx context.Context) error { + if err := repo.UserGrantRepo.Health(); err != nil { + return err + } + return nil +} diff --git a/internal/authz/repository/eventsourcing/spooler/lock.go b/internal/authz/repository/eventsourcing/spooler/lock.go new file mode 100644 index 0000000000..6100f470d3 --- /dev/null +++ b/internal/authz/repository/eventsourcing/spooler/lock.go @@ -0,0 +1,19 @@ +package spooler + +import ( + "database/sql" + es_locker "github.com/caos/zitadel/internal/eventstore/locker" + "time" +) + +const ( + lockTable = "authz.locks" +) + +type locker struct { + dbClient *sql.DB +} + +func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error { + return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime) +} diff --git a/internal/authz/repository/eventsourcing/spooler/lock_test.go b/internal/authz/repository/eventsourcing/spooler/lock_test.go new file mode 100644 index 0000000000..904d0b9838 --- /dev/null +++ b/internal/authz/repository/eventsourcing/spooler/lock_test.go @@ -0,0 +1,127 @@ +package spooler + +import ( + "database/sql" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +type dbMock struct { + db *sql.DB + mock sqlmock.Sqlmock +} + +func mockDB(t *testing.T) *dbMock { + mockDB := dbMock{} + var err error + mockDB.db, mockDB.mock, err = sqlmock.New() + if err != nil { + t.Fatalf("error occured while creating stub db %v", err) + } + + mockDB.mock.MatchExpectationsInOrder(true) + + return &mockDB +} + +func (db *dbMock) expectCommit() *dbMock { + db.mock.ExpectCommit() + + return db +} + +func (db *dbMock) expectRollback() *dbMock { + db.mock.ExpectRollback() + + return db +} + +func (db *dbMock) expectBegin() *dbMock { + db.mock.ExpectBegin() + + return db +} + +func (db *dbMock) expectSavepoint() *dbMock { + db.mock.ExpectExec("SAVEPOINT").WillReturnResult(sqlmock.NewResult(1, 1)) + return db +} + +func (db *dbMock) expectReleaseSavepoint() *dbMock { + db.mock.ExpectExec("RELEASE SAVEPOINT").WillReturnResult(sqlmock.NewResult(1, 1)) + + return db +} + +func (db *dbMock) expectRenew(lockerID, view string, affectedRows int64) *dbMock { + query := db.mock. + ExpectExec(`INSERT INTO authz\.locks \(object_type, locker_id, locked_until\) VALUES \(\$1, \$2, now\(\)\+\$3\) ON CONFLICT \(object_type\) DO UPDATE SET locked_until = now\(\)\+\$4, locker_id = \$5 WHERE \(locks\.locked_until < now\(\) OR locks\.locker_id = \$6\) AND locks\.object_type = \$7`). + WithArgs(view, lockerID, sqlmock.AnyArg(), sqlmock.AnyArg(), lockerID, lockerID, view). + WillReturnResult(sqlmock.NewResult(1, 1)) + + if affectedRows == 0 { + query.WillReturnResult(sqlmock.NewResult(0, 0)) + } else { + query.WillReturnResult(sqlmock.NewResult(1, affectedRows)) + } + + return db +} + +func Test_locker_Renew(t *testing.T) { + type fields struct { + db *dbMock + } + type args struct { + lockerID string + viewModel string + waitTime time.Duration + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "renew succeeded", + fields: fields{ + db: mockDB(t). + expectBegin(). + expectSavepoint(). + expectRenew("locker", "view", 1). + expectReleaseSavepoint(). + expectCommit(), + }, + args: args{lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second}, + wantErr: false, + }, + { + name: "renew now rows updated", + fields: fields{ + db: mockDB(t). + expectBegin(). + expectSavepoint(). + expectRenew("locker", "view", 0). + expectRollback(), + }, + args: args{lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := &locker{ + dbClient: tt.fields.db.db, + } + if err := l.Renew(tt.args.lockerID, tt.args.viewModel, tt.args.waitTime); (err != nil) != tt.wantErr { + t.Errorf("locker.Renew() error = %v, wantErr %v", err, tt.wantErr) + } + if err := tt.fields.db.mock.ExpectationsWereMet(); err != nil { + t.Errorf("not all database expectations met: %v", err) + } + }) + } +} diff --git a/internal/authz/repository/eventsourcing/spooler/spooler.go b/internal/authz/repository/eventsourcing/spooler/spooler.go new file mode 100644 index 0000000000..656721ed55 --- /dev/null +++ b/internal/authz/repository/eventsourcing/spooler/spooler.go @@ -0,0 +1,31 @@ +package spooler + +import ( + "database/sql" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/handler" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/spooler" +) + +type SpoolerConfig struct { + BulkLimit uint64 + FailureCountUntilSkip uint64 + ConcurrentTasks int + Handlers handler.Configs +} + +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos, systemDefaults sd.SystemDefaults) *spooler.Spooler { + spoolerConfig := spooler.Config{ + Eventstore: es, + Locker: &locker{dbClient: sql}, + ConcurrentTasks: c.ConcurrentTasks, + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, systemDefaults), + } + spool := spoolerConfig.New() + spool.Start() + return spool +} diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go new file mode 100644 index 0000000000..e99a01950f --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/application.go @@ -0,0 +1,60 @@ +package view + +import ( + 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" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + applicationTable = "authz.applications" +) + +func (v *View) ApplicationByID(appID string) (*model.ApplicationView, error) { + return view.ApplicationByID(v.Db, applicationTable, appID) +} + +func (v *View) ApplicationByOIDCClientID(clientID string) (*model.ApplicationView, error) { + return view.ApplicationByOIDCClientID(v.Db, applicationTable, clientID) +} + +func (v *View) ApplicationByProjecIDAndAppName(projectID, appName string) (*model.ApplicationView, error) { + return view.ApplicationByProjectIDAndAppName(v.Db, applicationTable, projectID, appName) +} + +func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) { + return view.SearchApplications(v.Db, applicationTable, request) +} + +func (v *View) PutApplication(project *model.ApplicationView) error { + err := view.PutApplication(v.Db, applicationTable, project) + if err != nil { + return err + } + return v.ProcessedApplicationSequence(project.Sequence) +} + +func (v *View) DeleteApplication(appID string, eventSequence uint64) error { + err := view.DeleteApplication(v.Db, applicationTable, appID) + if err != nil { + return nil + } + return v.ProcessedApplicationSequence(eventSequence) +} + +func (v *View) GetLatestApplicationSequence() (uint64, error) { + return v.latestSequence(applicationTable) +} + +func (v *View) ProcessedApplicationSequence(eventSequence uint64) error { + return v.saveCurrentSequence(applicationTable, eventSequence) +} + +func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(applicationTable, sequence) +} + +func (v *View) ProcessedApplicationFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/authz/repository/eventsourcing/view/error_event.go b/internal/authz/repository/eventsourcing/view/error_event.go new file mode 100644 index 0000000000..a6e8bb9927 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/error_event.go @@ -0,0 +1,17 @@ +package view + +import ( + "github.com/caos/zitadel/internal/view" +) + +const ( + errTable = "authz.failed_event" +) + +func (v *View) saveFailedEvent(failedEvent *view.FailedEvent) error { + return view.SaveFailedEvent(v.Db, errTable, failedEvent) +} + +func (v *View) latestFailedEvent(viewName string, sequence uint64) (*view.FailedEvent, error) { + return view.LatestFailedEvent(v.Db, errTable, viewName, sequence) +} diff --git a/internal/authz/repository/eventsourcing/view/sequence.go b/internal/authz/repository/eventsourcing/view/sequence.go new file mode 100644 index 0000000000..ddcfafbf62 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/sequence.go @@ -0,0 +1,17 @@ +package view + +import ( + "github.com/caos/zitadel/internal/view" +) + +const ( + sequencesTable = "authz.current_sequences" +) + +func (v *View) saveCurrentSequence(viewName string, sequence uint64) error { + return view.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence) +} + +func (v *View) latestSequence(viewName string) (uint64, error) { + return view.LatestSequence(v.Db, sequencesTable, viewName) +} diff --git a/internal/authz/repository/eventsourcing/view/token.go b/internal/authz/repository/eventsourcing/view/token.go new file mode 100644 index 0000000000..3bbc834b4e --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/token.go @@ -0,0 +1,59 @@ +package view + +import ( + "github.com/caos/zitadel/internal/token/repository/view" + "github.com/caos/zitadel/internal/token/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + tokenTable = "auth.tokens" +) + +func (v *View) TokenByID(tokenID string) (*model.Token, error) { + return view.TokenByID(v.Db, tokenTable, tokenID) +} + +func (v *View) IsTokenValid(tokenID string) (bool, error) { + return view.IsTokenValid(v.Db, tokenTable, tokenID) +} + +func (v *View) PutToken(token *model.Token) error { + err := view.PutToken(v.Db, tokenTable, token) + if err != nil { + return err + } + return v.ProcessedTokenSequence(token.Sequence) +} + +func (v *View) DeleteToken(tokenID string, eventSequence uint64) error { + err := view.DeleteToken(v.Db, tokenTable, tokenID) + if err != nil { + return nil + } + return v.ProcessedTokenSequence(eventSequence) +} + +func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64) error { + err := view.DeleteTokens(v.Db, tokenTable, agentID, userID) + if err != nil { + return nil + } + return v.ProcessedTokenSequence(eventSequence) +} + +func (v *View) GetLatestTokenSequence() (uint64, error) { + return v.latestSequence(tokenTable) +} + +func (v *View) ProcessedTokenSequence(eventSequence uint64) error { + return v.saveCurrentSequence(tokenTable, eventSequence) +} + +func (v *View) GetLatestTokenFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(tokenTable, sequence) +} + +func (v *View) ProcessedTokenFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/authz/repository/eventsourcing/view/user_grant.go b/internal/authz/repository/eventsourcing/view/user_grant.go new file mode 100644 index 0000000000..f4b01adfd8 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/user_grant.go @@ -0,0 +1,64 @@ +package view + +import ( + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + userGrantTable = "authz.user_grants" +) + +func (v *View) UserGrantByID(grantID string) (*model.UserGrantView, error) { + return view.UserGrantByID(v.Db, userGrantTable, grantID) +} + +func (v *View) UserGrantByIDs(resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) { + return view.UserGrantByIDs(v.Db, userGrantTable, resourceOwnerID, projectID, userID) +} + +func (v *View) UserGrantsByUserID(userID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByUserID(v.Db, userGrantTable, userID) +} + +func (v *View) UserGrantsByProjectID(projectID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByProjectID(v.Db, userGrantTable, projectID) +} + +func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) { + return view.SearchUserGrants(v.Db, userGrantTable, request) +} + +func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error { + err := view.PutUserGrant(v.Db, userGrantTable, grant) + if err != nil { + return err + } + return v.ProcessedUserGrantSequence(sequence) +} + +func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error { + err := view.DeleteUserGrant(v.Db, userGrantTable, grantID) + if err != nil { + return nil + } + return v.ProcessedUserGrantSequence(eventSequence) +} + +func (v *View) GetLatestUserGrantSequence() (uint64, error) { + return v.latestSequence(userGrantTable) +} + +func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error { + return v.saveCurrentSequence(userGrantTable, eventSequence) +} + +func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(userGrantTable, sequence) +} + +func (v *View) ProcessedUserGrantFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/authz/repository/eventsourcing/view/view.go b/internal/authz/repository/eventsourcing/view/view.go new file mode 100644 index 0000000000..61799ad360 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/view.go @@ -0,0 +1,28 @@ +package view + +import ( + "database/sql" + "github.com/caos/zitadel/internal/id" + + "github.com/jinzhu/gorm" +) + +type View struct { + Db *gorm.DB + idGenerator id.Generator +} + +func StartView(sqlClient *sql.DB, idGenerator id.Generator) (*View, error) { + gorm, err := gorm.Open("postgres", sqlClient) + if err != nil { + return nil, err + } + return &View{ + Db: gorm, + idGenerator: idGenerator, + }, nil +} + +func (v *View) Health() (err error) { + return v.Db.DB().Ping() +} diff --git a/internal/authz/repository/iam.go b/internal/authz/repository/iam.go new file mode 100644 index 0000000000..0197c163c7 --- /dev/null +++ b/internal/authz/repository/iam.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/iam/model" +) + +type IamRepository interface { + Health(ctx context.Context) error + IamByID(ctx context.Context, id string) (*model.Iam, error) +} diff --git a/internal/authz/repository/repository.go b/internal/authz/repository/repository.go new file mode 100644 index 0000000000..4b54764fd8 --- /dev/null +++ b/internal/authz/repository/repository.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" +) + +type Repository interface { + Health(context.Context) error + UserGrantRepository + IamRepository +} diff --git a/internal/authz/repository/token_verifier.go b/internal/authz/repository/token_verifier.go new file mode 100644 index 0000000000..e856178233 --- /dev/null +++ b/internal/authz/repository/token_verifier.go @@ -0,0 +1,10 @@ +package repository + +import ( + "context" +) + +type TokenVerifierRepository interface { + VerifyAccessToken(ctx context.Context, appName string) (string, string, string, error) + ProjectIDByClientID(ctx context.Context, clientID string) (string, error) +} diff --git a/internal/authz/repository/user_grant.go b/internal/authz/repository/user_grant.go new file mode 100644 index 0000000000..6a6619855b --- /dev/null +++ b/internal/authz/repository/user_grant.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" +) + +type UserGrantRepository interface { + ResolveGrants(ctx context.Context) (*auth.Grant, error) + SearchMyZitadelPermissions(ctx context.Context) ([]string, error) +} diff --git a/internal/crypto/crypto.go b/internal/crypto/crypto.go index 4dec2ecd09..e82ad6d039 100644 --- a/internal/crypto/crypto.go +++ b/internal/crypto/crypto.go @@ -1,6 +1,9 @@ package crypto import ( + "database/sql/driver" + "encoding/json" + "github.com/caos/zitadel/internal/errors" ) @@ -35,6 +38,23 @@ type CryptoValue struct { Crypted []byte } +func (c *CryptoValue) Value() (driver.Value, error) { + if c == nil { + return nil, nil + } + return json.Marshal(c) +} + +func (c *CryptoValue) Scan(src interface{}) error { + if b, ok := src.([]byte); ok { + return json.Unmarshal(b, c) + } + if s, ok := src.(string); ok { + return json.Unmarshal([]byte(s), c) + } + return nil +} + type CryptoType int func Crypt(value []byte, c Crypto) (*CryptoValue, error) { diff --git a/internal/crypto/rsa.go b/internal/crypto/rsa.go new file mode 100644 index 0000000000..b8295fbb29 --- /dev/null +++ b/internal/crypto/rsa.go @@ -0,0 +1,103 @@ +package crypto + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" +) + +func GenerateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { + privkey, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return nil, nil, err + } + return privkey, &privkey.PublicKey, nil +} + +func GenerateEncryptedKeyPair(bits int, alg EncryptionAlgorithm) (*CryptoValue, *CryptoValue, error) { + privateKey, publicKey, err := GenerateKeyPair(bits) + if err != nil { + return nil, nil, err + } + return EncryptKeys(privateKey, publicKey, alg) +} + +func PrivateKeyToBytes(priv *rsa.PrivateKey) []byte { + return pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(priv), + }, + ) +} + +func PublicKeyToBytes(pub *rsa.PublicKey) ([]byte, error) { + pubASN1, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, err + } + + pubBytes := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: pubASN1, + }) + + return pubBytes, nil +} + +func BytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(priv) + enc := x509.IsEncryptedPEMBlock(block) + b := block.Bytes + var err error + if enc { + b, err = x509.DecryptPEMBlock(block, nil) + if err != nil { + return nil, err + } + } + key, err := x509.ParsePKCS1PrivateKey(b) + if err != nil { + return nil, err + } + return key, nil +} + +func BytesToPublicKey(pub []byte) (*rsa.PublicKey, error) { + block, _ := pem.Decode(pub) + enc := x509.IsEncryptedPEMBlock(block) + b := block.Bytes + var err error + if enc { + b, err = x509.DecryptPEMBlock(block, nil) + if err != nil { + return nil, err + } + } + ifc, err := x509.ParsePKIXPublicKey(b) + if err != nil { + return nil, err + } + key, ok := ifc.(*rsa.PublicKey) + if !ok { + return nil, err + } + return key, nil +} + +func EncryptKeys(privateKey *rsa.PrivateKey, publicKey *rsa.PublicKey, alg EncryptionAlgorithm) (*CryptoValue, *CryptoValue, error) { + encryptedPrivateKey, err := Encrypt(PrivateKeyToBytes(privateKey), alg) + if err != nil { + return nil, nil, err + } + pubKey, err := PublicKeyToBytes(publicKey) + if err != nil { + return nil, nil, err + } + encryptedPublicKey, err := Encrypt(pubKey, alg) + if err != nil { + return nil, nil, err + } + return encryptedPrivateKey, encryptedPublicKey, nil +} diff --git a/internal/form/parser.go b/internal/form/parser.go new file mode 100644 index 0000000000..e0b4406bb1 --- /dev/null +++ b/internal/form/parser.go @@ -0,0 +1,27 @@ +package form + +import ( + "github.com/caos/zitadel/internal/errors" + "net/http" + + "github.com/gorilla/schema" +) + +type Parser struct { + decoder *schema.Decoder +} + +func NewParser() *Parser { + d := schema.NewDecoder() + d.IgnoreUnknownKeys(true) + return &Parser{d} +} + +func (p *Parser) Parse(r *http.Request, data interface{}) error { + err := r.ParseForm() + if err != nil { + return errors.ThrowInternal(err, "FORM-lCC9zI", "error parsing http form") + } + + return p.decoder.Decode(data, r.Form) +} diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go new file mode 100644 index 0000000000..6c48c0fb04 --- /dev/null +++ b/internal/i18n/i18n.go @@ -0,0 +1,128 @@ +package i18n + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "os" + + http_util "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/errors" + + "github.com/caos/logging" + "github.com/ghodss/yaml" + "github.com/nicksnyder/go-i18n/v2/i18n" + "golang.org/x/text/language" +) + +const ( + i18nPath = "/i18n" +) + +type Translator struct { + bundle *i18n.Bundle + cookieName string + cookieHandler *http_util.CookieHandler +} + +type TranslatorConfig struct { + DefaultLanguage language.Tag + CookieName string +} + +func NewTranslator(dir http.FileSystem, config TranslatorConfig) (*Translator, error) { + t := new(Translator) + var err error + t.bundle, err = newBundle(dir, config.DefaultLanguage) + if err != nil { + return nil, err + } + t.cookieHandler = http_util.NewCookieHandler() + t.cookieName = config.CookieName + return t, nil +} + +func newBundle(dir http.FileSystem, defaultLanguage language.Tag) (*i18n.Bundle, error) { + bundle := i18n.NewBundle(defaultLanguage) + bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal) + bundle.RegisterUnmarshalFunc("json", json.Unmarshal) + i18nDir, err := dir.Open(i18nPath) + if err != nil { + return nil, errors.ThrowNotFound(err, "I18N-MnXRie", "path not found") + } + defer i18nDir.Close() + files, err := i18nDir.Readdir(0) + if err != nil { + return nil, errors.ThrowNotFound(err, "I18N-Gew23", "cannot read dir") + } + for _, file := range files { + if err := addFileToBundle(dir, bundle, file); err != nil { + return nil, errors.ThrowNotFound(err, "I18N-ZS2AW", "cannot append file to bundle") + } + } + return bundle, nil +} + +func addFileToBundle(dir http.FileSystem, bundle *i18n.Bundle, file os.FileInfo) error { + f, err := dir.Open("/i18n/" + file.Name()) + if err != nil { + return err + } + defer f.Close() + content, err := ioutil.ReadAll(f) + if err != nil { + return err + } + bundle.MustParseMessageFileBytes(content, file.Name()) + return nil +} + +func (t *Translator) LocalizeFromRequest(r *http.Request, id string, args map[string]interface{}) string { + s, err := t.localizerFromRequest(r).Localize(&i18n.LocalizeConfig{ + MessageID: id, + TemplateData: args, + }) + if err != nil { + logging.Log("I18N-MsF5sx").WithError(err).Warnf("missing translation") + return id + } + return s +} + +func (t *Translator) Localize(id string, args map[string]interface{}) string { + s, _ := t.localizer().Localize(&i18n.LocalizeConfig{ + MessageID: id, + TemplateData: args, + }) + return s +} + +func (t *Translator) Lang(r *http.Request) language.Tag { + matcher := language.NewMatcher(t.bundle.LanguageTags()) + tag, _ := language.MatchStrings(matcher, t.langsFromRequest(r)...) + return tag +} + +func (t *Translator) SetLangCookie(w http.ResponseWriter, lang language.Tag) { + t.cookieHandler.SetCookie(w, t.cookieName, lang.String()) +} + +func (t *Translator) localizerFromRequest(r *http.Request) *i18n.Localizer { + return t.localizer(t.langsFromRequest(r)...) +} + +func (t *Translator) localizer(langs ...string) *i18n.Localizer { + return i18n.NewLocalizer(t.bundle, langs...) +} + +func (t *Translator) langsFromRequest(r *http.Request) []string { + langs := make([]string, 0) + if r != nil { + lang, err := t.cookieHandler.GetCookieValue(r, t.cookieName) + if err == nil { + langs = append(langs, lang) + } + langs = append(langs, r.Header.Get("Accept-Language")) + } + return langs +} diff --git a/internal/iam/repository/eventsourcing/model/iam.go b/internal/iam/repository/eventsourcing/model/iam.go index 1cd98beed7..bc0226a20c 100644 --- a/internal/iam/repository/eventsourcing/model/iam.go +++ b/internal/iam/repository/eventsourcing/model/iam.go @@ -65,7 +65,7 @@ func (i *Iam) AppendEvent(event *es_models.Event) (err error) { i.SetUpDone = true case IamProjectSet, GlobalOrgSet: - err = i.setData(event) + err = i.SetData(event) case IamMemberAdded: err = i.appendAddMemberEvent(event) case IamMemberChanged: @@ -76,7 +76,7 @@ func (i *Iam) AppendEvent(event *es_models.Event) (err error) { return err } -func (i *Iam) setData(event *es_models.Event) error { +func (i *Iam) SetData(event *es_models.Event) error { i.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, i); err != nil { logging.Log("EVEN-9sie4").WithError(err).Error("could not unmarshal event data") diff --git a/internal/iam/repository/eventsourcing/model/iam_member.go b/internal/iam/repository/eventsourcing/model/iam_member.go index 4ba5a3456d..7fc23d2b18 100644 --- a/internal/iam/repository/eventsourcing/model/iam_member.go +++ b/internal/iam/repository/eventsourcing/model/iam_member.go @@ -56,7 +56,7 @@ func IamMemberToModel(member *IamMember) *model.IamMember { func (iam *Iam) appendAddMemberEvent(event *es_models.Event) error { member := &IamMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -67,7 +67,7 @@ func (iam *Iam) appendAddMemberEvent(event *es_models.Event) error { func (iam *Iam) appendChangeMemberEvent(event *es_models.Event) error { member := &IamMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -79,7 +79,7 @@ func (iam *Iam) appendChangeMemberEvent(event *es_models.Event) error { func (iam *Iam) appendRemoveMemberEvent(event *es_models.Event) error { member := &IamMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -91,7 +91,7 @@ func (iam *Iam) appendRemoveMemberEvent(event *es_models.Event) error { return nil } -func (m *IamMember) setData(event *es_models.Event) error { +func (m *IamMember) SetData(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, m); err != nil { logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data") diff --git a/internal/key/model/key.go b/internal/key/model/key.go new file mode 100644 index 0000000000..a0af401dc1 --- /dev/null +++ b/internal/key/model/key.go @@ -0,0 +1,46 @@ +package model + +import ( + "time" + + "github.com/caos/zitadel/internal/crypto" + es_models "github.com/caos/zitadel/internal/eventstore/models" +) + +type KeyPair struct { + es_models.ObjectRoot + + Usage KeyUsage + Algorithm string + PrivateKey *Key + PublicKey *Key +} + +type KeyUsage int32 + +const ( + KeyUsageSigning KeyUsage = iota +) + +func (u KeyUsage) String() string { + switch u { + case KeyUsageSigning: + return "sig" + } + return "" +} + +type Key struct { + Key *crypto.CryptoValue + Expiry time.Time +} + +func (k *KeyPair) IsValid() bool { + return k.Algorithm != "" && + k.PrivateKey != nil && k.PrivateKey.IsValid() && + k.PublicKey != nil && k.PublicKey.IsValid() +} + +func (k *Key) IsValid() bool { + return k.Key != nil +} diff --git a/internal/key/model/key_view.go b/internal/key/model/key_view.go new file mode 100644 index 0000000000..545f986158 --- /dev/null +++ b/internal/key/model/key_view.go @@ -0,0 +1,120 @@ +package model + +import ( + "time" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/model" +) + +type KeyView struct { + ID string + Private bool + Expiry time.Time + Algorithm string + Usage KeyUsage + Key *crypto.CryptoValue + Sequence uint64 +} + +type SigningKey struct { + ID string + Algorithm string + Key interface{} +} + +type PublicKey struct { + ID string + Algorithm string + Usage KeyUsage + Key interface{} +} + +type KeySearchRequest struct { + Offset uint64 + Limit uint64 + SortingColumn KeySearchKey + Asc bool + Queries []*KeySearchQuery +} + +type KeySearchKey int32 + +const ( + KEYSEARCHKEY_UNSPECIFIED KeySearchKey = iota + KEYSEARCHKEY_ID + KEYSEARCHKEY_PRIVATE + KEYSEARCHKEY_EXPIRY + KEYSEARCHKEY_USAGE +) + +type KeySearchQuery struct { + Key KeySearchKey + Method model.SearchMethod + Value interface{} +} + +type KeySearchResponse struct { + Offset uint64 + Limit uint64 + TotalResult uint64 + Result []*KeyView +} + +func (r *KeySearchRequest) EnsureLimit(limit uint64) { + if r.Limit == 0 || r.Limit > limit { + r.Limit = limit + } +} + +func SigningKeyFromKeyView(key *KeyView, alg crypto.EncryptionAlgorithm) (*SigningKey, error) { + if key.Usage != KeyUsageSigning || !key.Private { + return nil, errors.ThrowInvalidArgument(nil, "MODEL-5HBdh", "key must be private signing key") + } + keyData, err := crypto.Decrypt(key.Key, alg) + if err != nil { + return nil, err + } + privateKey, err := crypto.BytesToPrivateKey(keyData) + if err != nil { + return nil, err + } + return &SigningKey{ + ID: key.ID, + Algorithm: key.Algorithm, + Key: privateKey, + }, nil +} + +func PublicKeysFromKeyView(keys []*KeyView, alg crypto.EncryptionAlgorithm) ([]*PublicKey, error) { + converted := make([]*PublicKey, len(keys)) + var err error + for i, key := range keys { + converted[i], err = PublicKeyFromKeyView(key, alg) + if err != nil { + return nil, err + } + } + return converted, nil + +} +func PublicKeyFromKeyView(key *KeyView, alg crypto.EncryptionAlgorithm) (*PublicKey, error) { + if key.Private { + return nil, errors.ThrowInvalidArgument(nil, "MODEL-dTZa2", "key must be public") + } + keyData, err := crypto.Decrypt(key.Key, alg) + if err != nil { + return nil, err + } + publicKey, err := crypto.BytesToPublicKey(keyData) + if err != nil { + return nil, err + } + return &PublicKey{ + ID: key.ID, + Algorithm: key.Algorithm, + Usage: key.Usage, + Key: publicKey, + }, nil +} diff --git a/internal/key/repository/eventsourcing/eventstore.go b/internal/key/repository/eventsourcing/eventstore.go new file mode 100644 index 0000000000..149480f5c8 --- /dev/null +++ b/internal/key/repository/eventsourcing/eventstore.go @@ -0,0 +1,84 @@ +package eventsourcing + +import ( + "context" + "time" + + "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/crypto" + caos_errs "github.com/caos/zitadel/internal/errors" + es_int "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + "github.com/caos/zitadel/internal/id" + key_model "github.com/caos/zitadel/internal/key/model" + "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" +) + +type KeyEventstore struct { + es_int.Eventstore + keySize int + keyAlgorithm crypto.EncryptionAlgorithm + privateKeyLifetime time.Duration + publicKeyLifetime time.Duration + idGenerator id.Generator +} + +type KeyConfig struct { + Size int + PrivateKeyLifetime types.Duration + PublicKeyLifetime types.Duration + EncryptionConfig *crypto.KeyConfig + SigningKeyRotation types.Duration +} + +func StartKey(eventstore es_int.Eventstore, config KeyConfig, keyAlgorithm crypto.EncryptionAlgorithm, generator id.Generator) (*KeyEventstore, error) { + return &KeyEventstore{ + Eventstore: eventstore, + keySize: config.Size, + keyAlgorithm: keyAlgorithm, + privateKeyLifetime: config.PrivateKeyLifetime.Duration, + publicKeyLifetime: config.PublicKeyLifetime.Duration, + idGenerator: generator, + }, nil +} + +func (es *KeyEventstore) GenerateKeyPair(ctx context.Context, usage key_model.KeyUsage, algorithm string) (*key_model.KeyPair, error) { + privateKey, publicKey, err := crypto.GenerateEncryptedKeyPair(es.keySize, es.keyAlgorithm) + if err != nil { + return nil, err + } + privateKeyExp := time.Now().UTC().Add(es.privateKeyLifetime) + publicKeyExp := time.Now().UTC().Add(es.publicKeyLifetime) + return es.CreateKeyPair(ctx, &key_model.KeyPair{ + ObjectRoot: models.ObjectRoot{}, + Usage: usage, + Algorithm: algorithm, + PrivateKey: &key_model.Key{ + Key: privateKey, + Expiry: privateKeyExp, + }, + PublicKey: &key_model.Key{ + Key: publicKey, + Expiry: publicKeyExp, + }, + }) +} +func (es *KeyEventstore) CreateKeyPair(ctx context.Context, pair *key_model.KeyPair) (*key_model.KeyPair, error) { + if !pair.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-G34ga", "Name is required") + } + id, err := es.idGenerator.Next() + if err != nil { + return nil, err + } + pair.AggregateID = id + repoKey := model.KeyPairFromModel(pair) + + createAggregate := KeyPairCreateAggregate(es.AggregateCreator(), repoKey) + err = es_sdk.Push(ctx, es.PushAggregates, repoKey.AppendEvents, createAggregate) + if err != nil { + return nil, err + } + return model.KeyPairToModel(repoKey), nil +} diff --git a/internal/key/repository/eventsourcing/key.go b/internal/key/repository/eventsourcing/key.go new file mode 100644 index 0000000000..b23d38bfb4 --- /dev/null +++ b/internal/key/repository/eventsourcing/key.go @@ -0,0 +1,33 @@ +package eventsourcing + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" +) + +func KeyPairQuery(latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.KeyPairAggregate). + LatestSequenceFilter(latestSequence) +} + +func KeyPairAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, pair *model.KeyPair) (*es_models.Aggregate, error) { + if pair == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d5HNJA", "existing key pair must not be nil") + } + return aggCreator.NewAggregate(ctx, pair.AggregateID, model.KeyPairAggregate, model.KeyPairVersion, pair.Sequence) +} + +func KeyPairCreateAggregate(aggCreator *es_models.AggregateCreator, pair *model.KeyPair) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := KeyPairAggregate(ctx, aggCreator, pair) + if err != nil { + return nil, err + } + + return agg.AppendEvent(model.KeyPairAdded, pair) + } +} diff --git a/internal/key/repository/eventsourcing/model/key.go b/internal/key/repository/eventsourcing/model/key.go new file mode 100644 index 0000000000..50325612dd --- /dev/null +++ b/internal/key/repository/eventsourcing/model/key.go @@ -0,0 +1,90 @@ +package model + +import ( + "encoding/json" + "time" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/key/model" +) + +const ( + KeyPairVersion = "v1" +) + +type KeyPair struct { + es_models.ObjectRoot + + Usage int32 `json:"usage"` + Algorithm string `json:"algorithm"` + PrivateKey *Key `json:"privateKey"` + PublicKey *Key `json:"publicKey"` +} + +type Key struct { + Key *crypto.CryptoValue `json:"key"` + Expiry time.Time `json:"expiry"` +} + +func KeyPairFromModel(pair *model.KeyPair) *KeyPair { + return &KeyPair{ + ObjectRoot: pair.ObjectRoot, + Usage: int32(pair.Usage), + Algorithm: pair.Algorithm, + PrivateKey: KeyFromModel(pair.PrivateKey), + PublicKey: KeyFromModel(pair.PublicKey), + } +} + +func KeyPairToModel(pair *KeyPair) *model.KeyPair { + return &model.KeyPair{ + ObjectRoot: pair.ObjectRoot, + Usage: model.KeyUsage(pair.Usage), + Algorithm: pair.Algorithm, + PrivateKey: KeyToModel(pair.PrivateKey), + PublicKey: KeyToModel(pair.PublicKey), + } +} + +func KeyFromModel(key *model.Key) *Key { + return &Key{ + Key: key.Key, + Expiry: key.Expiry, + } +} + +func KeyToModel(key *Key) *model.Key { + return &model.Key{ + Key: key.Key, + Expiry: key.Expiry, + } +} + +func (k *KeyPair) AppendEvents(events ...*es_models.Event) error { + for _, event := range events { + if err := k.AppendEvent(event); err != nil { + return err + } + } + return nil +} + +func (k *KeyPair) AppendEvent(event *es_models.Event) error { + k.ObjectRoot.AppendEvent(event) + switch event.Type { + case KeyPairAdded: + return k.AppendAddKeyPair(event) + } + return nil +} + +func (k *KeyPair) AppendAddKeyPair(event *es_models.Event) error { + if err := json.Unmarshal(event.Data, k); err != nil { + logging.Log("EVEN-Je92s").WithError(err).Error("could not unmarshal event data") + return err + } + return nil +} diff --git a/internal/key/repository/eventsourcing/model/types.go b/internal/key/repository/eventsourcing/model/types.go new file mode 100644 index 0000000000..2a7975ec04 --- /dev/null +++ b/internal/key/repository/eventsourcing/model/types.go @@ -0,0 +1,9 @@ +package model + +import "github.com/caos/zitadel/internal/eventstore/models" + +const ( + KeyPairAggregate models.AggregateType = "key_pair" + + KeyPairAdded models.EventType = "key_pair.added" +) diff --git a/internal/key/repository/view/key.go b/internal/key/repository/view/key.go new file mode 100644 index 0000000000..482ddf9370 --- /dev/null +++ b/internal/key/repository/view/key.go @@ -0,0 +1,70 @@ +package view + +import ( + "time" + + "github.com/jinzhu/gorm" + + key_model "github.com/caos/zitadel/internal/key/model" + "github.com/caos/zitadel/internal/key/repository/view/model" + global_model "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/view" +) + +func KeyByIDAndType(db *gorm.DB, table, keyID string, private bool) (*model.KeyView, error) { + key := new(model.KeyView) + query := view.PrepareGetByQuery(table, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: keyID}, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_PRIVATE, Method: global_model.SEARCHMETHOD_EQUALS, Value: private}, + ) + err := query(db, key) + return key, err +} + +func GetSigningKey(db *gorm.DB, table string) (*model.KeyView, error) { + key := new(model.KeyView) + query := view.PrepareGetByQuery(table, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_PRIVATE, Method: global_model.SEARCHMETHOD_EQUALS, Value: true}, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_USAGE, Method: global_model.SEARCHMETHOD_EQUALS, Value: key_model.KeyUsageSigning}, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_EXPIRY, Method: global_model.SEARCHMETHOD_GREATER_THAN, Value: time.Now().UTC()}, + ) + err := query(db, key) + return key, err +} + +func GetActivePublicKeys(db *gorm.DB, table string) ([]*model.KeyView, error) { + keys := make([]*model.KeyView, 0) + query := view.PrepareSearchQuery(table, + model.KeySearchRequest{ + Queries: []*key_model.KeySearchQuery{ + {Key: key_model.KEYSEARCHKEY_PRIVATE, Method: global_model.SEARCHMETHOD_EQUALS, Value: false}, + {Key: key_model.KEYSEARCHKEY_USAGE, Method: global_model.SEARCHMETHOD_EQUALS, Value: key_model.KeyUsageSigning}, + {Key: key_model.KEYSEARCHKEY_EXPIRY, Method: global_model.SEARCHMETHOD_GREATER_THAN, Value: time.Now().UTC()}, + }, + }, + ) + _, err := query(db, &keys) + return keys, err +} + +func PutKeys(db *gorm.DB, table string, privateKey, publicKey *model.KeyView) error { + save := view.PrepareSave(table) + err := save(db, privateKey) + if err != nil { + return err + } + return save(db, publicKey) +} + +func DeleteKey(db *gorm.DB, table, keyID string, private bool) error { + delete := view.PrepareDeleteByKeys(table, + view.Key{Key: model.KeySearchKey(key_model.KEYSEARCHKEY_ID), Value: keyID}, + view.Key{Key: model.KeySearchKey(key_model.KEYSEARCHKEY_PRIVATE), Value: private}, + ) + return delete(db) +} + +func DeleteKeyPair(db *gorm.DB, table, keyID string) error { + delete := view.PrepareDeleteByKey(table, model.KeySearchKey(key_model.KEYSEARCHKEY_ID), keyID) + return delete(db) +} diff --git a/internal/key/repository/view/model/key.go b/internal/key/repository/view/model/key.go new file mode 100644 index 0000000000..8cae30b6ae --- /dev/null +++ b/internal/key/repository/view/model/key.go @@ -0,0 +1,88 @@ +package model + +import ( + "database/sql" + "encoding/json" + "time" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/key/model" + es_model "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" +) + +const ( + KeyKeyID = "id" + KeyPrivate = "private" + KeyUsage = "usage" + KeyAlgorithm = "algorithm" + KeyExpiry = "expiry" +) + +type KeyView struct { + ID string `json:"-" gorm:"column:id;primary_key"` + Private sql.NullBool `json:"-" gorm:"column:private;primary_key"` + Expiry time.Time `json:"-" gorm:"column:expiry"` + Algorithm string `json:"-" gorm:"column:algorithm"` + Usage int32 `json:"-" gorm:"column:usage"` + Key *crypto.CryptoValue `json:"-" gorm:"column:key"` + Sequence uint64 `json:"-" gorm:"column:sequence"` +} + +func KeysFromPairEvent(event *models.Event) (*KeyView, *KeyView, error) { + pair := new(es_model.KeyPair) + if err := json.Unmarshal(event.Data, pair); err != nil { + logging.Log("MODEL-s3Ga1").WithError(err).Error("could not unmarshal event data") + return nil, nil, caos_errs.ThrowInternal(nil, "MODEL-G3haa", "could not unmarshal data") + } + privateKey := &KeyView{ + ID: event.AggregateID, + Private: sql.NullBool{Bool: true, Valid: true}, + Expiry: pair.PrivateKey.Expiry, + Algorithm: pair.Algorithm, + Usage: pair.Usage, + Key: pair.PrivateKey.Key, + Sequence: pair.Sequence, + } + publicKey := &KeyView{ + ID: event.AggregateID, + Private: sql.NullBool{Bool: false, Valid: true}, + Expiry: pair.PublicKey.Expiry, + Algorithm: pair.Algorithm, + Usage: pair.Usage, + Key: pair.PublicKey.Key, + Sequence: pair.Sequence, + } + return privateKey, publicKey, nil +} + +func KeyViewsToModel(keys []*KeyView) []*model.KeyView { + converted := make([]*model.KeyView, len(keys)) + for i, key := range keys { + converted[i] = KeyViewToModel(key) + } + return converted +} + +func KeyViewToModel(key *KeyView) *model.KeyView { + return &model.KeyView{ + ID: key.ID, + Private: key.Private.Bool, + Expiry: key.Expiry, + Algorithm: key.Algorithm, + Usage: model.KeyUsage(key.Usage), + Key: key.Key, + Sequence: key.Sequence, + } +} + +func (k *KeyView) setData(event *models.Event) error { + if err := json.Unmarshal(event.Data, k); err != nil { + logging.Log("MODEL-4ag41").WithError(err).Error("could not unmarshal event data") + return caos_errs.ThrowInternal(nil, "MODEL-GFQ31", "could not unmarshal data") + } + return nil +} diff --git a/internal/key/repository/view/model/key_query.go b/internal/key/repository/view/model/key_query.go new file mode 100644 index 0000000000..68764231e5 --- /dev/null +++ b/internal/key/repository/view/model/key_query.go @@ -0,0 +1,65 @@ +package model + +import ( + key_model "github.com/caos/zitadel/internal/key/model" + global_model "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/view" +) + +type KeySearchRequest key_model.KeySearchRequest +type KeySearchQuery key_model.KeySearchQuery +type KeySearchKey key_model.KeySearchKey + +func (req KeySearchRequest) GetLimit() uint64 { + return req.Limit +} + +func (req KeySearchRequest) GetOffset() uint64 { + return req.Offset +} + +func (req KeySearchRequest) GetSortingColumn() view.ColumnKey { + if req.SortingColumn == key_model.KEYSEARCHKEY_UNSPECIFIED { + return nil + } + return KeySearchKey(req.SortingColumn) +} + +func (req KeySearchRequest) GetAsc() bool { + return req.Asc +} + +func (req KeySearchRequest) GetQueries() []view.SearchQuery { + result := make([]view.SearchQuery, len(req.Queries)) + for i, q := range req.Queries { + result[i] = KeySearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} + } + return result +} + +func (req KeySearchQuery) GetKey() view.ColumnKey { + return KeySearchKey(req.Key) +} + +func (req KeySearchQuery) GetMethod() global_model.SearchMethod { + return req.Method +} + +func (req KeySearchQuery) GetValue() interface{} { + return req.Value +} + +func (key KeySearchKey) ToColumnName() string { + switch key_model.KeySearchKey(key) { + case key_model.KEYSEARCHKEY_ID: + return KeyKeyID + case key_model.KEYSEARCHKEY_PRIVATE: + return KeyPrivate + case key_model.KEYSEARCHKEY_USAGE: + return KeyUsage + case key_model.KEYSEARCHKEY_EXPIRY: + return KeyExpiry + default: + return "" + } +} diff --git a/internal/login/config.go b/internal/login/config.go deleted file mode 100644 index 7912985764..0000000000 --- a/internal/login/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package login - -type Config struct { -} diff --git a/internal/login/handler/auth_request.go b/internal/login/handler/auth_request.go new file mode 100644 index 0000000000..885be90da0 --- /dev/null +++ b/internal/login/handler/auth_request.go @@ -0,0 +1,27 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + queryAuthRequestID = "authRequestID" +) + +func (l *Login) getAuthRequest(r *http.Request) (*model.AuthRequest, error) { + authRequestID := r.FormValue(queryAuthRequestID) + if authRequestID == "" { + return nil, nil + } + return l.authRepo.AuthRequestByID(r.Context(), authRequestID) +} + +func (l *Login) getAuthRequestAndParseData(r *http.Request, data interface{}) (*model.AuthRequest, error) { + authReq, err := l.getAuthRequest(r) + if err != nil { + return nil, err + } + err = l.parser.Parse(r, data) + return authReq, err +} diff --git a/internal/login/handler/callback_handler.go b/internal/login/handler/callback_handler.go new file mode 100644 index 0000000000..9f4b80fbcf --- /dev/null +++ b/internal/login/handler/callback_handler.go @@ -0,0 +1,11 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +func (l *Login) redirectToCallback(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + callback := l.oidcAuthCallbackURL + authReq.ID + http.Redirect(w, r, callback, http.StatusFound) +} diff --git a/internal/login/handler/change_password_handler.go b/internal/login/handler/change_password_handler.go new file mode 100644 index 0000000000..bb39181a12 --- /dev/null +++ b/internal/login/handler/change_password_handler.go @@ -0,0 +1,52 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplChangePassword = "changepassword" + tmplChangePasswordDone = "changepassworddone" +) + +type changePasswordData struct { + OldPassword string `schema:"old_password"` + NewPassword string `schema:"new_password"` +} + +func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) { + data := new(changePasswordData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.ChangePassword(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.OldPassword, data.NewPassword) + if err != nil { + l.renderChangePassword(w, r, authReq, err) + return + } + l.renderChangePasswordDone(w, r, authReq) +} + +func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Change Password", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePassword], data, nil) +} + +func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + var errType, errMessage string + data := userData{ + baseData: l.getBaseData(r, authReq, "Password Change Done", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePasswordDone], data, nil) +} diff --git a/internal/login/handler/health_handler.go b/internal/login/handler/health_handler.go new file mode 100644 index 0000000000..42ce77174f --- /dev/null +++ b/internal/login/handler/health_handler.go @@ -0,0 +1,18 @@ +package handler + +import ( + "net/http" +) + +func (l *Login) handleHealthz(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("OK")) +} + +func (l *Login) handleReadiness(w http.ResponseWriter, r *http.Request) { + err := l.authRepo.Health(r.Context()) + if err != nil { + http.Error(w, "not ready", http.StatusInternalServerError) + return + } + w.Write([]byte("OK")) +} diff --git a/internal/login/handler/init_password_handler.go b/internal/login/handler/init_password_handler.go new file mode 100644 index 0000000000..f6a61717a8 --- /dev/null +++ b/internal/login/handler/init_password_handler.go @@ -0,0 +1,97 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" + "net/http" +) + +const ( + queryInitPWCode = "code" + queryInitPWUserID = "userID" + + tmplInitPassword = "initpassword" + tmplInitPasswordDone = "initpassworddone" +) + +type initPasswordFormData struct { + Code string `schema:"code"` + Password string `schema:"password"` + PasswordConfirm string `schema:"passwordconfirm"` + UserID string `schema:"userID"` + Resend bool `schema:"resend"` +} + +type initPasswordData struct { + baseData + Code string + UserID string +} + +func (l *Login) handleInitPassword(w http.ResponseWriter, r *http.Request) { + userID := r.FormValue(queryInitPWUserID) + code := r.FormValue(queryInitPWCode) + l.renderInitPassword(w, r, nil, userID, code, nil) +} + +func (l *Login) handleInitPasswordCheck(w http.ResponseWriter, r *http.Request) { + data := new(initPasswordFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + + if data.Resend { + l.resendPasswordSet(w, r, authReq) + return + } + l.checkPWCode(w, r, authReq, data, nil) +} + +func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *initPasswordFormData, err error) { + if data.Password != data.PasswordConfirm { + err := errors.ThrowInvalidArgument(nil, "VIEW-KaGue", "passwords dont match") + l.renderInitPassword(w, r, authReq, data.UserID, data.Code, err) + return + } + userOrg := login + if authReq != nil { + userOrg = authReq.UserOrgID + } + err = l.authRepo.SetPassword(setContext(r.Context(), userOrg), data.UserID, data.Code, data.Password) + if err != nil { + l.renderInitPassword(w, r, authReq, data.UserID, "", err) + return + } + l.renderInitPasswordDone(w, r, authReq) +} + +func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + err := l.authRepo.RequestPasswordReset(r.Context(), authReq.UserName) + l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) +} + +func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if userID == "" && authReq != nil { + userID = authReq.UserID + } + data := initPasswordData{ + baseData: l.getBaseData(r, authReq, "Init Password", errType, errMessage), + UserID: userID, + Code: code, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPassword], data, nil) +} + +func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + data := userData{ + baseData: l.getBaseData(r, authReq, "Password Init Done", "", ""), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPasswordDone], data, nil) +} diff --git a/internal/login/handler/init_user_handler.go b/internal/login/handler/init_user_handler.go new file mode 100644 index 0000000000..b6d89f281a --- /dev/null +++ b/internal/login/handler/init_user_handler.go @@ -0,0 +1,105 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + caos_errs "github.com/caos/zitadel/internal/errors" + "net/http" +) + +const ( + queryInitUserCode = "code" + queryInitUserUserID = "userID" + + tmplInitUser = "inituser" + tmplInitUserDone = "inituserdone" +) + +type initUserFormData struct { + Code string `schema:"code"` + Password string `schema:"password"` + PasswordConfirm string `schema:"passwordconfirm"` + UserID string `schema:"userID"` + Resend bool `schema:"resend"` +} + +type initUserData struct { + baseData + Code string + UserID string +} + +func (l *Login) handleInitUser(w http.ResponseWriter, r *http.Request) { + userID := r.FormValue(queryInitUserUserID) + code := r.FormValue(queryInitUserCode) + l.renderInitUser(w, r, nil, userID, code, nil) +} + +func (l *Login) handleInitUserCheck(w http.ResponseWriter, r *http.Request) { + data := new(initUserFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, nil, err) + return + } + + if data.Resend { + l.resendUserInit(w, r, authReq, data.UserID) + return + } + l.checkUserInitCode(w, r, authReq, data, nil) +} + +func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *initUserFormData, err error) { + if data.Password != data.PasswordConfirm { + err := caos_errs.ThrowInvalidArgument(nil, "VIEW-fsdfd", "passwords dont match") + l.renderInitUser(w, r, nil, data.UserID, data.Code, err) + return + } + userOrgID := login + if authReq != nil { + userOrgID = authReq.UserOrgID + } + err = l.authRepo.VerifyInitCode(setContext(r.Context(), userOrgID), data.UserID, data.Code, data.Password) + if err != nil { + l.renderInitUser(w, r, nil, data.UserID, "", err) + return + } + l.renderInitUserDone(w, r, nil) +} + +func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID string) { + userOrgID := login + if authReq != nil { + userOrgID = authReq.UserOrgID + } + err := l.authRepo.ResendInitVerificationMail(setContext(r.Context(), userOrgID), userID) + l.renderInitUser(w, r, authReq, userID, "", err) +} + +func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if authReq != nil { + userID = authReq.UserID + } + data := initUserData{ + baseData: l.getBaseData(r, nil, "Init User", errType, errMessage), + UserID: userID, + Code: code, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUser], data, nil) +} + +func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + var errType, errMessage, userName string + if authReq != nil { + userName = authReq.UserName + } + data := userData{ + baseData: l.getBaseData(r, authReq, "User Init Done", errType, errMessage), + UserName: userName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUserDone], data, nil) +} diff --git a/internal/login/handler/login.go b/internal/login/handler/login.go new file mode 100644 index 0000000000..4144adb490 --- /dev/null +++ b/internal/login/handler/login.go @@ -0,0 +1,92 @@ +package handler + +import ( + "context" + "net" + "net/http" + + "github.com/caos/logging" + "github.com/gorilla/mux" + "github.com/rakyll/statik/fs" + "golang.org/x/text/language" + + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing" + "github.com/caos/zitadel/internal/form" + + _ "github.com/caos/zitadel/internal/login/statik" +) + +type Login struct { + endpoint string + router *mux.Router + renderer *Renderer + parser *form.Parser + authRepo *eventsourcing.EsRepository + zitadelURL string + oidcAuthCallbackURL string +} + +type Config struct { + Port string + OidcAuthCallbackURL string + ZitadelURL string + LanguageCookieName string + DefaultLanguage language.Tag +} + +const ( + login = "LOGIN" +) + +func StartLogin(ctx context.Context, config Config, authRepo *eventsourcing.EsRepository) { + login := &Login{ + endpoint: config.Port, + oidcAuthCallbackURL: config.OidcAuthCallbackURL, + zitadelURL: config.ZitadelURL, + authRepo: authRepo, + } + statikFS, err := fs.NewWithNamespace("login") + logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start listener") + + login.router = CreateRouter(login, statikFS) + login.renderer = CreateRenderer(statikFS, config.LanguageCookieName, config.DefaultLanguage) + login.parser = form.NewParser() + login.Listen(ctx) +} + +func (l *Login) Listen(ctx context.Context) { + if l.endpoint == "" { + l.endpoint = ":80" + } else { + l.endpoint = ":" + l.endpoint + } + + defer logging.LogWithFields("APP-xUZof", "port", l.endpoint).Info("html is listening") + httpListener, err := net.Listen("tcp", l.endpoint) + logging.Log("CONFI-W5q2O").OnError(err).Panic("unable to start listener") + + httpServer := &http.Server{ + Handler: l.router, + } + + go func() { + <-ctx.Done() + if err = httpServer.Shutdown(ctx); err != nil { + logging.Log("APP-mJKTv").WithError(err) + } + }() + + go func() { + err := httpServer.Serve(httpListener) + logging.Log("APP-oSklt").OnError(err).Panic("unable to start listener") + }() +} + +func setContext(ctx context.Context, resourceOwner string) context.Context { + data := auth.CtxData{ + UserID: login, + OrgID: resourceOwner, + } + return auth.SetCtxData(ctx, data) +} diff --git a/internal/login/handler/login_handler.go b/internal/login/handler/login_handler.go new file mode 100644 index 0000000000..e009426383 --- /dev/null +++ b/internal/login/handler/login_handler.go @@ -0,0 +1,63 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplLogin = "login" +) + +type loginData struct { + UserName string `schema:"username"` +} + +func (l *Login) handleLogin(w http.ResponseWriter, r *http.Request) { + authReq, err := l.getAuthRequest(r) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + if authReq == nil { + http.Redirect(w, r, l.zitadelURL, http.StatusFound) + return + } + l.renderNextStep(w, r, authReq) +} + +func (l *Login) handleUsername(w http.ResponseWriter, r *http.Request) { + authSession, err := l.getAuthRequest(r) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + l.renderLogin(w, r, authSession, nil) +} + +func (l *Login) handleUsernameCheck(w http.ResponseWriter, r *http.Request) { + data := new(loginData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.CheckUsername(r.Context(), authReq.ID, data.UserName) + if err != nil { + l.renderLogin(w, r, authReq, err) + return + } + l.renderNextStep(w, r, authReq) +} + +func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Login", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogin], data, nil) +} diff --git a/internal/login/handler/logout_handler.go b/internal/login/handler/logout_handler.go new file mode 100644 index 0000000000..19cb8c94dd --- /dev/null +++ b/internal/login/handler/logout_handler.go @@ -0,0 +1,20 @@ +package handler + +import ( + "net/http" +) + +const ( + tmplLogoutDone = "logoutdone" +) + +func (l *Login) handleLogoutDone(w http.ResponseWriter, r *http.Request) { + l.renderLogoutDone(w, r) +} + +func (l *Login) renderLogoutDone(w http.ResponseWriter, r *http.Request) { + data := userData{ + baseData: l.getBaseData(r, nil, "Logout Done", "", ""), + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogoutDone], data, nil) +} diff --git a/internal/login/handler/mail_verify_handler.go b/internal/login/handler/mail_verify_handler.go new file mode 100644 index 0000000000..ba99a56e50 --- /dev/null +++ b/internal/login/handler/mail_verify_handler.go @@ -0,0 +1,90 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + queryCode = "code" + queryUserID = "userID" + + tmplMailVerification = "mail_verification" + tmplMailVerified = "mail_verified" +) + +type mailVerificationFormData struct { + Code string `schema:"code"` + UserID string `schema:"userID"` + Resend bool `schema:"resend"` +} + +type mailVerificationData struct { + baseData + UserID string +} + +func (l *Login) handleMailVerification(w http.ResponseWriter, r *http.Request) { + userID := r.FormValue(queryUserID) + code := r.FormValue(queryCode) + if code != "" { + l.checkMailCode(w, r, nil, userID, code) + return + } + l.renderMailVerification(w, r, nil, userID, nil) +} + +func (l *Login) handleMailVerificationCheck(w http.ResponseWriter, r *http.Request) { + data := new(mailVerificationFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + if !data.Resend { + l.checkMailCode(w, r, authReq, data.UserID, data.Code) + return + } + userOrg := login + if authReq != nil { + userOrg = authReq.UserOrgID + } + err = l.authRepo.ResendEmailVerificationMail(setContext(r.Context(), userOrg), data.UserID) + l.renderMailVerification(w, r, authReq, data.UserID, err) +} + +func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string) { + userOrg := login + if authReq != nil { + userID = authReq.UserID + userOrg = authReq.UserOrgID + } + err := l.authRepo.VerifyEmail(setContext(r.Context(), userOrg), userID, code) + if err != nil { + l.renderMailVerification(w, r, authReq, userID, err) + return + } + l.renderMailVerified(w, r, authReq) +} + +func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID string, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if userID == "" { + userID = authReq.UserID + } + data := mailVerificationData{ + baseData: l.getBaseData(r, authReq, "Mail Verification", errType, errMessage), + UserID: userID, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerification], data, nil) +} + +func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + data := mailVerificationData{ + baseData: l.getBaseData(r, authReq, "Mail Verified", "", ""), + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerified], data, nil) +} diff --git a/internal/login/handler/mfa_init_done_handler.go b/internal/login/handler/mfa_init_done_handler.go new file mode 100644 index 0000000000..b88d7838e4 --- /dev/null +++ b/internal/login/handler/mfa_init_done_handler.go @@ -0,0 +1,20 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplMfaInitDone = "mfainitdone" +) + +type mfaInitDoneData struct { +} + +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.UserName = authReq.UserName + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaInitDone], data, nil) +} diff --git a/internal/login/handler/mfa_init_verify_handler.go b/internal/login/handler/mfa_init_verify_handler.go new file mode 100644 index 0000000000..53a9fea609 --- /dev/null +++ b/internal/login/handler/mfa_init_verify_handler.go @@ -0,0 +1,95 @@ +package handler + +import ( + "bytes" + "net/http" + + "github.com/aaronarduino/goqrsvg" + svg "github.com/ajstarks/svgo" + "github.com/boombuler/barcode/qr" + "github.com/caos/zitadel/internal/auth_request/model" +) + +const ( + tmplMfaInitVerify = "mfainitverify" +) + +type mfaInitVerifyData struct { + 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) { + data := new(mfaInitVerifyData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + var verifyData *mfaVerifyData + switch data.MfaType { + case model.MfaTypeOTP: + verifyData = l.handleOtpVerify(w, r, authReq, data) + } + + if verifyData != nil { + l.renderMfaInitVerify(w, r, authReq, verifyData, err) + return + } + + done := &mfaDoneData{ + MfaType: data.MfaType, + } + 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) + if err == nil { + return nil + } + mfadata := &mfaVerifyData{ + MfaType: data.MfaType, + otpData: otpData{ + Secret: data.Secret, + Url: data.URL, + }, + } + + return mfadata +} + +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 = err.Error() + } + data.baseData = l.getBaseData(r, authReq, "Mfa Init Verify", errType, errMessage) + data.UserName = authReq.UserName + 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) +} + +func generateQrCode(url string) (string, error) { + var b bytes.Buffer + s := svg.New(&b) + + qrCode, err := qr.Encode(url, qr.M, qr.Auto) + if err != nil { + return "", err + } + qs := goqrsvg.NewQrSVG(qrCode, 5) + qs.StartQrSVG(s) + qs.WriteQrSVG(s) + + s.End() + return string(b.Bytes()), nil +} diff --git a/internal/login/handler/mfa_prompt_handler.go b/internal/login/handler/mfa_prompt_handler.go new file mode 100644 index 0000000000..863bea60e3 --- /dev/null +++ b/internal/login/handler/mfa_prompt_handler.go @@ -0,0 +1,88 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + caos_errs "github.com/caos/zitadel/internal/errors" + "net/http" +) + +const ( + tmplMfaPrompt = "mfaprompt" +) + +type mfaPromptData struct { + MfaProvider model.MfaType `schema:"provider"` + Skip bool `schema:"skip"` +} + +func (l *Login) handleMfaPrompt(w http.ResponseWriter, r *http.Request) { + data := new(mfaPromptData) + authSession, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + if !data.Skip { + mfaVerifyData := new(mfaVerifyData) + mfaVerifyData.MfaType = data.MfaProvider + l.handleMfaCreation(w, r, authSession, mfaVerifyData) + return + } + err = l.authRepo.SkipMfaInit(setContext(r.Context(), authSession.UserOrgID), authSession.UserID) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + l.handleLogin(w, r) +} + +func (l *Login) renderMfaPrompt(w http.ResponseWriter, r *http.Request, authSession *model.AuthRequest, mfaPromptData *model.MfaPromptStep, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := mfaData{ + baseData: l.getBaseData(r, authSession, "Mfa Prompt", errType, errMessage), + UserName: authSession.UserName, + } + + if mfaPromptData == nil { + l.renderError(w, r, authSession, caos_errs.ThrowPreconditionFailed(nil, "APP-XU0tj", "No available mfa providers")) + return + } + + data.MfaProviders = mfaPromptData.MfaProviders + data.MfaRequired = mfaPromptData.Required + + if len(mfaPromptData.MfaProviders) == 1 && mfaPromptData.Required { + data := &mfaVerifyData{ + MfaType: mfaPromptData.MfaProviders[0], + } + l.handleMfaCreation(w, r, authSession, data) + return + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaPrompt], data, nil) +} + +func (l *Login) handleMfaCreation(w http.ResponseWriter, r *http.Request, authSession *model.AuthRequest, data *mfaVerifyData) { + switch data.MfaType { + case model.MfaTypeOTP: + l.handleOtpCreation(w, r, authSession, data) + return + } + l.renderError(w, r, authSession, caos_errs.ThrowPreconditionFailed(nil, "APP-Or3HO", "No available mfa providers")) +} + +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 + } + + data.otpData = otpData{ + Secret: otp.SecretString, + Url: otp.Url, + } + l.renderMfaInitVerify(w, r, authReq, data, nil) +} diff --git a/internal/login/handler/mfa_verify_handler.go b/internal/login/handler/mfa_verify_handler.go new file mode 100644 index 0000000000..dbe8008b2e --- /dev/null +++ b/internal/login/handler/mfa_verify_handler.go @@ -0,0 +1,49 @@ +package handler + +import ( + "net/http" + + "github.com/caos/zitadel/internal/auth_request/model" +) + +const ( + tmplMfaVerify = "mfaverify" +) + +type mfaVerifyFormData struct { + MfaType model.MfaType `schema:"mfaType"` + Code string `schema:"code"` +} + +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 { + err = l.authRepo.VerifyMfaOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Code, model.BrowserInfoFromRequest(r)) + } + if err != nil { + l.renderError(w, r, authReq, err) + return + } + l.renderNextStep(w, r, authReq) +} + +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 = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Mfa Verify", errType, errMessage), + UserName: authReq.UserName, + } + if verificationStep != nil { + data.MfaProviders = verificationStep.MfaProviders + data.SelectedMfaProvider = verificationStep.MfaProviders[0] + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaVerify], data, nil) +} diff --git a/internal/login/handler/password_handler.go b/internal/login/handler/password_handler.go new file mode 100644 index 0000000000..c06e4a5d79 --- /dev/null +++ b/internal/login/handler/password_handler.go @@ -0,0 +1,42 @@ +package handler + +import ( + "net/http" + + "github.com/caos/zitadel/internal/auth_request/model" +) + +const ( + tmplPassword = "password" +) + +type passwordData struct { + Password string `schema:"password"` +} + +func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Password", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPassword], data, nil) +} + +func (l *Login) handlePasswordCheck(w http.ResponseWriter, r *http.Request) { + data := new(passwordData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.VerifyPassword(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Password, model.BrowserInfoFromRequest(r)) + if err != nil { + l.renderPassword(w, r, authReq, err) + return + } + l.renderNextStep(w, r, authReq) +} diff --git a/internal/login/handler/password_reset_handler.go b/internal/login/handler/password_reset_handler.go new file mode 100644 index 0000000000..d9168e6a23 --- /dev/null +++ b/internal/login/handler/password_reset_handler.go @@ -0,0 +1,32 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplPasswordResetDone = "passwordresetdone" +) + +func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) { + authReq, err := l.getAuthRequest(r) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.RequestPasswordReset(setContext(r.Context(), authReq.UserOrgID), authReq.UserName) + l.renderPasswordResetDone(w, r, authReq, err) +} + +func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Password Reset Done", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordResetDone], data, nil) +} diff --git a/internal/login/handler/register_handler.go b/internal/login/handler/register_handler.go new file mode 100644 index 0000000000..b61b6106e8 --- /dev/null +++ b/internal/login/handler/register_handler.go @@ -0,0 +1,119 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + caos_errs "github.com/caos/zitadel/internal/errors" + usr_model "github.com/caos/zitadel/internal/user/model" + "golang.org/x/text/language" + "net/http" +) + +const ( + tmplRegister = "register" + + globalRO = "GlobalResourceOwner" +) + +type registerFormData struct { + Email string `schema:"email"` + Firstname string `schema:"firstname"` + Lastname string `schema:"lastname"` + Language string `schema:"language"` + Gender int32 `schema:"gender"` + Password string `schema:"password"` + Password2 string `schema:"password2"` +} + +type registerData struct { + baseData + registerFormData +} + +func (l *Login) handleRegister(w http.ResponseWriter, r *http.Request) { + data := new(registerFormData) + authRequest, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authRequest, err) + return + } + l.renderRegister(w, r, authRequest, data, nil) +} + +func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) { + data := new(registerFormData) + authRequest, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authRequest, err) + return + } + if data.Password != data.Password2 { + err := caos_errs.ThrowInvalidArgument(nil, "VIEW-KaGue", "passwords dont match") + l.renderRegister(w, r, authRequest, data, err) + return + } + iam, err := l.authRepo.GetIam(r.Context()) + if err != nil { + l.renderRegister(w, r, authRequest, data, err) + return + } + user, err := l.authRepo.Register(setContext(r.Context(), iam.GlobalOrgID), data.toUserModel(), iam.GlobalOrgID) + if err != nil { + l.renderRegister(w, r, authRequest, data, err) + return + } + if authRequest == nil { + http.Redirect(w, r, l.zitadelURL, http.StatusFound) + return + } + authRequest.UserName = user.UserName + l.renderNextStep(w, r, authRequest) +} + +func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authRequest *model.AuthRequest, formData *registerFormData, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if formData == nil { + formData = new(registerFormData) + } + if formData.Language == "" { + formData.Language = l.renderer.Lang(r).String() + } + data := registerData{ + baseData: l.getBaseData(r, authRequest, "Register", errType, errMessage), + registerFormData: *formData, + } + funcs := map[string]interface{}{ + "selectedLanguage": func(l string) bool { + if formData == nil { + return false + } + return formData.Language == l + }, + "selectedGender": func(g int32) bool { + if formData == nil { + return false + } + return formData.Gender == g + }, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplRegister], data, funcs) +} + +func (d registerFormData) toUserModel() *usr_model.User { + return &usr_model.User{ + Profile: &usr_model.Profile{ + FirstName: d.Firstname, + LastName: d.Lastname, + PreferredLanguage: language.Make(d.Language), + Gender: usr_model.Gender(d.Gender), + }, + Password: &usr_model.Password{ + SecretString: d.Password, + }, + Email: &usr_model.Email{ + EmailAddress: d.Email, + }, + } +} diff --git a/internal/login/handler/renderer.go b/internal/login/handler/renderer.go new file mode 100644 index 0000000000..c968b11b1a --- /dev/null +++ b/internal/login/handler/renderer.go @@ -0,0 +1,260 @@ +package handler + +import ( + "fmt" + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/i18n" + "github.com/caos/zitadel/internal/renderer" + "net/http" + "path" + + "github.com/caos/logging" + "golang.org/x/text/language" +) + +const ( + tmplError = "error" +) + +type Renderer struct { + *renderer.Renderer +} + +func CreateRenderer(staticDir http.FileSystem, cookieName string, defaultLanguage language.Tag) *Renderer { + r := new(Renderer) + 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", + tmplRegister: "register.html", + tmplLogoutDone: "logout_done.html", + } + funcs := map[string]interface{}{ + "resourceUrl": func(file string) string { + return path.Join(EndpointResources, file) + }, + "resourceThemeUrl": func(file, theme string) string { + return path.Join(EndpointResources, "themes", theme, file) + }, + "loginUrl": func() string { + return EndpointLogin + }, + "registerUrl": func(id string) string { + return fmt.Sprintf("%s?%s=%s", EndpointRegister, queryAuthRequestID, id) + }, + "usernameUrl": func() string { + return EndpointUsername + }, + "usernameChangeUrl": func(id string) string { + return fmt.Sprintf("%s?%s=%s", EndpointUsername, queryAuthRequestID, id) + }, + "userSelectionUrl": func() string { + return EndpointUserSelection + }, + "passwordResetUrl": func(id string) string { + return fmt.Sprintf("%s?%s=%s", EndpointPasswordReset, queryAuthRequestID, id) + }, + "passwordUrl": func() string { + return EndpointPassword + }, + "mfaVerifyUrl": func() string { + return EndpointMfaVerify + }, + "mfaPromptUrl": func() string { + return EndpointMfaPrompt + }, + "mfaInitVerifyUrl": func() string { + return EndpointMfaInitVerify + }, + "mailVerificationUrl": func() string { + return EndpointMailVerification + }, + "initPasswordUrl": func() string { + return EndpointInitPassword + }, + "initUserUrl": func() string { + return EndpointInitUser + }, + "changePasswordUrl": func() string { + return EndpointChangePassword + }, + "registrationUrl": func() string { + return EndpointRegister + }, + "selectedLanguage": func(l string) bool { + return false + }, + "selectedGender": func(g int32) bool { + return false + }, + } + var err error + r.Renderer, err = renderer.NewRenderer( + staticDir, + tmplMapping, funcs, + i18n.TranslatorConfig{DefaultLanguage: defaultLanguage, CookieName: cookieName}, + ) + logging.Log("APP-40tSoJ").OnError(err).WithError(err).Panic("error creating renderer") + return r +} + +func (l *Login) renderNextStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + authReq, err := l.authRepo.AuthRequestByID(r.Context(), authReq.ID) + if err != nil { + l.renderInternalError(w, r, authReq, errors.ThrowInternal(nil, "APP-sio0W", "could not get authreq")) + } + if len(authReq.PossibleSteps) == 0 { + l.renderInternalError(w, r, authReq, errors.ThrowInternal(nil, "APP-9sdp4", "no possible steps")) + return + } + l.chooseNextStep(w, r, authReq, 0, nil) +} + +func (l *Login) renderError(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + if authReq == nil || len(authReq.PossibleSteps) == 0 { + l.renderInternalError(w, r, authReq, errors.ThrowInternal(err, "APP-OVOiT", "no possible steps")) + return + } + l.chooseNextStep(w, r, authReq, 0, err) +} + +func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, stepNumber int, err error) { + switch step := authReq.PossibleSteps[stepNumber].(type) { + case *model.LoginStep: + if len(authReq.PossibleSteps) > 1 { + l.chooseNextStep(w, r, authReq, 1, err) + return + } + l.renderLogin(w, r, authReq, err) + case *model.SelectUserStep: + l.renderUserSelection(w, r, authReq, step) + case *model.InitPasswordStep: + 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.RedirectToCallbackStep: + if len(authReq.PossibleSteps) > 1 { + l.chooseNextStep(w, r, authReq, 1, err) + return + } + l.redirectToCallback(w, r, authReq) + case *model.ChangePasswordStep: + 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.InitUserStep: + l.renderInitUser(w, r, authReq, "", "", nil) + default: + l.renderInternalError(w, r, authReq, errors.ThrowInternal(nil, "APP-ds3QF", "step no possible")) + } +} + +func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var msg string + if err != nil { + msg = err.Error() + } + data := l.getBaseData(r, authReq, "Error", "Internal", msg) + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplError], data, nil) +} + +func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title string, errType, errMessage string) baseData { + return baseData{ + errorData: errorData{ + ErrType: errType, + ErrMessage: errMessage, + }, + Lang: l.renderer.Lang(r).String(), + Title: title, + Theme: l.getTheme(r), + ThemeMode: l.getThemeMode(r), + AuthReqID: getRequestID(authReq, r), + } +} + +func (l *Login) getTheme(r *http.Request) string { + return "zitadel" //TODO: impl +} + +func (l *Login) getThemeMode(r *http.Request) string { + return "" //TODO: impl +} + +func getRequestID(authReq *model.AuthRequest, r *http.Request) string { + if authReq != nil { + return authReq.ID + } + return r.FormValue(queryAuthRequestID) +} + +type baseData struct { + errorData + Lang string + Title string + Theme string + ThemeMode string + AuthReqID string +} + +type errorData struct { + ErrType string + ErrMessage string +} + +type userData struct { + baseData + UserName string + PasswordChecked string + MfaProviders []model.MfaType + SelectedMfaProvider model.MfaType +} + +type userSelectionData struct { + baseData + Users []model.UserSelection +} + +type mfaData struct { + baseData + UserName string + MfaProviders []model.MfaType + MfaRequired bool +} + +type mfaVerifyData struct { + baseData + UserName string + MfaType model.MfaType + otpData +} + +type mfaDoneData struct { + baseData + UserName string + MfaType model.MfaType +} + +type otpData struct { + Url string + Secret string + QrCode string +} diff --git a/internal/login/handler/resources_handler.go b/internal/login/handler/resources_handler.go new file mode 100644 index 0000000000..b06449a6da --- /dev/null +++ b/internal/login/handler/resources_handler.go @@ -0,0 +1,9 @@ +package handler + +import ( + "net/http" +) + +func (l *Login) handleResources(staticDir http.FileSystem) http.Handler { + return http.FileServer(staticDir) +} diff --git a/internal/login/handler/router.go b/internal/login/handler/router.go new file mode 100644 index 0000000000..60b0ba4eb3 --- /dev/null +++ b/internal/login/handler/router.go @@ -0,0 +1,58 @@ +package handler + +import ( + "net/http" + + "github.com/gorilla/mux" +) + +const ( + EndpointRoot = "/" + EndpointHealthz = "/healthz" + EndpointReadiness = "/ready" + EndpointLogin = "/login" + EndpointUsername = "/username" + EndpointUserSelection = "/userselection" + EndpointPassword = "/password" + EndpointInitPassword = "/password/init" + EndpointChangePassword = "/password/change" + EndpointPasswordReset = "/password/reset" + EndpointInitUser = "/user/init" + EndpointMfaVerify = "/mfa/verify" + EndpointMfaPrompt = "/mfa/prompt" + EndpointMfaInitVerify = "/mfa/init/verify" + EndpointMailVerification = "/mail/verification" + EndpointMailVerified = "/mail/verified" + EndpointRegister = "/register" + EndpointLogoutDone = "/logout/done" + + EndpointResources = "/resources" +) + +func CreateRouter(login *Login, staticDir http.FileSystem) *mux.Router { + router := mux.NewRouter() + router.HandleFunc(EndpointRoot, login.handleLogin).Methods(http.MethodGet) + router.HandleFunc(EndpointHealthz, login.handleHealthz).Methods(http.MethodGet) + router.HandleFunc(EndpointReadiness, login.handleReadiness).Methods(http.MethodGet) + router.HandleFunc(EndpointLogin, login.handleLogin).Methods(http.MethodGet, http.MethodPost) + router.HandleFunc(EndpointUsername, login.handleUsername).Methods(http.MethodGet) + router.HandleFunc(EndpointUsername, login.handleUsernameCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost) + router.HandleFunc(EndpointPassword, login.handlePasswordCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet) + router.HandleFunc(EndpointInitPassword, login.handleInitPasswordCheck).Methods(http.MethodPost) + 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.handleMfaPrompt).Methods(http.MethodPost) + router.HandleFunc(EndpointMfaInitVerify, login.handleMfaInitVerify).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) + router.HandleFunc(EndpointRegister, login.handleRegister).Methods(http.MethodGet) + router.HandleFunc(EndpointRegister, login.handleRegisterCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointLogoutDone, login.handleLogoutDone).Methods(http.MethodGet) + router.PathPrefix(EndpointResources).Handler(login.handleResources(staticDir)).Methods(http.MethodGet) + return router +} diff --git a/internal/login/handler/select_user_handler.go b/internal/login/handler/select_user_handler.go new file mode 100644 index 0000000000..1676ee5ccf --- /dev/null +++ b/internal/login/handler/select_user_handler.go @@ -0,0 +1,42 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplUserSelection = "userselection" +) + +type userSelectionFormData struct { + UserID string `schema:"userID"` +} + +func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, selectionData *model.SelectUserStep) { + var errType, errMessage string + data := userSelectionData{ + baseData: l.getBaseData(r, authReq, "Select User", errType, errMessage), + Users: selectionData.Users, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplUserSelection], data, nil) +} + +func (l *Login) handleSelectUser(w http.ResponseWriter, r *http.Request) { + data := new(userSelectionFormData) + authSession, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + if data.UserID == "0" { + l.renderLogin(w, r, authSession, nil) + return + } + err = l.authRepo.SelectUser(r.Context(), authSession.ID, data.UserID) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + l.renderNextStep(w, r, authSession) +} diff --git a/internal/login/login.go b/internal/login/login.go new file mode 100644 index 0000000000..61a0a0a4ae --- /dev/null +++ b/internal/login/login.go @@ -0,0 +1,17 @@ +package login + +import ( + "context" + + "github.com/caos/zitadel/internal/auth/repository/eventsourcing" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/login/handler" +) + +type Config struct { + Handler handler.Config +} + +func Start(ctx context.Context, config Config, systemDefaults sd.SystemDefaults, authRepo *eventsourcing.EsRepository) { + handler.StartLogin(ctx, config.Handler, authRepo) +} diff --git a/internal/login/static/i18n/de.yaml b/internal/login/static/i18n/de.yaml new file mode 100644 index 0000000000..ae20d7e6a9 --- /dev/null +++ b/internal/login/static/i18n/de.yaml @@ -0,0 +1,119 @@ +Password: + Title: Passwort + Description: Gib deine Benutzerdaten ein. + Password: Passwort + +Login: + Title: Anmeldung + Description: Gib deine Benutzerdaten ein. + Username: Benutzername + +UserSelection: + Title: Account auswählen + Description: Wähle deinen Account aus. + OtherUser: Anderer Benutzer + SessionState0: aktiv + SessionState1: inaktiv + +MfaVerify: + Title: Multifaktor verifizieren + Description: Verifiziere deinen Multifaktor + OTP: OTP + Code: Code + +InitPassword: + Title: Passwort setzen + Description: Du hast einen Code erhalten, welcher im untenstehenden Formular eingegeben werden muss um ein neues Passwort zu setzen. + Code: Code + NewPassword: Neues Passwort + NewPasswordConfirm: Passwort bestätigen + +InitPasswordDone: + Title: Passwort gesetzt + Description: Passwort erfolgreich gesetzt + +InitUser: + Title: User aktivieren + Description: Du hast einen Code erhalten, welcher im untenstehenden Formular eingegeben werden muss um deine EMail zu verifizieren und ein neues Passwort zu setzen. + Code: Code + NewPassword: Neues Passwort + NewPasswordConfirm: Passwort bestätigen + +InitUserDone: + Title: User aktiviert + Description: EMail verifiziert und Passwort erfolgreich gesetzt + +MfaPrompt: + Title: Multifaktor hinzufügen + Description: Möchtest du einen Mulitfaktor hinzufügen? + Provider0: OTP + Provider1: SMS + +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. + Secret: Secret + Code: Code + +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. + +PasswordChange: + Title: Passwort ändern + Description: Ändere dein Password in dem du dein altes und dann dein neuen Passwort eingibst. + OldPassword: Altes Passwort + NewPassword: Neues Passwort + +PasswordChangeDone: + Title: Passwort ändern + Description: Das Passwort wurde erfolgreich geändert. + +PasswordResetDone: + Title: Resetlink versendet + Description: Prüfe dein E-Mail Postfach, um ein neues Passwort zu setzen. + +PasswordSetDone: + Title: Passwort gesetzt + Description: Das Passwort wurde erfolgreich gesetzt. + +EmailVerification: + Title: E-Mail Verifizierung + Description: Du hast ein E-Mail zur Verifizierung deiner E-Mail Adresse bekommen. Gib den Code im untenstehenden Formular ein. Mit erneut versenden, wird dir ein neues E-Mail zugestellt. + Code: Code + +EmailVerificationDone: + Title: E-Mail Verifizierung + Description: Deine E-Mail Adresse wurde erfolgreich verifiziert. + +Registration: + Title: Registration + Description: Gib deine Benutzerangaben an. Die E-Mail Adresse wird als Benutzernamen verwendet. + Email: E-Mail + Firstname: Vorname + Lastname: Nachname + Language: Sprache + German: Deutsch + English: English + Gender: Geschlecht + Female: weiblich + Male: männlich + Diverse: diverse + Password: Passwort + Password2: Passwort wiederholen + +LogoutDone: + Title: Ausgeloggt + Description: Du wurdest erfolgreich ausgeloggt. + +Actions: + Login: anmelden + Next: weiter + Back: zurück + Resend: erneut senden + Skip: überspringen + Register: registrieren + ForgotPassword: Password zurücksetzen + +optional: (optional) diff --git a/internal/login/static/i18n/en.yaml b/internal/login/static/i18n/en.yaml new file mode 100644 index 0000000000..417dae0636 --- /dev/null +++ b/internal/login/static/i18n/en.yaml @@ -0,0 +1,119 @@ +Login: + Title: Login + Description: Enter your logindata. + Username: Username + +UserSelection: + Title: Select account + Description: Select your account. + OtherUser: Other User + SessionState0: active + SessionState1: inactive + +Password: + Title: Password + Description: Enter your logindata. + Password: Password + +MfaVerify: + Title: Verify Multificator + Description: Verify your multifactor + OTP: OTP + Code: Code + +InitPassword: + Title: Set Password + Description: You have received a code, which you have to enter in the form below, to set your new password. + Code: Code + NewPassword: New Password + NewPasswordConfirm: Confirm Password + +InitPasswordDone: + Title: Passwortd set + Description: Password successfully set + +InitUser: + Title: Activate User + Description: You have received a code, which you have to enter in the form below, to verify your email and set your new password. + Code: Code + NewPassword: New Password + NewPasswordConfirm: Confirm Password + +InitUserDone: + Title: User activated + Description: Email verified and Password successfully set + +MfaPrompt: + Title: Multifactor Setup + Description: Would you like to setup multifactor authentication? + Provider0: OTP + Provider1: SMS + +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. + Secret: Secret + Code: Code + +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. + +PasswordChange: + Title: Change Password + Description: Change your password. Enter your old and new password. + OldPassword: Old Password + NewPassword: New Password + +PasswordChangeDone: + Title: Change Password + Description: Your password was changed successfully. + +PasswordResetDone: + Title: Reset link set + Description: Check your email to to reset your password. + +PasswordSetDone: + Title: Password set + Description: Your password was set successfully. + +EmailVerification: + Title: E-Mail Verification + Description: We have sent you an email to verify your address. Please enter the code in the form below. + Code: Code + +EmailVerificationDone: + Title: E-Mail Verification + Description: Your email address has been successfully verified. + +Registration: + Title: Registration + Description: Enter your Userdata. Your email address will be used as username. + Email: E-Mail + Firstname: Firstname + Lastname: Lastname + Language: Language + German: Deutsch + English: English + Gender: Gender + Female: Female + Male: Male + Diverse: diverse / X + Password: Password + Password2: Password confirmation + +LogoutDone: + Title: Logged out + Description: You have logged out successfully. + +Actions: + Login: login + Next: next + Back: back + Resend: resend + Skip: skip + Register: register + ForgotPassword: Reset password + +optional: (optional) diff --git a/internal/login/static/resources/fonts/ailerons/ailerons.otf b/internal/login/static/resources/fonts/ailerons/ailerons.otf new file mode 100644 index 0000000000000000000000000000000000000000..8a18b632c655a55fb5e9aed5da5110a6bb30a31f GIT binary patch literal 10676 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%0Ajp=!UCwJi3SXpBgoJ@I{DYaNvAZ_8L+h7?+ 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

G9&_q3@_awm3 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 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/lato/Lato-Bold.ttf b/internal/login/static/resources/fonts/lato/Lato-Bold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..b63a14d6aeec11bce432820914e73db28e489634 GIT binary patch literal 73316 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 M$8RP7dXDOU1KQ%3=>Px# literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/lato/Lato-BoldItalic.ttf b/internal/login/static/resources/fonts/lato/Lato-BoldItalic.ttf new file mode 100755 index 0000000000000000000000000000000000000000..8f9a50d135d1481a483bc8bf78f4b359a7ec5db7 GIT binary patch literal 77680 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 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/lato/Lato-Italic.ttf b/internal/login/static/resources/fonts/lato/Lato-Italic.ttf new file mode 100755 index 0000000000000000000000000000000000000000..49e9f2c3e371b71e2e7d58d03ed5d705e5f13ffc GIT binary patch literal 75744 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�PCR?BHn>0C`UfbHw_YIxBH(D-!weI>6 zy4FN`wzz1jEp~7q`)-rEnp*-sW?1|m$M_8=t?^wJr%8Tm@lR79U-xL6bWL?FE<34M zc6aN!nbCaJc;5yz z)G-rlL$8Jx8T-`v^DpE?iT`{QeDf&hKl#D~IPJo2&$s8f9N<4WW+QTb)EHTam>%>P zSYu#6(6@*KQQ`(T5RWXWdnZCbQy|NnrMVLj2`rUL8FKK=D9DIok-DXDH+qo&9gHKL zH)KJU0%9KZ>g_AI(BiM(-Sf<)@uAzlb@aO-T<%mq^j*4r<>q6WLCl{BPWFW!xEo?8iAZXN0uMJ)?J z{*r>Km9!#k66L%LutvI(SdD_xF$ro8FK!d%`VbLQ)0|Cc;q3w%lPW=Id_h~&DJ${0 z>Qi}*7C|U1K&Gk8NO-bJGI`O8*ndL0EnHXFm&2Q)F+o422S4(L;I8=BkyFC+N+^pf z`))GijnKAsHBAr6_{tfFILfoWLlXaW^6Ifj&AhRBHPPg7GTO22*vRCqwK0R&ZZE1z z#wz;j{nfo=z16it6GOG`s=zg9s zn(}D-vaY4Ktf}vdcbhH#B0r@_#5$|X8U~s=mi4tHN1F;-V}YK1r~%g+FTdx_qJ9)_TM`u(@F-XCBfjr9BH<@+<`f5eJ1@4q15n0fz;toL7$ zPh{S2&w77G{>=%{@>;J#%-UPnN;%fY#=Wf~e4YJ;wkPWht zgd~Ij2_a-5Agi(nBQ!726qh23MPFlEi%TugitAgg zwtcHY^8227?!CDQ!R7b9pa19gC!G6iGiT1sIdf*_%*+{UNp;qF=dv1g=DBmvn>+EG z#)jIOs!Dc^6y#(%*)|Xr5gerIjrvHbk_OoSP)Pg zX2=nZI5~u|5up}ycTW)8g4y2_f-xT15nnpCXqz^NCj4*Vi!<>_?V0j_OCS2gOCBBf zkPzR4%_%*1X=Pe}G;Sl5lLgfPPu9_A{!eF5D3pYLMnbc`FQEt{G(b%I85(;)px&_L zU-HTlBAvJl6=Ji|HRS5ej9guk8<`H7{e6irb?Qwg3k!TeU=YnEl%o>b=i4^s)z zr}SbJ@wMS0A*RBR3z?~2)OQNO7ETf`?mHjs)MMA8seU+c9HB+0{Xj|~Voc*-w|cS! zoZ$eM^Ss#}q&G~`{0}MZu>@7l2Qk;4N(Z1^yX4X9du+3+7LFZQe(k4^8|#-17B9JJ zkvNFfUUHY*o$Z`H|AN8S+*Ezjr@QFK7(1$_jx36gX7$N=k1bxdKE7&q=d~9`NRn=Q>V;6{k}c3YGQFiot(&Qe4RgKZ9~9-lIj6NML6ZIH9i* z`X#}&OK+U=J-*UQ8uAmYRXxY&+Sj&jV;ju2SDn&rsl30!@BLc!C*S*vblYo&f6wpz zRl1Ee-(TQ)Kb#)!O&ZUu;CHCnFQo;?)@fPe_jYZEyrmVl%+|Qgus`-l~%w#U;hVhZWbA)D6mYrRjAnB2WX%^JRl~>foY&(NW>7%431H z>~xWN0K8F(Y0@*&k)?^>ADA?0D7s^5)3doWQARW)8NbL1gpqKU&3t;jy71Xzih;RX zM*IZ9C#{4?P5p&VR*<-f8dgY{T3o7b1{(4F4 zT}77W<^!&p71KsU24z)E9XfX1q(SM!C);xELH3xS+5Ix3LQ=zG$|I{wHVh34jSQbW zCmOy=PY~irl~W}-}-Xhwo})ZEZey@Z{o%4kHLKbqLE@L#$PQ=rhC}J{<3zC4|sn zrgGveA%5-)ae+64MN>-8ZIyb#R%5%2yEx`EYO2HKGzIM~749((uO0+hEPC_K1W7la zhOJKz3+Bl)0j{322U*r0ONz6uvL1*$HOkl?pH-aPFFPeNA*(oP@UUtAk406MV^GrlWQgpr0}ntGoy~^P7r+5KiM{ed$ovF04#>|K}+#6;Lh_6hky*g)*cyru1Gd;%X zoUtjJrvsfYB^vuG#y72>KKOX!rPBw8g?5f94<9}_wf~btZk#6m9jgnH<983a{yg#V zXgn}|lx0SK^EFR&t{QjE6N~c3I!`~8Cv{SLn9?QyIuhY+s*fsh*D@UiRoz9sq&izly@kGQ>!!#4)1KCu_Q7qIs zF|V2j&{R16kKv{alu(Hn0iCMU%l=El)U6$u{OX=gWNP)@Y3%oq`XjMzs zi=7YK4q=PRRz=1m(x1)E8IW$;!)aIX1Fo`-Y~7!gMWIFc?6?%mg^Ye_ZUfP`6q!9F zjpOAoNu>qI6cyhG@Dpk1nLlB2xhGzLh0_i=evFQAao-3SEp|s284-(4>Gwxxd?}G+ z&e=1;td3Vv~wJeepV2Q({dj|hgqzBB9wjVdKhLGXB+fG>6nz2i;2i8 zE*v;Fki*OL7C#wg87_|(FWdcL*67sfMa`4W9fhN8`}os)?+?mMxW)4PbH<$bxcsbs zInKD0*pO528=qZ`F)chL?CsF%gp@IrBbVp)k2Pk?jHmsMZx@BS29~5avjc(xEuUB> zCXUL=s^usv@qhZT_J3Nc##lyHCzcK2K$5B#vMXHLo z{3HX~`gw+Eo6eZ@8AW<8v-T%z^%HREa5L{fJC427I>IaE{RUR1$AtHBfZHXJ-NN2k z+v_klkH|ZRR}78~NQ*u5WVgI-@i)%zeaaj9c7E5FwtqYRNfxE~5bOW5dSoT%fUVGN z?HEs6`&$ab*AJ&3*NPslK@VpdZ_567=9k2CC`&k^^t1rAC)3E(J3K}1he~~6%?@*c zrY8Ul_S37_y}~*C z?0A9{DTrX6g|u#&9M&6&wcBflk1QWL=0-ia^Q>-`g>H2}28DS1Q4$-Yo@5^h^yWz@ z6=glv#Di(qVhJ4BT|9kJ6aWjq2b0sQt5H&Z-Wh&-w@8W}9)=#4^R;T2Rk^)7v38W9Mop-l zFruocAUC^z0>1U^s>Z1C>EV&}_(m?K_d~`NbC!0NR^yU3i1mv;RSXA36Pvxao{CuH zNd)qzp`kB#CK^$mWBjObbW#6hFzI40>BooE#YUPflJ-;)IB4avn+aoVip*LG`%TC#~)pK#R6s*2k` zulrjoLlw`VVwOg)xHJx(x@Asr_d#N395y!YmML+A1|*oRyWRhkF^?!!F3d5iF4#WH zcd}UK8HbNem=zW3$}LXT&Ax5=87Gfn@iDgIztO7BtM21O4R(&0+wNFa?mJP#_maio zZ2vp^`KYGNnF&aJyp4I94f-;fVf9_;%P4g@C&5O_rZL~%!sHMtF02qYmKO9O{|6lMI+kuJ|TWi3%b6tpQN2-yrZTXpI18@>SfGR zKeb`%2tDp8D##jO&LPXVC)8`(D{C(1xOAC9rhA5dVhJUOS%n08ri<+|evVBGrk^aP zY(_s;YqaTiMtiOK>9O%NF6(b)dvk5yv014IUk7-SW*p)7)PoREi6BeUdd^Qrh5GX5 zC@w9S(Vg$fs^w3*am{B#8zAdmGc<`}Jdn25(1XSdFj?hbLAmjwl&kdS#`TE~feT?% zlwcHdPk_a?Kz@$NkUW1{JzE~18=SHJ?k?9OuzIr-QxCAhTuIX1eotMEsJ7g z)YAdoEx7GS&Elr)go^X8KXBP47wWS?(;{Oc@`_s*uB>L(v+j*6Ca#~DJN4%0moEKT z#>joA8z*j@I%rnw_zlwvV+)$B4Z{{rs0h9J>BU(w*~4wt^pVqs#==u;$6tToqE%a(uRC~2;kl!7tf2+dFP|7)Qd#5bH_#O$ zT0N98j7@8GSuw#FMs?~jjGQ5np~o<+%QPHn?d5(t-Hd1bK(D|wx89_8G_9mpdM{*LCy5mbq@Q4qAN>41#QpTq{OI*CMWpy))(lo7o zM)ocYqzYw}m$4$LTpz!RkqU>yDv6KYLMEu7joGDfa+M2Nt*fpq6YEk>E2H0h;~ zuIb~Q9Loq+=#$e#cyH1t-u=@!LqqQ<%(&>{kQn>?u$Zd?;zL$_akqVYpyP^|m@6EC zo!?SFJYIefzKakvL)~P%-f{~R_EYP{gFtKyC({M8pQN9jc@+ta#(M(AMc7QnjF>ol zJ_+#?Y7#<^R)or&h4lm$CtB$WO^-U-R4OYcy%_~Mx0yL z&tkd6S~@DbEF;#oJ|L@Zk?nd{<+%K?r0}?yl936yLtSO9je`*97~6A}Nc%o^#3y(A zTfjNBNV*IKXo-x=C`e4qPvw{%T*ojX1g+v2sCzXOlhor?_-EnMCodJWe}%Ohgt~%B2|06Ym_) zILjMyavLk0&Wgs|oQ87e{IbIQ^78z`GJD3r(Zxwg#iIx2jxI_{DjJ=eS5c9dUr_6gMC zm?9=g&vF9ZNffa}%N0Q$>s|>ucEH(XWpuGG61|CD9@o8bC>+kaHG_No4fcp;di?Vy zMd3@XO80nM|w$3rmHkR$DTW_ za9nvBM~CO<6^yTt8s#y` z=Vdyt=|(|8V;qydLthBI=PQ{9NHDaQX(H*YvP4e~TNO9o))L!oftK{d4a*)`+IiQNdx>RO`Ppn=Xx zo>-O~=;){2RNY`b&N`<*n|Lu5;FCnw|2P6X@Znlo%@oaZyM&V*8(aBCe>; z0C7M7h^aE2e=}_Ab3eSCzt;0awIo=zBw6^u z0^0rKOKf0I+Wd;rqHePuw>+UsQq$HSyRCS5={wh%eZMv?>0KJew%%{fUhKW7^W%r5 z>wWm~o#ux>b!XwpS*UxyHz~$-z2BUbd1t51PhMe~3yJ-s@o8&g z0+l|8G|vNA?TjvCMjjiPA?IhCzU@VsYke1Q4hlqX`G-XnvAwK!1oM2dcEYCn;gzu9 z1GSA>&Jc)rW(Pr5I~Vwcgccmsn87t28A1nfXmXiC$9jrYVy{({VkwK`eS}L#R#QaJ zofueL&Dhdy!ro*?*872nn9;P4Xb|*{#-b^jW3-}7*<<~s(@CN}7iS#XR3aWZ%h*Hi zS)GwgBNX5YF=y4YlML6dY>2t0} zoAr^DLi!lS@8jb;^Q@u4LAi;BEi5sibM&ciL->bn;#unYDERjs{2OY#TOB{NqMSaP zcw3i^hbABOjEwNH(p!qTE>3*SNw;7NWj5Ltz^IEwD&$C*C00t%O4}>kbvWW3+Rh`~ z?GuCexgYZVXiQ6y@Vufg8Z-vdBWaWSy|J0?s7S)-KI3bd5HflpF?W1}O|r+%9CmBd z@-fG6%Ewr*eE1iLIph&!G=CmR@en4KVOjNuy}mb2Y(kSwY(WZa0fC<4^}~jvLM#0t z5gb-&i_p-p2AaFc*==Aqox+-=%D!?a_09D4Ayl*yF6IVkav3jrT3*gYp#jE+9BZHUZA>X`L)>#OtuIjhOziEgZ0cB6zNSt3)^HJnv4D`TG3 zq-&vkqN6VtmsPA_y&cqjRJmYt^SG@Gh7DV=bzJl21(lY`-luU}<_{Y-e+v~jzw7Vz zJTz6^fo@t7F(d1|J2xAhQ z#NtrtQA<|XPltbPsYftaoKkRSrsm0>=X5hUkkUIVCw*_+rGM{pe(zI-ES59gSYup_ zE(>IIDOXp_a_>V@etL`!?)i9@XQmitbbS%fWq&}Ip{$Uet}awp81Gf5UbbO%+XahT zW{Y>|QPmY?gA4NpddoK4J2GYTjR8$mM^=at5NfcsMcYA5H*eBSk4g(OOd~wTU+wup z?8h<%Qt>0=vZfuEW*b&B*CCd^ta^=vteM`N18z};MO?PNRj~+q&P)K~l zu$@q^q|vh68US_vcwrr@WnB@sRYjoyjGx!is@Uk>(Zlym)Uyw0FQe!i~IHoMkcJaI&7nJ9Y zTQO$dol7fn$FFQCZYYRPZ(22Ra9w_!tNtQmYDm<#*MvnFH_W?p2?3WAaG4pfz925W zscqumF$8RAoAd+U;S3(>jZduiU?F6TV2PG7!kOOaulaGV=4H%-&qCu}FTQA|Ec^6V z*xNbbS$q*Ps%0+JIuH9>kQ!C(5Z`XT*mj(l?2VkrkkZ z(%M5T1I>7Yww9taWa`RX35ipgKvn~ax9c#m3yWqAH5@3HAa-R)?bL=Ah^Jx);(wlI zBse%a*tbff>FhY6k)~ZV^jWd{FvbPz$tkJclmBNJgT;+lhL2Vu89#H?^L`9gSP>>i z;gN6J8Bc!=pIrf=A@a_lyrmM@S1Pj0PMTJ%=5lb9wv-oeHU|qobQi)U9aMSiO4Zxw z#m=j{t9Y);C@*0h=#(2=>wfj}%4;4URvQ`~9uk|BRn}B8ZtIFEiIyUVHKqUQZyn4x zz8fHCcg+uY@a9P?8VjNWLmV}eKe+Lt-D^i!Zw}pJ4ZYfW#pOqCY@T=CsL;UZBxh1| z>B3uE%A=Ap8nViwl8^i`zbxMtIC{ZFlWu)$)4V38`z`7oYoomkxlO^e_Sfousi~=% zshI;Z(m7u$i9T*jB#wvzbstycs5Cw<95aSp%-weJN{lJQ+|CdbC=1zG#tY-6y&m9s zVd&niaJS@)xHbuI^X?ftch6k}$>>@wp?O5sR2$lCT`G z!Tvl;pdLBU%f-qfe3P1Pc7MP|cTX(GvZ2vD{S~81xs|g}aqb_-y|6A@`wGq|x4sl; zbA$yx7Zeq_uzqPlg!KzEO2QqdA2-_S zJ0DF-GA1>2-e?)m7P1AM3C1T2pa9)qufcvd+=#*oub9!Q8j3FpXIj7b&|sg}fB~*J z=?XD30QnFtQ%SU$x_Q;!qCNI5(I4sFu;h~ZtSg#dNWB(jtXq2Yd3}Y%rbj2+AGxGL zaeI31`F%xV_Q=p~C%y5c^Q~i5mz)t^<{BgoY-B|9blY@RJh8+?D(rB@$YxSJn|S70 z6Ri026w^i-XLj{mVkI+AR3yu9hD`a{lByxCTP7{|^`?e_%@Eef0&e%4mXw;@>*N?kodS!U$IVlMd znUT@4d*Y|8{rQyEM{Zd?aZvNt=T^2IymMLq$6J$}7<5%l*Vncb`$L>5(4gL_j%7#L z@Y04M4bo3@rp83!flGR6Qa{R>C{gLCQ}k^2=`XwAis6zAbWMC6jtVmGL;F zmySqQw%>+1cq0CTf0f-dZc0((>WO(aTmR(`{OQ_;byEr~mhd?@?_D(eigbGrHt7ZD zXV;eJhJ{20CRAQDf2z~gub^?r*h|l^46$%b_0Xh&$>9~t?wXe}()C*BqhD_+oOaoS zsEp`Uul?fONfXnDC!`Hc{Mk*h{bNI;zq_`4#lvm+ldH2wTzKnwktyMeR^msk17+|c zy39&bySB$kF~Xbvv;#8nrdwkfs9;>sjk4DphcAFRDd!153oSEX-pKl!C{ASCi$rjF zOyjw-j^DR<|HbbjEx+G+`g*JNLwlG#tY3(I`?p=zHxhTJ(<%2sBBq|)?tz@9l9}~NjfIQtmf8AzqMu?v z=fI)JQxC8Sk@&16v@df!#vI>O)xk;q!?Ys=T{gnrWLyG^+eiB7|T0WChfbEdP#nOL4|pBNd3`l7w-w7o`OTWkmCsP^jA;Z?agthuVII%oJf zC4+N@2|QF&4D7(jedr{wUM0xa_E=b zNQYsRFB&O(*Y_gnp6CXenE&(_Bm(1RStsX^Ier%2)6WBmKA|O((Ux|L&^_o%@G3}L zBFXlJ?)}2zkIUPL1*BT7mzGQzIXEtD^!RBdLuS@ym!E&}sFHK4i+MASH|LMeE}wPD z>7TpkwI@Xn$SZYa)eKH%oMxGvIcjjSjKo~S!*xcN)6|S7Ii)$v`xMa9% zs5}qld5Jt%-I6+_E<3xfG|g2tr8KKDD@Lx_L$hMiO6C0!^j+7bo%dQ_weM6e^^5A@ z6!zYR1aYi{&;Be+oa3qR+WssBfo##|_a4A)i8Otsi7dMO!eU{QI;`uUCz7s%gZ#o! zJLsK=xUxQkMvMi65(gzB7w>c;CS7l@nZwS^C0V-Np^%MtbDzC7qb51Vo;vXS<;nlu z@0>*&$2dnP#ae@-QxeK14$q6U)&6>Kc;tD}G0WF{_wB-4=H!P(HizOrIH_{>C=~Tm z#+BAC>r2$Ga<#HLF(sLW7sYaBW^#E-xjq9rP%)!UAGdmZEV|7a!y-OQk&6;4OsBKS z_9n6_^P%R_RfBbQ+#*02cqL059b*rW2A)^a)4?r}TwDRtsEVK@$i$u5#R&pzLpTrrph&e>}{-*^g+1Y5wH941m6R4mW(c&oh6Y4Nx!-R& z?h#LVGTtai;SX7KMZr_#(oC2sGigepbKYx700%JWKODr%-z&yvH*LJ>%ZSd7b;b>m zokMQjcx&h1aKO5*bFy{Y*I!@t+Eu4cUG@(B^>xZ_R*sb1QeSd6 z(HX2?hx^j{ODU2t^pa(pBx^|b)DAE~Vb_yjaRG)bFn`=y5@Cr??95LnPD(6{HSUg! zG9pe79AULbo%+t2U|h03GAZ;wgTo#6@Q{v>co|}?H!kfA-XioYfu2LQTM$A`kI12> zr(Z%C@+a;SUAN@_?<~s zXRDB9d3(YZ<6oUy`XH(E8lmTBUDw+B*}tOi5UYx+^+tE0Cp{`W*ujo@%0m`62^D>o zQAv=If&T|Xx|FoJwAcYZGd6E9wsc;y;VUCHFv4yR4>J07ejFWaj|j9pXB~3tx2KL+ zOHc1l$cm26O0d*f#^hzhWW|$6*S5}3b(#Hr%BG~(4hC7x6DBPse)#k%ddw^g<*EC; zG_bS4Fe?k^*M4RBsxvg;&3`kJG}MSLhxKXue%hh-YR?M5bUB+S9E%PGulxCO>d5d! zM4hE}R%{H0>~|4OAnUXBYJWNf1L#9@bd)yxh>f)SmAQRNlxb-%Bp6MEkrLCZTK)0r z24AX{3;=&}Tsi_0_Z{Mv_exhrWJ()mzbAd|4cMI5>799Rd<-Y1fnMjp%uSXq2k?7U zKBJXUp7h0mkrdt;@s&7_laer`Jw~FW{SdkLBJs@z8hTwsw;wg#YRIAIdZ~oDT+#aU zCGMr28yAYFv}@<(1pFc(q;dU2OQW;1Gs2>*aZw?Ok(1X?9USDa9zT_4Z8`Mt#Os^*nugxLBcB}T) z93(QrIh-sXBooX5Y8jCn(3inGFvmM!W0U^8-eRNI^^5#@-Y9Jn%lcj27D3Qs-6hw71-Ie&$iPu z5&6*v4$jaK9I{7dWZyU#OsD{x`T<;~J8bD*j{bf$C_0b1gUos9%MyN(O|4}Ond+== z@}ObAnC7x4M_y{W(I_p<=tTBr1TbeNLfr$IUhv~tsqW_*&>Vmd6G<h24MO1)~SlaYgKaq=<;50enx1j7%YX&u5X|&5j()D~=m!OMd(+ zsGnO(!%x5NxN#u`mf*lA8)X_IWr}79QD_5CnNp~F9kMP{dI)ktp0&j4=sXtHKlbK# zgQKG3BOU*ID>Ur4L1E^Yav>ag#ql14yph#`VuPh)Dm`{7)hK$GdWp0DvS%zgeJp#H z0@VCNBa&!|<&~>K`Uke%7?c!x<-c}1f*k=%mj*a6oEYkAQv6V-SjYT?v^F7jl&&5p zNUG6{j~Iv2k@x0?b%XJ|lw?V}6xC+#$YVLPq#GdTr6ND{KuRnh{%hw;zN8)Rb#$01 zlkTJTe_QrD-baS!$jW7$IR`uJD#nP>E0-nZ|CRO0LXlV&S(1spN>-?L}O#5qFk^F~yaPN{N|(`$p%8uK4ij9@0Jeg9?qb9v)f8BC!Kt8FYNngfqWpcF(W?+>u zZGe4^+jZx&*DSaH%H#J^OGjtP7*WQAS))r+r+Zf(J1)&0RhXDqI4V1=mkd0a&v~5Zsy-4%?|JKS|VS&lrUMp`cNvXN^ z+4j_e5t+`4;)1x;Ysr_TTO0Ayj_zX=M zqZXfK?X8y4|Fspiy6TuJ!YC1ox92#`oHxUhVkh4om7Qkn`X(whcGmvb+*HSBuY`v_ z8QbrburPiR6cNi9btQw+xw4g3rR$T`mD=w3kSD(4Pe}h6lZ=-w2d)30V>gH;$oD$l z4VV+~WMD|(pup9E_XMQ}?F^n0QXFzH^pdc+uuH;6hQAXrC*mKG8IhABuZ${;o*I2D zW@Bt_>@Bh1#!ZQjjo%!PIr`S^Fr<_W?GWFxM z#fJZDmFc<$JNIRlRlnwU2M!W6}>aKW$+)1%Zm3F|D|Mc$x|gyl@2UDHROx38_TDb-%>HP;+3J_R301_ zGOTXcf~tF~UK*Y`{N@qyBVHQu)yUshH&$<`397lc=DkrFwXLI{9dmVkN&U$BvGwQG z&#PZie`!N`<`JCp%<6a)uG44;}J{kAV@y7VD2?Z0cn)tJccTRk8;+}~ICLW&n`-y*^boHcL zCp|Ff=}E6ndS}w7lN+XtpE764$|+Y&xn;_IQ?H(S>$%TNtD4p@ZTj?$GoGID_nGI; z+%xm}nQzV-Jo}fkAD+E$_MzEt&;EG!KjzryM9oQ`Q!r=boKr2$Ew{G(N2}3V)Ou~} zzvo^z_p5pP=e;-YyZPDkC(plZ{*eVq3zjTwTy*22Ba4?`5O%?k3uayL^QF%$TYBNx zCB8{i&dL_FW39| z)}caeBh{t$k?I!PXKF*h40VO=p{{+l8`LGX4JwknxGYbpW#s4Y(C|mg+g-o1RH$** zuT+sOQJrI*tEz0tYKV1*8fKZLMp}Q>b-*@2onw5Y<{0mFEwVnZ#vAXcX^u2iPq=#P zf2nd?s7jXjmIFKot6+#y0hyI?k8IDc2D|)Ez{I4(*Kh5hkD9h z%5@tM0qg=UlQ7o1p`k*}b_`duEElVvS(mD7_|`6E&%4=tTgl1lH}bB;a=W?$Xtz|* zX|<>*`!KcClA(S~p$TAr)s|DJ^7UMBn|5)Y}J{r znk9e2>wx#vd`F-v5E&Cbd#_&E68?&e^|)?jw!1=21TGSO0XM;;7_QF%g}`FqLEFX5 zU9x`L{<*r%*rxUaHyFFsr|tkok*|;JzgGEy=Wqhtx#}8Vou#HL zk@o}bh3X#rER_hqYV09h9ro$!Hrsz`S!=glteS0~tKpWDU6&H}DM0Gr3}6ZOKV!$| zHd~q+VXIdoplPbwtTr17YN5JXJ!%Y8@2NY~tDoQJHHln} zAjXz&88^wCmHlEn)*1G;>8o|0T5bFz5SN|IVOeC_b(2z$R;!jKZ~WDlOlX!AzOy)* zI@cRF1w3Uu>{N2<9X+dmGApH&Q)@8MVptxqY{{g$Tx~`R*D0!6+q=Y)beZa6P~YDe zY>YN08#9eo<1*tG%PW?{mOoivaK<_lovF@rXO^?bS?L_@e8iRR%1XDSJJKW4qtg@9 zQ_}~fH>9_uFUWi?Ysq&OcJj$TcD1Q{*zM8}tTnXEGmIAFVz3?p>rt@AIQu!1olcE) zXfLc$epu>Oi((u77s@rR$}x16{xF+TOLb>(Z_@T^DuD>}u$Y>x}JmoE~uOtz-Xr z?2TiuAA9ZCi^rZh=04W==imRiYVN(xhawmFHD%`T`tnxr617 z{rE0-SxZt2W9=lj8Z>>nCv6h9{>NG6;$ zk8e(rwA9UW8+CJAM(4Y2-gjzH#$yg!W{b0KTSlv7MyIWkgg&=3i9C2ybXzksT1OMt zp651NoaCprNy>qnj8W6w!SXbTr(mA)-402>ZOI(vq2;k4?jH;0$8E%CI6($}LfA4# zZQJG~ZMS`(E5mKHdhf}tjt>s~Z93`IlS+Myd(+(Ryga5?H8w)5Qq zdCJ)Wu01SGR-?AHJm#DYJkV{#73I4_^PEG#o9_$d9@*cCO z_)KSkvtA2>C9`qcw)%|vjMlksBV*L#?Cy$-C4p$z5>KJ?Uw?HQgBENn$Z$HVwt*$4 z`>V4+e|Ng=h?X(P>248DS5KU_$Lh2>llEA%Y>CrHje?VbwXjSF&KT3;w%5X*7AN^L zCE8lsGC#v@t8JYRzpb^cN!+(ghy4U=C0%Mx#+cTMqzv$k5uOCrYFwZ&QIP^N%0r8k znO%fI;u4Sgg5ZMP$}jaKDZ@3r8zU@=5SXJN- zA`1g_d5WxgiyuLvx;YDwcQco+yvG9306v-Y7Saz&UHwlJG$~%Gyj2+$NiIL8yQX^x zaZ>3K^fbs$m%Mw~kSW=939p1C58b{Trb!O#CST7r8~BcN|e(=BQrI<<$t>(uqqi?Q#+o0sa` zY2V3dDf?{JuCF?Op#w*#ebS?`u|LM3=j6E;U;VnL!+Q&db0mA-Th$~Z$8&FEX~25V zy&d0lH+k+Iyg%l-4^S<}zdZMWj91R}+y|*t%Vy7guzfH6O_PQYRTOx>=RQ=;50ss! zLR*+|b>Nqt`*2knyjs<&6>6orM71#sx=1ZntLZ1@sCjtfcB*1kqy_`|p1Z-kn@dj{Wo7JGYhK^5SqpQ8yO(VwURQvxMlI zrXnT`h7tEXC|(6Vp?kR+xbmSzckO3p1!DE1&yXGh~#>yl>9H`i{#v??=Ix)GA*-` zGvW0j;+Yb(M034ccGi${kv@?quk3pz{ybeKlIl9@!(6UjIqZp7;(mW_q<;BJw^OHS z=0@axGQ9KBkq$PKO0%|^oX*uXLgdQin$$GmqSO{Ac^B?UIjkY)X5NL~Wx#Sz$*dxz zS2&XX^Kbl%+o2Z0+VP96Tg&| z)JaKM%1TOf73XbADGEk;H&2(AJeizY%R9j_muD%ho-(?Im?Gm+w@nEYY?3F@rII64 z4@%tC{7J}#I{gcE9;I%WH9~kTvbtDbFVwV2d3p8u0-gRM{VcUf@>&DN?lhz>m@*{! zkUOEpTbiqM`~_NzoLN_wk=_dZO?1st;tB^Akc%Z+1DUOXH#cUD_NFbZg1>%U2L_4V zvmSO!j<+TYb&`VFE(mUsRB7|P(mS6wCMCI?S?>G7_G(@n_Z=Q;y_* zzAh!NM2PfDS?3c{Qj+hc-jS=c38I;Va<7&>lXvp9o4eh5Q1taeun3pDHPgf*rO`&Z zl0V6@NVTNnFCEf?2u)^X|LrJVSOu@ry z8s+bz70O`oNhV82vdLjCEAl&6$o4S2^9@%c)JQCt zHEI+RHd@t@*LwD{G^!>wmRyfhAb_FVdM)7YUrL(Sv_idkwlr$eO!~Z>kRUC|vnc-K^eL zzvo1u#p*NlU+P+Q0bE;3ZCpk@z6ai2q;hnSh>|>xI+t7e^no1ArE6`UW5^;PO{_v z0d-UzH=?jnzt61cG4+o6v$|6~&WP(N^|U&uo={J!m(`W(CACHEQis$5^}Kr4h*sCD zyVdRLA+-bB_7|#M-J+Qv_9 zZVp(pd`VGJO_Aq1I-q97q7};*EDdP&TFpl!jb zC9CvP$c3%*+Ey&r_rV&gzKxi-q;1}s3l}b1aIyJmUaK$E+_nWCRN=lvb)cZOCCe9? z!B;O?Hs4GxYVn%oi(1>(T)3=t&1(IT3dJ%L>PG;U?Fem&4o2QbE6eCH%~MqPvewnh zsVg?Acw+nJ(tS_Nr3>1Yt8nvI;}U!_J1$poqWU)-zAa{b%=*xVnDx=A(Z`}w9TURV z$F2@P6t>=YJFFpSg5}My_10g8t+$X3 zU&MO;cnWS{A~&{v@^6b`dDbEyop`i{U_=8{WXN?zld+cG&aG= zpa1;};h_}qn`h6WPN6Xw%8qE$qvj zMe4NP7>ma6>Wis9Ju#cQxs2K=y-Lx8YjjQAKwZ2N%^-SXGxg+JYJ=2++t3lWQ=9HW zgZz^Eau4<8VQSGMXo)?#W=S2}i{;{ZsV~&AgXoUKXo@$`5x++>9HqWWE&Uk1@hKYO zbL!fcTL1hDAEqNzP}c?((bcS?fN1Vhx(=#TARQe$fams6s}XbP6O5fR}$|k;A-F+U^B1<*b3ZB*!zI{fp*{l;6dOaU?=b}unTwu*bO`m z>;dN!T%QD<0-gr;0{ejde0vsn4mbe3L>j;0{mZ~Bz!BcP!SxgJ_c`z-@C{)~@MPMh zf`Kp~vTK;i=xSG4z(AlFC=|9V)cIVO5@s3kFC_j7 zU?tCOJg+9~8sHM%UCMO>?>2IOE#H3u+zQ+VYzJ-!b^v!1?s;&&2pr`3b>Mfr`;d4i zfserPG4Lty8Sn+~z5>1m3gP2g_*e@cYvJQsc()ebHNm?R@a_b>I|1)bz_SzZ>jXSn z3y;>qqqXp8Ej(HakJiGYweaW!JURi7PQarR@aP0QIsuPPz@roJ=mb1E0gq0=qZ9Dx z1pGMxe@?)k6Y%E*{5b)CPQZ_~@Z$vhH~~LSz>5>`q847%!i!pXv6hxRqw6STf0VL6 zO4%Q!?2l6Rud9l#w<+VJlL}ZBO%S?@bx^gXHe*xSI+y-n1ZU=S%_mb{?!2Liw@Br{2@DQ*Qco^6PJOb54G#<9VIg&DA*Fjayew32lJB>GKakHq z0`CAHlCP71x6XaRz0|v}fUg0me;1)&%izw9XxTEfY#Gv9Lp|IKmuisU8_`6&;LLfcwUY6UIVNn&LzCRl=}_5-^l%y&~g=UHE<2E8Q21B z1-?&C?}e88fct@V-~r%4;2~fq@G!6ocm&uDJPzz3{U^9S2|NWn4eSN>0sHy(Ebts~ z0C=7}y$HMn9lznb)Pt9~z5*QKyVQv{xPOzfcnkOg`TryE4)7uQIthG49zO;?fe)W@ z{S5e=`!D$RCD*UGehqv>8sp(&C0yJK7c1dnC0x7<4&DU^_rk#gaPR>2YcKU`2lZ(? zoZ1ejw!^9I)Tc+_)&aP60B&uETL<9QcDQu_ZaoaQ4$xLs!i`F}Q3W@u;Kl(sQ3WR| z;lf_Huoo`ug$sM(!d|$r7cT6jer%_tw^P#FDe3K$^ma;mJ0-oHlHN{9Z>OZUQ_|Zh z>Ft#Cc1rpHCB2=J-cCtxr=+)2(%UKN?UeKZO8NjLeSnfaKnd@qgtt?=+bP}clK9jXx>cpiM3-t`hP`#WUzCFFGnrILoc?n7SpA+I|qp)_Q4AElCpeC|UAcc3|T zpgDG+Id-5qcAzcCb<-Y+Nbms6V~XiKAj(a7Q$ zpdM%dCIM4`dx86a`+;`g0pLO4Az&x)Ft7`F1lSEc4m<%o2|NWn4eSN>0lxuW23`T) z06rnz&w($62ITe_)a-_u-N@@PL5=YYK36&?I z@+9Tc0i`FQ^dyv?gwm5eO8gtX=l9vxkM24S<;S7?IFuiU^5al`{71F@_Y&?t;C`ST zcmQ}1cnH`DJPhmt9sza(j{{EtPXbQ?PXl{_eZX%3Q)eD02gg17@;LGz)HMYenL;^F z(Kdrh>T?zLg^^sZ}SC^3%` z^C&To67wiAj}q%BF$kyZU5APFz6$0V%9}8*(L4_T%4vs(A`!#7o~4KCR>SG*j^w$T za4ov3h4X_#50&E5DChkjIf5-Lr;CLH23VcMokAY8t&wy_T|4o%}jF*-a^9KPSuzppE<0T^s5DZzP55=>KD9 z;oU~=?oT6(fDOP$ zz{kL+z-PdP=>Br#uZ_|xNB@_jcd{vwCb*vs_uFXaZ=jvOfif$mcJD_n+i1!5(~|A? z^r!dJn(aqF)lkc8sO2@(@*3Lz^JxEXp#8sr8ec>Ee*?9?hW7sk+W#8b{~PF`-Gvs| zPg_$?2{%!~O|*FXX?MzLcSg|ejG#}z3S-`1%KZl3Z{+?;Xt)Zv8n_173~T|m0@o7% z7r?E+ZNPTmc3=l^FX`R~+z+$^4*(AW4*@%Yhk;$dBfxIpabOSWKf(1$;3?o~U@x!_ z*w43Tf#-k&z)Ph68{Quzt(UpJ0vzG}>pZ`~{hPpBz#qu>AAxs(56RC-;3M+(G4KiH z{wdebfX})Af^T1P{fg_?z&E6k1c#*WoB>A;!Hq+3;}HFdLvZ2{C3=X`+(l{bqBIXt zdb=pKU6jlrO6CwHbBK~TM9CbYWDZd>hoJZnR33twT~M=&RCkf$E>hfuoyp#{73tcF zWNjs78BHH1)x)HEm{bpw>S1)%5Nc5#wP*viXc)C94|#5*7VSl*Wi)*lN!$u$-qEz^ zuB}iv49VOIg))LZ426fG@Guk}hQh;8co+%~Q@e&C|82;B8`K_#+QZbcVNmQDL4)IC z;8Wl;z<&hIX*sm$L0w14#cp!38!4ZSgwIC8k08-UpuPs`H=}9yL47rv_Aoiv48^;l zayJz2M(U0rbw`l8BS_s5r0xh(cLb?B0(I4J{|FRSqhSxDVGpBW4^!WEL)C7$IvdJ% zLz(n2X2a3haPo+@(M*M!`zcrHtK1JoQ=w=o?NAx5PZ8}VP*J zuoWDIKQ|&>yFEJkM*7aLAYmOy*fAum0}1PZUrm(A5lZ9;vflykn$V(+XwgPW=m?s$ z5neV?Qb&-s4y3IEY3o4RI*_&wq^$#K>%iu46r00QYz{}UIUM!q_70@41L^BP`Z_#1 z{s=ie0-u}Ua}zvng2zqd_z1Z@LT-;O2Uz%z$;^PJ#`&+HA-XqUZ3|U=F1_l~7W? O6wSSccUE&A=l=j8$$|F( literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/lato/Lato-Light.ttf b/internal/login/static/resources/fonts/lato/Lato-Light.ttf new file mode 100755 index 0000000000000000000000000000000000000000..9c0a7053621b248d8b6589dcaa0854ef49c33985 GIT binary patch literal 77192 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 z z?s9>ENz(a929GD;?aG4(>_^ccp{7(pB!d`kN@+g}euOaRm)1h%A(@S?d9<fmT z^(?$5MRi>R}b>)L0&z`tH+P&L0&z`s|R`Y zAg^8}@73Rg$eV#Dq&3kd+BsqedF>#t9ptrxympY+4)WSTUOUKZ2YKxvuN~yIgS>W- z*ADX9L0-E`-mAZfLSE=znY?I_$0WrUpe&716R-2WZWz6(e1YE7R zymDaYOGi2*RI^|Z6hEQphw+$xaA5Yqyo)(T_NhrHI5@kc6G(T+^$al6qD}DxTDXnZ z4T|K)cxBcc6mJGedV$FDx98BkiSN7v_)ygXf6q-6vMAa~i(Ar?CWWXZy+BKvibP_{ zS6Mq9tep0s@2u(qNp^k^gl zaskzVcEAu|6tEv~1aJay3NQ{h3pfWj51=JYY1SbVL-nVjCvuSKWGg}^F_T+ZlcF&; ze`Twz8rB`FS{Ypq#ZY_4kfaz=A6~jKDyfCecE0;!&z$wceB$DHieBI)z3?dXLJp#o zPsE~>BJ3@SOZvb8KFlQ8V+W22;av!G45c1WTt?L&3Jb(|LRs{NT{3|S83dio5L!V- z5|S*Z7Radua%zE`S|Fzu$f*T#YJr?uAg30{sReRsft*?(rxwVm1q@*ULs(Qfz51Id z3;~l+mQys8T_*um*9BBvhlZ@{0-$98v%K#W6pz6A-ze#M@iPjIBUtWQnsYjB)6gnUFxbrFfca7C0nx{%DRvzi^+}c@S zgd#~^xN2MV`cwOx8g@Ossq300VFQ16!J_TLd$rphA9GtB+rO}@)|claZIa_|JMyg? zHob65M_b9#>$?}-Focph453Ai-zq+UWyTNXwM%kGFpYp$D6@suFy)mwl{Y>iM{NR3 zF0WD&Z^+Bx3E+``WMhJ+>L8q)a#bMZ?O;GVc8Vcl^xB=C&lfD((UQ@aEHHaQp0~8G z-pA%fzb;&B;FE&aFTQCYWHJ_+wVpW}ITe>8hC2y6zby!}$T3Oe zG(t+003{V8pyXeooAQDhC>qovP$h{;S%F2;54qo58;FeY4=v{Nx zw)nGK*EBY+ZOzVZT`Rnw>G7rTrof7-_C0+?smaY5p(2-7XD{rT8`(Kj8JfScYT?cd z+ngF#QDLq%@5pfbp8lds-zl!iOw?)(mSAa}zo0XmnH3q}i*lM#v1p_@JG*%Vm5Z9O zZ;pE$EAU?ypXFRk16K_+R;v`L9s$K8<(WST)Tc^Cl!K<1hHoB*5xj04UB&H>H?h$B?1+RM|jJb7%es2^X^`jxG{*Y)PFxbfE2 zrkzV)fC%sayGjcRsRiXo|e6`=RXG#CsuhNwmL!vYO?pS3JE+GN-OTs@R(q zgqk%i#-dWPXK#3`N#uTn@WO8Z{76$8WZQrd8!%!6Mr^={4H&TjBQ{{f28`H%5gRaK z1Af+k5gU*^F2}eWYA{yWYrs4!Znq?7+U=RiX0!Zi5#FBk2ye4Ndj|Do*zG=g^+Bm$ z{$J6%q!CknorfkUBN5t%^o<>_PHDsx(MD8mnqU0nH~8aLT4E!X(~afaHd@9?k%yXs zp`r?oJk-Cv3XVKfX`J$cgBxkzmA2U<_tq_`_Y}EBmZZVyG#{Xevq2 z5A|qP&qfKOy+*<*NRyZArKt)<3M5TPQ&lWaM@fi?$xJN2Pw}qejUfs*QBE{bj55~c zxb=**9292)v$BLDbBcxCWlFO5N9P;uCaXJveXq~#Hbs})(!GT%#b+mP*IU@NCUbO! z(WceA6Qf2`0(;etS3EQ0UI7Pt&;l7_u~d~;W1J}S4tPa;_F@k%m$iuaPm-^Q3{cp4 zO32ZV7I}?w4LG?ZSOIV$=bF&Y8ICKE=9@%ZNBi95wfdszIY#-_7_O9@rdWr9yjaI9 z4Wz7!$3k8T6G|PFMd?vhl1EiZXviwb1KILGwmgt64`j;&+44ZPJdiC9WXl8D@<6sc zK$8cu<$*TwK%01=l02$Py84@tubPVhCe#v~Kic7eBqIEcsV7+Uaf+%URb%ipcP=j8 za&wZsseesH$KJkzmDlg7STR4eV)wS5qgBG&DR<|!l&0OVBeJy4Q@ZlbrKH5}c_7fa zy@Ohxd2rRhlvSar@MX{x;a*S$GlQB*q0S6R(##M~%Or_{6eluco_0sk$$(ryHJ}|Z1Q-SE2OI&M0GtAh1I_}@0nP)IiGwJF*h`EyG<6U~ zT3*-|n>|2)`v=Bm%^u`?{|eZqT&B;&YI%@XMYTNC+%)o|qTr6(the z$RTHaH<45Qw{H!76W@6U@F75&V*j3-C_a=^mNPAGsrpc;87Rk#ys8YMAyd~2!gxU# zF9_oWVZ0!W7liSGFkTSG3&MCo7%vFp1!24(j2DFQg1TN+2Cx1mF&|3aMNQ_Q;|jx% z_iXz7Zmd#&e$%GU?`de*^Z89nZd+1NfIs+;N?o@J@6A8-@}4~}9cphs^wOR^FCUse z+1ar3v9)U+-xZ1MdVI~=$96WrhIl;sD7fH#_%qq;2Xb_lGQ=qst4f`0kI8w!XQWhX zmn3xoT$2E9p{zcth(vBtRvdrKlE7KhkitQ_>9qnIP1ZI!3xa|=|JVxxHawxE$%)TB zFv2`AOFW1bcn~Y_AXeZ(tiXdXecz#w1)U?1Qx;5guEz>9#_0B-``0VsT~%qLp(P)yH3d7iS8n2y@oX2xtEuSm2q z1A;T-->upD*x34GRjhf% z22Tg{uxXLa4CtL$+5GHgIh?oQc$I;rNAE>Iuj}^D**p(eIl7zq&{ftk+hzusDFc` z{xL1-(MSg50;&P+fFZyrU_amp-~`|lU>tB3a1L-DZ~>rrepi1Jbpls~Q>lL{JAY+1 z3)7c8x~FhKR-$0jx_u=XJ3dn=ylu9hHXDO3D(Uoeb|`7O!VtM9pVt zZpuq*02V7=2f!DSGtej}%>`Xufmbg+@!~2MFcgZ@*EOVkYvNW|VmWE@zF0ZPQiHGk z<7cNy5mM620jSgfRB8Y!H2{?wfJzNOr3Ro<15l{}sMG*dY5*!V0F@emN)14z2B4Rf zc&HAIBtQ@l2DAYN0UH4O0EYp`0Z#*71iS`#6Yvf|(aTDlR*N2Kt>vS$(_~}r%Jek; z+d7NMU(;7#wWQHs(!FMMO?OH0lAHU+PShu%lw@L{VR&xi$~iuKG=`6g7GJYq_)~Sl zs5vDgC8MG>P#h`9%na7{*EenNEty-DrPpWXWKxCCvS!rL4%GHVDpz+DR8+yMssK0L zDb9hJ_iNd^rri;8**`TCm@@kBfsK=@HTv!jF~=-ywgLDRlt4%R*jf1b<%t( z=UJRV6vrrK(5f16*1R~&r-_;13UOi@c6s*PCUw%p#zoVq=dJ3&bb{RMx#QrzyFF4kbejxlBlmlD7Cbs6G*G zXOYv5XrGUJzS%BZ(&;r~f}WXluAp1TbQXigpr6#I&WnC^o>dq9gNSOOIx+gL);>2j zp!_5u+3lV@UzqO-B?-3VNsmj&wRkP~KY7kYemXK(g}uOY8d&G!=4K@b8yi?GCsO%J zY<4LrRkHS!Skug;J$6U*sbNam%hn_^n`ki(MNhJg!<4i4hG>lb49aman_|CC&_|cr z9PB1TLNsG4iln)5r#U)mKxqxo1{Ugzcw%>qGiJq+T{Qi<;-)_(^%gd!v^b7p@Uyss zU8{B2Tb_*$FSLL|7HSO|(WGUaqTMt<`YLL{-zK~QKDlVgKz5f!&`NyL0qoV{S>m$v zW+5wn$Dv&Ri<~Qz^O1H^$0h0cgj(b!@@uE^Ec}kC$N29H6E552*E$0>r_j}jkvAeg z?hnY1Yv)!>P+>hOP6i4<-tqad^syrBt{HZZ29aXo2m3DMDNbOF|^?a=|`% zc}OagMYSS;Vp{A|N=Zm7MJ^znU8f?`YEY4xEF&{nMW(^3BGa8$0AwQ`*vwo<$eAC$KP@pb9iFIYx4^~%f8ePqY(@L6y;pOvk zgC)VZCS^(f8uWYwws0c6UsS=NDj&2SqUxx4)t@GZ`qL2VPg6tvX>bYB;1Z<4B}jw7 zq(PCRWHDer;0WLZ;1pmSa26nk`tjW1a&R^d^FVPInP709SQ4+E%hem6q3!*O-FS)L}VA)-(%1zpin_t|$ zed2Hz|Gh-VAN93GK2ewCNfRgU=d*&D8ZpCDnv=x8frA$Qu==5Gb9BO((75AK@YP&M zT90@?SIb0sRi83_<<)%BRvK_v^>h}hf~8mFS{qV<@p5EgAQgjZeA@hT9kwSc zHaxU`!S2C`J77q(B{~Zu1NGf|7Ui;^+Y+OV?Ttt$7aYmX$*Qb5WuEWwCoE1D7~3+0DiHSSDV04`iXyNM}&Bxm_RV^Y1VG)YfV?SOJg zPXZU=U>N%t$b1VYVFNkUMNHC3g_)437{qFNSTXCBl1%*XaYTAL1XOOUoXVFMUAyD&FVeR%P_QdiDHJ zXg*2@%HIN?Ayr zTN+)uFg1}a)hCJu8(TtqRiaDSaP%IwHG0nq`Gp@9GE$~CIPs+*|A5In`ODh9wb7f| z^|gCBK5mB9aYeMk7jJ*iIu7lI6{kn7*ksdlF1Z3U@6yaW`RC}jCqD$m@3?%Out`MC zVQv}Ao8aaHr?t}9F|lxcXr1Bapl7~>-8o7GD9niQX8#ttH-gGJX&^C&&+Ctbp9j9L@?i85pmE;GD7PMSfsu(?x5zNNY0QG z$Mr;De^4F@6LOVUMD_3-KdMS?8SO3W@2#3UBOVc1hAN!RSrr3Yc5E4_7~T+WRbmoT zPXy-Q@kk|mGgo{E#ab)@Vt>o-?je0>el#JMOJ-JaruI} zl9GznB@JEI=H#sDs9M!oP+2+kg}kQ9!u(K5=E{b`dEtV*U{YW?Spq@L^L&;#NNZc% z+}PSytVaE5*u4~)&IA8Bp?jp=sA{QB*-WD)4J!5JCtAka++(92QDgPE6BFGYtIbQ-d2Ls`#{+STFaMW#0drh|#NBTbcWbypiMw;~ zF|&N}Cgh#85cnY&b3-uZhJei>>E9^+?gtzJ zoB*5xj04UB&H>H?E&!zA=+Q_9n{E7Dv!nQ5vMOroC8 zsC#tx%ExxinY;g~H5G#$b25^3iAG=Ta7*8jRh5;?Z|Yin?POoY$gPi#ql(aDw~kbx z{n+^0HK!j%yKckte>!^fz2`?qpMUS@(LX)Efql-X!7b-C?R{$f+Nbt4TReGbK2vH& zYUS!X2bbQtsyvS^qOUHms91jMqo>!b9ar1qYwvjPh0)O$-n-+D_r5kZ_O^?3<^v6C?}@lXUSXtt)3QB4^{VI^n!!ByCiznZ)AL3w z$7cc@tU6Q(`b)Ayd(`O=Glfl(!6w*3F0b?^qnQliB!f7~AP$i#8N^8jg_A+yWKcL6 z6ix<(lR@ERP&gSB#x%h8H?`A>z{?(oOqM6pGlaz26+PqV0L8pV?$!e(u z9?g=45>Z-memmvDn(^GR3f!|w;3%;x$-ALALbr75Hnbo%APp_`pi-k8i1$I$`yeMi zXnG$sy$_n+2TkvTruRY9`=IH4(DXiNdLJ~s51QTwP49!Imnt=qrvE!{B5V4Ozloyh zebDqM@BmFuB_mMBO+KeC1Q8CYB7F7r*e>8EiU|LmH<3m7<8MMDjPlB#sKQ0CA?5;d zToB=<9=CA9(ntJqZp2^DHu2w9)_4r=)E?c3|J;y^r(X z{BNr4SE2`mJ-ha}YgR1-C9oxto%Tu7!F04gnqdl(qNPgk%|cmmzA}$=EDnws zRgT4x4+NyWuxy~9yT+H2U+w+ABj{v~lxksfJx>YRLn;58rA4yKmQ zFUf6ftnD4v$nf{6_TU*${n7DF1J;7?>Am4xyHF8Vk5y^_T1U!kV z)8OF}j4k*&0M-kQvuS#q4P>S_kdHZmfyjFqab!ahCEp zEVayMZK`t$8W|hk*WAvF@X@8c=~x&0n7!#tM`w+Z`^k&v^tObWhfT@J;_)e??)P?S z-R5>Fv*>Nk!$#$tg$!Vi_JqiGpt^cWJ9<8T^;C{BP>hAD(~;JZ>!Yd>)me*jvsP7= zeBM~L(O+3+RVLc2Um;bNS!tsEJ8vRSv>$&HWunz!qD47~k6wli1QAc8Rq`3DvGcyL ze)X+6qEO;Ynz00T9MjglLLbNn(VIe`lp!RSzwwjp22hW<(0ucki=*QM8&2+QXxMpjgLt_2 zVxsuo#YEvi_3GQY7Tvt847Yfaz00=oFXDL|RM~;7S7~K}j*F4z=^0A+No!iR(-la! zTGInAXLg#EUo`zLC(UY2%b_ve8hx034~*_1dlL~jWjmo1Z6kYA#5Kv15Idlyq&c0W zw>&-!Q}sE~mX_-&uSqRw3g$O>myD#9w&dn@ry8}u2O|;*8d0_|wEFa%9it*;mdHMuJjbW1b9O4`>{NBmP6fJB;hCkvGfRbMmI}`- z6`oltJhN1IW~uPZQsJ4ULX1=4nWe%rOND2a3ePN6owNVWo5*wa$KOQq%%)d-nFKSV^$E1A`JNN%&zT*8Mi@|0xv4AO2BPN@EYU-W(c3=e1F+j6 zX!srC9pEo7%%wu^=h(vs-Y5oW$&P!S*8fPhi7({b7I~MS6`xQVkz9!iZCr)WKCYrl z-Wm9mUggL?qP1veqmQacP=6uXh0}FHXI1SjplP)rE_5495ydl6A(9|n5tQR&jD!aA zLGBtO#s#`*Nr@B_ZKfdxr>P?gl9PiSd?DuYSJKXBR-SW(Ac<5yN0d&{q>4|P_pY~X zX^c)J@mjWW?xoW+#7v_XqCaQe$^S5=*>Z(UV~R8X!))s}zG2N|=lpRJxG%{Qz3!Yn zQCw@I6AcLCoxpe@?1nb(TjN|ia55i2^4N~YEXLy&BbH)<8!Df~M>a>il#*=X8uXUp zTB`h54D2J4j%awB@-20SRL&29239aPk1#hc4!5&56gANmO)_ptN0Eg_p-YBC=n1#9 z3kEfd@CX#dECN>5Qw{&B^>!t`9Whj||3tfPzC-KcoqUq{;N%lCsPJ+O`~1IslEpVC z;@}xBRC$Z4q+6h*TT~_80wvu7CEWrg-2x?z6Yl||fc=0YfD?dIfN{WC zz&XHqzy*NfSpA(hk(Knv--OPHC&}%fEx9tw{Z00CKIK@!gZLyFpIrL4nA?#KyUxZm z2D`<4t?VX9cxhHxe#s>+dM%O-))fpl-ISbZNa9lnz9Q26JHSX>nkc-N1Bzxf^=HVLNy7)=}R$J za+fc|V#0|v+W+JO$Ok~VJ*H>F+(-4BX7qn=`uYU6GVb~pru%I(`u}aZ-!P+pYP#P_ z{n+37JC4&%z*4rsh+3}FBxX4&+IN=s5vzzNFYm~O&(wpe@GS^19C#>ON_3z?IZ(H7 z)#=D;0vxl0L@k_jiA|pTCE?Y{AGGrurylF%KQonDJ@w4niJpb*5T7}wcbcY8z+hjC zu1Nulg;R@?pfL_cAC}IQS;$U}bBmzGdH}7k@ljR-zq<$m=zuPx`oZy4IcC)lj?Ej& zU}Kx|WFs19HbH|@XDf2f?O6uxSu%8U&kC4aFeXGzc~gf=z>9 z(;(P12pk8&ra|bXAoNlYdPylssz)OkkPD~=v;&3!qk#Q@BY+ctQ-E>6S-?5Kc>ryq zY{C=5aF#=^rJ!diJ}5=VwG`89DMGHL2)ULbKFUj*# zNj|UaH?jDBl4tq)1hyjXdXihY-=OsCV9Goo-M;|$*D}3^w8hI1-R`(vlhlh;S-w?E z_m;0sFwnJd*l;b~S?)C$&;inNA`X{9HlUBY3q~enhw3ZSN(zJ2FnW)+9@ZUAWoGoz z234E1hD`@bB}=WeX`gvk{z$BBE2UvjT~iVx9$%$BcJgg$@rG8ssW?g^KB2NhlAkCY z+T&7A@bTwRqNjXDjSn%W(sT0JJ*%a2e9nn3{3%^AMlZi4I>F^u!y=dhqk$f&3ASC%*23}`iK?4gLnDFc9 zXV~uY=pE6c6>LxR?n<_uZPg@1?}^@7!FE&UUbejowF|aky1n-DahxGQ2VfO)HS9|` z`x(@&1JLP9wfGfzcbvSJ@(dhz8Q<v@Loy=w8{@RWZ=jAPGt+Aw9ZLK1>zwj$BGBvNda|+s_H~K5_aP&Xo4@RK66tCfQNf*TJ5dfTJQH1&n?Od+DGms09@O z+m=>sLwJ=v>=0}ld9U<>Y5#1N?bbpf+CttJ1fGHrv274^zM#VVSHIuvL)=7R{;R)< z!u&Hft>JM&od`W4DUgV&K+upCNCY&9K=vcxln7)$0@;s1_9Kw}2xLD3*^fZ>BcN^s zvLAu$MPqJK&o4=DTtC0(LtefeaH z@SAmyZL5QnNmY2o?EBp7(=s!Gt{ZD4}k4^XgYDWLybpOT~{b#28 ze?k3VZTznITgYKE*UOCv!3mI40BMQyQD+#Br^>(*Nd~;=kt?>&g+v!(U&);59s_!Y zAlpNj;V1^R;!4?wC9W$AVX=-_vZW#{u}a?)2w|u-`_jOeW>s{|m^aLrH_Vtf%$PUK zm^aLrH_Vtf%$PUKm^aLrH_Vtf%$PUKm^aLrH_Vtf%&O>I{Y@0nL1;@hwb4NQp#e`Q zIRhj*iWzR8hAcXz5S>!sw-lmN3S5^$bV?yQr4XG`h)yX)rxc=73ehQr=#)ZqN+CL> z5FN!m(4&zI$OTjb+5tm=QNVt{5x@z+DZn`3EZ`jAJb>n2N|EYPao7bMb^(W7z+o3~ z*aaMR0f$|{VHa@N1srw(hh4y77jW1G9CiVRUBF?Nio>hFiGsr}6^Cd5hopY`RQ1!R zsvk6D9QI-OeHeZphTn(b_hI;b7=9my--qG%VfcL*ejkS4hvD~O_Gs-LUB zNlg79*pfODOTXElJ-kU)e$v^J8xbYHkzk4mkb?T z(6+WEU^MHKlRB2JtGMOmV&~$`2f`@BTohNg*<==NT~BYi{_dpW=cB)piZ<8xmNxGm zEMt$f@9Hhp@&mc;>xB2}cYR@-+q(S=J8OMGpV3Qo6p!BCwXxZg(L6eT&W?d9P3zI) zc_n#9J!(7Ow0+x6QLC8Syri;vVOes);)4tMP{r~?y^9Zzz+6Yw-srpT}m#D?R^a=o;Dc&sNzWTV(?@WH!hK8)SnGvcU$~ zV1sP1K{nVR8*GpbHpm7WWP=T|!3No2gKV%tHrOB=Y>=(8!PVb{M2R-YANkxZ1#lPj5{A7-xU4w)5r}cgY2Tvu0NeuI<(=jC1kHBBd(Pk4kf8yE0dP zAkCFm_V4B5`)RI}um8!6ewq{I{*6k17MOZKy8l_+U(3z?F8%65=>0)l?_TP?{4RRm z7wO*ewLg)1-$U>3MY^-xyYahZ885l~zHm;w4vPUDTy&i4#C*5_&}wINR`vZt|m$!2!sE^;J>i+ zuMK|(0UH4O0EYp`0Z#*71iS`#6Yvh;Lx946SAP?Q|H3N&p+Wp7txzJ6PNgoZ8tKfD zFlC5>&rs=-g23`xD($9A!eu(DeiSZ(5|#IovTy4WuCKqX!)O(G?b2tvAFzvwI~&Kk z@@sZJvupT~eJv;zyP{ilCRpl*_AVGgZKUvu>oi4rqtUd*S8U-e zP`x+&}L*`pd@#n+|+w^U5#WFh8wksQ!ij>io=PVe3t2c9*YT zR93(7uHKP*)>eWm9*42?Ws&Ty9*Gx!#hAp4Qf)1XTY429z4(#+d%5_2;v@O`pUmi| z`^){mn$b@jCiicoei&w3xSt}kYXw>kti*<8k44@mM~gX>1CxN)^w$x`NJ0dHj<(QI z7zu_QW$eXr_SlTQjJ6r?woq0VI}pFAF}}@zV?H|^3|mtC4k^$+wIc2fJ>}r#7laQq z0qjC3;Hub*<6IcLO(#zX@CCzoK6SpJn%=Ze8GuhImqJ~^q+{^Pq)*fFX*yQODllXr zE*3Iteu*7BAx|RGQ4VB}<*Jhi8uBEPi%BF``d5v=?SLV`C}2O}2;c5o;|7yLU9nBxjStu zDQmbfTS*Bk#1hhCwvwD{K{Z$;Ki#1+HySc?UwzfV3lK4dxv%~v#N1TV9*I6ObEks2 zQ^DM+VD3~fcPf}W70jIq=1v83r-Hdt!Q81}?o=>$DwsPJ%$*A6mJ)qvZRF~2@_(v( z4>+rev+;kF@0)J_;U-UA%}+ih+G-+b81$8 z{5|(t7g}XKp+>brW;x5gK2oQPhvR_WFXtmh&HA%n?^Vk71ot(j`?{G7CsUjeu=&_P ztiSY}SqB=Ekn}abS}H0T64c!)nvL}vSea#%Nh{7SFk+qHG6(WI8mFEZuN;sUas2qu zq&ulZr<>YNF|~OHHdl-pm|v0SKWI0d)AOp`XXpQ8M@gb!%Gjb|18ahoxc0-I#qNN0 z{lCsmHXc>kG}!HNoBnS4O|UkRsAZQ7c6GYf{E*TApgp^j=?v!VlwXekgfLk> zDCIJL;Z{cSNu1rwDAG`sGUW2mNBws-%1UN>M00J>>HDHBj`Z(fV~--?VzXoZeSPCc*ns{j&%B7NB(re=LqsCU;%z5e(irwQp~sRq z$sEp|>_8v$!i%G&y^OGw<%l1z7?5{prg_GpxM}&JF4Nn`_0c(}^Fs&L27CPm`Y1?2 z=A!4avqzhnuHCnj>11ZTY&*qCEUV{f?ipkLO$T z@yO4iKAD(o8Gw-hb!NmG6;KT-QUeQWP>~u`qy`nKK}Bj%ks4H_1{JA6MQTuy8dRhP z6{$f*YEY4yoQiz?M6xPUlT#5Q^ma*~CT>4fKxDXN9y+gR|@7QfV8j36OrdOb4^-tJ2xUt2fxJE!1vxxO-NcZa(|mDgAC({b$k zG!m3r$kQ*F898dlJ??P->?HDH8-n}h4Rrgh9S7ety*GbQ)X`yDhjn`v?}eCd^^Ea* zxAwkn^^C9MO|){1uj6%^EYr@e>9yL0n4 zq{OmvrJRd7i}!hiC;P8pd4vyec8{<=5+AV&Ss&^<4aV#CL3Zn+q!dAXA8mTfPNqq& z^g%lLZp;pkIVEB=t-t=ZIsZd@?-=E6%2~E1EL#(ntqIH4gk@{OvNd7Zny_q5ShglC zTN9S83Cq@mWoyE+HDTGBuxw2^%l7pX$y&CioMj^--;I4Wiry{Wx1+f!9xP_Rlfyb7 z9WA+v<>1cp(=Na5g!Ql9GH>23udYAgw#!c|H;+HKW%Bxm)~tSb{gf%|A6~uYq4krk z0}nku>(KqjYSU+4IIr=Phcwsi`j~ms{0nDl(+;(E9k^re+&d0*U3=iRIdg710N3fQ zvCW|t8c65bF{bl(GVEoBskzavp?XY4e5Vl;uZyAjXqW75W5f)poQi-*kDiQj&FZb2 zvY%>w_9Hust?x$PpjOu86iXAd*l2<>_8~5G)LF7YW^<0S&2Y9E&Njo@W;ojnXPe<{ zGn{RPv(0d}8O}Dt*=9J~3}>6+Y%`o~&T;nZCz9oCbB?n_sIz2kDb^G>>a5mWokhgZ zj#fHETKVK?g=(#Ih_v!i-Aac@D;*-O)LE@`h_uon(u(PAr9-5Z4v|(mL|W-pX*J61 zAdfT6%dU@ou}I19KOxE}ZkupRgn@I3GqARnGGhSZ)bA=9IcT9t@V!gdmGC-HU? zZzu6~5^pE*b`ozV@pck#CvjQ!u${!)NxYrJ+bLmtu7qDdk*^p->Rl~Q`dCJpjb4>L zZRs00`e@3^}Fh79`8E&h84qyuefR9_jc7p#-DiB zq4_hUse5|mvS1xYdiYB^JUy!Jki7^F(IDB43l8=m5Mhk%h(x;m&%DX5ksv1`wQDWPjYVo{{*r< zK3_i(U98R6`oV*mN10ogmc(j>GU+oKkq&)7p2((iJ3Zr;Up=?1xpR7p>!e5XUQfiI zf3R$@TqW6Hyx`ymCx83++NQKtG~pXF%`O+)ls)q3gUy9<`4IZ6(w3`DRkXYUvKun% zC_vd<3$AZU1eK4>cVj%3AuZj5tJzd_RKR_Mjd29ijaHwd?Zsm)S9@-=*ezDmZC3jy z{ZjU-(K4Tg4s3YlhEM)pJ{{rZ)3^Mb;j}Cc+2Tn#u*k%GWbqU$O}CM++kJ!8Z$IjV zW3B7mw|Tv{*{q)+<=MIQCYw54mzu$r@0lXt7FBZ&-!aRI)L7|LL@sEm#3@sdZ%3Bt z?(I43n<<~ITlzj5jh(SYkRXc;xHRV$NRwq5wX(6t4NHy>Rvp#UbX0Y4eBQ9*EZ?gf zH-BLH*ntHF1ILyRoIehCYxT6{eeHbf&GZaLcM5Iv7B8a<{;Zdz_POC4?flPg_hg;$ z`Hh}T>MY9|M%#9fYLRO1n{6mxeMUd3(Z6%#Dgn&4`5Utx#UoujTn*~WY%ZwZ`)y(j zFtzB*4eP`4wzE==qf1LiH|FOX=hW~q%>&1b8Q46=8Y>%Fn@rY@EGrvPmq^r&D3kjD zIc(^;SKEt&CW}VOoJQk|^>b23W8Nr^=(Q>rmVq)2`mlRz-R?Cq!>5*`oZi>-seGpk6KSpAr z5q+tl&C$rz)|A6mF|gF?w-i@QshIw~5h0tyZfjmNWJIgO;p25pt+Yh7JnIui+N3M# zOWHE-ug?WH7LwE_(#om|dgOx`Y3JLGw5?C{rtPo|Ts&lWU)mX^i|fdV~qIcM*d}VQTE)l zAsI5wL;SNPjz>VYfpEmyQf~Pgb<3mzW4}aWc~O}sBElwv^7)t*R$y($jl+yFiJO^+ zE~|SN2g6vH%5bpwmUw*Hy|cXW{8ZdK^WN$4M9;<1HxOW%8TVcXoIm z5?M6+8ig`N*ThG?v=&&yQ#UUVh9sn^VdpIF2xiW*Y)B#J8t`qQ7enmjkvP-uX)DEP z#lW2zb*!6li*{bmB}dXgJ3kShe(y|!6tnJ~7LPw{dN_RqJr0dc2UF0fr@-sgUWZ1h zAgh-bY6Dms`8;Z4>VIPui{6@7T!@U-ELb@3u+=QI!iE{Aj%>wouwlmX){&>qXfSoO zE|(>PxLPK6mqCGLnGY@hPe)T zF3VQ+CSW?jU{STO=PuHBgBkf(;TlaN2{0f}rWZrk2 zL#s(vB5k6_eXd%rzGdo^U6U<(TUlDo7HK^~(W8mwCShB$a}Lhr-a`FXe64Ztkshcz z-khhmxtg-E?P?x$yr`E4eM==BA@A86jlu&K2k4!M&^PdzeIh%zTyMdSLF;4`W+wt+ zEclPc(e9xEV63;5WLh{&aTy<+Not%V{U}NLQIhndBtbh#KT48*lqCHqN%~Qe^rIv( zI!XFblJuh_`QS|Q!KrWcB0DtwKPF;K3;*&&WLmh)zwZzXq~+Fu^mV|c4y3OG>FYrH zI*`5&q^|?%>p=QCkiHJ2uLJ4ppwZPqqpO3KTZeol{|_W$tk(18CCRSV)4>7|9T0oF z8Uxpt?%A#;b6(B4gY$XP%KO}Bm;H0ys`^K$>=W`;50-yLLZ-W#W-cE&YK2%1W6`mx zrLD)**UuPPS~_w@ef=@5rKZKUps($q!y6lCd9mr3!=7%KDjN~iA0tm2XLI^1AF(vg zxpZ!Q{oG6E%)LzZI=pP|w3Y3}#qBGnOf{VMP$7@v`ijU~%3S>fgLi@AK+;w?(c(2r)?W?j$M+hCc(NGqCLKlNKSJeYyiLUu8J- zvTU(TY>>uLv8;_0H=_Ewb*zgiL&W0tTUk1|S-wPCN{em}%-`_f$}uZWIHtVF;&M1* zB?H>#4WEDA>687Y`TpRcN6ngMvIhJ;Mc#?uxNiQalO_%-OFCW7^0JOo&YE!g_VpdU zAKj>F=9|nXUGnV4>G8UwYD=y5XkmF_bo4n7tSfW}8wW-!BZZ#edB3<|OrpHDJmD;D zm@>Fv`gJc{IU-US9nd7Bl@rYqtu{0#g;?Kc_+*I?89hF%Tuh7s8qq1eHzchbdLM|c zTaZIMS0j)lL_9=XMqvATc)zUgp-+^v4oZDDvO7d^Ll)SQ6?8;f1zj2lkHELKMHuY zl=H?744_I;hZ0v74cY#E11-q3oheefVZc)Ynky@3K{idbo2v z-|k$`HxZ*D;-(?urXk{{A>yVX;-(?uru1$aB5oQYZW`|xR)Y;<>Mzp6+zVqyHi?_VHe*L@mEgpB)ohNI*iUhUOB1fNj>yit8 zalz=(1WRr`^XN#=wUNM}S7OIs{=kYWp1@bMWGwz~mJ}lr z4Qj0R}3)GW4G+ zA#znAc2@fJK0jyT>aw=B_NqBooHVfgJI{Ulm`ghcPrBsirw?8@dtA(H(X{KnGhoWl za+lq0oi_8TRYyl$we5??pZtT+fqM!VHo`a6(cFVMHbq|AA6U~O_MOy>GJjwnU8#nb0ko$U=VZXmk-*Po>QM4B!! zyt;9fbtp>*TW!yteCWQDpJnOEPfxR5D=?GS*dy6;5Gn*@#ar5VGD?Fw1Spxax9{bM z@?@K2z1bU!_{iJ<@kybMW$_*@DogoLV>+2uGskkrXCIg@J#?-m@Y!*0)2)X(Jrv~N zfxLt7&MXW0%md5~-mqBk+fC=_>!bfCy|%24e(*77b;x^Fe62oY+s0UwY<{kL4@IQ0 z6)_rH6ic`J&;%L8s7c)ui|4kODb)tQ8Hj7c*)8w4J{wC)zhwz|h97$NXw&`SSfSr_ z=#7Tz@=EI)Ztth$hT|W-vtIMX=*|c}j?e8|SxD9s%JupjL%dXhpU@8`BqH5OQdNtI8_Btf^FYoMgvHV}F`6hjCpX66 zbGEwt@cBuyEJ|*hA$y_O{9eoP)7y%Q+NK}ZGHmJ5jg3by9oBN3ap(BlokJ7qri>j? zSU6(rl)AcU!;6cDPcz+BJ8f8T@vv#N^|_z4ysEKt8XIS~Rn^W|)84*%Mr~EwoQ8%u za=p5}ea(#8=@nyU)z^27sVEvgyJhI?;YFN>ws5W((@|ePYYdL5TIRx@@0+Jke^)E! zYCC8~$k%|hOjuPi%hf)6zEk|2=_JdUZx&uKMw!-f; zQ{VcjZ~fG_e(GC4^{t;={M5I8>RUhct)KeVpQ~@bej@rvvv4Ilmr=Kcb{Tq>aSna9 zt@yFGXqUT&&t5gAa#)_#?De?|V}s_l)jKcoj6UJ4@x@0a>#}O;aZ4tC_Ts{;=GQO+;UMg+s(f;-=tf4W+JgeD)f|nhR|_c z9xJmkV|)%jeq&@aH$E5F8^{=Ko1LZQM5b6owB^XVX78Z6(Qv_{p@SAL>}+V66O9%w z969Keg(o$9$$fK8eg5#;#D$pSu`4Ab{q!uh4~A$0!u3|2;?l|fT^(03?g zdJlL(TQ|xba`b%YV3}2RCH=q|aF5o`I`q~gQv4U?daJKoFbZP0O@1xl@UQ@^L-RXA?okIdDc9ARQ_TOcN;hg$A;ZFbp_ksTtV@C35uumJ zOiAJ*!??-vkkF^usg*iq8Ye|@W+#bUt!*5uZR}Y&w&zi8s>5k!>sf7j&;1Uk#p1G= z?lg}%_~^k$&0`MD@)!7g`2o{Crh5YU62m_A^xUFM*83<%*$xC$%3}2DTYK$Ow!uKv z*fhY*K4B({#d_aAKa@I(Ws%q+>`r_K@T$+PR4kvRLSaSAz$Rzv1DRu$8x!U;iYHQx zJ<+e->p#&qOu!qmT+0z(BYoa`GUj54j4`BOEFvod304HUIjH-+7?lV1Nyc8$co`*; zC9I$PcEL}FEa^I_xIJNEr|H__o9;HXclM;r=Q{CqIrjK#mbAECO)mS7?womWr1|`V z7iaOj(Rzz2(I!#@f|sm}TS|WY@hsyy3|90kfvaF$qQ{Iiq;l5&2w&tQ@C-{WA2w?F zBJeaiQe;fsy2o&+PvrW7{}1l4^K;=H4XVSqB)inYoCcaQJ`;>$4ur62(4uQQOD2sU z8J&32kTaX6tUIPwOZV(E7t78G|szV`cdsVugo@^b}b%ocuz}OUi*7b9}x_$eZF@9HQy2BSMWIHosyRtxG%%|NV8=D2W z(^M?moY^i66hyt=D4U%bo0;*naa}xst<8|lV{L=Azu8VlgTL4-K*sxZ+X_{W)o$)t zU^^YxJx%@GW;0FB(a9hWbTT?DX@%*_Doagnn%wh}E9jZ=*Ys$m> zBW=%M_oG5ysfn@WvMnOpT!=pmRBkjZRIdxz$VrZ{{RW54WU@PMw1*s%-<@x>S*_=i zl*wj0*J^$8@RY$QAoRv2N&7t_wFO-c*_m{BdC7hZVheM=UY^O0ko`uRhbczM*%w+y#HmdIAL-}D^qI#Eho$e?jXqPMN?X=WzBI`NGsYR4 z4WFjwh)pXyZ{3)got-nsth4^(8>h4%b4>fmYk9WYHk3`P|AHj_hyGgU;;$797R7zO zcu_EzPWWwC<*u@RTX6Dx>!aG!wnL=)|Bt`c`KkKWl9EyNsZ{-_l9JZ?)Zm=ImhHrn z5jBZK&4`lH;WhDi&G6Dbf2|su&s1&O`gJ{~Zm6l#hJ;E6mlTg2IyhBRYZ@9Z8&py< za_Au2jF#Hc5%tM*d3tC~$w)l{RZc~K9lhUlP}Q%mRr(*B4xM81nO?9gVI|ig)^n^|ZB4dCw#RI*+MDc?95Wr8oX5Dn>H3rV zdXMrncwX|J>V3_()_1S(Wq;KFgTUOt?ZKK*edwytp0GPIAaX_Ip6ICPUD4-avtm!h zpG^!%wkLm;_im~%wJVj$KRy391&M;A3(hLoSg^C;V4=ToV9|o~S;eQ9TvB>N*@W`b zDgqT(RE8=~ul!EcS=Eg-18Y0#R@R3ahBfSKyuR^|O;elhXnJ=*$$%{bo*sDI!0Y+@ zta<&Q;|A>;ykPK^Lv9@M>Ch#^rVhJl*u%qK95H>wsUzz~t{C};))QJU9JOfF-J||6 zIx>2~=tE;Vj`AM$LR(GS&)Obpd#dgCZGUe2Yul&eW{>~=_&dh`Z2UvxpBn$%_*cij zGyd-r)=v1=gl|u{e!}e&woLfNgm)(vPOOA#!)^7OZ-|NUs~Xz$URfuRmed39C-H_=KOG@al=4 z6BnQO$VrKlF7EVqws!72dDqDwFRWNNd(mTyr=2oz$-*VqE_ril!_vu1FI-l??7341 zoqE%$@0>Q|wDV89VR>Nrn=7mYMZ)~q~s9JmNL3%FbRle$`f_$|Plz-P>gDz=@bmRr#H`bjxR$F`sdcA%LejK9sDhUJ zbVyo0Qft8DKGSb9|Kxlc`Txco0ryF2w)q*Z$Emx`-%)cp&oTF?xu#20q4`5K#WGy| zh;m=2{V~&ReqP7pVOxv(k=zI7SQ=` zIi!x`-U`!oY5{OE&;M5PwtS$5m?G*9t}o&KwWfC|->GVg^?T|v9lF#kXkVk#U1z*xz>3h{Kx|QND9v^m#HU(?q3A9 zN!*7Q!iW9G85MJ~L=#ss@LZ^w)#o$X!cqTj%yd{6ZRplIFjFtC>^L1I~q(<*JY} zNq6Y6N}AvvdgHp)`An-lRqT!Z!5-#$IG)W6$qaX#ldZdQ#zbi}qRof2I_a{oo@GV9 zw1jas?@;5kzd6kKOqon3i`iuUmQwePQJu{DFpjln&zP#lD9nOwa?d&1_v{a9ccqoO zMt(KFPCu&;?&_#HNcAuM&k`sEBm(Zttgns4E9Hf~T zAPlM?VMv7t*>foK86RU2!l;T8##D?juHu9VmB{=H&zB@&p2{P{yPGgyl3H;Q%#&aG)AU*sPif2dP1szu_4+m~aUDJN=E3 zjTXY8YAE3_H7xTnb76-Qj!+{AN2-y8t*Vu9lp2-!h*{aA3CE~0gh#2P2*;|inGcx> z-bOf1jUybd#uH9Z6A0T?d*%Z*QB5SAq$UwgR+9;*s40X~)zr-UOwW^Wx|&9Kw3<#h zLmi!YkJ+a)2xqEe2xqC8gdJ)Y;jyZN758VeXXjrTk(o_67k{n4va;k{!uiZLI-rhI z^9hev#}S^Ojwd`(osfB#4LMFE>{KTaE>N9>C#wa73)RV)chn-akZ`eDM0ko?Ot?gy zLby~d$-J$WsilOc;$`=?I!&EQxSSO?-@>_TIpIpRf^Zf7r*Elms8xigt8ZlXtJUgs z!Zm6&;aatZ@C>zj=+MXA+*R<WVolSVIIw$jnI*)O_H_)r|2rp3Q z6Mj=&kok-Hmii{)h3Z>`7pV&gFIE>3UZO6}ysj=)mk?g2E+t&AE+f2LttY%fU7p#e zHn7UhK6RzqK=^HTW#6Z+Qs2(}S$#)cMfhFy9m4Oa?-E|EzDKx`KBm{uu#JRW>Kejp zRTm+32H_@kUFKDKhc^*^UtLf513mnq`hMmWb%Xi=;f?Btgg2=h2ya$565gV2%Dk*@ zRW}pK?)^>R!U1srv};S6c}GOZ_bKf_gyRPqe~ss2!O@o5k9IOCj6y(B=ZNgOFc^XnEEB* z<7yY-6Y4R--Rkko?-><*g78;rH{nyPPyBoJYxS$lbLuzhDZ;1KuL++~zai{aPZR!D zJ(Jn1_NZ>c->KgcKCAW+az*%@dN%W{`n}pq_y_eI;UCrS37=Pg$ox*dp#DhsqI#b2 zPwEB2m(+`dFRMRg_NZ6XON6hgmkD1}uMqxOy-K)Gy_Wf{dR_gQ@Goi~;T!68!Z+1l z2=^0q)6@S3;oIs>!gthu!gtkMnP=1i^)}&O)jNdmsdowAR|g0`P=C!ltv*!m5q_lJ zC;V7_K=?QHA>rTEN15NKPt?bR|4@G;{HOXm;iu}8%&+Nb{RiP^>Ys!M)u)7q)V~OO z)MuHeR7M>nRM=f=4X4{i~^c2J_5VV$#Z62mDem*tC^`}CX2~o<*-<|ZMSeTn{ARHKa&pcOQ8SEZT4U!Vfu&U zaF8ZXaoCN+rk}`&WH=mTVI>EO)c+tc$_kjQX1mqpq$C!(mOn{M4&Jcy9x>juyXA)6 z0fK^}83e61W#nv@@|sN$$K}!KLiwC_p$o(@agjTucf@9KQbcHDcbFOGbvhh^13OQ; z_>Gio&_E8IE>;uN61so|q!c_MfFx(OnVl5ELg%ne$R@8^ptU2Lozt#A#S3gcDF;(I zICPFkl6t!R>7vt7et}OQ30)jkw@w$qSN;q%%@&Yw7E;u;sZc@(Dg+jm|7-Tg&1wEaM zB01y(y>*OjW*2m@xD2`=Cqg_Dwg~!myGthn&zqeNryO=TK(=sJKU_M4<#$P~_W*xN z20(X*&Epb+h(ya@jxN06gf8SK%=JnV4tTBOBnaBrk&3cI6rC>?P;hx3mbje|7(;%oLk}Ag$bkXHYenGNC$3?EaZk;X;tNdjZ z5a9$ngD#ZA>605EL7svDV23Wf5A!Q@@%kA4q zm&?Hg;N>9%!!C3|yvRZ5B2t80i)2w|(1ZYznobumVB`r2u%MKX#YV!}>^!=72will zNG@`~5y9PNbBo}UL$CeO=}5+u$%*uu5khPPf~Fr1;z(Cpb9WF25j! z;v*^02@X*ZyTv0!KvE1nli!U5tqzNq^sRbewJ-=J=H2af+YCDR$N}Nu@VGs4I6VBw zO_$KaZud(0byVfdq0^C!?Rd-}y%ynL&@0AIB$_{RkmLxFZRjFpaXMT$w)wq27rb?O+(F1Cbg@Ghh~A$r7;VY|Hc}R| zRg$7Y@!1?Mo6lxP!K_a72}1$CE+nLM$)`lTViUTAW6Vp( zKDga}FQ(GrrVzmMT8FWT&J*eIjh z4LK>ZH6ZArSd<0skPAr)-k9N_-RZFh$qaFFdxb16@E6)}g#G$cybufoyKw@F7pH z$LG+MR>5K8QF$D?BvN>Apa(u*C`e`J@=;lE;nPLgi(?jXXT%=}hIk@mN7`edFgSR9 zA%DW>^CPvWw1?d>u#=$bv4zDpKoPGeB(lbekL)haVfWZ04!6${Av46u>xV2(H~2dR zeZM~z)Su#oa40N?FC60FrqIiSbV?|Nmkc<3dI4Dlbb@>W|9f&?QxfKMO`M5Qv7U-&mp2VdcW_5BPa6 zfKVgQv0yM94frDwhbQDqMq&YQ2tjDl4<9Vww4 zkSFL3Bf&OE?k|k{JwA^}G=BlolEdi;_@mGTeI$!eA=PCd90@>lzdz)XWCF_P&ps-T zLzjXyGhb}Nw^)QmpeKkKprBx^3$xwM*_{Z7BG4ulb9%%6yjVOK5BY<*D+Plg)H~>Q z_yXR5-{}v?a-eZR58)4>XFjQ%NK!C&`W{E3qp1}G4MEN)LU8exH8IZ_e*DPD-j z;&KGyQ4Y!?^k9tAD`XI+N(LMhlEWA9g?tfj$Y=LEV}W!c;PHEcA+P)eK~blRGw6>) zPxO&2qG=k7!DuWP7NSSoI--od9!{5Z8RKgh!EiVcqki*-X+Kd=Lz2T`hl3J(QqgD} z+9VP#e>6~#$P4F1g5h{H9S%oO?~vCS2>OEo7t-ShIPwHN%vvyz@CT^jT_KxG@OA~9 zNw+WTPLc`Dl3;`?)8hkwXd_2qTz`rel8HPy!g)d+^3d@Qq;vt6(n|&$VLgOA(LmfE z2|9wVM6fJB=nMMr4UoUE)HEC}S2&o2E|?{TuKp|mbSbaF_tx(5MWY3I4l3&??MiPHQbuFKM5mL8uP~9w%a29#^WDKj zxFo+Y25)1jM0qS0XAk(8-yMnsAzv5~2ssM{J%7L(38jJ%%k7TYb1^I64ZC6b9iX)0BiP9}=d-f(`jB3+U!NyU;ysp@1h<@I}$K~E%( zTKS@&8g-S#u@AwJKOQN971&IYl+-YsCB9J7S3)M#G4T{_2#jE1VL;GNr78=P9AaaO z(j6BohSz5KJUgEYaII@zQcp4TBPlr22!YRB75pRh)AAo!Np) zVcl+mU`1g;x-^wnQtFEqCTdE{Q{@GTR7qidetrRFFBS5}lF?+sA5Xg7ad(-Z7m5Uu zu@YpCvgA4ak`#us+#gB#%gKalBw66``Gb+-;^Lq#9fdV%{V853D=n8JRW8)Y7m<;p zJSx-`_DcpFDLsrOV}-GFG(YZ6`bv|{mB~mVl3x&&zf`s=_xX@*3OvmM~KoZlBg8VAv4D&=eN{9OWo`SN9g5r{rg8Y)O zl&w&u@}+rU972~Nt@+R;7%3{MF82fju_DYs81YSu3>Ou7y~HB*rKJ_s>7uIYK(Z`< zKy_`pwj@7YRXRAGEk;&TA>d2bSs=!m(1r7J(CPLiu5qA zAg?4+^|u$zlwh*?bN^C8O7rta0UD&^$!Jl2Z7N?XZITp)2o?q#!pV|w z1DS-w!J={zm%Qrgny83HdHIlP{V85(sB4g;q(P`tiYnz05IQpr_JaxGRx#Wa+1 zk3*NXDW!By#gdhk%?&hYQn$pSv zwPUNQYS8A&yhw3*VR=ccq%0694h%sx%2Nf2vf=?n#Zozuq@))qjtq$vRK|ux@+xDo zNLfuN97`57H8my${o2}5jUpamV+S`6mZM_u0FJ7v3TzO^kV3&g*hvO*RO(@IS#fP~ zV_|hkpe)i{Hf2~@L1{r%O`-f%(Abb89Ih-IjGSSlC`ZGTXf#mS)LaSmD=QlEDl020 zDpgs9{;2UdbeYmo!4h(b{JOefgM#sRVI5{5RaaM6Yy5{olsJD>Q`6vKb+to>#YzTN zj2kwxeq>{1T}#vC`ufIrDqdF@E2}Q4u1Hi=heG9{k=4~z)rIL)b$Lr^Ih9kq)|Vi` zx_CvbHCbGnY>gGvC6lr0#z-ugUp#p5ko+e77(ZB^5(_(G*ho3*Mz(O&*VpU#m$jCl za}`o&S5@mrogS7~l{b|SE@`L?RmF!@cN|rnu1wcAmdIbNB&HvA)gv(-*lBVY)Inph zZpg5@0nN>|HO=`tQ&d$=?pe;zg+sc(rAt#Ls*6Vu3s-2JoIBJQ#^D)*XB7MbmC@{4 zQX8O+(`ISMX$!Oqw2h`GO;4F#Hb0tizMdgi#y#GYtRq{nus?6qfK`|WGp zuRZhHuV4G+Yd?Q&%WIQfeeTuYz4FN`AHVYMEAPDW`YW%!^4u%iU%B;_oBlNXMV1i! zynljT?*HdtyHa&i@B^GN_h*{+oq5}}%%x1xEYO!oKIz1I+~Vuf>G8|PZP7ZpFx7FR zrkI$yEq+^kEc!kF|%p-+Uvng=aZ#5p`A#2@~^cHi)jJe0m-SVw*sV!s1%}W&* zr^j!3bjI8*kB&a&r=zc;K6GABPNmhB;tPNKj4RgSB=aVlq1Oa zEgEOx^GXv{G~$|yaAm|z%BR(2<7Ry3hGyd|E~DL$ja$_WZA&(8>vtdDP!!up$AM2y zXEyHa7k62Am@dfPcdI5xE`5($?w5lf+K8t;^aP$3Q3n(#Sk!XL$m4dC9%Je%gJv+?Ozg}=lC{3I4}XDVJ0 zr*X9ge}^=FBj=DFei!*VM@p!c16Vma=7ahaR&1RBAcb4YIusR>>y(H(Ghb$a%dOP)$o z4x#31&Wm_<1?Sc9Ro*>C|K)J31+Ra{_lB?d{fly6L!JhgMJ98(O36>*7m==2oX5X$zKiZj4OV0|MlGbXlHzY%3=o}qyu{a%Bo3c>PaSbU6 zy@c8Ztwft7XQ7o)bPe8n@{3^|dH;kC%>QvJL_FPqRSXQ>zK`7hD0MVkcIqe!tY577lf zh6Fc>Nm+8#T%*6gShosC>gsaxTc!Udw&OJ36%H&0i)Fe+G3tUbdF<$ye|bj76#?pZ?MzwqMF*XtZ&423W1t@scM+%UAVsLrNh}EkG(IE#Yy0SrJSP zs~}n{wUy|BNQ|@;){@$A@ld5K^4FlhEm~n%B%zvEn-x6q-+lgYo=Yv=c$oD)>4-K) zSmXX~f|9jX=YwG__3rOm*!!cX~A4Lwn0p7xYv17|Qi~U;yXO5-~HD|cM31=0=&12;7KucQz>5B<#=aTf^{`t54C7lJ(x7=t>1xoS`Xqo zV+fwrL-D8{PCIKPUkIb{oF0SS9E;SAJf3G#>v!Pc zJe#)JTs)fRwH9?U25h0&=NXl6WRFTun2A^dOO!pHYJc=FzeXYB2o1<&3W@dLgF zkIRqo>D`3a?_+pO{tBPe-{On<3_hrD zV@<^W^mlmDF2RrUYVkA0<8&z=pMS-J81HASG#<}r_bu=fA7^;F279p zFH`pYS^y8!{dfUCul}qB@n?MrKi1dqaebAw{qDz~_d$GjAIGD2EB>|@;f1>%pWxki z={}-E0?e2Kry2i~>n=g7jN>X%xCC0Jt2o=ec@k*B4! zd{zi3v`jyC>Qws~E0?i;epB{5&VJOYC9760KFz)$dmf)XFE-A$=?fN~v39X-rE!{N zoYokp`NruS{p6azXw}*U3l}b4xz=?~Z&c4`VB0Xu_%l|ol8b>uh75BpS-oK0;)aC_ z)-3ieTDExg;x)_G=vVF)3l^?kwNj6}^i=hzf8ny#3(r__%JRi$89yyt(EHTMs~2aJ z^7Uq_Kjd7!Y~>Q;@wLmAFEX+VEU)RU|2SUYZvl9 zPMO9{nA)Ly%NML&DNBur;z=J3r@lCEp0;@PO64;`ev{u>4ww|>>;OK|pI;X$3zfN- zhROnaf|mvM*yegJ2+#DEc`nf2^o(@YnYMc_Fu&rtz;eCi9nVPHT%5M*d`km9_fnqP z5u0Oa|yDoA4LDCFf7QD=J0qK9_{wR2v`y;s%p4s;&`Skl6 z>CyjuOFb7zdbvNz#rQMw$X)qjQU))}t$U~IzfdmulUxO>z#b!%Yq=Aa)rHn!iNpeV zd##UH7qKnXS(}oxCr4Tnu_9tYreHgAmgCr7i*X_vDs4H@PN~gBBhN!8FTz5I{kRN$ zxdN>aeYg%=aXngf1D50_^yU`q#BKQE-+}i17#+F`&AJ=Q@n5>OiQa9em*r7(?lCm* zNi53KSPt<{{{!0khOW17VM*S>W*k8K#2$TuclRJ>;atW1nyJjInaZr1tC$z_IJ06N zN3IH)`EnKWSQ?l$vXwa_TbVJkmH8i!GyCIl=6-Bt=EvjA``F5?kH?wk@i;Rk9%s(O zRm^y}iun##G27uP<~m%(OoywO=WrGC1GX|dU@LP2wlXtdEAs-j;{7ka|5y#qTY(3G zZNPS52e6ahegQlLJPhn2ohP{eB=9uX-JIX1><55P`E8Q2_Pn56fEVzCVIWgREi#BX zJ>AUc*}@#2EzH;1!W^6}%)QydY@6elWiy*OHfJ-prj^+=v%&aPFn$$`Uj@@w!SYq+ zu-wKBmMzR&xlJu6?G>cE3Rq2iZDuTUN5(Qwq>T9?W7T=wJD>O!Jl_Re3tR_m0jwC`0lsd4uN&a&2Kc&x86w@x59wxhNH=psx|tc$&AgCqW`%Tv;XW|j2ZsB= za32`%1H*k_xDO2Xf#E(d+y{pHz;GY@-N0OpZm`@3mixePAN(zn4VS3Ps9(0o1 z<+>hJaIOLBGegPsa&l#B$czT9s-aaiw5nzn)hP6%6aDCfZq?{VC$y_ZKRTHc#fsIO z=aI+!%vxqaEkTl|G6RYkkDONlXY%{moX-dTogQ7mJ6*uFz;yt9?qGR2SY8e#fm zWD}Np0=BvZ&TN7+x1tHRq6xR63AdsNx1tHRq6xPme|zD~UO2NC&g_LVd*RGpII|bd zbitV}IMW4Zy5LL~oauryU2vug&UC?oY@O!y5LL~oY|(&Ug{?P24#N}*bg3W0dGU^cR0Tb93cKa zzkLLJ41B`9Pe~7JO3aygq#w67!ma&qYa`rx1TK}sp-14%op59u9610-4#1HEaN|a} zZ~zV*fch_Hsk|R5%N#tRatl;$fx`Qta7&iL`=Rh7Q1}rj{0J0&1PVU_g&%>!k3hw3 zP;nbn+y)i5LB(xQaT`?J1{DuL#RE|B08~5x6%Rng15oe)6g&V04?w{KQ1Ad0JOITW zfnwXB)&Zz>0Qo%tmG(oW{r#x4u^*K-LZ$ssX+KojpQX|x^f(8Y0ac3pRRA@>KwuCs zff<19z(imYe3{9)1DJ!%&CBe@66{6>cO!dGL6xVV#8b%FQ~G?sF5bTuxDMC^To3#J z_$lw-1#AZH2JQjw2Oa>n0uKV)fbGBz;Bnr0g7cHWGsL?&zd;^v0`CJK0UrY)cs&I^ zPeCiEpp|FC_XGZ*vr z#d>Y>?`j9J^l$Ur0l>mr-Ml4ty1CPht)D;*-wsR!W&$0+Pl3CD&A{EjJ;43I1He|` zL0}uO9oPXp0XzwG17*lEi;rhZ7b0E;Okf6UJ1`N@=d^OZi2D};QK0&J&!U1iFD7#-DPZuUBR@Rsc1?KwuCs0qJT7 zCIT~o4&VyzcLCP|*8!V=>wzBtKjrtkfX%?&z&*hIzyrWm;6Y#;upQU|JkC2$aDEba zhIlvU5VYw;r#qoZC*R2v_)?yL4X)xlc>?t4gdUyHqZ4{`LXS@9(Fr{|X`fbsV<+v+ zDy&8)U+qq0I>*fr@iO2d;9}qs;8Nf+U_Ed-unWj>{Zr!A%E~-QC(`QT?4g8S&VGIg z0wL~~0WH)y!_cY`#7EK^YNahWn(Hw<-w7<|oz=j3z(qWBF>ncRDR3FE9+3IBH}mc; z&U-mOM;dViw ziknGsGbwH+#m%I+nG`qEcVVSZ$4LoYoV|cpo&ZuL)+faM0;p67NKGT{_cHF~+VDne z%xK3O?SW48rW3vCr1m+Ew!lW(0vpkxPTB$+(W6e<0voA~zDqk`Bc;6oI&7xI7gORJ zuy#qP-wE|Qv3g0YUOiT?o_4@SIM9jptH=5!;Xo%6wHAq5i$twOqShi&Ymun6NYq+% z^~>A+|Gpj2i5_>N$DQbLCwkn89(U3X*oZE7qRXA=awodni7t1d%bm0XHqs8*NIPI7 z?SPF)^4e@WK)w|^(eX~&0UObC`CjNmVmgtSPAs^wQHWu|lUVSiZo%K@w~v62fls*i zDe19=G5TO|U>;{wFV6q#F zG8KuQ+D|j5g2lziNH>^Vj5NE!W*yk9L#o|iv<}I3gVj2)+6`8_!D=^H?FOseV6_{p zcI(>uIOk^oLu=Pj!gXi_Yor730Ph0tbMGVIW8f36D=GC@wBuz;K9-V?MLX7^8SBuD zm(hfmvnAd{iT7g%pTeGWVh4YZK5nA4V<{zHqrgQxdogeca4B#ZupYP^xS4l$ao)@M zIo|yP@I0`e_uc~DCck$$zY84DOEwm%c$u2s$rq!aat8P%$T`GyDb}%!a|P!bU?4CE z7)A?kI4}~K8qIlJW*3sP8Ohm<AeE8o&%p{ta9HYJ};$!AmY*_3=X zC7(^nXG8Nn(0mUx-viC}K=VD&d=E6=L#>pgwYZDc;x1Z?yJ#)$qP4h-*5WQ&i@T7t z%}Cm2B#pil;2z+9-~nJO@F1`a*beLfc9Gv>y!SY1Kf(2rz%#_VIqxN}Hz@0yz}wK_ z0PsHXkARPXPkDC;yqpamXT!(YQ0!%TB=$h9zE&fvhCnT&<=Dcv(om#j7_IQ(*wc|{ z;b`LXkn!Vz<)pEKG*$ttiLZrsX8>n&eJ{TZ1wMZlx>+f=zA0|H(BAd?^@#? zJ^s>>sw#|d`LZPoRGks7IpZ5^)IcND`y(YG){oIc882|qB3YTec93?ya%&Fhx0XKZ zTyM1&q}N%aFRzV0^3&lbWi@?qx@FSK|xF U$W?y#kn_3J31@K6Y>Y|#e~`^thJu4^?KXd)@p65zHhBNaSs_pLt@!$+Wn9tX=cb0c*I&LS3=N^W;W}4g6v)=V?I!q9^binoE zuFA%q^*gU);rc0pVE!llZWpkh~u{r1llk>xgn1DTy};a?)V(;k65;5bd{v{ zPA@^+E`#6Kj}EP0L&Onb@IL&zYIJhOGGh2{saCL&Pw1cBNO>3PgV?RHfd-rvb)ky5z5K-(K*>^q&;2(|6IoGTu+w8 zY?9dHoyexQdEpJcg2wyH#51z=tZvY?|KlVH7F% z--=T9vcE*rY?VeWm7`nOakBwUhtX0d8cij{qT@y*TZx`ktE6&vl|!dvw?t4Vg7C_vF~}+fo=PKKR15|DM`{s<00Pc)Q9cTpVo0k|L!m$JdfXSQG|H{< z>1CaHtBcn4<`%EJZ#0@TsO|A1H+jQVT9v)9r);=%+i-E^jwjbR@Gt1g)P^OwD|-(w z$@ahHs_e;H+_AGOMJrj-;?!7diS}@c+-*v)9cyU1Wla_JfJXnSbU~?2XLBbo{^!jZ zHDgWv=XN$R@2CvqV+AewZiD|;#y7m1d?dFqKgmF*(77GsAaIH8vwvsunB#kCe8Jnd!RP5Nv1j*8mU+5L919}Se2$Es z3RgsGi6f)CB9ZKo={03n9@3i2>4*5ceQ@{2z}?08?!<^Re0O;wy>|4@v217Es+!R| zm*+Satg0*O&X00;?;9xU%8N|wx&bYbDJ~z>qnk!gjlu8ZHKTXIef6tq;l4;7)-q(=fQw1o&ZLhb6f*9;nKd2E3;Mv2L-#`n{OoG)M{@=uAf% z_=yLXHw_DW5|bK+lox&?-}H?waA%V=X{6}zjQZT-rFDtELNt_BrXf}8B27o--x|Xs zH7C=@uiIBsv#me3V0d3+W=8Ik{cJ|sf<;-r^~(nn*+Vt!T2h!3?)tG3ISPxbDo99a zT<)v7sg7-`Jz1mF48FRM{Xl8>p{L7dPwm{+)OKV`e@yia)h+u+@~%8yzO*vlR?w1; zUXSToejP|AkhN$jCu>cCwTqH=j$jRyrlArP6gqJy`!!k1{1f!Ol6Z!&!v9mr8JR}R zXjs2#5yzjj7hg#=B>8upEz3sBrOC-fE`uT_yK{4!Qz>uX(UFW^Xnyd4GqrM=Tt$cX zTzK-4macR6KXmb@>%yfMj{BX(J5=tLAj{X|-NKQ7Dqy^DBLXPNSDiBu~g?6eW{Sq)f<728~6<$e3UM z$`EDH8@MqA3D3uOX>@9%62$bcU>&=N3$%y60ag)BOat`;EIIzCK*LBu!;o;4a~j4b zwNZ8>7$rvX883QF#x{E!^4L~6I-f`1z!ulAh3MrP^ddZ=WR@a6C%zBzBgj8i%s*D1 ze<b+*>)F0_xTxx9ObZ z-}Nq6y3xSAHb14)5_bcrx=YK;Kd8v|#8z%h{+NLZp6 ze2B{OA%kE&B9K2ZBzd9#&UK|r?tgC!cYNTzwBaWYwC410uNi&{jsx476ScRzd*pZQ zGrwMePu@p0zg}_q!9_13_iKBeyRLB2i|ns|y7z}$3jt!6!5024a~L4z3CvfRo@fDT z@O(A=d;uS{D!d5bn2wN#0$d;xRo|>-?@_4?QVV*q?i|XI`4emD16AzD za+M1$zdT)w@mURqQ4YW<^E;qqz;8A1Z`A~$6dwX5ASw{W9$S`KYQua8mUqC)=FGx$ z7$AREzjrvlaOqS%E03$OlVdT`nYA=h%Sl`P_P(st#%1}H8y8iZBo>X7PP6v!IK`Yu zYTw?r@Wj-vN;Xd>v*p;778&}qV(YdWnkt6N;#_s3B?c{$_T9838?R+8=#e5=OD$0m zfS@Qz1&o{UT1vu2qdU`fhRE<{KTMu3w8#=PANadC*ltxmM)x4%@=)`EQqwAJc@}ZL}^HSK&?ams43i z+Zsw2mBhGeM@xgCAi;Jf=t1THp#%H9Bmj$fCW;ipLdwGeb24v-Fr56kNFX?xupF}S z)+=6aEh>O-^?X*7S%?8x$uYKQuY3HoD}Qq3+$C)CPR>XGN- zTr+RM(?LTM*dUa~;X!XJ~TdET~cK1vi z$(ts(GK);%tRpseXkW|rR}U^Q*;B(^nwW%`;&tbim#=C{NidS@fM#~WN{q0QSm4y4 zycI=+x?BsxfErRNMH4y$if!xAqsT-L$h7t1JI+lIrax zHEe3-hR%%Q@nhZ9>spd4SKkDX{9mAmGcad^IAa+GwhRLscmvNE>qy>C2Nnio=XmKe zG?FtjZ^^9sS}IMZSIoSrRLhttyCzb8`7df6L#r)HwF1bEB9;MEoWOkvpqWGLxKMY( z0B>RD+Gha-N_j4G1sE${Lt_DJ6t8)KD;d0FRZ;HZ>l;_CDc}6SvhMwhGTn`9YKw+z zTule2m-ZeXFD_oZ(VH^R*IMjI>)3Md!hOBT3AHP#+OO}=vQ@9tW%liC>b-GUna*~{ zSjVm7C7$k$6_uM7R~t1sP0P!don2eBz_aLv_U4skk=ppYmX%c{%N8V(Kg%DO^x=>| zR?nuYtijr3?5lnPFztgC#}HW}R73Ty0z);#e8-e3<;-=?Xu;MJZ^`oHKsL5qKj>*b zcyW2>jl(%H1zldYRv*`aK8^E5mp_KOlA9*VyKWsXb~jE`4jfyaNA`L8_cSkibZ1@O zvYWap*R5V(<^RA!);Sy8<+bR!inXn&`J*>?RgBjsmM!0hXAD{y^--^aj)?_%Cx}E* zFFym~A{taHs1#uS`8wJtxFLMNWRAvO_HF8$s+^($LM4sADpsY4^ti&D)kB5tlRafczQp^!pHk&3X&I|cug{6H zC)rh3Mg!;yMz4lu4a{jKi|8iCfx@O?wj@ywu$(5E;4GOtv%wj#FO2oTnVdT_!`Tp= zfi(rfuL%1Uf;UNHwGV-wfZr{wkrPp#tXyms#3BhT-py;J1nhVk)8Hw*G^1s8HK^oJ zLuz@F+2-q8yT2*3!?x3EG(@}1h3osg4c9+4+W+`HHw<~Z?s)6E1Aktmlp84NYIgSa zgP%MwShV8S$6g*=^V8dVD%al1CfI6gt7Fz!(qan7`|ER}wXx~XHq}Zsvi|nC{Dzdm zZ5x&~r0DhRx#GS!TT+<3Zt6#q+n(K4;$3$1;=9+~_VJx9l|HE009mp${CY1FIugtdPCxsE@?CSuo9?&3apoP+a>`-B9P=#pl zP;t*OvZxoQLG18GMnQ*hsPdUt+|BD3urDF&&`td*$4;@IGE+&->uM{vEv++HPi$Fo&zd6g0sn(f z-(N6L?x-zTbY0n|9Wa}{ph3R^eoGhSVmO9xcnEw2BaZV}fd9b*2!}a4xj6&50inhQ zgCK@n2Uf2_C=Q5Fa9SRy+t62*7A=$0_O#`jZ)~~lNX6uI%AbOmAh&C z;_E+taHxFpTvd2NazeNy3HU9#=j?|EFCowSTdXPNNr|eIoRqQW+0VYe?bRC>U}*+e zU{V1K8X^)ThM-;Kcm?v16^K?R__;85-tUqMH~@tS;d(oSNMYt&xXVTXxRHTL&0M(q z^fRNZ<2-tQ`)h|AMoTt6Fvjjbg*IRR!P!14efw{pzG;bvnd-drgB!QJu&?$?%s_S|gJVM=Z^i>={!N$_v3|Kon1gGKg)_*lz&m-t z1u^Z6Y-|cbo}U9oyeUuwp`Er=q~%95Pb+YhzveB+kJiC2)}zQ!G6 zUCvmQMkbR-y1eyEN)CVey@B%U9xl_yBt@d#MoMWlvx@^avcEmF?bSo|JVY5Ahs)Lgg$V!@AvzDaBHIf@Nn=RRJS61sR6d4b0~kZV z1^j2Dhh9I@KJ%OQk@F*MRASo*uxl^mO;(b};O=t(@Cz^pO3aOr_<>{yti@MiVQ2Ip z`N$(998FkeKPUeQXJMd;gy{&@kGKK`KaRok!|o7A1sDa8T>&o}7=w#w8a?E8ZSBO7 z?%dvF8L7}H!t9y$!tw56_2viL`;Q~Gny4|jIL1Ndi2ir~~n)C4dwPg+G`OhknsR!DmB zUK37LM&LUlFs^`CVc7x@V9nU-g4le#3z?)C1YkoTDwUQ3uE-q_Y_B@seT<|j|3O{2 zE<(;uP`7oTuhi%nbQ`)wX;oRmsE^f>%UkG6%1F(OJv^NHLrmC}YG#Vj%s>K{g9XP6 zMzCQ7)CgoJ!eSmag1XXx;Pbi#u0oM9cn6kyLGZW(9^WS_|M2$3+~v~ZQb z6;C{qnUbomWN5;b^y8PeSm?J?uhal+K`YFD!K?+zgd=f5tuQYZAyPc#<3J9D1J#2I z0%vxf{!L`Sz7o`$kPG2;8ZZQ?h_$O;V81@O?I(vDCVq^hcWnPD))JEsjPCj1-u}|b z`$s`hETl4~**AZ?x%cdc2cAKm_u%BC8@GZ29D9NN>%&`LK3G5c0y1K4hIs{R4Ha1C z!Ff{{HdF{Xh>6E((0hopDZxvDdE+!0Py`^}hEvR70V{z;aNNjgM>W;MkD!jX-(Il) z`N^XlpAVi`S#a;YWTF3MW@`F-<4^9cCH?;Pq7_HG_MhN1EBg};hLKeY4H-1($ zacU4;p0%AZTJ|B0Eup>f_lr)f$UA!{x!b>!nY#B>{~haVRoXEB$#AmNVjzFuzcqXD z{`OtiMsv-6PCW+HTrA?D0MkT42u+9*;UZB0(1%DC;2{FeT>L~i=!5daAq@#1z5>zC zB~p0`Nt5syKX5v3Q)*T5g#*Hh zJA5yjt6-)&F2BKeI^fPHA)`ve^JAdeL%`}h?JZa-qJR>~I$#p<=7}e0mSFM3J7?tT zfjc)gs8)`QYX@$9Vg2Zt)ddo`AgR>uUDdTa9v-H~XKvg0v*TSg+a6k)k_uPHOo^tB zo5yejeka(kFkA5Oa|5%RxB7X4OVp0w3v(hKbO4t8T)5A^vst61kdskRa-)*0ff#R- zzW_`Lt@6sSIU^z>!%W|$)L!0#<@s)cknVu@Cw_-K7cu}Mbml22A)zlSC>N$r7cb9Y zhE`+91m|8MJLiW%D8s(HDVmz5NK&emp;^YHu|zT-P&6r3OVN9@RnzFd*!w4vA{ja3 z{}h%Jab?WtwpiRo`gWxjE(~t7*=@iVpuhe{8KKccD6gbLCg(Yzuv=h_k)qC>=cS2t zB?66zX%AsQ-oRy(#p`S=aaK~i{eP<{iR%kNR*d+fU~3C;A+rX!fY zextUlbdpI>6=220QGW$U>cI{c2r3kkNUsn}RujE-%PX<@#zXW7rmU9*{BE#OQk*5cq*LTrfv43N9z z{$$x(Wo0n7lRkiUfJTu4h0U7{EGo+q3v)vPPi?=dH|`pFK@QaBh_NitrCc1#2^tF` zUKWx~Giq(lg`?|=O9o5gQd-wcoop)_^Y}l`Up>+bnd7R89jgZ_6BZiOD8FUzV0LET zu9ofxj_>HtHb>0tF5P%;1RXP_woL3j+OY2!tYR6gVw!mrWI~2$4+w_qcdSAT5kn~# z%s+}-2~OqlYSsfIP7L`Nrk;+Rc}>#_%i0vnU9-y_j|Gy?rCYf=h*d2@*5k*^;+s& z>4y78*pFS_c&(>roS|mbFEQwl_EN`sj%b7%Hr6vB^5axWtq-M zrBY$OP}q>7D+Keh`P8Awu1upnE7qorONi^c{nhcR$*v4*ygS~ihydJ_!W!P!H)ux3*ZHZ84|c9;mp!i1O}Lz8!NSte+L?K4UJD02N1KXu62J(UH=no zUH&?Zm*ibl0#<;|id%13l%3VTr?ugpV|$n6*VK^pms?9qHrzXm;+jf5Jsb8MEZuh; z)>F;l5Ra^2FAAkE0Nlxw0>8$W1MyphEOXk3$Wd-fKdmy6Qy=H%N z-O`dM_RE&t!xg%n7k4$MXpJc~RDyd!d10nYYj&HCJ!o|#Isi-A^%++0(j$HKw;#H$ zFWX&QGg`U!SgR(%o#DxiHfJVAV(D2vD-(@ofYLsj6lJYQq9csyjeYRAMt=}47hocx2gufEJz>WJ}VWagH-N;dZ8#ufME)vj(xWEg99oW0f) z72^Q3R^2dG5*{9>(30xdhM6B_R!37ZNkU0ST5?5dSWyu6EjLk1$V9K)o!wKGpio*YI$2LE zy=4BRp(YEkya%uxBVt*Qzaqdwk;>&|L=nduauJ+yf{T=|8O6i(%XTALw<^J4(V{z5 z7JVC=uQVz(200pUf&XVOXd)sV#RE@(jyxdOpsh*`yGWsz$Si7Bp-`je4RC}>0<<>5 z|Ka&k^DG_^xICq8d~D!x=F!WoaQ7g1Wp{&2$RRcb=tIE1xVm{nEi6~OW1fZ**DnxV z5=L?oc9Sj=1`s2BJy0eXfk66MW(r4Maq%Q4{sboQfiw}gAixn4DK)q`*&fyO`r46B z$~7=Lp0jcg^F@?tpq{3EjhRb_y6qJM_40xR>wa8ULj9kE{q)pBJ0{~@Et{HMQ`;5c zxre2mjYu3V3f965Ba2#|Hdg0;ku2<~;`1kREhUFz+v5L7b*Yr@XU&k-)lE#?1|z2t2&88EOqmbw1gO zp6I@LnfIn01W$%EecJEW;_*l2+Dc`~qFOHr*?_RKU^SGMHf&dzyL@;2HrMec`v#+P6Vg8nm|s1DvCz0AzU+8`D%qW+YG& z4`XiTkT!-~s9=}EPn=zvbzibQ&NZ}3w10NjwjM|>M6>zpR}4DrDM9OpJ>=S!h){Ef_Zdo%5pxIUH2gf*q({xp-leOHuJ#&Mjr7=2cF=8LPg@K!hFssc zy)SdF>rk@c>@bCH7kvkg7s$t{&w#3eIq7-4Fi$#!3Ipsp@D8%b=2j_8TVUkq%14LY z$@;X!l@ApcVIu#{y^rgA^}l$PWiT(=Ae-|6&`gnN;|sk@B2A0Y3cfo@j0f_0TU@u9 z7N`Ugyo%g-nJmr~=c??@N-0W? ziMD6eW*4k%&&MOf7LwCAF$Dq~TU{nld=ju3-2hA8X7u9v zV(f+k31E+$OJQoD6$Bf{*yw^RHKvK$(+-qX)Dkn9Hv~(0FWB*XaNN7}?Ve>d4 z2PB~kiR<#)1|ELO7$AHf4dsy7;_JIM6!!@Tuk zlxg0)g=vcO4$ahXu}2)*3#e~-?`xr(ovHaU>3Y803sI|#c@Y74va#W?&`2( zyo++?Ks^;?%epGUnSC^p>Ex(OW^q`kTN#R!XcVZL(JRZ@u1YO^2P0Lor)9cw>Z7ok zzgyfUliNatSu8W3Sd+}=BrCr%GnE)_wuH_6#tdtmeFxy%1@N68cNEt+k1oWFgRmr# zld-vpeFvieZa(lxaW!GkjW1TLDxhFdn>ZGsI|;rBy#o%saDkj4$xat z8M{uaLThDmHpBlnr4s!_t72PaDvS}3(&u5eW|10%K!G@0L4S(_LfR9AHozMoY2<>A zq0!zen#hWuv;SP6QByys0jg>lI>H#_b?mcI=mzRJwQ}aNHb$$B)lhP!0#gPwUQk6a z4~?j?=TU|j!3b38;*67$({u>nAx0dbUYFAPhsbofe~?BB8F|M4D+PIqnl>3`F4Q|^ zCOOrJbNn?B>8plFUnN*L)8KzY-6H4aY2gf4>`X)Io&@WW>pKAZ%ZuxBFej4GdWKz9 z-dn@2pHNnc>$ZUEEanUo#PI_D;7gVH(gppRT=C?l zt!3`=j0lB-lW3uhrKxfBX7Ld^ZJ9AcIiA zwP{*z?S*ib$(>PfhU-*-7C|&YZxl!fWh0vfq^p21H-C95e$jozhW>XR?GtfB3htM@_F(vxH1LmDH*^hj{V{g zV~$5~*0BdJwF||jOvorOtO)EHOPotM3GYzgU&%qVwx2dfiZ z8Lp61>{~tr@O}m?PBn0SYQUbG7l9Kb8)xh2L6L=n2Nwzb3SJKsq)}XlFgDXbM>`*? zlqghcnOh>4%bAL}9G6k(S7A?+PO+ud|6BT>F0VG+4$ZbXFppES6iw5AfZT0?7}F4B zx5&Q2JV0E|b4UVOmErLi(qzd8GH_2NU--rMSyDjmxWAIrcO6`k-Eh;-cG+>?q`PZR zS|p>8$z!sc@{ZS!*Ci>H5_80Yf$;(d1ncczx*Jwi9bbNKU9n11y86`O-M_xGhkQ$A z{9IO;8plX1(UHu|tz^6_P977LnP4SYUJZ+O%hJvD|^ap~+(^9s68Lb$+^urd`^|Qnfw1E(didD0Rp^ zaC&1!LP=MKh0(_qrA1~h+S|o?rG~aGL4G}w1uoZE%h5)4E#_A|I;-c;t zIAR+z4xDYH4M1VVg*3q=DrgY=AFibE!hesUh3pR-!{wksq@+}%M(3p_$g2JuEtIlH zv}m=2J(50<&K{AX2`zh+9HU~x{Uav3UT-(yRNBlR^C$DzooIL7Buq+_$x<;IA>^ca zO$t(3&r4=3n`i#TzB2P~jNP8u?bH(HI8jCPinf0_ruFg=TDRi?J8v*2!(YV#)-Mv} zK+)I>0J(RS?Jo(Go8n@x+(4}tNNz}0H?sJga!!VAAnS-dbvg!omuD2U09xw zSl-#wS)MpJkeHPkX6}Oib z)C|>h9(3Efe1+p}nb|r1JDf#X$%)Bf&XrY(C7vXw(~>+2tDdA^BiAykfD96V1D*j* zhBJOR&jIolkgtWK4X4}YL~CP6NIVPCTMiT`5+ZmyeY91rwnpo95Yaq{#(-9Mb&y`U@x8d>GG!iAOX`-gIJ7VT~*>MBW{Nyr|& z{`AF>;Y+8lAI!$*mxlTCqS2?mIN1OF+qQJ4k3Ie6!Gm8sHHyxW5SO+WR+mlQzij0G zP378Xcce`j5gU=S>m)<5w4!FTd~= zVD}W|BS)BH;3XD-wI*mUF=jdq<_Zbqj=`sgvm6e54geaIm17o&cNTNrAP+I<7S7Je z#wGx0Txc8waRB-kIxHxuD+?NnxfBa&R;sdx%cHWK7WcvS%3NNO zUT*6i?`$rsq8$c69!?|OA<$i{yuF#|_L0-|al!4l*Np`1YEiO>q-T!2S2 zhtyg)%i@rVlYG!w0SRSX&z;Jl7rJu3lhhe3U-_~D5c&`l;L5gK5Qhe%J{hg$Xc?9xe1YW5Z# zTBKB$4lV4*6-?{sk3o_-K#uS@z%>w@9|8($3;J5d${9x~jGdt>$;-^`An{y~Nf3BK zaFw`>8*KH!8T5f7N6ZOg0~0Uyu2%eKGFn&pN+w#<(_68wZ_TK3_&PH(I*J{R;*N}r zPM?FGfZ?<>xXm|?ZyWbzbod+&AN<-;;&7C7V9ixTw9t9U#2aNf*f5 zARJP$Xiddh68D4zoH{%;2M0`UuLltQTFm{>RE+m8ut7&tf=_5GmSEctY9gSO^8Lgr zPgJa@BH=H_L?g0TNJO$O68=;XUz`$QvZqJn_gQI;QbIYx4@kN!DJ4m%4V5LfUos3d zcgsv+I?dl=3nBX!n;N4nFILKsWbsnWJ&#e_$OmEGK2fF>;CXYEe$!y+l92krK*RIK z}Cg+5EH%!=x)DlJQ{9rP46Wrj=R zq33@tUqr$v@@Smk}X0#=B0^Z~Nt+bd6?!;SMKJ!HoxT8sA) zb(obo!RkKKZD@E!&waH63$OEpBScg6=LUKvBA{LPV3jw%c zMq^yHWl0bD_nBy`Jhsr&vv5IWQk$Lqfzixx8S*W&HIQBJ2pq* zUmy#?WXnIC?wn>XPIs;9zjZ9HYS&W}%v9TDHS^VFHMJ$ReN%ncEz1irWj&AniVl)L zfH(0Tu$HfW3N}~r%>TSD(qS??qjb6`r`hC))R8U0tAt3ME;0c>%gWw`IzS^tbMlA* z0>t|pfhgg+1h{@Bm)8@dLu^!LGg_-X!c$;@O&{_KTnn0_v#JuEl~%Qk{YSOOmDh!jYiVysUUXYqL1$iM8*|K2F_7Q9 zdtsKN93T6${2wGWj+ghYOl}%4>s^88v=emx*$|x%4MZGvyxc}65bc9h4TPE?tSzPH z4?P&Ek-wo*%H-G6rr1YO?A*(JTCDAn%P5yvkV_^rD>Upr6??-qhas{9F-vAKa}eNc z1^A>9>jQKtI28aRfl!5vlQLj;U0%N+gMIz!+s8L(x}Ux|d$k#iL*PJB=!4#15S{5eb_VG*2uWRFPVC z8|YjNky?O=3_Pv{#Hs*11XEpH{yf8FPSG;%+7PQ`u{X}|12GLdN03Av2agyaIB;LV zlBoqq6ktdMmQD#27|>35PcN>hGDJN|>`AZ{jSnSU4JNcH2#+mSX)dUf1jPk~szJ@= z>oG~qq)HYReqiR2dBBV1Aypr$(u|0f#f3?AQc=Nm|R@zS_ZfP!OBz&?V^I_75J z=P>YK7Xjr9#5Aw3U|tiVSY|5xiBPZsA%06jHyS?6hcmuFC$PH&?pkc% z;EO43kf$^Z;rXPNaBW?B)jk{{%9H~=1<=O?`4tePTpmi1M}iobIdLt8D^rn-K0Y_; zYK_|kv0+jwkHRV!_B{*`u1q$Ea%I=j#Zs9iHNkqdGOo%qkqlPGGtck@4)rI0WN#x2 zA!eBfc1E!0It|+$X?(6F55kj-m}=$rIKq`qoLh;5NLTFzNESv{w)AHgjy5D`*7vm( zO5=Q5I=8W>KGT+0?=BuFcR~3H_4eGh>pwu(wKbt~iLY%#dvR`F!hH`Vm*nTyFRjUF z$cc0$Iiw8TGN@WdK`G{ZcxRt?`^CmgT%-x=5Cj9x z90yuL^&aZD{~fYh1Y^HL;lg(J)?q%=dx`7+Sj!wZk5@#&J502US)4Wul@YDiyqad-8%b__2O+ly02)?eQc^DP#}I?3Sa z_iy-?eqy2PIJGV(mTU;ML}q7+y&%3yI7&+dRA5T0!4x%bTsdbPQyPE2YR)*OD1KZn zjPC~UzsEfvYVHXMl1cE>q3e@;Ib>AHjqZohTO|0|{Jkn}^fZhfkl-itqjCuhKrjjG z^C@r}Y>@92MCZJSs%R7QvJ_{1@UCEDk26s=j*eI8r=W>?l%1+Y>!s}B1<*?UyEA>{U&&L@M15eI z{rNA~k>_{fW@`ThpZ{L2pPGj=W0PPG&E(*(N8jh+k30Q12*Fli99~|(=C~4tj$_#I z_p9cNu{|y4VvEoh0*-wcn-q+I9mZGIb`juxJ3;&<|jbyDKH$cU$BpH z?2(FFH1Rt3>kFE=cE(jtS6!zz8M7}`)?V3EkV_>L+_@NcHq!Cg88g4jKh_u0-ssDJ zLa*_+{_kO~$FZv9gkJSw>j&(8lh0LAe<~`)&5ntypRSsT%=L2pj(}CJH;cnwo`AjM z9QLjrSEA5yj6ME-)tqsRC4O8kj86gAp68xl#64e$oNy$G-@-U_5P_8&E<#&i0#VY5 zZMS^k3BO|p#y;i`a1*%@63%^sPv!|}`g`@uxBh3rf#)}VVTbnO)Q&H3tL52q^zvu8 zHcR$H*hukKe+O>0Jb-KV3uh(Ndl0v20W1m}DtaWsK&X=n`*#A?v3pV&l(RUfE7l&* zkK>D55KG0jNPD_&VnIT7V_#!-T2*URTJEB~jRQL}!c}@ztf!%%V6fbgUfWii zp3^+goMXxEC@$MNT%}sWmtOA;qt6(+x1D5ePp#`us~%}6Dkw{Kdt6R$M|s1}eosZN z4M*-1s|IrNsx$1Vld{@a4ZjBaPb?S11(aqgL2XgV+@=h!UFlx$-|8-g44? z-hoP|@0QOVrEc7k(^(1K0ZQl&$mm}@TCm}+=%|G&R%hf5R3ua%|LgrqlImYrK2)8i zF-ujg_YSYypv-@oy>RfAoy8H57B61iTckj*)NJT2RG)ZlYxWZAtGL3}jDoSI4CHn{ zd`V~^@YH8o58u$ZqAWTxue+#z`@&qh6Y^!tC!p5d5Y^POdF6`DEXla4mXxHGC!1kU z(-ty0cldA@<0@)Ot!>3zSj*nU^|~}c<-WisLMBi|f@rM>ca&ngwvp2c_hf!_#V@d& zuABV_bsw_@c%csLB>{srj6s{2BrD~Z#|C)Iyz?g;UHZUb7t4p2UcW4Iw% zvTPjicS$KIKu?3Xo`ypy`U@>P+2SFHPi+-L`PmkB@dn=JyoK^s+PmSATRS#XsvAY0j+Oc5bk7YgZbE6IXG~tN@q- zv4b4^5JB7@#<`ki<_;Kd6L9&LYmQG6?}v;Z2;TqRoN@eo{y87c8DAY7UxCL#4(=j8 zfIVaf;S9&lqQUA32P{y@*!t1K5nGOdT}|-bVUTXbMVEp(&wGf0s{=T0--*7bi%Kv% z()7_zlOv@kaFJlPr;;z!psi+Sv@X+bPKeZ|`+Gw!uvCtleU5sXwm@z>3AAR=V*1Vs z7afoYu6_kNf-`=90wx}J=n1wGH{qbEglCRSR^-HV!PN?3d&z>nzpuAiZPPn z_vGB%gG<2C9S6F}XKH$nzrvRFop^a=`9zYxrX1s+t19L2+#}%mPaHn49-kzB6EcqR z%-{dsoNLk%)#>4*>}jcX=6{>!^hVa!uvK~s z!<25k4>w0b32`I}*Weg9i;=-QWq}0Z3J1YFcZu7PVZF@N`U)G9At}9APAQ^VlgsPFlX9aq z8XE6WCNXn+l%dgZZ(58eDZ&x1nR%SwuS{-|{X=F8i!LvS_vNM;pbsvvb=l=DDn~|9 zygLIz?c_gU8?$7qH3g@|i`esAWqvl)P#GJzsiwYw_~`&K8CaiCel1dp zXk3Ae#UXETrwUXlwtP= zXJ?G>06ZRP8H!LncE^OfG;-R zlWIV7+G1m`(L0-2n-M{Vt3~kA_gvjPi?|*|sGJ8)clEbWL}&|5Cm?Nb$`U%|aN{B0 zX9xt80cvtL__#*UbOP{&gpBCnhPF%#wP6VWMkxb?WHU-3XaGqk4;n?cNlBTK-BHQy zW>x!=oRle^SU61n{MW?_jpS|ruRF=cWu;0rGf4g~w#=ckfXo9Oq8IDiM8xBo1E{Hi z{%bFnWrvwd+oj4U8U|{gm#TiSsK4(S@+a`D4sz1}cy|`;z1TJLIr(W9=1GWV**Jfm zj{+%$C=hQeVVj7zl_s&R1pn=w{R%c4J^@xjHtcjFKtbR+5eoC1ZGmq^xh}#9*MajJ zO2X5CH2IxqNQjAHR>d&nb6VJ;;B5^&&hK!Cf=p@)HZB?XS|clbP6q;Kf$b8xkc^Cw z`}=ChEV=)UTJoIIk6g)X_utjE`tj`*OCSIHjonAqwOUgKyrZ`bY?gu<{jl{@w{R&6Q}-KP?`rv|I89Z+>Mjn&-xDxhEpFbNP;% z<_-0Z#;FU-Hy^PUyyVZTS=a3YhqIu&uax1l@0u#9Slyi5aq_+WxyxEI zsI>(v?^t9isA_V>5#RcMQzd33v{^|KAL@`1t$ZCvM>GpW>okI2y)Bz2rFR1@}W-m_Eb3w^(>DXfPP(Ixe{P z4hZkPoqG;{|Htqg{(dbAz5fi1^Y{Or2)!Ri=lJ{8bMD9U=oE400;%DR&h;saJK;1Fdph#_jfztpEJ^3WzIy)I85Fhp8}&klJ#WLvRTzE!5YkI~4={?tw% zQQfCf-N#7(1~pI(WCZ>rf#(xdRV)!-OeQ0mDl zEzR(5$aBV;lz5m#;IoRB44tpVS@_dW-^uB?XR^;7@51kNa|_3 zx3K4QxsH)SqfO>yNqQ13)k!edpQNp*pLr3gr|=WOc;e{?!Y~rXuldxAa~^vBTb@Z0 zuy%5aTf19WJ>R2s&DC4~BS@b8&+rMqCeTRYd$g5Y%E1i2wZ=g$@;jiGaLrYtjycOl zd2=qm1+;iV*8n&<`#-ZJI?Ta)?u@Pt@oUd$+ngC(HKA*x1h!@%8)EmrwP_r2P z&dWSqA|})L+?f?bBe;XWm=rK3Zot947tp8efdDN&;3^WRp5cqKZAvao;)+DJpOE3! z>bvUGm3X@pc}>IFYLf}dZBG|BDO@lzh$IShIK+9-l8ED5iISu zN+c@s&u9iy?J{B3xlnl|$nQCV4ZEwN!;ZK5;kz!d_T}T6{FfSWBasB=Z-OKKZWhjm z+u)c1>q&rap>JCfxKtp3aLfnGAs2W6QXB_@Uf$PwSlAcun#(-XhZa#}gthvf`V?-x zHO}VdMu!<{uAU&@iM!^y{mHSqNTh?3WLQ0V7fB=x3WM6@Fn|KeN14=KYMY>k8PJ=Y zM!8B`qWrX$ zP!&pWMRzJ4`~1Rp3i+>oz?R?uMi+n(cky%G7hLyaLhybh2}|KvFtP>(-o*6Jr=A#1Uu9!Ag{gQ?wGZAzp}1$MR#3X0^Y>R z6q8cgU9jlB>la6oODR&P_g|38ND{u@VbHQs*+YkVeZ!3f?kG9zIpQ81-&Q^G(8i*( zlDkNm>~?DKhM(WsWKAhcaxjcJ))8wi-F{(Xv{IkclM$`bUH9y+iZJ*PMVQ={1|Onm zz5U&({Pf-=oR@rWA=UQA);q#wZlIRYke-f6Da=t@JK$QMFg0 zpq`grD5)y>fs9tc&Z_V~G$CXBKSs~F*nL_p+U91<$r47UF7RI=nF64RL@*Hx!5=7q zoS-npBrL6xLb^)@GhLMCp<53n0s8Sa419SK{;1(aA_ta~3rn&=vozm*!lzlS6x4U~ zAA8`_>w?_p-FBb_@((E^4{oWfm^?kO=4YoCX7p}rNM=2;ur&fY8`-pHAbb4MKc?2b zc(|p0@8hFU=qy8mnj5qB9+=*;;_QUC?v`KQ)OBF2+Q{A>ODQa--<#Vuo$NpP)q}m& z*Z**G`x~dm!hY}37;&7i8}iJv%pE|vWn$%{*f}MDLJVf})&brjLfkhKTQ|W-A5Y@2 zbC*QSIP=v5!R@=i2EaT01@q1p^j1Q7d8M;zMXggFw(`s`_f(8Gx}8-+n-11zcGqNU z^w!nmsWrI?3XQa>e*fem8x`U0Dp_{#y5bE?ahTnr%o#a4SXTEU`^3L)OlhC2Z@cs0 zhK}?|Z%0AXxvo3!HHVq?SDe*1JhwS}q$y+Z$saA=as$xvEF{{YdwvS^xk`)_&#Mp= zvCg|)8JTYQEFZE#Eg1+IDZTv43i6F!{|f3L`ynl(A+OC$UH&P(TbE$5I6?Fw;sR_M zwF%y%ggPeypz~rL0t<;*MM1jp0{~t=+{yq&;k|#b*QdbD!f^xcjIn!}P4Zv7wdhU% z!*4Bm>*sQ2s^y#Ik`wq}3&_teVGfvY4PwT4-W;y|O59t>06F8A*t^a7(~{v z1qb_?%+#UJXnz~^wBpJo25HFG{WCI>f?({-Un6Gz(&m6q3}sQNY89!2&2Nc|-rF^i;~>Yg;eiJ~mvv*)DPf9hEBF82;x^k8nLopp&p-tYD1yE~?Im2?H}$;G zcT)tf!LcB|IGOLd#Bl%xfFHNe<5qgSZ$cs*v*1{bQ36pT_`1@ZVv7J%Xh?43)wE#2 z1yqXipSHxRAcmrLdzwo;miXG19uICM^mI-X;SpFH*Z6lO)>W3pnNzb% z6H{A?9pR}(xR9Hy-m)N zj?~nSQm3nCX>nS0MtD-)NI@zbou%#EIM%yM**mDGK`wqvUnT5f3@8c+16;xd0Klt- zElate0}j)`77|?ef%A1Bzz?5?{)@S)Z@kcvZB@`JwLH?a_@?-ou==6(rLl!36)lq~ z;v#YvF7TRYU-zEQWTiSq!Jxf2U-|9G;Xb!qlh83o^|23$8Zfy*BYm?!#$}9DwTbCo@Z#FKP}RelAzMq$BMFt1{O*q zvQnKYrF|?9uKLsAH-}2=7%R#d8t9`ERptmyUUHfP2F;P0+|+b9V_)V*lkhp5X>(IE zK%WAzP7}YR<@6e`vN3((ohkT|ci=ECh{kv6W6MGT^rV3!4(Z?xva#o70Qxe*w^eYG zDs+>Ex6mJtS06`48T-Z*x>L?p-(GcseMN@)_OU){7^&H>YQCspKS#QnF92qvL<{u` zx*4J^VO;zMLPro`<6^8hs0ABCLAk8>p*{Svi&UhP)ENDjoNkjtPtpPdidyGWEk4){{$B|!48xy)RS~8a2WqST;7kl3cNFHuJyuwPX$VTK^1wE%|&)9T~56!)j-H+dQ z*X%NyV*U@L79ah=`}T10B;9n4vv&9Z<75cXmeElxr4fOUbl@<0${z;Xvy7V%%l!ks%hEMKs+ zw}qCna(e^|<#{;DD@A!^)TY4+wt75?4mZUg+7U*dQYtIQkMw909C1oHrBSEEAAQ0^ zy);uqZHH}w%_goAHL0`z=+ayYzN?+4l-+ZGVCK(2^x6Scpn~q2_sIycN@5yj&ExhW z5fAfK0^Q;+b=*wIXT)Is^QLZr9qa7;hx_>bjXfdrmMP0u9OEOYcq56El3a4HbCu7wq0jx=LTaE>~tK@fLL z$T`YRkBv!7i-}D~&1tc*sj0ECX_DQsDJijWsi|?o5$1OY-gH)itKjE%x8F*FdiqMT z25eK5B9V|k3a$fcv3Uu{aMfEN*2o{Rzk}Tu>OR$2t&&gQkxAcFLt+am_2KUhO5T86 zG=9Dw)`mO9VBR2&(=qi!qc`^q4|%Xgs%Q3*G@_UXqy|~d7u^s$VfKQF%}{$8sLw~l zJ@B*#f=^Sx({MvJ_G&OdL0~{;n=7@q-!uPVZ_IfZJnaSMYjO&nX5i+gf~WBk0dJU< z4KaScpaDnw5jr$F3;{A!+0@hd|5bM;U{zP^zkl}tB7%sTia2a=s0|2)v*C=OMP}+D z$uv>PFa%>rK|@PZQ-dex5j?^&K8Q9s`CwIBI$-Jv9twj;J<&1xi zh`_+XJ^cN93=Ry8=;7aIh;xl)i2IbldxF}v3%Vz;%fO(vZG#4OxxL1c@7~WVe7$;XY2LoA;o-}^ZF=o% z;osK%>`4!g{ViIYYym-@Vra!agC^_~SGxq%A1k#ib*3r8(Gu7Haeg#pxA6g!$@Hvg zo2kOw#++r|YW{-XNo&oo87_5u-~CSa9q!kgOlo3pa?ayXk7AFTO~*A|)O1tRlb*qz zr<-+cwyasLS1+$QUfaC=yeD~Qc^5bLYd)m;hUQm&#`vuA`K3i%iw|1->>KU7%=bpi zaV=N3ENl5|t2V9fX_egS*;X4{n_8!|{`igoci7u_v?*$9Xgj*?mbSmNYuWC#cGvx) z{oZLG&_2HXNq?*VbN+`q^y%=o4yQUc>o~XL^Br$?3gbVm(}m6{oljbZS*BQi2pAY} zCh&p4R|4M*Jk%ww%j_`hKvq574mh+`H&xaNDr?b?RuOI%?e!_x-xWqXhEnw^g!sb(9>ZP!ls5L zh0P0F682))y09}nC-j`!GpXmio=bYZ*t7m_&%2j~w+^?2hlIb@YkaTtUORhL_PW^X zdhgsm!}{FcC$3LIpC|h~-Di29m-}q$Q`qO7K8O2u>N~t|THpD7_xAm!Ux$9N{g(DS z)W2K*0sZgq|5X1?{f`Z3F(7WhrUAbWTsUysJw6f5BKky3iC8iyaM1IEJqPCues^&F zkl{mOhrBqn{m@xM4-PXAix`$ZZ2PeHhPNL+Z}>~YKN$Y?@SjI?9uYNS_K258oET9b z8LDfFq5Z}k2X?&rs87U?(zMAbrAi;ZG-ZySR)x;jyz0F?1p8FKL!!I}e`W*kudYA+ zr+z2M7Gs{&nsfN>jT}jJTPjbRZ_53KHBxK5OV$CCv0C!Ew#e{T8Nv$Hbkc#wRoZUO zJq&JwDDWg03}%9b;4F9yoLBdQ2y?I$a=elBZ^lAd=vFQ9=5^X}^J}u$d`%X+Jw-YM zbRa(!%#p?H2iRsBE^W*QWWA|S7P~L!d@^{4`=VsMTQO-a*AB{^{Mzs`w~_L;`3+gv z#9y87N)b(-h4$ejjiPX_q64Fo$)RG z`Gu@iedfYeW1;qq&UeN8KfrynR-|O1%R$M)1?2FIk_E^C8{M|c$ObtmSu_UidKS4n zpk&b)x-6pPOZaz>&UeN8KY&J}h7+>+!jZ0jMjT`O~&AiK@y zwX0k!Hcyk0=30p{9?=pw{tze|oCz|>zs~-iT+>%Fl%4WJY14dJ%ddBb@ae@3a*)p~ zpOJj2QU0dM?t1nRd06l(r#%FJbG^ZnsMNr|1Jgd9b0Z!x&#g6Q+Bs8`LxvfC@Gu#D zOh%)T?{_sV5_xl|Oue_^`Si@OF{*}NjPCc=XBl2>vfEH#5qU{nH=S`?MxsV$iev`E zA5o~EJv3qSn^uo+^Mrare`6-v4C*CbP;b_te`D-!4)qZq?N?@DEug;Q3vDSap{=Bq z_6u)!t)X|w9ndz?2HIBILfc6@?Iycn{GjcnJ=9B6=DG4VGZ-I(x7} zpbTHoPzi;GNtpH{YfU|&cgx+-a6WVPBj4573))+HYd^3zqYtz%`}BU`jkzDRzx0Rl zSyAm8(b|E~d-xpTHDWb{9y+^dX6bP9)~~Ju9&jp$|)(_8t4~ABH|6lc1C3 z5$F_|tX<+;BBns6%A?SDnF^gI@zCiqO}ofUYdSPRWWu zXGtRT37G{=;=B0H^DQ1p&}5knO_5~i97%ybDRZ=1N#)zgYWe1qRA{=SK{F&B`jlj7 z=lDg4r=as>E;Li-L9-+iI$yH1v$8!{&$0@Xt$iztWFhn!Sphv{PqgBc}Sqpug z?~kpN^|B7Sfk;9n5u5c|g=~@y(9N^ZiVgY?*`a+YZ%QGwNd5tROWuU;lp^Tc@|O06?2?^OJD(K(LUzk8 z=pL~{i)FV~F7L=5s6&dOd*vPIyW-G3m-l2Zbf3Hn-7oJ!56C{~`?6m*oPqa_?4w*9OY55fTxqJpKm($wE@`Zd3{Zh)IU&$BHujNZ>NBUR8Esn$;7yT5^cD>cxwat3-%zJ=C8Psn*W3%wxcpckbUdP&Y} zAIW!e0s6gMg#J@5K`+a9&@1vi-=3L4TC1+A+q2YtWzM2k6i8 zBlLz`*FKb+@)PtI`5F4F+<^WjH=*_Ni*{5r`4y^OgH&``@W{@{7hmIVn9A`4e3Khz z1+Shh8i6-I!`+5R!+66aL%bo|u+n(Mc+^;7I$&vSX>aLd3AA*#^t24LL|S$P1O{{u zGzPi{`UJKNY#-PuFgS2j;MBl`ZXb3}{6&3MPW^e~yEhulhIW)X%rMUIuwklU9;KF2 zYB{C0vb3{wuvqj`2mGN_-$td*&`UK?szLivJEI-c_G$mnUeR*2`C5kdq&7(#Rewi) z>w5R!x>kQueX{yQ^+(koR=;2UPIXcB=&DbvKCZl8d9CtN<;BV~mDQD>Ru)%os$Boo zz%SRitElJyg}-8vko$DR{bV?7tZz;rL8JQSaWSGi< zF@zIA0pv^}mZ&0Ax2SOwyTn;?ExDs-Zihf<0iL|`z%GK?qerDII(C^q<_)S$TPPc_ggKc#ZM=;bG5k%ZFUdhx`(rr@e_-N`WH!DZmueG{KPH+ zMT>HC{d4Ju>$q4B{NaQ_{&-@j>ja#j3^*~e*sy3Ug^_d#@K-0g1at|YopF)W-8AIB z@e@bV(ttSq3%`T)7$~cX!3GDau4nd>S;MF>jWL!5Wbp{zPlRAD<5>)&dVqcgM@2A< z!6y!b=bIr|NTD=bK4SkKwMom(1`;b>+PcOFd4z^3A2U=OeCs3-R!L(Utd= zcAl>?Z%JXa&V*5kjP;K*LR*+^O@|8>W==hsL-k~S<;>m9xoO;M;jT>PC@GBp@r?U3 zI1|ID{sc#9jNcaKL0Oc?JVH;Wb7n5b>6C9_K9j&*3Do$Meuo7qGHcLl9zzMUIcs57 z7(+gtD}l`HRQZXtDuMgdv#Q1ny=GO8YR}{PQ{$Oq#c=!peNy)}F8lW-gm5jEdr~Pc zQLo=ZUqf}M+MIPe>vi&FG_}OjW7Up7_P=rO|Je6|)O5SNQIwHLt*V@4z0HlwRrfaV zy5X4~df)%thJW4qo~ZUcl=2W|r_oN;!(?X5PH81_PRT&Y+{w!n_?W75wxK=?ElcB` zc#zJuc(|Q_RN~1$p+EbWe&xT@fKYnz?=<9J)t*M3PI)WsY^YVW{4uU5ZLsLM*<4N1 z^-{G|$#bU8Tcst6%Z>FTgPtf2Q(DuY-wj&*klsgC>s)l6c`;=?S#_;fy5W?9vL+=JWf2zouB4&(kU`I#eOK*G0?97U zq;aRymY9v}nxJefQNPRi#B|OlQ$~YMD_+f{^f{ERY(i1>gsNF-raH2af1GQoUd3O< zA*CG_X8RfX9Zu_YYL1fL99LUa?W(VHbz4sDo@(tD?7C>_eu`>lM>1ebT2uGg4G zNy-N(ZaaCUtVz|Zc%?X+#(Sx{qDoZfrt92NM^3&!#W_{RG>#Rwey^h$JgIbCS*240 zRcWeE%3t2rW%X=2|LV@i^!jJ(eN?vLv1@4iieC*rJ3+61rhcrfN%eIY zCEl(>*@9DtR6kTswWWcZY5MaCx>xwKttL@lihfP`jwg6lNg#nG2ypx6`5< z>Q>&jvDZ{%yL$Tfc6eKJ8Z240PSxP_{iZRg|bX%DT*7Z)T{cZdaSfs)zerzl-|!9Dl1R9B@NXI zbyqxEsmf9^ZmcV+r%tb+tX7R&$_|vqs5wJAr43ZE7uur!L-nVXRX9D8;+pa{v$^BH zz5n+zSL1cq@4WA$f0}KC{Rgv}yZ?{OYVP{4d!y!6|NqQ|)HwEgd8Hvor3Z76u#&&> zV@agS|II`)4=|gHVfOfE&G^rrY|#H0%59jBj;5}LnV0_NOYBgziTJ92@yD8>7}PFA z*4LTcyR&{s^pmJ(Goqc|L^*w!$@>!3Y{gsh9YitP620^zYUxk3vLjK-&PXVLk*W*P z$Zotks9j1{-ZO%+wI1{E*&D|kU;>f6SY~Pyc}aPgh}|Q+b4(#ZHv8$kLFO?+W)i0(I!F9ylZwm{mwSeo$Untla5K0Qx2Pxn;6aS0M$WKC z>q%VdEx!4|i#W?!*=z7-r+|;41(B9oqFv?kjlq|=&DX?hs)^-P$!o-}-X>19hq%%% zqE?5A^&KRlXCt<>j~Bdm4J~=a+d%X!pQzg!VlUf>)~zFE_5zW*m*pLF;efnvXl=NI zFPdpf%)-ym-r#TOVCZP*WFGUEn3yIR$%#FC4(sVkBby9MnVFKD@I;e%S31&_COA{~ zG4azg(i7a1oymA-lIBbvb|zVR;`#85l=S%N(-V@@J+p3Q^?Jfb3^0$(NKH`(;eGoK z@SK?%|5QTg^!T&{?-_{+sR?O`Y5GyK+40j;Q- z);o?p(RaQFI5H|`f;3NxPfx~HSnSb1>#VNd&hz9G38~4_+)25nuB*L9Mm^;>V9^bA ze`>3&R#{%7T4lBD)Uvu|C-<@5S*_EXmwIOzPJ54PI@Wl~JIl1*JInltdAIi{_pu&r znvV6k>09JAs&%^00iOd+>wU7Cwe!j1pCivv&AmK7Y1XdU^IoI8DVGwfRm!4neamXE zdUd9C`t5&JPow`)-ul1KO>ez4RU-e5^9P!H`2f{I(kuEkTBH6|U8*lFJ2|Q9jq_aV zbb6bL2U4EL`n(*k&(LJxDSuf;4l7i%TG+fHj}VUHS<(+%naQU z7hsFe;u)0RSc;u2#~PF!tj0&YiZ!jngRIA1HexRYSkVr=#M`=MDH|&$8nR#63pQ4Q z?>LI5IDwD&6wgqOy(%j`kKee6hxiU#yQ2G_>qIRFv%0i`b)y*8i(*(UTETix39CIN zc+u9Z=&WFUCX|&CJ1Zh~)&GRW>4#%k+r*m%x$mHC7(gmD*n*4IEuL3WF)!-HIDp(6PaNmB)d>@o>{1GVQ z+*zJG2WlzfJh%uhfyNpNx)AM#pBAQX+`%Zvz8Zy{!d0b z9z;7bS-qQvhVU&x8gE&YHJf}2m_vRp_hpiQ8vHw3SAYoBP%kpA|op@vLYiZGO{8gD>AYoBP%kpVn>salNC8xk&_iUS&@?!Ia#rz$=K0k z>}WD}G#O2N5KVm0WlvT(nu83j$k2*SO@_NU$kNIRPZTRVQLN=8u!fVs+D!r)8-vEi z+_JgL~JMgibjKNc%nk2REU(Kbp7bcxdt8S zp{3l?lSpk1Qd)zQ)*z)dNT?7A6(XTENT?7AtwBPCNN5uhDnvrxBB5`Q&bLVCsIFg0 z)IXcLQ-IR7RF2c}-t1LIT7^h!CG(}R%$EiuwUtQChV|I69vjwU!+LC3j}7aw{aZcV zOk1{qtza9-18;zQupJZt8`uE~!A|ft_3t9JgWX^cCO;73viZxoddP>@jSSI94?Yx0^gCp%(W||S4ppd z8`LodDY7$!r#(r%fseKh39dteN0DGD5-i2Oj$&7N*i!+LDnL>NNU8vP+J&@Akya_v zDnMGLNUH#8l_IU3NUM~wG74!#A&m&65rH&HkwgTNh(ZcSk-|}=a1<#VMG8le!cnAf z6#FQE(*j;dR$vR@bOD@Z90fZ-A=nAtrtDp$cCZ`l0mZ-p_HylA@E+I) z4pPS<&L0Lxz;Vux8wFD{Z^0^gCp0&ehZFr4#)YkqLe550Gw<9X}Tlg3G_7&uK1y^4)oQ5zUILpKXlXqSNzaV2RfLC z=g7lzg!KU(XDydB8efvg?8 zbGh*rAa<6fcann$F<-*xWGLZNiTu#$X@}0x1Nqf7o$Kl7zM_G z31BnW0=9x}AP>9&^1*gc0Bm3fCixVmTQZ_67U>Y3YLK!u$k*yz*evg9>Kq1%(b^$xs4fcRy-~fk!(`VMwgIbrrtVREuGOo1* zUBLisc_4@&zA%LJS$3wYq zDoEnqRImW3eKw2167U>Y3YLK!uz_a}l9rKvN*Sj?IjH5i^WY-51a5FogZ5=(IoY)2 z|7GpV##*zn)@)i{g$HZF%waZ20h!=wa2A{cm%&wV4FtmV6gZv&w^Mj39WKw}JzynV z&V<9W@X1B^rzYl83 zp9dGgCD5EwiYTQB4XUN2A~d9yS!x+tQcGz?l%`53;>jYOEaJ%`o-E>B)s1*rQ#j~J z>J5CfNpK_<=}$uX*^KkKjPtqhEF9~$qnFu?WOha}yK6peXEd|ppQ5pHwXcrI8n{<` zl<_~8@jn-fk7oSO#p?Tn6gMn^lNqn**w zjz5gXn?&PHqVXotc#~+nNi^Oh8gCMfH;KlZMB`1O@g~uDlW67*xp9T4 za?Y&+FN4+K74Rxp3pP;Ze#(0vlyLkJDC68&o;wF>DdRl22rhxkoVyCHf$sDm6D_Zx z7n$@T6D^;GhR;I7E70f)S|3g8SK?_MwEjUn?J;`5et7Op1q;Bl+_xAk0ndS@U>V2( z8}zrS3R?6a9`+a>_81=a7_G{rRhdY27A?!9WonKx3yID`k`>Ipn<87)nigDfwrCP9 zn#4FXm~m(r<4_pm&|vJ#hJD$vFB|q{!=`N5lMQ}m!p}_jmy{i4XZ+Sv3Sv` zc+shFr~*$q6-G+p5sEDzuFqqhKv~jr!Js*TH(=^zBt>UlrO{h4xjs ze0&8xtw7GP$T=1n$0FlcdR#$oE9h;7E8gnKdc>UH#cMm=iqWbagX)v34KZ7GAhAxu zDv1g{OLr$tN}L%lAx@f>F(*yJozzvnis(Ayx@wKZgPBXR>)3;`J4iEr&52mQit{%_ z_zk`WzPXe*=m^#oo@D(%Mfod<@K>vq0lhT_O5!(3fhxtFJyhyj8eabk U)vd03QS*E}cLv8M=Q_^+0)HEF0{{R3 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/lato/Lato-Regular.ttf b/internal/login/static/resources/fonts/lato/Lato-Regular.ttf new file mode 100755 index 0000000000000000000000000000000000000000..33eba8b192384487f04951539f13bf1f8dd9f9cb GIT binary patch literal 75136 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 ojk(g9PAtLVP?*9aY%s*7-^F-90;3|7E6 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

FpM0k7!$XuTDosBeYY{|%I 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 Hzx)3OGG_Ot literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.ttf b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7015564ad166a3e9d88c82f17829f0cc01ebe29a GIT binary patch literal 128180 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 ohyj3!`#ee%L;DTjx@8!5k5~VH0QmdE^#A|> literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff new file mode 100644 index 0000000000000000000000000000000000000000..b648a3eea2d16b6ce783906d6b7d5f251b9eb56c GIT binary patch literal 57620 zcmY&^NelVwr$(CZQHhO+t!`$=Dp;-onGnG%1YJl`q9)OmoxnxQ~!cx z7yTwvL_vxFmrDfzAms%BFq1u;FO!o|pk)96AY1*_{QHG2qyvG0ft8*u0022U001yH z001b^-7WpDiJrqRN5%B30sjv_KLEfcmTtzs92WpU*)#y4J?2lST9B!co*@9hGW4&8 z`4=pp>u1uYzvM6XUw$aRAo>Fc^vBf7(e;Ws_PPwU|4;c6vAY`D4U;s#9fGPn0SECQP7GZX@2I3WUo4pB*5bE|8|@Fm_rEMeislDJkxA(b z7tCUlVW`i$#DWbQZsJMnX?Wci4^U?JYSLP9^{854ZTD(mZmHb5Kg#0WKDy&x2*LAw zTo>W>_}n7h_S_HghvODJCnAQCPwY%2)^GlIWGK?6;jNOlF0WOptuo*kv8|j_g}1_c zE+(DP(B{zS(DhLNP{BA|<)Y%`;w0l_Q6WO2EZKL|*ys_L#EFFrpqv(C%GE%Zc>Y>~HgyL!|@;oHhHQP}pO{tpwUsv%B#6 zd!u<`WFA2+30r%fO!U*(zhn@xA;rJNv7)dPqcC&`Gkpup)6p#8t-&S%`VH#+Vw47 z1ZrYVoekY6m!+MmkfSl@=(83Jh>RM=6@_BZ@#m2@gjSQDm~M#;i*tlcAUFkg;=PQs zMJnWEk_2tyBE8hNCL`jfI6N%DY2a%&bpE?0I6k{55d>M94FoUL_axD8r2MZ;xv-@Hvaw zq9i|4u;P4|nOd?89&S@e7$fg9w5ik7{;s1p<$%{Px^pXA)ZiJ*T_`9A%ZsrKN$)%D ztOb7M#2uWj)1nwnb0-iLgR~WM*q`jEA@w~(cU<3;TcGz6UD5z$GW#O`20df8;pRVY zzoC4zzo)g|0FvRy)=K0+BCPi)KabsDwpTdF%AsoFeo@XLYf`R3tW(N(V4APa8VTqO zYaFp!PT=^&)H+bv3U5T*5vk{AeXej$R;Oewpd^)uVn0)o;zmt7lRTM9REl*{mONZN z<|S<4WFKxe0$E{t$xn2nCGWG0$W{E${W(Sw*BQ{1U**^A&8 zI$rVs&Q8tZEFBp*nancPz{--(mmK4uN7@+{1uq?=-Qk{v}Ai(*JQ<Qb) ziI9oKiR_8ziS&uliH3S=!6yBgeC6Harr>SJm)-bB1PpopT0sz{MF16qoR^V~HVCLue&LVU6e$yTtP$;v!eHTHBEyb|!?`@o*sevdTrHJeop zwT0oAcEND0l*idnVa$A8P(K0ZVSeX`ivqs>8G5=X`&lYF5ee)Be(wuIckU$q*}<;@ z4r2#7nhUhaoUJcj*VC0s$-JYm=`HaJpLeRxTzn;J_aSv6KyL2}I@N-Vcnp-x5iQOX zh|qORY8E5lSTmQTC|@~e(_QfIL@S-9IHiq1PS)wZ*$t!IY(~`< z@a6PU3WzmFyeT?es(00UuAHM@*;!`}3SHx%=v)j#UpfM9*n2$NSKt9wR?y-h;`3^0 zlYNOTiCjHHknv2F8#vP^LJ`;lRH+t>(JB&-@R!sXn&Y*hje6bmXmdd%}w>*#3>A))z4~D%XF*+~}&sYg%I=ANO zz+0?E;B}3LCnPO}qgGQ!*}YM8HpXcy0t)~RdNRI{N?XQk$esPOG6h--f1AR(K2Yziif%z`E-CQd|Vjt8W*X++>o7Rd;B-rq6B<{d^Zlfz}sJqYrNd!pa_ zv~xQf91*{23mLP% z=BlE92usq)WUw6&Ro)nNR3PVL#>GlTLTK{`kJK^8KKJLHq&ZVA4;v&*36q<~QinCH z8E8{4&WTw=(-taC8{*&Y)m>{mW;<|X=qQp<-?&t`l^B*7m*i@fXMII|Q+)w_3;ssi z%qnt_Hr$~Zm1?=m@E-RRyV`{IWmoBEdvGCKTzT8TS91N#R<1Np$x??E36qMGdv<18 z-6C$)sM&E&c*s)~p)A_WQ4HKo+H)oAY8H!rC62qL1M);9P+;YW0|eykR*VC;U+M$b ztVo>Ecpx6C5U+sWXwHg;;i@n-q2H3Oeh+`um{bho(vHgJ^=3xK-bvtgD!Q+M%U>PP zQpY9F=}<8`)-ouvWJa~Y#!7b;#NGKhR^V@_k;Io-OE|z-BG$LdgV;o>~$$`2S05D;l@z?Bzz6w^+;vkT0VL`Ae&SJ zB7L8(p|q!#^NJ=dXA143B}42VU%KTfd%-Y_rKfmqA9`_DiO*O)Ij*dIQDvIVs0itZ>oVwYF~0%fjhehYKuIl;r$d0Z{9rb$9%=i zll)UXq1#cW|ECVFNqkfDd4YUbD+D05 zKJhAu2Ew|aPfc~ZCwAyQQIaVTo!aw5f0++2`+ zfh+wx1C4~2ezj|#t5caIHkncw<$=cm+JOvG0#m%$7+%6#0!l(uf>y#n0%Jl&f=7Z$ zLQ4YeM6o70Tq0?r$v#Hbi&S>oK*JS54wtBrT`Vs1WpP4tXE5gz9&el z<)-MSY1?K(>7M;TV#DV1BQd6`oqLQz>u%LYpC1Rvxm6ceTY_XuJ75~{Ri=3s%%yL4 z6#hikAX3@&grZH&61yjBtJqUC;@0^)_q%a0ZOcqWj3q!fZc&6{W!}EwL@8JOWf7;1 zoQZNbbVuXgqUc6R3poRBwF2_1*5G{UT9_g>pDmxZ=^WXsVIr-I@^#YnJ7jA-{r=6I&hH zN#!;#6L&mW<`MItoSS0tjqbmAvUogwxJflVDmDxZ*!0wKp7%)JmTY3p!_` zuHK_rDjtS~%J(<3mhcsP630pGaY|{xrTNUfkyAR2e)g|4d9Cps5uy_j7CP@6?Ks@& zD@oo9BS^C+ub8IcqJ0ttGfTxPO*MC3*);KI7SZWza^_vsPrlMgp+5&xU}>sG!wO{^ zR|1U!mknKuS7M8-wzvmTE^0?UT`PZ#$+IFUc4!P(5pCp z7b^|QjLrMQ$J5ibz-r3ga%PbOV#S%pE>P3v!h1SancBz>cSRYh9a=?~s;+s)!5DC* zhs}NNBxPb9{(sAtkPxmn)jm0+ne-N z2lo(C_W<2mr`PV|o*5!yugWoq57fBC^<~`xOZF1oV+Rm#!ZGsuSX|=0F%UyrA$%G| zty?ztS=*)7-2(-Vb5h7{7p#o(s;ls{VtRUJRB1_!?*J5fg}XrBY(FT1<1q@kF3-Y^ zhnto$jkY<0=g>?wnXk=`bXj66^8t?xUgLvG)2^uBq_m?G_vxMFH=`a4q-<@Kqbmp| zB>9l;CEI=+e-Y0nbj@oJ-|5m&y!eb})kCwC1|#U3#rTIz7s+a~y&WitVNrTy^J0QP zwIFd`$;0bb+`Qs*0EC3WQS1V8ibwY_8okmt%#-<84>$><$U7m0&Sf-WAIODLRZMEX z6z4JIJ>naiAf+1$V0b5GQ)-z#?pw6t_le&)} zV-DC~dpZj<`;$9K@y1FXhCI1<#^4?rl&@3QgD*^iA64x0!*B$+-7#UBWae z8y+5zDNDMW@1WS~!l&nI3&`zv23(b{R@kq!TJ?G{OPeS2z68QOa^h?zb6Fm#g5F+o z)565l!C0(>i90JJxK{xo!7Z9YB%l;G^8e{zs}KkH=E%>ead@Px{N;^xTF(Aih(%-(+? zaga~hD5!tGa;2Ed?Y7$VXPHjdNo>w;!jS;vL-J0eGAf_jEREX|t+DS-aJAM>a5*}7 znxOS_w%Y_v2!zBtliWNgr))mBt4GFNwi!;Gh3WME*}6}k3xFV`x< zLD6p(sai1gKU<~W5+)pyia28fSaQrTgkHOh4BzM%63Nh#v#v?$&}`kf48&L3fT`n} zq#E?+Nb_Xm?Xz(|{OZrxw>rH#%R1G<7`Fc2_ev)>5@uLnxCqhCGGIhAxt`=o za^rrmYEHK@DluA_x=!V0@^BC3fAe}SyPQ~?ad?~UXb`nlw!Yfj+{|txbSMd7OU!U^ z31UYoXj2)e46Auaq&@O5RqM+HH=mYQ{FHa^371(K-{zS5*J4HcUZbAtFDM_a62_-6 zhtjg78Cbj7yhMLTeqNnor!6X?j?v`G^whuBA<@G&WVQfbwss6WNV-0pTo@PYS(Z53 zCa2LF9}m@0K*EJ7gjNp06~1p~Dy68fV_%EYSZFn8Gv{>>FAAwXWTt18!lvP?EY%Dj zJ{}%)BNQKEpm@w2jH8EjF{LIST~-emATQdZTNhm$@1yqG(mxH9+IGf>Oayn;ho zgr3_1dOlpex`UYIRWQ*kUV$b(>T*L78OOW=L{D2zt8r#2)vTRS+NJPn4!cD2l=Qm> zCDT3vdEa6wLRLjfiTICBfIoE$nOu4he>^|toeqZ@MbCguI=8ItwBIdT)m|eG?Oi6W z`WU%V4M`Q~4ttQ(q8WLKZu z)AEbW>s2UiCgjd}(H4BydS_(kb;>oqjG*>GE|Maax~k(xvc8e}G4&zh&cjs3^pD#^ z@PkjZ^}lIv7cOrzZHM!QMzVVPn}?c1-aE(K4e)59b(9Ah2J^b*sf$s;f?FSaq%4I8 z3a%*hEijojCk&wi*oT_EGG22(GR*KWRjiK#{>^|Cm^6fj&b4K1D;idpG`RPFgi!&PcXzh}kwqAiwc$otwH-YVRm!q#YQJ%P&Lnt={ZWph5NFkx&SH>mQ z9R0T#;KyrtihYj6#PX~5KB7cR z=?sG$Sp{=PnlU!0s;KO#GxD8*}K%1W8<)k#|ooe|xCu5dRvXaU1MaI1r2So1D)!R|?Qa!}` zxlhNyu~9KGrfH1xF|+c>b%|O~;B%B!EPI|KN`=_4Qc1Yp1==k*xOyE&NUkN5mlY&V zzh$6;NIedWNI<4KD%EZtUn4p+(tYL5Kw7C7wed;|XI9emiYee@onsC2S%OA}siLnl z!S+<^Lf(0UMLl|=aC01W2;u=7WzJ>{ zCOnJCQjx|}GGWCScuq%(aeLgQ0<^m-b0x;3!Lpct?iI=ul-&Z|^fH?u+=054X>(WL zn>NGRNDmPHi=JT2!JkQy?1(1tP+uS`hCK5cv-^~R!vpy>lmEo-_Vuz76Pagjpc2=O z8S)vwxs()yw7TDz!{?|Dp;-&H5|;V?vO8#9Mcg_)`w?WlyUHCt9hN)hQxnLf=!?t< zE6X8qqtoFLWT?@4biJW>>KM-xl#~fL_k$Z$Q*^lA4g^YIGxaqaaP{?Q2aeO>(NjxFMOT>DrUj#tD|h-~DZ z+t(`cessRx)1Ncd?Y_c+#?C6f3c5ebY$1a!M_9Mxg6KNWaP;(PFG1zj?ea>=6H#A% zFd%fbE;F_1gl@k&tzMy(jZ(brs$XX}RmE7N_rRqzwf3;!xiT)Wm_%T1r=bt2Dbym9 zDkv@Hu6sKC06mUy>~J#@xR+c!LN+T@Ipx(Zh?Bx1*1&br5(;UX!y7!eZOmBYuvi_4 zF1nMcm?9z~krDCw_86JSPu>L|B5tq9rEZc^P_81~)Cze+Y+^AlYG9dB`W$e*2&=PS zdcWqCi6MNFa;yNWi9V9Ml9b2}G&kWnF_OKStk{z*H<%VY{{6boH(=8aCKLAm5gN*t zeu5{QWszDudu;9I2BP`!bZYO}%78#G&XA3M5hBZsU2TOta=alk=9kIC-U%ev>2H`G zwQAymG3vN3mLIz&l95`39l1cts_>&+Xb?X|T_F?aXBtD7DJ@;Tk+V+WEVo*k9bz@# z37+M5pP;60!T5spyVwhD2y$Zp;yl2OKub{etR6o}-ujDm#Pl(Wj_Q^%>Bss(C|aZN zw3!88I9;>;cFcK2df{w^$}td)k#l?(&dU3{XD8=5CPU2DxX@V`E3NNYYb#}EVJ~x@ z5%F0$6Hk=+Og3eL2M0XWQik1p^l}Q(_CHg06Bisv6n-YagwuLAE)BW&(~ zY8&0+G6Yx>fbN)UsVrPj7#AY2KhbRCo>7vGCXS2@b3AkIqk^e;nS@q`S&wWC?ZG76 za5BaVGco-O%-aAm#v6jtTvZ$Us+wURw`iH9r|-CXvcZlnDsbGcc zng6y^2tPHL_U$;kT_0(ghBIq8SGr^!hA-t~lnGd4ZR8zqWIYaN-d%=+kjtZ=gqku~ z{}H2TAxs9m!+!^fhaiBy84nqU;usmE9y}HW{8mwh4Fac^pji`U zeV7w>w55Iy9zV;rii7Xt!lbCS_IW>sXasYt)Z~YpA(fIcAIZMBHbnOIOTca63;grI zhq0SOY1>+-q?3B~b4i6+BDc2x$$gn8TF=Fkt3&5j7gU!>Kii|M@z7*;p4OM_@s}lG zB)3flH@%0&bJ1)*F66<~#<4WG14QyR84(F>t zJKwUP&Pz!#tg`QyL{BW zq&#q%U5FDtB7@T!?hqtgrN+X*skIAOv;b=zZBB-ER?C=Y+FCc$9q3kuEqD zyIEA-9LCD+IH1UYh}kwjYYs2HlzEG!6@F2rlGiKC|oLYe}fe zMNTJ;f{1#%58fpE1)P?&3(K7oMNPk%V$IYxgjyJXu-ppe86kDvmI2{o^ zEMV15dI-8`$+R`4U)P4($zoo{F4nC~b#OLQTC_sygyfj>?l!QleK$e;S!t1%o*pCm=VN~xwzT+le6Qq|bE&So zAnwtuG&1RkMDZIpDfRkHp;s@sqvGRYoB8iS8WqLEw$ag{l&qbKnH(O!3Wv({tZx(9 zrVG-Fh}u!&`2mB;R|cyvJM*)x;n=-!**cN9;ew-;rIoC(ay~fUia@`{U-Sr(Nxic6 zV4+!?uwHc#lnM|i?eH8~?ehpzOPxQ~^F!dn>jtnR*b@u`>)?i+dT9yg511ZXTEk_9 z4;OQX%m{^K1@_@IiEYsN>B0wl{fq0=P2>^sk}{+`-U#B(f+NcLDzb>uk_Q;oB4*q5 z1eXenJkr(JGeUp^6c$xV;wJ^ZfKBLwHTVp+oXD4D4RJu;*dSYZ?)zFP0)>jFI5ns; z`MbmMhaJ4&%i9DLOBwcR`xZ)8YlT&Eu?m#)tLu7|MMfTQffpqmvaz%=Y`E1ZO^%rf zB^|h)Yc6*YtO0R>N_*kNd54@5&QbqB`3$ zGxc6r%uWtB(G2a(H|=GJbi%E8e)UQG2OHe4oej(3FH{(QNe$gC#%85G^mpwV2{cP+ zWYoo??vPGz|NdOn#EZND+(h6v;igqoGHaFCcrOr>ot@3Mb}a!vi_BdWF}Z>YMev9U zdQFK-yTw$t1(V!_`xhBV_7KX6&dcoRv;lRCYQ?R*BMJiOkn1xm-CL>k90M(qla^>L z7u)BGp}ZzDI#zoEd^%Iy^W1JYEW5HEUUeEBDK59j?{Ai96-ITV6O&f@dg?dhrrJb_ zTLx0aWXe*63u#&Z*o<#=K-e>24OJ^3v<;@J{kGa-BI+k6_eO^snJVy+#?&bOB0Uva z9dt5nD|p`QbJK~8x!L52ZS*Ce0xJfQW@?;tRjzo!(FMyMW%b7I*fN3lC#Ubhqk!i zBY@}MCB;}M@2vF-Gbzjo@+>|td`#wFyuaZ`g+8nDD(5;Klt#;MxCbvCbRvj9Tjam2 zv*QNjKO<;Sm&Zv}doO!Y0diJcN(7VF$6@=f3p2mgmLp`=R1lNf5{9+09AGiB3xu z9U0v^z3hM7sJ^cA4#(nPq^z-3iW+7qAcJi{dw-%NMFosfx`@mT3=|0pEASo#k9K%S zs^G`yjm+Hfj+%+#otuh9U%s!RnH)HC1-QVZ;WqfD=`AyFWB^Zv9rHVMy%o6iN2aGt zbsQ`3@O2m6)J%SKDV-;)5IupQM`&6Imt+kvqQt~`(=Q^+Ha{P~u2SZnhT4k!EszM~ zy!Rmt6>-*?KinXOMO>r!dX`=j(ML);EE`t2RWKb=a}R+b)yBKq+eo7bDg)FJu2@Hd z)_C->k4dsxo^d_r(^h9b!bKN^(jh$2Me2wZAij(4l^ErF6_uF<8inX$N*KfrkZk1P zLC7}t*nyNWX=O*><2XZwFQ>bGC1P3x&A{h8HTGUYx_PbZMD9YiN(xmKlUbq)euF;T z!sNkeD-|>ry^R$@joo5C9RP`ou0mKW^eC!Z|~_q>TqxGE^JW` zgD68I9UUEgEdygOKmmNLuHHW&7--O+A4b14Nm*vmdPwMXfIvmiFIT|9Dd1Qt737dR zM%9guE0d{fMrRlOUke^q&}wr6zifDpRYpq(Sc?Ig|1=ubkW0Du(+?`6ilBHbKWGwx zm;_>CVb5MmqTydv!}7Y~-E1#`B9b+mQ74*cwvn_vVe~i6UTeT(&FO83$w?ZG~rF^Q=s^Y5r zZA6^(srpvF$0Oi7!B?<0wwNO3lF-2R4rjEG;UC(Z+`ts6B^elHE%U~6rI6B8xp-X{%|#>F;Up=Z|NP=H>|JzW4F>e)sM6)%MxX{!K$` zCRTLHsG?zPgXFvTJ72pVyBxb3yBNC`yA(T<52yIpDyOB`Ld56^{Xgw-{dT++eGsjP zO$6e-J4SRHfTF?7b0OD;A9=jo!8no7+|gJ4qU|X-QP%F9&1hhA9rYo*K<{kN%#wvQ z#-s+2UX+}`jAt8bYoiM;;jbOL*zZcu)?EK;^zgt8kv_1EXEWB?duZ1~f>V>$n+Cm2(X^CTUf`&zZu6m_X*tPSIlDwKta>5jV!(K-cNO-mK( z8L~#4y{Xms^Vm^In@bvwObEyw_9ZGvdOBu_Vt#gH39Np)bcy~ri?!-y3xHD#wnxxD zs_oAzD1UURp(=SZMuQR-$m1uKpV*y3ErRm}zu~L*s6cS@qHpt#Qx?;MG7BYySOmYf zS{S+umlE5fNuedLuB-JMrg)>hP1)ippzz47LK4;d~#PEl@t4jljp z0HBEy)ck8t1^o5p0=WWSx`ViGs5akrg;NjF58;zHBPHll#>KbSQBw+(iJv*jXJWY7 z{?G!SSzjD&O;b4uPfT9WFpf+_?%d$v(gZxDwrLwX?zE}cQ*oXdc+Z4Y7gkg_Omn~7 zqUg*1`TJ;YnNL6XS20YHz@C^uDBIyDjdAs|iJ;Y=&i*TT_Gj~F=8N~j8@fz%2xl{o z0Zq6xSF95pOaXP@vRieiGoK8M*LJTTjK-0=qPl#w_1|@D$q$JaZLnaV`H^~4s>y-e ziB?y?1Q&LWd*ARd6pMBKzjesZNtpQn1!Vb2d8OWILSPph4iZpD+d6b&y^4*i#f#!{ z%+@uFUNYdjR+xh?vH(a&u1JzoigdDjcBz$eX8S~tY_vbw74Y%3W@N#6T(zqWs8L0) zj-F$$ms4S$`|;-Jw?6K2$Y?q8>{oCh`**UdKJD{iL{NDUL(HbC}$2sXg*i=+26DI`coUniD8kh006JaS3WX zG>I1KO=J)9n;7OG`F*;NV2xfhKId~W-U|gWJxpJ(o76IGN5Sd*bL)?VW*hz|F+5G) zDBfo8b`R_0)Gd`%J6t?JB8OK1MpduT8KDZFQc32DV#6#bL0RbXt0X|W{&J*P|~e-Ycu^>GyjV)cXW`i`}0ND5j#f3 zB{DXVVO@R?N zj$H%A-%eL^S+Vj$U0q3K%vh$#p#$w&+Q~W340=zT2RXL_N!xA|Mn*G=Byt3?Y{r^4 zzgS7Al&~hIlbfd0pw>e7Rj2oQ5e;C};OARprmNX*{Wt$&WMJLV?}9N9Hg2IbJxp*! z-`t;vr2@T4Uh+nfMX-5flgtZL)ctDz$#Mv%9C0)2CyVdL2>=^!7 zY64g&U=d9NA|I)T5mu3Cn+w>s=oZN#**S!z|p-)!@HIMB|zQA_7&R z(TnGDn#je1v%^+~;b#&bSr$z{jg z3}Z41!#>bf;|OXnuA0mjqzC*>m+2@Rxt^>6txplh;xfM-8e4*qu}rFqLm4zDxx-Sz zk4}VRZ@XXCK4=6?U2hGY#g_c&FGA<8i zgQxYOh7}rb6K6v4tQ$(S8m+C=D=)ie&O;!L<`1LTAk5W%DRIU)YB7Ru;N=D*e#g3? zr0wPFxVXdUNN8JF1!NfuByZI-50{k;Z%hn1i;-wS5rRiQZ0-pZY-S~2MHeuUo2^Yj z^d{eJlG%yg@^H~rG?Q}9n6VRS8FY7lRy+i4OM{YRV1 zxLrT&@c=S^*TmW{Y8w%ar213h2Y_}c+udPyU@9egcHDC(_31ygMa>C=*6!iq`g3BI zGkFqj>4Xjd9Dwm7dsnJ_hZF)1fD4UbaqA!KO??S$$nU)~`3eei+s2NNgh;u~;fDyu zxa=N82tjSVlJw$)w6a?OQWo->7({>5Mp2&jJg1hg&tYRA>~VnKhQEPVa9uU+jEmVE z!e2)wLfPaj$;!)FNP`UJQ$Lq5?q5;gp@nr#%SdK{>7^t2DkTP!Pq1G_v;&-G5YQl> z&lqBBbWPKpZsUsUjB;jIpF5~zc|dHC)aEGnrSZ959e(>ki!31B%+N6HaeQB_VQJ$) zYWyQm&tA`Q9(?voO%4_o>cGe++e?Hm+a7`%0nzRSd(i}H$b}6EPTKQE@CFzYsRsbV zO<-u(8f;|SEwdkdm|(b)ycAz0jVCpk*#WZwrNni$LQj5I8i)u31kOC+)C8=_7SI8z zm{9S0IUlD+h2^)IkSo0gpDg!)LJ&*>h2)^n`=X;&F~=AnxpA{=&Cz%*(KXyhsG)Cg zJz<6bt!eF?Pi-9vE&=?=HY!IO>n-smT_c@)^f7J&b(>Oamr-k2eu`*EWXTbSRQ#ZM z7^ZfOn_=}~jWCz(e?mYp)zOn0mzR~b*2%O1>i{v-D19Oder!9v#p(bFlzyEx~NR(#3&6kQe7&=O>N#+a8#GMFS^dilnJn4 zi1c4$t8A)Fs0-6%6pW>|!n#jG?2|=n`QGwX1Q@=mW@?)1ZoW%rp`KM|mpwrvJcozr zjVBHB!GofNn7JM-@U@JB*%4p^{vgCUW-gL04|Wk+#fMF|o6lLgg?RdM5#y)h>7~Oo zP$QCwbfC36|2?-qV+sO{?LOw(9AKxw^Mz;2#?X`Bs@fF`70IW;616T3O;jHK>076j zgi&_!yl(I2n~bH&cZ2W(mPN{-$yUBujL``fI*dt`cA|*HYsITX?KB`V*qPrnP!lzg z$BVLIXfd(cK2cr&5D`v}`}zoO>uulmg|$4vd^@&}pyu}>_tCiUo7UUn$U|8PxA_cQ zxl&mqo;Hd67$J&_-A3^G32blFA%Smy9#3&Zs}vc-6mH@A;dt#oJTf0d$U0tefBUi( ze2n^uX_YzV)8BSUNT2{14~iMUsNVt7BU@$>my~q`!`vTqIr4#?RAWKE5Xp34odH0= z!2ve8S}kaCX;%!mf!EYJ`kB>L>;Ze+);l+JRB7ysO3!YJXV)w&QI zg}xroV1rIv;V0Kl16=!P5N^I?y;?92q`hxuB;Bud3M|+{Ni{u@&7bo-FzSn)l zY~`^@>=K}BBQ;}Q+#XZu4(=Fn`)2m+u)!k-G_>)UdJ*78UUl(<>*P2>@BVZQV5hAo zWdV$`;yyP3TZ3{RTFtno>T&DA(sXUt+4TmfK_BXYdXVNN5I_(bXG|D1LSh^9VT;y| zCpA&nrqT^h!G~aZWlz}4#k;5_=GaNjYLL@SqR-NUh5~Zl{)Hw@HTgsK$Y98DgS&r# z7rj>}&o-u{u_3iYVfUxYv{`wdIo8er;YDxyMH zVX!28fL8)SiwiLX+HepTd@VBLGF7d<_zh#^tukHsh1-u2Ye?|!@S~rvvlbOZm;8p7 z_!SdfyIusPt5*6}RMk=Ui-?i*|lhrKy2hiCCH} z{a@(TFv_2pG+_@}jHS$RHm6yAp=!JK!LfKU&a9(#Q(Y>cnBTL=nW-^ZO0c1BH6%jK zZw3{1(BHzM5B(T|nmeLVO=*Y=+nWa>q&%LQN!wKMn0Vf5)FMS|o;K+Yr5zQ#$P5 zFg~G|Y?1Fk+3ZAhIV;!-LmP_7*dU&ibWyQ9Uk-$m(!wHBRdOY90tYPT8hK;Z@ca6@ zJ1{})hP<-4q?DDag~ja-ab^K@&~kA(pdz!`Fryzo(ZD{WdNj$ZHfJBtiiN@UrPkny zJ6cCDpFD|>U-B`ilxv1+2wOV;0vXgig#$y$gQ3>PoVA+oXIybK!Q@rU3#xoj3<)7B zOgDj;Q^M!^@b;zl1c4;sl!>DJTnlnw3*$fQ+6Vm<&Pzn_C^Jdb57e?<=#d0m6E15i z9iK1zIz@_Sma~f2t31w|4#q}!F53sc-JfDx&3kc%DeNK8@?!QTFp4@t$~g*>Hd$au z_?_Z=aec1!ZeVe^8ChBqD6XmTsXTxg#>5tIruKxle$imQ2u6155Gkkv?^5x8<%CgQ zWRml$ff*laDKm9|_n!oQ5uNe&)qFLesnj~~u@dmO3tchZ6szr|t(^UX`cNRK3<<&qNnWx&VOqIInKK3wkQr+F@BM>gLl1 z=JIi4g7!8DJ42l?txuQp1oU3_8dFjh`ksh5Sr=A#D)oO*y$>~nyptk=jLuS^RubVP zk!Sv+0+0muLTV=LWyJ!ND~@u8?3-?fX7wue?;2mEnItj1YUxvo&)fhviuaF2Eh*x$JdD-csIjW~)&=oKD=Y@5D zzWA(k@|86e<`*}GkT9?1StV&jCI6!vG@n`co_ z?y3XSG8TvQcKAHIG`4%nm|6R};Ry3Wmk=OT(ciG+uh$H!}vG-N{$SsUD>zWAl!;I-|wfQ|y-z)@~rFB28`08RtSLizn}dG1lpvbu(MM4b2fdt0Vj zMn~rDo_`bcozzlB&xZ|vzol?Ps>$i)s}&HsCRyxp*0ZfjP7MMG$XoT$dCzR!Rad(iGWZZ|i7E3C%M_4yu=Y2%y zDD6U}$xYoHzk+*+qZwr=!lY$84wBMXv5FKJC98E}ZX|&~z6&WS1_3aNa6X|};8wx& z4Amf)I!IiBKA0vDf)cV*@kH0G0{A!_=D+18Xfas>fspz;a!CHr?>!(w$Q`|@xyo33 zumRun9>55_n0bAxa{?lGnHkyH8Q%33*6KG_EDZ{0kBZMP#bW~+o6-4ThIFBV7Bo1c z`T011(VUflrkCOCzsx#3(^>-L?FEoATY{eo6yJ4-b!?rbcVUuPPb)9_MMN5l98cuO zP9Q$(@MR4^4BYsL)A|K{a(32OCjn%{MMXYx*X`|Ptxz)^tPZ(TsrrEX%R(^Jtx`&sZFOlrsKxnJH{TUwey9>m{ysJ@I z{AAACnmx3%Ji__ZCkPP`Pr!+35kncGdc#)#c;O&v0^LCIPwP5+0Zt}p6>unz?V|(g z)WFOvv8;bnzdBHBU% zNlF%UbQ7$ia7qQiBkDCK^1Kb|E4p5#9oE^{msLot;F90$9oLBIq4aptx-FA+9b3S0 zC#Y16$RCtdL>$d8Oso{ThTSH{)~N^%Nws5ffvoRZHX%bq!y6d?q45$wYRCdu(ya?SFth-rGjSg|D)B0Xn((j%D-ITWgS-J z1U^4K7Z~4)B$n~r-z#4P3;o{S3#RAUWaQh+V?X^~Ir*;_Cy>1=jm|NT%IE;V7BNUB z2QYP_Ban0ebb2ZDuf-8b5@{=K_pb7IBlRZifea|`Q}`Jvp3d!&`K7BC7CLGnQ@-xj z3z;mxu_WQLySW6%KrQMwjL0}jj z3K;?a9Z1D*$6XrJr;udlV`S#;T1>GF;sqik*6a&xSQjQjp@}DvMrt2UFTY_qef7cv zU^;Hkn5|YPH1Q>P1WlMcTuxuNu#nDBtK@v+;ABV;RTUiH)6Y$u?{l7-hzv3b+}PS8 zdQ2PJw(+>>Pz|~-MYb)svsOcIG-y5L!9+jlg7!ZUCD^H^wdnUHqGXp~9a*G~)cMp; zpdaI6%QV0vfkQIP?JL}>H>Gk}Y7(g6W1HZVoSR)Ox2uL&7&e*>l_W=47?@pNrN8!Y ze2h>NB-lcnU8S9M{0r-xXUl@kMM`^|tAKIB4_{H$m4!lWx(Nf~Af1sKV2_8_O zsH`amIy8j3wr-lm5)_$Bh;ib9E)ogl*tK5tLt_FHpotu)A}3Stj43O@qpO{cO7=HR z-mLS`)=k{)C%cA<>#7k+zNY^OTKX-DgN=hIM*~gouk5gnIjgK+ftt_7lCe7`CL{jy z6O)q@g*~(HAEF5J*}&vvAUo+_gF(=QvqCm2d~B39+mG|O<49~0<#(4_uRu5Ob$Y7G zSak_8R^xF#8a*&KC(O*4B#*!slP-z=3}1~2iKzp{MnTA&oF+V2+2(i#-F#)9GyRn% z*#s-eENNko4yKS}Wf^vbG`UE&hQu0aD`j4!?p6eYIkHH_d?JxgK1K8}JmZ-TdA(k& zGGo}|4W$_`&rD5`2i{bW^S}ev>kUma9-a|*u4nHOl^{0eVG3l|Bjxqr6yx(T-dT?) zB1E>ky`&d=W<5;AU0Wg*a$r2{xsz~sw}Nm-F-@i3CAE{mP60+BX8Z9%@9Ve@eYBoO zYI{^0G=TgjVbuZef(LHx(cB7vHhNe4Opwz~fSY$Unvgz+w<21zi0K%)tOL?8%& z>}Cc*aE3FSo*X#4lNOlS*&uG#5-aVjw6l4oR@@}{Buf~Dv!vDflnBdtC1=5sqt>!d zI)Tpjt%Iz);hp94|JLdAVgB#E>IRA+Ig;-r`#us~9nh$%uCDOn?+ttCb)r0ap4F1t z{<*pR+3ZP8b~znmd-u=jC+4S7JtOPOC%}UL?>ZB&C0HWS_-&WWp!=xI<6^rKi3B{2 zAeG{hvOA5A2;*m+l2qtzkESeKC zQ%a@#RlRtn*pP}SXr%mKIemJv_l>)s&_Qxr#|EnVImHo$T>qFT!zB8S6y|~4KuZ-n z-$Ir_$HwwtRl_2jFqc$@W`+}QWS@%eZafWT^d#9YhaMR&Ib_Er=J$vD7X7tR-*Egd z8@EJv>o67qzGUNS*!M`{)C6M>4uF(XmqghJ$x{m4r$RPjFFgtpkqWy34nRgyv8>cS z$v#PQXc+G1Ci|(pwO5Eg!FO1^@YLR$m!A8|o=-d!9gRc-!6+Mh>cY~^FMs8^hd%LV zfoNnj8s(A}lK6B%Teg&DAQd(>6FwW5nC(6j>FZc!vT_McI?a|H$_AXnr`|5JY+8B- zHs@$_*;Y<(Aj?xLldEKR+Ge*J-NwsEX(mmGQ80fJ$h8|{H^ArQ?bMvLV9%T1+!Op6xMY8r&Pxt_ z{__E88@p&&|Iut@o!zH|;lQu%&;=E)j zm?yhkV8dqThFeCFe6KQepb52Xdbx7~Cox#XsOX7M=-q# z(1?)Llq>pj=nLVIaCqd~l=>V0pj7PdVE(blz( zlUtVA@;JI#PG|`kmQ2HdS<>{;_oA9EFfb61gb|9KLnIji!W*~(cL5xS*e_&HXMuX3 z^)$@?cKW}aW~+D(r~R+OX;W52Z>*nYRoUGV{1;$tWztXnH{N%j zi(XGX?0e`T?kz@o1Y7=DKnW($$f(#fnbd%<8fK-mp=lMpuIs#S86?5&usofhnLr|+ zd+dt$F%537YZX?8uLRp%iJ|2U$OR>kTd^Xn8l^R?|6c3qz0zUo^#u=dxLHuE5f4k; z5W1%Db5u!rEJnL9>4J3+-E0_i?2+=z@`QGM?T3!!WE0wnG zDizqqyQ0kxc6EJy)6#TMlNi_FS~?l9#vu!v`s*L+zv1JR3Nw1&cFP;iS1LALMEBv- z+IPyb3Mo^pAAs6U_!V-4@LO@^vsYs!WYsmGf=y614_RoPAwSTr51>W)B_IrL^@sZU zLM#EN@M+71I7Ts-&3={jCrKDmEjC>~p)Pgq2TeMmU&s|_74k44y}}4s3ygz} z_`I|mc!dLC%eM?Iq~xeaJFTq%Tb3UOJ$OK0!eoqJDrmL@j){C$P=~y$})T;26iQh28gnQSSr0Wgtj|J&932v>DgBCO43$%EETVX@% zclut3uh$?e;^#T#@5XsEozA;;W;EcjVS&;sHEHMBRe|an+)lq?n$5}8$=7Y7zB~Df zkdx84ONHeSe#WHH)3*i3?@8P<9{egv7|e2JYGY&SqDHl;vj4{#H?t%sgeejf{lF7+ z9e-Gz_20a(G<{?3{>;=RQyJ_MLqi>iPceU z_%Yci7DI*sjUli|rLg}pNDK^vb!r-LGg`#I0oNgkXq%)}eksfOX9X5TC5aB>n5S!V zL2!oOAvYcvxF!t*pw3gnT!uyZD2;)>b5c$ywl53*HLn!=?m39=HOIiurYQK#>*c@)F3qdq@c1UQ{QUAeaJYWPt+MJ36}e z)?1%Y?nM6ePUSz0onhWHW4GS=_)GlCOOo66RwSRk4zfTZD;9a1{HW){vaL;S&bO@L z3x~g3w-iu^t6c8OHNFlQwISlePy%J;ts-fn(y$sGeTgl^W^To--&@m^C-%pNpBf$e z&yC-T&D`=5UhFummml9BOG!fAc^gEf_MR6#v?9?XT{BqtYCHZyiuJ3Q8V z=(!_D?ml|-Zl3;HI9#pOv^Vh!l>YpUH%em8a1<9UHuwybZY$wW$pbL4iniiR7mHv; za{BwxW&G|bp&%TCV*Q)*vwKs{iu#I`EB_g#Cgs-8Pbn31BYq}Le3#mm7n4x)P;JZV zH^q!>-s78O*A4j;RGWiUh}jKP!A)~n zStB{WX2kBiGj{Ncv4aO=cQ&qC7t0z^Uq$TFH+XsJ4ow|G;zdt8_K?hFi*U<08a=&}2JC?RnIh&s> zOj>#}D*&wmuGeB21vi!|x9kddne3LY$Ima#{%sU}Jtqo0XHS})8y|P~CA!Wp#iEIL z8ZJNo^|4v#ue+n@^_lkYdK4z^*0Mv1Xl&_xSEA4Te{Y?B@NYs~pX?q^5;Ylo{RveE z_F33)T`B@EN(432OGWInfRVJu)*Adou&i;Q^n)?5f@NzuL(B=UG|&Elq*Ju|O&78t zWMn_fUVfP!dc5&CQ`xJpvYU!Ukpcy84YHsjzfbZyQ9_E1VudcC+i16#3ANJJj1cf0 zp|Jl-V@=czaZ@4i=9u<{aTJDq)1Y#zlUC6bIY-GO;Gg(ObD5Q%b@eUwgfs4nh8&~K%`j(k^s6CCh1k6*r zicF{LmUQn=*q=20C5TPQVnWgicGu&N-&Vcxu`2wrKY1MXkKI_kt?{STs^k)o9)`#_ zo@5=^k>pL!DC*Z}0Oy#N`5YK1eP3 zA<8yrGN%MJ!lDgBRGQgd#;;zthMTM$&a_vJn?0DKlDM{g?Wk=O_D>Fp+9pd#W!Ehk zWa98eHWvz|EwdR0Y!?a4Q5gdZ9J}|p5(`m%0OAIBjn@Xx^xXXcZ^Cn!UFz(7wj0%V*nI)q=cXYX3P<2`WiGo77Gg5N&d z2|pWu>~9~Rib4Gu)cBf1BL50}0;$lfp$hX>fwfgrM*IOamC3v~WL4_W*Pp#6J^OLS zc-0!$X#c+E*Yi||Ju87{ne^-@8rOIg7^8jE`ciUn3UnvC4^avWJejF0@Q+SGBz0wP zWyKQxwFaSNZt|E2koI|-0UzLmOpXiZNkrZ57ytlN$pM!#IjFf9w(Tm{bBkKV#zrO* z9&zaDC|D%6&141U*J&DSl*HMItf}x@)I3(VM(5id7#UqR9wBTi3wX?{(Fz7 zI}}cgWG5ykvLlIbsN3Ti_w-HdeI91HlDE6tTgD_d8GmKrb~f*Jb@ccETg>h5?CSOP zbhz9Lj=eV|kaNB*k|Yq zAi{;Tq~Qtj=tik@1=AWGLaW{@WoVuoZ(;+b#Py4s368kM5@byl8?a+WQ3>}Ok?3eN zVt{wmU}iAP1s)3Owfn>Sdjmk){+xy??|7ze`rjeobrwjO@#V~B=h6?^0()-jsH|ZT7)(8pd=v|q~KVAJt2@lk9Whd z+g6KMD*<`h;3gagtbG}4Qq>uO{50120c@H{TV2z26Sf-c$h}v`14!4&C8kb(SKP0P z4oHzg?3E-b|AJ>ZDlLOY$2n{@Qu@&5v~bDrIA@*PN};T9EN;1N?qLR2lW1st4HNpS z^V(ZqY1VaCfqUpVc#}|K>3&M|%xiS9NT>W3{_yk-%>}q{IPj<&*B*ouYw7o88Ms%6 z)R5ROXs0#O@gH74yz^Y@Iu;H(#J0!8coZmWN|M z?BU5x-bSbvLv6l^4+SZ{@FJvS*Kg~~Oll@NW6egO-DROre0luoP80Xn04LxrkUty%>#fT{xg5~Nh;3a_CFU&9CM#^^iKs%+h^Dg6D* z+T8A`DsM+>bH8;B>xQ^(^e#l*rf@FXJyWwgAsjVK`&6_4>>f#7td4z=o(OhaiO4%% zgMUv?ZQmowJ3NmRu=)dDJwhM11^5&&aiCWVhviu&& zD?AC(^|n4NNpG5TxBisfPi3n{xmF)+n5~Hvh7R>XtceNPH)lxx_b(sYs@+;vi!i8- zyRF6Kw$`IoYxOgY=5meK)3mBtZ=3%%_{=9YyAY#xEZQwsgztq3kIw$(PeUW!t|cGg zyhW`M!|;3IX>xSjHfro~L#<6BlIBI>NvNvLxeA}WId<%a5O3UmB@ZASO6!p2=LyFK z9gM(h;wvi-Aa_S9fPdfg}7 zu3jdSAT!EqyNZ#<$Yf8lD!1&k<>iDgNJnaj=wClFi7e664|oCw(zFYc6T=^R_sGo4 zK>ivv18v`xx#20M&mOZe@~UJV4$eK)lYIveIw`aG9%|#zi8gn0H z731{y$R3xw@k;dZ8=w3jNIis=xQCEC_*#rL;`}QpI=CZFihJG^vV3W-=-^|ZbT+>A zwfo-F*?GCM+t>L>XXhJpaag9irUsFJ^<{h$_nz*IbXm<%2>qcYb7?>F^M0cg9^2>uqneP1J?jHRpdtc+Xq6>-T{P6tIPxN;G+;ZRilQtE> zYPLN{0MXq7gzkp+AYZ#T2Y9~I>bnP~FH@DJXLdE}hG7&X$nsgKe;m?94vnBdY2c9J_0e8S&8FE}VFHoPo41G8$ihHTbGQNc^ZigLfG3PXcW z?hjm`I;Z%K>6&3`8@d4mSjjX?xRE@Syr5{VAZmbU4jA2j_%~|kU8k%XWhNP5=TmNlx;x8es!h zk$0_9r~vd~E+OL!aFCLtDPf~L3Q0n{Eo{!Civ10Y(kTyIfhro9#|e3m=QNk7@jT{5 zz8Cf+J^kwHa(;Yi99Xg<=oYJSU5{6*c|KB#_DEq$3gysA>?O>stgcqBNiP8Ur%^5& zx`|ddZDTdM8Ba=-s&y+_VsZ>o%ZW%^^6eysnHjvzH_A^6h#XW)oSx?6D^AB13b_8#hKC#&S zN8KN%A^Z+Xe@d{hd0{M>yh9k}|4Fp8vF*=Dt{&xREJ@^9a&3)FJ{mx8lfU6rU1>R6 zDEeBcTn1gGxv8~bnk<*4e?4npyU!3_msF6GAXXRZkCVg8Cz!T!Vv|?Mt1IS8o}Xa) zzmGK{`i5`D(5Q>J8C3x;x5%~0>?6#vzf%{)URAI&2^pTP?&$1 zK}hpB_F!YCj=tv-#T;p&^3BqCaWOF<+H&L3v-~tNt)-c6KLe<}uQBtSlgS5_a9{68F#F@VkuGOnU(cN`Z(?{RAB+E&`H{XJufw71 z%+37$djlS)+&eV;*hI+VML8~WvTijEcyNPbE!;qECrL9uk#cx|`^)=KW6IP{PkvF=2|f1~Xo%v5skbc|=_bKP=HtfX{4}M{m-$6SR9dOtcme zNs#VbNKwW~RyT}k8bja0>`bP>R14P-CK}g5R02R9&O@%BgE|DIVNQ#Qg1`d21@feC zi2~om3el-R(nyYj6mU(jbFh*kEBJ!C|iHW+lTOO-|i- zLKo>v;*I`tVKBYin>rplHoRg<4%T7gcFg8FPyXiY8?;*ODoJN__#QqwzoTf~L0;?2 zlFnXk&hdnCt;%WG3Ksu^O~_U!ViS$8#3o{I)-+tLP4@6aY;rO-5jPE(xQx|RuFZLc z)mdJO+HZ6?oASVB`|_%}dED5GD9Ih^Ug|yu+lY9=@}L+>z@N2~+FKcGg)}`dV%W|b z(9Aq?Pno@9(-}6pWY(fH*egIGtg}$rC^Mupj4}}#qPAxk{q@saR?KUfK`E|>My$f0 zBm|m?W*CXs!HWygfeDA^Sll&~zIm5An0IN;gS#G~MdU5r^Ly2vXm456`6=2aXp zFQbI~#g{rdzKFx-)%f^${FPT`e$5uK>k0_#(JxzKP1~M+@=D+&A~8$oh7n>P8{55a zys?pAJ}|AEoY;MVY0kac_`c=*%yD;i`ncGN{ZgdK56*E{4ystQ)mBL7I-813$WAm4 zbn-wP@Um06^dJLcLOULZ;796~2DlA&R!(oNU;VwY2ghTqzpa*)_r~5h9y_tAszRO~ z^4_6gr53h%=(15V%I#0S0gTMr<{WK3P?aQ|I=o5iRWP(>v8=z`ExWH&N&xQoR2tvZ ze{B2>nzHEslwUrUW5Z*+C*sLWByngat|qcm(B3*KLi*5(MO)6#op9(-g+e0UpNV9; zW)5}7!^g$e;u>6wTHr5%S81EJW0gpTiW*(&>czUSp|(ec*gsgvbQ z{Owv(M_RS?ruOCp^1afYCtszvS+}^kfre|fsc(RzjJfUI1yb7k#cN_Q>{lUv2qT z7Uvc@AeABJUI_(MH4v&s&?o+)Sd38LE@`OU8+dE}gwI)O;XR@#lZ?Nsf_h+Y}&M6#%hz24-$~Q+;YeaXQt6nU4iux3AQ!P;FDG z6|7Ntecwtjb;YWe*xQ|?wMOz}8=rPq{n4A1S)Bk$9i8{Uk$m?D); zY76pWMO)K25&{|e5LaXX)1=cHYP&JA<<}-%O<59g;B%5h@TVs=rpV`#axFu!YFA(hZB}#i_bti zansT%JMGv^TTRl5Tr92;m={mL&KCW#$wz;2t z@lpoBUBE!FXhbq>1*qxuF6z}+=^e$Fp?;=mV z0^adO`tgraN@aWz$|%zJSt^5m`bA2GcrRY^j8b_awZ=D2;teO6qTPT8H#B1eJxBT@ zqW`mWvk7HjSus=BzeWdAw}sGBYocp&&WCdY8q8`-XbGDu{GYrIskml*w>P4cuG$hA zt~9IAfi7G$gt>|+P-=}%8Y5P7BvJkKOS~Oen3YX_Xrub@SYtjOTZx*ufKIxglK5G= zukm#@g#x2Lr!%dIYghZ3Go-dk2AJy|6XfFmE&lnNy^Wk#I+xzDCrG& z4xDvha>k&$!Y^_BrCPSdPO1%md+jyi@n5e%y*LnAt8QgN7htigR~s8xIRa&%L~;mq z42w^j-<)}>{dqBZVZE`T>x%HiqD;}&*dwk~bB=Gy7cuwdB*g_^w9(uz=Pi)X@;W)z zg#9FY^oKW}RJEd6SzkA|`HD`+gx@rqa*F>7_45%Ohk+xU`6TIg(7htHapnAZhQau1 z`_5ls|MheGR~r8hMgzTvJ?LH8FF6IfSXolJRqS>?VeHbY|Gq?BX$=#T=?#3T3})5_ zU16n2M&kMLb%`XelwZ@Qx;@Wg?HoxJA3-*#iV5Xg!*v#0>^q7BQ@6v>208)Z4e7%gc>XQy_u1hjqfKj7sY_Y4?E|mEi-|Vem3C}py?#osYZy0T2m2MENfn2r< zd7(KTOy%?Q=s>72srJURXWv*`JnOAM?<|=&e;^qAz|CgmOM&|j{?dUbBuQ>c%*C}l zEyTDI_9XWY*rZs2I9e1Fkr|f>ZN<1`9Rs0(dJeuZi}Xk4Cq~mYIQ;!V!*dC^rM-kt zzr`;sKs+j*wEI&270vR&3;RHFP1ydB?Zsws79!)j_Tl$TS5nzB$gkG()h#eDfg9+6~QmN~O@c;(2(^x?zPxWO@#tb+~v zi_O^e^z1vthp4qXg;loo10zWz%(vvF5P%*UZtQ>+t1T;&nmcdV-;#MMD;Fu!Tq!UB{dXWxE$_d0aeujZNKTN~ ztdfuqaXtldVn%b!^BA6dBWr0^1Q<5>tgd2&{hDo8h8i-lk40h36}DeP?2cbRt7)t% z*-dBd@xhmtT5;9e)8jSKEc{V=do!C)p6 z7#a*@fZWq<`GiZreng57sw=f&O=bm|Mf*y?ei$|E{RgNX+)JG)V*CZtz@Mcw%;O$Z zh$E!rUpa>D7Q`>fa$wq`mo#W5TM@neBQ*DIY*InmSeKMzg!>@NvZ`)}b3JT<5{JpGZY>dnRnuAB`v0GwW zZ1?lh>!kan2PMh2#ZYH44p@G!y`9|rdh`1%Y&kf#?b_{gx&1zC-;N#6hLNW34s~{R z-7B`e0T;Sp%R?HVTky&9@yV-P$GXmySy}z)W?UbPu$Z^&FYDy*dm{5VTtYt##aX zEA8+LB%&QctB89R<4-B11~v_BjaRtQC>;J6aV@tA_A$%MB=SfVkm<5bM6%XZm1onxL({d4 z5%P1hN|s(rj#3%rl>FY59j+iB3LT)PT7~AgVxKUWYX2)W{0mWb%iw8-Edep?_Bi@| z-GRQYJq#PA!}BRz~|9dEO zqWP9;!hrmQ@HSPt^*OtPG@#@P-2STg+f_Qc396=S`MqH4Aw+G{X>R;1O|-P?aL%Ti zGzz3`rBGb+^_!o5`sUr!GrM-pOtU)NJUDpQ!*>l1(h8)r%67l0U3mKG3&XJk=gu97 z(Qi6}5B<atzKg8^uxuwxYqs{LE+Ef#k`1z_0H=V^Z3W z=cIjW+WmwiiCk^T^v5-8spiqii~WMf^QFZvfdx?GKf{Pk%_V!I>|=0>7d_v~L{hUl zbY{sT^hY18AYm!S(S+v-t|Oa+i5WDA=srhUTd+a~m8Q&P4c~CxsNA@CQu*TVotiwD zc;H1B`?PD}UeCYB)BowfZ^F~^v#DpME6@0kUi-zsz`0S__Wop-0_Ue3&rG{*4Iq^t z6(xd!oVvw|%w|r%N!+h)W)HO_xrb7t3!|e870&rGP2>!J6TcZHzFT4yhs2RBNI$I* z50cL}HBNF~)DPKKb4dPIAjA-sbj1Ms4g-&#BK&ROHR`WokfB#~>rJAw0e_2C9^>Y( z$VbvH-AibI60@E(RM??#Gzy05V;SM6H&Mp2Vw>%DGll8@xtH5|=7 z`JrsWGs48ecVkt{tOj?bwY7+!w8J6t$OKjc{Sj)LKTK)VNaO$tM6#MyB7)^TM>j~} z8%S?~G>~l+1KC#aG*^xaA=3lTRIJkx9)FCZi_m3O#H+eaC-oxUQ{nI;9+841sfQ-z zwqlv7-$QM9lq4?|dv%)%)p_hAD);Ahs+PzJdHD<+$XU$Qw&sVr#`&w7!KBi@FNxe0 zGl{*b7FSP2?Q3DbB(%3pQ_QtE%Z$Kbiu(eeMaV6bj&KC9*VC#yLFswnxN_>DedFn# z{=WX6)0ZwWNgz}C=k;{u$L~Hmz7**03i^8b5qp!*kH1Z_3WZyE1ROtBkeS}{>4uKLkqP7Z)x zLJ)!w2e`V5Hq*MkiYK9PY`2oW(YG$ z6-riSZ?kDaJPWC6@OZW)!6Pqy(+a(GdKei=6 zuCA@s1&Kj>l+Jd1g!UY^7uSh6GksE+>{T|YP;vp>Vbv-O+6&~Hm?Da91=5T8|W8luUi&c#r0!fLc@RPl=aEgnhVmo{?>cGF&x@Tp*Lq;B`%+Va)i z+NU??_fPkn%pKgW1w@a5?^Vj)mWdE=ap$)|R{9(dWT#$ABmV_fXD^6x677G&=V)#( zVE8^w7#|KxbDvH+pMC7H#&0nbrABqIoc=$x-xgyfd!!JLal!)Ii0lG1miXL(irJ7^ zYf()bw65#ioSEzo1XV$U~orNx2I97R?WW%jf|KaaoV(c zRf799rDr*uxy+q=<_lz3ni^J8VDt^BNNld;l3jjv?^}QF=KgNk(K$FdIS@vR>gArU zfG4UR7)jg#*g1XO?#Rr@K-j8JmFm;qtdA^Ck5%2cTVAKBmujY2Q?6CNI>iT=hWZIV zQa4vm_D}`6UAh{wo}o&@&2_4(x2rR#^mI)Q^z`^G^}-MxLi z-923cBLh8d0A-hhsewq)-G}_wXQ3uHLroNl&IN^LGs9R2j6s#K-}8BS4oiojPo;C) zd8T){I^~eu>FNs0T}qelofr1|Wj4^$(>L1J(=)(ENBtg;%jNO-M|Umsy8Qj4yX1$L zB7@_L@jkc5eVUL)Q& zuHRi1T_@=45>><8_T><`0Mw~}fKaiak~_aAp`|G15=FD)K8N3>B3coeeB1JCRd9y5 z-Z=3H?IDxoeV25Aw@6lK6>DcV%=g+p&_Xn5U|jRjbDee~2!k*mJqfhU6#Zi4r_ZhZ|MDoKN#y7~6?L`yO-8^+!ihFJ)}$-lSS@uaI`f> zeLkhO)f^i>yLm*?Y$MdLL`JfPLFz$BHtZThi<`vWSH((J6`V>H@X|v=1H-Pea}%8# zBKmA=4P_u7E0q?p2Pb8wnVaItSJyUkseQB(=_Hl=p80WZ5mDcU6Ss7TKd}=NF4)AW zlD64TKn{`3^mp|Y*gZ0q*JqDh$6H{k>+pCgx7B07<|!Q#+3OGS2#vt60u#KY3xX)p zf{|P~v3v&;VfBke2G7j&<>mHHRxC=))-6*knm`g*>nzi24b5B`-b1m%&F~q?*|yeP zf2G-Bk*Qp-mv>0x(m4Aj`=({>5GD)1XK9jNL=;`zxNo*qG-Ay25VcC;ZNIEVu8L z7=Dqa%jL|(Qtp$~e~OgNTi~|bo9Mpx3HKr0I3xMl@3HR?rc9Ijmr?r#mJIViB2wod z-xla2FgP(rPt2jh6;C!pDl#6w76>^mRDNP2-5(n^j1I3OH8hlRcsmSZIOdQ&PNzq9 zw0%=0dD2ap!@iFG#bi3|l6yRWItEx{o*vniPA3=pnajzT)5W&?9^ZgCi+72(&lZva zdbz=t5u&{yhB5^kfxQg-4eeu-vB^)zCS&j90Z~kI2rd-0EL>uyVw!J*Q~1Pwi(Z9W zdn=sWWt#7YOW-VLNoxLx_!jc5WH~68U>yp{oSbv!Q|!Lku!0cVy<>+Pb>L+y2D|M> z4dsfpYf_EV@Lb#Bwm2sMF(=@0^m1e6KI}U81d%ZRD{b054p0&;aE(z-q0A_fj6$B#Vx-sNuA9((zaPAR2hyO#{JN9 zWUoP6Ub&9HJH1u%S!g;^67DI$ND#kID~7(sCtl<5H~d>ugRp1lq+s$}D?0r#L!8^q z7K)QjzMnQf-fr(8=wRCRp6kW07w)5w^x+3d9R46lXBX-C{aYi})7N2ErL#R@N=c5s z$m7$CsqiiI3ixB+V&B5(kkl(+6#SR*$DvSjq4{$Jb}AU_(~>jr4oz7 zFIZn=K8ki*C-iu!gw}pv(BoR^1SQmaY+1n;zXw4hK$~-i<1OTNwS<3~kcw*(0;`(z zVba#4Hqc`jXE7q%g=GQJ;ZpN)V zMp^Nkew2=@f@U*8$EY*YB#rl?W?Yr5bdpEkv;FlvZQ6w_d>695Q(I6&vd6|7vT=-U zbU=33jW^y9BSrpk($~l7c;to~Zu~_$zo+Q&-0JD*^xRYg@z`x1PZ2KM28YF)JOTK| z1HZrV2|;}yr{g$WP0{(>4!Mw1Q~bHWEsj zXG_EyiGB(s8$+oM&hLI!;L8J<_H7M;S}ue9v{O&$dg3*KVo#i4aQ!v744)P8S-(fR zQq;Qnpe+Zb5kiMW`&Npo0{av{Aw$(XsIGI?K81T`dqQqB-6BmqGQoRn>AXhnir~U{ z=`=Ixl#bz=z*TU1bAo0%EJ;?gxO0*VvWzxOB?#S|J z5{%`U0vPY+{80!)cJj05H0`F2bA_b~7nXM2Wbs9R2){%ron#wff+SU@Y*J0}TuNzX z`9?AxXE&c*0QrtW0Sc5VWzQ7S;0JfzB%jk(38K4XSjCa&smYErlW^f>3iEWFJEz`B zJMug=S&`onz#Fo4bSb@)nY8=A+CIVd77!=^_qG%Olf;M*uQf>k2~)`-S`BQq84&FR zHdzRW7z--RcC*mkQ^TYn0;_F5sf9p8MC6o0z3I1oK8I`NH&$E@`(W_K+b*0td-H{J ztlHD~jUGoT<>+C%X1tn0((THX)*!i?3P*$S9jt3hI`5-(=ER zW75daS6cex@*B<;{<@k-R5y8C{j1uz{ot*NWPzJRJ~#sF%`}%;=UVb-m4JFv7R@PJ z%hBw7);ijDJ<^p8UY&~aDzHz9e1A_q-_u_XbmtRFcK~?eW(B(dZNPFWSq6jZgsCM$ z269$`LI_eV@OklBM4Jlo|JjKS4=CK_$~IJQw}5!9c3{teleoYPZew%M_!a~hjzo;1 z%+OGVb6_iMgT2W8{I=SfLJ6t|E@bCLufD;Ln}dTUCd?4L`F`iZv11ot!+iVc4g8HA zRg{G|vRVPO#x!CHI&9VrG z?)jmifmnL-b&=>q2Fff#nV+-0;>gpNB*HS64yRBE4AK@)%Q7m@UXQs9zA2{0N2Wih zyZ!OO^LJnsuqt0rW0UC+Ui17)OpT?FzU~|quTxbHNbTB;9r!aHG#*nG56|Fzf01MyDfHckil>It+dL*O_N^n(J3Y%8eArEJ@ zohWf88wLi3yanay6LEiJm|MahlzaL<=It2lT6IP~-rdZ z7tnnEq^9-z8prSP=*C~okNA6?J#+bi4tJu@*MIa41B1K9-uTA6>U2Au4pfaeJkAbx zS7%qc*Om2k##B#-)6?N_db`z3k1IB$xSYGw*QBpujGvpOx3Dk6(=SN3OA^CJ1M%~= z4;Lb=OL(^S=aca+a_J?5o;d<8Mf;+rbrGS0KN4rm2~X-_9UWc$-X7TlPa0V8yGKKQ zcvRWlHyG^aj~eiOQX5cD098P$zf9>}-F|H{5>9kDGLcTFHtp}rXe_BZT}~%+Zh6q& zUVKt0!_(~>peGHwov}VG-48BVL2u{Tr0VVhomq=6aT9RE#N# z5=!w8odR+=krGe@%)w3IxF*_xlpXn<;Q6<+C!_PT3#Tt77JmauU5~}IL_BzYX>>R- zz58IksQk|G*wO`7YP>5tpLpoh?&-ywW5@p=T|XI%=MU_jj>EU-gYkrhS_%;hsaxu& zngP-ltwSIT$3%f7uK*@u)=r#$T#%Z;exGtUK6uIJd}|`M^g)N?eQ$O8E-l4Qz;fiG zaaZ^Bg$%ztwB+imh59@OEKf_pzQ#|pv$!a+M+6>#N7eF5al(t{N^q4UehXkDph5E| z>!@Hdi@IT;45CN}Ok=3&Hcf&sgVjTa{WVG2B$*SVWLuVkDr8IE+OUUXy6Chcpc{IT zjCblf9GIF0zRvYJ8cdsn|F6TY4jV&^O+;NXu7|p0V`wRPNQBLf;)2JjaGm1WpkSv~ zsugR+4cM1fiwd1!7G_)RJ8b;YEak~_ z1eGavB}?ziF2yo21&qfj)>UfA+%VR)-_FD`PY-2cU)A5~-)2zdb6@U{r={0b8dGTLF$wLNRaCPFNmRhOr1$iP5zy#*=XH zFcg*Fw~wuIb%g#HREaIa4RG|3D671oTiYB9n(CIop2DOKXm$At|vHhj~{14p?A>mkA2<%Ax z@U_kIR~a;6N%pfe62w`KFx8wm!q9>Ongk_bSqn>e6}s*r*w_I`9@n(D!R}qCMN@o?D zXAOkBkecvRZ{<-p^FwEx-q&H`h#0c?WfFfdGu%I< z4K_BG@Wu~q;5`JSVTA7+T+WXzHm>a+1@SJml+HE?X~<7f3PKHrLIr@EEVY*)hS}@P zHO1Fo9~~Tmta`DaCEciG4^cM&V<$oc{W&OSXmB(`6?r=?upE_t-Ndhrc7#*X;aK<- zvb7KFC}F;Td^{M0?ViQOXk>9QQr%YK%;Ys9Cmk~*_;@zCTi`K(I}Qe?m(cMI`@WCXz`7BXcG&&6}D*J3Z7 zjA4BOpZ|OSIB7axhnM%?l%9tl?on9KAF<@Ke@fUV96Q8Tm;i7uMX{MH8-7r3BIl%< zM;X-qeuK0MKTfHB;nNquRTR8H*SaC~g_r{Prvj(!tmlS@b9KPR!51A0VVViHWOfy+ zHWNs%WmE07NvqAWlg*<7YC2#+PF(#{D&_YnWn<&M4#@wSM7wcM_-dFbD_<2V^JTNz zszudQpzQRu2K!^O2OCBofdGnwSvFIkaNtdJKNUI*FoYiX(CQ3(I3kWO1Rv8h8{Zt2 z6(9r*(*WW?kw@7~I=zxk&oEe{C&r4!u?bC^9L?UE9c3nB{53XyC@6Q_#W88_>X3s! z#I326@o_~Tj7DKtxy3g|oc|c7ee71s;&GdfPQ~ykBza*2Wm(KD2hV0%V^b)Z^>KWWV%e)|zqpz-BAp;iA ztGQGv_o`LEzwxs)k%$S$k>br??Xck_wYF=96`M;4AeQY^4 z0a+ft$STpr&n|r?9*(n(#--?)vz6$Ri?LxSVE*F!l*!LdH#Xvdn8cdx6@(%F-?F1s#8ay>la;j^x=PoG zrV){_!yN0^FWSg8r(p`PfsLcjrp#0h10Nxm3C;xl0|v$`#y-YZ^Y1ig`310Qy%BQ# z7tQq<&ej%yxC?E2_+1wRdEn~6MkLVZ^(Jl}?8n^&ezvjl3QZvV^A&TA@C+18*UXRx z&_P3;ooP@|ZF3}2fW$4gBGd!tO=*hkGe{Il_+t4aD=JDzFQPxDUN_cCYX;MpROWER zA;nNa2FSHbEMyREN239bddOm-kW@p|Q?e*Yb0(c0YNjlErlav{#~bD{iM~F=WTx&I z=v(g_aG=Y26VOl)6Mr|Hbo)bz=T2WbeF;A71;Uj)lI-nG zh7z4FM1gg6CPH)`?{Fc8qN^kRmk*tK=+r4ltaa#ROPZB$SrN#DR;utCQS%D07K#;r z%oa2j*rTKvDVr>V^-HXiUpM&4z(p9R@!<)T={^ogwYu1=zCs9(FEScZfT_2FqyD2V zh~LsP5#stk{%&NBbzxg@vYeWv29pt=PKK~0#OR|vWU8rc;AWnU`jH^p)8TWT^o2hW zVD7(12E#pcgU$_^IR*%OQ0wk+yPprGoNnMjIy>_(HR|+@Fv>Z8<#n+Am{|m0lG3UG z91G|0*$`RX@7pTl=DPN##v&_C2wDrPr#0h1w9m~2Y$c8z#NpU-lvet~_H29TvGDAX zBJt|1O8{#t*z+~c-Hl&+JbZMPS}AV5DL?je{tzFR-~>w62q6P8qdDoYgnma%Y8O#%CAW=sm&4xP|^2rA(qjO2~nY``XzDjNT>e zF_lES7Sd}swT?l~G}#VmD!0pF5Bq#qd?UV^4_t;p@mMB;>#}bIuENEB0A%+`jwXsC zy#r>&Q7w=O7*?A_$d1cEL8MV+3eZ)hD!gBlna$OV-a)vnpDVJ;;{_&B4pSr?jH*sg z#Cqei16FvCnr6Zk)6`0Vg92{pAX=k?eX<(jQwE&nEc-9+on2wBcnL>uhe}V zsBUz1u*hxGQ=M)fo!776m!l)y9m0G~QA1iiK4amlW@c5VlS9lHL=+GI)eW^;jYjiJ zH0BM^3bNwA5zSziN!E%iF9ZFxWge;GpXdyrm&-soY=TvA2{Z)sU*a9$CAoxoyFfFG zZMR0=Z+r~vYgZ!~@ZBwDA`B$_HM;uA)m2! zi~}u;e7(x{#y=4Izz1Ug(dQ4xPfm8k!^USXhQn7_r*(b62**1nZ-|Hcq8GzQ!WHRX z8L!H=LgPA`v6cj(0A1VFqKWLuhEfau{7po!82Q&VK1)Yz*}%!hgpK0NT&6+z`TPsC z|5~w(^9^nrATt*2Ww<2ZU&edW1oOS{-+43t-8gVv=U!vYQ8T=KoS=5JSM$Q@3m={y z9-bb)#m0NZb)gypszOisVP9rIPBipd@~3leHBSdwKlyej}J!wmDaF7IRJ zo1B!E|JTI-VxwJ+U-3G|CdOG8J3t45S0&+%2{L9N`aE_pK43EDtr&c^zmug*y=i=0 zUOA{8T#@aAKPJCHj_`9%{DKagmZt`jR^S<4BpU~b1+eQg>BZjnzrUB&8&C8aMlbYZ z8-tvzxH$SwvfsiSA4cy*dD21D9T~Z-M*QISJp6vJ%7Tc^FzFUG#(k{7ktUt)oqI}$ zX<2dz$mRpBbs>XOWsd{0bmix+5*66-)cN?h-rMI1&SevOD%j)6% zXX8tPR)=cI5$NSqt}qWvj4U@r^)i3om-UtW2fW^lSN;Igxy5@ij81eP@XB!e2VUWt zogy>gP5qBPb}e`>-XOw1S({d@D~u%&}!(ccfV-*I}w zd?eB+M43qIpg?xVkk}IgMKBQ(n-r&e{(2-FrVsQqd$&F^Xp9VYcL2jRIAZV*oxxQ! zUPmg<|1Mf3-x7((Zj!oIW&JEvq_&4!-dm&8lN|2Z{mCfc^?UTyF4MTobPd$MBW}iVSjRbMr(iqn$xB?v90b!ixK~{QRmmIh-G! zBvZXup;20ch`GZvj#|wzGhBf`fg42|GxBc-J!sCJ{R`hSKUyv7Mg4b(-(1{@AvG)I z7ng}Ao%(JJDd~Y|J?i4t*nyxbTcnD|rd4Dd1>Dhb?zOS6cSrmm?Mo1ma%|2>#vxl~ z?t<$y1I2D6%I0Xc>#hFC+!)hzw;{ zVBXp@^T5*L;iNh+lGu|-45&$$KG`Tu>iSE+Sg&^y&G#HJbf5nK(k&lQlLOvF!aI;; zlYNIK8vlh2OdRU-SIRj7r(2Yl%a%-exYY0dsVu&$DS2?ji&Vp>(ti%r%RKUPzKG z(yAjk1uL)LMrFS|6mjsPhtG|M-ik=KV%^xPh?4Ac6pm4n^hbC{AjFNjXlZ~?J+!f zj4%UgtV~uQh#62>hvTxy1v>~At&nQE)JnxQCpYyft#NBE%B2pu7?Oi*V=Cn`yrcGd zSi!-vOu{-e{+YQRWmT+&_Lxv!7a`hZN%5)5Fby^>&&oI45VJp@q8j{+aD^FmwB6%` z{r8;Yrn<0fq4wvoYto~!&+y&%!@tLl=}TB^Hho3QEvr2GXw3ewM}?Ek@#q-+gh`lP zj1_4|cT^eF&AtPw4;6whtR`Z>5u~tnZAn4>}qWlkabyQ)mS%H zwJUI~1Q&PA2QVY3|5I)XrK|`))K-l(ZFN;+MQydQ4!K-~i*SXcv^M6ZfFTGhlN&aJ zVg}I0OdYZ*>pHC=z-Kevw&(5N0im6X3O-8dUs1|*NH%|Py{Exr79^%=-2;zN~OPpar=A<7wb>x~BaqRKgD~B_4D6i2DbdUGkx_IR7yN?{@ zmw|_v$}AiM+ZyQCABWuTB&h=R6zn6;0=|6eY=;hgno{;&+BJTQb`t&0fZx^l@6x27 zD)3<}9g5*yls-l2uTk1I-U9d=K$nz@)oT1v?J;54iSa)=sfXtfLl*Aeh~4mO`gb74 zA2VV%tY4Ghh;lVph3=(Dj3j2uLRW{7e&5l5?S@zl4w$rlLu_*m=xG5&q`<0T6_^X= zAuFchbJTA-$d@O@qdcPMs)KqvQs*%`g1aB32#j>M7;O-3qW*L9?musi64Gz}nT3R& zZI3#`DU~EqA}W|bz&Nu)%drB{Bo9;i`Mr(xy%YU2i9?B*{>EQ14Ov%12#|4p0z7n< zCno$eeSI_j#vd1p=s+mBn{<~0jss|AOZq%NOz<*NcYLw{rG5xw~GTRD?Yz6qchGMqBTv_Y6 zOml$fa)a!F0>bI|TMwxduP7(i2*c_SLA=uOQll(%k-jZ7ai@$5hSwK$lq9|c$!?#vZ zN=VnHFf(`NB4*`7z|$QU0m#) z>D)UxxwrG>Hr>M1tus>{F5gd$1}}{UAMf3>r+4NI-gw5AYHm=iQs1pc91M4-N`OKA z4h63O)l_b`HXN5Eh6)I74@!IadZjZX11c`<{L<-5%C;3?QY51Tz{Gg~`dHq+BCR^` z_rDwJaNYOsziy2_8j2|wv4}Dz@$tm=^{RIEhC;oat-jHTYU^v#4s|5#!Gkn9hR`lF z&2?wwLX-zLZ}c3p4G`xOX>Lu8^A!6hk0%d?hJ!=C$=6T%5@9$7cgXwMaO0m6=JJZE zRDOhCiuAa94)pdO=ymrF@Za41!m^owJFbXck5)7a%>H`qfHvCS&4|++t#m5*j(laX`$xy#}u9ZYT^_q%CD(@ti67e8`ZDY%1SR5v3^pU zyxNZ2*+YJj$cdAjNJXLmGqio96tvR9D8JEo?{ePSfxy=&mW+Fj%#OvQ$^0_Yn}={6 z>bFnMQk%?=EBJAMq# zOt^Zlr!yW7;SGnUwRmi34lc){0LC}l;~96le~e$@-#R>rUbjfAP)zVN$0jUbZLk8o zKFEM&DJVj-IvZMbcJ|mpW-2{h)av}eoSoe;&022u$l|R%HfnKRkQNDzIl%#gGv&&?GK36E}Sx)AL z@F@lNdFzDHNSVr@v8O zU$25g$hvNtqGbY~4`c!%D72}HfZa1&luPx{q3YpZ6h@nfzTHVEg*RY7#Ks{KypRhu z=Sf>!$`ebLt3p35TzAa@ccc4UrH0O)zJO7^;z_`X^mXVa1k{Olj!!8uW%6o=gUGT(adg zk_H|R>R3f99oXK=*331Ntu;1ksafX7Yp`9?bP!FLIf>SbGW$0BR4YHqE+iM+GCJ|3 zW#Gg^p`V@3h5WF6s+U!I?pR~fy^VjE_`-0E&ERF&?i>B#(c$40*XZjWKj1T($Wvu# z@qRu|pknPdMGZ}~C^FZt*ycnQdeC398kcRSL5Ihc!I%dj%!Sg3UC z@imvDUB?D|;l{&YKVXh8Y47tzJR_A%q-qXSy4>D-h~TK%R8+lL0=G=b+ht&dH2jkIRg%!kQv+O4D_xj zCND#a`2tMhc{V=Xs~SbCoZhC*<{zL9B2mODwGPl1AhMYUy%$WTSyff&S`OY{&VjEL z4m|AQlZi7wtft&UPBp+ny{YNB>7~$JS4Q`EVBKbdOKzpBPrAeb7IJG)YYv}yy9%hpLtpwVn=4-Qhnkq%DD$wD*CTaqeP zjW0hC$qWTppfBd%6;-VTy)-SN-9wmNRTw(^ly7Vnno@A(Mk9Kf9Il@q~LJn!Bq5Ofg=5o1A6=DT8!Sl7JKcr5|`8U9FunG~ozOljkX z&6i@am&_L_jQ!;oC8uSX^GOTWP(l|W8K`y@_u2Ubos^e;0^D=oGOkBXMvRR+S>O)+ z^sA>g_U_fk;Tl}J;|~4QsTS%G*URaft=F=!;X0zWA%$)DzW{VL11C(p{ZPeFIuHxF?)j zoa))-9h)#a8~>g41jGGZo&VsK1fMPiDTIIm;VWBu(JXHRCTDpAkWBJdvhKyP@qM5T z{nLlx;h7^c;Pv3stK%5HJv%xNPZ{?A^q=74H$E5{aKO`teLBqoMNTCUz1L5clRWqy zP6AEwXU;aP!XgQ)w?Oq_Wy7del_DXOcCTw|XjA2nTqzj_7*DafVd(n0VVEQV&1q;< z753A+&*I_hg>FaBzO{6Cb7h-GbzXC_mzenli}pdVu7F8!(HJY!L3QO9q2+#P6mkfYunQ zmr7)j!2ospJ{k<0ysSGY{yIqeWq$~qOtXFj<6)sM$q$@7`GEW-{mg?8UWEg;1{c26 zD0!dw^b?Xx_-2^ZNFn(119%$Ujrf^f)eNO&htz_)G|AX?m&rq$;%jb5N0JH~S z61*SWeJ;nJz$xNNlQpVUe@|;J$Z_%Re_kx@*;De;n69JeCb)O9FkV}{L^Hvy3!~ZH zS&q&52;l^fWf1z%W-T|CCiFys)%T}m-4iYq&BTkvy^F=;i?L%D?>)MgJ#c*SSZ?x; z5?n7GIXo9LP919H`8?E9vSg0gW%%WXVlNjTfjie?zf-d9LmiS7C46s*@o`U}xs(Y0 zC=?~AIVs=?5MGdE`4CkJFA!*h@UU-k(wFj0O!|hynMhf?AruP*0WfE+!xvCvAz1d8 z6m{7jkw-@4Fp6N3{xJRox3E76Yp7lcb>E4E<(=JlyQ2O|#NXAmZ(mmz@;N@yBV-G{ zLr&U7Qc&*MZTmbZBEmG^+RqWY%+KwVOH~dh&i{1luUc=E>NPS_UaJ#)5|hYYxk%UA zP8xM)N`h}{Cr6|uN{)=!=fLEL4wKNr^KEcItT=dJ!PMlRUpP=`)E6E@sx$pA9+AFp zM9t^NV~qCd$Zoi1e^5&)nGT6nEGcM8nj-BRm6Em!Zbd3bO$YCKHIk}s&NqCwlz%dq!#vtgQGM!mJ^*O~`)vTORcLSfpzTqs3N(d)imxqnQ> z4)0KG9g4kw$6}i}i?2ulk}i-vI`lEyWes|POfW$(Ty;Qb$W5TTVh;S?OOdLsDEjK` ziLPE`CwjY1%mV9AvL!oDne-`58Fyiu+&z>#D^A`xSr-ZbCz4Xd94i#Y%+R*QSf$jc z=3&yMWMRV2p|M74_w08oA7k9Gf^=x_cu zb2F!-RoXy*KieJtkGrC}qL;@Ki-Y!RLGkQ)ybx)GN-8K@A5kS*CCx$T`bWaWlJK0G z`$+7ZyYaQ7ZryzjXoCK4thPUHwv>w*_dPdz{yswz+7>a$Ml7^p86CCM>%6=C>f+++ z;=9}5Ae+i$j%PB9JG{u9<2@GSd?0Jbdz1@8yvM9c@gB>eQYlmhqp;ObiDOg1DXZ~) zqmI|g2ESvC?iTFVyE)<#*H@-OR7$9T)_ZD>%YQT5qPa=q`y3N4;6Iad&7(&*L%UV> zjmy9e!m_d6JTlr~-u~6+Vc9OPi8eb1R_#kIuQr=&$h4iST>Z*xMk5UB$?JxK9`+Ei zmOk{RAO9!e_|>B$kxWaz~#o;?~+}3eG1m;%te3^&Ji!z^d2DXx-??_GMj5H zEX_vk#B3CfTJaY`ZttSSqip5rYSyKL_=P0Z$Er{>D#x&gF4*n(s&R5(V{PAY%Jpp* zO3d{j8tg?j`ZYAX*S?X%Z@!T9sjBbKfLIAC734YWOO_*jDk4)-`P_ukE%W?nIf6^Cy@k4t?4;ss0P;q!XnHclB%8UBAHrCUf z9|VupxynswGW5V%Z*p>CI5;O-nA$yX%v!-S!!Y%S+E(p$qf%VOQ{g+qsqToddarV0 zO-f-U*R-I-PkhJF!@&dYkxoF_}3p50+Kim-gXOUb{7 z54(tu?b@OIs+JrZOPb%y6T@gEnrXtOnhJvT1W#qUvOV=AtMC_6>F-B`|k35`u-{~v&bien#-S=Fv zCHD0GNS2_Y0SnxobH`HHZ*Blb%7MBho3IS^(XsL5F#{+(6mP4M(6b&eZ2XII< zppEhg>97UxNl>BC5jpS{lMqTw+#I@819xE#_mcP%3R*8jWf$zj=l^OP^-%_yO@b6ta-oj#XuK<(;* zIZ*ZYc1OKF^$#tKF2TovEQeW&yn!)IHcggmg!jhGuX7_(qXDW@1_Ue7D15B7MMaYW zNDI43X_r)-77*QQuQbXGm^|pLl?@Pr8L)K08e6=w3P;kFE4J-H-SXB?x2%F>vW9Ad z_*HD*0d|b$qkLVlO{8!H)bN0t107uhi>VfzyFy^eZT2W}7_$~}GH+2RSu98xdnS{> zbFfBK;~()tc!3o~0oTEYiJ%n5<#wZ}kb%6LQIYI6{)v~S*o7M}u#Zv}AEwcC@8Q8r zdgv;ZcCTfxN7{m~unlXj-34{tgb|R>;cTep01}%J1VU{#!G(M)=J!WhkO4=6LH9`K zm1Q}77QqB+WuyLQp!+;L^;-y!LefJ!^GkPaG7QHjdAz~W<5Bt!^qnBnQd(6AeCeEHs zo=ZqVIU+`>KnHr-%0%l}88)WS1C0rVvI-RT3YKc{r`Qk*J_*Gopjap|WtGSgjgsW~ zN{}@kqFkIINo`7MX|;1>nIsf!*(g3S2(`ZhtM&ive$_k_>J^&f^>+JzbrrvQNob6>G~3@plJUC3 zMYMDTD9KsrWXmoF404mu2pLcx5D!ELAW>3)02>UydMd4SI{V+ z(j90XeYp;x;LCWt%u}DZ>Iqgu1>CM@m4k9EFeYiY60mh*Bp-?I9NjCYP?~48&5FGu zc^|B@@y0hHb!$K_-h47GY+s9V44u7WOrrVq$sH;p)`aAu z>6Y(uQx?5#4gQ{r)!=V!O9NC${qr@T?$Oq)y->kM(IfSc^dnC=_ur+_!Tz$`vHio= zzzL;nFlnc!+*)FR`q2FKOO!x_WbE*k5qQ7;UCX0+DrHm4*DtPKjlH)Jdv5#UD%IF~ z3bCCEY_pJK$a0d-ju_D_iMC`CZGr6^dtdaPBgJBVx%VO1;&j4p8Jj(Fk5MWb%lTOB z&~iQ*jayeFAy%|U3iFtsu)-F$foXHn3(iI;^zeH9LfOGe}Qu8)#-zh#6Mh z8eaz9kcFJmX>k!*%SaI-sZ_##Vi~H2!HUFnH1Bpvz1$Y75D~|qR_34#DKV!o-&u&Xa|KA}n~o$hbSoXb^(Gv;?wHu)Up%tt-(#Kh z4y0mJup~~!QUkqA;)(;U$E)ay+@lYrK-JMB!-=;CnjsaNbUG(vDV&WNy!URl!Twqb zS@u7kY}Nw?wHfqhpGTTWW`8L&?@Vv+mq*UT5`DqjjaxGp5;1>o*%grSa<4y@xRANk zxV6705j!&?M1rC|6+qy15}wHD+>usOK|AmY`1ZG1SSrGa(Xz-)So^$)r{dsP4atC< zWD;t%o@IRmFz5aw$suYj>``Q|@SNA&OSB~CGV8XkgVrW7`lMia*A@}j299O`HPc#~ z>R0HmjQxOSunis^4k9Ndo=+%=?^FMU=OYU>)Ar-a65oy~E8KNg%rxHvTkNinljEV~ z>?C6N5rQ*ePj2UD!EyRFWA&j&RNXW;WAklYX?wX{v>%!$Y1<_#;HT9vAz?Lerb6I* zfWN0vC88JM{U9xO`jeKCBl?z{2(5-*VG{8rtg7pZ(x@?s8b-8_c92y9MW4$ymmjrh z&P=4qBaawsYXIGBnKVO78kb)sH5)5Jwd}SPo=7HH)l_R`YmY&*)Ae`qkjVsT*jU4K zYReU75Pxv5ufqg`MM!*&DlrZB(FtAN+3R%Z(|>`x82PQ0*+0S^c+}0QT81~ONXd4@ z9*wb!@oUm!@tdD{Cicvq<9UpJdh@S68+*3R^C!+de*!Q~Z{vDHR2jaNtGcqu>n2o2 zKOa-y>~d2pmqm$1II!$! z7^brE|69-&;G50#DfjdRo~AuUHk&&06K6(g*uN6&?hbZ;{U^@+1S`_m-`|Z_NE*Yv zV5X?9wxrrtV{o$;jBZ2&+1;7U?%9KLdk^m#oSr;X z7@9dWF>z=nd(+aAV2NG z4<~eGesbEeGJ7zzIGvBj5AU6$VjtGW_e_Qo+F&R&s3k&^d&YGKyYbM>P~p(z^k8&p z>831JM*6<{57>BnASbou!z%Hs+XLsEffBon*=*-Od z_(XP>S9krp>~62_y=h@DUHj$N$L|}Wqv`a>f0$0spP&<|d(&*)$2nodogk}|IcY)K zBT057ezzU^!EJ}|m+>lGp`dRRvPb5j3FhXTVVDgaL+~>R7YT}_Lgz4?i%9V6CWX=E z?s!P4KwNydhe_)g*Pru0c&hVQ{!GHlJW_K$GO$EM|gNB86~;KLZo^l1b#@M@hrv^}PnyG>RV0>B1tbP>nh{9+c$; z!ENrfN(J~|eWOw_&3~z+*R@4wB8{}+-Z|Q(^!vsWfC5@1WT+x0i5!>D)0JPPE7v4C zVfq$%w!*am%z`J%aXd$ub>OgoJ^@YD-2Nb_B{dLvc1OZmIIJC{QdnPb5F)aspuvW_ zqtRqnGWvc^W2;n9o5U}=Rc`JUbRnA}Zuw$`g8kVfLU#&ZSQ@`NX&DBI27%o8^vG#V z{!kc6Vvb3P<-S{Xqu^#CHokZ10!VUY^djKpzXEtvR-3il}LJuYkc+HBB2vLvppP)G9@3Qrb06DqP#pZV~!H zO~b4<#18Nk)7+%#jltXDu9$@#$c&Bk^Ote{CymLl3hzd@5`IEQQY zTfOa=$8*d%wl}e_GwgKU?R3r#cAxFu)fwEINbC)Eo<8Pu9`jW3+GBYBd9Ixtj14N| zF9a7x&nn{zeBL@XKE6IW5?okY2#$3 z`FiZ@Cs%cwAVs}?I!gs7JTJyD#MbfnKRgRVj3=Cpz9Qc)$5#N=E z2jU0+M&r*e(@DB*+grb_93cq3(sT$iacypu_hqQW7?gRDDpFiuXOd7JR)fmqRe{kf zl-xxevxjmtE?Mht%Fa zi0l`N_ulgP?QnK~p${;&`}%tE##@+gJJ4N;@j5sp;-I&(NrX<$1T|`B^kt-3k@5A)o)vM5OhOq=2NVfC zBChs_k+o{97s&&M=_S)#=SAuDy3WneelR0b@EsH|>nLJhTBaFYR!A&a;A=0J7qU

wF7DI|Kx|V1sBQ9FYs>m5C)C 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 BJ$(QG literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff2 b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..9fa211252080046a23b2449dbdced6abc2b0bb34 GIT binary patch literal 44300 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 QW8}wPUeo^@jR61v08@RD2LJ#7 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/generate.go b/internal/login/static/resources/generate.go new file mode 100644 index 0000000000..95cb7ff036 --- /dev/null +++ b/internal/login/static/resources/generate.go @@ -0,0 +1,7 @@ +package resources + +// scss +//go:generate sass themes/scss/zitadel/dark.scss themes/zitadel/css/dark.css +//go:generate sass themes/scss/zitadel/light.scss themes/zitadel/css/light.css +//go:generate sass themes/scss/caos/dark.scss themes/caos/css/dark.css +//go:generate sass themes/scss/caos/light.scss themes/caos/css/light.css diff --git a/internal/login/static/resources/themes/caos/css/dark.css b/internal/login/static/resources/themes/caos/css/dark.css new file mode 100644 index 0000000000..54f36e6474 --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/dark.css @@ -0,0 +1,257 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: white; +} + +h1 { + color: white; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #760038; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #f60075; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #760038; + border: 2px solid #760038; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #f60075; + border: 2px solid #f60075; +} +button.primary { + background-color: #760038; + color: white; + border: none; +} +button.primary:hover { + background-color: #f60075; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: white; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: white !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +/*# sourceMappingURL=dark.css.map */ diff --git a/internal/login/static/resources/themes/caos/css/dark.css.map b/internal/login/static/resources/themes/caos/css/dark.css.map new file mode 100644 index 0000000000..6a09f3088a --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/dark.css.map @@ -0,0 +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,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;ADsEhB;EACI;;;AAIR;EACI,kBE7EmB;EF8EnB,OC/EQ;EDgFR,QEzFU;EF0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE9GK;EF+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/caos/css/light.css b/internal/login/static/resources/themes/caos/css/light.css new file mode 100644 index 0000000000..f8eda48dc1 --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/light.css @@ -0,0 +1,299 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: white; +} + +h1 { + color: white; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #760038; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #f60075; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #760038; + border: 2px solid #760038; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #f60075; + border: 2px solid #f60075; +} +button.primary { + background-color: #760038; + color: white; + border: none; +} +button.primary:hover { + background-color: #f60075; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: white; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: white !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +html { + background-color: white; + color: #282828; +} +html header .logo { + background-image: url("../logo-light.png"); +} +html h1 { + color: #282828; +} +html button { + background-color: white; + color: #760038; + border: 2px solid #760038; +} +html button:hover { + background-color: #f60075; + border: 2px solid #f60075; +} +html button.primary { + background-color: #760038; + color: white; + border: none; + box-shadow: 0px 10px 30px #760038; +} +html button.primary:hover { + background-color: #f60075; +} +html input { + background-color: white; + color: #282828; +} +html #qrcode svg rect[style*="fill:white"] { + fill: white !important; +} +html #qrcode svg rect[style*="fill:black"] { + fill: #282828 !important; +} +html footer { + background-image: url("../gradientdeco-full.svg"); +} + +/*# sourceMappingURL=light.css.map */ diff --git a/internal/login/static/resources/themes/caos/css/light.css.map b/internal/login/static/resources/themes/caos/css/light.css.map new file mode 100644 index 0000000000..2e0ba005c5 --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/light.css.map @@ -0,0 +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,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;ADsEhB;EACI;;;AAIR;EACI,kBE7EmB;EF8EnB,OC/EQ;EDgFR,QEzFU;EF0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE9GK;EF+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AG1MJ;EACI,kBFYQ;EEXR,OFUc;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;;AAGJ;EACI,kBFTG;EEUH,OFXA;EEYA;EACA;;AACA;EACI,kBFbI;;AEkBhB;EACI,kBFrBI;EEsBJ,OFvBU;;AE2BV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/caos/favicon.ico b/internal/login/static/resources/themes/caos/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fcc06db3951aa0fc3bae50924566cb519a6c98d9 GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/themes/caos/gradientdeco-full.svg b/internal/login/static/resources/themes/caos/gradientdeco-full.svg new file mode 100644 index 0000000000..bd2418a23b --- /dev/null +++ b/internal/login/static/resources/themes/caos/gradientdeco-full.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/login/static/resources/themes/caos/logo-dark.png b/internal/login/static/resources/themes/caos/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..48d5a9da16e583b5d4eb7979e6a2ad5a1d59b6b9 GIT binary patch literal 32831 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 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/themes/caos/logo-light.png b/internal/login/static/resources/themes/caos/logo-light.png new file mode 100644 index 0000000000000000000000000000000000000000..39008bbc8ae21f8468931cdb5ea2f2a507636b4a GIT binary patch literal 33078 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 OoL5TfiYNusp#KM?&I .sessionstate { + text-transform: lowercase; + } +} + +input:not([type='radio']), select { + background-color: $inputBackgroundColor; + color: $fontColor; + height: $inputHeight; + border: 2px solid $inputBorderColor; + border-radius: 5px; + padding-left: 15px; +} + +form { + .field { + display: grid; + padding: 10px 0; + } + + .field.radio-button { + display: flex; + + input[type='radio'] { + height: 20px; + vertical-align: middle; + } + + & label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; + } + } + + label { + color: $labelColor; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; + + span.optional { + font-style: italic; + text-transform: none; + } + } + + .actions { + padding: 20px 0; + + .right { + float: right; + } + + button, a { + margin: 10px 0; + } + } +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; + + svg rect[style*="fill:white"] { + fill: $backgroundColor !important; + } + + svg rect[style*="fill:black"] { + fill: $fontColor !important; + } +} + +#secret { + .copy { + float: right; + cursor: pointer; + } +} + +footer { + background-image: url($footerimgDark); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + + /* Support for IE. */ + font-feature-settings: 'liga'; +} diff --git a/internal/login/static/resources/themes/scss/variables.scss b/internal/login/static/resources/themes/scss/variables.scss new file mode 100644 index 0000000000..03fd773f07 --- /dev/null +++ b/internal/login/static/resources/themes/scss/variables.scss @@ -0,0 +1,23 @@ +// ----- FONTS ------------ +$standardFont: Lato; +$headerFont: Aileron; + +// ----- LAYOUT ------------ +$inputHeight: 50px; + + +// ----- DARK-THEME -------- +$backgroundColor: #282828; +$fontColor: #FFFFFF; +$primaryColor: #364DF6; +$primaryColorHover: lighten($primaryColor, 10%); +$labelColor: #898989; +$inputBorderColor: #595959; +$inputBackgroundColor: #252525; + + +// ----- LIGHT-THEME -------- +$backgroundColorLight: $fontColor; +$fontColorLight: $backgroundColor; +$primaryColorLight: $primaryColor; +$primaryColorHoverLight: lighten($primaryColorLight, 10%); \ No newline at end of file diff --git a/internal/login/static/resources/themes/scss/zitadel/dark.scss b/internal/login/static/resources/themes/scss/zitadel/dark.scss new file mode 100644 index 0000000000..b34f994b21 --- /dev/null +++ b/internal/login/static/resources/themes/scss/zitadel/dark.scss @@ -0,0 +1,3 @@ +@import "../variables.scss"; +@import "./variables.scss"; +@import "../main.scss"; diff --git a/internal/login/static/resources/themes/scss/zitadel/light.scss b/internal/login/static/resources/themes/scss/zitadel/light.scss new file mode 100644 index 0000000000..112a44a1a0 --- /dev/null +++ b/internal/login/static/resources/themes/scss/zitadel/light.scss @@ -0,0 +1,4 @@ +@import "../variables.scss"; +@import "./variables.scss"; +@import "../main.scss"; +@import "../light.scss"; diff --git a/internal/login/static/resources/themes/scss/zitadel/variables.scss b/internal/login/static/resources/themes/scss/zitadel/variables.scss new file mode 100644 index 0000000000..14b52e3b9d --- /dev/null +++ b/internal/login/static/resources/themes/scss/zitadel/variables.scss @@ -0,0 +1,5 @@ +$logoImgDark: "../logo-dark.png"; +$logoImgLight: "../logo-light.png"; + +$footerimgDark: "../gradientdeco-full.svg"; +$footerimgLight: "../gradientdeco-full.svg"; \ No newline at end of file diff --git a/internal/login/static/resources/themes/zitadel/css/dark.css b/internal/login/static/resources/themes/zitadel/css/dark.css new file mode 100644 index 0000000000..ff63cfafe1 --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/dark.css @@ -0,0 +1,257 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: #FFFFFF; +} + +h1 { + color: #FFFFFF; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #364DF6; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #6778f8; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #364DF6; + border: 2px solid #364DF6; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #6778f8; + border: 2px solid #6778f8; +} +button.primary { + background-color: #364DF6; + color: #FFFFFF; + border: none; +} +button.primary:hover { + background-color: #6778f8; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: #FFFFFF; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: #FFFFFF !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +/*# sourceMappingURL=dark.css.map */ diff --git a/internal/login/static/resources/themes/zitadel/css/dark.css.map b/internal/login/static/resources/themes/zitadel/css/dark.css.map new file mode 100644 index 0000000000..6f813dd6a2 --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/dark.css.map @@ -0,0 +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,kBCLc;EDMd,OCLQ;;;ADQZ;EACI,OCTQ;EDUR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvCW;EDwCX;EACA;EACA;;AAEA;EACI,OC5CY;;;ADgDpB;EACI;EACA,kBCrDc;EDsDd,OCpDW;EDqDX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBC7DY;ED8DZ;;AAGJ;EACI,kBCnEO;EDoEP,OCrEI;EDsEJ;;AACA;EACI,kBCtEQ;;AD0EhB;EACI;;;AAIR;EACI,kBC7EmB;ED8EnB,OCnFQ;EDoFR,QCzFU;ED0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC9GK;ED+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/zitadel/css/light.css b/internal/login/static/resources/themes/zitadel/css/light.css new file mode 100644 index 0000000000..b49348d315 --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/light.css @@ -0,0 +1,299 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: #FFFFFF; +} + +h1 { + color: #FFFFFF; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #364DF6; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #6778f8; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #364DF6; + border: 2px solid #364DF6; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #6778f8; + border: 2px solid #6778f8; +} +button.primary { + background-color: #364DF6; + color: #FFFFFF; + border: none; +} +button.primary:hover { + background-color: #6778f8; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: #FFFFFF; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: #FFFFFF !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +html { + background-color: #FFFFFF; + color: #282828; +} +html header .logo { + background-image: url("../logo-light.png"); +} +html h1 { + color: #282828; +} +html button { + background-color: #FFFFFF; + color: #364DF6; + border: 2px solid #364DF6; +} +html button:hover { + background-color: #6778f8; + border: 2px solid #6778f8; +} +html button.primary { + background-color: #364DF6; + color: #FFFFFF; + border: none; + box-shadow: 0px 10px 30px #364DF6; +} +html button.primary:hover { + background-color: #6778f8; +} +html input { + background-color: #FFFFFF; + color: #282828; +} +html #qrcode svg rect[style*="fill:white"] { + fill: #FFFFFF !important; +} +html #qrcode svg rect[style*="fill:black"] { + fill: #282828 !important; +} +html footer { + background-image: url("../gradientdeco-full.svg"); +} + +/*# sourceMappingURL=light.css.map */ diff --git a/internal/login/static/resources/themes/zitadel/css/light.css.map b/internal/login/static/resources/themes/zitadel/css/light.css.map new file mode 100644 index 0000000000..b6e2b250ab --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/light.css.map @@ -0,0 +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,kBCLc;EDMd,OCLQ;;;ADQZ;EACI,OCTQ;EDUR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvCW;EDwCX;EACA;EACA;;AAEA;EACI,OC5CY;;;ADgDpB;EACI;EACA,kBCrDc;EDsDd,OCpDW;EDqDX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBC7DY;ED8DZ;;AAGJ;EACI,kBCnEO;EDoEP,OCrEI;EDsEJ;;AACA;EACI,kBCtEQ;;AD0EhB;EACI;;;AAIR;EACI,kBC7EmB;ED8EnB,OCnFQ;EDoFR,QCzFU;ED0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC9GK;ED+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AE1MJ;EACI,kBDQQ;ECPR,ODMc;;ACJd;EACI;;AAGJ;EACI,ODDU;;ACId;EACI,kBDJI;ECKJ,ODJO;ECKP;;AAEA;EACI,kBDGa;ECFb;;AAGJ;EACI,kBDbG;ECcH,ODfA;ECgBA;EACA;;AACA;EACI,kBDjBI;;ACsBhB;EACI,kBDzBI;EC0BJ,OD3BU;;AC+BV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/zitadel/favicon.ico b/internal/login/static/resources/themes/zitadel/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b488a5d3414211140f1678639884627ccc67ce9e GIT binary patch literal 15086 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 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/themes/zitadel/gradientdeco-full.svg b/internal/login/static/resources/themes/zitadel/gradientdeco-full.svg new file mode 100644 index 0000000000..bd2418a23b --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/gradientdeco-full.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/internal/login/static/resources/themes/zitadel/logo-dark.png b/internal/login/static/resources/themes/zitadel/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..b77c08072215ae5df61afe37def399c0accd5b97 GIT binary patch literal 52154 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 e&hTX0>vx;c5o>;`ZC=-u(>wGpkoZk&o^O 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

>GRy2ljP|x;<_1A~{ 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 literal 0 HcmV?d00001 diff --git a/internal/login/static/resources/themes/zitadel/logo-light.png b/internal/login/static/resources/themes/zitadel/logo-light.png new file mode 100644 index 0000000000000000000000000000000000000000..365021ab49117b47e4fcc655759fd4039e6d558b GIT binary patch literal 19825 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 IGk1^q527%F!2kdN literal 0 HcmV?d00001 diff --git a/internal/login/static/templates/change_password.html b/internal/login/static/templates/change_password.html new file mode 100644 index 0000000000..1874206202 --- /dev/null +++ b/internal/login/static/templates/change_password.html @@ -0,0 +1,32 @@ +{{template "main-top" .}} + + +

{{t "PasswordChange.Title"}}

+

{{t "PasswordChange.Description"}}

+ +
+ + + +
+
+ + +
+ +
+ + +
+
+ + {{ template "error-message" .}} + +
+
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/change_password_done.html b/internal/login/static/templates/change_password_done.html new file mode 100644 index 0000000000..8ff07063bd --- /dev/null +++ b/internal/login/static/templates/change_password_done.html @@ -0,0 +1,19 @@ +{{template "main-top" .}} + + +

{{t "PasswordChangeDone.Title"}}

+

{{t "PasswordChangeDone.Description"}}

+ +
+ + + + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/error-message.html b/internal/login/static/templates/error-message.html new file mode 100644 index 0000000000..8bee342aa1 --- /dev/null +++ b/internal/login/static/templates/error-message.html @@ -0,0 +1,9 @@ +{{ define "error-message" }} +{{if .ErrMessage }} +
+
+ {{ if .ErrType }}{{ .ErrType }} - {{end}}{{ .ErrMessage }} +
+
+{{end}} +{{ end }} \ No newline at end of file diff --git a/internal/login/static/templates/error.html b/internal/login/static/templates/error.html new file mode 100644 index 0000000000..b7553992f4 --- /dev/null +++ b/internal/login/static/templates/error.html @@ -0,0 +1,9 @@ +{{template "main-top" .}} + +
+ {{ .ErrType }} + {{ .ErrMessage }} +
+ +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/footer.html b/internal/login/static/templates/footer.html new file mode 100644 index 0000000000..ee505f2268 --- /dev/null +++ b/internal/login/static/templates/footer.html @@ -0,0 +1,3 @@ +{{define "footer"}} + +{{end}} \ No newline at end of file diff --git a/internal/login/static/templates/header.html b/internal/login/static/templates/header.html new file mode 100644 index 0000000000..73d7049994 --- /dev/null +++ b/internal/login/static/templates/header.html @@ -0,0 +1,3 @@ +{{define "header"}} + +{{end}}selec \ No newline at end of file diff --git a/internal/login/static/templates/init_password.html b/internal/login/static/templates/init_password.html new file mode 100644 index 0000000000..dcc6d6fbd8 --- /dev/null +++ b/internal/login/static/templates/init_password.html @@ -0,0 +1,37 @@ +{{template "main-top" .}} + + +

{{t "InitPassword.Title" }}

+

{{t "InitPassword.Description" }}

+ +
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {{ template "error-message" .}} + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/init_password_done.html b/internal/login/static/templates/init_password_done.html new file mode 100644 index 0000000000..cae159ef6b --- /dev/null +++ b/internal/login/static/templates/init_password_done.html @@ -0,0 +1,17 @@ +{{template "main-top" .}} + + +

{{t "PasswordSetDone.Title"}}

+

{{t "PasswordSetDone.Description"}}

+
+ + + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/init_user.html b/internal/login/static/templates/init_user.html new file mode 100644 index 0000000000..3383ed64bf --- /dev/null +++ b/internal/login/static/templates/init_user.html @@ -0,0 +1,37 @@ +{{template "main-top" .}} + + +

{{t "InitUser.Title" }}

+

{{t "InitUser.Description" }}

+ +
+ + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {{ template "error-message" .}} + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/init_user_done.html b/internal/login/static/templates/init_user_done.html new file mode 100644 index 0000000000..62d9fa0e7b --- /dev/null +++ b/internal/login/static/templates/init_user_done.html @@ -0,0 +1,17 @@ +{{template "main-top" .}} + + +

{{t "InitUserDone.Title"}}

+

{{t "InitUserDone.Description"}}

+
+ + + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/login.html b/internal/login/static/templates/login.html new file mode 100644 index 0000000000..a9c8a3b6b5 --- /dev/null +++ b/internal/login/static/templates/login.html @@ -0,0 +1,27 @@ +{{template "main-top" .}} + +

{{t "Login.Title"}}

+

{{t "Login.Description"}}

+ +
+ + + +
+
+ + +
+
+ + {{template "error-message" .}} + +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/logout_done.html b/internal/login/static/templates/logout_done.html new file mode 100644 index 0000000000..3416a808f1 --- /dev/null +++ b/internal/login/static/templates/logout_done.html @@ -0,0 +1,15 @@ +{{template "main-top" .}} + + +

{{t "LogoutDone.Title"}}

+

{{t "LogoutDone.Description"}}

+
+ +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mail_verification.html b/internal/login/static/templates/mail_verification.html new file mode 100644 index 0000000000..b70863d586 --- /dev/null +++ b/internal/login/static/templates/mail_verification.html @@ -0,0 +1,31 @@ +{{template "main-top" .}} + + +

{{t "EmailVerification.Title"}}

+

{{t "EmailVerification.Description"}}

+ +
+ + + + +
+
+ + +
+
+ + {{ template "error-message" .}} + +
+ + {{ end }} +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mail_verified.html b/internal/login/static/templates/mail_verified.html new file mode 100644 index 0000000000..e7b212f8ce --- /dev/null +++ b/internal/login/static/templates/mail_verified.html @@ -0,0 +1,19 @@ +{{template "main-top" .}} + + +

{{t "EmailVerificationDone.Title"}}

+

{{t "EmailVerificationDone.Description"}}

+ +
+ + + + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/main.html b/internal/login/static/templates/main.html new file mode 100644 index 0000000000..5b9aab1f6b --- /dev/null +++ b/internal/login/static/templates/main.html @@ -0,0 +1,34 @@ +{{define "main-top"}} + + + + + + + + {{if .ThemeMode}} + + {{else}} + + + {{end}} + + + {{ .Title }} + + +
+ {{template "header" .}} +
+
+{{end}} + + + +{{define "main-bottom"}} +
+ +
+ {{template "footer" .}} +
+{{end}} diff --git a/internal/login/static/templates/mfa_init_done.html b/internal/login/static/templates/mfa_init_done.html new file mode 100644 index 0000000000..399a3f7b47 --- /dev/null +++ b/internal/login/static/templates/mfa_init_done.html @@ -0,0 +1,19 @@ +{{template "main-top" .}} + + +

{{t "MfaInitDone.Title"}}

+

{{t "MfaInitDone.Description"}}

+ +
+ + + + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mfa_init_verify.html b/internal/login/static/templates/mfa_init_verify.html new file mode 100644 index 0000000000..fe1f472e2b --- /dev/null +++ b/internal/login/static/templates/mfa_init_verify.html @@ -0,0 +1,47 @@ +{{template "main-top" .}} + + +

{{t "MfaInitVerify.Title"}}

+

{{t "MfaInitVerify.Description"}}

+ +
+ + + + + + + {{if (eq .MfaType 0) }} +

{{t "MfaInitVerify.OtpDescription"}}

+
+ {{.QrCode}} +
+
+
+ {{t "MfaInitVerify.Secret"}} + + {{.Secret}} + content_copy + +
+
+ + +
+
+ {{end}} + +
+ +
+
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mfa_prompt.html b/internal/login/static/templates/mfa_prompt.html new file mode 100644 index 0000000000..0f2b2581cd --- /dev/null +++ b/internal/login/static/templates/mfa_prompt.html @@ -0,0 +1,30 @@ +{{template "main-top" .}} + + +

{{t "MfaPrompt.Title"}}

+ +
+ + + +
+ {{ range $provider := .MfaProviders}} + {{ $providerName := (t (printf "MfaPrompt.Provider%v" $provider)) }} +
+ + +
+ {{ end }} +
+ +
+ + {{if not .MfaRequired}} + + {{end}} +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mfa_verify.html b/internal/login/static/templates/mfa_verify.html new file mode 100644 index 0000000000..7f49746406 --- /dev/null +++ b/internal/login/static/templates/mfa_verify.html @@ -0,0 +1,28 @@ +{{template "main-top" .}} + + +

{{t "MfaVerify.Title"}}

+

{{t "MfaVerify.Description"}}

+ +
+ + + + +
+
+ + +
+
+ + {{ template "error-message" .}} + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/password.html b/internal/login/static/templates/password.html new file mode 100644 index 0000000000..4b813f2b2b --- /dev/null +++ b/internal/login/static/templates/password.html @@ -0,0 +1,33 @@ +{{template "main-top" .}} + + +

{{t "Password.Title"}}

+ +
+ + + + +
+
+ + +
+
+ + {{template "error-message" .}} + + +
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/password_reset_done.html b/internal/login/static/templates/password_reset_done.html new file mode 100644 index 0000000000..a146f740db --- /dev/null +++ b/internal/login/static/templates/password_reset_done.html @@ -0,0 +1,17 @@ +{{template "main-top" .}} + + +

{{t "PasswordResetDone.Title"}}

+

{{t "PasswordResetDone.Description"}}

+
+ + + +
+ +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/register.html b/internal/login/static/templates/register.html new file mode 100644 index 0000000000..83de5f3535 --- /dev/null +++ b/internal/login/static/templates/register.html @@ -0,0 +1,61 @@ +{{template "main-top" .}} + +

{{t "Registration.Title"}}

+

{{t "Registration.Description"}}

+ +
+ + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + {{template "error-message" .}} + +
+ +
+
+ + +{{template "main-bottom" .}} diff --git a/internal/login/static/templates/select_user.html b/internal/login/static/templates/select_user.html new file mode 100644 index 0000000000..1dc69726af --- /dev/null +++ b/internal/login/static/templates/select_user.html @@ -0,0 +1,25 @@ +{{template "main-top" .}} + + +

{{t "UserSelection.Title"}}

+

{{t "UserSelection.Description"}}

+ +
+ + + +
+ {{ range $user := .Users }} + {{ $sessionState := (t (printf "UserSelection.SessionState%v" $user.UserSessionState)) }} + + {{ end }} + +
+
+ + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/statik/generate.go b/internal/login/statik/generate.go new file mode 100644 index 0000000000..75330afad9 --- /dev/null +++ b/internal/login/statik/generate.go @@ -0,0 +1,3 @@ +package statik + +//go:generate statik -src=../static -dest=.. -ns=login diff --git a/internal/management/auth/token_verifier.go b/internal/management/auth/token_verifier.go index 84ba0abe38..842874c568 100644 --- a/internal/management/auth/token_verifier.go +++ b/internal/management/auth/token_verifier.go @@ -3,23 +3,34 @@ package auth import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" +) + +const ( + mgmtName = "Management-API" ) type TokenVerifier struct { + mgmtID string + authZRepo *authz_repo.EsRepository } -func Start() (v *TokenVerifier) { - return new(TokenVerifier) +func Start(authZRepo *authz_repo.EsRepository) (v *TokenVerifier) { + return &TokenVerifier{authZRepo: authZRepo} } func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { - return "", "", "", nil + userID, clientID, agentID, err := v.authZRepo.VerifyAccessToken(ctx, token, mgmtName, v.mgmtID) + if clientID != "" { + v.mgmtID = clientID + } + return userID, clientID, agentID, err } -func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) { - return nil, nil +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*auth.Grant, error) { + return v.authZRepo.ResolveGrants(ctx) } func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { - return "", nil + return v.authZRepo.ProjectIDByClientID(ctx, clientID) } diff --git a/internal/management/repository/eventsourcing/eventstore/project.go b/internal/management/repository/eventsourcing/eventstore/project.go index 810c90d22b..f0e1b31f0b 100644 --- a/internal/management/repository/eventsourcing/eventstore/project.go +++ b/internal/management/repository/eventsourcing/eventstore/project.go @@ -2,6 +2,8 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/api/auth" + global_model "github.com/caos/zitadel/internal/model" "strings" "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" @@ -41,6 +43,13 @@ func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*pro func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *proj_model.GrantedProjectSearchRequest) (*proj_model.GrantedProjectSearchResponse, error) { request.EnsureLimit(repo.SearchLimit) + + permissions := auth.GetPermissionsFromCtx(ctx) + if !auth.HasGlobalPermission(permissions) { + ids := auth.GetPermissionCtxIDs(permissions) + request.Queries = append(request.Queries, &proj_model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Method: global_model.SEARCHMETHOD_IN, Value: ids}) + } + projects, count, err := repo.View.SearchGrantedProjects(request) if err != nil { return nil, err diff --git a/internal/management/repository/eventsourcing/handler/org.go b/internal/management/repository/eventsourcing/handler/org.go index cddecd83be..832f9e984e 100644 --- a/internal/management/repository/eventsourcing/handler/org.go +++ b/internal/management/repository/eventsourcing/handler/org.go @@ -1,12 +1,12 @@ package handler import ( + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/spooler" - org_model "github.com/caos/zitadel/internal/org/model" "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/view" ) @@ -37,9 +37,9 @@ func (o *Org) Process(event *es_models.Event) error { org := new(view.OrgView) switch event.Type { - case org_model.OrgAdded: + case model.OrgAdded: org.AppendEvent(event) - case org_model.OrgChanged: + case model.OrgChanged: err := org.SetData(event) if err != nil { return err diff --git a/internal/management/repository/eventsourcing/handler/org_member.go b/internal/management/repository/eventsourcing/handler/org_member.go index 79b0e0bce7..089e8a351e 100644 --- a/internal/management/repository/eventsourcing/handler/org_member.go +++ b/internal/management/repository/eventsourcing/handler/org_member.go @@ -2,13 +2,13 @@ package handler import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/spooler" - org_model "github.com/caos/zitadel/internal/org/model" view_model "github.com/caos/zitadel/internal/org/repository/view" usr_model "github.com/caos/zitadel/internal/user/model" usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" @@ -36,13 +36,13 @@ func (m *OrgMember) EventQuery() (*models.SearchQuery, error) { return nil, err } return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate, usr_es_model.UserAggregate). + AggregateTypeFilter(model.OrgAggregate, usr_es_model.UserAggregate). LatestSequenceFilter(sequence), nil } func (m *OrgMember) Process(event *models.Event) (err error) { switch event.AggregateType { - case org_model.OrgAggregate: + case model.OrgAggregate: err = m.processOrgMember(event) case usr_es_model.UserAggregate: err = m.processUser(event) @@ -53,10 +53,10 @@ func (m *OrgMember) Process(event *models.Event) (err error) { func (m *OrgMember) processOrgMember(event *models.Event) (err error) { member := new(view_model.OrgMemberView) switch event.Type { - case org_model.OrgMemberAdded: + case model.OrgMemberAdded: member.AppendEvent(event) m.fillData(member) - case org_model.OrgMemberChanged: + case model.OrgMemberChanged: err := member.SetData(event) if err != nil { return err @@ -66,7 +66,7 @@ func (m *OrgMember) processOrgMember(event *models.Event) (err error) { return err } member.AppendEvent(event) - case org_model.OrgMemberRemoved: + case model.OrgMemberRemoved: err := member.SetData(event) if err != nil { return err diff --git a/internal/model/search_method.go b/internal/model/search_method.go index 914a728024..9ad66d0e8a 100644 --- a/internal/model/search_method.go +++ b/internal/model/search_method.go @@ -10,4 +10,7 @@ const ( SEARCHMETHOD_STARTS_WITH_IGNORE_CASE SEARCHMETHOD_CONTAINS_IGNORE_CASE SEARCHMETHOD_NOT_EQUALS + SEARCHMETHOD_GREATER_THAN + SEARCHMETHOD_LESS_THAN + SEARCHMETHOD_IN ) diff --git a/internal/notification/types/email_verification_code.go b/internal/notification/types/email_verification_code.go index dd03d2705f..fd0a6d043c 100644 --- a/internal/notification/types/email_verification_code.go +++ b/internal/notification/types/email_verification_code.go @@ -30,5 +30,5 @@ func SendEmailVerificationCode(user *view_model.NotifyUser, code *es_model.Email if err != nil { return err } - return generateEmail(user, template, systemDefaults.Notifications, true) + return generateEmail(user, systemDefaults.Notifications.TemplateData.VerifyEmail.Subject, template, systemDefaults.Notifications, true) } diff --git a/internal/notification/types/init_code.go b/internal/notification/types/init_code.go index 4ece7e3ae6..0c73e3f7d8 100644 --- a/internal/notification/types/init_code.go +++ b/internal/notification/types/init_code.go @@ -35,5 +35,5 @@ func SendUserInitCode(user *view_model.NotifyUser, code *es_model.InitUserCode, if err != nil { return err } - return generateEmail(user, template, systemDefaults.Notifications, true) + return generateEmail(user, systemDefaults.Notifications.TemplateData.InitCode.Subject, template, systemDefaults.Notifications, true) } diff --git a/internal/notification/types/password_code.go b/internal/notification/types/password_code.go index 0bfc236a7e..b3843185de 100644 --- a/internal/notification/types/password_code.go +++ b/internal/notification/types/password_code.go @@ -30,5 +30,5 @@ func SendPasswordCode(user *view_model.NotifyUser, code *es_model.PasswordCode, if err != nil { return err } - return generateEmail(user, template, systemDefaults.Notifications, false) + return generateEmail(user, systemDefaults.Notifications.TemplateData.PasswordReset.Subject, template, systemDefaults.Notifications, false) } diff --git a/internal/notification/types/user_email.go b/internal/notification/types/user_email.go index c916a6c8af..d6b3928e2e 100644 --- a/internal/notification/types/user_email.go +++ b/internal/notification/types/user_email.go @@ -9,7 +9,7 @@ import ( view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) -func generateEmail(user *view_model.NotifyUser, content string, config systemdefaults.Notifications, lastEmail bool) error { +func generateEmail(user *view_model.NotifyUser, subject, content string, config systemdefaults.Notifications, lastEmail bool) error { provider, err := email.InitEmailProvider(config.Providers.Email) if err != nil { return err @@ -17,7 +17,7 @@ func generateEmail(user *view_model.NotifyUser, content string, config systemdef message := &email.EmailMessage{ SenderEmail: config.Providers.Email.From, Recipients: []string{user.VerifiedEmail}, - Subject: config.TemplateData.InitCode.Subject, + Subject: subject, Content: content, } if lastEmail { diff --git a/internal/org/repository/eventsourcing/eventstore.go b/internal/org/repository/eventsourcing/eventstore.go index 5e5b22d1be..6ccf48d89f 100644 --- a/internal/org/repository/eventsourcing/eventstore.go +++ b/internal/org/repository/eventsourcing/eventstore.go @@ -8,6 +8,7 @@ import ( es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/id" org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" ) type OrgEventstore struct { @@ -26,7 +27,7 @@ func StartOrg(conf OrgConfig) *OrgEventstore { } } -func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org) (*Org, []*es_models.Aggregate, error) { +func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org) (*model.Org, []*es_models.Aggregate, error) { if orgModel == nil || !orgModel.IsValid() { return nil, nil, errors.ThrowInvalidArgument(nil, "EVENT-OeLSk", "org not valid") } @@ -35,7 +36,7 @@ func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_mod return nil, nil, errors.ThrowInternal(err, "EVENT-OwciI", "id gen failed") } orgModel.AggregateID = id - org := OrgFromModel(orgModel) + org := model.OrgFromModel(orgModel) aggregates, err := orgCreatedAggregates(ctx, es.AggregateCreator(), org) @@ -49,7 +50,7 @@ func (es *OrgEventstore) CreateOrg(ctx context.Context, orgModel *org_model.Org) return nil, err } - return OrgToModel(org), nil + return model.OrgToModel(org), nil } func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_model.Org, error) { @@ -61,7 +62,7 @@ func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_ return nil, err } - esOrg := OrgFromModel(org) + esOrg := model.OrgFromModel(org) err = es_sdk.Filter(ctx, es.FilterEvents, esOrg.AppendEvents, query) if err != nil && !errors.IsNotFound(err) { return nil, err @@ -70,7 +71,7 @@ func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_ return nil, errors.ThrowNotFound(nil, "EVENT-kVLb2", "org not found") } - return OrgToModel(esOrg), nil + return model.OrgToModel(esOrg), nil } func (es *OrgEventstore) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) { @@ -93,7 +94,7 @@ func isUniqueValidation(unique *bool) func(events ...*es_models.Event) error { if len(events) == 0 { return nil } - *unique = *unique || events[0].Type == org_model.OrgDomainReserved || events[0].Type == org_model.OrgNameReserved + *unique = *unique || events[0].Type == model.OrgDomainReserved || events[0].Type == model.OrgNameReserved return nil } @@ -104,7 +105,7 @@ func (es *OrgEventstore) DeactivateOrg(ctx context.Context, orgID string) (*org_ if err != nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-oL9nT", "org not found") } - org := OrgFromModel(existingOrg) + org := model.OrgFromModel(existingOrg) aggregate := orgDeactivateAggregate(es.AggregateCreator(), org) err = es_sdk.Push(ctx, es.PushAggregates, org.AppendEvents, aggregate) @@ -112,7 +113,7 @@ func (es *OrgEventstore) DeactivateOrg(ctx context.Context, orgID string) (*org_ return nil, err } - return OrgToModel(org), nil + return model.OrgToModel(org), nil } func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_model.Org, error) { @@ -120,7 +121,7 @@ func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_ if err != nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-oL9nT", "org not set") } - org := OrgFromModel(existingOrg) + org := model.OrgFromModel(existingOrg) aggregate := orgReactivateAggregate(es.AggregateCreator(), org) err = es_sdk.Push(ctx, es.PushAggregates, org.AppendEvents, aggregate) @@ -128,7 +129,7 @@ func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_ return nil, err } - return OrgToModel(org), nil + return model.OrgToModel(org), nil } func (es *OrgEventstore) OrgMemberByIDs(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) { @@ -150,12 +151,12 @@ func (es *OrgEventstore) OrgMemberByIDs(ctx context.Context, member *org_model.O return nil, errors.ThrowNotFound(nil, "EVENT-SXji6", "member not found") } -func (es *OrgEventstore) PrepareAddOrgMember(ctx context.Context, member *org_model.OrgMember) (*OrgMember, *es_models.Aggregate, error) { +func (es *OrgEventstore) PrepareAddOrgMember(ctx context.Context, member *org_model.OrgMember) (*model.OrgMember, *es_models.Aggregate, error) { if member == nil || !member.IsValid() { return nil, nil, errors.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required") } - repoMember := OrgMemberFromModel(member) + repoMember := model.OrgMemberFromModel(member) addAggregate, err := orgMemberAddedAggregate(ctx, es.Eventstore.AggregateCreator(), repoMember) return repoMember, addAggregate, err @@ -171,7 +172,7 @@ func (es *OrgEventstore) AddOrgMember(ctx context.Context, member *org_model.Org return nil, err } - return OrgMemberToModel(repoMember), nil + return model.OrgMemberToModel(repoMember), nil } func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) { @@ -185,8 +186,8 @@ func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model. } member.ObjectRoot = existingMember.ObjectRoot - repoMember := OrgMemberFromModel(member) - repoExistingMember := OrgMemberFromModel(existingMember) + repoMember := model.OrgMemberFromModel(member) + repoExistingMember := model.OrgMemberFromModel(existingMember) orgAggregate := orgMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoExistingMember, repoMember) err = es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate) @@ -194,7 +195,7 @@ func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model. return nil, err } - return OrgMemberToModel(repoMember), nil + return model.OrgMemberToModel(repoMember), nil } func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model.OrgMember) error { @@ -211,7 +212,7 @@ func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model. } member.ObjectRoot = existingMember.ObjectRoot - repoMember := OrgMemberFromModel(member) + repoMember := model.OrgMemberFromModel(member) orgAggregate := orgMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoMember) return es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate) diff --git a/internal/org/repository/eventsourcing/eventstore_test.go b/internal/org/repository/eventsourcing/eventstore_test.go index 4cfa83302d..bf9cad3dee 100644 --- a/internal/org/repository/eventsourcing/eventstore_test.go +++ b/internal/org/repository/eventsourcing/eventstore_test.go @@ -2,6 +2,7 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" "time" @@ -428,7 +429,7 @@ func TestOrgEventstore_OrgMemberByIDs(t *testing.T) { { name: "new events found and added success", fields: fields{Eventstore: newTestEventstore(t).expectFilterEvents([]*es_models.Event{ - {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: org_model.OrgMemberChanged}, + {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: model.OrgMemberChanged}, }, nil)}, args: args{ ctx: auth.NewMockContext("user", "org"), @@ -442,8 +443,8 @@ func TestOrgEventstore_OrgMemberByIDs(t *testing.T) { { name: "not member of org error", fields: fields{Eventstore: newTestEventstore(t).expectFilterEvents([]*es_models.Event{ - {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: org_model.OrgMemberAdded}, - {Sequence: 7, Data: []byte("{\"userId\": \"apple\"}"), Type: org_model.OrgMemberRemoved}, + {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: model.OrgMemberAdded}, + {Sequence: 7, Data: []byte("{\"userId\": \"apple\"}"), Type: model.OrgMemberRemoved}, }, nil)}, args: args{ ctx: auth.NewMockContext("user", "org"), @@ -511,7 +512,7 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, @@ -541,7 +542,7 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, @@ -570,7 +571,7 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectAggregateCreator(). expectFilterEvents([]*es_models.Event{ { - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -600,12 +601,12 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectPushEvents(10, nil). expectFilterEvents([]*es_models.Event{ { - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, { - Type: org_model.OrgMemberRemoved, + Type: model.OrgMemberRemoved, Data: []byte(`{"userId": "hodor"}`), Sequence: 10, }, @@ -708,13 +709,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "brudi", "roles": ["master of desaster"]}`), Sequence: 6, }, @@ -740,13 +741,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -772,13 +773,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -805,13 +806,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -890,13 +891,13 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "brudi", "roles": ["master of desaster"]}`), Sequence: 6, }, @@ -921,13 +922,13 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -952,13 +953,13 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -996,7 +997,7 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { func orgCreatedEvent() *es_models.Event { return &es_models.Event{ AggregateID: "hodor-org", - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, AggregateVersion: "v1", CreationDate: time.Now().Add(-1 * time.Minute), Data: []byte(`{"name": "hodor-org", "domain":"hodor.org"}`), @@ -1005,14 +1006,14 @@ func orgCreatedEvent() *es_models.Event { ID: "sdlfö4t23kj", ResourceOwner: "hodor-org", Sequence: 32, - Type: org_model.OrgAdded, + Type: model.OrgAdded, } } func orgInactiveEvent() *es_models.Event { return &es_models.Event{ AggregateID: "hodor-org", - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, AggregateVersion: "v1", CreationDate: time.Now().Add(-1 * time.Minute), Data: nil, @@ -1021,6 +1022,6 @@ func orgInactiveEvent() *es_models.Event { ID: "sdlfö4t23kj", ResourceOwner: "hodor-org", Sequence: 52, - Type: org_model.OrgDeactivated, + Type: model.OrgDeactivated, } } diff --git a/internal/org/repository/eventsourcing/member_model.go b/internal/org/repository/eventsourcing/model/member_model.go similarity index 95% rename from internal/org/repository/eventsourcing/member_model.go rename to internal/org/repository/eventsourcing/model/member_model.go index e8483ac2c7..2390d66a97 100644 --- a/internal/org/repository/eventsourcing/member_model.go +++ b/internal/org/repository/eventsourcing/model/member_model.go @@ -1,4 +1,4 @@ -package eventsourcing +package model import ( "encoding/json" @@ -29,10 +29,10 @@ func (m *OrgMember) AppendEvents(events ...*es_models.Event) error { func (m *OrgMember) AppendEvent(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) - return m.setData(event) + return m.SetData(event) } -func (m *OrgMember) setData(event *es_models.Event) error { +func (m *OrgMember) SetData(event *es_models.Event) error { err := json.Unmarshal(event.Data, m) if err != nil { return errors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data") diff --git a/internal/org/repository/eventsourcing/org_model.go b/internal/org/repository/eventsourcing/model/org_model.go similarity index 92% rename from internal/org/repository/eventsourcing/org_model.go rename to internal/org/repository/eventsourcing/model/org_model.go index 143a8e8a7c..cb13fe3c47 100644 --- a/internal/org/repository/eventsourcing/org_model.go +++ b/internal/org/repository/eventsourcing/model/org_model.go @@ -1,15 +1,14 @@ -package eventsourcing +package model import ( "encoding/json" - "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" org_model "github.com/caos/zitadel/internal/org/model" ) const ( - orgVersion = "v1" + OrgVersion = "v1" ) type Org struct { @@ -64,22 +63,22 @@ func (o *Org) AppendEvents(events ...*es_models.Event) error { func (o *Org) AppendEvent(event *es_models.Event) error { switch event.Type { - case org_model.OrgAdded: + case OrgAdded: *o = Org{} err := o.setData(event) if err != nil { return err } - case org_model.OrgChanged: + case OrgChanged: err := o.setData(event) if err != nil { return err } - case org_model.OrgDeactivated: + case OrgDeactivated: o.State = int32(org_model.ORGSTATE_INACTIVE) - case org_model.OrgReactivated: + case OrgReactivated: o.State = int32(org_model.ORGSTATE_ACTIVE) - case org_model.OrgMemberAdded: + case OrgMemberAdded: member, err := OrgMemberFromEvent(nil, event) if err != nil { return err @@ -87,7 +86,7 @@ func (o *Org) AppendEvent(event *es_models.Event) error { member.CreationDate = event.CreationDate o.setMember(member) - case org_model.OrgMemberChanged: + case OrgMemberChanged: member, err := OrgMemberFromEvent(nil, event) if err != nil { return err @@ -96,7 +95,7 @@ func (o *Org) AppendEvent(event *es_models.Event) error { member.CreationDate = existingMember.CreationDate o.setMember(member) - case org_model.OrgMemberRemoved: + case OrgMemberRemoved: member, err := OrgMemberFromEvent(nil, event) if err != nil { return err diff --git a/internal/org/repository/eventsourcing/org_model_test.go b/internal/org/repository/eventsourcing/model/org_model_test.go similarity index 93% rename from internal/org/repository/eventsourcing/org_model_test.go rename to internal/org/repository/eventsourcing/model/org_model_test.go index f3bad7f4c5..cfcdd950c1 100644 --- a/internal/org/repository/eventsourcing/org_model_test.go +++ b/internal/org/repository/eventsourcing/model/org_model_test.go @@ -1,4 +1,4 @@ -package eventsourcing +package model import ( "encoding/json" @@ -22,7 +22,7 @@ func TestOrgFromEvents(t *testing.T) { name: "org from events, ok", args: args{ event: []*es_models.Event{ - {AggregateID: "ID", Sequence: 1, Type: model.OrgAdded}, + {AggregateID: "ID", Sequence: 1, Type: OrgAdded}, }, org: &Org{Name: "OrgName"}, }, @@ -32,7 +32,7 @@ func TestOrgFromEvents(t *testing.T) { name: "org from events, nil org", args: args{ event: []*es_models.Event{ - {AggregateID: "ID", Sequence: 1, Type: model.OrgAdded}, + {AggregateID: "ID", Sequence: 1, Type: OrgAdded}, }, org: nil, }, @@ -66,7 +66,7 @@ func TestAppendEvent(t *testing.T) { { name: "append added event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgAdded}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgAdded}, org: &Org{Name: "OrgName"}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName"}, @@ -74,7 +74,7 @@ func TestAppendEvent(t *testing.T) { { name: "append change event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)}, org: &Org{Name: "OrgName", Domain: "asdf"}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName", Domain: "OrgDomain"}, @@ -82,14 +82,14 @@ func TestAppendEvent(t *testing.T) { { name: "append deactivate event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgDeactivated}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgDeactivated}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_INACTIVE)}, }, { name: "append reactivate event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgReactivated}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgReactivated}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)}, }, diff --git a/internal/org/model/types.go b/internal/org/repository/eventsourcing/model/types.go similarity index 100% rename from internal/org/model/types.go rename to internal/org/repository/eventsourcing/model/types.go diff --git a/internal/org/repository/eventsourcing/org.go b/internal/org/repository/eventsourcing/org.go index 8c266d052f..3f18f653e8 100644 --- a/internal/org/repository/eventsourcing/org.go +++ b/internal/org/repository/eventsourcing/org.go @@ -5,6 +5,7 @@ import ( "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" ) func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) { @@ -17,7 +18,7 @@ func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, err func OrgDomainUniqueQuery(domain string) *es_models.SearchQuery { return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgDomainAggregate). + AggregateTypeFilter(model.OrgDomainAggregate). AggregateIDFilter(domain). OrderDesc(). SetLimit(1) @@ -25,7 +26,7 @@ func OrgDomainUniqueQuery(domain string) *es_models.SearchQuery { func OrgNameUniqueQuery(name string) *es_models.SearchQuery { return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgNameAggregate). + AggregateTypeFilter(model.OrgNameAggregate). AggregateIDFilter(name). OrderDesc(). SetLimit(1) @@ -33,15 +34,15 @@ func OrgNameUniqueQuery(name string) *es_models.SearchQuery { func OrgQuery(latestSequence uint64) *es_models.SearchQuery { return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate). + AggregateTypeFilter(model.OrgAggregate). LatestSequenceFilter(latestSequence) } func OrgAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, id string, sequence uint64) (*es_models.Aggregate, error) { - return aggCreator.NewAggregate(ctx, id, org_model.OrgAggregate, orgVersion, sequence) + return aggCreator.NewAggregate(ctx, id, model.OrgAggregate, model.OrgVersion, sequence) } -func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *Org) (_ []*es_models.Aggregate, err error) { +func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *model.Org) (_ []*es_models.Aggregate, err error) { if org == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie7", "org should not be nil") } @@ -56,11 +57,11 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr return nil, err } - agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, org_model.OrgAggregate, orgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID)) + agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, model.OrgAggregate, model.OrgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID)) if err != nil { return nil, err } - agg, err = agg.AppendEvent(org_model.OrgAdded, org) + agg, err = agg.AppendEvent(model.OrgAdded, org) if err != nil { return nil, err } @@ -72,7 +73,7 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr }, nil } -func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *Org, updated *Org) ([]*es_models.Aggregate, error) { +func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, updated *model.Org) ([]*es_models.Aggregate, error) { if existing == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dk83d", "existing org must not be nil") } @@ -107,7 +108,7 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre return nil, err } - orgAggregate, err = orgAggregate.AppendEvent(org_model.OrgChanged, changes) + orgAggregate, err = orgAggregate.AppendEvent(model.OrgChanged, changes) if err != nil { return nil, err } @@ -116,7 +117,7 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre return aggregates, nil } -func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if org == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-R03z8", "existing org must not be nil") @@ -129,11 +130,11 @@ func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) fu return nil, err } - return agg.AppendEvent(org_model.OrgDeactivated, nil) + return agg.AppendEvent(model.OrgDeactivated, nil) } } -func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if org == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-cTHLd", "existing org must not be nil") @@ -146,40 +147,40 @@ func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) fu return nil, err } - return agg.AppendEvent(org_model.OrgReactivated, nil) + return agg.AppendEvent(model.OrgReactivated, nil) } } func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) { - aggregate, err := aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0) + aggregate, err := aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0) if resourceOwner != "" { - aggregate, err = aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) + aggregate, err = aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) } if err != nil { return nil, err } - aggregate, err = aggregate.AppendEvent(org_model.OrgDomainReserved, nil) + aggregate, err = aggregate.AppendEvent(model.OrgDomainReserved, nil) if err != nil { return nil, err } - return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, org_model.OrgDomainReserved)), nil + return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, model.OrgDomainReserved)), nil } func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) { - aggregate, err = aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0) + aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0) if resourceOwner != "" { - aggregate, err = aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) + aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) } if err != nil { return nil, err } - aggregate, err = aggregate.AppendEvent(org_model.OrgNameReserved, nil) + aggregate, err = aggregate.AppendEvent(model.OrgNameReserved, nil) if err != nil { return nil, err } - return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, org_model.OrgNameReserved)), nil + return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, model.OrgNameReserved)), nil } func isReservedValidation(aggregate *es_models.Aggregate, resevedEventType es_models.EventType) func(...*es_models.Event) error { diff --git a/internal/org/repository/eventsourcing/org_member.go b/internal/org/repository/eventsourcing/org_member.go index 106ca3ff2f..26ff8b6582 100644 --- a/internal/org/repository/eventsourcing/org_member.go +++ b/internal/org/repository/eventsourcing/org_member.go @@ -2,33 +2,33 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) -func orgMemberAddedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, member *OrgMember) (*es_models.Aggregate, error) { +func orgMemberAddedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, member *model.OrgMember) (*es_models.Aggregate, error) { if member == nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-c63Ap", "member must not be nil") } - aggregate, err := aggCreator.NewAggregate(ctx, member.AggregateID, org_model.OrgAggregate, orgVersion, member.Sequence) + aggregate, err := aggCreator.NewAggregate(ctx, member.AggregateID, model.OrgAggregate, model.OrgVersion, member.Sequence) if err != nil { return nil, err } validationQuery := es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate, usr_model.UserAggregate). + AggregateTypeFilter(model.OrgAggregate, usr_model.UserAggregate). AggregateIDsFilter(member.AggregateID, member.UserID) validation := addMemberValidation(aggregate, member) - return aggregate.SetPrecondition(validationQuery, validation).AppendEvent(org_model.OrgMemberAdded, member) + return aggregate.SetPrecondition(validationQuery, validation).AppendEvent(model.OrgMemberAdded, member) } -func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingMember *OrgMember, member *OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingMember *model.OrgMember, member *model.OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if member == nil || existingMember == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d34fs", "member must not be nil") @@ -43,11 +43,11 @@ func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingM if err != nil { return nil, err } - return agg.AppendEvent(org_model.OrgMemberChanged, changes) + return agg.AppendEvent(model.OrgMemberChanged, changes) } } -func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *model.OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if member == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dieu7", "member must not be nil") @@ -57,11 +57,11 @@ func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *O if err != nil { return nil, err } - return agg.AppendEvent(org_model.OrgMemberRemoved, member) + return agg.AppendEvent(model.OrgMemberRemoved, member) } } -func addMemberValidation(aggregate *es_models.Aggregate, member *OrgMember) func(...*es_models.Event) error { +func addMemberValidation(aggregate *es_models.Aggregate, member *model.OrgMember) func(...*es_models.Event) error { return func(events ...*es_models.Event) error { existsOrg := false existsUser := false @@ -70,17 +70,17 @@ func addMemberValidation(aggregate *es_models.Aggregate, member *OrgMember) func switch event.AggregateType { case usr_model.UserAggregate: existsUser = true - case org_model.OrgAggregate: + case model.OrgAggregate: aggregate.PreviousSequence = event.Sequence existsOrg = true switch event.Type { - case org_model.OrgMemberAdded, org_model.OrgMemberRemoved: - manipulatedMember, err := OrgMemberFromEvent(new(OrgMember), event) + case model.OrgMemberAdded, model.OrgMemberRemoved: + manipulatedMember, err := model.OrgMemberFromEvent(new(model.OrgMember), event) if err != nil { return errors.ThrowInternal(err, "EVENT-Eg8St", "unable to validate object") } if manipulatedMember.UserID == member.UserID { - isMember = event.Type == org_model.OrgMemberAdded + isMember = event.Type == model.OrgMemberAdded } } } diff --git a/internal/org/repository/eventsourcing/org_member_test.go b/internal/org/repository/eventsourcing/org_member_test.go index b4076198fd..fb83f6792a 100644 --- a/internal/org/repository/eventsourcing/org_member_test.go +++ b/internal/org/repository/eventsourcing/org_member_test.go @@ -2,12 +2,12 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -18,7 +18,7 @@ func TestOrgMemberAddedAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - member *OrgMember + member *model.OrgMember ctx context.Context } tests := []struct { @@ -42,7 +42,7 @@ func TestOrgMemberAddedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, }, @@ -78,8 +78,8 @@ func TestOrgMemberChangedAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - existingMember *OrgMember - member *OrgMember + existingMember *model.OrgMember + member *model.OrgMember ctx context.Context } tests := []struct { @@ -93,7 +93,7 @@ func TestOrgMemberChangedAggregate(t *testing.T) { aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), member: nil, - existingMember: &OrgMember{}, + existingMember: &model.OrgMember{}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -105,7 +105,7 @@ func TestOrgMemberChangedAggregate(t *testing.T) { aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), existingMember: nil, - member: &OrgMember{}, + member: &model.OrgMember{}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -116,10 +116,10 @@ func TestOrgMemberChangedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, - existingMember: &OrgMember{ + existingMember: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, }, @@ -132,11 +132,11 @@ func TestOrgMemberChangedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, Roles: []string{"asdf"}, }, - existingMember: &OrgMember{ + existingMember: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, Roles: []string{"asdf", "woeri"}, }, @@ -174,7 +174,7 @@ func TestOrgMemberRemovedAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - member *OrgMember + member *model.OrgMember ctx context.Context } tests := []struct { @@ -198,7 +198,7 @@ func TestOrgMemberRemovedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, }, @@ -236,7 +236,7 @@ func Test_addMemberValidation(t *testing.T) { type args struct { aggregate *es_models.Aggregate events []*es_models.Event - member *OrgMember + member *model.OrgMember } tests := []struct { name string @@ -258,21 +258,21 @@ func Test_addMemberValidation(t *testing.T) { aggregate: &es_models.Aggregate{}, events: []*es_models.Event{ { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1234, - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId":"hodor"}`), }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -292,7 +292,7 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 142, }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -308,11 +308,11 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: nil, @@ -329,23 +329,23 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1234, - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId":"hodor"}`), }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1236, - Type: org_model.OrgMemberRemoved, + Type: model.OrgMemberRemoved, Data: []byte(`{"userId":"hodor"}`), }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: nil, @@ -362,17 +362,17 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1234, - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId":"hodor"}`), }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: errors.IsPreconditionFailed, diff --git a/internal/org/repository/eventsourcing/org_test.go b/internal/org/repository/eventsourcing/org_test.go index 805d962104..347cf4aabe 100644 --- a/internal/org/repository/eventsourcing/org_test.go +++ b/internal/org/repository/eventsourcing/org_test.go @@ -2,6 +2,7 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" "github.com/caos/zitadel/internal/api/auth" @@ -217,7 +218,7 @@ func TestOrgReactivateAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - org *Org + org *model.Org ctx context.Context } tests := []struct { @@ -230,7 +231,7 @@ func TestOrgReactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -244,7 +245,7 @@ func TestOrgReactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -291,7 +292,7 @@ func TestOrgDeactivateAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - org *Org + org *model.Org ctx context.Context } tests := []struct { @@ -304,7 +305,7 @@ func TestOrgDeactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -318,7 +319,7 @@ func TestOrgDeactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -367,8 +368,8 @@ func TestOrgUpdateAggregates(t *testing.T) { type args struct { ctx context.Context aggCreator *es_models.AggregateCreator - existing *Org - updated *Org + existing *model.Org + updated *model.Org } tests := []struct { name string @@ -381,7 +382,7 @@ func TestOrgUpdateAggregates(t *testing.T) { ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), existing: nil, - updated: &Org{}, + updated: &model.Org{}, }, res: res{ aggregateCount: 0, @@ -393,7 +394,7 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{}, + existing: &model.Org{}, updated: nil, }, res: res{ @@ -406,8 +407,8 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{}, - updated: &Org{}, + existing: &model.Org{}, + updated: &model.Org{}, }, res: res{ aggregateCount: 0, @@ -419,7 +420,7 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{ + existing: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -427,7 +428,7 @@ func TestOrgUpdateAggregates(t *testing.T) { Domain: "caos.ch", Name: "coas", }, - updated: &Org{ + updated: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -446,7 +447,7 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{ + existing: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -454,7 +455,7 @@ func TestOrgUpdateAggregates(t *testing.T) { Domain: "caos.swiss", Name: "caos", }, - updated: &Org{ + updated: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -493,7 +494,7 @@ func TestOrgCreatedAggregates(t *testing.T) { type args struct { ctx context.Context aggCreator *es_models.AggregateCreator - org *Org + org *model.Org } tests := []struct { name string @@ -517,7 +518,7 @@ func TestOrgCreatedAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -536,7 +537,7 @@ func TestOrgCreatedAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -554,7 +555,7 @@ func TestOrgCreatedAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, diff --git a/internal/org/repository/view/org.go b/internal/org/repository/view/org.go index b6aee2cf4a..571c416d9f 100644 --- a/internal/org/repository/view/org.go +++ b/internal/org/repository/view/org.go @@ -2,12 +2,12 @@ package view import ( "encoding/json" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_es_model "github.com/caos/zitadel/internal/org/model" org_model "github.com/caos/zitadel/internal/org/model" ) @@ -69,17 +69,17 @@ func OrgsToModel(orgs []*OrgView) []*org_model.OrgView { func (o *OrgView) AppendEvent(event *es_models.Event) (err error) { switch event.Type { - case org_es_model.OrgAdded: + case model.OrgAdded: o.CreationDate = event.CreationDate o.State = int32(org_model.ORGSTATE_ACTIVE) o.setRootData(event) err = o.SetData(event) - case org_es_model.OrgChanged: + case model.OrgChanged: o.setRootData(event) err = o.SetData(event) - case org_es_model.OrgDeactivated: + case model.OrgDeactivated: o.State = int32(org_model.ORGSTATE_INACTIVE) - case org_es_model.OrgReactivated: + case model.OrgReactivated: o.State = int32(org_model.ORGSTATE_ACTIVE) } return err diff --git a/internal/org/repository/view/org_member.go b/internal/org/repository/view/org_member.go index b4ebddcd98..0e281c3a26 100644 --- a/internal/org/repository/view/org_member.go +++ b/internal/org/repository/view/org_member.go @@ -2,6 +2,7 @@ package view import ( "encoding/json" + es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" @@ -76,11 +77,11 @@ func (r *OrgMemberView) AppendEvent(event *models.Event) (err error) { r.Sequence = event.Sequence r.ChangeDate = event.CreationDate switch event.Type { - case model.OrgMemberAdded: + case es_model.OrgMemberAdded: r.setRootData(event) r.CreationDate = event.CreationDate err = r.SetData(event) - case model.OrgMemberChanged: + case es_model.OrgMemberChanged: err = r.SetData(event) } return err diff --git a/internal/project/model/granted_project.go b/internal/project/model/granted_project.go index 301eb538fd..ebd58c85d3 100644 --- a/internal/project/model/granted_project.go +++ b/internal/project/model/granted_project.go @@ -50,7 +50,7 @@ const ( type GrantedProjectSearchQuery struct { Key GrantedProjectSearchKey Method model.SearchMethod - Value string + Value interface{} } type GrantedProjectSearchResponse struct { diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go index b87e13de53..91446bea32 100644 --- a/internal/project/repository/eventsourcing/eventstore.go +++ b/internal/project/repository/eventsourcing/eventstore.go @@ -4,18 +4,21 @@ import ( "context" "github.com/caos/zitadel/internal/cache/config" sd "github.com/caos/zitadel/internal/config/systemdefaults" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/crypto" caos_errs "github.com/caos/zitadel/internal/errors" es_int "github.com/caos/zitadel/internal/eventstore" es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/id" proj_model "github.com/caos/zitadel/internal/project/model" - "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" ) type ProjectEventstore struct { es_int.Eventstore projectCache *ProjectCache + passwordAlg crypto.HashAlgorithm pwGenerator crypto.Generator idGenerator id.Generator } @@ -35,6 +38,7 @@ func StartProject(conf ProjectConfig, systemDefaults sd.SystemDefaults) (*Projec return &ProjectEventstore{ Eventstore: conf.Eventstore, projectCache: projectCache, + passwordAlg: passwordAlg, pwGenerator: pwGenerator, idGenerator: id.SonyFlakeGenerator, }, nil @@ -535,6 +539,42 @@ func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, project return nil, caos_errs.ThrowInternal(nil, "EVENT-dk87s", "Could not find app in list") } +func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, projectID, appID string, secret string) error { + if appID == "" { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-H3RT2", "some required fields missing") + } + existing, err := es.ProjectByID(ctx, projectID) + if err != nil { + return err + } + var app *proj_model.Application + if _, app = existing.GetApp(appID); app == nil { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-D6hba", "App is not in this project") + } + if app.Type != proj_model.APPTYPE_OIDC { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-huywq", "App is not an oidc application") + } + + if err := crypto.CompareHash(app.OIDCConfig.ClientSecret, []byte(secret), es.passwordAlg); err == nil { + return es.setOIDCClientSecretCheckResult(ctx, existing, app.AppID, OIDCClientSecretCheckSucceededAggregate) + } + if err := es.setOIDCClientSecretCheckResult(ctx, existing, app.AppID, OIDCClientSecretCheckFailedAggregate); err != nil { + return err + } + return caos_errs.ThrowInvalidArgument(nil, "EVENT-wg24q", "invalid client secret") +} + +func (es *ProjectEventstore) setOIDCClientSecretCheckResult(ctx context.Context, project *proj_model.Project, appID string, check func(*es_models.AggregateCreator, *model.Project, string) es_sdk.AggregateFunc) error { + repoProject := model.ProjectFromModel(project) + agg := check(es.AggregateCreator(), repoProject, appID) + err := es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, agg) + if err != nil { + return err + } + es.projectCache.cacheProject(repoProject) + return nil +} + func (es *ProjectEventstore) ProjectGrantByIDs(ctx context.Context, projectID, grantID string) (*proj_model.ProjectGrant, error) { if grantID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-e8die", "grantID missing") diff --git a/internal/project/repository/eventsourcing/model/project_grant_member.go b/internal/project/repository/eventsourcing/model/project_grant_member.go index aeeda8446f..92d9a8a528 100644 --- a/internal/project/repository/eventsourcing/model/project_grant_member.go +++ b/internal/project/repository/eventsourcing/model/project_grant_member.go @@ -59,7 +59,7 @@ func GrantMemberToModel(member *ProjectGrantMember) *model.ProjectGrantMember { func (p *Project) appendAddGrantMemberEvent(event *es_models.Event) error { member := &ProjectGrantMember{} - err := member.getData(event) + err := member.SetData(event) if err != nil { return err } @@ -73,13 +73,13 @@ func (p *Project) appendAddGrantMemberEvent(event *es_models.Event) error { func (p *Project) appendChangeGrantMemberEvent(event *es_models.Event) error { member := &ProjectGrantMember{} - err := member.getData(event) + err := member.SetData(event) if err != nil { return err } if _, g := GetProjectGrant(p.Grants, member.GrantID); g != nil { if i, m := GetProjectGrantMember(g.Members, member.UserID); m != nil { - g.Members[i].getData(event) + g.Members[i].SetData(event) } } return nil @@ -87,7 +87,7 @@ func (p *Project) appendChangeGrantMemberEvent(event *es_models.Event) error { func (p *Project) appendRemoveGrantMemberEvent(event *es_models.Event) error { member := &ProjectGrantMember{} - err := member.getData(event) + err := member.SetData(event) if err != nil { return err } @@ -102,7 +102,7 @@ func (p *Project) appendRemoveGrantMemberEvent(event *es_models.Event) error { return nil } -func (m *ProjectGrantMember) getData(event *es_models.Event) error { +func (m *ProjectGrantMember) SetData(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, m); err != nil { logging.Log("EVEN-8die2").WithError(err).Error("could not unmarshal event data") diff --git a/internal/project/repository/eventsourcing/model/project_member.go b/internal/project/repository/eventsourcing/model/project_member.go index f04cf21b86..3f8c57dd8e 100644 --- a/internal/project/repository/eventsourcing/model/project_member.go +++ b/internal/project/repository/eventsourcing/model/project_member.go @@ -56,7 +56,7 @@ func ProjectMemberToModel(member *ProjectMember) *model.ProjectMember { func (p *Project) appendAddMemberEvent(event *es_models.Event) error { member := &ProjectMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -67,7 +67,7 @@ func (p *Project) appendAddMemberEvent(event *es_models.Event) error { func (p *Project) appendChangeMemberEvent(event *es_models.Event) error { member := &ProjectMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -79,7 +79,7 @@ func (p *Project) appendChangeMemberEvent(event *es_models.Event) error { func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error { member := &ProjectMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -91,7 +91,7 @@ func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error { return nil } -func (m *ProjectMember) setData(event *es_models.Event) error { +func (m *ProjectMember) SetData(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, m); err != nil { logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data") diff --git a/internal/project/repository/eventsourcing/model/types.go b/internal/project/repository/eventsourcing/model/types.go index 787cc23264..babaa808f1 100644 --- a/internal/project/repository/eventsourcing/model/types.go +++ b/internal/project/repository/eventsourcing/model/types.go @@ -35,7 +35,9 @@ const ( ApplicationDeactivated models.EventType = "project.application.deactivated" ApplicationReactivated models.EventType = "project.application.reactivated" - OIDCConfigAdded models.EventType = "project.application.config.oidc.added" - OIDCConfigChanged models.EventType = "project.application.config.oidc.changed" - OIDCConfigSecretChanged models.EventType = "project.application.config.oidc.secret.changed" + OIDCConfigAdded models.EventType = "project.application.config.oidc.added" + OIDCConfigChanged models.EventType = "project.application.config.oidc.changed" + OIDCConfigSecretChanged models.EventType = "project.application.config.oidc.secret.changed" + OIDCClientSecretCheckSucceeded models.EventType = "project.application.oidc.secret.check.succeeded" + OIDCClientSecretCheckFailed models.EventType = "project.application.oidc.secret.check.failed" ) diff --git a/internal/project/repository/eventsourcing/project.go b/internal/project/repository/eventsourcing/project.go index 65a31bfd2a..54c152f712 100644 --- a/internal/project/repository/eventsourcing/project.go +++ b/internal/project/repository/eventsourcing/project.go @@ -6,7 +6,8 @@ import ( "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -290,7 +291,7 @@ func OIDCConfigSecretChangedAggregate(aggCreator *es_models.AggregateCreator, ex if err != nil { return nil, err } - changes := make(map[string]interface{}, 1) + changes := make(map[string]interface{}, 2) changes["appId"] = appID changes["clientSecret"] = secret @@ -300,6 +301,36 @@ func OIDCConfigSecretChangedAggregate(aggCreator *es_models.AggregateCreator, ex } } +func OIDCClientSecretCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, appID string) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := ProjectAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := make(map[string]interface{}, 1) + changes["appId"] = appID + + agg.AppendEvent(model.OIDCClientSecretCheckSucceeded, changes) + + return agg, nil + } +} + +func OIDCClientSecretCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, appID string) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := ProjectAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := make(map[string]interface{}, 1) + changes["appId"] = appID + + agg.AppendEvent(model.OIDCClientSecretCheckFailed, changes) + + return agg, nil + } +} + func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, grant *model.ProjectGrant) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if grant == nil { @@ -310,7 +341,7 @@ func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existing return nil, err } validationQuery := es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate). + AggregateTypeFilter(org_es_model.OrgAggregate). AggregateIDFilter(grant.GrantedOrgID) validation := addProjectGrantValidation() @@ -475,11 +506,11 @@ func addProjectGrantValidation() func(...*es_models.Event) error { existsOrg := false for _, event := range events { switch event.AggregateType { - case org_model.OrgAggregate: + case org_es_model.OrgAggregate: switch event.Type { - case org_model.OrgAdded: + case org_es_model.OrgAdded: existsOrg = true - case org_model.OrgRemoved: + case org_es_model.OrgRemoved: existsOrg = false } } diff --git a/internal/project/repository/view/application_view.go b/internal/project/repository/view/application_view.go index 2c993e16c1..2b660f04ef 100644 --- a/internal/project/repository/view/application_view.go +++ b/internal/project/repository/view/application_view.go @@ -1,6 +1,7 @@ package view import ( + global_model "github.com/caos/zitadel/internal/model" proj_model "github.com/caos/zitadel/internal/project/model" "github.com/caos/zitadel/internal/project/repository/view/model" "github.com/caos/zitadel/internal/view" @@ -14,6 +15,23 @@ func ApplicationByID(db *gorm.DB, table, appID string) (*model.ApplicationView, return app, err } +func ApplicationByOIDCClientID(db *gorm.DB, table, clientID string) (*model.ApplicationView, error) { + app := new(model.ApplicationView) + clientIDQuery := model.ApplicationSearchQuery{Key: proj_model.APPLICATIONSEARCHKEY_OIDC_CLIENT_ID, Value: clientID, Method: global_model.SEARCHMETHOD_EQUALS} + query := view.PrepareGetByQuery(table, clientIDQuery) + err := query(db, app) + return app, err +} + +func ApplicationByProjectIDAndAppName(db *gorm.DB, table, projectID, appName string) (*model.ApplicationView, error) { + app := new(model.ApplicationView) + projectIDQuery := model.ApplicationSearchQuery{Key: proj_model.APPLICATIONSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS} + appNameQuery := model.ApplicationSearchQuery{Key: proj_model.APPLICATIONSEARCHKEY_NAME, Value: appName, Method: global_model.SEARCHMETHOD_EQUALS} + query := view.PrepareGetByQuery(table, projectIDQuery, appNameQuery) + err := query(db, app) + return app, err +} + func SearchApplications(db *gorm.DB, table string, req *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) { apps := make([]*model.ApplicationView, 0) query := view.PrepareSearchQuery(table, model.ApplicationSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries}) diff --git a/internal/project/repository/view/model/application.go b/internal/project/repository/view/model/application.go index e738855eb8..e4ced437fb 100644 --- a/internal/project/repository/view/model/application.go +++ b/internal/project/repository/view/model/application.go @@ -16,7 +16,7 @@ const ( ApplicationKeyProjectID = "project_id" ApplicationKeyResourceOwner = "resource_owner" ApplicationKeyOIDCClientID = "oidc_client_id" - ApplicationKeyName = "name" + ApplicationKeyName = "app_name" ) type ApplicationView struct { diff --git a/internal/renderer/renderer.go b/internal/renderer/renderer.go new file mode 100644 index 0000000000..c0690c028d --- /dev/null +++ b/internal/renderer/renderer.go @@ -0,0 +1,120 @@ +package renderer + +import ( + "io/ioutil" + "net/http" + "os" + "text/template" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/i18n" + + "github.com/caos/logging" + "golang.org/x/text/language" +) + +const ( + TranslateFn = "t" + + templatesPath = "/templates" +) + +type Renderer struct { + Templates map[string]*template.Template + i18n *i18n.Translator +} + +func NewRenderer(dir http.FileSystem, tmplMapping map[string]string, funcs map[string]interface{}, translatorConfig i18n.TranslatorConfig) (*Renderer, error) { + var err error + r := new(Renderer) + r.i18n, err = i18n.NewTranslator(dir, translatorConfig) + if err != nil { + return nil, err + } + r.loadTemplates(dir, tmplMapping, funcs) + return r, nil +} + +func (r *Renderer) RenderTemplate(w http.ResponseWriter, req *http.Request, tmpl *template.Template, data interface{}, reqFuncs map[string]interface{}) { + reqFuncs = r.registerTranslateFn(req, reqFuncs) + if err := tmpl.Funcs(reqFuncs).Execute(w, data); err != nil { + logging.Log("RENDE-lF8F6w").WithError(err).WithField("template", tmpl.Name).Error("error rendering template") + } +} + +func (r *Renderer) Localize(id string, args map[string]interface{}) string { + return r.i18n.Localize(id, args) +} + +func (r *Renderer) LocalizeFromRequest(req *http.Request, id string, args map[string]interface{}) string { + return r.i18n.LocalizeFromRequest(req, id, args) +} +func (r *Renderer) Lang(req *http.Request) language.Tag { + return r.i18n.Lang(req) +} + +func (r *Renderer) loadTemplates(dir http.FileSystem, tmplMapping map[string]string, funcs map[string]interface{}) error { + funcs = r.registerTranslateFn(nil, funcs) + funcs[TranslateFn] = func(id string, args ...interface{}) string { + return id + } + templatesDir, err := dir.Open(templatesPath) + if err != nil { + return errors.ThrowNotFound(err, "RENDE-G3aea", "path not found") + } + defer templatesDir.Close() + files, err := templatesDir.Readdir(0) + if err != nil { + return errors.ThrowNotFound(err, "RENDE-dfR33", "cannot read dir") + } + tmpl := template.New("") + for _, file := range files { + if err := r.addFileToTemplate(dir, tmpl, tmplMapping, funcs, file); err != nil { + return errors.ThrowNotFound(err, "RENDE-dfTe1", "cannot append file to templates") + } + } + r.Templates = make(map[string]*template.Template, len(tmplMapping)) + for name, file := range tmplMapping { + r.Templates[name] = tmpl.Lookup(file) + } + return nil +} + +func (r *Renderer) addFileToTemplate(dir http.FileSystem, tmpl *template.Template, tmplMapping map[string]string, funcs map[string]interface{}, file os.FileInfo) error { + f, err := dir.Open(templatesPath + "/" + file.Name()) + if err != nil { + return err + } + defer f.Close() + content, err := ioutil.ReadAll(f) + if err != nil { + return err + } + tmpl, err = tmpl.New(file.Name()).Funcs(funcs).Parse(string(content)) + if err != nil { + return err + } + return nil +} + +func (r *Renderer) registerTranslateFn(req *http.Request, funcs map[string]interface{}) map[string]interface{} { + if funcs == nil { + funcs = make(map[string]interface{}) + } + funcs[TranslateFn] = func(id string, args ...interface{}) string { + m := map[string]interface{}{} + var key string + for i, arg := range args { + if i%2 == 0 { + key = arg.(string) + continue + } + m[key] = arg + } + if r == nil { + return r.Localize(id, m) + } + return r.LocalizeFromRequest(req, id, m) + } + return funcs +} diff --git a/internal/token/model/token.go b/internal/token/model/token.go index bd8e2ff5ed..5e3b6a74d6 100644 --- a/internal/token/model/token.go +++ b/internal/token/model/token.go @@ -14,7 +14,9 @@ type Token struct { UserID string ApplicationID string UserAgentID string + Audience []string Expiration time.Time + Scopes []string Sequence uint64 } diff --git a/internal/token/repository/view/model/token.go b/internal/token/repository/view/model/token.go index 2c094322d2..1b08051a96 100644 --- a/internal/token/repository/view/model/token.go +++ b/internal/token/repository/view/model/token.go @@ -3,6 +3,8 @@ package model import ( "time" + "github.com/lib/pq" + "github.com/caos/zitadel/internal/token/model" ) @@ -16,15 +18,17 @@ const ( ) type Token struct { - ID string `json:"-" gorm:"column:id;primary_key"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - UserID string `json:"-" gorm:"column:user_id"` - ApplicationID string `json:"-" gorm:"column:application_id"` - UserAgentID string `json:"-" gorm:"column:user_agent_id"` - Expiration time.Time `json:"-" gorm:"column:expiration"` - Sequence uint64 `json:"-" gorm:"column:sequence"` + ID string `json:"-" gorm:"column:id;primary_key"` + CreationDate time.Time `json:"-" gorm:"column:creation_date"` + ChangeDate time.Time `json:"-" gorm:"column:change_date"` + ResourceOwner string `json:"-" gorm:"column:resource_owner"` + UserID string `json:"-" gorm:"column:user_id"` + ApplicationID string `json:"-" gorm:"column:application_id"` + UserAgentID string `json:"-" gorm:"column:user_agent_id"` + Audience pq.StringArray `json:"-" gorm:"column:audience"` + Scopes pq.StringArray `json:"-" gorm:"column:scopes"` + Expiration time.Time `json:"-" gorm:"column:expiration"` + Sequence uint64 `json:"-" gorm:"column:sequence"` } func TokenFromModel(token *model.Token) *Token { @@ -36,6 +40,8 @@ func TokenFromModel(token *model.Token) *Token { UserID: token.UserID, ApplicationID: token.ApplicationID, UserAgentID: token.UserAgentID, + Audience: token.Audience, + Scopes: token.Scopes, Expiration: token.Expiration, Sequence: token.Sequence, } @@ -50,6 +56,8 @@ func TokenToModel(token *Token) *model.Token { UserID: token.UserID, ApplicationID: token.ApplicationID, UserAgentID: token.UserAgentID, + Audience: token.Audience, + Scopes: token.Scopes, Expiration: token.Expiration, Sequence: token.Sequence, } diff --git a/internal/user/model/phone.go b/internal/user/model/phone.go index f83ef241f2..a6f93b237c 100644 --- a/internal/user/model/phone.go +++ b/internal/user/model/phone.go @@ -9,7 +9,6 @@ import ( ) const ( - //TODO: How do we get region? defaultRegion = "CH" ) diff --git a/internal/user/model/user_session_view.go b/internal/user/model/user_session_view.go index 8e06fc43e3..66db359b41 100644 --- a/internal/user/model/user_session_view.go +++ b/internal/user/model/user_session_view.go @@ -8,18 +8,19 @@ import ( ) type UserSessionView struct { - ID string - CreationDate time.Time - ChangeDate time.Time - State req_model.UserSessionState - ResourceOwner string - UserAgentID string - UserID string - UserName string - PasswordVerification time.Time - MfaSoftwareVerification time.Time - MfaHardwareVerification time.Time - Sequence uint64 + CreationDate time.Time + ChangeDate time.Time + State req_model.UserSessionState + ResourceOwner string + UserAgentID string + UserID string + UserName string + PasswordVerification time.Time + MfaSoftwareVerification time.Time + MfaSoftwareVerificationType req_model.MfaType + MfaHardwareVerification time.Time + MfaHardwareVerificationType req_model.MfaType + Sequence uint64 } type UserSessionSearchRequest struct { @@ -34,7 +35,6 @@ type UserSessionSearchKey int32 const ( USERSESSIONSEARCHKEY_UNSPECIFIED UserSessionSearchKey = iota - USERSESSIONSEARCHKEY_SESSION_ID USERSESSIONSEARCHKEY_USER_AGENT_ID USERSESSIONSEARCHKEY_USER_ID USERSESSIONSEARCHKEY_STATE diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index 111d6a071c..b93d356b40 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -36,6 +36,7 @@ type UserView struct { OTPState MfaState MfaMaxSetUp req_model.MfaLevel MfaInitSkipped time.Time + InitRequired bool Sequence uint64 } @@ -88,6 +89,8 @@ func (r *UserSearchRequest) AppendMyOrgQuery(orgID string) { func (u *UserView) MfaTypesSetupPossible(level req_model.MfaLevel) []req_model.MfaType { types := make([]req_model.MfaType, 0) switch level { + default: + fallthrough case req_model.MfaLevelSoftware: if u.OTPState != MFASTATE_READY { types = append(types, req_model.MfaTypeOTP) diff --git a/internal/user/repository/eventsourcing/eventstore.go b/internal/user/repository/eventsourcing/eventstore.go index 9047385fa2..1a4803f141 100644 --- a/internal/user/repository/eventsourcing/eventstore.go +++ b/internal/user/repository/eventsourcing/eventstore.go @@ -89,6 +89,14 @@ func (es *UserEventstore) UserByID(ctx context.Context, id string) (*usr_model.U return model.UserToModel(user), nil } +func (es *UserEventstore) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + query, err := UserByIDQuery(id, sequence) + if err != nil { + return nil, err + } + return es.FilterEvents(ctx, query) +} + func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) { user.SetEmailAsUsername() if !user.IsValid() { @@ -317,6 +325,39 @@ func (es *UserEventstore) InitCodeSent(ctx context.Context, userID string) error return nil } +func (es *UserEventstore) VerifyInitCode(ctx context.Context, policy *policy_model.PasswordComplexityPolicy, userID, verificationCode, password string) error { + if userID == "" || verificationCode == "" { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo9fd", "userId or Code empty") + } + pw := &usr_model.Password{SecretString: password} + err := pw.HashPasswordIfExisting(policy, es.PasswordAlg, false) + if err != nil { + return err + } + existing, err := es.UserByID(ctx, userID) + if err != nil { + return err + } + if existing.InitCode == nil { + return caos_errs.ThrowNotFound(nil, "EVENT-spo9W", "code not found") + } + repoPassword := model.PasswordFromModel(pw) + repoExisting := model.UserFromModel(existing) + var updateAggregate func(ctx context.Context) (*es_models.Aggregate, error) + if err := crypto.VerifyCode(existing.InitCode.CreationDate, existing.InitCode.Expiry, existing.InitCode.Code, verificationCode, es.InitializeUserCode); err != nil { + updateAggregate = InitCodeCheckFailedAggregate(es.AggregateCreator(), repoExisting) + } else { + updateAggregate = InitCodeVerifiedAggregate(es.AggregateCreator(), repoExisting, repoPassword) + } + err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + if err != nil { + return err + } + + es.userCache.cacheUser(repoExisting) + return nil +} + func (es *UserEventstore) SkipMfaInit(ctx context.Context, userID string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "EVENT-dic8s", "userID missing") @@ -572,17 +613,23 @@ func (es *UserEventstore) VerifyEmail(ctx context.Context, userID, verificationC if existing.EmailCode == nil { return caos_errs.ThrowNotFound(nil, "EVENT-lso9w", "code not found") } - if err := crypto.VerifyCode(existing.EmailCode.CreationDate, existing.EmailCode.Expiry, existing.EmailCode.Code, verificationCode, es.EmailVerificationCode); err != nil { + + err = crypto.VerifyCode(existing.EmailCode.CreationDate, existing.EmailCode.Expiry, existing.EmailCode.Code, verificationCode, es.EmailVerificationCode) + if err == nil { + return es.setEmailVerifyResult(ctx, existing, EmailVerifiedAggregate) + } + if err := es.setEmailVerifyResult(ctx, existing, EmailVerificationFailedAggregate); err != nil { return err } + return caos_errs.ThrowInvalidArgument(err, "EVENT-dtGaa", "invalid code") +} +func (es *UserEventstore) setEmailVerifyResult(ctx context.Context, existing *usr_model.User, check func(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc) error { repoExisting := model.UserFromModel(existing) - updateAggregate := EmailVerifiedAggregate(es.AggregateCreator(), repoExisting) - err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + err := es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, check(es.AggregateCreator(), repoExisting)) if err != nil { return err } - es.userCache.cacheUser(repoExisting) return nil } @@ -693,17 +740,23 @@ func (es *UserEventstore) VerifyPhone(ctx context.Context, userID, verificationC if existing.PhoneCode == nil { return caos_errs.ThrowNotFound(nil, "EVENT-slp0s", "code not found") } - if err := crypto.VerifyCode(existing.PhoneCode.CreationDate, existing.PhoneCode.Expiry, existing.PhoneCode.Code, verificationCode, es.PhoneVerificationCode); err != nil { + + err = crypto.VerifyCode(existing.PhoneCode.CreationDate, existing.PhoneCode.Expiry, existing.PhoneCode.Code, verificationCode, es.PhoneVerificationCode) + if err == nil { + return es.setPhoneVerifyResult(ctx, existing, PhoneVerifiedAggregate) + } + if err := es.setPhoneVerifyResult(ctx, existing, PhoneVerificationFailedAggregate); err != nil { return err } + return caos_errs.ThrowInvalidArgument(err, "EVENT-dsf4G", "invalid code") +} +func (es *UserEventstore) setPhoneVerifyResult(ctx context.Context, existing *usr_model.User, check func(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc) error { repoExisting := model.UserFromModel(existing) - updateAggregate := PhoneVerifiedAggregate(es.AggregateCreator(), repoExisting) - err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + err := es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, check(es.AggregateCreator(), repoExisting)) if err != nil { return err } - es.userCache.cacheUser(repoExisting) return nil } diff --git a/internal/user/repository/eventsourcing/eventstore_mock_test.go b/internal/user/repository/eventsourcing/eventstore_mock_test.go index 53ac275597..3e36f0b0bb 100644 --- a/internal/user/repository/eventsourcing/eventstore_mock_test.go +++ b/internal/user/repository/eventsourcing/eventstore_mock_test.go @@ -246,13 +246,13 @@ func GetMockManipulateLockedUser(ctrl *gomock.Controller) *UserEventstore { return GetMockedEventstore(ctrl, mockEs) } -func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller) *UserEventstore { - user := model.User{ - Profile: &model.Profile{ - UserName: "UserName", - }, - } - code := model.InitUserCode{Expiry: time.Hour * 30} +func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller, user model.User) *UserEventstore { + code := model.InitUserCode{Code: &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("code"), + }} dataUser, _ := json.Marshal(user) dataCode, _ := json.Marshal(code) events := []*es_models.Event{ @@ -263,7 +263,7 @@ func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller) *UserEventstore mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) - return GetMockedEventstore(ctrl, mockEs) + return GetMockedEventstoreWithPw(ctrl, mockEs, true, false, false, true) } func GetMockManipulateUserWithEmailCode(ctrl *gomock.Controller) *UserEventstore { @@ -362,6 +362,7 @@ func GetMockManipulateUserVerifiedPhone(ctrl *gomock.Controller) *UserEventstore mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) return GetMockedEventstore(ctrl, mockEs) } + func GetMockManipulateUserFull(ctrl *gomock.Controller) *UserEventstore { user := model.User{ Profile: &model.Profile{ @@ -446,3 +447,12 @@ func GetMockManipulateUserNoEvents(ctrl *gomock.Controller) *UserEventstore { mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) return GetMockedEventstore(ctrl, mockEs) } + +func GetMockManipulateUserNoEventsWithPw(ctrl *gomock.Controller) *UserEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreWithPw(ctrl, mockEs, false, false, false, true) +} diff --git a/internal/user/repository/eventsourcing/eventstore_test.go b/internal/user/repository/eventsourcing/eventstore_test.go index bfade59408..7802e4b72e 100644 --- a/internal/user/repository/eventsourcing/eventstore_test.go +++ b/internal/user/repository/eventsourcing/eventstore_test.go @@ -753,7 +753,13 @@ func TestGetInitCodeByID(t *testing.T) { { name: "get by id, ok", args: args{ - es: GetMockManipulateUserWithInitCode(ctrl), + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Profile: &repo_model.Profile{ + UserName: "UserName", + }, + }), ctx: auth.NewMockContext("orgID", "userID"), existing: &model.User{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, }, @@ -791,8 +797,8 @@ func TestGetInitCodeByID(t *testing.T) { if tt.res.errFunc == nil && result.AggregateID == "" { t.Errorf("result has no id") } - if tt.res.errFunc == nil && result.Expiry != tt.res.code.Expiry { - t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.code.Expiry, result.Expiry) + if tt.res.errFunc == nil && result == nil { + t.Error("got wrong result code should not be nil", result) } if tt.res.errFunc != nil && !tt.res.errFunc(err) { t.Errorf("got wrong err: %v ", err) @@ -858,8 +864,8 @@ func TestCreateInitCode(t *testing.T) { if tt.res.errFunc == nil && result.AggregateID == "" { t.Errorf("result has no id") } - if tt.res.errFunc == nil && result.Expiry != tt.res.code.Expiry { - t.Errorf("got wrong result expiry: expected: %v, actual: %v ", tt.res.code.Expiry, result.Expiry) + if tt.res.errFunc == nil && result == nil { + t.Errorf("got wrong result code is nil") } if tt.res.errFunc != nil && !tt.res.errFunc(err) { t.Errorf("got wrong err: %v ", err) @@ -929,6 +935,135 @@ func TestInitCodeSent(t *testing.T) { } } +func TestInitCodeVerify(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *UserEventstore + ctx context.Context + policy *policy_model.PasswordComplexityPolicy + userID string + verifyCode string + password string + } + type res struct { + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "verify init code, no pw", + args: args{ + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Email: &repo_model.Email{ + EmailAddress: "EmailAddress", + }, + }, + ), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + verifyCode: "code", + userID: "userID", + }, + }, + { + name: "verify init code, pw", + args: args{ + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Email: &repo_model.Email{ + EmailAddress: "EmailAddress", + IsEmailVerified: true, + }, + }, + ), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "userID", + verifyCode: "code", + password: "password", + }, + }, + { + name: "verify init code, email and pw", + args: args{ + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Email: &repo_model.Email{ + EmailAddress: "EmailAddress", + }, + }, + ), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "userID", + verifyCode: "code", + password: "password", + }, + }, + { + name: "empty userid", + args: args{ + es: GetMockManipulateUser(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "", + verifyCode: "code", + password: "password", + }, + res: res{ + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "password policy not matched", + args: args{ + es: GetMockManipulateUser(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{HasNumber: true}, + userID: "userID", + verifyCode: "code", + password: "password", + }, + res: res{ + errFunc: caos_errs.IsErrorInvalidArgument, + }, + }, + { + name: "existing user not found", + args: args{ + es: GetMockManipulateUserNoEventsWithPw(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "userID", + password: "password", + verifyCode: "code", + }, + res: res{ + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.args.es.VerifyInitCode(tt.args.ctx, tt.args.policy, tt.args.userID, tt.args.verifyCode, tt.args.password) + + if tt.res.errFunc == nil && err != nil { + t.Errorf("should not have err: %v", err) + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v", err) + } + }) + } +} + func TestSkipMfaInit(t *testing.T) { ctrl := gomock.NewController(t) type args struct { @@ -1980,12 +2115,24 @@ func TestVerifyEmail(t *testing.T) { }, res: res{}, }, + { + name: "verify email code wrong", + args: args{ + es: GetMockManipulateUserWithEmailCode(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + userID: "AggregateID", + code: "wrong", + }, + res: res{ + errFunc: caos_errs.IsErrorInvalidArgument, + }, + }, { name: "empty userid", args: args{ es: GetMockManipulateUser(ctrl), ctx: auth.NewMockContext("orgID", "userID"), - code: "Code", + code: "code", }, res: res{ errFunc: caos_errs.IsPreconditionFailed, @@ -2008,7 +2155,7 @@ func TestVerifyEmail(t *testing.T) { es: GetMockManipulateUserNoEvents(ctrl), ctx: auth.NewMockContext("orgID", "userID"), userID: "AggregateID", - code: "Code", + code: "code", }, res: res{ errFunc: caos_errs.IsNotFound, @@ -2346,6 +2493,18 @@ func TestVerifyPhone(t *testing.T) { }, res: res{}, }, + { + name: "verify code wrong", + args: args{ + es: GetMockManipulateUserWithPhoneCode(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + userID: "AggregateID", + code: "wrong", + }, + res: res{ + errFunc: caos_errs.IsErrorInvalidArgument, + }, + }, { name: "empty userid", args: args{ diff --git a/internal/user/repository/eventsourcing/model/email.go b/internal/user/repository/eventsourcing/model/email.go index 734ac257ab..099365953a 100644 --- a/internal/user/repository/eventsourcing/model/email.go +++ b/internal/user/repository/eventsourcing/model/email.go @@ -94,6 +94,7 @@ func (a *Email) setData(event *es_models.Event) error { func (a *EmailCode) SetData(event *es_models.Event) error { a.ObjectRoot.AppendEvent(event) + a.CreationDate = event.CreationDate if err := json.Unmarshal(event.Data, a); err != nil { logging.Log("EVEN-lo9s").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "MODEL-s8uws", "could not unmarshal event") diff --git a/internal/user/repository/eventsourcing/model/password.go b/internal/user/repository/eventsourcing/model/password.go index 6273a79374..591f68a574 100644 --- a/internal/user/repository/eventsourcing/model/password.go +++ b/internal/user/repository/eventsourcing/model/password.go @@ -74,9 +74,10 @@ func (pw *Password) setData(event *es_models.Event) error { return nil } -func (a *PasswordCode) SetData(event *es_models.Event) error { - a.ObjectRoot.AppendEvent(event) - if err := json.Unmarshal(event.Data, a); err != nil { +func (c *PasswordCode) SetData(event *es_models.Event) error { + c.ObjectRoot.AppendEvent(event) + c.CreationDate = event.CreationDate + if err := json.Unmarshal(event.Data, c); err != nil { logging.Log("EVEN-lo0y2").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "MODEL-q21dr", "could not unmarshal event") } diff --git a/internal/user/repository/eventsourcing/model/phone.go b/internal/user/repository/eventsourcing/model/phone.go index ed806158c7..2416690c5c 100644 --- a/internal/user/repository/eventsourcing/model/phone.go +++ b/internal/user/repository/eventsourcing/model/phone.go @@ -90,9 +90,10 @@ func (p *Phone) setData(event *es_models.Event) error { return nil } -func (a *PhoneCode) SetData(event *es_models.Event) error { - a.ObjectRoot.AppendEvent(event) - if err := json.Unmarshal(event.Data, a); err != nil { +func (c *PhoneCode) SetData(event *es_models.Event) error { + c.ObjectRoot.AppendEvent(event) + c.CreationDate = event.CreationDate + if err := json.Unmarshal(event.Data, c); err != nil { logging.Log("EVEN-sk8ws").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "MODEL-7hdj3", "could not unmarshal event") } diff --git a/internal/user/repository/eventsourcing/model/types.go b/internal/user/repository/eventsourcing/model/types.go index f2cbe799b0..e9d03fccae 100644 --- a/internal/user/repository/eventsourcing/model/types.go +++ b/internal/user/repository/eventsourcing/model/types.go @@ -7,10 +7,12 @@ const ( UserUserNameAggregate models.AggregateType = "user.username" UserEmailAggregate models.AggregateType = "user.email" - UserAdded models.EventType = "user.added" - UserRegistered models.EventType = "user.selfregistered" - InitializedUserCodeAdded models.EventType = "user.initialization.code.added" - InitializedUserCodeSent models.EventType = "user.initialization.code.sent" + UserAdded models.EventType = "user.added" + UserRegistered models.EventType = "user.selfregistered" + InitializedUserCodeAdded models.EventType = "user.initialization.code.added" + InitializedUserCodeSent models.EventType = "user.initialization.code.sent" + InitializedUserCheckSucceeded models.EventType = "user.initialization.check.succeeded" + InitializedUserCheckFailed models.EventType = "user.initialization.check.failed" UserUserNameReserved models.EventType = "user.username.reserved" UserUserNameReleased models.EventType = "user.username.released" @@ -29,15 +31,17 @@ const ( UserPasswordCheckSucceeded models.EventType = "user.password.check.succeeded" UserPasswordCheckFailed models.EventType = "user.password.check.failed" - UserEmailChanged models.EventType = "user.email.changed" - UserEmailVerified models.EventType = "user.email.verified" - UserEmailCodeAdded models.EventType = "user.email.code.added" - UserEmailCodeSent models.EventType = "user.email.code.sent" + UserEmailChanged models.EventType = "user.email.changed" + UserEmailVerified models.EventType = "user.email.verified" + UserEmailVerificationFailed models.EventType = "user.email.verification.failed" + UserEmailCodeAdded models.EventType = "user.email.code.added" + UserEmailCodeSent models.EventType = "user.email.code.sent" - UserPhoneChanged models.EventType = "user.phone.changed" - UserPhoneVerified models.EventType = "user.phone.verified" - UserPhoneCodeAdded models.EventType = "user.phone.code.added" - UserPhoneCodeSent models.EventType = "user.phone.code.sent" + UserPhoneChanged models.EventType = "user.phone.changed" + UserPhoneVerified models.EventType = "user.phone.verified" + UserPhoneVerificationFailed models.EventType = "user.phone.verification.failed" + UserPhoneCodeAdded models.EventType = "user.phone.code.added" + UserPhoneCodeSent models.EventType = "user.phone.code.sent" UserProfileChanged models.EventType = "user.profile.changed" UserAddressChanged models.EventType = "user.address.changed" diff --git a/internal/user/repository/eventsourcing/user.go b/internal/user/repository/eventsourcing/user.go index 97d8870f49..ebb568340b 100644 --- a/internal/user/repository/eventsourcing/user.go +++ b/internal/user/repository/eventsourcing/user.go @@ -248,6 +248,38 @@ func UserInitCodeSentAggregate(aggCreator *es_models.AggregateCreator, existing } } +func InitCodeVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + if existing.Email != nil && !existing.Email.IsEmailVerified { + agg, err = agg.AppendEvent(model.UserEmailVerified, nil) + if err != nil { + return nil, err + } + } + if password != nil { + agg, err = agg.AppendEvent(model.UserPasswordChanged, password) + if err != nil { + return nil, err + } + } + return agg.AppendEvent(model.InitializedUserCheckSucceeded, nil) + } +} + +func InitCodeCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + return agg.AppendEvent(model.InitializedUserCheckFailed, nil) + } +} + func SkipMfaAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { agg, err := UserAggregate(ctx, aggCreator, existing) @@ -378,7 +410,7 @@ func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCr return append(aggregates, agg), nil } -func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { +func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { return func(ctx context.Context) (*es_models.Aggregate, error) { agg, err := UserAggregate(ctx, aggCreator, existing) if err != nil { @@ -388,6 +420,16 @@ func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *mo } } +func EmailVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + return agg.AppendEvent(model.UserEmailVerificationFailed, nil) + } +} + func EmailVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.EmailCode) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if code == nil { @@ -443,7 +485,8 @@ func PhoneChangeAggregate(aggCreator *es_models.AggregateCreator, existing *mode return agg, nil } } -func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { + +func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { return func(ctx context.Context) (*es_models.Aggregate, error) { agg, err := UserAggregate(ctx, aggCreator, existing) if err != nil { @@ -453,6 +496,16 @@ func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *mo } } +func PhoneVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + return agg.AppendEvent(model.UserPhoneVerificationFailed, nil) + } +} + func PhoneVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if code == nil { diff --git a/internal/user/repository/eventsourcing/user_test.go b/internal/user/repository/eventsourcing/user_test.go index a7369b744c..cb5ef9f048 100644 --- a/internal/user/repository/eventsourcing/user_test.go +++ b/internal/user/repository/eventsourcing/user_test.go @@ -716,7 +716,91 @@ func TestInitCodeSentAggregate(t *testing.T) { } } -func TestSkipMfaAggregate(t *testing.T) { +func TestInitCodeVerifiedAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + password *model.Password + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user init code only email verify", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + Email: &model.Email{EmailAddress: "EmailAddress"}, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 2, + eventTypes: []models.EventType{model.UserEmailVerified, model.InitializedUserCheckSucceeded}, + }, + }, + { + name: "user init code only password", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + Email: &model.Email{EmailAddress: "EmailAddress", IsEmailVerified: true}, + }, + password: &model.Password{ChangeRequired: false}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 2, + eventTypes: []models.EventType{model.UserPasswordChanged, model.InitializedUserCheckSucceeded}, + }, + }, + { + name: "user init code email and pw", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + Email: &model.Email{EmailAddress: "EmailAddress"}, + }, + password: &model.Password{ChangeRequired: false}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 3, + eventTypes: []models.EventType{model.UserEmailVerified, model.UserPasswordChanged, model.InitializedUserCheckSucceeded}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := InitCodeVerifiedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.password)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) + } + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestInitCodeCheckFailedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.User @@ -764,6 +848,54 @@ func TestSkipMfaAggregate(t *testing.T) { } } +func TestSkipMfaAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "init code check failed", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: model.InitializedUserCheckFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := InitCodeCheckFailedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestChangePasswordAggregate(t *testing.T) { type args struct { ctx context.Context @@ -1113,7 +1245,7 @@ func TestChangeEmailAggregate(t *testing.T) { } } -func TestVerifiyEmailAggregate(t *testing.T) { +func TestVerifyEmailAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.User @@ -1161,6 +1293,54 @@ func TestVerifiyEmailAggregate(t *testing.T) { } } +func TestVerificationFailedEmailAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user email verification failed aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventTypes: []models.EventType{model.UserEmailVerificationFailed}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := EmailVerificationFailedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) + } + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestCreateEmailCodeAggregate(t *testing.T) { type args struct { ctx context.Context @@ -1391,7 +1571,7 @@ func TestChangePhoneAggregate(t *testing.T) { } } -func TestVerifiyPhoneAggregate(t *testing.T) { +func TestVerifyPhoneAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.User @@ -1441,6 +1621,56 @@ func TestVerifiyPhoneAggregate(t *testing.T) { } } +func TestVerificationFailedPhoneAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user phone verification failed aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Phone: &model.Phone{PhoneNumber: "PhoneNumber"}, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventTypes: []models.EventType{model.UserPhoneVerificationFailed}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PhoneVerificationFailedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) + } + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestCreatePhoneCodeAggregate(t *testing.T) { type args struct { ctx context.Context diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index 7ed99e0f9c..a3a9d0da7a 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -54,6 +54,7 @@ type UserView struct { OTPState int32 `json:"-" gorm:"column:otp_state"` MfaMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"` MfaInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"` + InitRequired bool `json:"-" gorm:"column:init_required"` Sequence uint64 `json:"-" gorm:"column:sequence"` } @@ -87,6 +88,7 @@ func UserFromModel(user *model.UserView) *UserView { OTPState: int32(user.OTPState), MfaMaxSetUp: int32(user.MfaMaxSetUp), MfaInitSkipped: user.MfaInitSkipped, + InitRequired: user.InitRequired, Sequence: user.Sequence, } } @@ -121,6 +123,7 @@ func UserToModel(user *UserView) *model.UserView { OTPState: model.MfaState(user.OTPState), MfaMaxSetUp: req_model.MfaLevel(user.MfaMaxSetUp), MfaInitSkipped: user.MfaInitSkipped, + InitRequired: user.InitRequired, Sequence: user.Sequence, } } @@ -177,6 +180,10 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) { u.OTPState = int32(model.MFASTATE_UNSPECIFIED) case es_model.MfaInitSkipped: u.MfaInitSkipped = event.CreationDate + case es_model.InitializedUserCodeAdded: + u.InitRequired = true + case es_model.InitializedUserCheckSucceeded: + u.InitRequired = false } u.ComputeObject() return err @@ -203,6 +210,7 @@ func (u *UserView) setPasswordData(event *models.Event) error { } u.PasswordSet = password.Secret != nil u.PasswordChangeRequired = password.ChangeRequired + u.PasswordChanged = event.CreationDate return nil } diff --git a/internal/user/repository/view/model/user_session.go b/internal/user/repository/view/model/user_session.go index f4a1e6158f..d5c0a7ff48 100644 --- a/internal/user/repository/view/model/user_session.go +++ b/internal/user/repository/view/model/user_session.go @@ -14,7 +14,6 @@ import ( ) const ( - UserSessionKeySessionID = "id" UserSessionKeyUserAgentID = "user_agent_id" UserSessionKeyUserID = "user_id" UserSessionKeyState = "state" @@ -22,18 +21,19 @@ const ( ) type UserSessionView struct { - ID string `json:"-" gorm:"column:id;primary_key"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - State int32 `json:"-" gorm:"column:state"` - UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id"` - UserID string `json:"userID" gorm:"column:user_id"` - UserName string `json:"userName" gorm:"column:user_name"` - PasswordVerification time.Time `json:"-" gorm:"column:password_verification"` - MfaSoftwareVerification time.Time `json:"-" gorm:"column:mfa_software_verification"` - MfaHardwareVerification time.Time `json:"-" gorm:"column:mfa_hardware_verification"` - Sequence uint64 `json:"-" gorm:"column:sequence"` + CreationDate time.Time `json:"-" gorm:"column:creation_date"` + ChangeDate time.Time `json:"-" gorm:"column:change_date"` + ResourceOwner string `json:"-" gorm:"column:resource_owner"` + State int32 `json:"-" gorm:"column:state"` + UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id;primary_key"` + UserID string `json:"userID" gorm:"column:user_id;primary_key"` + UserName string `json:"userName" gorm:"column:user_name"` + PasswordVerification time.Time `json:"-" gorm:"column:password_verification"` + MfaSoftwareVerification time.Time `json:"-" gorm:"column:mfa_software_verification"` + MfaSoftwareVerificationType int32 `json:"-" gorm:"column:mfa_software_verification_type"` + MfaHardwareVerification time.Time `json:"-" gorm:"column:mfa_hardware_verification"` + MfaHardwareVerificationType int32 `json:"-" gorm:"column:mfa_hardware_verification_type"` + Sequence uint64 `json:"-" gorm:"column:sequence"` } func UserSessionFromEvent(event *models.Event) (*UserSessionView, error) { @@ -47,18 +47,19 @@ func UserSessionFromEvent(event *models.Event) (*UserSessionView, error) { func UserSessionToModel(userSession *UserSessionView) *model.UserSessionView { return &model.UserSessionView{ - ID: userSession.ID, - ChangeDate: userSession.ChangeDate, - CreationDate: userSession.CreationDate, - ResourceOwner: userSession.ResourceOwner, - State: req_model.UserSessionState(userSession.State), - UserAgentID: userSession.UserAgentID, - UserID: userSession.UserID, - UserName: userSession.UserName, - PasswordVerification: userSession.PasswordVerification, - MfaSoftwareVerification: userSession.MfaSoftwareVerification, - MfaHardwareVerification: userSession.MfaHardwareVerification, - Sequence: userSession.Sequence, + ChangeDate: userSession.ChangeDate, + CreationDate: userSession.CreationDate, + ResourceOwner: userSession.ResourceOwner, + State: req_model.UserSessionState(userSession.State), + UserAgentID: userSession.UserAgentID, + UserID: userSession.UserID, + UserName: userSession.UserName, + PasswordVerification: userSession.PasswordVerification, + MfaSoftwareVerification: userSession.MfaSoftwareVerification, + MfaSoftwareVerificationType: req_model.MfaType(userSession.MfaSoftwareVerificationType), + MfaHardwareVerification: userSession.MfaHardwareVerification, + MfaHardwareVerificationType: req_model.MfaType(userSession.MfaHardwareVerificationType), + Sequence: userSession.Sequence, } } @@ -80,6 +81,7 @@ func (v *UserSessionView) AppendEvent(event *models.Event) { v.PasswordVerification = time.Time{} case es_model.MfaOtpCheckSucceeded: v.MfaSoftwareVerification = event.CreationDate + v.MfaSoftwareVerificationType = int32(req_model.MfaTypeOTP) case es_model.MfaOtpCheckFailed, es_model.MfaOtpRemoved: v.MfaSoftwareVerification = time.Time{} diff --git a/internal/user/repository/view/model/user_session_query.go b/internal/user/repository/view/model/user_session_query.go index ca7fef4733..897648cabb 100644 --- a/internal/user/repository/view/model/user_session_query.go +++ b/internal/user/repository/view/model/user_session_query.go @@ -51,8 +51,6 @@ func (req UserSessionSearchQuery) GetValue() interface{} { func (key UserSessionSearchKey) ToColumnName() string { switch usr_model.UserSessionSearchKey(key) { - case usr_model.USERSESSIONSEARCHKEY_SESSION_ID: - return UserSessionKeySessionID case usr_model.USERSESSIONSEARCHKEY_USER_AGENT_ID: return UserSessionKeyUserAgentID case usr_model.USERSESSIONSEARCHKEY_USER_ID: diff --git a/internal/user/repository/view/user_session_view.go b/internal/user/repository/view/user_session_view.go index 652ba6d40a..09f68ed01c 100644 --- a/internal/user/repository/view/user_session_view.go +++ b/internal/user/repository/view/user_session_view.go @@ -9,13 +9,6 @@ import ( "github.com/caos/zitadel/internal/view" ) -func UserSessionByID(db *gorm.DB, table, sessionID string) (*model.UserSessionView, error) { - userSession := new(model.UserSessionView) - query := view.PrepareGetByKey(table, model.UserSessionSearchKey(usr_model.USERSESSIONSEARCHKEY_SESSION_ID), sessionID) - err := query(db, userSession) - return userSession, err -} - func UserSessionByIDs(db *gorm.DB, table, agentID, userID string) (*model.UserSessionView, error) { userSession := new(model.UserSessionView) userAgentQuery := model.UserSessionSearchQuery{ @@ -33,6 +26,20 @@ func UserSessionByIDs(db *gorm.DB, table, agentID, userID string) (*model.UserSe return userSession, err } +func UserSessionsByUserID(db *gorm.DB, table, userID string) ([]*model.UserSessionView, error) { + userSessions := make([]*model.UserSessionView, 0) + userAgentQuery := &usr_model.UserSessionSearchQuery{ + Key: usr_model.USERSESSIONSEARCHKEY_USER_ID, + Method: global_model.SEARCHMETHOD_EQUALS, + Value: userID, + } + query := view.PrepareSearchQuery(table, model.UserSessionSearchRequest{ + Queries: []*usr_model.UserSessionSearchQuery{userAgentQuery}, + }) + _, err := query(db, &userSessions) + return userSessions, err +} + func UserSessionsByAgentID(db *gorm.DB, table, agentID string) ([]*model.UserSessionView, error) { userSessions := make([]*model.UserSessionView, 0) userAgentQuery := &usr_model.UserSessionSearchQuery{ @@ -43,7 +50,7 @@ func UserSessionsByAgentID(db *gorm.DB, table, agentID string) ([]*model.UserSes query := view.PrepareSearchQuery(table, model.UserSessionSearchRequest{ Queries: []*usr_model.UserSessionSearchQuery{userAgentQuery}, }) - _, err := query(db, userSessions) + _, err := query(db, &userSessions) return userSessions, err } diff --git a/internal/usergrant/model/project_org.go b/internal/usergrant/model/project_org.go new file mode 100644 index 0000000000..792b923474 --- /dev/null +++ b/internal/usergrant/model/project_org.go @@ -0,0 +1,13 @@ +package model + +type ProjectOrgSearchResponse struct { + Offset uint64 + Limit uint64 + TotalResult uint64 + Result []*Org +} + +type Org struct { + OrgID string + OrgName string +} diff --git a/internal/usergrant/model/user_grant_view.go b/internal/usergrant/model/user_grant_view.go index f4636d3601..d8509f705a 100644 --- a/internal/usergrant/model/user_grant_view.go +++ b/internal/usergrant/model/user_grant_view.go @@ -43,6 +43,7 @@ const ( USERGRANTSEARCHKEY_RESOURCEOWNER USERGRANTSEARCHKEY_STATE USERGRANTSEARCHKEY_GRANT_ID + USERGRANTSEARCHKEY_ORG_NAME ) type UserGrantSearchQuery struct { diff --git a/internal/usergrant/model/zitadel_permission.go b/internal/usergrant/model/zitadel_permission.go new file mode 100644 index 0000000000..072791dc95 --- /dev/null +++ b/internal/usergrant/model/zitadel_permission.go @@ -0,0 +1,23 @@ +package model + +type Permissions struct { + Permissions []string +} + +func (p *Permissions) AppendPermissions(ctxID string, permissions ...string) { + for _, permission := range permissions { + p.appendPermission(ctxID, permission) + } +} + +func (p *Permissions) appendPermission(ctxID, permission string) { + if ctxID != "" { + permission = permission + ":" + ctxID + } + for _, existingPermission := range p.Permissions { + if existingPermission == permission { + return + } + } + p.Permissions = append(p.Permissions, permission) +} diff --git a/internal/usergrant/repository/eventsourcing/eventstore.go b/internal/usergrant/repository/eventsourcing/eventstore.go index 171511d62e..3e8450352c 100644 --- a/internal/usergrant/repository/eventsourcing/eventstore.go +++ b/internal/usergrant/repository/eventsourcing/eventstore.go @@ -57,7 +57,6 @@ func (es *UserGrantEventStore) AddUserGrant(ctx context.Context, grant *grant_mo if grant == nil || !grant.IsValid() { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sdiw3", "User grant invalid") } - //TODO: Check Uniqueness id, err := es.idGenerator.Next() if err != nil { return nil, err diff --git a/internal/usergrant/repository/eventsourcing/user_grant.go b/internal/usergrant/repository/eventsourcing/user_grant.go index 15ae30a684..d1791621f5 100644 --- a/internal/usergrant/repository/eventsourcing/user_grant.go +++ b/internal/usergrant/repository/eventsourcing/user_grant.go @@ -5,7 +5,7 @@ import ( "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" proj_model "github.com/caos/zitadel/internal/project/model" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" @@ -48,7 +48,7 @@ func UserGrantAddedAggregate(ctx context.Context, aggCreator *es_models.Aggregat return nil, err } validationQuery := es_models.NewSearchQuery(). - AggregateTypeFilter(usr_model.UserAggregate, org_model.OrgAggregate, proj_es_model.ProjectAggregate). + AggregateTypeFilter(usr_model.UserAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate). AggregateIDsFilter(grant.UserID, auth.GetCtxData(ctx).OrgID, grant.ProjectID) validation := addUserGrantValidation(auth.GetCtxData(ctx).OrgID, grant) @@ -185,11 +185,11 @@ func addUserGrantValidation(resourceOwner string, grant *model.UserGrant) func(. case usr_model.UserRemoved: existsUser = false } - case org_model.OrgAggregate: + case org_es_model.OrgAggregate: switch event.Type { - case org_model.OrgAdded: + case org_es_model.OrgAdded: existsOrg = true - case org_model.OrgRemoved: + case org_es_model.OrgRemoved: existsOrg = false } case proj_es_model.ProjectAggregate: diff --git a/internal/usergrant/repository/view/model/user_grant.go b/internal/usergrant/repository/view/model/user_grant.go index 3ea8518755..c81f613b62 100644 --- a/internal/usergrant/repository/view/model/user_grant.go +++ b/internal/usergrant/repository/view/model/user_grant.go @@ -18,6 +18,7 @@ const ( UserGrantKeyProjectID = "project_id" UserGrantKeyResourceOwner = "resource_owner" UserGrantKeyState = "state" + UserGrantKeyOrgName = "org_name" ) type UserGrantView struct { diff --git a/internal/usergrant/repository/view/model/user_grant_query.go b/internal/usergrant/repository/view/model/user_grant_query.go index 2d69fd6555..c76114bedb 100644 --- a/internal/usergrant/repository/view/model/user_grant_query.go +++ b/internal/usergrant/repository/view/model/user_grant_query.go @@ -61,6 +61,8 @@ func (key UserGrantSearchKey) ToColumnName() string { return UserGrantKeyResourceOwner case grant_model.USERGRANTSEARCHKEY_GRANT_ID: return UserGrantKeyID + case grant_model.USERGRANTSEARCHKEY_ORG_NAME: + return UserGrantKeyOrgName default: return "" } diff --git a/internal/usergrant/repository/view/user_grant_view.go b/internal/usergrant/repository/view/user_grant_view.go index 3d9a5fee3f..c5ca4ec466 100644 --- a/internal/usergrant/repository/view/user_grant_view.go +++ b/internal/usergrant/repository/view/user_grant_view.go @@ -15,6 +15,17 @@ func UserGrantByID(db *gorm.DB, table, grantID string) (*model.UserGrantView, er return user, err } +func UserGrantByIDs(db *gorm.DB, table, resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) { + user := new(model.UserGrantView) + + resourceOwnerIDQuery := model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, Value: resourceOwnerID, Method: global_model.SEARCHMETHOD_EQUALS} + projectIDQuery := model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS} + userIDQuery := model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_USER_ID, Value: userID, Method: global_model.SEARCHMETHOD_EQUALS} + query := view.PrepareGetByQuery(table, resourceOwnerIDQuery, projectIDQuery, userIDQuery) + err := query(db, user) + return user, err +} + func SearchUserGrants(db *gorm.DB, table string, req *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) { users := make([]*model.UserGrantView, 0) query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries}) diff --git a/internal/view/query.go b/internal/view/query.go index 26829e1122..90f3dc4ce3 100644 --- a/internal/view/query.go +++ b/internal/view/query.go @@ -98,6 +98,12 @@ func SetQuery(query *gorm.DB, key ColumnKey, value interface{}, method model.Sea query = query.Where("LOWER("+column+") LIKE LOWER(?)", "%"+valueText+"%") case model.SEARCHMETHOD_NOT_EQUALS: query = query.Where(""+column+" <> ?", value) + case model.SEARCHMETHOD_GREATER_THAN: + query = query.Where(column+" > ?", value) + case model.SEARCHMETHOD_LESS_THAN: + query = query.Where(column+" < ?", value) + case model.SEARCHMETHOD_IN: + query = query.Where(column+" IN (?)", value) default: return nil, nil } diff --git a/internal/view/requests.go b/internal/view/requests.go index 22276138a4..2a888efd24 100644 --- a/internal/view/requests.go +++ b/internal/view/requests.go @@ -75,7 +75,7 @@ func PrepareDeleteByKey(table string, key ColumnKey, id string) func(db *gorm.DB type Key struct { Key ColumnKey - Value string + Value interface{} } func PrepareDeleteByKeys(table string, keys ...Key) func(db *gorm.DB) error { diff --git a/k8s/base/deployment.yaml b/k8s/base/deployment.yaml index 05777d819f..d24e32c39a 100644 --- a/k8s/base/deployment.yaml +++ b/k8s/base/deployment.yaml @@ -20,26 +20,26 @@ spec: - name: zitadel image: docker.pkg.github.com/caos/zitadel/zitadel:latest imagePullPolicy: IfNotPresent - args: ["-login=false", "-console=false"] + args: [] ports: - name: management-rest - containerPort: 60021 + containerPort: 50011 - name: management-grpc - containerPort: 60020 + containerPort: 50010 - name: auth-rest - containerPort: 60051 + containerPort: 50021 - name: issuer-rest - containerPort: 60052 + containerPort: 50022 - name: auth-grpc - containerPort: 60050 + containerPort: 50020 - name: admin-rest - containerPort: 60091 + containerPort: 50041 - name: admin-grpc - containerPort: 60090 + containerPort: 50040 - name: console-http - containerPort: 9090 + containerPort: 50050 - name: accounts-http - containerPort: 61121 + containerPort: 50031 env: - name: ZITADEL_GOOGLE_CHAT_URL valueFrom: diff --git a/migrations/cockroach/V1.11__auth_oidc.sql b/migrations/cockroach/V1.11__auth_oidc.sql new file mode 100644 index 0000000000..de38f0d349 --- /dev/null +++ b/migrations/cockroach/V1.11__auth_oidc.sql @@ -0,0 +1,56 @@ +BEGIN; + +CREATE TABLE auth.keys ( + id TEXT, + + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + + resource_owner TEXT, + private BOOLEAN, + expiry TIMESTAMPTZ, + algorithm TEXT, + usage SMALLINT, + key JSONB, + sequence BIGINT, + + PRIMARY KEY (id, private) +); + +CREATE TABLE auth.applications ( + id TEXT, + + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + app_state SMALLINT, + resource_owner TEXT, + app_name TEXT, + project_id TEXT, + app_type SMALLINT, + is_oidc BOOLEAN, + oidc_client_id TEXT, + oidc_redirect_uris TEXT ARRAY, + oidc_response_types SMALLINT ARRAY, + oidc_grant_types SMALLINT ARRAY, + oidc_application_type SMALLINT, + oidc_auth_method_type SMALLINT, + oidc_post_logout_redirect_uris TEXT ARRAY, + + PRIMARY KEY (id) +); + +ALTER TABLE auth.tokens ADD COLUMN scopes TEXT ARRAY; +ALTER TABLE auth.tokens ADD COLUMN audience TEXT ARRAY; + +ALTER TABLE auth.users ADD COLUMN init_required BOOLEAN; +ALTER TABLE management.users ADD COLUMN init_required BOOLEAN; + +ALTER TABLE auth.auth_requests ADD COLUMN code TEXT; +ALTER TABLE auth.auth_requests ADD COLUMN request_type smallint; + +ALTER TABLE auth.user_sessions ADD COLUMN mfa_software_verification_type smallint; +ALTER TABLE auth.user_sessions ADD COLUMN mfa_hardware_verification_type smallint; + +COMMIT; \ No newline at end of file diff --git a/migrations/cockroach/V1.12__auth_user_grant_view.sql b/migrations/cockroach/V1.12__auth_user_grant_view.sql new file mode 100644 index 0000000000..307f5fb6d0 --- /dev/null +++ b/migrations/cockroach/V1.12__auth_user_grant_view.sql @@ -0,0 +1,25 @@ +BEGIN; + +CREATE TABLE auth.user_grants ( + id TEXT, + resource_owner TEXT, + project_id TEXT, + user_id TEXT, + org_name TEXT, + org_domain TEXT, + project_name TEXT, + user_name TEXT, + first_name TEXT, + last_name TEXT, + email TEXT, + role_keys TEXT Array, + + grant_state SMALLINT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + PRIMARY KEY (id) +); + +COMMIT; diff --git a/migrations/cockroach/V1.13__auth_org_view.sql b/migrations/cockroach/V1.13__auth_org_view.sql new file mode 100644 index 0000000000..9cdb2da0fc --- /dev/null +++ b/migrations/cockroach/V1.13__auth_org_view.sql @@ -0,0 +1,17 @@ +BEGIN; + +CREATE TABLE auth.orgs ( + id TEXT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + resource_owner TEXT, + org_state SMALLINT, + sequence BIGINT, + + domain TEXT, + name TEXT, + + PRIMARY KEY (id) +); + +COMMIT; diff --git a/migrations/cockroach/V1.14__authz.sql b/migrations/cockroach/V1.14__authz.sql new file mode 100644 index 0000000000..3e38e2ee6b --- /dev/null +++ b/migrations/cockroach/V1.14__authz.sql @@ -0,0 +1,94 @@ +BEGIN; + +CREATE DATABASE authz; + + +COMMIT; + +BEGIN; + +CREATE USER authz; + +GRANT SELECT, INSERT, UPDATE, DELETE ON DATABASE authz TO authz; +GRANT SELECT, INSERT, UPDATE ON DATABASE eventstore TO authz; +GRANT SELECT, INSERT, UPDATE ON TABLE eventstore.* TO authz; +GRANT SELECT, INSERT, UPDATE ON DATABASE auth TO authz; +GRANT SELECT, INSERT, UPDATE ON TABLE auth.* TO authz; + +COMMIT; + +BEGIN; + +CREATE TABLE authz.locks ( + locker_id TEXT, + locked_until TIMESTAMPTZ, + object_type TEXT, + + PRIMARY KEY (object_type) +); + +CREATE TABLE authz.current_sequences ( + view_name TEXT, + + current_sequence BIGINT, + + PRIMARY KEY (view_name) +); + +CREATE TABLE authz.failed_event ( + view_name TEXT, + failed_sequence BIGINT, + failure_count SMALLINT, + err_msg TEXT, + + PRIMARY KEY (view_name, failed_sequence) +); + +CREATE TABLE authz.user_grants ( + id TEXT, + resource_owner TEXT, + project_id TEXT, + user_id TEXT, + org_name TEXT, + org_domain TEXT, + project_name TEXT, + user_name TEXT, + first_name TEXT, + last_name TEXT, + email TEXT, + role_keys TEXT Array, + + grant_state SMALLINT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + PRIMARY KEY (id) +); + +CREATE TABLE authz.applications ( + id TEXT, + + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + app_state SMALLINT, + resource_owner TEXT, + app_name TEXT, + project_id TEXT, + app_type SMALLINT, + is_oidc BOOLEAN, + oidc_client_id TEXT, + oidc_redirect_uris TEXT ARRAY, + oidc_response_types SMALLINT ARRAY, + oidc_grant_types SMALLINT ARRAY, + oidc_application_type SMALLINT, + oidc_auth_method_type SMALLINT, + oidc_post_logout_redirect_uris TEXT ARRAY, + + PRIMARY KEY (id) +); + +COMMIT; + diff --git a/pkg/admin/admin.go b/pkg/admin/admin.go index e4807186e7..526abea3a9 100644 --- a/pkg/admin/admin.go +++ b/pkg/admin/admin.go @@ -2,6 +2,7 @@ package admin import ( "context" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/logging" @@ -15,9 +16,9 @@ type Config struct { API api.Config } -func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) { +func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) { repo, err := eventsourcing.Start(ctx, config.Repository, systemDefaults) logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") - api.Start(ctx, config.API, authZ, repo) + api.Start(ctx, config.API, authZRepo, authZ, repo) } diff --git a/pkg/admin/api/api.go b/pkg/admin/api/api.go index 3272ef5ea8..4aaf4e1843 100644 --- a/pkg/admin/api/api.go +++ b/pkg/admin/api/api.go @@ -2,6 +2,7 @@ package api import ( "context" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/admin/repository" "github.com/caos/zitadel/internal/api/auth" @@ -14,8 +15,8 @@ type Config struct { GRPC grpc_util.Config } -func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) { - grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo) +func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) { + grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, repo) grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig()) server.StartServer(ctx, grpcServer) diff --git a/pkg/admin/api/grpc/server.go b/pkg/admin/api/grpc/server.go index a82832f532..0349117cca 100644 --- a/pkg/admin/api/grpc/server.go +++ b/pkg/admin/api/grpc/server.go @@ -6,6 +6,7 @@ import ( "github.com/caos/zitadel/internal/api/auth" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc/server/middleware" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "google.golang.org/grpc" ) @@ -20,13 +21,13 @@ type Server struct { repo repository.Repository } -func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server { +func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server { return &Server{ port: conf.Port, org: repo, repo: repo, authZ: authZ, - verifier: admin_auth.Start(), + verifier: admin_auth.Start(authZRepo), } } diff --git a/pkg/auth/api/api.go b/pkg/auth/api/api.go index 737af9eb8b..8240b0c091 100644 --- a/pkg/auth/api/api.go +++ b/pkg/auth/api/api.go @@ -2,22 +2,29 @@ package api import ( "context" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + + "github.com/caos/oidc/pkg/op" auth_util "github.com/caos/zitadel/internal/api/auth" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc/server" "github.com/caos/zitadel/internal/auth/repository" "github.com/caos/zitadel/pkg/auth/api/grpc" + "github.com/caos/zitadel/pkg/auth/api/oidc" ) type Config struct { GRPC grpc_util.Config + OIDC oidc.OPHandlerConfig } -func Start(ctx context.Context, conf Config, authZ auth_util.Config, repo repository.Repository) { - grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo) +func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth_util.Config, authRepo repository.Repository) { + grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, authRepo) grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig()) + oidcHandler := oidc.NewProvider(ctx, conf.OIDC, authRepo) server.StartServer(ctx, grpcServer) server.StartGateway(ctx, grpcGateway) + op.Start(ctx, oidcHandler) } diff --git a/pkg/auth/api/grpc/auth.pb.authoptions.go b/pkg/auth/api/grpc/auth.pb.authoptions.go index ee4700c496..5b53bf70fa 100644 --- a/pkg/auth/api/grpc/auth.pb.authoptions.go +++ b/pkg/auth/api/grpc/auth.pb.authoptions.go @@ -105,12 +105,12 @@ var AuthService_AuthMethods = utils_auth.MethodMapping{ CheckParam: "", }, - "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs": utils_auth.Option{ + "/zitadel.auth.api.v1.AuthService/SearchMyUserGrant": utils_auth.Option{ Permission: "authenticated", CheckParam: "", }, - "/zitadel.auth.api.v1.AuthService/IsIamAdmin": utils_auth.Option{ + "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs": utils_auth.Option{ Permission: "authenticated", CheckParam: "", }, diff --git a/pkg/auth/api/grpc/auth.pb.go b/pkg/auth/api/grpc/auth.pb.go index 2eae69dd91..fad9bc28a2 100644 --- a/pkg/auth/api/grpc/auth.pb.go +++ b/pkg/auth/api/grpc/auth.pb.go @@ -1,11 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.20.1 +// protoc v3.11.3 // source: auth.proto package grpc import ( context "context" - fmt "fmt" _ "github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/authoption" _ "github.com/envoyproxy/protoc-gen-validate/validate" proto "github.com/golang/protobuf/proto" @@ -17,19 +19,22 @@ import ( grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 type UserSessionState int32 @@ -39,24 +44,45 @@ const ( UserSessionState_USERSESSIONSTATE_TERMINATED UserSessionState = 2 ) -var UserSessionState_name = map[int32]string{ - 0: "USERSESSIONSTATE_UNSPECIFIED", - 1: "USERSESSIONSTATE_ACTIVE", - 2: "USERSESSIONSTATE_TERMINATED", -} +// Enum value maps for UserSessionState. +var ( + UserSessionState_name = map[int32]string{ + 0: "USERSESSIONSTATE_UNSPECIFIED", + 1: "USERSESSIONSTATE_ACTIVE", + 2: "USERSESSIONSTATE_TERMINATED", + } + UserSessionState_value = map[string]int32{ + "USERSESSIONSTATE_UNSPECIFIED": 0, + "USERSESSIONSTATE_ACTIVE": 1, + "USERSESSIONSTATE_TERMINATED": 2, + } +) -var UserSessionState_value = map[string]int32{ - "USERSESSIONSTATE_UNSPECIFIED": 0, - "USERSESSIONSTATE_ACTIVE": 1, - "USERSESSIONSTATE_TERMINATED": 2, +func (x UserSessionState) Enum() *UserSessionState { + p := new(UserSessionState) + *p = x + return p } func (x UserSessionState) String() string { - return proto.EnumName(UserSessionState_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (UserSessionState) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[0].Descriptor() +} + +func (UserSessionState) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[0] +} + +func (x UserSessionState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserSessionState.Descriptor instead. func (UserSessionState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{0} + return file_auth_proto_rawDescGZIP(), []int{0} } type OIDCResponseType int32 @@ -67,24 +93,45 @@ const ( OIDCResponseType_OIDCRESPONSETYPE_ID_TOKEN_TOKEN OIDCResponseType = 2 ) -var OIDCResponseType_name = map[int32]string{ - 0: "OIDCRESPONSETYPE_CODE", - 1: "OIDCRESPONSETYPE_ID_TOKEN", - 2: "OIDCRESPONSETYPE_ID_TOKEN_TOKEN", -} +// Enum value maps for OIDCResponseType. +var ( + OIDCResponseType_name = map[int32]string{ + 0: "OIDCRESPONSETYPE_CODE", + 1: "OIDCRESPONSETYPE_ID_TOKEN", + 2: "OIDCRESPONSETYPE_ID_TOKEN_TOKEN", + } + OIDCResponseType_value = map[string]int32{ + "OIDCRESPONSETYPE_CODE": 0, + "OIDCRESPONSETYPE_ID_TOKEN": 1, + "OIDCRESPONSETYPE_ID_TOKEN_TOKEN": 2, + } +) -var OIDCResponseType_value = map[string]int32{ - "OIDCRESPONSETYPE_CODE": 0, - "OIDCRESPONSETYPE_ID_TOKEN": 1, - "OIDCRESPONSETYPE_ID_TOKEN_TOKEN": 2, +func (x OIDCResponseType) Enum() *OIDCResponseType { + p := new(OIDCResponseType) + *p = x + return p } func (x OIDCResponseType) String() string { - return proto.EnumName(OIDCResponseType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (OIDCResponseType) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[1].Descriptor() +} + +func (OIDCResponseType) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[1] +} + +func (x OIDCResponseType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use OIDCResponseType.Descriptor instead. func (OIDCResponseType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{1} + return file_auth_proto_rawDescGZIP(), []int{1} } type UserState int32 @@ -99,32 +146,53 @@ const ( UserState_USERSTATE_INITIAL UserState = 6 ) -var UserState_name = map[int32]string{ - 0: "USERSTATE_UNSPECIEFIED", - 1: "USERSTATE_ACTIVE", - 2: "USERSTATE_INACTIVE", - 3: "USERSTATE_DELETED", - 4: "USERSTATE_LOCKED", - 5: "USERSTATE_SUSPEND", - 6: "USERSTATE_INITIAL", -} +// Enum value maps for UserState. +var ( + UserState_name = map[int32]string{ + 0: "USERSTATE_UNSPECIEFIED", + 1: "USERSTATE_ACTIVE", + 2: "USERSTATE_INACTIVE", + 3: "USERSTATE_DELETED", + 4: "USERSTATE_LOCKED", + 5: "USERSTATE_SUSPEND", + 6: "USERSTATE_INITIAL", + } + UserState_value = map[string]int32{ + "USERSTATE_UNSPECIEFIED": 0, + "USERSTATE_ACTIVE": 1, + "USERSTATE_INACTIVE": 2, + "USERSTATE_DELETED": 3, + "USERSTATE_LOCKED": 4, + "USERSTATE_SUSPEND": 5, + "USERSTATE_INITIAL": 6, + } +) -var UserState_value = map[string]int32{ - "USERSTATE_UNSPECIEFIED": 0, - "USERSTATE_ACTIVE": 1, - "USERSTATE_INACTIVE": 2, - "USERSTATE_DELETED": 3, - "USERSTATE_LOCKED": 4, - "USERSTATE_SUSPEND": 5, - "USERSTATE_INITIAL": 6, +func (x UserState) Enum() *UserState { + p := new(UserState) + *p = x + return p } func (x UserState) String() string { - return proto.EnumName(UserState_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (UserState) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[2].Descriptor() +} + +func (UserState) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[2] +} + +func (x UserState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserState.Descriptor instead. func (UserState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{2} + return file_auth_proto_rawDescGZIP(), []int{2} } type Gender int32 @@ -136,26 +204,47 @@ const ( Gender_GENDER_DIVERSE Gender = 3 ) -var Gender_name = map[int32]string{ - 0: "GENDER_UNSPECIFIED", - 1: "GENDER_FEMALE", - 2: "GENDER_MALE", - 3: "GENDER_DIVERSE", -} +// Enum value maps for Gender. +var ( + Gender_name = map[int32]string{ + 0: "GENDER_UNSPECIFIED", + 1: "GENDER_FEMALE", + 2: "GENDER_MALE", + 3: "GENDER_DIVERSE", + } + Gender_value = map[string]int32{ + "GENDER_UNSPECIFIED": 0, + "GENDER_FEMALE": 1, + "GENDER_MALE": 2, + "GENDER_DIVERSE": 3, + } +) -var Gender_value = map[string]int32{ - "GENDER_UNSPECIFIED": 0, - "GENDER_FEMALE": 1, - "GENDER_MALE": 2, - "GENDER_DIVERSE": 3, +func (x Gender) Enum() *Gender { + p := new(Gender) + *p = x + return p } func (x Gender) String() string { - return proto.EnumName(Gender_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (Gender) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[3].Descriptor() +} + +func (Gender) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[3] +} + +func (x Gender) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Gender.Descriptor instead. func (Gender) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{3} + return file_auth_proto_rawDescGZIP(), []int{3} } type MfaType int32 @@ -166,24 +255,45 @@ const ( MfaType_MFATYPE_OTP MfaType = 2 ) -var MfaType_name = map[int32]string{ - 0: "MFATYPE_UNSPECIFIED", - 1: "MFATYPE_SMS", - 2: "MFATYPE_OTP", -} +// Enum value maps for MfaType. +var ( + MfaType_name = map[int32]string{ + 0: "MFATYPE_UNSPECIFIED", + 1: "MFATYPE_SMS", + 2: "MFATYPE_OTP", + } + MfaType_value = map[string]int32{ + "MFATYPE_UNSPECIFIED": 0, + "MFATYPE_SMS": 1, + "MFATYPE_OTP": 2, + } +) -var MfaType_value = map[string]int32{ - "MFATYPE_UNSPECIFIED": 0, - "MFATYPE_SMS": 1, - "MFATYPE_OTP": 2, +func (x MfaType) Enum() *MfaType { + p := new(MfaType) + *p = x + return p } func (x MfaType) String() string { - return proto.EnumName(MfaType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (MfaType) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[4].Descriptor() +} + +func (MfaType) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[4] +} + +func (x MfaType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MfaType.Descriptor instead. func (MfaType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{4} + return file_auth_proto_rawDescGZIP(), []int{4} } type MFAState int32 @@ -195,26 +305,96 @@ const ( MFAState_MFASTATE_REMOVED MFAState = 3 ) -var MFAState_name = map[int32]string{ - 0: "MFASTATE_UNSPECIFIED", - 1: "MFASTATE_NOT_READY", - 2: "MFASTATE_READY", - 3: "MFASTATE_REMOVED", -} +// Enum value maps for MFAState. +var ( + MFAState_name = map[int32]string{ + 0: "MFASTATE_UNSPECIFIED", + 1: "MFASTATE_NOT_READY", + 2: "MFASTATE_READY", + 3: "MFASTATE_REMOVED", + } + MFAState_value = map[string]int32{ + "MFASTATE_UNSPECIFIED": 0, + "MFASTATE_NOT_READY": 1, + "MFASTATE_READY": 2, + "MFASTATE_REMOVED": 3, + } +) -var MFAState_value = map[string]int32{ - "MFASTATE_UNSPECIFIED": 0, - "MFASTATE_NOT_READY": 1, - "MFASTATE_READY": 2, - "MFASTATE_REMOVED": 3, +func (x MFAState) Enum() *MFAState { + p := new(MFAState) + *p = x + return p } func (x MFAState) String() string { - return proto.EnumName(MFAState_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (MFAState) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[5].Descriptor() +} + +func (MFAState) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[5] +} + +func (x MFAState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MFAState.Descriptor instead. func (MFAState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{5} + return file_auth_proto_rawDescGZIP(), []int{5} +} + +type UserGrantSearchKey int32 + +const ( + UserGrantSearchKey_UserGrantSearchKey_UNKNOWN UserGrantSearchKey = 0 + UserGrantSearchKey_UserGrantSearchKey_ORG_ID UserGrantSearchKey = 1 + UserGrantSearchKey_UserGrantSearchKey_PROJECT_ID UserGrantSearchKey = 2 +) + +// Enum value maps for UserGrantSearchKey. +var ( + UserGrantSearchKey_name = map[int32]string{ + 0: "UserGrantSearchKey_UNKNOWN", + 1: "UserGrantSearchKey_ORG_ID", + 2: "UserGrantSearchKey_PROJECT_ID", + } + UserGrantSearchKey_value = map[string]int32{ + "UserGrantSearchKey_UNKNOWN": 0, + "UserGrantSearchKey_ORG_ID": 1, + "UserGrantSearchKey_PROJECT_ID": 2, + } +) + +func (x UserGrantSearchKey) Enum() *UserGrantSearchKey { + p := new(UserGrantSearchKey) + *p = x + return p +} + +func (x UserGrantSearchKey) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UserGrantSearchKey) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[6].Descriptor() +} + +func (UserGrantSearchKey) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[6] +} + +func (x UserGrantSearchKey) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserGrantSearchKey.Descriptor instead. +func (UserGrantSearchKey) EnumDescriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{6} } type MyProjectOrgSearchKey int32 @@ -224,171 +404,242 @@ const ( MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_ORG_NAME MyProjectOrgSearchKey = 1 ) -var MyProjectOrgSearchKey_name = map[int32]string{ - 0: "MYPROJECTORGSEARCHKEY_UNSPECIFIED", - 1: "MYPROJECTORGSEARCHKEY_ORG_NAME", -} +// Enum value maps for MyProjectOrgSearchKey. +var ( + MyProjectOrgSearchKey_name = map[int32]string{ + 0: "MYPROJECTORGSEARCHKEY_UNSPECIFIED", + 1: "MYPROJECTORGSEARCHKEY_ORG_NAME", + } + MyProjectOrgSearchKey_value = map[string]int32{ + "MYPROJECTORGSEARCHKEY_UNSPECIFIED": 0, + "MYPROJECTORGSEARCHKEY_ORG_NAME": 1, + } +) -var MyProjectOrgSearchKey_value = map[string]int32{ - "MYPROJECTORGSEARCHKEY_UNSPECIFIED": 0, - "MYPROJECTORGSEARCHKEY_ORG_NAME": 1, +func (x MyProjectOrgSearchKey) Enum() *MyProjectOrgSearchKey { + p := new(MyProjectOrgSearchKey) + *p = x + return p } func (x MyProjectOrgSearchKey) String() string { - return proto.EnumName(MyProjectOrgSearchKey_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (MyProjectOrgSearchKey) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[7].Descriptor() +} + +func (MyProjectOrgSearchKey) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[7] +} + +func (x MyProjectOrgSearchKey) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MyProjectOrgSearchKey.Descriptor instead. func (MyProjectOrgSearchKey) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{6} + return file_auth_proto_rawDescGZIP(), []int{7} } type SearchMethod int32 const ( - SearchMethod_SEARCHMETHOD_EQUALS SearchMethod = 0 - SearchMethod_SEARCHMETHOD_STARTS_WITH SearchMethod = 1 - SearchMethod_SEARCHMETHOD_CONTAINS SearchMethod = 2 + SearchMethod_SEARCHMETHOD_EQUALS SearchMethod = 0 + SearchMethod_SEARCHMETHOD_STARTS_WITH SearchMethod = 1 + SearchMethod_SEARCHMETHOD_CONTAINS SearchMethod = 2 + SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE SearchMethod = 3 + SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE SearchMethod = 4 + SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE SearchMethod = 5 ) -var SearchMethod_name = map[int32]string{ - 0: "SEARCHMETHOD_EQUALS", - 1: "SEARCHMETHOD_STARTS_WITH", - 2: "SEARCHMETHOD_CONTAINS", -} +// Enum value maps for SearchMethod. +var ( + SearchMethod_name = map[int32]string{ + 0: "SEARCHMETHOD_EQUALS", + 1: "SEARCHMETHOD_STARTS_WITH", + 2: "SEARCHMETHOD_CONTAINS", + 3: "SEARCHMETHOD_EQUALS_IGNORE_CASE", + 4: "SEARCHMETHOD_STARTS_WITH_IGNORE_CASE", + 5: "SEARCHMETHOD_CONTAINS_IGNORE_CASE", + } + SearchMethod_value = map[string]int32{ + "SEARCHMETHOD_EQUALS": 0, + "SEARCHMETHOD_STARTS_WITH": 1, + "SEARCHMETHOD_CONTAINS": 2, + "SEARCHMETHOD_EQUALS_IGNORE_CASE": 3, + "SEARCHMETHOD_STARTS_WITH_IGNORE_CASE": 4, + "SEARCHMETHOD_CONTAINS_IGNORE_CASE": 5, + } +) -var SearchMethod_value = map[string]int32{ - "SEARCHMETHOD_EQUALS": 0, - "SEARCHMETHOD_STARTS_WITH": 1, - "SEARCHMETHOD_CONTAINS": 2, +func (x SearchMethod) Enum() *SearchMethod { + p := new(SearchMethod) + *p = x + return p } func (x SearchMethod) String() string { - return proto.EnumName(SearchMethod_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (SearchMethod) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[8].Descriptor() +} + +func (SearchMethod) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[8] +} + +func (x SearchMethod) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SearchMethod.Descriptor instead. func (SearchMethod) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{7} + return file_auth_proto_rawDescGZIP(), []int{8} } type UserSessionViews struct { - UserSessions []*UserSessionView `protobuf:"bytes,1,rep,name=user_sessions,json=userSessions,proto3" json:"user_sessions,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserSessions []*UserSessionView `protobuf:"bytes,1,rep,name=user_sessions,json=userSessions,proto3" json:"user_sessions,omitempty"` } -func (m *UserSessionViews) Reset() { *m = UserSessionViews{} } -func (m *UserSessionViews) String() string { return proto.CompactTextString(m) } -func (*UserSessionViews) ProtoMessage() {} +func (x *UserSessionViews) Reset() { + *x = UserSessionViews{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserSessionViews) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserSessionViews) ProtoMessage() {} + +func (x *UserSessionViews) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserSessionViews.ProtoReflect.Descriptor instead. func (*UserSessionViews) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{0} + return file_auth_proto_rawDescGZIP(), []int{0} } -func (m *UserSessionViews) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserSessionViews.Unmarshal(m, b) -} -func (m *UserSessionViews) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserSessionViews.Marshal(b, m, deterministic) -} -func (m *UserSessionViews) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserSessionViews.Merge(m, src) -} -func (m *UserSessionViews) XXX_Size() int { - return xxx_messageInfo_UserSessionViews.Size(m) -} -func (m *UserSessionViews) XXX_DiscardUnknown() { - xxx_messageInfo_UserSessionViews.DiscardUnknown(m) -} - -var xxx_messageInfo_UserSessionViews proto.InternalMessageInfo - -func (m *UserSessionViews) GetUserSessions() []*UserSessionView { - if m != nil { - return m.UserSessions +func (x *UserSessionViews) GetUserSessions() []*UserSessionView { + if x != nil { + return x.UserSessions } return nil } type UserSessionView struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` - AuthState UserSessionState `protobuf:"varint,3,opt,name=auth_state,json=authState,proto3,enum=zitadel.auth.api.v1.UserSessionState" json:"auth_state,omitempty"` - UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - UserName string `protobuf:"bytes,5,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` - Sequence uint64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` + AuthState UserSessionState `protobuf:"varint,3,opt,name=auth_state,json=authState,proto3,enum=zitadel.auth.api.v1.UserSessionState" json:"auth_state,omitempty"` + UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + UserName string `protobuf:"bytes,5,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` + Sequence uint64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"` } -func (m *UserSessionView) Reset() { *m = UserSessionView{} } -func (m *UserSessionView) String() string { return proto.CompactTextString(m) } -func (*UserSessionView) ProtoMessage() {} +func (x *UserSessionView) Reset() { + *x = UserSessionView{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserSessionView) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserSessionView) ProtoMessage() {} + +func (x *UserSessionView) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserSessionView.ProtoReflect.Descriptor instead. func (*UserSessionView) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{1} + return file_auth_proto_rawDescGZIP(), []int{1} } -func (m *UserSessionView) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserSessionView.Unmarshal(m, b) -} -func (m *UserSessionView) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserSessionView.Marshal(b, m, deterministic) -} -func (m *UserSessionView) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserSessionView.Merge(m, src) -} -func (m *UserSessionView) XXX_Size() int { - return xxx_messageInfo_UserSessionView.Size(m) -} -func (m *UserSessionView) XXX_DiscardUnknown() { - xxx_messageInfo_UserSessionView.DiscardUnknown(m) -} - -var xxx_messageInfo_UserSessionView proto.InternalMessageInfo - -func (m *UserSessionView) GetId() string { - if m != nil { - return m.Id +func (x *UserSessionView) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserSessionView) GetAgentId() string { - if m != nil { - return m.AgentId +func (x *UserSessionView) GetAgentId() string { + if x != nil { + return x.AgentId } return "" } -func (m *UserSessionView) GetAuthState() UserSessionState { - if m != nil { - return m.AuthState +func (x *UserSessionView) GetAuthState() UserSessionState { + if x != nil { + return x.AuthState } return UserSessionState_USERSESSIONSTATE_UNSPECIFIED } -func (m *UserSessionView) GetUserId() string { - if m != nil { - return m.UserId +func (x *UserSessionView) GetUserId() string { + if x != nil { + return x.UserId } return "" } -func (m *UserSessionView) GetUserName() string { - if m != nil { - return m.UserName +func (x *UserSessionView) GetUserName() string { + if x != nil { + return x.UserName } return "" } -func (m *UserSessionView) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserSessionView) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` State UserState `protobuf:"varint,2,opt,name=state,proto3,enum=zitadel.auth.api.v1.UserState" json:"state,omitempty"` CreationDate *timestamp.Timestamp `protobuf:"bytes,3,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` @@ -414,1827 +665,3245 @@ type User struct { StreetAddress string `protobuf:"bytes,23,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` PasswordChangeRequired bool `protobuf:"varint,24,opt,name=password_change_required,json=passwordChangeRequired,proto3" json:"password_change_required,omitempty"` Sequence uint64 `protobuf:"varint,25,opt,name=sequence,proto3" json:"sequence,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` } -func (m *User) Reset() { *m = User{} } -func (m *User) String() string { return proto.CompactTextString(m) } -func (*User) ProtoMessage() {} +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{2} + return file_auth_proto_rawDescGZIP(), []int{2} } -func (m *User) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_User.Unmarshal(m, b) -} -func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_User.Marshal(b, m, deterministic) -} -func (m *User) XXX_Merge(src proto.Message) { - xxx_messageInfo_User.Merge(m, src) -} -func (m *User) XXX_Size() int { - return xxx_messageInfo_User.Size(m) -} -func (m *User) XXX_DiscardUnknown() { - xxx_messageInfo_User.DiscardUnknown(m) -} - -var xxx_messageInfo_User proto.InternalMessageInfo - -func (m *User) GetId() string { - if m != nil { - return m.Id +func (x *User) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *User) GetState() UserState { - if m != nil { - return m.State +func (x *User) GetState() UserState { + if x != nil { + return x.State } return UserState_USERSTATE_UNSPECIEFIED } -func (m *User) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *User) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *User) GetActivationDate() *timestamp.Timestamp { - if m != nil { - return m.ActivationDate +func (x *User) GetActivationDate() *timestamp.Timestamp { + if x != nil { + return x.ActivationDate } return nil } -func (m *User) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *User) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } -func (m *User) GetLastLogin() *timestamp.Timestamp { - if m != nil { - return m.LastLogin +func (x *User) GetLastLogin() *timestamp.Timestamp { + if x != nil { + return x.LastLogin } return nil } -func (m *User) GetPasswordChanged() *timestamp.Timestamp { - if m != nil { - return m.PasswordChanged +func (x *User) GetPasswordChanged() *timestamp.Timestamp { + if x != nil { + return x.PasswordChanged } return nil } -func (m *User) GetUserName() string { - if m != nil { - return m.UserName +func (x *User) GetUserName() string { + if x != nil { + return x.UserName } return "" } -func (m *User) GetFirstName() string { - if m != nil { - return m.FirstName +func (x *User) GetFirstName() string { + if x != nil { + return x.FirstName } return "" } -func (m *User) GetLastName() string { - if m != nil { - return m.LastName +func (x *User) GetLastName() string { + if x != nil { + return x.LastName } return "" } -func (m *User) GetNickName() string { - if m != nil { - return m.NickName +func (x *User) GetNickName() string { + if x != nil { + return x.NickName } return "" } -func (m *User) GetDisplayName() string { - if m != nil { - return m.DisplayName +func (x *User) GetDisplayName() string { + if x != nil { + return x.DisplayName } return "" } -func (m *User) GetPreferredLanguage() string { - if m != nil { - return m.PreferredLanguage +func (x *User) GetPreferredLanguage() string { + if x != nil { + return x.PreferredLanguage } return "" } -func (m *User) GetGender() Gender { - if m != nil { - return m.Gender +func (x *User) GetGender() Gender { + if x != nil { + return x.Gender } return Gender_GENDER_UNSPECIFIED } -func (m *User) GetEmail() string { - if m != nil { - return m.Email +func (x *User) GetEmail() string { + if x != nil { + return x.Email } return "" } -func (m *User) GetIsEmailVerified() bool { - if m != nil { - return m.IsEmailVerified +func (x *User) GetIsEmailVerified() bool { + if x != nil { + return x.IsEmailVerified } return false } -func (m *User) GetPhone() string { - if m != nil { - return m.Phone +func (x *User) GetPhone() string { + if x != nil { + return x.Phone } return "" } -func (m *User) GetIsPhoneVerified() bool { - if m != nil { - return m.IsPhoneVerified +func (x *User) GetIsPhoneVerified() bool { + if x != nil { + return x.IsPhoneVerified } return false } -func (m *User) GetCountry() string { - if m != nil { - return m.Country +func (x *User) GetCountry() string { + if x != nil { + return x.Country } return "" } -func (m *User) GetLocality() string { - if m != nil { - return m.Locality +func (x *User) GetLocality() string { + if x != nil { + return x.Locality } return "" } -func (m *User) GetPostalCode() string { - if m != nil { - return m.PostalCode +func (x *User) GetPostalCode() string { + if x != nil { + return x.PostalCode } return "" } -func (m *User) GetRegion() string { - if m != nil { - return m.Region +func (x *User) GetRegion() string { + if x != nil { + return x.Region } return "" } -func (m *User) GetStreetAddress() string { - if m != nil { - return m.StreetAddress +func (x *User) GetStreetAddress() string { + if x != nil { + return x.StreetAddress } return "" } -func (m *User) GetPasswordChangeRequired() bool { - if m != nil { - return m.PasswordChangeRequired +func (x *User) GetPasswordChangeRequired() bool { + if x != nil { + return x.PasswordChangeRequired } return false } -func (m *User) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *User) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } type UserProfile struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - UserName string `protobuf:"bytes,2,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` - FirstName string `protobuf:"bytes,3,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` - LastName string `protobuf:"bytes,4,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` - NickName string `protobuf:"bytes,5,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` - DisplayName string `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - PreferredLanguage string `protobuf:"bytes,7,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` - Gender Gender `protobuf:"varint,8,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` - Sequence uint64 `protobuf:"varint,9,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,10,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,11,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + UserName string `protobuf:"bytes,2,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` + FirstName string `protobuf:"bytes,3,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName string `protobuf:"bytes,4,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + NickName string `protobuf:"bytes,5,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` + DisplayName string `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + PreferredLanguage string `protobuf:"bytes,7,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` + Gender Gender `protobuf:"varint,8,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` + Sequence uint64 `protobuf:"varint,9,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,10,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,11,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserProfile) Reset() { *m = UserProfile{} } -func (m *UserProfile) String() string { return proto.CompactTextString(m) } -func (*UserProfile) ProtoMessage() {} +func (x *UserProfile) Reset() { + *x = UserProfile{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserProfile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserProfile) ProtoMessage() {} + +func (x *UserProfile) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserProfile.ProtoReflect.Descriptor instead. func (*UserProfile) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{3} + return file_auth_proto_rawDescGZIP(), []int{3} } -func (m *UserProfile) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserProfile.Unmarshal(m, b) -} -func (m *UserProfile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserProfile.Marshal(b, m, deterministic) -} -func (m *UserProfile) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserProfile.Merge(m, src) -} -func (m *UserProfile) XXX_Size() int { - return xxx_messageInfo_UserProfile.Size(m) -} -func (m *UserProfile) XXX_DiscardUnknown() { - xxx_messageInfo_UserProfile.DiscardUnknown(m) -} - -var xxx_messageInfo_UserProfile proto.InternalMessageInfo - -func (m *UserProfile) GetId() string { - if m != nil { - return m.Id +func (x *UserProfile) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserProfile) GetUserName() string { - if m != nil { - return m.UserName +func (x *UserProfile) GetUserName() string { + if x != nil { + return x.UserName } return "" } -func (m *UserProfile) GetFirstName() string { - if m != nil { - return m.FirstName +func (x *UserProfile) GetFirstName() string { + if x != nil { + return x.FirstName } return "" } -func (m *UserProfile) GetLastName() string { - if m != nil { - return m.LastName +func (x *UserProfile) GetLastName() string { + if x != nil { + return x.LastName } return "" } -func (m *UserProfile) GetNickName() string { - if m != nil { - return m.NickName +func (x *UserProfile) GetNickName() string { + if x != nil { + return x.NickName } return "" } -func (m *UserProfile) GetDisplayName() string { - if m != nil { - return m.DisplayName +func (x *UserProfile) GetDisplayName() string { + if x != nil { + return x.DisplayName } return "" } -func (m *UserProfile) GetPreferredLanguage() string { - if m != nil { - return m.PreferredLanguage +func (x *UserProfile) GetPreferredLanguage() string { + if x != nil { + return x.PreferredLanguage } return "" } -func (m *UserProfile) GetGender() Gender { - if m != nil { - return m.Gender +func (x *UserProfile) GetGender() Gender { + if x != nil { + return x.Gender } return Gender_GENDER_UNSPECIFIED } -func (m *UserProfile) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserProfile) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserProfile) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserProfile) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserProfile) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserProfile) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type UpdateUserProfileRequest struct { - FirstName string `protobuf:"bytes,1,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` - LastName string `protobuf:"bytes,2,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` - NickName string `protobuf:"bytes,3,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` - DisplayName string `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - PreferredLanguage string `protobuf:"bytes,5,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` - Gender Gender `protobuf:"varint,6,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FirstName string `protobuf:"bytes,1,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName string `protobuf:"bytes,2,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + NickName string `protobuf:"bytes,3,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` + DisplayName string `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + PreferredLanguage string `protobuf:"bytes,5,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` + Gender Gender `protobuf:"varint,6,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` } -func (m *UpdateUserProfileRequest) Reset() { *m = UpdateUserProfileRequest{} } -func (m *UpdateUserProfileRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserProfileRequest) ProtoMessage() {} +func (x *UpdateUserProfileRequest) Reset() { + *x = UpdateUserProfileRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserProfileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserProfileRequest) ProtoMessage() {} + +func (x *UpdateUserProfileRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserProfileRequest.ProtoReflect.Descriptor instead. func (*UpdateUserProfileRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{4} + return file_auth_proto_rawDescGZIP(), []int{4} } -func (m *UpdateUserProfileRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserProfileRequest.Unmarshal(m, b) -} -func (m *UpdateUserProfileRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserProfileRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserProfileRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserProfileRequest.Merge(m, src) -} -func (m *UpdateUserProfileRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserProfileRequest.Size(m) -} -func (m *UpdateUserProfileRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserProfileRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserProfileRequest proto.InternalMessageInfo - -func (m *UpdateUserProfileRequest) GetFirstName() string { - if m != nil { - return m.FirstName +func (x *UpdateUserProfileRequest) GetFirstName() string { + if x != nil { + return x.FirstName } return "" } -func (m *UpdateUserProfileRequest) GetLastName() string { - if m != nil { - return m.LastName +func (x *UpdateUserProfileRequest) GetLastName() string { + if x != nil { + return x.LastName } return "" } -func (m *UpdateUserProfileRequest) GetNickName() string { - if m != nil { - return m.NickName +func (x *UpdateUserProfileRequest) GetNickName() string { + if x != nil { + return x.NickName } return "" } -func (m *UpdateUserProfileRequest) GetDisplayName() string { - if m != nil { - return m.DisplayName +func (x *UpdateUserProfileRequest) GetDisplayName() string { + if x != nil { + return x.DisplayName } return "" } -func (m *UpdateUserProfileRequest) GetPreferredLanguage() string { - if m != nil { - return m.PreferredLanguage +func (x *UpdateUserProfileRequest) GetPreferredLanguage() string { + if x != nil { + return x.PreferredLanguage } return "" } -func (m *UpdateUserProfileRequest) GetGender() Gender { - if m != nil { - return m.Gender +func (x *UpdateUserProfileRequest) GetGender() Gender { + if x != nil { + return x.Gender } return Gender_GENDER_UNSPECIFIED } type UserEmail struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` - IsEmailVerified bool `protobuf:"varint,3,opt,name=isEmailVerified,proto3" json:"isEmailVerified,omitempty"` - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` + IsEmailVerified bool `protobuf:"varint,3,opt,name=isEmailVerified,proto3" json:"isEmailVerified,omitempty"` + Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserEmail) Reset() { *m = UserEmail{} } -func (m *UserEmail) String() string { return proto.CompactTextString(m) } -func (*UserEmail) ProtoMessage() {} +func (x *UserEmail) Reset() { + *x = UserEmail{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserEmail) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserEmail) ProtoMessage() {} + +func (x *UserEmail) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserEmail.ProtoReflect.Descriptor instead. func (*UserEmail) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{5} + return file_auth_proto_rawDescGZIP(), []int{5} } -func (m *UserEmail) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserEmail.Unmarshal(m, b) -} -func (m *UserEmail) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserEmail.Marshal(b, m, deterministic) -} -func (m *UserEmail) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserEmail.Merge(m, src) -} -func (m *UserEmail) XXX_Size() int { - return xxx_messageInfo_UserEmail.Size(m) -} -func (m *UserEmail) XXX_DiscardUnknown() { - xxx_messageInfo_UserEmail.DiscardUnknown(m) -} - -var xxx_messageInfo_UserEmail proto.InternalMessageInfo - -func (m *UserEmail) GetId() string { - if m != nil { - return m.Id +func (x *UserEmail) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserEmail) GetEmail() string { - if m != nil { - return m.Email +func (x *UserEmail) GetEmail() string { + if x != nil { + return x.Email } return "" } -func (m *UserEmail) GetIsEmailVerified() bool { - if m != nil { - return m.IsEmailVerified +func (x *UserEmail) GetIsEmailVerified() bool { + if x != nil { + return x.IsEmailVerified } return false } -func (m *UserEmail) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserEmail) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserEmail) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserEmail) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserEmail) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserEmail) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type VerifyMyUserEmailRequest struct { - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyMyUserEmailRequest) Reset() { *m = VerifyMyUserEmailRequest{} } -func (m *VerifyMyUserEmailRequest) String() string { return proto.CompactTextString(m) } -func (*VerifyMyUserEmailRequest) ProtoMessage() {} +func (x *VerifyMyUserEmailRequest) Reset() { + *x = VerifyMyUserEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyMyUserEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyMyUserEmailRequest) ProtoMessage() {} + +func (x *VerifyMyUserEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyMyUserEmailRequest.ProtoReflect.Descriptor instead. func (*VerifyMyUserEmailRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{6} + return file_auth_proto_rawDescGZIP(), []int{6} } -func (m *VerifyMyUserEmailRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyMyUserEmailRequest.Unmarshal(m, b) -} -func (m *VerifyMyUserEmailRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyMyUserEmailRequest.Marshal(b, m, deterministic) -} -func (m *VerifyMyUserEmailRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyMyUserEmailRequest.Merge(m, src) -} -func (m *VerifyMyUserEmailRequest) XXX_Size() int { - return xxx_messageInfo_VerifyMyUserEmailRequest.Size(m) -} -func (m *VerifyMyUserEmailRequest) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyMyUserEmailRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyMyUserEmailRequest proto.InternalMessageInfo - -func (m *VerifyMyUserEmailRequest) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyMyUserEmailRequest) GetCode() string { + if x != nil { + return x.Code } return "" } type VerifyUserEmailRequest struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyUserEmailRequest) Reset() { *m = VerifyUserEmailRequest{} } -func (m *VerifyUserEmailRequest) String() string { return proto.CompactTextString(m) } -func (*VerifyUserEmailRequest) ProtoMessage() {} +func (x *VerifyUserEmailRequest) Reset() { + *x = VerifyUserEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyUserEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyUserEmailRequest) ProtoMessage() {} + +func (x *VerifyUserEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyUserEmailRequest.ProtoReflect.Descriptor instead. func (*VerifyUserEmailRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{7} + return file_auth_proto_rawDescGZIP(), []int{7} } -func (m *VerifyUserEmailRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyUserEmailRequest.Unmarshal(m, b) -} -func (m *VerifyUserEmailRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyUserEmailRequest.Marshal(b, m, deterministic) -} -func (m *VerifyUserEmailRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyUserEmailRequest.Merge(m, src) -} -func (m *VerifyUserEmailRequest) XXX_Size() int { - return xxx_messageInfo_VerifyUserEmailRequest.Size(m) -} -func (m *VerifyUserEmailRequest) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyUserEmailRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyUserEmailRequest proto.InternalMessageInfo - -func (m *VerifyUserEmailRequest) GetId() string { - if m != nil { - return m.Id +func (x *VerifyUserEmailRequest) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *VerifyUserEmailRequest) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyUserEmailRequest) GetCode() string { + if x != nil { + return x.Code } return "" } type UpdateUserEmailRequest struct { - Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` } -func (m *UpdateUserEmailRequest) Reset() { *m = UpdateUserEmailRequest{} } -func (m *UpdateUserEmailRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserEmailRequest) ProtoMessage() {} +func (x *UpdateUserEmailRequest) Reset() { + *x = UpdateUserEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserEmailRequest) ProtoMessage() {} + +func (x *UpdateUserEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserEmailRequest.ProtoReflect.Descriptor instead. func (*UpdateUserEmailRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{8} + return file_auth_proto_rawDescGZIP(), []int{8} } -func (m *UpdateUserEmailRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserEmailRequest.Unmarshal(m, b) -} -func (m *UpdateUserEmailRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserEmailRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserEmailRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserEmailRequest.Merge(m, src) -} -func (m *UpdateUserEmailRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserEmailRequest.Size(m) -} -func (m *UpdateUserEmailRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserEmailRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserEmailRequest proto.InternalMessageInfo - -func (m *UpdateUserEmailRequest) GetEmail() string { - if m != nil { - return m.Email +func (x *UpdateUserEmailRequest) GetEmail() string { + if x != nil { + return x.Email } return "" } type UserPhone struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Phone string `protobuf:"bytes,2,opt,name=phone,proto3" json:"phone,omitempty"` - IsPhoneVerified bool `protobuf:"varint,3,opt,name=is_phone_verified,json=isPhoneVerified,proto3" json:"is_phone_verified,omitempty"` - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Phone string `protobuf:"bytes,2,opt,name=phone,proto3" json:"phone,omitempty"` + IsPhoneVerified bool `protobuf:"varint,3,opt,name=is_phone_verified,json=isPhoneVerified,proto3" json:"is_phone_verified,omitempty"` + Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserPhone) Reset() { *m = UserPhone{} } -func (m *UserPhone) String() string { return proto.CompactTextString(m) } -func (*UserPhone) ProtoMessage() {} +func (x *UserPhone) Reset() { + *x = UserPhone{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserPhone) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserPhone) ProtoMessage() {} + +func (x *UserPhone) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserPhone.ProtoReflect.Descriptor instead. func (*UserPhone) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{9} + return file_auth_proto_rawDescGZIP(), []int{9} } -func (m *UserPhone) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserPhone.Unmarshal(m, b) -} -func (m *UserPhone) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserPhone.Marshal(b, m, deterministic) -} -func (m *UserPhone) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserPhone.Merge(m, src) -} -func (m *UserPhone) XXX_Size() int { - return xxx_messageInfo_UserPhone.Size(m) -} -func (m *UserPhone) XXX_DiscardUnknown() { - xxx_messageInfo_UserPhone.DiscardUnknown(m) -} - -var xxx_messageInfo_UserPhone proto.InternalMessageInfo - -func (m *UserPhone) GetId() string { - if m != nil { - return m.Id +func (x *UserPhone) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserPhone) GetPhone() string { - if m != nil { - return m.Phone +func (x *UserPhone) GetPhone() string { + if x != nil { + return x.Phone } return "" } -func (m *UserPhone) GetIsPhoneVerified() bool { - if m != nil { - return m.IsPhoneVerified +func (x *UserPhone) GetIsPhoneVerified() bool { + if x != nil { + return x.IsPhoneVerified } return false } -func (m *UserPhone) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserPhone) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserPhone) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserPhone) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserPhone) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserPhone) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type UpdateUserPhoneRequest struct { - Phone string `protobuf:"bytes,1,opt,name=phone,proto3" json:"phone,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Phone string `protobuf:"bytes,1,opt,name=phone,proto3" json:"phone,omitempty"` } -func (m *UpdateUserPhoneRequest) Reset() { *m = UpdateUserPhoneRequest{} } -func (m *UpdateUserPhoneRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserPhoneRequest) ProtoMessage() {} +func (x *UpdateUserPhoneRequest) Reset() { + *x = UpdateUserPhoneRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserPhoneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserPhoneRequest) ProtoMessage() {} + +func (x *UpdateUserPhoneRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserPhoneRequest.ProtoReflect.Descriptor instead. func (*UpdateUserPhoneRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{10} + return file_auth_proto_rawDescGZIP(), []int{10} } -func (m *UpdateUserPhoneRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserPhoneRequest.Unmarshal(m, b) -} -func (m *UpdateUserPhoneRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserPhoneRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserPhoneRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserPhoneRequest.Merge(m, src) -} -func (m *UpdateUserPhoneRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserPhoneRequest.Size(m) -} -func (m *UpdateUserPhoneRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserPhoneRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserPhoneRequest proto.InternalMessageInfo - -func (m *UpdateUserPhoneRequest) GetPhone() string { - if m != nil { - return m.Phone +func (x *UpdateUserPhoneRequest) GetPhone() string { + if x != nil { + return x.Phone } return "" } type VerifyUserPhoneRequest struct { - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyUserPhoneRequest) Reset() { *m = VerifyUserPhoneRequest{} } -func (m *VerifyUserPhoneRequest) String() string { return proto.CompactTextString(m) } -func (*VerifyUserPhoneRequest) ProtoMessage() {} +func (x *VerifyUserPhoneRequest) Reset() { + *x = VerifyUserPhoneRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyUserPhoneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyUserPhoneRequest) ProtoMessage() {} + +func (x *VerifyUserPhoneRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyUserPhoneRequest.ProtoReflect.Descriptor instead. func (*VerifyUserPhoneRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{11} + return file_auth_proto_rawDescGZIP(), []int{11} } -func (m *VerifyUserPhoneRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyUserPhoneRequest.Unmarshal(m, b) -} -func (m *VerifyUserPhoneRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyUserPhoneRequest.Marshal(b, m, deterministic) -} -func (m *VerifyUserPhoneRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyUserPhoneRequest.Merge(m, src) -} -func (m *VerifyUserPhoneRequest) XXX_Size() int { - return xxx_messageInfo_VerifyUserPhoneRequest.Size(m) -} -func (m *VerifyUserPhoneRequest) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyUserPhoneRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyUserPhoneRequest proto.InternalMessageInfo - -func (m *VerifyUserPhoneRequest) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyUserPhoneRequest) GetCode() string { + if x != nil { + return x.Code } return "" } type UserAddress struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Country string `protobuf:"bytes,2,opt,name=country,proto3" json:"country,omitempty"` - Locality string `protobuf:"bytes,3,opt,name=locality,proto3" json:"locality,omitempty"` - PostalCode string `protobuf:"bytes,4,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` - Region string `protobuf:"bytes,5,opt,name=region,proto3" json:"region,omitempty"` - StreetAddress string `protobuf:"bytes,6,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` - Sequence uint64 `protobuf:"varint,7,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,8,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,9,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Country string `protobuf:"bytes,2,opt,name=country,proto3" json:"country,omitempty"` + Locality string `protobuf:"bytes,3,opt,name=locality,proto3" json:"locality,omitempty"` + PostalCode string `protobuf:"bytes,4,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` + Region string `protobuf:"bytes,5,opt,name=region,proto3" json:"region,omitempty"` + StreetAddress string `protobuf:"bytes,6,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` + Sequence uint64 `protobuf:"varint,7,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,8,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,9,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserAddress) Reset() { *m = UserAddress{} } -func (m *UserAddress) String() string { return proto.CompactTextString(m) } -func (*UserAddress) ProtoMessage() {} +func (x *UserAddress) Reset() { + *x = UserAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserAddress) ProtoMessage() {} + +func (x *UserAddress) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserAddress.ProtoReflect.Descriptor instead. func (*UserAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{12} + return file_auth_proto_rawDescGZIP(), []int{12} } -func (m *UserAddress) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserAddress.Unmarshal(m, b) -} -func (m *UserAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserAddress.Marshal(b, m, deterministic) -} -func (m *UserAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserAddress.Merge(m, src) -} -func (m *UserAddress) XXX_Size() int { - return xxx_messageInfo_UserAddress.Size(m) -} -func (m *UserAddress) XXX_DiscardUnknown() { - xxx_messageInfo_UserAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_UserAddress proto.InternalMessageInfo - -func (m *UserAddress) GetId() string { - if m != nil { - return m.Id +func (x *UserAddress) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserAddress) GetCountry() string { - if m != nil { - return m.Country +func (x *UserAddress) GetCountry() string { + if x != nil { + return x.Country } return "" } -func (m *UserAddress) GetLocality() string { - if m != nil { - return m.Locality +func (x *UserAddress) GetLocality() string { + if x != nil { + return x.Locality } return "" } -func (m *UserAddress) GetPostalCode() string { - if m != nil { - return m.PostalCode +func (x *UserAddress) GetPostalCode() string { + if x != nil { + return x.PostalCode } return "" } -func (m *UserAddress) GetRegion() string { - if m != nil { - return m.Region +func (x *UserAddress) GetRegion() string { + if x != nil { + return x.Region } return "" } -func (m *UserAddress) GetStreetAddress() string { - if m != nil { - return m.StreetAddress +func (x *UserAddress) GetStreetAddress() string { + if x != nil { + return x.StreetAddress } return "" } -func (m *UserAddress) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserAddress) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserAddress) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserAddress) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserAddress) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserAddress) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type UpdateUserAddressRequest struct { - Country string `protobuf:"bytes,1,opt,name=country,proto3" json:"country,omitempty"` - Locality string `protobuf:"bytes,2,opt,name=locality,proto3" json:"locality,omitempty"` - PostalCode string `protobuf:"bytes,3,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` - Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` - StreetAddress string `protobuf:"bytes,5,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Country string `protobuf:"bytes,1,opt,name=country,proto3" json:"country,omitempty"` + Locality string `protobuf:"bytes,2,opt,name=locality,proto3" json:"locality,omitempty"` + PostalCode string `protobuf:"bytes,3,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` + Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` + StreetAddress string `protobuf:"bytes,5,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` } -func (m *UpdateUserAddressRequest) Reset() { *m = UpdateUserAddressRequest{} } -func (m *UpdateUserAddressRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserAddressRequest) ProtoMessage() {} +func (x *UpdateUserAddressRequest) Reset() { + *x = UpdateUserAddressRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserAddressRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserAddressRequest) ProtoMessage() {} + +func (x *UpdateUserAddressRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserAddressRequest.ProtoReflect.Descriptor instead. func (*UpdateUserAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{13} + return file_auth_proto_rawDescGZIP(), []int{13} } -func (m *UpdateUserAddressRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserAddressRequest.Unmarshal(m, b) -} -func (m *UpdateUserAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserAddressRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserAddressRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserAddressRequest.Merge(m, src) -} -func (m *UpdateUserAddressRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserAddressRequest.Size(m) -} -func (m *UpdateUserAddressRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserAddressRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserAddressRequest proto.InternalMessageInfo - -func (m *UpdateUserAddressRequest) GetCountry() string { - if m != nil { - return m.Country +func (x *UpdateUserAddressRequest) GetCountry() string { + if x != nil { + return x.Country } return "" } -func (m *UpdateUserAddressRequest) GetLocality() string { - if m != nil { - return m.Locality +func (x *UpdateUserAddressRequest) GetLocality() string { + if x != nil { + return x.Locality } return "" } -func (m *UpdateUserAddressRequest) GetPostalCode() string { - if m != nil { - return m.PostalCode +func (x *UpdateUserAddressRequest) GetPostalCode() string { + if x != nil { + return x.PostalCode } return "" } -func (m *UpdateUserAddressRequest) GetRegion() string { - if m != nil { - return m.Region +func (x *UpdateUserAddressRequest) GetRegion() string { + if x != nil { + return x.Region } return "" } -func (m *UpdateUserAddressRequest) GetStreetAddress() string { - if m != nil { - return m.StreetAddress +func (x *UpdateUserAddressRequest) GetStreetAddress() string { + if x != nil { + return x.StreetAddress } return "" } type PasswordID struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` } -func (m *PasswordID) Reset() { *m = PasswordID{} } -func (m *PasswordID) String() string { return proto.CompactTextString(m) } -func (*PasswordID) ProtoMessage() {} +func (x *PasswordID) Reset() { + *x = PasswordID{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PasswordID) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PasswordID) ProtoMessage() {} + +func (x *PasswordID) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PasswordID.ProtoReflect.Descriptor instead. func (*PasswordID) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{14} + return file_auth_proto_rawDescGZIP(), []int{14} } -func (m *PasswordID) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PasswordID.Unmarshal(m, b) -} -func (m *PasswordID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PasswordID.Marshal(b, m, deterministic) -} -func (m *PasswordID) XXX_Merge(src proto.Message) { - xxx_messageInfo_PasswordID.Merge(m, src) -} -func (m *PasswordID) XXX_Size() int { - return xxx_messageInfo_PasswordID.Size(m) -} -func (m *PasswordID) XXX_DiscardUnknown() { - xxx_messageInfo_PasswordID.DiscardUnknown(m) -} - -var xxx_messageInfo_PasswordID proto.InternalMessageInfo - -func (m *PasswordID) GetId() string { - if m != nil { - return m.Id +func (x *PasswordID) GetId() string { + if x != nil { + return x.Id } return "" } type PasswordRequest struct { - Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` } -func (m *PasswordRequest) Reset() { *m = PasswordRequest{} } -func (m *PasswordRequest) String() string { return proto.CompactTextString(m) } -func (*PasswordRequest) ProtoMessage() {} +func (x *PasswordRequest) Reset() { + *x = PasswordRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PasswordRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PasswordRequest) ProtoMessage() {} + +func (x *PasswordRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PasswordRequest.ProtoReflect.Descriptor instead. func (*PasswordRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{15} + return file_auth_proto_rawDescGZIP(), []int{15} } -func (m *PasswordRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PasswordRequest.Unmarshal(m, b) -} -func (m *PasswordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PasswordRequest.Marshal(b, m, deterministic) -} -func (m *PasswordRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PasswordRequest.Merge(m, src) -} -func (m *PasswordRequest) XXX_Size() int { - return xxx_messageInfo_PasswordRequest.Size(m) -} -func (m *PasswordRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PasswordRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_PasswordRequest proto.InternalMessageInfo - -func (m *PasswordRequest) GetPassword() string { - if m != nil { - return m.Password +func (x *PasswordRequest) GetPassword() string { + if x != nil { + return x.Password } return "" } type PasswordChange struct { - OldPassword string `protobuf:"bytes,1,opt,name=old_password,json=oldPassword,proto3" json:"old_password,omitempty"` - NewPassword string `protobuf:"bytes,2,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OldPassword string `protobuf:"bytes,1,opt,name=old_password,json=oldPassword,proto3" json:"old_password,omitempty"` + NewPassword string `protobuf:"bytes,2,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` } -func (m *PasswordChange) Reset() { *m = PasswordChange{} } -func (m *PasswordChange) String() string { return proto.CompactTextString(m) } -func (*PasswordChange) ProtoMessage() {} +func (x *PasswordChange) Reset() { + *x = PasswordChange{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PasswordChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PasswordChange) ProtoMessage() {} + +func (x *PasswordChange) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PasswordChange.ProtoReflect.Descriptor instead. func (*PasswordChange) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{16} + return file_auth_proto_rawDescGZIP(), []int{16} } -func (m *PasswordChange) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PasswordChange.Unmarshal(m, b) -} -func (m *PasswordChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PasswordChange.Marshal(b, m, deterministic) -} -func (m *PasswordChange) XXX_Merge(src proto.Message) { - xxx_messageInfo_PasswordChange.Merge(m, src) -} -func (m *PasswordChange) XXX_Size() int { - return xxx_messageInfo_PasswordChange.Size(m) -} -func (m *PasswordChange) XXX_DiscardUnknown() { - xxx_messageInfo_PasswordChange.DiscardUnknown(m) -} - -var xxx_messageInfo_PasswordChange proto.InternalMessageInfo - -func (m *PasswordChange) GetOldPassword() string { - if m != nil { - return m.OldPassword +func (x *PasswordChange) GetOldPassword() string { + if x != nil { + return x.OldPassword } return "" } -func (m *PasswordChange) GetNewPassword() string { - if m != nil { - return m.NewPassword +func (x *PasswordChange) GetNewPassword() string { + if x != nil { + return x.NewPassword } return "" } type VerifyMfaOtp struct { - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyMfaOtp) Reset() { *m = VerifyMfaOtp{} } -func (m *VerifyMfaOtp) String() string { return proto.CompactTextString(m) } -func (*VerifyMfaOtp) ProtoMessage() {} +func (x *VerifyMfaOtp) Reset() { + *x = VerifyMfaOtp{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyMfaOtp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyMfaOtp) ProtoMessage() {} + +func (x *VerifyMfaOtp) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyMfaOtp.ProtoReflect.Descriptor instead. func (*VerifyMfaOtp) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{17} + return file_auth_proto_rawDescGZIP(), []int{17} } -func (m *VerifyMfaOtp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyMfaOtp.Unmarshal(m, b) -} -func (m *VerifyMfaOtp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyMfaOtp.Marshal(b, m, deterministic) -} -func (m *VerifyMfaOtp) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyMfaOtp.Merge(m, src) -} -func (m *VerifyMfaOtp) XXX_Size() int { - return xxx_messageInfo_VerifyMfaOtp.Size(m) -} -func (m *VerifyMfaOtp) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyMfaOtp.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyMfaOtp proto.InternalMessageInfo - -func (m *VerifyMfaOtp) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyMfaOtp) GetCode() string { + if x != nil { + return x.Code } return "" } type MultiFactors struct { - Mfas []*MultiFactor `protobuf:"bytes,1,rep,name=mfas,proto3" json:"mfas,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mfas []*MultiFactor `protobuf:"bytes,1,rep,name=mfas,proto3" json:"mfas,omitempty"` } -func (m *MultiFactors) Reset() { *m = MultiFactors{} } -func (m *MultiFactors) String() string { return proto.CompactTextString(m) } -func (*MultiFactors) ProtoMessage() {} +func (x *MultiFactors) Reset() { + *x = MultiFactors{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MultiFactors) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MultiFactors) ProtoMessage() {} + +func (x *MultiFactors) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MultiFactors.ProtoReflect.Descriptor instead. func (*MultiFactors) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{18} + return file_auth_proto_rawDescGZIP(), []int{18} } -func (m *MultiFactors) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MultiFactors.Unmarshal(m, b) -} -func (m *MultiFactors) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MultiFactors.Marshal(b, m, deterministic) -} -func (m *MultiFactors) XXX_Merge(src proto.Message) { - xxx_messageInfo_MultiFactors.Merge(m, src) -} -func (m *MultiFactors) XXX_Size() int { - return xxx_messageInfo_MultiFactors.Size(m) -} -func (m *MultiFactors) XXX_DiscardUnknown() { - xxx_messageInfo_MultiFactors.DiscardUnknown(m) -} - -var xxx_messageInfo_MultiFactors proto.InternalMessageInfo - -func (m *MultiFactors) GetMfas() []*MultiFactor { - if m != nil { - return m.Mfas +func (x *MultiFactors) GetMfas() []*MultiFactor { + if x != nil { + return x.Mfas } return nil } type MultiFactor struct { - Type MfaType `protobuf:"varint,1,opt,name=type,proto3,enum=zitadel.auth.api.v1.MfaType" json:"type,omitempty"` - State MFAState `protobuf:"varint,2,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type MfaType `protobuf:"varint,1,opt,name=type,proto3,enum=zitadel.auth.api.v1.MfaType" json:"type,omitempty"` + State MFAState `protobuf:"varint,2,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` } -func (m *MultiFactor) Reset() { *m = MultiFactor{} } -func (m *MultiFactor) String() string { return proto.CompactTextString(m) } -func (*MultiFactor) ProtoMessage() {} +func (x *MultiFactor) Reset() { + *x = MultiFactor{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MultiFactor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MultiFactor) ProtoMessage() {} + +func (x *MultiFactor) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MultiFactor.ProtoReflect.Descriptor instead. func (*MultiFactor) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{19} + return file_auth_proto_rawDescGZIP(), []int{19} } -func (m *MultiFactor) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MultiFactor.Unmarshal(m, b) -} -func (m *MultiFactor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MultiFactor.Marshal(b, m, deterministic) -} -func (m *MultiFactor) XXX_Merge(src proto.Message) { - xxx_messageInfo_MultiFactor.Merge(m, src) -} -func (m *MultiFactor) XXX_Size() int { - return xxx_messageInfo_MultiFactor.Size(m) -} -func (m *MultiFactor) XXX_DiscardUnknown() { - xxx_messageInfo_MultiFactor.DiscardUnknown(m) -} - -var xxx_messageInfo_MultiFactor proto.InternalMessageInfo - -func (m *MultiFactor) GetType() MfaType { - if m != nil { - return m.Type +func (x *MultiFactor) GetType() MfaType { + if x != nil { + return x.Type } return MfaType_MFATYPE_UNSPECIFIED } -func (m *MultiFactor) GetState() MFAState { - if m != nil { - return m.State +func (x *MultiFactor) GetState() MFAState { + if x != nil { + return x.State } return MFAState_MFASTATE_UNSPECIFIED } type MfaOtpResponse struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - Secret string `protobuf:"bytes,3,opt,name=secret,proto3" json:"secret,omitempty"` - State MFAState `protobuf:"varint,4,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Secret string `protobuf:"bytes,3,opt,name=secret,proto3" json:"secret,omitempty"` + State MFAState `protobuf:"varint,4,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` } -func (m *MfaOtpResponse) Reset() { *m = MfaOtpResponse{} } -func (m *MfaOtpResponse) String() string { return proto.CompactTextString(m) } -func (*MfaOtpResponse) ProtoMessage() {} +func (x *MfaOtpResponse) Reset() { + *x = MfaOtpResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MfaOtpResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MfaOtpResponse) ProtoMessage() {} + +func (x *MfaOtpResponse) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MfaOtpResponse.ProtoReflect.Descriptor instead. func (*MfaOtpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{20} + return file_auth_proto_rawDescGZIP(), []int{20} } -func (m *MfaOtpResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MfaOtpResponse.Unmarshal(m, b) -} -func (m *MfaOtpResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MfaOtpResponse.Marshal(b, m, deterministic) -} -func (m *MfaOtpResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MfaOtpResponse.Merge(m, src) -} -func (m *MfaOtpResponse) XXX_Size() int { - return xxx_messageInfo_MfaOtpResponse.Size(m) -} -func (m *MfaOtpResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MfaOtpResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MfaOtpResponse proto.InternalMessageInfo - -func (m *MfaOtpResponse) GetUserId() string { - if m != nil { - return m.UserId +func (x *MfaOtpResponse) GetUserId() string { + if x != nil { + return x.UserId } return "" } -func (m *MfaOtpResponse) GetUrl() string { - if m != nil { - return m.Url +func (x *MfaOtpResponse) GetUrl() string { + if x != nil { + return x.Url } return "" } -func (m *MfaOtpResponse) GetSecret() string { - if m != nil { - return m.Secret +func (x *MfaOtpResponse) GetSecret() string { + if x != nil { + return x.Secret } return "" } -func (m *MfaOtpResponse) GetState() MFAState { - if m != nil { - return m.State +func (x *MfaOtpResponse) GetState() MFAState { + if x != nil { + return x.State } return MFAState_MFASTATE_UNSPECIFIED } type OIDCClientAuth struct { - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - ClientSecret string `protobuf:"bytes,2,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientSecret string `protobuf:"bytes,2,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` } -func (m *OIDCClientAuth) Reset() { *m = OIDCClientAuth{} } -func (m *OIDCClientAuth) String() string { return proto.CompactTextString(m) } -func (*OIDCClientAuth) ProtoMessage() {} +func (x *OIDCClientAuth) Reset() { + *x = OIDCClientAuth{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OIDCClientAuth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OIDCClientAuth) ProtoMessage() {} + +func (x *OIDCClientAuth) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OIDCClientAuth.ProtoReflect.Descriptor instead. func (*OIDCClientAuth) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{21} + return file_auth_proto_rawDescGZIP(), []int{21} } -func (m *OIDCClientAuth) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OIDCClientAuth.Unmarshal(m, b) -} -func (m *OIDCClientAuth) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OIDCClientAuth.Marshal(b, m, deterministic) -} -func (m *OIDCClientAuth) XXX_Merge(src proto.Message) { - xxx_messageInfo_OIDCClientAuth.Merge(m, src) -} -func (m *OIDCClientAuth) XXX_Size() int { - return xxx_messageInfo_OIDCClientAuth.Size(m) -} -func (m *OIDCClientAuth) XXX_DiscardUnknown() { - xxx_messageInfo_OIDCClientAuth.DiscardUnknown(m) -} - -var xxx_messageInfo_OIDCClientAuth proto.InternalMessageInfo - -func (m *OIDCClientAuth) GetClientId() string { - if m != nil { - return m.ClientId +func (x *OIDCClientAuth) GetClientId() string { + if x != nil { + return x.ClientId } return "" } -func (m *OIDCClientAuth) GetClientSecret() string { - if m != nil { - return m.ClientSecret +func (x *OIDCClientAuth) GetClientSecret() string { + if x != nil { + return x.ClientSecret + } + return "" +} + +type UserGrantSearchRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + SortingColumn UserGrantSearchKey `protobuf:"varint,3,opt,name=sorting_column,json=sortingColumn,proto3,enum=zitadel.auth.api.v1.UserGrantSearchKey" json:"sorting_column,omitempty"` + Asc bool `protobuf:"varint,4,opt,name=asc,proto3" json:"asc,omitempty"` + Queries []*UserGrantSearchQuery `protobuf:"bytes,5,rep,name=queries,proto3" json:"queries,omitempty"` +} + +func (x *UserGrantSearchRequest) Reset() { + *x = UserGrantSearchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantSearchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantSearchRequest) ProtoMessage() {} + +func (x *UserGrantSearchRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantSearchRequest.ProtoReflect.Descriptor instead. +func (*UserGrantSearchRequest) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{22} +} + +func (x *UserGrantSearchRequest) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *UserGrantSearchRequest) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *UserGrantSearchRequest) GetSortingColumn() UserGrantSearchKey { + if x != nil { + return x.SortingColumn + } + return UserGrantSearchKey_UserGrantSearchKey_UNKNOWN +} + +func (x *UserGrantSearchRequest) GetAsc() bool { + if x != nil { + return x.Asc + } + return false +} + +func (x *UserGrantSearchRequest) GetQueries() []*UserGrantSearchQuery { + if x != nil { + return x.Queries + } + return nil +} + +type UserGrantSearchQuery struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key UserGrantSearchKey `protobuf:"varint,1,opt,name=key,proto3,enum=zitadel.auth.api.v1.UserGrantSearchKey" json:"key,omitempty"` + Method SearchMethod `protobuf:"varint,2,opt,name=method,proto3,enum=zitadel.auth.api.v1.SearchMethod" json:"method,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *UserGrantSearchQuery) Reset() { + *x = UserGrantSearchQuery{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantSearchQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantSearchQuery) ProtoMessage() {} + +func (x *UserGrantSearchQuery) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantSearchQuery.ProtoReflect.Descriptor instead. +func (*UserGrantSearchQuery) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{23} +} + +func (x *UserGrantSearchQuery) GetKey() UserGrantSearchKey { + if x != nil { + return x.Key + } + return UserGrantSearchKey_UserGrantSearchKey_UNKNOWN +} + +func (x *UserGrantSearchQuery) GetMethod() SearchMethod { + if x != nil { + return x.Method + } + return SearchMethod_SEARCHMETHOD_EQUALS +} + +func (x *UserGrantSearchQuery) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +type UserGrantSearchResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + TotalResult uint64 `protobuf:"varint,3,opt,name=total_result,json=totalResult,proto3" json:"total_result,omitempty"` + Result []*UserGrantView `protobuf:"bytes,4,rep,name=result,proto3" json:"result,omitempty"` +} + +func (x *UserGrantSearchResponse) Reset() { + *x = UserGrantSearchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantSearchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantSearchResponse) ProtoMessage() {} + +func (x *UserGrantSearchResponse) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantSearchResponse.ProtoReflect.Descriptor instead. +func (*UserGrantSearchResponse) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{24} +} + +func (x *UserGrantSearchResponse) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *UserGrantSearchResponse) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *UserGrantSearchResponse) GetTotalResult() uint64 { + if x != nil { + return x.TotalResult + } + return 0 +} + +func (x *UserGrantSearchResponse) GetResult() []*UserGrantView { + if x != nil { + return x.Result + } + return nil +} + +type UserGrantView struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=OrgId,proto3" json:"OrgId,omitempty"` + ProjectId string `protobuf:"bytes,2,opt,name=ProjectId,proto3" json:"ProjectId,omitempty"` + UserId string `protobuf:"bytes,3,opt,name=UserId,proto3" json:"UserId,omitempty"` + Roles []string `protobuf:"bytes,4,rep,name=Roles,proto3" json:"Roles,omitempty"` + OrgName string `protobuf:"bytes,5,opt,name=OrgName,proto3" json:"OrgName,omitempty"` +} + +func (x *UserGrantView) Reset() { + *x = UserGrantView{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantView) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantView) ProtoMessage() {} + +func (x *UserGrantView) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantView.ProtoReflect.Descriptor instead. +func (*UserGrantView) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{25} +} + +func (x *UserGrantView) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *UserGrantView) GetProjectId() string { + if x != nil { + return x.ProjectId + } + return "" +} + +func (x *UserGrantView) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UserGrantView) GetRoles() []string { + if x != nil { + return x.Roles + } + return nil +} + +func (x *UserGrantView) GetOrgName() string { + if x != nil { + return x.OrgName } return "" } type MyProjectOrgSearchRequest struct { - Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` - Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - Asc bool `protobuf:"varint,4,opt,name=asc,proto3" json:"asc,omitempty"` - Queries []*MyProjectOrgSearchQuery `protobuf:"bytes,5,rep,name=queries,proto3" json:"queries,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + Asc bool `protobuf:"varint,4,opt,name=asc,proto3" json:"asc,omitempty"` + Queries []*MyProjectOrgSearchQuery `protobuf:"bytes,5,rep,name=queries,proto3" json:"queries,omitempty"` } -func (m *MyProjectOrgSearchRequest) Reset() { *m = MyProjectOrgSearchRequest{} } -func (m *MyProjectOrgSearchRequest) String() string { return proto.CompactTextString(m) } -func (*MyProjectOrgSearchRequest) ProtoMessage() {} +func (x *MyProjectOrgSearchRequest) Reset() { + *x = MyProjectOrgSearchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyProjectOrgSearchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyProjectOrgSearchRequest) ProtoMessage() {} + +func (x *MyProjectOrgSearchRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyProjectOrgSearchRequest.ProtoReflect.Descriptor instead. func (*MyProjectOrgSearchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{22} + return file_auth_proto_rawDescGZIP(), []int{26} } -func (m *MyProjectOrgSearchRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyProjectOrgSearchRequest.Unmarshal(m, b) -} -func (m *MyProjectOrgSearchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyProjectOrgSearchRequest.Marshal(b, m, deterministic) -} -func (m *MyProjectOrgSearchRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyProjectOrgSearchRequest.Merge(m, src) -} -func (m *MyProjectOrgSearchRequest) XXX_Size() int { - return xxx_messageInfo_MyProjectOrgSearchRequest.Size(m) -} -func (m *MyProjectOrgSearchRequest) XXX_DiscardUnknown() { - xxx_messageInfo_MyProjectOrgSearchRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_MyProjectOrgSearchRequest proto.InternalMessageInfo - -func (m *MyProjectOrgSearchRequest) GetOffset() uint64 { - if m != nil { - return m.Offset +func (x *MyProjectOrgSearchRequest) GetOffset() uint64 { + if x != nil { + return x.Offset } return 0 } -func (m *MyProjectOrgSearchRequest) GetLimit() uint64 { - if m != nil { - return m.Limit +func (x *MyProjectOrgSearchRequest) GetLimit() uint64 { + if x != nil { + return x.Limit } return 0 } -func (m *MyProjectOrgSearchRequest) GetAsc() bool { - if m != nil { - return m.Asc +func (x *MyProjectOrgSearchRequest) GetAsc() bool { + if x != nil { + return x.Asc } return false } -func (m *MyProjectOrgSearchRequest) GetQueries() []*MyProjectOrgSearchQuery { - if m != nil { - return m.Queries +func (x *MyProjectOrgSearchRequest) GetQueries() []*MyProjectOrgSearchQuery { + if x != nil { + return x.Queries } return nil } type MyProjectOrgSearchQuery struct { - Key MyProjectOrgSearchKey `protobuf:"varint,1,opt,name=key,proto3,enum=zitadel.auth.api.v1.MyProjectOrgSearchKey" json:"key,omitempty"` - Method SearchMethod `protobuf:"varint,2,opt,name=method,proto3,enum=zitadel.auth.api.v1.SearchMethod" json:"method,omitempty"` - Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key MyProjectOrgSearchKey `protobuf:"varint,1,opt,name=key,proto3,enum=zitadel.auth.api.v1.MyProjectOrgSearchKey" json:"key,omitempty"` + Method SearchMethod `protobuf:"varint,2,opt,name=method,proto3,enum=zitadel.auth.api.v1.SearchMethod" json:"method,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` } -func (m *MyProjectOrgSearchQuery) Reset() { *m = MyProjectOrgSearchQuery{} } -func (m *MyProjectOrgSearchQuery) String() string { return proto.CompactTextString(m) } -func (*MyProjectOrgSearchQuery) ProtoMessage() {} +func (x *MyProjectOrgSearchQuery) Reset() { + *x = MyProjectOrgSearchQuery{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyProjectOrgSearchQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyProjectOrgSearchQuery) ProtoMessage() {} + +func (x *MyProjectOrgSearchQuery) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyProjectOrgSearchQuery.ProtoReflect.Descriptor instead. func (*MyProjectOrgSearchQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{23} + return file_auth_proto_rawDescGZIP(), []int{27} } -func (m *MyProjectOrgSearchQuery) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyProjectOrgSearchQuery.Unmarshal(m, b) -} -func (m *MyProjectOrgSearchQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyProjectOrgSearchQuery.Marshal(b, m, deterministic) -} -func (m *MyProjectOrgSearchQuery) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyProjectOrgSearchQuery.Merge(m, src) -} -func (m *MyProjectOrgSearchQuery) XXX_Size() int { - return xxx_messageInfo_MyProjectOrgSearchQuery.Size(m) -} -func (m *MyProjectOrgSearchQuery) XXX_DiscardUnknown() { - xxx_messageInfo_MyProjectOrgSearchQuery.DiscardUnknown(m) -} - -var xxx_messageInfo_MyProjectOrgSearchQuery proto.InternalMessageInfo - -func (m *MyProjectOrgSearchQuery) GetKey() MyProjectOrgSearchKey { - if m != nil { - return m.Key +func (x *MyProjectOrgSearchQuery) GetKey() MyProjectOrgSearchKey { + if x != nil { + return x.Key } return MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_UNSPECIFIED } -func (m *MyProjectOrgSearchQuery) GetMethod() SearchMethod { - if m != nil { - return m.Method +func (x *MyProjectOrgSearchQuery) GetMethod() SearchMethod { + if x != nil { + return x.Method } return SearchMethod_SEARCHMETHOD_EQUALS } -func (m *MyProjectOrgSearchQuery) GetValue() string { - if m != nil { - return m.Value +func (x *MyProjectOrgSearchQuery) GetValue() string { + if x != nil { + return x.Value } return "" } type MyProjectOrgSearchResponse struct { - Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` - Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - TotalResult uint64 `protobuf:"varint,3,opt,name=total_result,json=totalResult,proto3" json:"total_result,omitempty"` - Result []*Org `protobuf:"bytes,4,rep,name=result,proto3" json:"result,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + TotalResult uint64 `protobuf:"varint,3,opt,name=total_result,json=totalResult,proto3" json:"total_result,omitempty"` + Result []*Org `protobuf:"bytes,4,rep,name=result,proto3" json:"result,omitempty"` } -func (m *MyProjectOrgSearchResponse) Reset() { *m = MyProjectOrgSearchResponse{} } -func (m *MyProjectOrgSearchResponse) String() string { return proto.CompactTextString(m) } -func (*MyProjectOrgSearchResponse) ProtoMessage() {} +func (x *MyProjectOrgSearchResponse) Reset() { + *x = MyProjectOrgSearchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyProjectOrgSearchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyProjectOrgSearchResponse) ProtoMessage() {} + +func (x *MyProjectOrgSearchResponse) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyProjectOrgSearchResponse.ProtoReflect.Descriptor instead. func (*MyProjectOrgSearchResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{24} + return file_auth_proto_rawDescGZIP(), []int{28} } -func (m *MyProjectOrgSearchResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyProjectOrgSearchResponse.Unmarshal(m, b) -} -func (m *MyProjectOrgSearchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyProjectOrgSearchResponse.Marshal(b, m, deterministic) -} -func (m *MyProjectOrgSearchResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyProjectOrgSearchResponse.Merge(m, src) -} -func (m *MyProjectOrgSearchResponse) XXX_Size() int { - return xxx_messageInfo_MyProjectOrgSearchResponse.Size(m) -} -func (m *MyProjectOrgSearchResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MyProjectOrgSearchResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MyProjectOrgSearchResponse proto.InternalMessageInfo - -func (m *MyProjectOrgSearchResponse) GetOffset() uint64 { - if m != nil { - return m.Offset +func (x *MyProjectOrgSearchResponse) GetOffset() uint64 { + if x != nil { + return x.Offset } return 0 } -func (m *MyProjectOrgSearchResponse) GetLimit() uint64 { - if m != nil { - return m.Limit +func (x *MyProjectOrgSearchResponse) GetLimit() uint64 { + if x != nil { + return x.Limit } return 0 } -func (m *MyProjectOrgSearchResponse) GetTotalResult() uint64 { - if m != nil { - return m.TotalResult +func (x *MyProjectOrgSearchResponse) GetTotalResult() uint64 { + if x != nil { + return x.TotalResult } return 0 } -func (m *MyProjectOrgSearchResponse) GetResult() []*Org { - if m != nil { - return m.Result +func (x *MyProjectOrgSearchResponse) GetResult() []*Org { + if x != nil { + return x.Result } return nil } -type IsAdminResponse struct { - IsAdmin bool `protobuf:"varint,1,opt,name=is_admin,json=isAdmin,proto3" json:"is_admin,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *IsAdminResponse) Reset() { *m = IsAdminResponse{} } -func (m *IsAdminResponse) String() string { return proto.CompactTextString(m) } -func (*IsAdminResponse) ProtoMessage() {} -func (*IsAdminResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{25} -} - -func (m *IsAdminResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_IsAdminResponse.Unmarshal(m, b) -} -func (m *IsAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_IsAdminResponse.Marshal(b, m, deterministic) -} -func (m *IsAdminResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_IsAdminResponse.Merge(m, src) -} -func (m *IsAdminResponse) XXX_Size() int { - return xxx_messageInfo_IsAdminResponse.Size(m) -} -func (m *IsAdminResponse) XXX_DiscardUnknown() { - xxx_messageInfo_IsAdminResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_IsAdminResponse proto.InternalMessageInfo - -func (m *IsAdminResponse) GetIsAdmin() bool { - if m != nil { - return m.IsAdmin - } - return false -} - type Org struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` } -func (m *Org) Reset() { *m = Org{} } -func (m *Org) String() string { return proto.CompactTextString(m) } -func (*Org) ProtoMessage() {} +func (x *Org) Reset() { + *x = Org{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Org) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Org) ProtoMessage() {} + +func (x *Org) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Org.ProtoReflect.Descriptor instead. func (*Org) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{26} + return file_auth_proto_rawDescGZIP(), []int{29} } -func (m *Org) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Org.Unmarshal(m, b) -} -func (m *Org) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Org.Marshal(b, m, deterministic) -} -func (m *Org) XXX_Merge(src proto.Message) { - xxx_messageInfo_Org.Merge(m, src) -} -func (m *Org) XXX_Size() int { - return xxx_messageInfo_Org.Size(m) -} -func (m *Org) XXX_DiscardUnknown() { - xxx_messageInfo_Org.DiscardUnknown(m) -} - -var xxx_messageInfo_Org proto.InternalMessageInfo - -func (m *Org) GetId() string { - if m != nil { - return m.Id +func (x *Org) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *Org) GetName() string { - if m != nil { - return m.Name +func (x *Org) GetName() string { + if x != nil { + return x.Name } return "" } type MyPermissions struct { - Permissions []string `protobuf:"bytes,1,rep,name=permissions,proto3" json:"permissions,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Permissions []string `protobuf:"bytes,1,rep,name=permissions,proto3" json:"permissions,omitempty"` } -func (m *MyPermissions) Reset() { *m = MyPermissions{} } -func (m *MyPermissions) String() string { return proto.CompactTextString(m) } -func (*MyPermissions) ProtoMessage() {} +func (x *MyPermissions) Reset() { + *x = MyPermissions{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyPermissions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyPermissions) ProtoMessage() {} + +func (x *MyPermissions) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyPermissions.ProtoReflect.Descriptor instead. func (*MyPermissions) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{27} + return file_auth_proto_rawDescGZIP(), []int{30} } -func (m *MyPermissions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyPermissions.Unmarshal(m, b) -} -func (m *MyPermissions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyPermissions.Marshal(b, m, deterministic) -} -func (m *MyPermissions) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyPermissions.Merge(m, src) -} -func (m *MyPermissions) XXX_Size() int { - return xxx_messageInfo_MyPermissions.Size(m) -} -func (m *MyPermissions) XXX_DiscardUnknown() { - xxx_messageInfo_MyPermissions.DiscardUnknown(m) -} - -var xxx_messageInfo_MyPermissions proto.InternalMessageInfo - -func (m *MyPermissions) GetPermissions() []string { - if m != nil { - return m.Permissions +func (x *MyPermissions) GetPermissions() []string { + if x != nil { + return x.Permissions } return nil } -func init() { - proto.RegisterEnum("zitadel.auth.api.v1.UserSessionState", UserSessionState_name, UserSessionState_value) - proto.RegisterEnum("zitadel.auth.api.v1.OIDCResponseType", OIDCResponseType_name, OIDCResponseType_value) - proto.RegisterEnum("zitadel.auth.api.v1.UserState", UserState_name, UserState_value) - proto.RegisterEnum("zitadel.auth.api.v1.Gender", Gender_name, Gender_value) - proto.RegisterEnum("zitadel.auth.api.v1.MfaType", MfaType_name, MfaType_value) - proto.RegisterEnum("zitadel.auth.api.v1.MFAState", MFAState_name, MFAState_value) - proto.RegisterEnum("zitadel.auth.api.v1.MyProjectOrgSearchKey", MyProjectOrgSearchKey_name, MyProjectOrgSearchKey_value) - proto.RegisterEnum("zitadel.auth.api.v1.SearchMethod", SearchMethod_name, SearchMethod_value) - proto.RegisterType((*UserSessionViews)(nil), "zitadel.auth.api.v1.UserSessionViews") - proto.RegisterType((*UserSessionView)(nil), "zitadel.auth.api.v1.UserSessionView") - proto.RegisterType((*User)(nil), "zitadel.auth.api.v1.User") - proto.RegisterType((*UserProfile)(nil), "zitadel.auth.api.v1.UserProfile") - proto.RegisterType((*UpdateUserProfileRequest)(nil), "zitadel.auth.api.v1.UpdateUserProfileRequest") - proto.RegisterType((*UserEmail)(nil), "zitadel.auth.api.v1.UserEmail") - proto.RegisterType((*VerifyMyUserEmailRequest)(nil), "zitadel.auth.api.v1.VerifyMyUserEmailRequest") - proto.RegisterType((*VerifyUserEmailRequest)(nil), "zitadel.auth.api.v1.VerifyUserEmailRequest") - proto.RegisterType((*UpdateUserEmailRequest)(nil), "zitadel.auth.api.v1.UpdateUserEmailRequest") - proto.RegisterType((*UserPhone)(nil), "zitadel.auth.api.v1.UserPhone") - proto.RegisterType((*UpdateUserPhoneRequest)(nil), "zitadel.auth.api.v1.UpdateUserPhoneRequest") - proto.RegisterType((*VerifyUserPhoneRequest)(nil), "zitadel.auth.api.v1.VerifyUserPhoneRequest") - proto.RegisterType((*UserAddress)(nil), "zitadel.auth.api.v1.UserAddress") - proto.RegisterType((*UpdateUserAddressRequest)(nil), "zitadel.auth.api.v1.UpdateUserAddressRequest") - proto.RegisterType((*PasswordID)(nil), "zitadel.auth.api.v1.PasswordID") - proto.RegisterType((*PasswordRequest)(nil), "zitadel.auth.api.v1.PasswordRequest") - proto.RegisterType((*PasswordChange)(nil), "zitadel.auth.api.v1.PasswordChange") - proto.RegisterType((*VerifyMfaOtp)(nil), "zitadel.auth.api.v1.VerifyMfaOtp") - proto.RegisterType((*MultiFactors)(nil), "zitadel.auth.api.v1.MultiFactors") - proto.RegisterType((*MultiFactor)(nil), "zitadel.auth.api.v1.MultiFactor") - proto.RegisterType((*MfaOtpResponse)(nil), "zitadel.auth.api.v1.MfaOtpResponse") - proto.RegisterType((*OIDCClientAuth)(nil), "zitadel.auth.api.v1.OIDCClientAuth") - proto.RegisterType((*MyProjectOrgSearchRequest)(nil), "zitadel.auth.api.v1.MyProjectOrgSearchRequest") - proto.RegisterType((*MyProjectOrgSearchQuery)(nil), "zitadel.auth.api.v1.MyProjectOrgSearchQuery") - proto.RegisterType((*MyProjectOrgSearchResponse)(nil), "zitadel.auth.api.v1.MyProjectOrgSearchResponse") - proto.RegisterType((*IsAdminResponse)(nil), "zitadel.auth.api.v1.IsAdminResponse") - proto.RegisterType((*Org)(nil), "zitadel.auth.api.v1.Org") - proto.RegisterType((*MyPermissions)(nil), "zitadel.auth.api.v1.MyPermissions") +var File_auth_proto protoreflect.FileDescriptor + +var file_auth_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, + 0x2d, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x18, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5d, 0x0a, 0x10, + 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x73, + 0x12, 0x49, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x52, 0x0c, 0x75, + 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xd4, 0x01, 0x0a, 0x0f, + 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x0a, 0x61, 0x75, + 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x22, 0xfe, 0x07, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x7a, 0x69, 0x74, + 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, + 0x74, 0x65, 0x12, 0x43, 0x0a, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x44, 0x61, 0x74, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6c, 0x6f, 0x67, + 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, + 0x45, 0x0a, 0x10, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x2d, 0x0a, 0x12, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x33, + 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x73, 0x5f, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x10, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x69, + 0x73, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x79, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x14, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, + 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x38, 0x0a, + 0x18, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x16, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x22, 0xb4, 0x03, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x6e, 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x12, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x72, 0x65, 0x64, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x67, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x0d, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, + 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x18, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, + 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, + 0x01, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x09, 0x6e, + 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, + 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, + 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x12, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, + 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x11, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x33, + 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x22, 0xf5, 0x01, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x73, 0x45, 0x6d, 0x61, + 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0f, 0x69, 0x73, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, + 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, + 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x0a, 0x18, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, + 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x48, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, + 0x65, 0x22, 0x3a, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, + 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0xf7, 0x01, + 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, + 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, + 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x73, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, + 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1a, 0x0a, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x39, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x14, 0x52, 0x05, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x22, 0x38, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x55, 0x73, 0x65, 0x72, + 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, + 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0xcd, 0x02, 0x0a, + 0x0b, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, + 0x74, 0x72, 0x65, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, + 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, + 0x3b, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0xe2, 0x01, 0x0a, + 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x07, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, + 0x03, 0x18, 0xc8, 0x01, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x24, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, + 0xc8, 0x01, 0x52, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, + 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x12, 0x2f, 0x0a, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, + 0xc8, 0x01, 0x52, 0x0d, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x22, 0x1c, 0x0a, 0x0a, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x49, 0x44, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x38, 0x0a, 0x0f, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x48, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x6c, 0x0a, 0x0e, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x0c, 0x6f, + 0x6c, 0x64, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x48, 0x52, 0x0b, 0x6f, 0x6c, + 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2c, 0x0a, 0x0c, 0x6e, 0x65, 0x77, + 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x48, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x22, 0x0a, 0x0c, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x4d, 0x66, 0x61, 0x4f, 0x74, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x44, 0x0a, 0x0c, 0x4d, + 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x6d, + 0x66, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, + 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x6d, 0x66, 0x61, + 0x73, 0x22, 0x74, 0x0a, 0x0b, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x12, 0x30, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x66, 0x61, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1d, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x46, 0x41, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x0e, 0x4d, 0x66, 0x61, 0x4f, + 0x74, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x33, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x46, 0x41, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x22, 0x52, 0x0a, 0x0e, 0x4f, 0x49, 0x44, 0x43, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x41, 0x75, 0x74, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0xf7, 0x01, 0x0a, 0x16, 0x55, 0x73, 0x65, 0x72, 0x47, + 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, + 0x58, 0x0a, 0x0e, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x20, 0x00, 0x52, 0x0d, 0x73, 0x6f, 0x72, 0x74, + 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x63, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x73, 0x63, 0x12, 0x43, 0x0a, 0x07, 0x71, + 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x22, 0xac, 0x01, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x43, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x20, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, + 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0xa6, 0x01, 0x0a, 0x17, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3a, 0x0a, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x56, 0x69, 0x65, 0x77, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x8b, 0x01, 0x0a, 0x0d, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x56, 0x69, 0x65, 0x77, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x72, + 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x72, 0x67, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, + 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x19, 0x4d, 0x79, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x03, 0x61, 0x73, 0x63, 0x12, 0x46, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x79, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0xb2, 0x01, 0x0a, + 0x17, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x79, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, + 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x20, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x39, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x21, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, + 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x52, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x22, 0x29, 0x0a, 0x03, 0x4f, 0x72, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x31, + 0x0a, 0x0d, 0x4d, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x2a, 0x72, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x55, 0x53, 0x45, 0x52, 0x53, 0x45, 0x53, + 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x53, 0x45, 0x52, 0x53, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x53, 0x45, 0x52, 0x53, 0x45, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, + 0x54, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x71, 0x0a, 0x10, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x49, 0x44, + 0x43, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, + 0x44, 0x45, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x45, 0x53, 0x50, + 0x4f, 0x4e, 0x53, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x54, 0x4f, 0x4b, 0x45, + 0x4e, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x45, 0x53, 0x50, 0x4f, + 0x4e, 0x53, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, + 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x10, 0x02, 0x2a, 0xb0, 0x01, 0x0a, 0x09, 0x55, 0x73, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x45, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, 0x52, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, + 0x12, 0x15, 0x0a, 0x11, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, + 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x53, 0x45, 0x52, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x04, 0x12, 0x15, 0x0a, + 0x11, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x55, 0x53, 0x50, 0x45, + 0x4e, 0x44, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x06, 0x2a, 0x58, 0x0a, 0x06, 0x47, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, + 0x0d, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x46, 0x45, 0x4d, 0x41, 0x4c, 0x45, 0x10, 0x01, + 0x12, 0x0f, 0x0a, 0x0b, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x4d, 0x41, 0x4c, 0x45, 0x10, + 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x56, 0x45, + 0x52, 0x53, 0x45, 0x10, 0x03, 0x2a, 0x44, 0x0a, 0x07, 0x4d, 0x66, 0x61, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x46, 0x41, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x46, 0x41, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4d, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x46, + 0x41, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x54, 0x50, 0x10, 0x02, 0x2a, 0x66, 0x0a, 0x08, 0x4d, + 0x46, 0x41, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x46, 0x41, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x46, 0x41, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, + 0x54, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x46, 0x41, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x12, 0x14, 0x0a, + 0x10, 0x4d, 0x46, 0x41, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, + 0x44, 0x10, 0x03, 0x2a, 0x76, 0x0a, 0x12, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x5f, + 0x4f, 0x52, 0x47, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x55, 0x73, 0x65, 0x72, + 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x5f, 0x50, + 0x52, 0x4f, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x49, 0x44, 0x10, 0x02, 0x2a, 0x62, 0x0a, 0x15, 0x4d, + 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x21, 0x4d, 0x59, 0x50, 0x52, 0x4f, 0x4a, 0x45, 0x43, + 0x54, 0x4f, 0x52, 0x47, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x4d, + 0x59, 0x50, 0x52, 0x4f, 0x4a, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x47, 0x53, 0x45, 0x41, 0x52, 0x43, + 0x48, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x10, 0x01, 0x2a, + 0xd6, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x12, 0x17, 0x0a, 0x13, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, + 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x53, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x41, + 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x53, + 0x5f, 0x57, 0x49, 0x54, 0x48, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x41, 0x52, 0x43, + 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, + 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, + 0x4f, 0x44, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x53, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, + 0x5f, 0x43, 0x41, 0x53, 0x45, 0x10, 0x03, 0x12, 0x28, 0x0a, 0x24, 0x53, 0x45, 0x41, 0x52, 0x43, + 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x53, 0x5f, 0x57, + 0x49, 0x54, 0x48, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x41, 0x53, 0x45, 0x10, + 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, + 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, + 0x45, 0x5f, 0x43, 0x41, 0x53, 0x45, 0x10, 0x05, 0x32, 0xd5, 0x18, 0x0a, 0x0b, 0x41, 0x75, 0x74, + 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x07, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x7a, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x7a, 0x12, 0x47, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x0e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x12, 0x4e, + 0x0a, 0x08, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x11, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x7f, + 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, + 0x77, 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x6d, 0x65, 0x2f, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xb5, 0x18, 0x0f, + 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x7a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2c, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x97, 0x01, 0x0a, 0x13, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x2d, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x1a, 0x11, 0x2f, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x3a, + 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x74, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, + 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, + 0x6d, 0x65, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8f, 0x01, 0x0a, 0x11, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x2d, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x1a, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, + 0x65, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x91, 0x01, + 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x12, 0x2d, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x2f, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x82, 0xb5, + 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x92, 0x01, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x79, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x61, 0x69, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2f, 0x5f, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x64, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x74, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x1e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, + 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8f, 0x01, 0x0a, + 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, + 0x6e, 0x65, 0x12, 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x22, + 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x1a, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, + 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, + 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8f, + 0x01, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1c, 0x22, 0x17, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x2f, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, + 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x92, 0x01, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x79, 0x50, 0x68, 0x6f, + 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2f, 0x5f, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x64, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, + 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x7a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x82, 0xb5, + 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x97, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x2e, 0x7a, 0x69, 0x74, 0x61, + 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x16, 0x1a, 0x11, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x71, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x4d, 0x79, 0x4d, 0x66, 0x61, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x21, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, + 0x6f, 0x72, 0x73, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, 0x66, 0x61, 0x73, 0x82, 0xb5, 0x18, 0x0f, 0x0a, + 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8a, + 0x01, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x12, 0x23, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x1a, 0x1b, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x2f, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x79, 0x0a, 0x09, 0x41, + 0x64, 0x64, 0x4d, 0x66, 0x61, 0x4f, 0x54, 0x50, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x23, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x66, 0x61, 0x4f, 0x74, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, 0x66, 0x61, 0x2f, 0x6f, 0x74, 0x70, + 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x82, 0x01, 0x0a, 0x0c, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x4d, 0x66, 0x61, 0x4f, 0x54, 0x50, 0x12, 0x21, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x4d, 0x66, 0x61, 0x4f, 0x74, 0x70, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x37, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x1a, 0x19, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, 0x66, 0x61, 0x2f, 0x6f, 0x74, 0x70, 0x2f, 0x5f, 0x76, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x6c, 0x0a, 0x0c, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x66, 0x61, 0x4f, 0x54, 0x50, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2c, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, + 0x66, 0x61, 0x2f, 0x6f, 0x74, 0x70, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0xa4, 0x01, 0x0a, 0x11, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x12, + 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x2f, + 0x6d, 0x65, 0x2f, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, + 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x12, 0xb1, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x79, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x73, 0x12, 0x2e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x20, 0x22, 0x1b, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x67, 0x73, 0x2f, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, + 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x12, 0x89, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x5a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x32, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x6d, 0x65, 0x82, 0xb5, 0x18, + 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x42, 0xb7, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x61, 0x6f, 0x73, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x92, 0x41, + 0x88, 0x01, 0x12, 0x3b, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x20, 0x41, 0x50, 0x49, 0x22, 0x2a, + 0x12, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x6f, 0x73, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x2a, + 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x6a, 0x73, 0x6f, 0x6e, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } -func init() { proto.RegisterFile("auth.proto", fileDescriptor_8bbd6f3875b0e874) } +var ( + file_auth_proto_rawDescOnce sync.Once + file_auth_proto_rawDescData = file_auth_proto_rawDesc +) -var fileDescriptor_8bbd6f3875b0e874 = []byte{ - // 2779 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0x4b, 0x6f, 0x1b, 0xd7, - 0x15, 0xf6, 0x90, 0x14, 0x45, 0x1e, 0x4a, 0xd4, 0xe8, 0xca, 0x96, 0x46, 0x0f, 0xdb, 0xf4, 0x38, - 0x46, 0x64, 0xc6, 0x16, 0x13, 0x25, 0x45, 0x63, 0x67, 0x51, 0xd0, 0xe2, 0xc8, 0x66, 0x2d, 0x3e, - 0x32, 0xa4, 0xdd, 0x3a, 0x40, 0xc1, 0x8e, 0x39, 0x57, 0xd4, 0x24, 0x24, 0x67, 0x3c, 0x33, 0x94, - 0xc1, 0x6c, 0x0a, 0x78, 0x95, 0x76, 0x13, 0x34, 0x5d, 0x74, 0xd9, 0x45, 0x77, 0x5d, 0xb5, 0x45, - 0x1f, 0x7f, 0xa1, 0x9b, 0xae, 0xda, 0x5f, 0x50, 0xf4, 0x2f, 0x14, 0x05, 0xb2, 0x28, 0x8a, 0xfb, - 0x18, 0x72, 0x1e, 0x1c, 0x91, 0x82, 0x51, 0xa0, 0x2b, 0xf3, 0x9e, 0xe7, 0x77, 0xcf, 0x39, 0xf7, - 0xcc, 0xbd, 0xc7, 0x02, 0xd0, 0x46, 0xee, 0xd9, 0x81, 0x65, 0x9b, 0xae, 0x89, 0x36, 0xbe, 0x34, - 0x5c, 0x4d, 0xc7, 0xfd, 0x03, 0x4a, 0xd3, 0x2c, 0xe3, 0xe0, 0xfc, 0x83, 0x9d, 0xbd, 0x9e, 0x69, - 0xf6, 0xfa, 0xb8, 0xa4, 0x59, 0x46, 0x49, 0x1b, 0x0e, 0x4d, 0x57, 0x73, 0x0d, 0x73, 0xe8, 0x30, - 0x95, 0x9d, 0x5d, 0xce, 0xa5, 0xab, 0x97, 0xa3, 0xd3, 0x12, 0x1e, 0x58, 0xee, 0x98, 0x33, 0xf7, - 0xc2, 0x4c, 0xc7, 0xb5, 0x47, 0x5d, 0x97, 0x73, 0x6f, 0x86, 0xb9, 0xae, 0x31, 0xc0, 0x8e, 0xab, - 0x0d, 0x2c, 0x2e, 0xb0, 0x75, 0xae, 0xf5, 0x0d, 0x5d, 0x73, 0x71, 0xc9, 0xfb, 0xc1, 0x19, 0xf7, - 0xe8, 0x3f, 0xdd, 0xfb, 0x3d, 0x3c, 0xbc, 0xef, 0xbc, 0xd6, 0x7a, 0x3d, 0x6c, 0x97, 0x4c, 0x8b, - 0xc2, 0x9a, 0x01, 0x51, 0x22, 0xbb, 0x61, 0x6c, 0x4f, 0x8a, 0x71, 0xe4, 0x1f, 0x81, 0xf8, 0xcc, - 0xc1, 0x76, 0x0b, 0x3b, 0x8e, 0x61, 0x0e, 0x9f, 0x1b, 0xf8, 0xb5, 0x83, 0xaa, 0xb0, 0x3a, 0x72, - 0xb0, 0xdd, 0x71, 0x18, 0xd1, 0x91, 0x84, 0x42, 0x72, 0x3f, 0x77, 0xf8, 0xce, 0xc1, 0x8c, 0xd8, - 0x1c, 0x84, 0xb4, 0xd5, 0x95, 0xd1, 0x94, 0xe0, 0xc8, 0x7f, 0x17, 0x60, 0x2d, 0x24, 0x81, 0xf2, - 0x90, 0x30, 0x74, 0x49, 0x28, 0x08, 0xfb, 0x59, 0x35, 0x61, 0xe8, 0x68, 0x1b, 0x32, 0x5a, 0x0f, - 0x0f, 0xdd, 0x8e, 0xa1, 0x4b, 0x09, 0x4a, 0x5d, 0xa6, 0xeb, 0xaa, 0x8e, 0x2a, 0x2c, 0x37, 0x1d, - 0xc7, 0xd5, 0x5c, 0x2c, 0x25, 0x0b, 0xc2, 0x7e, 0xfe, 0xf0, 0xce, 0x3c, 0x18, 0x2d, 0x22, 0xac, - 0x66, 0x09, 0x97, 0xfe, 0x44, 0x5b, 0xb0, 0x4c, 0xf7, 0x63, 0xe8, 0x52, 0x8a, 0xda, 0x4f, 0x93, - 0x65, 0x55, 0x47, 0xbb, 0x90, 0xa5, 0x8c, 0xa1, 0x36, 0xc0, 0xd2, 0x12, 0x65, 0x65, 0x08, 0xa1, - 0xae, 0x0d, 0x30, 0xda, 0x81, 0x8c, 0x83, 0x5f, 0x8d, 0xf0, 0xb0, 0x8b, 0xa5, 0x74, 0x41, 0xd8, - 0x4f, 0xa9, 0x93, 0xb5, 0xfc, 0x9f, 0x65, 0x48, 0x11, 0x8f, 0x91, 0xbd, 0x7c, 0x04, 0x4b, 0x0c, - 0x6b, 0x82, 0x62, 0xbd, 0x11, 0x8f, 0x95, 0x82, 0x64, 0xc2, 0xe8, 0x7b, 0xb0, 0xda, 0xb5, 0x31, - 0xcd, 0x58, 0x47, 0xf7, 0x76, 0x9a, 0x3b, 0xdc, 0x39, 0x60, 0xe5, 0x71, 0xe0, 0x95, 0xc7, 0x41, - 0xdb, 0x2b, 0x0f, 0x75, 0xc5, 0x53, 0xa8, 0x10, 0x03, 0x47, 0xb0, 0xa6, 0x75, 0x5d, 0xe3, 0xdc, - 0x67, 0x22, 0x35, 0xd7, 0x44, 0x7e, 0xaa, 0x42, 0x8d, 0x7c, 0x02, 0xb9, 0xee, 0x99, 0x36, 0xec, - 0x61, 0x66, 0x60, 0x69, 0xae, 0x01, 0x60, 0xe2, 0x54, 0xf9, 0x01, 0x40, 0x5f, 0x73, 0xdc, 0x4e, - 0xdf, 0xec, 0x19, 0x43, 0x1a, 0xaf, 0x8b, 0x75, 0xb3, 0x44, 0xfa, 0x84, 0x08, 0x23, 0x05, 0x44, - 0x4b, 0x73, 0x9c, 0xd7, 0xa6, 0xad, 0x77, 0x98, 0x45, 0x5d, 0x5a, 0x9e, 0x6b, 0x60, 0xcd, 0xd3, - 0x39, 0x62, 0x2a, 0xc1, 0x64, 0x66, 0x42, 0xc9, 0xbc, 0x0e, 0x70, 0x6a, 0xd8, 0x8e, 0xcb, 0xb8, - 0x59, 0xca, 0xcd, 0x52, 0x0a, 0x65, 0xef, 0x02, 0xc5, 0xc3, 0xb8, 0xc0, 0x74, 0x09, 0xc1, 0x63, - 0x0e, 0x8d, 0xee, 0x17, 0x8c, 0x99, 0x63, 0x4c, 0x42, 0xa0, 0xcc, 0x5b, 0xb0, 0xa2, 0x1b, 0x8e, - 0xd5, 0xd7, 0xc6, 0x8c, 0xbf, 0x42, 0xf9, 0x39, 0x4e, 0xa3, 0x22, 0xf7, 0x01, 0x59, 0x36, 0x3e, - 0xc5, 0xb6, 0x8d, 0xf5, 0x4e, 0x5f, 0x1b, 0xf6, 0x46, 0x5a, 0x0f, 0x4b, 0xab, 0x54, 0x70, 0x7d, - 0xc2, 0x39, 0xe1, 0x0c, 0xf4, 0x21, 0xa4, 0x7b, 0x78, 0xa8, 0x63, 0x5b, 0xca, 0xd3, 0x1a, 0xda, - 0x9d, 0x59, 0x43, 0x8f, 0xa9, 0x88, 0xca, 0x45, 0xd1, 0x55, 0x58, 0xc2, 0x03, 0xcd, 0xe8, 0x4b, - 0x6b, 0xd4, 0x2c, 0x5b, 0xa0, 0x22, 0xac, 0x1b, 0x4e, 0x87, 0xfe, 0xee, 0x9c, 0x63, 0xdb, 0x38, - 0x35, 0xb0, 0x2e, 0x89, 0x05, 0x61, 0x3f, 0xa3, 0xae, 0x19, 0x8e, 0x42, 0xe8, 0xcf, 0x39, 0x99, - 0x58, 0xb0, 0xce, 0xcc, 0x21, 0x96, 0xd6, 0x99, 0x05, 0xba, 0xe0, 0x16, 0xe8, 0xef, 0xa9, 0x05, - 0xe4, 0x59, 0x68, 0x12, 0xfa, 0xc4, 0x82, 0x04, 0xcb, 0x5d, 0x73, 0x34, 0x74, 0xed, 0xb1, 0xb4, - 0xc1, 0x8e, 0x31, 0x5f, 0x92, 0xa3, 0xd4, 0x37, 0xbb, 0x5a, 0xdf, 0x70, 0xc7, 0xd2, 0x55, 0x1e, - 0x5d, 0xbe, 0x46, 0x37, 0x21, 0x67, 0x99, 0x8e, 0xab, 0xf5, 0x3b, 0x5d, 0x53, 0xc7, 0xd2, 0x35, - 0xca, 0x06, 0x46, 0x3a, 0x32, 0x75, 0x8c, 0x36, 0x21, 0x6d, 0xe3, 0x9e, 0x61, 0x0e, 0xa5, 0x4d, - 0x76, 0x78, 0xd9, 0x0a, 0xdd, 0x81, 0xbc, 0xe3, 0xda, 0x18, 0xbb, 0x1d, 0x4d, 0xd7, 0x6d, 0xec, - 0x38, 0xd2, 0x16, 0xe5, 0xaf, 0x32, 0x6a, 0x99, 0x11, 0xd1, 0xc7, 0x20, 0x85, 0xaa, 0xab, 0x63, - 0xe3, 0x57, 0x23, 0xc3, 0xc6, 0xba, 0x24, 0xd1, 0x8d, 0x6c, 0x06, 0x2b, 0x49, 0xe5, 0xdc, 0x40, - 0x03, 0xd8, 0x0e, 0x35, 0x80, 0x3f, 0x24, 0x21, 0x47, 0x8e, 0x71, 0xd3, 0x36, 0x4f, 0x8d, 0x3e, - 0x8e, 0xf4, 0x81, 0x40, 0x31, 0x26, 0x2e, 0x2c, 0xc6, 0xe4, 0x85, 0xc5, 0x98, 0xba, 0xa8, 0x18, - 0x97, 0xe6, 0x14, 0x63, 0x7a, 0xd1, 0x62, 0x5c, 0x9e, 0x5f, 0x8c, 0x99, 0xc5, 0x8b, 0xd1, 0x1f, - 0xb8, 0x6c, 0x30, 0x70, 0xd1, 0x56, 0x07, 0x97, 0x6c, 0x75, 0xa1, 0x2e, 0x95, 0xbb, 0x4c, 0x97, - 0x92, 0xff, 0x94, 0x00, 0xe9, 0x99, 0x45, 0x14, 0x7d, 0xc9, 0x23, 0x09, 0xc7, 0x8e, 0x8b, 0xee, - 0x06, 0xd2, 0x42, 0x73, 0xf9, 0x08, 0xbe, 0x7d, 0xb4, 0x6c, 0x2f, 0x89, 0x82, 0xf4, 0x17, 0xc1, - 0x9f, 0xa2, 0x77, 0xfd, 0x29, 0x4a, 0x44, 0x24, 0xa7, 0xe9, 0x7a, 0xd7, 0x9f, 0xae, 0x64, 0x54, - 0x70, 0x92, 0xba, 0xfb, 0xa1, 0xd4, 0xa5, 0x22, 0xb2, 0x81, 0x34, 0x3e, 0x98, 0x99, 0xc6, 0xa5, - 0x88, 0xd2, 0x85, 0x29, 0x4d, 0x2f, 0x9c, 0x52, 0xf9, 0x5f, 0x02, 0x64, 0x49, 0xc8, 0x68, 0xcf, - 0x88, 0x54, 0xfb, 0xa4, 0xfb, 0x24, 0xfc, 0xdd, 0x67, 0x1f, 0xc2, 0x4d, 0x86, 0x46, 0x60, 0x46, - 0xef, 0xf1, 0x17, 0x4c, 0x6a, 0x5e, 0xc1, 0x2c, 0xbd, 0x5d, 0xc1, 0xa4, 0x2f, 0x55, 0x30, 0x0f, - 0x41, 0xa2, 0x28, 0xc7, 0xb5, 0xf1, 0x64, 0xfb, 0x5e, 0xbd, 0xdc, 0x80, 0x14, 0x6d, 0x59, 0xd1, - 0x4a, 0xa1, 0x74, 0xf9, 0x09, 0x6c, 0x32, 0xdd, 0x88, 0x66, 0x38, 0x7e, 0x9e, 0xa5, 0x44, 0x8c, - 0xa5, 0x87, 0xb0, 0x39, 0xad, 0xda, 0x80, 0xa5, 0x82, 0x17, 0xf9, 0x28, 0x08, 0xc6, 0x90, 0xff, - 0xcd, 0x33, 0x47, 0x7b, 0xf5, 0xac, 0xcc, 0xb1, 0xae, 0x9f, 0x98, 0xdb, 0xf5, 0x93, 0xb3, 0xbb, - 0xfe, 0xff, 0x6f, 0xee, 0x1e, 0xf8, 0xa3, 0x46, 0x41, 0x7b, 0x51, 0xbb, 0xe9, 0xed, 0x9a, 0x45, - 0x2d, 0xfb, 0xed, 0xa3, 0xb4, 0x9d, 0x12, 0x05, 0xe9, 0x2a, 0x0f, 0x80, 0xfc, 0xb1, 0x3f, 0x75, - 0x01, 0xd5, 0x79, 0x49, 0xff, 0x6b, 0x82, 0x7d, 0x18, 0xbc, 0xcf, 0x4f, 0x38, 0xe0, 0xbe, 0x8f, - 0x64, 0x22, 0xfe, 0x23, 0x99, 0xbc, 0xf8, 0x23, 0x99, 0xba, 0xe0, 0x23, 0xb9, 0x34, 0xe7, 0x23, - 0x99, 0x9e, 0xf5, 0x91, 0xf4, 0x27, 0x71, 0x79, 0x5e, 0x12, 0x33, 0x6f, 0x97, 0xc4, 0xec, 0xa5, - 0x92, 0xf8, 0x0f, 0xc1, 0xdf, 0xb1, 0x39, 0x5e, 0x2f, 0x19, 0xf2, 0x34, 0x98, 0x2c, 0x1f, 0x99, - 0x6f, 0x1f, 0x2d, 0xd9, 0x49, 0x92, 0x8d, 0x49, 0x58, 0xdf, 0xf1, 0x85, 0x35, 0x11, 0x12, 0x9a, - 0x06, 0xf8, 0x6e, 0x30, 0xc0, 0xc9, 0x90, 0xa0, 0x3f, 0xd4, 0x85, 0x49, 0xa8, 0x53, 0x21, 0x29, - 0x2f, 0xe8, 0xa5, 0x48, 0xd0, 0x97, 0x42, 0x92, 0xc1, 0xf0, 0xcb, 0x7b, 0x00, 0x4d, 0x7e, 0x07, - 0xa9, 0x56, 0xc2, 0x25, 0x23, 0x7f, 0x0c, 0x6b, 0x1e, 0xd7, 0xdb, 0xf8, 0x1d, 0xc8, 0x78, 0x97, - 0x96, 0x70, 0x0d, 0x3f, 0x51, 0x27, 0x2c, 0xb9, 0x0f, 0xf9, 0x66, 0xe0, 0x6e, 0x83, 0xee, 0xc1, - 0x8a, 0xd9, 0xd7, 0x3b, 0xf1, 0xca, 0x39, 0xb3, 0xaf, 0x7b, 0x3a, 0x44, 0x7a, 0x88, 0x5f, 0x4f, - 0xa5, 0x13, 0x11, 0xe9, 0x21, 0x7e, 0xed, 0x49, 0xcb, 0x32, 0xac, 0xf0, 0x5e, 0x79, 0xaa, 0x35, - 0x5c, 0x0b, 0x21, 0xff, 0x51, 0xe1, 0xc7, 0xa3, 0x02, 0x2b, 0xb5, 0x51, 0xdf, 0x35, 0x8e, 0xb5, - 0xae, 0x6b, 0xda, 0x0e, 0xfa, 0x08, 0x52, 0x83, 0x53, 0xcd, 0x7b, 0x61, 0x16, 0x66, 0x7e, 0x8a, - 0x7c, 0x0a, 0x2a, 0x95, 0x96, 0x5d, 0xc8, 0xf9, 0x88, 0xe8, 0x7d, 0x48, 0xb9, 0x63, 0x8b, 0x39, - 0xca, 0x1f, 0xee, 0xcd, 0x36, 0x72, 0xaa, 0xb5, 0xc7, 0x16, 0x56, 0xa9, 0x24, 0xfa, 0x30, 0xf8, - 0x4c, 0xbb, 0x3e, 0x5b, 0xe5, 0xb8, 0xec, 0x7f, 0xa5, 0xc9, 0x5f, 0x09, 0x90, 0x67, 0x5b, 0x53, - 0xb1, 0x63, 0x99, 0x43, 0x27, 0xf0, 0xb2, 0x14, 0x02, 0x2f, 0x4b, 0x11, 0x92, 0x23, 0xdb, 0xfb, - 0x1e, 0x92, 0x9f, 0xe4, 0x84, 0x3a, 0xb8, 0x6b, 0x63, 0x97, 0x1f, 0x6e, 0xbe, 0x9a, 0x42, 0x49, - 0x5d, 0x02, 0x8a, 0x0a, 0xf9, 0x46, 0xb5, 0x72, 0x74, 0xd4, 0x37, 0xf0, 0xd0, 0x2d, 0x8f, 0xdc, - 0x33, 0x72, 0x2f, 0xec, 0xd2, 0xd5, 0x14, 0x4b, 0x86, 0x11, 0xaa, 0x3a, 0xba, 0x0d, 0xab, 0x9c, - 0xc9, 0x21, 0x30, 0x5c, 0x2b, 0x8c, 0xd8, 0xa2, 0x34, 0xf9, 0xd7, 0x02, 0x6c, 0xd7, 0xc6, 0x4d, - 0xdb, 0xfc, 0x1c, 0x77, 0xdd, 0x86, 0xdd, 0x6b, 0x61, 0xcd, 0xee, 0x9e, 0x79, 0x15, 0xb7, 0x09, - 0x69, 0xf3, 0xf4, 0xd4, 0xc1, 0x2e, 0x35, 0x9e, 0x52, 0xf9, 0x8a, 0x7c, 0x40, 0xfa, 0xc6, 0xc0, - 0x60, 0x26, 0x53, 0x2a, 0x5b, 0x90, 0xed, 0x6b, 0x4e, 0x97, 0x6e, 0x29, 0xa3, 0x92, 0x9f, 0xe8, - 0x18, 0x96, 0x5f, 0x8d, 0xb0, 0x6d, 0x60, 0x72, 0x18, 0x48, 0xae, 0xef, 0xcd, 0xde, 0x68, 0x04, - 0xc0, 0xa7, 0x23, 0x6c, 0x8f, 0x55, 0x4f, 0x59, 0xfe, 0xbd, 0x00, 0x5b, 0x31, 0x42, 0xe8, 0x18, - 0x92, 0x5f, 0xe0, 0x31, 0x2f, 0x83, 0xe2, 0x82, 0xf6, 0x9f, 0xe2, 0x31, 0x3d, 0x98, 0x6f, 0x84, - 0x44, 0xe1, 0x8a, 0x4a, 0x0c, 0xa0, 0x07, 0x90, 0x1e, 0x60, 0xf7, 0xcc, 0xd4, 0x79, 0x79, 0xdc, - 0x9a, 0x69, 0x8a, 0xa9, 0xd7, 0xa8, 0xa0, 0xca, 0x15, 0x48, 0x38, 0xce, 0xb5, 0xfe, 0xc8, 0xbb, - 0xd5, 0xb3, 0x85, 0xfc, 0x2b, 0x01, 0x76, 0x66, 0x85, 0x96, 0x57, 0xd1, 0xe5, 0x62, 0x7b, 0x0b, - 0x56, 0x5c, 0x93, 0x74, 0x2a, 0x1b, 0x3b, 0xa3, 0x3e, 0x2b, 0xa7, 0x94, 0x9a, 0xa3, 0x34, 0x95, - 0x92, 0xd0, 0xfb, 0xa4, 0x45, 0x51, 0x66, 0x8a, 0xc6, 0x5a, 0x9a, 0xb9, 0x81, 0x86, 0xdd, 0x53, - 0xb9, 0x9c, 0x7c, 0x0f, 0xd6, 0xaa, 0x4e, 0x59, 0x1f, 0x18, 0xc3, 0x09, 0xaa, 0x6d, 0xc8, 0x18, - 0x4e, 0x47, 0x23, 0x34, 0x8a, 0x2b, 0xa3, 0x2e, 0x1b, 0x4c, 0x44, 0xbe, 0x0b, 0xc9, 0x86, 0xdd, - 0x8b, 0x7c, 0xdb, 0x10, 0xa4, 0x7c, 0xef, 0x1d, 0xfa, 0x5b, 0xfe, 0x00, 0x56, 0x6b, 0xe3, 0x26, - 0xb6, 0x07, 0x06, 0x9b, 0x08, 0xa1, 0x02, 0xe4, 0xac, 0xe9, 0x92, 0x1e, 0xfc, 0xac, 0xea, 0x27, - 0x15, 0xed, 0xc0, 0x48, 0x8a, 0x8d, 0x70, 0x0a, 0xb0, 0xf7, 0xac, 0xa5, 0xa8, 0x2d, 0xa5, 0xd5, - 0xaa, 0x36, 0xea, 0xad, 0x76, 0xb9, 0xad, 0x74, 0x9e, 0xd5, 0x5b, 0x4d, 0xe5, 0xa8, 0x7a, 0x5c, - 0x55, 0x2a, 0xe2, 0x15, 0xb4, 0x0b, 0x5b, 0x11, 0x89, 0xf2, 0x51, 0xbb, 0xfa, 0x5c, 0x11, 0x05, - 0x74, 0x13, 0x76, 0x23, 0xcc, 0xb6, 0xa2, 0xd6, 0xaa, 0xf5, 0x72, 0x5b, 0xa9, 0x88, 0x89, 0xe2, - 0x2b, 0x10, 0xc9, 0x81, 0xf2, 0x36, 0x4f, 0x5a, 0x05, 0xda, 0x86, 0x6b, 0x94, 0xa6, 0xb4, 0x9a, - 0x8d, 0x7a, 0x4b, 0x69, 0xbf, 0x68, 0x2a, 0x9d, 0xa3, 0x46, 0x45, 0x11, 0xaf, 0xa0, 0xeb, 0xb0, - 0x1d, 0x61, 0x55, 0x2b, 0x9d, 0x76, 0xe3, 0xa9, 0x52, 0x17, 0x05, 0x74, 0x1b, 0x6e, 0xc6, 0xb2, - 0xb9, 0x50, 0xa2, 0xf8, 0x5b, 0x7e, 0x31, 0x63, 0x1b, 0xdc, 0x81, 0x4d, 0x8a, 0xd0, 0xbf, 0x33, - 0x85, 0x6f, 0xed, 0x2a, 0x88, 0x53, 0xde, 0x64, 0x4f, 0x9b, 0x80, 0xa6, 0xd4, 0x6a, 0x9d, 0xd3, - 0x13, 0xe8, 0x1a, 0xac, 0x4f, 0xe9, 0x15, 0xe5, 0x44, 0x21, 0x3b, 0x4c, 0x06, 0x8d, 0x9c, 0x34, - 0x8e, 0x9e, 0x2a, 0x15, 0x31, 0x15, 0x14, 0x6e, 0x3d, 0x6b, 0x35, 0x95, 0x7a, 0x45, 0x5c, 0x0a, - 0x92, 0xab, 0xf5, 0x6a, 0xbb, 0x5a, 0x3e, 0x11, 0xd3, 0xc5, 0x1f, 0x42, 0x9a, 0xbd, 0x0b, 0x88, - 0xf3, 0xc7, 0x4a, 0xbd, 0xa2, 0xa8, 0xa1, 0x2c, 0xac, 0xc3, 0x2a, 0xa7, 0x1f, 0x2b, 0xb5, 0xf2, - 0x09, 0xc1, 0xb9, 0x06, 0x39, 0x4e, 0xa2, 0x84, 0x04, 0x42, 0x90, 0xe7, 0x84, 0x4a, 0xf5, 0x39, - 0x49, 0x8a, 0x98, 0x2c, 0x56, 0x60, 0x99, 0x77, 0x68, 0xb4, 0x05, 0x1b, 0xb5, 0xe3, 0x32, 0x8d, - 0x59, 0xd0, 0xf6, 0x1a, 0xe4, 0x3c, 0x46, 0xab, 0xd6, 0x62, 0x96, 0x3d, 0x42, 0xa3, 0xdd, 0x14, - 0x13, 0xc5, 0x53, 0xc8, 0x78, 0x9d, 0x12, 0x49, 0x70, 0x95, 0xfc, 0x9e, 0x51, 0x29, 0x9b, 0x80, - 0x26, 0x9c, 0x7a, 0xa3, 0xdd, 0x51, 0x95, 0x72, 0xe5, 0x85, 0x28, 0x10, 0x5c, 0x13, 0x3a, 0xa3, - 0x25, 0x48, 0xd4, 0x7c, 0xb4, 0x5a, 0xe3, 0x39, 0x89, 0x65, 0xf1, 0x25, 0x5c, 0x9b, 0xd9, 0x48, - 0xd0, 0x1d, 0xb8, 0x55, 0x7b, 0xd1, 0x54, 0x1b, 0xdf, 0x57, 0x8e, 0xda, 0x0d, 0xf5, 0x71, 0x4b, - 0x29, 0xab, 0x47, 0x4f, 0x9e, 0x2a, 0x2f, 0x42, 0x08, 0x64, 0xb8, 0x31, 0x5b, 0xac, 0xa1, 0x3e, - 0xee, 0xd4, 0xcb, 0x35, 0x45, 0x14, 0x8a, 0x3f, 0x86, 0x15, 0x7f, 0x87, 0x21, 0x61, 0x61, 0x72, - 0x35, 0xa5, 0xfd, 0xa4, 0x51, 0xe9, 0x28, 0x9f, 0x3e, 0x2b, 0x9f, 0xb4, 0xc4, 0x2b, 0x68, 0x0f, - 0xa4, 0x00, 0xa3, 0xd5, 0x2e, 0xab, 0xed, 0x56, 0xe7, 0x07, 0xd5, 0xf6, 0x13, 0x51, 0x20, 0x45, - 0x1c, 0xe0, 0x1e, 0x35, 0xea, 0xed, 0x72, 0xb5, 0xde, 0x12, 0x13, 0x87, 0xbf, 0x91, 0x20, 0x47, - 0xbe, 0x1d, 0x2d, 0x6c, 0x9f, 0x1b, 0x5d, 0x8c, 0x9e, 0xc2, 0xf2, 0x13, 0xac, 0xf5, 0xdd, 0xb3, - 0x2f, 0xd1, 0x66, 0xe4, 0x76, 0xa6, 0x0c, 0x2c, 0x77, 0xbc, 0x13, 0x43, 0x97, 0xc5, 0x37, 0x7f, - 0xfb, 0xe7, 0x2f, 0x12, 0x80, 0x32, 0xa5, 0x33, 0x6e, 0xe1, 0x31, 0x2c, 0xa9, 0x58, 0xd3, 0xc7, - 0x97, 0x36, 0x95, 0xa7, 0xa6, 0x32, 0x28, 0x5d, 0xb2, 0xa9, 0x7e, 0x1d, 0x32, 0xcf, 0xf9, 0xe8, - 0x3b, 0xd6, 0xd6, 0x56, 0x84, 0xde, 0xa2, 0x53, 0x76, 0x79, 0x9d, 0x1a, 0xcb, 0xa1, 0xec, 0x64, - 0x7c, 0x8e, 0x7e, 0x02, 0xeb, 0x8f, 0xb1, 0xcb, 0x9e, 0x73, 0xde, 0x98, 0x3a, 0xd6, 0xf0, 0x9d, - 0x45, 0x46, 0xde, 0x8e, 0xfc, 0xde, 0x9b, 0x3f, 0x4a, 0x6b, 0xb0, 0x4a, 0x64, 0xf0, 0xd0, 0x35, - 0xba, 0x9a, 0x8b, 0x75, 0xea, 0x19, 0x21, 0xb1, 0x34, 0xc0, 0x25, 0x72, 0x29, 0xf0, 0x86, 0xe9, - 0xe8, 0x4b, 0x10, 0x27, 0x00, 0xbc, 0xf1, 0x51, 0x9c, 0xff, 0x42, 0xac, 0x7f, 0xae, 0x29, 0xdf, - 0x8b, 0x73, 0xbd, 0x81, 0xd6, 0x99, 0x5f, 0x02, 0xc0, 0xe2, 0x7e, 0x7e, 0x29, 0xc0, 0x06, 0xbb, - 0x4d, 0x07, 0xfd, 0xdf, 0x9f, 0xed, 0x27, 0x66, 0x52, 0xb2, 0x00, 0xac, 0x52, 0x1c, 0xac, 0xcd, - 0x9d, 0x28, 0xac, 0x87, 0x42, 0x11, 0xb9, 0x90, 0x9f, 0x44, 0x85, 0x0d, 0x19, 0xe2, 0x62, 0x12, - 0x3f, 0x53, 0xa7, 0x7a, 0x72, 0x31, 0xce, 0xf5, 0x3a, 0x5a, 0x9b, 0xba, 0x66, 0x23, 0x8a, 0xaf, - 0x05, 0x58, 0x67, 0x37, 0x63, 0xbf, 0xe7, 0xf7, 0xe6, 0x44, 0xc3, 0xff, 0x02, 0x9f, 0x0b, 0xe7, - 0x7e, 0x1c, 0x9c, 0xab, 0x3b, 0x61, 0x38, 0x24, 0x0e, 0x3f, 0x17, 0x60, 0x3d, 0x32, 0x71, 0x88, - 0xc9, 0x4f, 0xdc, 0x64, 0x22, 0xf6, 0x6c, 0x7d, 0x27, 0x0e, 0xcb, 0x9e, 0xbc, 0x15, 0xc2, 0x52, - 0x62, 0x0f, 0xff, 0x31, 0xc1, 0xf4, 0x8d, 0x00, 0xd7, 0x55, 0xec, 0xe0, 0xa1, 0x5e, 0x1b, 0xfb, - 0x06, 0x37, 0x5d, 0xfa, 0xc4, 0xab, 0x5d, 0x94, 0xab, 0x38, 0x20, 0xe5, 0x38, 0x20, 0xfb, 0xf2, - 0xed, 0x08, 0x10, 0x9b, 0xba, 0x3e, 0xf7, 0xf9, 0x0c, 0x17, 0x0c, 0x9b, 0x6d, 0x5c, 0xbe, 0x60, - 0xa8, 0xde, 0x82, 0x05, 0xc3, 0x26, 0x23, 0xe1, 0x82, 0x61, 0x9e, 0xe7, 0x15, 0x8c, 0x7f, 0x82, - 0x30, 0x17, 0xce, 0x62, 0x05, 0x43, 0xe1, 0x90, 0x38, 0x7c, 0x1d, 0x2a, 0x98, 0x8b, 0x10, 0xcd, - 0x9e, 0x69, 0xbc, 0x65, 0xb9, 0x50, 0x24, 0x71, 0xe5, 0xe2, 0x9b, 0x15, 0xb1, 0xd4, 0xb1, 0x69, - 0xc5, 0xff, 0xa4, 0x5c, 0x38, 0x90, 0xd9, 0xe5, 0xe2, 0xef, 0xba, 0xde, 0xd4, 0xe3, 0xf2, 0x5d, - 0xd7, 0x7b, 0xb0, 0x2f, 0xd6, 0x75, 0xf9, 0xeb, 0x3f, 0xd2, 0x75, 0x3d, 0xff, 0xf3, 0xba, 0x6e, - 0x70, 0xda, 0xb1, 0x00, 0xac, 0xc5, 0xba, 0x2e, 0x87, 0x45, 0xa2, 0xf2, 0x0a, 0xb2, 0x34, 0x2a, - 0xb5, 0x53, 0x2d, 0x3e, 0x1c, 0xb7, 0xe6, 0xbd, 0xca, 0x1d, 0xf9, 0x6e, 0x9c, 0x63, 0x11, 0xe5, - 0xa7, 0x8e, 0xc9, 0xdb, 0x1d, 0xfd, 0x4c, 0x00, 0xd1, 0x3b, 0x41, 0x93, 0x41, 0xc3, 0xed, 0x99, - 0x2e, 0x82, 0xb3, 0x8b, 0xd8, 0xea, 0x78, 0x10, 0xe7, 0xbc, 0xb0, 0xb3, 0xeb, 0xab, 0x0e, 0x6e, - 0xcc, 0x29, 0xf1, 0xff, 0x06, 0x22, 0xfb, 0x1f, 0x43, 0xb6, 0xac, 0xeb, 0xe4, 0x51, 0xdf, 0x6e, - 0xc6, 0xee, 0xff, 0x76, 0xdc, 0x40, 0xc1, 0x37, 0x09, 0xb8, 0x20, 0xf4, 0xf2, 0x7a, 0x20, 0x02, - 0x25, 0xd3, 0xb5, 0x88, 0xeb, 0x37, 0x82, 0x7f, 0x5c, 0xd2, 0x6e, 0xa2, 0x5b, 0x17, 0xf5, 0x78, - 0xea, 0x2c, 0x36, 0x02, 0xdf, 0x8d, 0x73, 0x7e, 0x63, 0x67, 0x3b, 0xe2, 0xdc, 0x7f, 0x54, 0xfb, - 0xb0, 0xa2, 0xe2, 0x81, 0x79, 0x8e, 0xe7, 0x84, 0x20, 0xce, 0x71, 0xfc, 0x39, 0x28, 0x46, 0x77, - 0x8d, 0x7e, 0x27, 0xc0, 0x06, 0xbf, 0xd3, 0xfa, 0x6e, 0xcf, 0x0e, 0x3a, 0x58, 0xf0, 0xa9, 0xee, - 0x1d, 0x84, 0xd2, 0xc2, 0xf2, 0x3c, 0x39, 0xf1, 0x15, 0x22, 0xef, 0x96, 0x7a, 0x7d, 0xf3, 0xa5, - 0xd6, 0x27, 0x77, 0x11, 0xa2, 0x6c, 0xda, 0x3d, 0xa7, 0xd4, 0x71, 0xa8, 0x3e, 0xeb, 0x1b, 0x50, - 0x75, 0xaa, 0xda, 0x80, 0x3e, 0x7c, 0x63, 0xe3, 0x33, 0xfb, 0x4f, 0x23, 0x42, 0x2f, 0x6a, 0xf9, - 0x20, 0x0e, 0xc6, 0x35, 0xb4, 0xe1, 0xc1, 0xe8, 0x18, 0x8e, 0xa1, 0x0d, 0xe8, 0xab, 0x1b, 0xfd, - 0x54, 0x80, 0x2d, 0x7a, 0x3c, 0x3f, 0x63, 0xc6, 0xfd, 0xcf, 0xe8, 0x38, 0x24, 0x72, 0x5c, 0x6c, - 0xa6, 0xba, 0xf2, 0x61, 0x1c, 0x8e, 0x6d, 0xb4, 0x55, 0xf2, 0xbd, 0xc4, 0x4b, 0xdc, 0x54, 0x69, - 0x80, 0x1f, 0xfd, 0x59, 0xf8, 0xa6, 0xfc, 0x95, 0x80, 0x3e, 0x81, 0x0c, 0x79, 0x32, 0x14, 0xca, - 0xcd, 0xaa, 0x5c, 0x44, 0xfb, 0x67, 0xae, 0x6b, 0x39, 0x0f, 0x4b, 0xa5, 0x9e, 0xe1, 0x9e, 0x8d, - 0x5e, 0x1e, 0x74, 0xcd, 0x41, 0xa9, 0xab, 0x99, 0x53, 0x45, 0xeb, 0x8b, 0x5e, 0x89, 0xb8, 0x39, - 0x4c, 0xbe, 0x7f, 0xf0, 0x41, 0x51, 0x48, 0x1c, 0x8a, 0x9a, 0x65, 0xf5, 0x79, 0x5b, 0x2e, 0x7d, - 0xee, 0x98, 0xc3, 0x20, 0xa5, 0x67, 0x5b, 0xdd, 0x87, 0x11, 0x99, 0x87, 0x11, 0x99, 0xcf, 0xee, - 0xce, 0xf3, 0x48, 0xff, 0x56, 0x87, 0x88, 0xbe, 0x4c, 0xd3, 0x08, 0x7d, 0xf8, 0xdf, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x64, 0x6c, 0xef, 0xe7, 0xe6, 0x23, 0x00, 0x00, +func file_auth_proto_rawDescGZIP() []byte { + file_auth_proto_rawDescOnce.Do(func() { + file_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_auth_proto_rawDescData) + }) + return file_auth_proto_rawDescData +} + +var file_auth_proto_enumTypes = make([]protoimpl.EnumInfo, 9) +var file_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 31) +var file_auth_proto_goTypes = []interface{}{ + (UserSessionState)(0), // 0: zitadel.auth.api.v1.UserSessionState + (OIDCResponseType)(0), // 1: zitadel.auth.api.v1.OIDCResponseType + (UserState)(0), // 2: zitadel.auth.api.v1.UserState + (Gender)(0), // 3: zitadel.auth.api.v1.Gender + (MfaType)(0), // 4: zitadel.auth.api.v1.MfaType + (MFAState)(0), // 5: zitadel.auth.api.v1.MFAState + (UserGrantSearchKey)(0), // 6: zitadel.auth.api.v1.UserGrantSearchKey + (MyProjectOrgSearchKey)(0), // 7: zitadel.auth.api.v1.MyProjectOrgSearchKey + (SearchMethod)(0), // 8: zitadel.auth.api.v1.SearchMethod + (*UserSessionViews)(nil), // 9: zitadel.auth.api.v1.UserSessionViews + (*UserSessionView)(nil), // 10: zitadel.auth.api.v1.UserSessionView + (*User)(nil), // 11: zitadel.auth.api.v1.User + (*UserProfile)(nil), // 12: zitadel.auth.api.v1.UserProfile + (*UpdateUserProfileRequest)(nil), // 13: zitadel.auth.api.v1.UpdateUserProfileRequest + (*UserEmail)(nil), // 14: zitadel.auth.api.v1.UserEmail + (*VerifyMyUserEmailRequest)(nil), // 15: zitadel.auth.api.v1.VerifyMyUserEmailRequest + (*VerifyUserEmailRequest)(nil), // 16: zitadel.auth.api.v1.VerifyUserEmailRequest + (*UpdateUserEmailRequest)(nil), // 17: zitadel.auth.api.v1.UpdateUserEmailRequest + (*UserPhone)(nil), // 18: zitadel.auth.api.v1.UserPhone + (*UpdateUserPhoneRequest)(nil), // 19: zitadel.auth.api.v1.UpdateUserPhoneRequest + (*VerifyUserPhoneRequest)(nil), // 20: zitadel.auth.api.v1.VerifyUserPhoneRequest + (*UserAddress)(nil), // 21: zitadel.auth.api.v1.UserAddress + (*UpdateUserAddressRequest)(nil), // 22: zitadel.auth.api.v1.UpdateUserAddressRequest + (*PasswordID)(nil), // 23: zitadel.auth.api.v1.PasswordID + (*PasswordRequest)(nil), // 24: zitadel.auth.api.v1.PasswordRequest + (*PasswordChange)(nil), // 25: zitadel.auth.api.v1.PasswordChange + (*VerifyMfaOtp)(nil), // 26: zitadel.auth.api.v1.VerifyMfaOtp + (*MultiFactors)(nil), // 27: zitadel.auth.api.v1.MultiFactors + (*MultiFactor)(nil), // 28: zitadel.auth.api.v1.MultiFactor + (*MfaOtpResponse)(nil), // 29: zitadel.auth.api.v1.MfaOtpResponse + (*OIDCClientAuth)(nil), // 30: zitadel.auth.api.v1.OIDCClientAuth + (*UserGrantSearchRequest)(nil), // 31: zitadel.auth.api.v1.UserGrantSearchRequest + (*UserGrantSearchQuery)(nil), // 32: zitadel.auth.api.v1.UserGrantSearchQuery + (*UserGrantSearchResponse)(nil), // 33: zitadel.auth.api.v1.UserGrantSearchResponse + (*UserGrantView)(nil), // 34: zitadel.auth.api.v1.UserGrantView + (*MyProjectOrgSearchRequest)(nil), // 35: zitadel.auth.api.v1.MyProjectOrgSearchRequest + (*MyProjectOrgSearchQuery)(nil), // 36: zitadel.auth.api.v1.MyProjectOrgSearchQuery + (*MyProjectOrgSearchResponse)(nil), // 37: zitadel.auth.api.v1.MyProjectOrgSearchResponse + (*Org)(nil), // 38: zitadel.auth.api.v1.Org + (*MyPermissions)(nil), // 39: zitadel.auth.api.v1.MyPermissions + (*timestamp.Timestamp)(nil), // 40: google.protobuf.Timestamp + (*empty.Empty)(nil), // 41: google.protobuf.Empty + (*_struct.Struct)(nil), // 42: google.protobuf.Struct +} +var file_auth_proto_depIdxs = []int32{ + 10, // 0: zitadel.auth.api.v1.UserSessionViews.user_sessions:type_name -> zitadel.auth.api.v1.UserSessionView + 0, // 1: zitadel.auth.api.v1.UserSessionView.auth_state:type_name -> zitadel.auth.api.v1.UserSessionState + 2, // 2: zitadel.auth.api.v1.User.state:type_name -> zitadel.auth.api.v1.UserState + 40, // 3: zitadel.auth.api.v1.User.creation_date:type_name -> google.protobuf.Timestamp + 40, // 4: zitadel.auth.api.v1.User.activation_date:type_name -> google.protobuf.Timestamp + 40, // 5: zitadel.auth.api.v1.User.change_date:type_name -> google.protobuf.Timestamp + 40, // 6: zitadel.auth.api.v1.User.last_login:type_name -> google.protobuf.Timestamp + 40, // 7: zitadel.auth.api.v1.User.password_changed:type_name -> google.protobuf.Timestamp + 3, // 8: zitadel.auth.api.v1.User.gender:type_name -> zitadel.auth.api.v1.Gender + 3, // 9: zitadel.auth.api.v1.UserProfile.gender:type_name -> zitadel.auth.api.v1.Gender + 40, // 10: zitadel.auth.api.v1.UserProfile.creation_date:type_name -> google.protobuf.Timestamp + 40, // 11: zitadel.auth.api.v1.UserProfile.change_date:type_name -> google.protobuf.Timestamp + 3, // 12: zitadel.auth.api.v1.UpdateUserProfileRequest.gender:type_name -> zitadel.auth.api.v1.Gender + 40, // 13: zitadel.auth.api.v1.UserEmail.creation_date:type_name -> google.protobuf.Timestamp + 40, // 14: zitadel.auth.api.v1.UserEmail.change_date:type_name -> google.protobuf.Timestamp + 40, // 15: zitadel.auth.api.v1.UserPhone.creation_date:type_name -> google.protobuf.Timestamp + 40, // 16: zitadel.auth.api.v1.UserPhone.change_date:type_name -> google.protobuf.Timestamp + 40, // 17: zitadel.auth.api.v1.UserAddress.creation_date:type_name -> google.protobuf.Timestamp + 40, // 18: zitadel.auth.api.v1.UserAddress.change_date:type_name -> google.protobuf.Timestamp + 28, // 19: zitadel.auth.api.v1.MultiFactors.mfas:type_name -> zitadel.auth.api.v1.MultiFactor + 4, // 20: zitadel.auth.api.v1.MultiFactor.type:type_name -> zitadel.auth.api.v1.MfaType + 5, // 21: zitadel.auth.api.v1.MultiFactor.state:type_name -> zitadel.auth.api.v1.MFAState + 5, // 22: zitadel.auth.api.v1.MfaOtpResponse.state:type_name -> zitadel.auth.api.v1.MFAState + 6, // 23: zitadel.auth.api.v1.UserGrantSearchRequest.sorting_column:type_name -> zitadel.auth.api.v1.UserGrantSearchKey + 32, // 24: zitadel.auth.api.v1.UserGrantSearchRequest.queries:type_name -> zitadel.auth.api.v1.UserGrantSearchQuery + 6, // 25: zitadel.auth.api.v1.UserGrantSearchQuery.key:type_name -> zitadel.auth.api.v1.UserGrantSearchKey + 8, // 26: zitadel.auth.api.v1.UserGrantSearchQuery.method:type_name -> zitadel.auth.api.v1.SearchMethod + 34, // 27: zitadel.auth.api.v1.UserGrantSearchResponse.result:type_name -> zitadel.auth.api.v1.UserGrantView + 36, // 28: zitadel.auth.api.v1.MyProjectOrgSearchRequest.queries:type_name -> zitadel.auth.api.v1.MyProjectOrgSearchQuery + 7, // 29: zitadel.auth.api.v1.MyProjectOrgSearchQuery.key:type_name -> zitadel.auth.api.v1.MyProjectOrgSearchKey + 8, // 30: zitadel.auth.api.v1.MyProjectOrgSearchQuery.method:type_name -> zitadel.auth.api.v1.SearchMethod + 38, // 31: zitadel.auth.api.v1.MyProjectOrgSearchResponse.result:type_name -> zitadel.auth.api.v1.Org + 41, // 32: zitadel.auth.api.v1.AuthService.Healthz:input_type -> google.protobuf.Empty + 41, // 33: zitadel.auth.api.v1.AuthService.Ready:input_type -> google.protobuf.Empty + 41, // 34: zitadel.auth.api.v1.AuthService.Validate:input_type -> google.protobuf.Empty + 41, // 35: zitadel.auth.api.v1.AuthService.GetMyUserSessions:input_type -> google.protobuf.Empty + 41, // 36: zitadel.auth.api.v1.AuthService.GetMyUserProfile:input_type -> google.protobuf.Empty + 13, // 37: zitadel.auth.api.v1.AuthService.UpdateMyUserProfile:input_type -> zitadel.auth.api.v1.UpdateUserProfileRequest + 41, // 38: zitadel.auth.api.v1.AuthService.GetMyUserEmail:input_type -> google.protobuf.Empty + 17, // 39: zitadel.auth.api.v1.AuthService.ChangeMyUserEmail:input_type -> zitadel.auth.api.v1.UpdateUserEmailRequest + 15, // 40: zitadel.auth.api.v1.AuthService.VerifyMyUserEmail:input_type -> zitadel.auth.api.v1.VerifyMyUserEmailRequest + 41, // 41: zitadel.auth.api.v1.AuthService.ResendMyEmailVerificationMail:input_type -> google.protobuf.Empty + 41, // 42: zitadel.auth.api.v1.AuthService.GetMyUserPhone:input_type -> google.protobuf.Empty + 19, // 43: zitadel.auth.api.v1.AuthService.ChangeMyUserPhone:input_type -> zitadel.auth.api.v1.UpdateUserPhoneRequest + 20, // 44: zitadel.auth.api.v1.AuthService.VerifyMyUserPhone:input_type -> zitadel.auth.api.v1.VerifyUserPhoneRequest + 41, // 45: zitadel.auth.api.v1.AuthService.ResendMyPhoneVerificationCode:input_type -> google.protobuf.Empty + 41, // 46: zitadel.auth.api.v1.AuthService.GetMyUserAddress:input_type -> google.protobuf.Empty + 22, // 47: zitadel.auth.api.v1.AuthService.UpdateMyUserAddress:input_type -> zitadel.auth.api.v1.UpdateUserAddressRequest + 41, // 48: zitadel.auth.api.v1.AuthService.GetMyMfas:input_type -> google.protobuf.Empty + 25, // 49: zitadel.auth.api.v1.AuthService.ChangeMyPassword:input_type -> zitadel.auth.api.v1.PasswordChange + 41, // 50: zitadel.auth.api.v1.AuthService.AddMfaOTP:input_type -> google.protobuf.Empty + 26, // 51: zitadel.auth.api.v1.AuthService.VerifyMfaOTP:input_type -> zitadel.auth.api.v1.VerifyMfaOtp + 41, // 52: zitadel.auth.api.v1.AuthService.RemoveMfaOTP:input_type -> google.protobuf.Empty + 31, // 53: zitadel.auth.api.v1.AuthService.SearchMyUserGrant:input_type -> zitadel.auth.api.v1.UserGrantSearchRequest + 35, // 54: zitadel.auth.api.v1.AuthService.SearchMyProjectOrgs:input_type -> zitadel.auth.api.v1.MyProjectOrgSearchRequest + 41, // 55: zitadel.auth.api.v1.AuthService.GetMyZitadelPermissions:input_type -> google.protobuf.Empty + 41, // 56: zitadel.auth.api.v1.AuthService.Healthz:output_type -> google.protobuf.Empty + 41, // 57: zitadel.auth.api.v1.AuthService.Ready:output_type -> google.protobuf.Empty + 42, // 58: zitadel.auth.api.v1.AuthService.Validate:output_type -> google.protobuf.Struct + 9, // 59: zitadel.auth.api.v1.AuthService.GetMyUserSessions:output_type -> zitadel.auth.api.v1.UserSessionViews + 12, // 60: zitadel.auth.api.v1.AuthService.GetMyUserProfile:output_type -> zitadel.auth.api.v1.UserProfile + 12, // 61: zitadel.auth.api.v1.AuthService.UpdateMyUserProfile:output_type -> zitadel.auth.api.v1.UserProfile + 14, // 62: zitadel.auth.api.v1.AuthService.GetMyUserEmail:output_type -> zitadel.auth.api.v1.UserEmail + 14, // 63: zitadel.auth.api.v1.AuthService.ChangeMyUserEmail:output_type -> zitadel.auth.api.v1.UserEmail + 41, // 64: zitadel.auth.api.v1.AuthService.VerifyMyUserEmail:output_type -> google.protobuf.Empty + 41, // 65: zitadel.auth.api.v1.AuthService.ResendMyEmailVerificationMail:output_type -> google.protobuf.Empty + 18, // 66: zitadel.auth.api.v1.AuthService.GetMyUserPhone:output_type -> zitadel.auth.api.v1.UserPhone + 18, // 67: zitadel.auth.api.v1.AuthService.ChangeMyUserPhone:output_type -> zitadel.auth.api.v1.UserPhone + 41, // 68: zitadel.auth.api.v1.AuthService.VerifyMyUserPhone:output_type -> google.protobuf.Empty + 41, // 69: zitadel.auth.api.v1.AuthService.ResendMyPhoneVerificationCode:output_type -> google.protobuf.Empty + 21, // 70: zitadel.auth.api.v1.AuthService.GetMyUserAddress:output_type -> zitadel.auth.api.v1.UserAddress + 21, // 71: zitadel.auth.api.v1.AuthService.UpdateMyUserAddress:output_type -> zitadel.auth.api.v1.UserAddress + 27, // 72: zitadel.auth.api.v1.AuthService.GetMyMfas:output_type -> zitadel.auth.api.v1.MultiFactors + 41, // 73: zitadel.auth.api.v1.AuthService.ChangeMyPassword:output_type -> google.protobuf.Empty + 29, // 74: zitadel.auth.api.v1.AuthService.AddMfaOTP:output_type -> zitadel.auth.api.v1.MfaOtpResponse + 41, // 75: zitadel.auth.api.v1.AuthService.VerifyMfaOTP:output_type -> google.protobuf.Empty + 41, // 76: zitadel.auth.api.v1.AuthService.RemoveMfaOTP:output_type -> google.protobuf.Empty + 33, // 77: zitadel.auth.api.v1.AuthService.SearchMyUserGrant:output_type -> zitadel.auth.api.v1.UserGrantSearchResponse + 37, // 78: zitadel.auth.api.v1.AuthService.SearchMyProjectOrgs:output_type -> zitadel.auth.api.v1.MyProjectOrgSearchResponse + 39, // 79: zitadel.auth.api.v1.AuthService.GetMyZitadelPermissions:output_type -> zitadel.auth.api.v1.MyPermissions + 56, // [56:80] is the sub-list for method output_type + 32, // [32:56] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name +} + +func init() { file_auth_proto_init() } +func file_auth_proto_init() { + if File_auth_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_auth_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserSessionViews); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserSessionView); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserProfile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserProfileRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserEmail); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyMyUserEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyUserEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserPhone); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserPhoneRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyUserPhoneRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserAddressRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PasswordID); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PasswordRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PasswordChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyMfaOtp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MultiFactors); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MultiFactor); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MfaOtpResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OIDCClientAuth); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantSearchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantSearchQuery); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantSearchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantView); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyProjectOrgSearchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyProjectOrgSearchQuery); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyProjectOrgSearchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Org); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyPermissions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_auth_proto_rawDesc, + NumEnums: 9, + NumMessages: 31, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_auth_proto_goTypes, + DependencyIndexes: file_auth_proto_depIdxs, + EnumInfos: file_auth_proto_enumTypes, + MessageInfos: file_auth_proto_msgTypes, + }.Build() + File_auth_proto = out.File + file_auth_proto_rawDesc = nil + file_auth_proto_goTypes = nil + file_auth_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. @@ -2275,8 +3944,8 @@ type AuthServiceClient interface { AddMfaOTP(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*MfaOtpResponse, error) VerifyMfaOTP(ctx context.Context, in *VerifyMfaOtp, opts ...grpc.CallOption) (*empty.Empty, error) RemoveMfaOTP(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) + SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest, opts ...grpc.CallOption) (*UserGrantSearchResponse, error) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest, opts ...grpc.CallOption) (*MyProjectOrgSearchResponse, error) - IsIamAdmin(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*IsAdminResponse, error) //Permission GetMyZitadelPermissions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*MyPermissions, error) } @@ -2478,18 +4147,18 @@ func (c *authServiceClient) RemoveMfaOTP(ctx context.Context, in *empty.Empty, o return out, nil } -func (c *authServiceClient) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest, opts ...grpc.CallOption) (*MyProjectOrgSearchResponse, error) { - out := new(MyProjectOrgSearchResponse) - err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs", in, out, opts...) +func (c *authServiceClient) SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest, opts ...grpc.CallOption) (*UserGrantSearchResponse, error) { + out := new(UserGrantSearchResponse) + err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/SearchMyUserGrant", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *authServiceClient) IsIamAdmin(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*IsAdminResponse, error) { - out := new(IsAdminResponse) - err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/IsIamAdmin", in, out, opts...) +func (c *authServiceClient) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest, opts ...grpc.CallOption) (*MyProjectOrgSearchResponse, error) { + out := new(MyProjectOrgSearchResponse) + err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs", in, out, opts...) if err != nil { return nil, err } @@ -2533,8 +4202,8 @@ type AuthServiceServer interface { AddMfaOTP(context.Context, *empty.Empty) (*MfaOtpResponse, error) VerifyMfaOTP(context.Context, *VerifyMfaOtp) (*empty.Empty, error) RemoveMfaOTP(context.Context, *empty.Empty) (*empty.Empty, error) + SearchMyUserGrant(context.Context, *UserGrantSearchRequest) (*UserGrantSearchResponse, error) SearchMyProjectOrgs(context.Context, *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) - IsIamAdmin(context.Context, *empty.Empty) (*IsAdminResponse, error) //Permission GetMyZitadelPermissions(context.Context, *empty.Empty) (*MyPermissions, error) } @@ -2543,76 +4212,76 @@ type AuthServiceServer interface { type UnimplementedAuthServiceServer struct { } -func (*UnimplementedAuthServiceServer) Healthz(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) Healthz(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Healthz not implemented") } -func (*UnimplementedAuthServiceServer) Ready(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) Ready(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Ready not implemented") } -func (*UnimplementedAuthServiceServer) Validate(ctx context.Context, req *empty.Empty) (*_struct.Struct, error) { +func (*UnimplementedAuthServiceServer) Validate(context.Context, *empty.Empty) (*_struct.Struct, error) { return nil, status.Errorf(codes.Unimplemented, "method Validate not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserSessions(ctx context.Context, req *empty.Empty) (*UserSessionViews, error) { +func (*UnimplementedAuthServiceServer) GetMyUserSessions(context.Context, *empty.Empty) (*UserSessionViews, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserSessions not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserProfile(ctx context.Context, req *empty.Empty) (*UserProfile, error) { +func (*UnimplementedAuthServiceServer) GetMyUserProfile(context.Context, *empty.Empty) (*UserProfile, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserProfile not implemented") } -func (*UnimplementedAuthServiceServer) UpdateMyUserProfile(ctx context.Context, req *UpdateUserProfileRequest) (*UserProfile, error) { +func (*UnimplementedAuthServiceServer) UpdateMyUserProfile(context.Context, *UpdateUserProfileRequest) (*UserProfile, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateMyUserProfile not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserEmail(ctx context.Context, req *empty.Empty) (*UserEmail, error) { +func (*UnimplementedAuthServiceServer) GetMyUserEmail(context.Context, *empty.Empty) (*UserEmail, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserEmail not implemented") } -func (*UnimplementedAuthServiceServer) ChangeMyUserEmail(ctx context.Context, req *UpdateUserEmailRequest) (*UserEmail, error) { +func (*UnimplementedAuthServiceServer) ChangeMyUserEmail(context.Context, *UpdateUserEmailRequest) (*UserEmail, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeMyUserEmail not implemented") } -func (*UnimplementedAuthServiceServer) VerifyMyUserEmail(ctx context.Context, req *VerifyMyUserEmailRequest) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) VerifyMyUserEmail(context.Context, *VerifyMyUserEmailRequest) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method VerifyMyUserEmail not implemented") } -func (*UnimplementedAuthServiceServer) ResendMyEmailVerificationMail(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) ResendMyEmailVerificationMail(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ResendMyEmailVerificationMail not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserPhone(ctx context.Context, req *empty.Empty) (*UserPhone, error) { +func (*UnimplementedAuthServiceServer) GetMyUserPhone(context.Context, *empty.Empty) (*UserPhone, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserPhone not implemented") } -func (*UnimplementedAuthServiceServer) ChangeMyUserPhone(ctx context.Context, req *UpdateUserPhoneRequest) (*UserPhone, error) { +func (*UnimplementedAuthServiceServer) ChangeMyUserPhone(context.Context, *UpdateUserPhoneRequest) (*UserPhone, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeMyUserPhone not implemented") } -func (*UnimplementedAuthServiceServer) VerifyMyUserPhone(ctx context.Context, req *VerifyUserPhoneRequest) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) VerifyMyUserPhone(context.Context, *VerifyUserPhoneRequest) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method VerifyMyUserPhone not implemented") } -func (*UnimplementedAuthServiceServer) ResendMyPhoneVerificationCode(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) ResendMyPhoneVerificationCode(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ResendMyPhoneVerificationCode not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserAddress(ctx context.Context, req *empty.Empty) (*UserAddress, error) { +func (*UnimplementedAuthServiceServer) GetMyUserAddress(context.Context, *empty.Empty) (*UserAddress, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserAddress not implemented") } -func (*UnimplementedAuthServiceServer) UpdateMyUserAddress(ctx context.Context, req *UpdateUserAddressRequest) (*UserAddress, error) { +func (*UnimplementedAuthServiceServer) UpdateMyUserAddress(context.Context, *UpdateUserAddressRequest) (*UserAddress, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateMyUserAddress not implemented") } -func (*UnimplementedAuthServiceServer) GetMyMfas(ctx context.Context, req *empty.Empty) (*MultiFactors, error) { +func (*UnimplementedAuthServiceServer) GetMyMfas(context.Context, *empty.Empty) (*MultiFactors, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyMfas not implemented") } -func (*UnimplementedAuthServiceServer) ChangeMyPassword(ctx context.Context, req *PasswordChange) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) ChangeMyPassword(context.Context, *PasswordChange) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeMyPassword not implemented") } -func (*UnimplementedAuthServiceServer) AddMfaOTP(ctx context.Context, req *empty.Empty) (*MfaOtpResponse, error) { +func (*UnimplementedAuthServiceServer) AddMfaOTP(context.Context, *empty.Empty) (*MfaOtpResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddMfaOTP not implemented") } -func (*UnimplementedAuthServiceServer) VerifyMfaOTP(ctx context.Context, req *VerifyMfaOtp) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) VerifyMfaOTP(context.Context, *VerifyMfaOtp) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method VerifyMfaOTP not implemented") } -func (*UnimplementedAuthServiceServer) RemoveMfaOTP(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) RemoveMfaOTP(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method RemoveMfaOTP not implemented") } -func (*UnimplementedAuthServiceServer) SearchMyProjectOrgs(ctx context.Context, req *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { +func (*UnimplementedAuthServiceServer) SearchMyUserGrant(context.Context, *UserGrantSearchRequest) (*UserGrantSearchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchMyUserGrant not implemented") +} +func (*UnimplementedAuthServiceServer) SearchMyProjectOrgs(context.Context, *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SearchMyProjectOrgs not implemented") } -func (*UnimplementedAuthServiceServer) IsIamAdmin(ctx context.Context, req *empty.Empty) (*IsAdminResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method IsIamAdmin not implemented") -} -func (*UnimplementedAuthServiceServer) GetMyZitadelPermissions(ctx context.Context, req *empty.Empty) (*MyPermissions, error) { +func (*UnimplementedAuthServiceServer) GetMyZitadelPermissions(context.Context, *empty.Empty) (*MyPermissions, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyZitadelPermissions not implemented") } @@ -2998,6 +4667,24 @@ func _AuthService_RemoveMfaOTP_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _AuthService_SearchMyUserGrant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserGrantSearchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SearchMyUserGrant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zitadel.auth.api.v1.AuthService/SearchMyUserGrant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SearchMyUserGrant(ctx, req.(*UserGrantSearchRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AuthService_SearchMyProjectOrgs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MyProjectOrgSearchRequest) if err := dec(in); err != nil { @@ -3016,24 +4703,6 @@ func _AuthService_SearchMyProjectOrgs_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } -func _AuthService_IsIamAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AuthServiceServer).IsIamAdmin(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/zitadel.auth.api.v1.AuthService/IsIamAdmin", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AuthServiceServer).IsIamAdmin(ctx, req.(*empty.Empty)) - } - return interceptor(ctx, in, info, handler) -} - func _AuthService_GetMyZitadelPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(empty.Empty) if err := dec(in); err != nil { @@ -3141,12 +4810,12 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ Handler: _AuthService_RemoveMfaOTP_Handler, }, { - MethodName: "SearchMyProjectOrgs", - Handler: _AuthService_SearchMyProjectOrgs_Handler, + MethodName: "SearchMyUserGrant", + Handler: _AuthService_SearchMyUserGrant_Handler, }, { - MethodName: "IsIamAdmin", - Handler: _AuthService_IsIamAdmin_Handler, + MethodName: "SearchMyProjectOrgs", + Handler: _AuthService_SearchMyProjectOrgs_Handler, }, { MethodName: "GetMyZitadelPermissions", diff --git a/pkg/auth/api/grpc/auth.pb.gw.go b/pkg/auth/api/grpc/auth.pb.gw.go index b5ff7ac015..76e3b6a304 100644 --- a/pkg/auth/api/grpc/auth.pb.gw.go +++ b/pkg/auth/api/grpc/auth.pb.gw.go @@ -38,15 +38,6 @@ func request_AuthService_Healthz_0(ctx context.Context, marshaler runtime.Marsha } -func local_request_AuthService_Healthz_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.Healthz(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -56,15 +47,6 @@ func request_AuthService_Ready_0(ctx context.Context, marshaler runtime.Marshale } -func local_request_AuthService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.Ready(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -74,15 +56,6 @@ func request_AuthService_Validate_0(ctx context.Context, marshaler runtime.Marsh } -func local_request_AuthService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.Validate(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserSessions_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -92,15 +65,6 @@ func request_AuthService_GetMyUserSessions_0(ctx context.Context, marshaler runt } -func local_request_AuthService_GetMyUserSessions_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserSessions(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -110,15 +74,6 @@ func request_AuthService_GetMyUserProfile_0(ctx context.Context, marshaler runti } -func local_request_AuthService_GetMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserProfile(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_UpdateMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserProfileRequest var metadata runtime.ServerMetadata @@ -136,23 +91,6 @@ func request_AuthService_UpdateMyUserProfile_0(ctx context.Context, marshaler ru } -func local_request_AuthService_UpdateMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserProfileRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.UpdateMyUserProfile(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -162,15 +100,6 @@ func request_AuthService_GetMyUserEmail_0(ctx context.Context, marshaler runtime } -func local_request_AuthService_GetMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserEmail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ChangeMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserEmailRequest var metadata runtime.ServerMetadata @@ -188,23 +117,6 @@ func request_AuthService_ChangeMyUserEmail_0(ctx context.Context, marshaler runt } -func local_request_AuthService_ChangeMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserEmailRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ChangeMyUserEmail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_VerifyMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq VerifyMyUserEmailRequest var metadata runtime.ServerMetadata @@ -222,23 +134,6 @@ func request_AuthService_VerifyMyUserEmail_0(ctx context.Context, marshaler runt } -func local_request_AuthService_VerifyMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifyMyUserEmailRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.VerifyMyUserEmail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ResendMyEmailVerificationMail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -256,23 +151,6 @@ func request_AuthService_ResendMyEmailVerificationMail_0(ctx context.Context, ma } -func local_request_AuthService_ResendMyEmailVerificationMail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ResendMyEmailVerificationMail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -282,15 +160,6 @@ func request_AuthService_GetMyUserPhone_0(ctx context.Context, marshaler runtime } -func local_request_AuthService_GetMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserPhone(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ChangeMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserPhoneRequest var metadata runtime.ServerMetadata @@ -308,23 +177,6 @@ func request_AuthService_ChangeMyUserPhone_0(ctx context.Context, marshaler runt } -func local_request_AuthService_ChangeMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserPhoneRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ChangeMyUserPhone(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_VerifyMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq VerifyUserPhoneRequest var metadata runtime.ServerMetadata @@ -342,23 +194,6 @@ func request_AuthService_VerifyMyUserPhone_0(ctx context.Context, marshaler runt } -func local_request_AuthService_VerifyMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifyUserPhoneRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.VerifyMyUserPhone(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ResendMyPhoneVerificationCode_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -376,23 +211,6 @@ func request_AuthService_ResendMyPhoneVerificationCode_0(ctx context.Context, ma } -func local_request_AuthService_ResendMyPhoneVerificationCode_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ResendMyPhoneVerificationCode(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -402,15 +220,6 @@ func request_AuthService_GetMyUserAddress_0(ctx context.Context, marshaler runti } -func local_request_AuthService_GetMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserAddress(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_UpdateMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserAddressRequest var metadata runtime.ServerMetadata @@ -428,23 +237,6 @@ func request_AuthService_UpdateMyUserAddress_0(ctx context.Context, marshaler ru } -func local_request_AuthService_UpdateMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserAddressRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.UpdateMyUserAddress(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyMfas_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -454,15 +246,6 @@ func request_AuthService_GetMyMfas_0(ctx context.Context, marshaler runtime.Mars } -func local_request_AuthService_GetMyMfas_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyMfas(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ChangeMyPassword_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq PasswordChange var metadata runtime.ServerMetadata @@ -480,23 +263,6 @@ func request_AuthService_ChangeMyPassword_0(ctx context.Context, marshaler runti } -func local_request_AuthService_ChangeMyPassword_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq PasswordChange - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ChangeMyPassword(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_AddMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -514,23 +280,6 @@ func request_AuthService_AddMfaOTP_0(ctx context.Context, marshaler runtime.Mars } -func local_request_AuthService_AddMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.AddMfaOTP(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq VerifyMfaOtp var metadata runtime.ServerMetadata @@ -548,8 +297,17 @@ func request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler runtime.M } -func local_request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifyMfaOtp +func request_AuthService_RemoveMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.RemoveMfaOTP(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_AuthService_SearchMyUserGrant_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UserGrantSearchRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -560,25 +318,7 @@ func local_request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler run return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.VerifyMfaOTP(ctx, &protoReq) - return msg, metadata, err - -} - -func request_AuthService_RemoveMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.RemoveMfaOTP(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_AuthService_RemoveMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.RemoveMfaOTP(ctx, &protoReq) + msg, err := client.SearchMyUserGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -600,41 +340,6 @@ func request_AuthService_SearchMyProjectOrgs_0(ctx context.Context, marshaler ru } -func local_request_AuthService_SearchMyProjectOrgs_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MyProjectOrgSearchRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.SearchMyProjectOrgs(ctx, &protoReq) - return msg, metadata, err - -} - -func request_AuthService_IsIamAdmin_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.IsIamAdmin(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_AuthService_IsIamAdmin_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.IsIamAdmin(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyZitadelPermissions_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -644,503 +349,6 @@ func request_AuthService_GetMyZitadelPermissions_0(ctx context.Context, marshale } -func local_request_AuthService_GetMyZitadelPermissions_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyZitadelPermissions(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterAuthServiceHandlerServer registers the http handlers for service AuthService to "mux". -// UnaryRPC :call AuthServiceServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthServiceServer, opts []grpc.DialOption) error { - - mux.Handle("GET", pattern_AuthService_Healthz_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_Healthz_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_Healthz_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_Ready_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_Ready_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_Ready_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_Validate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_Validate_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_Validate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserSessions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserSessions_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserSessions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserProfile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserProfile_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserProfile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_UpdateMyUserProfile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_UpdateMyUserProfile_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_UpdateMyUserProfile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserEmail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserEmail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_ChangeMyUserEmail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ChangeMyUserEmail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ChangeMyUserEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_VerifyMyUserEmail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_VerifyMyUserEmail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_VerifyMyUserEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_ResendMyEmailVerificationMail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ResendMyEmailVerificationMail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ResendMyEmailVerificationMail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserPhone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserPhone_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserPhone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_ChangeMyUserPhone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ChangeMyUserPhone_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ChangeMyUserPhone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_VerifyMyUserPhone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_VerifyMyUserPhone_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_VerifyMyUserPhone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_ResendMyPhoneVerificationCode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ResendMyPhoneVerificationCode_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ResendMyPhoneVerificationCode_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserAddress_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_UpdateMyUserAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_UpdateMyUserAddress_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_UpdateMyUserAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyMfas_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyMfas_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyMfas_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_ChangeMyPassword_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ChangeMyPassword_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ChangeMyPassword_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_AddMfaOTP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_AddMfaOTP_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_AddMfaOTP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_VerifyMfaOTP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_VerifyMfaOTP_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_VerifyMfaOTP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("DELETE", pattern_AuthService_RemoveMfaOTP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_RemoveMfaOTP_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_RemoveMfaOTP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_SearchMyProjectOrgs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_SearchMyProjectOrgs_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_SearchMyProjectOrgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_IsIamAdmin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_IsIamAdmin_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_IsIamAdmin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyZitadelPermissions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyZitadelPermissions_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyZitadelPermissions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - // RegisterAuthServiceHandlerFromEndpoint is same as RegisterAuthServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterAuthServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -1599,6 +807,26 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_AuthService_SearchMyUserGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_SearchMyUserGrant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_SearchMyUserGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_AuthService_SearchMyProjectOrgs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1619,26 +847,6 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("GET", pattern_AuthService_IsIamAdmin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_AuthService_IsIamAdmin_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_IsIamAdmin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_AuthService_GetMyZitadelPermissions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1663,53 +871,53 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } var ( - pattern_AuthService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "")) - pattern_AuthService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "")) - pattern_AuthService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "")) - pattern_AuthService_GetMyUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"me", "usersessions"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"me", "usersessions"}, "")) - pattern_AuthService_GetMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "")) - pattern_AuthService_UpdateMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_UpdateMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "")) - pattern_AuthService_GetMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "")) - pattern_AuthService_ChangeMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ChangeMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "")) - pattern_AuthService_VerifyMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_verify"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_VerifyMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_verify"}, "")) - pattern_AuthService_ResendMyEmailVerificationMail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_resendverification"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ResendMyEmailVerificationMail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_resendverification"}, "")) - pattern_AuthService_GetMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "")) - pattern_AuthService_ChangeMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ChangeMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "")) - pattern_AuthService_VerifyMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_verify"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_VerifyMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_verify"}, "")) - pattern_AuthService_ResendMyPhoneVerificationCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_resendverification"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ResendMyPhoneVerificationCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_resendverification"}, "")) - pattern_AuthService_GetMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "")) - pattern_AuthService_UpdateMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_UpdateMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "")) - pattern_AuthService_GetMyMfas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "mfas"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyMfas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "mfas"}, "")) - pattern_AuthService_ChangeMyPassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "passwords", "_change"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ChangeMyPassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "passwords", "_change"}, "")) - pattern_AuthService_AddMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_AddMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "")) - pattern_AuthService_VerifyMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"users", "me", "mfa", "otp", "_verify"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_VerifyMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"users", "me", "mfa", "otp", "_verify"}, "")) - pattern_AuthService_RemoveMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_RemoveMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "")) - pattern_AuthService_SearchMyProjectOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"global", "projectorgs", "_search"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_SearchMyUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"usergrants", "me", "_search"}, "")) - pattern_AuthService_IsIamAdmin_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"global", "_isiamadmin"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_SearchMyProjectOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"global", "projectorgs", "_search"}, "")) - pattern_AuthService_GetMyZitadelPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"permissions", "zitadel", "me"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyZitadelPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"permissions", "zitadel", "me"}, "")) ) var ( @@ -1755,9 +963,9 @@ var ( forward_AuthService_RemoveMfaOTP_0 = runtime.ForwardResponseMessage - forward_AuthService_SearchMyProjectOrgs_0 = runtime.ForwardResponseMessage + forward_AuthService_SearchMyUserGrant_0 = runtime.ForwardResponseMessage - forward_AuthService_IsIamAdmin_0 = runtime.ForwardResponseMessage + forward_AuthService_SearchMyProjectOrgs_0 = runtime.ForwardResponseMessage forward_AuthService_GetMyZitadelPermissions_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/auth/api/grpc/auth.swagger.json b/pkg/auth/api/grpc/auth.swagger.json index df818781aa..98084c0057 100644 --- a/pkg/auth/api/grpc/auth.swagger.json +++ b/pkg/auth/api/grpc/auth.swagger.json @@ -19,22 +19,6 @@ "application/grpc" ], "paths": { - "/global/_isiamadmin": { - "get": { - "operationId": "IsIamAdmin", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1IsAdminResponse" - } - } - }, - "tags": [ - "AuthService" - ] - } - }, "/global/projectorgs/_search": { "post": { "operationId": "SearchMyProjectOrgs", @@ -128,6 +112,32 @@ ] } }, + "/usergrants/me/_search": { + "post": { + "operationId": "SearchMyUserGrant", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UserGrantSearchResponse" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UserGrantSearchRequest" + } + } + ], + "tags": [ + "AuthService" + ] + } + }, "/users/me/address": { "get": { "operationId": "GetMyUserAddress", @@ -510,7 +520,7 @@ "200": { "description": "A successful response.", "schema": { - "type": "object" + "$ref": "#/definitions/protobufStruct" } } }, @@ -521,6 +531,19 @@ } }, "definitions": { + "protobufListValue": { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufValue" + }, + "description": "Repeated field of dynamically typed values." + } + }, + "description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array." + }, "protobufNullValue": { "type": "string", "enum": [ @@ -529,6 +552,51 @@ "default": "NULL_VALUE", "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." }, + "protobufStruct": { + "type": "object", + "properties": { + "fields": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/protobufValue" + }, + "description": "Unordered map of dynamically typed values." + } + }, + "description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object." + }, + "protobufValue": { + "type": "object", + "properties": { + "null_value": { + "$ref": "#/definitions/protobufNullValue", + "description": "Represents a null value." + }, + "number_value": { + "type": "number", + "format": "double", + "description": "Represents a double value." + }, + "string_value": { + "type": "string", + "description": "Represents a string value." + }, + "bool_value": { + "type": "boolean", + "format": "boolean", + "description": "Represents a boolean value." + }, + "struct_value": { + "$ref": "#/definitions/protobufStruct", + "description": "Represents a structured value." + }, + "list_value": { + "$ref": "#/definitions/protobufListValue", + "description": "Represents a repeated `Value`." + } + }, + "description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value." + }, "v1Gender": { "type": "string", "enum": [ @@ -539,15 +607,6 @@ ], "default": "GENDER_UNSPECIFIED" }, - "v1IsAdminResponse": { - "type": "object", - "properties": { - "is_admin": { - "type": "boolean", - "format": "boolean" - } - } - }, "v1MFAState": { "type": "string", "enum": [ @@ -712,7 +771,10 @@ "enum": [ "SEARCHMETHOD_EQUALS", "SEARCHMETHOD_STARTS_WITH", - "SEARCHMETHOD_CONTAINS" + "SEARCHMETHOD_CONTAINS", + "SEARCHMETHOD_EQUALS_IGNORE_CASE", + "SEARCHMETHOD_STARTS_WITH_IGNORE_CASE", + "SEARCHMETHOD_CONTAINS_IGNORE_CASE" ], "default": "SEARCHMETHOD_EQUALS" }, @@ -837,6 +899,101 @@ } } }, + "v1UserGrantSearchKey": { + "type": "string", + "enum": [ + "UserGrantSearchKey_UNKNOWN", + "UserGrantSearchKey_ORG_ID", + "UserGrantSearchKey_PROJECT_ID" + ], + "default": "UserGrantSearchKey_UNKNOWN" + }, + "v1UserGrantSearchQuery": { + "type": "object", + "properties": { + "key": { + "$ref": "#/definitions/v1UserGrantSearchKey" + }, + "method": { + "$ref": "#/definitions/v1SearchMethod" + }, + "value": { + "type": "string" + } + } + }, + "v1UserGrantSearchRequest": { + "type": "object", + "properties": { + "offset": { + "type": "string", + "format": "uint64" + }, + "limit": { + "type": "string", + "format": "uint64" + }, + "sorting_column": { + "$ref": "#/definitions/v1UserGrantSearchKey" + }, + "asc": { + "type": "boolean", + "format": "boolean" + }, + "queries": { + "type": "array", + "items": { + "$ref": "#/definitions/v1UserGrantSearchQuery" + } + } + } + }, + "v1UserGrantSearchResponse": { + "type": "object", + "properties": { + "offset": { + "type": "string", + "format": "uint64" + }, + "limit": { + "type": "string", + "format": "uint64" + }, + "total_result": { + "type": "string", + "format": "uint64" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/definitions/v1UserGrantView" + } + } + } + }, + "v1UserGrantView": { + "type": "object", + "properties": { + "OrgId": { + "type": "string" + }, + "ProjectId": { + "type": "string" + }, + "UserId": { + "type": "string" + }, + "Roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "OrgName": { + "type": "string" + } + } + }, "v1UserPhone": { "type": "object", "properties": { diff --git a/pkg/auth/api/grpc/grant.go b/pkg/auth/api/grpc/grant.go deleted file mode 100644 index 8eb8681e06..0000000000 --- a/pkg/auth/api/grpc/grant.go +++ /dev/null @@ -1,15 +0,0 @@ -package grpc - -import ( - "context" - "github.com/caos/zitadel/internal/errors" - "github.com/golang/protobuf/ptypes/empty" -) - -func (s *Server) SearchMyProjectOrgs(ctx context.Context, request *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-8kdRf", "Not implemented") -} - -func (s *Server) IsIamAdmin(ctx context.Context, _ *empty.Empty) (*IsAdminResponse, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-9odFv", "Not implemented") -} diff --git a/pkg/auth/api/grpc/mock/auth.proto.mock.go b/pkg/auth/api/grpc/mock/auth.proto.mock.go index f829479430..347189b266 100644 --- a/pkg/auth/api/grpc/mock/auth.proto.mock.go +++ b/pkg/auth/api/grpc/mock/auth.proto.mock.go @@ -277,26 +277,6 @@ func (mr *MockAuthServiceClientMockRecorder) Healthz(arg0, arg1 interface{}, arg return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Healthz", reflect.TypeOf((*MockAuthServiceClient)(nil).Healthz), varargs...) } -// IsIamAdmin mocks base method -func (m *MockAuthServiceClient) IsIamAdmin(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.IsAdminResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IsIamAdmin", varargs...) - ret0, _ := ret[0].(*grpc.IsAdminResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IsIamAdmin indicates an expected call of IsIamAdmin -func (mr *MockAuthServiceClientMockRecorder) IsIamAdmin(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsIamAdmin", reflect.TypeOf((*MockAuthServiceClient)(nil).IsIamAdmin), varargs...) -} - // Ready mocks base method func (m *MockAuthServiceClient) Ready(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) { m.ctrl.T.Helper() @@ -397,24 +377,24 @@ func (mr *MockAuthServiceClientMockRecorder) SearchMyProjectOrgs(arg0, arg1 inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchMyProjectOrgs", reflect.TypeOf((*MockAuthServiceClient)(nil).SearchMyProjectOrgs), varargs...) } -// SetMyPassword mocks base method -func (m *MockAuthServiceClient) SetMyPassword(arg0 context.Context, arg1 *grpc.PasswordRequest, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) { +// SearchUserGrant mocks base method +func (m *MockAuthServiceClient) SearchUserGrant(arg0 context.Context, arg1 *grpc.UserGrantSearchRequest, arg2 ...grpc0.CallOption) (*grpc.UserGrantSearchResponse, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "SetMyPassword", varargs...) - ret0, _ := ret[0].(*emptypb.Empty) + ret := m.ctrl.Call(m, "SearchUserGrant", varargs...) + ret0, _ := ret[0].(*grpc.UserGrantSearchResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// SetMyPassword indicates an expected call of SetMyPassword -func (mr *MockAuthServiceClientMockRecorder) SetMyPassword(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// SearchUserGrant indicates an expected call of SearchUserGrant +func (mr *MockAuthServiceClientMockRecorder) SearchUserGrant(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMyPassword", reflect.TypeOf((*MockAuthServiceClient)(nil).SetMyPassword), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUserGrant", reflect.TypeOf((*MockAuthServiceClient)(nil).SearchUserGrant), varargs...) } // UpdateMyUserAddress mocks base method @@ -478,14 +458,14 @@ func (mr *MockAuthServiceClientMockRecorder) Validate(arg0, arg1 interface{}, ar } // VerifyMfaOTP mocks base method -func (m *MockAuthServiceClient) VerifyMfaOTP(arg0 context.Context, arg1 *grpc.VerifyMfaOtp, arg2 ...grpc0.CallOption) (*grpc.MfaOtpResponse, error) { +func (m *MockAuthServiceClient) VerifyMfaOTP(arg0 context.Context, arg1 *grpc.VerifyMfaOtp, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "VerifyMfaOTP", varargs...) - ret0, _ := ret[0].(*grpc.MfaOtpResponse) + ret0, _ := ret[0].(*emptypb.Empty) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/pkg/auth/api/grpc/permissions.go b/pkg/auth/api/grpc/permissions.go deleted file mode 100644 index 998ba2ee98..0000000000 --- a/pkg/auth/api/grpc/permissions.go +++ /dev/null @@ -1,50 +0,0 @@ -package grpc - -import ( - "context" - "github.com/caos/zitadel/internal/errors" - "github.com/golang/protobuf/ptypes/empty" -) - -func (s *Server) GetMyZitadelPermissions(ctx context.Context, _ *empty.Empty) (*MyPermissions, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-or67G", "Not implemented") - //ctxData := auth.GetCtxData(ctx) - // - //grants, err := s.processor.ResolveGrants(ctx, ctxData.UserID, ctxData.OrgID) - //if err != nil { - // return nil, err - //} - // - //permissions := &MyPermissions{Permissions: []string{}} - // - //for _, grant := range grants { - // for _, role := range grant.Roles { - // roleName, ctxID := auth.SplitPermission(role) - // for _, mapping := range s.authConf.RolePermissionMappings { - // if mapping.Role == roleName { - // permissions.appendPermissions(ctxID, mapping.Permissions...) - // } - // } - // } - //} - // - //return permissions, nil -} - -func (p *MyPermissions) appendPermissions(ctxID string, permissions ...string) { - for _, permission := range permissions { - p.appendPermission(ctxID, permission) - } -} - -func (p *MyPermissions) appendPermission(ctxID, permission string) { - if ctxID != "" { - permission = permission + ":" + ctxID - } - for _, existingPermission := range p.Permissions { - if existingPermission == permission { - return - } - } - p.Permissions = append(p.Permissions, permission) -} diff --git a/pkg/auth/api/grpc/search_converter.go b/pkg/auth/api/grpc/search_converter.go new file mode 100644 index 0000000000..d50c224171 --- /dev/null +++ b/pkg/auth/api/grpc/search_converter.go @@ -0,0 +1,22 @@ +package grpc + +import "github.com/caos/zitadel/internal/model" + +func searchMethodToModel(method SearchMethod) model.SearchMethod { + switch method { + case SearchMethod_SEARCHMETHOD_EQUALS: + return model.SEARCHMETHOD_EQUALS + case SearchMethod_SEARCHMETHOD_CONTAINS: + return model.SEARCHMETHOD_CONTAINS + case SearchMethod_SEARCHMETHOD_STARTS_WITH: + return model.SEARCHMETHOD_STARTS_WITH + case SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE: + return model.SEARCHMETHOD_EQUALS_IGNORE_CASE + case SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE: + return model.SEARCHMETHOD_CONTAINS_IGNORE_CASE + case SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE: + return model.SEARCHMETHOD_STARTS_WITH_IGNORE_CASE + default: + return model.SEARCHMETHOD_EQUALS + } +} diff --git a/pkg/auth/api/grpc/server.go b/pkg/auth/api/grpc/server.go index 7c55eaf303..a9177e1a11 100644 --- a/pkg/auth/api/grpc/server.go +++ b/pkg/auth/api/grpc/server.go @@ -1,6 +1,7 @@ package grpc import ( + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "google.golang.org/grpc" @@ -20,12 +21,12 @@ type Server struct { authZ auth_util.Config } -func StartServer(conf grpc_util.ServerConfig, authZ auth_util.Config, repo repository.Repository) *Server { +func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth_util.Config, authRepo repository.Repository) *Server { return &Server{ port: conf.Port, - repo: repo, + repo: authRepo, authZ: authZ, - verifier: auth.Start(), + verifier: auth.Start(authZRepo), } } diff --git a/pkg/auth/api/grpc/user.go b/pkg/auth/api/grpc/user.go index 5788c82df2..2f387aac89 100644 --- a/pkg/auth/api/grpc/user.go +++ b/pkg/auth/api/grpc/user.go @@ -110,7 +110,7 @@ func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *MfaOtpRespon } func (s *Server) VerifyMfaOTP(ctx context.Context, request *VerifyMfaOtp) (*empty.Empty, error) { - err := s.repo.VerifyMyMfaOTP(ctx, request.Code) + err := s.repo.VerifyMyMfaOTPSetup(ctx, request.Code) return &empty.Empty{}, err } diff --git a/pkg/auth/api/grpc/user_grant.go b/pkg/auth/api/grpc/user_grant.go new file mode 100644 index 0000000000..4035cfcf3b --- /dev/null +++ b/pkg/auth/api/grpc/user_grant.go @@ -0,0 +1,30 @@ +package grpc + +import ( + "context" + "github.com/golang/protobuf/ptypes/empty" +) + +func (s *Server) SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest) (*UserGrantSearchResponse, error) { + response, err := s.repo.SearchMyUserGrants(ctx, userGrantSearchRequestsToModel(in)) + if err != nil { + return nil, err + } + return userGrantSearchResponseFromModel(response), nil +} + +func (s *Server) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { + response, err := s.repo.SearchMyProjectOrgs(ctx, myProjectOrgSearchRequestRequestsToModel(in)) + if err != nil { + return nil, err + } + return projectOrgSearchResponseFromModel(response), nil +} + +func (s *Server) GetMyZitadelPermissions(ctx context.Context, _ *empty.Empty) (*MyPermissions, error) { + perms, err := s.repo.SearchMyZitadelPermissions(ctx) + if err != nil { + return nil, err + } + return &MyPermissions{Permissions: perms}, nil +} diff --git a/pkg/auth/api/grpc/user_grant_converter.go b/pkg/auth/api/grpc/user_grant_converter.go new file mode 100644 index 0000000000..2de2b539bc --- /dev/null +++ b/pkg/auth/api/grpc/user_grant_converter.go @@ -0,0 +1,126 @@ +package grpc + +import ( + grant_model "github.com/caos/zitadel/internal/usergrant/model" +) + +func userGrantSearchRequestsToModel(request *UserGrantSearchRequest) *grant_model.UserGrantSearchRequest { + return &grant_model.UserGrantSearchRequest{ + Offset: request.Offset, + Limit: request.Limit, + Queries: userGrantSearchQueriesToModel(request.Queries), + } +} + +func userGrantSearchQueriesToModel(queries []*UserGrantSearchQuery) []*grant_model.UserGrantSearchQuery { + converted := make([]*grant_model.UserGrantSearchQuery, len(queries)) + for i, q := range queries { + converted[i] = userGrantSearchQueryToModel(q) + } + return converted +} + +func userGrantSearchQueryToModel(query *UserGrantSearchQuery) *grant_model.UserGrantSearchQuery { + return &grant_model.UserGrantSearchQuery{ + Key: userGrantSearchKeyToModel(query.Key), + Method: searchMethodToModel(query.Method), + Value: query.Value, + } +} + +func userGrantSearchKeyToModel(key UserGrantSearchKey) grant_model.UserGrantSearchKey { + switch key { + case UserGrantSearchKey_UserGrantSearchKey_ORG_ID: + return grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER + case UserGrantSearchKey_UserGrantSearchKey_PROJECT_ID: + return grant_model.USERGRANTSEARCHKEY_PROJECT_ID + default: + return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED + } +} + +func myProjectOrgSearchRequestRequestsToModel(request *MyProjectOrgSearchRequest) *grant_model.UserGrantSearchRequest { + return &grant_model.UserGrantSearchRequest{ + Offset: request.Offset, + Limit: request.Limit, + Asc: request.Asc, + SortingColumn: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, + Queries: myProjectOrgSearchQueriesToModel(request.Queries), + } +} + +func myProjectOrgSearchQueriesToModel(queries []*MyProjectOrgSearchQuery) []*grant_model.UserGrantSearchQuery { + converted := make([]*grant_model.UserGrantSearchQuery, len(queries)) + for i, q := range queries { + converted[i] = myProjectOrgSearchQueryToModel(q) + } + return converted +} + +func myProjectOrgSearchQueryToModel(query *MyProjectOrgSearchQuery) *grant_model.UserGrantSearchQuery { + return &grant_model.UserGrantSearchQuery{ + Key: myProjectOrgSearchKeyToModel(query.Key), + Method: searchMethodToModel(query.Method), + Value: query.Value, + } +} + +func myProjectOrgSearchKeyToModel(key MyProjectOrgSearchKey) grant_model.UserGrantSearchKey { + switch key { + case MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_ORG_NAME: + return grant_model.USERGRANTSEARCHKEY_ORG_NAME + default: + return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED + } +} + +func userGrantSearchResponseFromModel(response *grant_model.UserGrantSearchResponse) *UserGrantSearchResponse { + return &UserGrantSearchResponse{ + Offset: response.Offset, + Limit: response.Limit, + TotalResult: response.TotalResult, + Result: userGrantViewsFromModel(response.Result), + } +} + +func userGrantViewsFromModel(users []*grant_model.UserGrantView) []*UserGrantView { + converted := make([]*UserGrantView, len(users)) + for i, user := range users { + converted[i] = userGrantViewFromModel(user) + } + return converted +} + +func userGrantViewFromModel(grant *grant_model.UserGrantView) *UserGrantView { + return &UserGrantView{ + UserId: grant.UserID, + OrgId: grant.ResourceOwner, + OrgName: grant.OrgName, + ProjectId: grant.ProjectID, + Roles: grant.RoleKeys, + } +} + +func projectOrgSearchResponseFromModel(response *grant_model.ProjectOrgSearchResponse) *MyProjectOrgSearchResponse { + return &MyProjectOrgSearchResponse{ + Offset: response.Offset, + Limit: response.Limit, + TotalResult: response.TotalResult, + Result: projectOrgsFromModel(response.Result), + } +} + +func projectOrgsFromModel(projectOrgs []*grant_model.Org) []*Org { + converted := make([]*Org, len(projectOrgs)) + for i, org := range projectOrgs { + converted[i] = projectOrgFromModel(org) + } + return converted +} + +func projectOrgFromModel(org *grant_model.Org) *Org { + return &Org{ + Id: org.OrgID, + Name: org.OrgName, + } +} diff --git a/pkg/auth/api/grpc/user_session.go b/pkg/auth/api/grpc/user_session.go index 05460f85ef..7df389d004 100644 --- a/pkg/auth/api/grpc/user_session.go +++ b/pkg/auth/api/grpc/user_session.go @@ -2,10 +2,13 @@ package grpc import ( "context" - "github.com/caos/zitadel/internal/errors" "github.com/golang/protobuf/ptypes/empty" ) func (s *Server) GetMyUserSessions(ctx context.Context, _ *empty.Empty) (_ *UserSessionViews, err error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-nc52s", "Not implemented") + userSessions, err := s.repo.GetMyUserSessions(ctx) + if err != nil { + return nil, err + } + return &UserSessionViews{UserSessions: userSessionViewsFromModel(userSessions)}, nil } diff --git a/pkg/auth/api/grpc/user_session_converter.go b/pkg/auth/api/grpc/user_session_converter.go new file mode 100644 index 0000000000..3b21ba6fcc --- /dev/null +++ b/pkg/auth/api/grpc/user_session_converter.go @@ -0,0 +1,35 @@ +package grpc + +import ( + auth_req_model "github.com/caos/zitadel/internal/auth_request/model" + usr_model "github.com/caos/zitadel/internal/user/model" +) + +func userSessionViewsFromModel(userSessions []*usr_model.UserSessionView) []*UserSessionView { + converted := make([]*UserSessionView, len(userSessions)) + for i, s := range userSessions { + converted[i] = userSessionViewFromModel(s) + } + return converted +} + +func userSessionViewFromModel(userSession *usr_model.UserSessionView) *UserSessionView { + return &UserSessionView{ + Sequence: userSession.Sequence, + AgentId: userSession.UserAgentID, + UserId: userSession.UserID, + UserName: userSession.UserName, + AuthState: userSessionStateFromModel(userSession.State), + } +} + +func userSessionStateFromModel(state auth_req_model.UserSessionState) UserSessionState { + switch state { + case auth_req_model.UserSessionStateActive: + return UserSessionState_USERSESSIONSTATE_ACTIVE + case auth_req_model.UserSessionStateTerminated: + return UserSessionState_USERSESSIONSTATE_TERMINATED + default: + return UserSessionState_USERSESSIONSTATE_UNSPECIFIED + } +} diff --git a/pkg/auth/api/oidc/auth_request.go b/pkg/auth/api/oidc/auth_request.go new file mode 100644 index 0000000000..62366797ed --- /dev/null +++ b/pkg/auth/api/oidc/auth_request.go @@ -0,0 +1,82 @@ +package oidc + +import ( + "context" + "time" + + "github.com/caos/oidc/pkg/oidc" + "github.com/caos/oidc/pkg/op" + "gopkg.in/square/go-jose.v2" + + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" +) + +func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (op.AuthRequest, error) { + userAgentID, ok := UserAgentIDFromCtx(ctx) + if !ok { + return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id") + } + authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID) + resp, err := o.repo.CreateAuthRequest(ctx, authRequest) + if err != nil { + return nil, err + } + return AuthRequestFromBusiness(resp) +} + +func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (op.AuthRequest, error) { + resp, err := o.repo.AuthRequestByIDCheckLoggedIn(ctx, id) + if err != nil { + return nil, err + } + return AuthRequestFromBusiness(resp) +} + +func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (op.AuthRequest, error) { + resp, err := o.repo.AuthRequestByCode(ctx, code) + if err != nil { + return nil, err + } + return AuthRequestFromBusiness(resp) +} + +func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) error { + return o.repo.SaveAuthCode(ctx, id, code) +} + +func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) error { + return o.repo.DeleteAuthRequest(ctx, id) +} + +func (o *OPStorage) CreateToken(ctx context.Context, authReq op.AuthRequest) (string, time.Time, error) { + req, err := o.repo.AuthRequestByID(ctx, authReq.GetID()) + if err != nil { + return "", time.Time{}, err + } + resp, err := o.repo.CreateToken(ctx, req.AgentID, req.ApplicationID, req.UserID, req.Audience, req.Request.(*model.AuthRequestOIDC).Scopes, o.defaultAccessTokenLifetime) //PLANNED: lifetime from client + if err != nil { + return "", time.Time{}, err + } + return resp.ID, resp.Expiration, nil +} + +func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID string) error { + userAgentID, ok := UserAgentIDFromCtx(ctx) + if !ok { + return errors.ThrowPreconditionFailed(nil, "OIDC-fso7F", "no user agent id") + } + return o.repo.SignOut(ctx, userAgentID, userID) +} + +func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) { + o.repo.GetSigningKey(ctx, keyCh, errCh, timer) +} + +func (o *OPStorage) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) { + return o.repo.GetKeySet(ctx) +} + +func (o *OPStorage) SaveNewKeyPair(ctx context.Context) error { + return o.repo.GenerateSigningKeyPair(ctx, o.signingKeyAlgorithm) +} diff --git a/pkg/auth/api/oidc/auth_request_converter.go b/pkg/auth/api/oidc/auth_request_converter.go new file mode 100644 index 0000000000..a837046809 --- /dev/null +++ b/pkg/auth/api/oidc/auth_request_converter.go @@ -0,0 +1,254 @@ +package oidc + +import ( + "context" + "net" + "time" + + "github.com/caos/oidc/pkg/oidc" + "github.com/caos/oidc/pkg/op" + "golang.org/x/text/language" + + api_utils "github.com/caos/zitadel/internal/api" + http_utils "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" +) + +const ( + amrPassword = "password" + amrMFA = "mfa" + amrOTP = "otp" +) + +type AuthRequest struct { + *model.AuthRequest +} + +func (a *AuthRequest) GetID() string { + return a.ID +} + +func (a *AuthRequest) GetACR() string { + // return a. + return "" //PLANNED: impl +} + +func (a *AuthRequest) GetAMR() []string { + amr := make([]string, 0) + if a.PasswordVerified { + amr = append(amr, amrPassword) + } + if len(a.MfasVerified) > 0 { + amr = append(amr, amrMFA) + for _, mfa := range a.MfasVerified { + if amrMfa := AMRFromMFAType(mfa); amrMfa != "" { + amr = append(amr, amrMfa) + } + } + } + return amr +} + +func (a *AuthRequest) GetAudience() []string { + return a.Audience +} + +func (a *AuthRequest) GetAuthTime() time.Time { + return a.AuthTime +} + +func (a *AuthRequest) GetClientID() string { + return a.ApplicationID +} + +func (a *AuthRequest) GetCodeChallenge() *oidc.CodeChallenge { + return CodeChallengeToOIDC(a.oidc().CodeChallenge) +} + +func (a *AuthRequest) GetNonce() string { + return a.oidc().Nonce +} + +func (a *AuthRequest) GetRedirectURI() string { + return a.CallbackURI +} + +func (a *AuthRequest) GetResponseType() oidc.ResponseType { + return ResponseTypeToOIDC(a.oidc().ResponseType) +} + +func (a *AuthRequest) GetScopes() []string { + return a.oidc().Scopes +} + +func (a *AuthRequest) GetState() string { + return a.TransferState +} + +func (a *AuthRequest) GetSubject() string { + return a.UserID +} + +func (a *AuthRequest) Done() bool { + for _, step := range a.PossibleSteps { + if step.Type() == model.NextStepRedirectToCallback { + return true + } + } + return false +} + +func (a *AuthRequest) oidc() *model.AuthRequestOIDC { + return a.Request.(*model.AuthRequestOIDC) +} + +func AuthRequestFromBusiness(authReq *model.AuthRequest) (_ op.AuthRequest, err error) { + if _, ok := authReq.Request.(*model.AuthRequestOIDC); !ok { + return nil, errors.ThrowInvalidArgument(nil, "OIDC-Haz7A", "auth request is not of type oidc") + } + return &AuthRequest{authReq}, nil +} + +func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, userAgentID, userID string) *model.AuthRequest { + return &model.AuthRequest{ + AgentID: userAgentID, + BrowserInfo: ParseBrowserInfoFromContext(ctx), + ApplicationID: authReq.ClientID, + CallbackURI: authReq.RedirectURI, + TransferState: authReq.State, + Prompt: PromptToBusiness(authReq.Prompt), + PossibleLOAs: ACRValuesToBusiness(authReq.ACRValues), + UiLocales: UILocalesToBusiness(authReq.UILocales), + LoginHint: authReq.LoginHint, + MaxAuthAge: authReq.MaxAge, + UserID: userID, + Request: &model.AuthRequestOIDC{ + Scopes: authReq.Scopes, + ResponseType: ResponseTypeToBusiness(authReq.ResponseType), + Nonce: authReq.Nonce, + CodeChallenge: CodeChallengeToBusiness(authReq.CodeChallenge, authReq.CodeChallengeMethod), + }, + } +} + +func ParseBrowserInfoFromContext(ctx context.Context) *model.BrowserInfo { + userAgent, acceptLang := HttpHeadersFromContext(ctx) + ip := IpFromContext(ctx) + return &model.BrowserInfo{RemoteIP: ip, UserAgent: userAgent, AcceptLanguage: acceptLang} +} + +func HttpHeadersFromContext(ctx context.Context) (userAgent, acceptLang string) { + ctxHeaders, ok := http_utils.HeadersFromCtx(ctx) + if !ok { + return + } + if agents, ok := ctxHeaders[api_utils.UserAgent]; ok { + userAgent = agents[0] + } + if langs, ok := ctxHeaders[api_utils.AcceptLanguage]; ok { + acceptLang = langs[0] + } + return userAgent, acceptLang +} + +func IpFromContext(ctx context.Context) net.IP { + ipString := http_utils.RemoteIPFromCtx(ctx) + if ipString == "" { + return nil + } + return net.ParseIP(ipString) +} + +func PromptToBusiness(prompt oidc.Prompt) model.Prompt { + switch prompt { + case oidc.PromptNone: + return model.PromptNone + case oidc.PromptLogin: + return model.PromptLogin + case oidc.PromptConsent: + return model.PromptConsent + case oidc.PromptSelectAccount: + return model.PromptSelectAccount + default: + return model.PromptUnspecified + } +} + +func ACRValuesToBusiness(values []string) []model.LevelOfAssurance { + return nil +} + +func UILocalesToBusiness(tags []language.Tag) []string { + if tags == nil { + return nil + } + locales := make([]string, len(tags)) + for i, tag := range tags { + locales[i] = tag.String() + } + return locales +} + +func ResponseTypeToBusiness(responseType oidc.ResponseType) model.OIDCResponseType { + switch responseType { + case oidc.ResponseTypeCode: + return model.OIDCResponseTypeCode + case oidc.ResponseTypeIDToken: + return model.OIDCResponseTypeIdToken + case oidc.ResponseTypeIDTokenOnly: + return model.OIDCResponseTypeToken + default: + return model.OIDCResponseTypeCode + } +} + +func ResponseTypeToOIDC(responseType model.OIDCResponseType) oidc.ResponseType { + switch responseType { + case model.OIDCResponseTypeCode: + return oidc.ResponseTypeCode + case model.OIDCResponseTypeToken: + return oidc.ResponseTypeIDToken + case model.OIDCResponseTypeIdToken: + return oidc.ResponseTypeIDTokenOnly + default: + return oidc.ResponseTypeCode + } +} + +func CodeChallengeToBusiness(challenge string, method oidc.CodeChallengeMethod) *model.OIDCCodeChallenge { + if challenge == "" { + return nil + } + challengeMethod := model.CodeChallengeMethodPlain + if method == oidc.CodeChallengeMethodS256 { + challengeMethod = model.CodeChallengeMethodS256 + } + return &model.OIDCCodeChallenge{ + Challenge: challenge, + Method: challengeMethod, + } +} + +func CodeChallengeToOIDC(challenge *model.OIDCCodeChallenge) *oidc.CodeChallenge { + if challenge == nil { + return nil + } + challengeMethod := oidc.CodeChallengeMethodPlain + if challenge.Method == model.CodeChallengeMethodS256 { + challengeMethod = oidc.CodeChallengeMethodS256 + } + return &oidc.CodeChallenge{ + Challenge: challenge.Challenge, + Method: challengeMethod, + } +} + +func AMRFromMFAType(mfaType model.MfaType) string { + switch mfaType { + case model.MfaTypeOTP: + return amrOTP + default: + return "" + } +} diff --git a/pkg/auth/api/oidc/client.go b/pkg/auth/api/oidc/client.go new file mode 100644 index 0000000000..ba4a6aa0dc --- /dev/null +++ b/pkg/auth/api/oidc/client.go @@ -0,0 +1,97 @@ +package oidc + +import ( + "context" + + "github.com/caos/oidc/pkg/oidc" + "github.com/caos/oidc/pkg/op" + + "github.com/caos/zitadel/internal/user/model" +) + +const ( + scopeOpenID = "openid" + scopeProfile = "profile" + scopeEmail = "email" + scopePhone = "phone" + scopeAddress = "address" +) + +func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (op.Client, error) { + client, err := o.repo.ApplicationByClientID(ctx, id) + if err != nil { + return nil, err + } + return ClientFromBusiness(client, o.defaultLoginURL, o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime) +} + +func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) error { + return o.repo.AuthorizeOIDCApplication(ctx, id, secret) +} + +func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID string) (*oidc.Userinfo, error) { + token, err := o.repo.TokenByID(ctx, tokenID) + if err != nil { + return nil, err + } + return o.GetUserinfoFromScopes(ctx, token.UserID, token.Scopes) +} + +func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, scopes []string) (*oidc.Userinfo, error) { + user, err := o.repo.UserByID(ctx, userID) + if err != nil { + return nil, err + } + userInfo := new(oidc.Userinfo) + for _, scope := range scopes { + switch scope { + case scopeOpenID: + userInfo.Subject = user.AggregateID + case scopeEmail: + if user.Email == nil { + continue + } + userInfo.Email = user.EmailAddress + userInfo.EmailVerified = user.IsEmailVerified + case scopeProfile: + if user.Profile == nil { + continue + } + userInfo.Name = user.FirstName + " " + user.LastName + userInfo.FamilyName = user.LastName + userInfo.GivenName = user.FirstName + userInfo.Nickname = user.NickName + userInfo.PreferredUsername = user.UserName + userInfo.UpdatedAt = user.ChangeDate + userInfo.Gender = oidc.Gender(getGender(user.Gender)) + case scopePhone: + if user.Phone == nil { + continue + } + userInfo.PhoneNumber = user.PhoneNumber + userInfo.PhoneNumberVerified = user.IsPhoneVerified + case scopeAddress: + if user.Address == nil { + continue + } + userInfo.Address.StreetAddress = user.StreetAddress + userInfo.Address.Locality = user.Locality + userInfo.Address.Region = user.Region + userInfo.Address.PostalCode = user.PostalCode + userInfo.Address.Country = user.Country + } + } + return userInfo, nil +} + +func getGender(gender model.Gender) string { + switch gender { + case model.GENDER_FEMALE: + return "female" + case model.GENDER_MALE: + return "male" + case model.GENDER_DIVERSE: + return "diverse" + } + return "" +} diff --git a/pkg/auth/api/oidc/client_converter.go b/pkg/auth/api/oidc/client_converter.go new file mode 100644 index 0000000000..e2aaf3a4bf --- /dev/null +++ b/pkg/auth/api/oidc/client_converter.go @@ -0,0 +1,73 @@ +package oidc + +import ( + "time" + + "github.com/caos/oidc/pkg/op" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/project/model" +) + +type Client struct { + *model.ApplicationView + defaultLoginURL string + defaultAccessTokenLifetime time.Duration + defaultIdTokenLifetime time.Duration +} + +func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration) (op.Client, error) { + if !app.IsOIDC { + return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application") + } + return &Client{ApplicationView: app, defaultLoginURL: defaultLoginURL, defaultAccessTokenLifetime: defaultAccessTokenLifetime, defaultIdTokenLifetime: defaultIdTokenLifetime}, nil +} + +func (c *Client) ApplicationType() op.ApplicationType { + return op.ApplicationType(c.OIDCApplicationType) +} + +func (c *Client) GetAuthMethod() op.AuthMethod { + return authMethodToOIDC(c.OIDCAuthMethodType) +} + +func (c *Client) GetID() string { + return c.OIDCClientID +} + +func (c *Client) LoginURL(id string) string { + return c.defaultLoginURL + id +} + +func (c *Client) RedirectURIs() []string { + return c.OIDCRedirectUris +} + +func (c *Client) PostLogoutRedirectURIs() []string { + return c.OIDCPostLogoutRedirectUris +} + +func (c *Client) AccessTokenLifetime() time.Duration { + return c.defaultAccessTokenLifetime //PLANNED: impl from real client +} + +func (c *Client) IDTokenLifetime() time.Duration { + return c.defaultIdTokenLifetime //PLANNED: impl from real client +} + +func (c *Client) AccessTokenType() op.AccessTokenType { + return op.AccessTokenTypeBearer //PLANNED: impl from real client +} + +func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod { + switch authType { + case model.OIDCAUTHMETHODTYPE_BASIC: + return op.AuthMethodBasic + case model.OIDCAUTHMETHODTYPE_POST: + return op.AuthMethodPost + case model.OIDCAUTHMETHODTYPE_NONE: + return op.AuthMethodNone + default: + return op.AuthMethodBasic + } +} diff --git a/pkg/auth/api/oidc/cookie_interceptor.go b/pkg/auth/api/oidc/cookie_interceptor.go new file mode 100644 index 0000000000..9604d72047 --- /dev/null +++ b/pkg/auth/api/oidc/cookie_interceptor.go @@ -0,0 +1,37 @@ +package oidc + +import ( + "context" + "net/http" + + http_utils "github.com/caos/zitadel/internal/api/http" +) + +type key int + +var ( + userAgentKey key +) + +func UserAgentIDFromCtx(ctx context.Context) (string, bool) { + userAgentID, ok := ctx.Value(userAgentKey).(string) + return userAgentID, ok +} + +func UserAgentCookieHandler(cookieHandler *http_utils.UserAgentHandler, nextHandlerFunc func(http.HandlerFunc) http.HandlerFunc) func(http.HandlerFunc) http.HandlerFunc { + return func(handlerFunc http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ua, err := cookieHandler.GetUserAgent(r) + if err != nil { + ua, err = cookieHandler.NewUserAgent() + } + if err == nil { + ctx := context.WithValue(r.Context(), userAgentKey, ua.ID) + r = r.WithContext(ctx) + cookieHandler.SetUserAgent(w, ua) + } + handlerFunc(w, r) + nextHandlerFunc(handlerFunc) + } + } +} diff --git a/pkg/auth/api/oidc/op.go b/pkg/auth/api/oidc/op.go new file mode 100644 index 0000000000..628247849b --- /dev/null +++ b/pkg/auth/api/oidc/op.go @@ -0,0 +1,87 @@ +package oidc + +import ( + "context" + "time" + + "github.com/caos/logging" + "github.com/caos/oidc/pkg/op" + + http_utils "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/auth/repository" + "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/id" +) + +type OPHandlerConfig struct { + OPConfig *op.Config + StorageConfig StorageConfig + UserAgentCookieConfig *http_utils.UserAgentCookieConfig + Endpoints *EndpointConfig +} + +type StorageConfig struct { + DefaultLoginURL string + SigningKeyAlgorithm string + DefaultAccessTokenLifetime types.Duration + DefaultIdTokenLifetime types.Duration +} + +type EndpointConfig struct { + Auth *Endpoint + Token *Endpoint + Userinfo *Endpoint + EndSession *Endpoint + Keys *Endpoint +} + +type Endpoint struct { + Path string + URL string +} + +type OPStorage struct { + repo repository.Repository + defaultLoginURL string + defaultAccessTokenLifetime time.Duration + defaultIdTokenLifetime time.Duration + signingKeyAlgorithm string +} + +func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Repository) op.OpenIDProvider { + cookieHandler, err := http_utils.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator) + logging.Log("OIDC-sd4fd").OnError(err).Panic("cannot user agent handler") + provider, err := op.NewDefaultOP( + ctx, + config.OPConfig, + newStorage(config.StorageConfig, repo), + op.WithHttpInterceptor( + UserAgentCookieHandler( + cookieHandler, + http_utils.CopyHeadersToContext, + ), + ), + op.WithCustomAuthEndpoint(op.NewEndpointWithURL(config.Endpoints.Auth.Path, config.Endpoints.Auth.URL)), + op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)), + op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)), + op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)), + op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)), + op.WithRetry(3, time.Duration(30*time.Second)), + ) + logging.Log("OIDC-asf13").OnError(err).Panic("cannot create provider") + return provider +} + +func newStorage(config StorageConfig, repo repository.Repository) *OPStorage { + return &OPStorage{ + repo: repo, + defaultLoginURL: config.DefaultLoginURL, + signingKeyAlgorithm: config.SigningKeyAlgorithm, + defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime.Duration, + defaultIdTokenLifetime: config.DefaultIdTokenLifetime.Duration, + } +} + +func (o *OPStorage) Health(ctx context.Context) error { + return o.repo.Health(ctx) +} diff --git a/pkg/auth/api/proto/auth.proto b/pkg/auth/api/proto/auth.proto index 89fd78fe33..63f107c63d 100644 --- a/pkg/auth/api/proto/auth.proto +++ b/pkg/auth/api/proto/auth.proto @@ -243,20 +243,20 @@ service AuthService { }; } - rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) { + rpc SearchMyUserGrant(UserGrantSearchRequest) returns (UserGrantSearchResponse) { option (google.api.http) = { - post: "/global/projectorgs/_search" + post: "/usergrants/me/_search" body: "*" }; - option (caos.zitadel.utils.v1.auth_option) = { permission: "authenticated" }; } - rpc IsIamAdmin(google.protobuf.Empty) returns (IsAdminResponse) { + rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) { option (google.api.http) = { - get: "/global/_isiamadmin" + post: "/global/projectorgs/_search" + body: "*" }; option (caos.zitadel.utils.v1.auth_option) = { @@ -478,6 +478,41 @@ message OIDCClientAuth { string client_secret = 2; } +message UserGrantSearchRequest { + uint64 offset = 1; + uint64 limit = 2; + UserGrantSearchKey sorting_column = 3 [(validate.rules).enum = {not_in: [0]}];; + bool asc = 4; + repeated UserGrantSearchQuery queries = 5; +} + +message UserGrantSearchQuery { + UserGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];; + SearchMethod method = 2; + string value = 3; +} + +enum UserGrantSearchKey { + UserGrantSearchKey_UNKNOWN = 0; + UserGrantSearchKey_ORG_ID = 1; + UserGrantSearchKey_PROJECT_ID = 2; +} + +message UserGrantSearchResponse { + uint64 offset = 1; + uint64 limit = 2; + uint64 total_result = 3; + repeated UserGrantView result = 4; +} + +message UserGrantView { + string OrgId = 1; + string ProjectId = 2; + string UserId = 3; + repeated string Roles = 4; + string OrgName = 5; +} + message MyProjectOrgSearchRequest { uint64 offset = 1; uint64 limit = 2; @@ -503,10 +538,6 @@ message MyProjectOrgSearchResponse { repeated Org result = 4; } -message IsAdminResponse { - bool is_admin = 1; -} - message Org { string id = 1; string name = 2; @@ -520,4 +551,7 @@ enum SearchMethod { SEARCHMETHOD_EQUALS = 0; SEARCHMETHOD_STARTS_WITH = 1; SEARCHMETHOD_CONTAINS = 2; -} \ No newline at end of file + SEARCHMETHOD_EQUALS_IGNORE_CASE = 3; + SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4; + SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5; +} diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 513ef76e03..948f23ae2d 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -2,8 +2,7 @@ package auth import ( "context" - - "github.com/caos/logging" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/auth/repository/eventsourcing" @@ -16,9 +15,6 @@ type Config struct { Repository eventsourcing.Config } -func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) { - repo, err := eventsourcing.Start(config.Repository, systemDefaults) - logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") - - api.Start(ctx, config.API, authZ, repo) +func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults, authRepo *eventsourcing.EsRepository) { + api.Start(ctx, config.API, authZRepo, authZ, authRepo) } diff --git a/pkg/console/console.go b/pkg/console/console.go index c28cf8dae4..d68ededd75 100644 --- a/pkg/console/console.go +++ b/pkg/console/console.go @@ -1,5 +1,3 @@ -//go:generate statik -src=../../console/dist/app - package console import ( @@ -31,7 +29,7 @@ func (i *spaHandler) Open(name string) (http.File, error) { } func Start(ctx context.Context, config Config) error { - statikFS, err := fs.New() + statikFS, err := fs.NewWithNamespace("console") if err != nil { return err } diff --git a/pkg/console/statik/generate.go b/pkg/console/statik/generate.go new file mode 100644 index 0000000000..9156db8f23 --- /dev/null +++ b/pkg/console/statik/generate.go @@ -0,0 +1,3 @@ +package statik + +//go:generate statik -src=../../../console/dist/app -dest=.. -ns=console diff --git a/pkg/console/statik/statik.go b/pkg/console/statik/statik.go deleted file mode 100644 index defdb7673f..0000000000 --- a/pkg/console/statik/statik.go +++ /dev/null @@ -1 +0,0 @@ -package statik diff --git a/pkg/eventstore/eventstore.go b/pkg/eventstore/eventstore.go deleted file mode 100644 index d07f825e44..0000000000 --- a/pkg/eventstore/eventstore.go +++ /dev/null @@ -1,14 +0,0 @@ -package eventstore - -import ( - "context" - - "github.com/caos/zitadel/internal/errors" -) - -type Config struct { -} - -func Start(ctx context.Context, config Config) error { - return errors.ThrowUnimplemented(nil, "EVENT-1hfiu", "not implemented yet") //TODO: implement -} diff --git a/pkg/login/api/config.go b/pkg/login/api/config.go deleted file mode 100644 index feed11d83a..0000000000 --- a/pkg/login/api/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package api - -type Config struct { -} diff --git a/pkg/login/login.go b/pkg/login/login.go deleted file mode 100644 index 462ba37aa1..0000000000 --- a/pkg/login/login.go +++ /dev/null @@ -1,18 +0,0 @@ -package login - -import ( - "context" - - "github.com/caos/zitadel/internal/errors" - app "github.com/caos/zitadel/internal/login" - "github.com/caos/zitadel/pkg/login/api" -) - -type Config struct { - App app.Config - API api.Config -} - -func Start(ctx context.Context, config Config) error { - return errors.ThrowUnimplemented(nil, "LOGIN-3fwvD", "not implemented yet") //TODO: implement -} diff --git a/pkg/management/api/api.go b/pkg/management/api/api.go index 0971c1b395..8bb54ccd3d 100644 --- a/pkg/management/api/api.go +++ b/pkg/management/api/api.go @@ -3,6 +3,7 @@ package api import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/management/repository" grpc_util "github.com/caos/zitadel/internal/api/grpc" @@ -14,8 +15,8 @@ type Config struct { GRPC grpc_util.Config } -func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) { - grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo) +func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) { + grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, repo) grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig()) server.StartServer(ctx, grpcServer) diff --git a/pkg/management/api/grpc/server.go b/pkg/management/api/grpc/server.go index f25c4309de..faa7276da8 100644 --- a/pkg/management/api/grpc/server.go +++ b/pkg/management/api/grpc/server.go @@ -4,6 +4,7 @@ import ( "github.com/caos/zitadel/internal/api/auth" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc/server/middleware" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" mgmt_auth "github.com/caos/zitadel/internal/management/auth" "github.com/caos/zitadel/internal/management/repository" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" @@ -23,7 +24,7 @@ type Server struct { authZ auth.Config } -func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server { +func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server { return &Server{ port: conf.Port, project: repo, @@ -32,7 +33,7 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository user: repo, usergrant: repo, authZ: authZ, - verifier: mgmt_auth.Start(), + verifier: mgmt_auth.Start(authZRepo), } } diff --git a/pkg/management/management.go b/pkg/management/management.go index f1134ce22c..355d7d796e 100644 --- a/pkg/management/management.go +++ b/pkg/management/management.go @@ -5,6 +5,7 @@ import ( "github.com/caos/logging" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/management/repository/eventsourcing" "github.com/caos/zitadel/pkg/management/api" @@ -15,7 +16,7 @@ type Config struct { API api.Config } -func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) { +func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) { roles := make([]string, len(authZ.RolePermissionMappings)) for i, role := range authZ.RolePermissionMappings { roles[i] = role.Role @@ -23,5 +24,5 @@ func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults repo, err := eventsourcing.Start(config.Repository, systemDefaults, roles) logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") - api.Start(ctx, config.API, authZ, repo) + api.Start(ctx, config.API, authZRepo, authZ, repo) }