diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 25969473d2..265902feff 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -21,7 +21,7 @@ For example: Replace this example with links to related issues, discussions, discord threads, or other sources with more context. Use the Closing #issue syntax for issues that are resolved with this PR. -- Closes #123 -- Discussion #456 -- Follow-up for PR #789 -- https://discord.com/channels/123/456 \ No newline at end of file +- Closes #xxx +- Discussion #xxx +- Follow-up for PR #xxx +- https://discord.com/channels/xxx/xxx diff --git a/MEETING_SCHEDULE.md b/MEETING_SCHEDULE.md index e13d2c6deb..671da36fa1 100644 --- a/MEETING_SCHEDULE.md +++ b/MEETING_SCHEDULE.md @@ -3,6 +3,31 @@ Dear community! We're excited to announce bi-weekly office hours. +## #4 Login UI deepdive + +Dear community, + +We are back from the summer pause with interesting topics. +We will showcase the new Login UI, provide insights into the application's architecture, session API, packages, OIDC middleware, customization options and settings, and offer a look ahead at upcoming features. + +## What to expect: + +* **Architecture of the Login UI**: Explore how server-side and client-side components interact within the new Login UI and NextJS framework. +* **Session API**: Understand the workings of the Session API +* **OIDC middleware configuration**: Learn how OIDC functions with the new Login UI and the necessary steps for a complete flow. +* **Customization Options / Settings**: Discover how to personalize the login and which ZITADEL settings are implemented. +* **Outlook**: Gain insights into future features +* **Q&A** + +## Details: + +* **Target Audience**: Developers using ZITADEL / Contributors +* **Topic**: New login UI and repo +* **Duration**: about 1 hour +* **When**: Wednesday 14th of August 19:00 UTC +* **Platform**: ZITADEL Discrod Server (Join us here: https://discord.gg/zitadel-927474939156643850?event=1270661421952274442) + + ## #2 New Resources and Settings APIs **Shape the future of ZITADEL Let's redesign the API for a better developer experience!** diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index e75f045b8e..0f56ddb8ba 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -25,6 +25,18 @@ Tracing: # The endpoint of the otel collector endpoint Endpoint: "" #ZITADEL_TRACING_ENDPOINT +# Profiler enables capturing profiling data (CPU, Memory, ...) for performance analysis +Profiler: + # Choose one of "google" and "none" + # Depending on the type there are different configuration options + # for type 'google' + # ProjectID: google-project-id + # + # type 'none' or '' disables profiling + Type: none # ZITADEL_PROFILER_TYPE + # projectID for google + ProjectID: '' # ZITADEL_PROFILER_PROJECTID + Telemetry: # As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints. # Data is projected by ZITADEL even if Enabled is false. @@ -83,9 +95,17 @@ TLS: Cert: # ZITADEL_TLS_CERT # Header name of HTTP2 (incl. gRPC) calls from which the instance will be matched +# Deprecated: Use the InstanceHostHeaders instead HTTP2HostHeader: ":authority" # ZITADEL_HTTP2HOSTHEADER # Header name of HTTP1 calls from which the instance will be matched +# Deprecated: Use the InstanceHostHeaders instead HTTP1HostHeader: "host" # ZITADEL_HTTP1HOSTHEADER +# Ordered header name list, which will be used to match the instance +InstanceHostHeaders: # ZITADEL_INSTANCEHOSTHEADERS + - "x-zitadel-instance-host" +# Ordered header name list, which will be used as the public host +PublicHostHeaders: # ZITADEL_PUBLICHOSTHEADERS + - "x-zitadel-public-host" WebAuthNName: ZITADEL # ZITADEL_WEBAUTHNNAME @@ -350,6 +370,13 @@ OIDC: Path: /oauth/v2/keys # ZITADEL_OIDC_CUSTOMENDPOINTS_KEYS_PATH DeviceAuth: Path: /oauth/v2/device_authorization # ZITADEL_OIDC_CUSTOMENDPOINTS_DEVICEAUTH_PATH + DeviceAuth: + Lifetime: 5m # ZITADEL_OIDC_DEVICEAUTH_LIFETIME + PollInterval: 5s # ZITADEL_OIDC_DEVICEAUTH_POLLINTERVAL + UserCode: + CharSet: "BCDFGHJKLMNPQRSTVWXZ" # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARSET + CharAmount: 8 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARARMOUNT + DashInterval: 4 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_DASHINTERVAL DefaultLoginURLV2: "/login?authRequest=" # ZITADEL_OIDC_DEFAULTLOGINURLV2 DefaultLogoutURLV2: "/logout?post_logout_redirect=" # ZITADEL_OIDC_DEFAULTLOGOUTURLV2 PublicKeyCacheMaxAge: 24h # ZITADEL_OIDC_PUBLICKEYCACHEMAXAGE @@ -532,6 +559,10 @@ SystemDefaults: PublicKeyLifetime: 30h # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_PUBLICKEYLIFETIME # 8766h are 1 year CertificateLifetime: 8766h # ZITADEL_SYSTEMDEFAULTS_KEYCONFIG_CERTIFICATELIFETIME + # DefaultQueryLimit limits the number of items that can be queried in a single v3 API search request without explicitly passing a limit. + DefaultQueryLimit: 100 # ZITADEL_SYSTEMDEFAULTS_DEFAULTQUERYLIMIT + # MaxQueryLimit limits the number of items that can be queried in a single v3 API search request with explicitly passing a limit. + MaxQueryLimit: 1000 # ZITADEL_SYSTEMDEFAULTS_MAXQUERYLIMIT Actions: HTTP: @@ -712,8 +743,8 @@ DefaultInstance: SecondFactorCheckLifetime: 18h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_SECONDFACTORCHECKLIFETIME MultiFactorCheckLifetime: 12h # ZITADEL_DEFAULTINSTANCE_LOGINPOLICY_MULTIFACTORCHECKLIFETIME PrivacyPolicy: - TOSLink: https://zitadel.com/docs/legal/terms-of-service # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_TOSLINK - PrivacyLink: https://zitadel.com/docs/legal/privacy-policy # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_PRIVACYLINK + TOSLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_TOSLINK + PrivacyLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_PRIVACYLINK HelpLink: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_HELPLINK SupportEmail: "" # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_SUPPORTEMAIL DocsLink: https://zitadel.com/docs # ZITADEL_DEFAULTINSTANCE_PRIVACYPOLICY_DOCSLINK @@ -738,6 +769,19 @@ DefaultInstance: MaxOTPAttempts: 0 # ZITADEL_DEFAULTINSTANCE_LOCKOUTPOLICY_MAXOTPATTEMPTS ShouldShowLockoutFailure: true # ZITADEL_DEFAULTINSTANCE_LOCKOUTPOLICY_SHOULDSHOWLOCKOUTFAILURE EmailTemplate: CjwhZG9jdHlwZSBodG1sPgo8aHRtbCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSI+CjxoZWFkPgogIDx0aXRsZT4KCiAgPC90aXRsZT4KICA8IS0tW2lmICFtc29dPjwhLS0+CiAgPG1ldGEgaHR0cC1lcXVpdj0iWC1VQS1Db21wYXRpYmxlIiBjb250ZW50PSJJRT1lZGdlIj4KICA8IS0tPCFbZW5kaWZdLS0+CiAgPG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9VVRGLTgiPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgICNvdXRsb29rIGEgeyBwYWRkaW5nOjA7IH0KICAgIGJvZHkgeyBtYXJnaW46MDtwYWRkaW5nOjA7LXdlYmtpdC10ZXh0LXNpemUtYWRqdXN0OjEwMCU7LW1zLXRleHQtc2l6ZS1hZGp1c3Q6MTAwJTsgfQogICAgdGFibGUsIHRkIHsgYm9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO21zby10YWJsZS1sc3BhY2U6MHB0O21zby10YWJsZS1yc3BhY2U6MHB0OyB9CiAgICBpbWcgeyBib3JkZXI6MDtoZWlnaHQ6YXV0bztsaW5lLWhlaWdodDoxMDAlOyBvdXRsaW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uOm5vbmU7LW1zLWludGVycG9sYXRpb24tbW9kZTpiaWN1YmljOyB9CiAgICBwIHsgZGlzcGxheTpibG9jazttYXJnaW46MTNweCAwOyB9CiAgPC9zdHlsZT4KICA8IS0tW2lmIG1zb10+CiAgPHhtbD4KICAgIDxvOk9mZmljZURvY3VtZW50U2V0dGluZ3M+CiAgICAgIDxvOkFsbG93UE5HLz4KICAgICAgPG86UGl4ZWxzUGVySW5jaD45NjwvbzpQaXhlbHNQZXJJbmNoPgogICAgPC9vOk9mZmljZURvY3VtZW50U2V0dGluZ3M+CiAgPC94bWw+CiAgPCFbZW5kaWZdLS0+CiAgPCEtLVtpZiBsdGUgbXNvIDExXT4KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAgLm1qLW91dGxvb2stZ3JvdXAtZml4IHsgd2lkdGg6MTAwJSAhaW1wb3J0YW50OyB9CiAgPC9zdHlsZT4KICA8IVtlbmRpZl0tLT4KCgogIDxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CiAgICBAbWVkaWEgb25seSBzY3JlZW4gYW5kIChtaW4td2lkdGg6NDgwcHgpIHsKICAgICAgLm1qLWNvbHVtbi1wZXItMTAwIHsgd2lkdGg6MTAwJSAhaW1wb3J0YW50OyBtYXgtd2lkdGg6IDEwMCU7IH0KICAgICAgLm1qLWNvbHVtbi1wZXItNjAgeyB3aWR0aDo2MCUgIWltcG9ydGFudDsgbWF4LXdpZHRoOiA2MCU7IH0KICAgIH0KICA8L3N0eWxlPgoKCiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCgoKICAgIEBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDo0ODBweCkgewogICAgICB0YWJsZS5tai1mdWxsLXdpZHRoLW1vYmlsZSB7IHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7IH0KICAgICAgdGQubWotZnVsbC13aWR0aC1tb2JpbGUgeyB3aWR0aDogYXV0byAhaW1wb3J0YW50OyB9CiAgICB9CgogIDwvc3R5bGU+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc2hhZG93IGEgewogICAgYm94LXNoYWRvdzogMHB4IDNweCAxcHggLTJweCByZ2JhKDAsIDAsIDAsIDAuMiksIDBweCAycHggMnB4IDBweCByZ2JhKDAsIDAsIDAsIDAuMTQpLCAwcHggMXB4IDVweCAwcHggcmdiYSgwLCAwLCAwLCAwLjEyKTsKICB9PC9zdHlsZT4KCiAge3tpZiAuRm9udFVSTH19CiAgPHN0eWxlPgogICAgQGZvbnQtZmFjZSB7CiAgICAgIGZvbnQtZmFtaWx5OiAne3suRm9udEZhY2VGYW1pbHl9fSc7CiAgICAgIGZvbnQtc3R5bGU6IG5vcm1hbDsKICAgICAgZm9udC1kaXNwbGF5OiBzd2FwOwogICAgICBzcmM6IHVybCh7ey5Gb250VVJMfX0pOwogICAgfQogIDwvc3R5bGU+CiAge3tlbmR9fQoKPC9oZWFkPgo8Ym9keSBzdHlsZT0id29yZC1zcGFjaW5nOm5vcm1hbDsiPgoKCjxkaXYKICAgICAgICBzdHlsZT0iIgo+CgogIDx0YWJsZQogICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImJhY2tncm91bmQ6e3suQmFja2dyb3VuZENvbG9yfX07YmFja2dyb3VuZC1jb2xvcjp7ey5CYWNrZ3JvdW5kQ29sb3J9fTt3aWR0aDoxMDAlO2JvcmRlci1yYWRpdXM6MTZweDsiCiAgPgogICAgPHRib2R5PgogICAgPHRyPgogICAgICA8dGQ+CgoKICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIGNsYXNzPSIiIHN0eWxlPSJ3aWR0aDo4MDBweDsiIHdpZHRoPSI4MDAiID48dHI+PHRkIHN0eWxlPSJsaW5lLWhlaWdodDowcHg7Zm9udC1zaXplOjBweDttc28tbGluZS1oZWlnaHQtcnVsZTpleGFjdGx5OyI+PCFbZW5kaWZdLS0+CgoKICAgICAgICA8ZGl2ICBzdHlsZT0ibWFyZ2luOjBweCBhdXRvO2JvcmRlci1yYWRpdXM6MTZweDttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7Ym9yZGVyLXJhZGl1czoxNnB4OyIKICAgICAgICAgID4KICAgICAgICAgICAgPHRib2R5PgogICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICBzdHlsZT0iZGlyZWN0aW9uOmx0cjtmb250LXNpemU6MHB4O3BhZGRpbmc6MjBweCAwO3BhZGRpbmctbGVmdDowO3RleHQtYWxpZ246Y2VudGVyOyIKICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiB3aWR0aD0iODAwcHgiID48IVtlbmRpZl0tLT4KCiAgICAgICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7IgogICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQ+CgoKICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBhbGlnbj0iY2VudGVyIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9IiIgc3R5bGU9IndpZHRoOjgwMHB4OyIgd2lkdGg9IjgwMCIgPjx0cj48dGQgc3R5bGU9ImxpbmUtaGVpZ2h0OjBweDtmb250LXNpemU6MHB4O21zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7Ij48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgICAgPGRpdiAgc3R5bGU9Im1hcmdpbjowcHggYXV0bzttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImRpcmVjdGlvbjpsdHI7Zm9udC1zaXplOjBweDtwYWRkaW5nOjA7dGV4dC1hbGlnbjpjZW50ZXI7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiBzdHlsZT0id2lkdGg6ODAwcHg7IiA+PCFbZW5kaWZdLS0+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3M9Im1qLWNvbHVtbi1wZXItMTAwIG1qLW91dGxvb2stZ3JvdXAtZml4IiBzdHlsZT0iZm9udC1zaXplOjA7bGluZS1oZWlnaHQ6MDt0ZXh0LWFsaWduOmxlZnQ7ZGlzcGxheTppbmxpbmUtYmxvY2s7d2lkdGg6MTAwJTtkaXJlY3Rpb246bHRyOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiA+PHRyPjx0ZCBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wO3dpZHRoOjgwMHB4OyIgPjwhW2VuZGlmXS0tPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ZGl2CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz0ibWotY29sdW1uLXBlci0xMDAgbWotb3V0bG9vay1ncm91cC1maXgiIHN0eWxlPSJmb250LXNpemU6MHB4O3RleHQtYWxpZ246bGVmdDtkaXJlY3Rpb246bHRyO2Rpc3BsYXk6aW5saW5lLWJsb2NrO3ZlcnRpY2FsLWFsaWduOnRvcDt3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHdpZHRoPSIxMDAlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQgIHN0eWxlPSJ2ZXJ0aWNhbC1hbGlnbjp0b3A7cGFkZGluZzowOyI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e2lmIC5Mb2dvVVJMfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRib2R5PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzo1MHB4IDAgMzBweCAwO3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iYm9yZGVyLWNvbGxhcHNlOmNvbGxhcHNlO2JvcmRlci1zcGFjaW5nOjBweDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCAgc3R5bGU9IndpZHRoOjE4MHB4OyI+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGltZwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9ImF1dG8iIHNyYz0ie3suTG9nb1VSTH19IiBzdHlsZT0iYm9yZGVyOjA7Ym9yZGVyLXJhZGl1czo4cHg7ZGlzcGxheTpibG9jaztvdXRsaW5lOm5vbmU7dGV4dC1kZWNvcmF0aW9uOm5vbmU7aGVpZ2h0OmF1dG87d2lkdGg6MTAwJTtmb250LXNpemU6MTNweDsiIHdpZHRoPSIxODAiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3tlbmR9fQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj4KCgogICAgICAgICAgICAgICAgICAgICAgPCEtLVtpZiBtc28gfCBJRV0+PC90ZD48L3RyPjwvdGFibGU+PCFbZW5kaWZdLS0+CgoKICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PHRyPjx0ZCBjbGFzcz0iIiB3aWR0aD0iODAwcHgiID48IVtlbmRpZl0tLT4KCiAgICAgICAgICAgICAgICA8dGFibGUKICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9IndpZHRoOjEwMCU7IgogICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICA8dGQ+CgoKICAgICAgICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjx0YWJsZSBhbGlnbj0iY2VudGVyIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgY2xhc3M9IiIgc3R5bGU9IndpZHRoOjgwMHB4OyIgd2lkdGg9IjgwMCIgPjx0cj48dGQgc3R5bGU9ImxpbmUtaGVpZ2h0OjBweDtmb250LXNpemU6MHB4O21zby1saW5lLWhlaWdodC1ydWxlOmV4YWN0bHk7Ij48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgICAgPGRpdiAgc3R5bGU9Im1hcmdpbjowcHggYXV0bzttYXgtd2lkdGg6ODAwcHg7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgIDx0YWJsZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIGJvcmRlcj0iMCIgY2VsbHBhZGRpbmc9IjAiIGNlbGxzcGFjaW5nPSIwIiByb2xlPSJwcmVzZW50YXRpb24iIHN0eWxlPSJ3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgIDx0Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImRpcmVjdGlvbjpsdHI7Zm9udC1zaXplOjBweDtwYWRkaW5nOjA7dGV4dC1hbGlnbjpjZW50ZXI7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgcm9sZT0icHJlc2VudGF0aW9uIiBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCI+PHRyPjx0ZCBjbGFzcz0iIiBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wO3dpZHRoOjQ4MHB4OyIgPjwhW2VuZGlmXS0tPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPSJtai1jb2x1bW4tcGVyLTYwIG1qLW91dGxvb2stZ3JvdXAtZml4IiBzdHlsZT0iZm9udC1zaXplOjBweDt0ZXh0LWFsaWduOmxlZnQ7ZGlyZWN0aW9uOmx0cjtkaXNwbGF5OmlubGluZS1ibG9jazt2ZXJ0aWNhbC1hbGlnbjp0b3A7d2lkdGg6MTAwJTsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZCAgc3R5bGU9InZlcnRpY2FsLWFsaWduOnRvcDtwYWRkaW5nOjA7Ij4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iIiB3aWR0aD0iMTAwJSIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGJvZHk+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dGQKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbj0iY2VudGVyIiBzdHlsZT0iZm9udC1zaXplOjBweDtwYWRkaW5nOjEwcHggMjVweDt3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlPSJmb250LWZhbWlseTp7ey5Gb250RmFtaWx5fX07Zm9udC1zaXplOjI0cHg7Zm9udC13ZWlnaHQ6NTAwO2xpbmUtaGVpZ2h0OjE7dGV4dC1hbGlnbjpjZW50ZXI7Y29sb3I6e3suRm9udENvbG9yfX07IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID57ey5HcmVldGluZ319PC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJmb250LXNpemU6MHB4O3BhZGRpbmc6MTBweCAyNXB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5Ont7LkZvbnRGYW1pbHl9fTtmb250LXNpemU6MTZweDtmb250LXdlaWdodDpsaWdodDtsaW5lLWhlaWdodDoxLjU7dGV4dC1hbGlnbjpjZW50ZXI7Y29sb3I6e3suRm9udENvbG9yfX07IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID57ey5UZXh0fX08L2Rpdj4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8dHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0ZAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduPSJjZW50ZXIiIHZlcnRpY2FsLWFsaWduPSJtaWRkbGUiIGNsYXNzPSJzaGFkb3ciIHN0eWxlPSJmb250LXNpemU6MHB4O3BhZGRpbmc6MTBweCAyNXB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRhYmxlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3JkZXI9IjAiIGNlbGxwYWRkaW5nPSIwIiBjZWxsc3BhY2luZz0iMCIgcm9sZT0icHJlc2VudGF0aW9uIiBzdHlsZT0iYm9yZGVyLWNvbGxhcHNlOnNlcGFyYXRlO2xpbmUtaGVpZ2h0OjEwMCU7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgYmdjb2xvcj0ie3suUHJpbWFyeUNvbG9yfX0iIHJvbGU9InByZXNlbnRhdGlvbiIgc3R5bGU9ImJvcmRlcjpub25lO2JvcmRlci1yYWRpdXM6NnB4O2N1cnNvcjphdXRvO21zby1wYWRkaW5nLWFsdDoxMHB4IDI1cHg7YmFja2dyb3VuZDp7ey5QcmltYXJ5Q29sb3J9fTsiIHZhbGlnbj0ibWlkZGxlIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGEKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhyZWY9Int7LlVSTH19IiByZWw9Im5vb3BlbmVyIG5vcmVmZXJyZXIgbm90cmFjayIgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrO2JhY2tncm91bmQ6e3suUHJpbWFyeUNvbG9yfX07Y29sb3I6I2ZmZmZmZjtmb250LWZhbWlseTp7ey5Gb250RmFtaWx5fX07Zm9udC1zaXplOjE0cHg7Zm9udC13ZWlnaHQ6NTAwO2xpbmUtaGVpZ2h0OjEyMCU7bWFyZ2luOjA7dGV4dC1kZWNvcmF0aW9uOm5vbmU7dGV4dC10cmFuc2Zvcm06bm9uZTtwYWRkaW5nOjEwcHggMjVweDttc28tcGFkZGluZy1hbHQ6MHB4O2JvcmRlci1yYWRpdXM6NnB4OyIgdGFyZ2V0PSJfYmxhbmsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3suQnV0dG9uVGV4dH19CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9hPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90ZD4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7e2lmIC5JbmNsdWRlRm9vdGVyfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzoxMHB4IDI1cHg7cGFkZGluZy10b3A6MjBweDtwYWRkaW5nLXJpZ2h0OjIwcHg7cGFkZGluZy1ib3R0b206MjBweDtwYWRkaW5nLWxlZnQ6MjBweDt3b3JkLWJyZWFrOmJyZWFrLXdvcmQ7IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxwCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHlsZT0iYm9yZGVyLXRvcDpzb2xpZCAycHggI2RiZGJkYjtmb250LXNpemU6MXB4O21hcmdpbjowcHggYXV0bzt3aWR0aDoxMDAlOyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9wPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48dGFibGUgYWxpZ249ImNlbnRlciIgYm9yZGVyPSIwIiBjZWxscGFkZGluZz0iMCIgY2VsbHNwYWNpbmc9IjAiIHN0eWxlPSJib3JkZXItdG9wOnNvbGlkIDJweCAjZGJkYmRiO2ZvbnQtc2l6ZToxcHg7bWFyZ2luOjBweCBhdXRvO3dpZHRoOjQ0MHB4OyIgcm9sZT0icHJlc2VudGF0aW9uIiB3aWR0aD0iNDQwcHgiID48dHI+PHRkIHN0eWxlPSJoZWlnaHQ6MDtsaW5lLWhlaWdodDowOyI+ICZuYnNwOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgoKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDx0cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHRkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxpZ249ImNlbnRlciIgc3R5bGU9ImZvbnQtc2l6ZTowcHg7cGFkZGluZzoxNnB4O3dvcmQtYnJlYWs6YnJlYWstd29yZDsiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3R5bGU9ImZvbnQtZmFtaWx5Ont7LkZvbnRGYW1pbHl9fTtmb250LXNpemU6MTNweDtsaW5lLWhlaWdodDoxO3RleHQtYWxpZ246Y2VudGVyO2NvbG9yOnt7LkZvbnRDb2xvcn19OyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA+e3suRm9vdGVyVGV4dH19PC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RkPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt7ZW5kfX0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90YWJsZT4KCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RyPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC90Ym9keT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PC90YWJsZT48IVtlbmRpZl0tLT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgICAgICAgICAgPC90cj4KICAgICAgICAgICAgICAgICAgICAgICAgICA8L3Rib2R5PgogICAgICAgICAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgICAgICAgIDwvZGl2PgoKCiAgICAgICAgICAgICAgICAgICAgICA8IS0tW2lmIG1zbyB8IElFXT48L3RkPjwvdHI+PC90YWJsZT48IVtlbmRpZl0tLT4KCgogICAgICAgICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICAgICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgogICAgICAgICAgICAgIDwvdGQ+CiAgICAgICAgICAgIDwvdHI+CiAgICAgICAgICAgIDwvdGJvZHk+CiAgICAgICAgICA8L3RhYmxlPgoKICAgICAgICA8L2Rpdj4KCgogICAgICAgIDwhLS1baWYgbXNvIHwgSUVdPjwvdGQ+PC90cj48L3RhYmxlPjwhW2VuZGlmXS0tPgoKCiAgICAgIDwvdGQ+CiAgICA8L3RyPgogICAgPC90Ym9keT4KICA8L3RhYmxlPgoKPC9kaXY+Cgo8L2JvZHk+CjwvaHRtbD4K # ZITADEL_DEFAULTINSTANCE_EMAILTEMPLATE + + # WebKeys configures the OIDC token signing keys that are generated when a new instance is created. + # WebKeys are still in alpha, so the config is disabled here. This will prevent generation of keys for now. + # WebKeys: + # Type: "rsa" # ZITADEL_DEFAULTINSTANCE_WEBKEYS_TYPE + # Config: + # Bits: "2048" # ZITADEL_DEFAULTINSTANCE_WEBKEYS_CONFIG_BITS + # Hasher: "sha256" # ZITADEL_DEFAULTINSTANCE_WEBKEYS_CONFIG_HASHER + # WebKeys: + # Type: "ecdsa" + # Config: + # Curve: "P256" # ZITADEL_DEFAULTINSTANCE_WEBKEYS_CONFIG_CURVE + # Sets the default values for lifetime and expiration for OIDC in each newly created instance # This default can be overwritten for each instance during runtime # Overwrites the system defaults @@ -983,6 +1027,9 @@ InternalAuthZ: - "iam.feature.delete" - "iam.restrictions.read" - "iam.restrictions.write" + - "iam.web_key.write" + - "iam.web_key.delete" + - "iam.web_key.read" - "org.read" - "org.global.read" - "org.create" @@ -1041,12 +1088,11 @@ InternalAuthZ: - "events.read" - "milestones.read" - "session.delete" - - "execution.target.read" - - "execution.target.write" - - "execution.target.delete" - - "execution.read" - - "execution.write" - - "execution.delete" + - "action.target.read" + - "action.target.write" + - "action.target.delete" + - "action.execution.read" + - "action.execution.write" - "userschema.read" - "userschema.write" - "userschema.delete" @@ -1060,6 +1106,7 @@ InternalAuthZ: - "iam.flow.read" - "iam.restrictions.read" - "iam.feature.read" + - "iam.web_key.read" - "org.read" - "org.member.read" - "org.idp.read" @@ -1080,8 +1127,8 @@ InternalAuthZ: - "project.grant.member.read" - "events.read" - "milestones.read" - - "execution.target.read" - - "execution.read" + - "action.target.read" + - "action.execution.read" - "userschema.read" - Role: "IAM_ORG_MANAGER" Permissions: diff --git a/cmd/initialise/config.go b/cmd/initialise/config.go index b3499ea7ad..3fe7173860 100644 --- a/cmd/initialise/config.go +++ b/cmd/initialise/config.go @@ -1,6 +1,7 @@ package initialise import ( + "github.com/mitchellh/mapstructure" "github.com/spf13/viper" "github.com/zitadel/logging" @@ -17,7 +18,10 @@ type Config struct { func MustNewConfig(v *viper.Viper) *Config { config := new(Config) err := v.Unmarshal(config, - viper.DecodeHook(database.DecodeHook), + viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( + database.DecodeHook, + mapstructure.TextUnmarshallerHookFunc(), + )), ) logging.OnError(err).Fatal("unable to read config") diff --git a/cmd/mirror/config.go b/cmd/mirror/config.go index 5d2ec8fac7..cc98000869 100644 --- a/cmd/mirror/config.go +++ b/cmd/mirror/config.go @@ -74,6 +74,7 @@ func mustNewConfig(v *viper.Viper, config any) { database.DecodeHook, actions.HTTPConfigDecodeHook, hook.EnumHookFunc(internal_authz.MemberTypeString), + mapstructure.TextUnmarshallerHookFunc(), )), ) logging.OnError(err).Fatal("unable to read default config") diff --git a/cmd/mirror/event_store.go b/cmd/mirror/event_store.go index 358f878d77..23145bdc37 100644 --- a/cmd/mirror/event_store.go +++ b/cmd/mirror/event_store.go @@ -44,7 +44,7 @@ Migrate only copies events2 and unique constraints`, } func copyEventstore(ctx context.Context, config *Migration) { - sourceClient, err := db.Connect(config.Source, false, dialect.DBPurposeQuery) + sourceClient, err := db.Connect(config.Source, false, dialect.DBPurposeEventPusher) logging.OnError(err).Fatal("unable to connect to source database") defer sourceClient.Close() diff --git a/cmd/ready/config.go b/cmd/ready/config.go index aaa7e2d7ee..f5067c562e 100644 --- a/cmd/ready/config.go +++ b/cmd/ready/config.go @@ -27,6 +27,7 @@ func MustNewConfig(v *viper.Viper) *Config { mapstructure.StringToTimeHookFunc(time.RFC3339), mapstructure.StringToSliceHookFunc(","), hook.EnumHookFunc(internal_authz.MemberTypeString), + mapstructure.TextUnmarshallerHookFunc(), )), ) logging.OnError(err).Fatal("unable to read default config") diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 2bee4642aa..6ac1767ca6 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -74,6 +74,7 @@ func MustNewConfig(v *viper.Viper) *Config { mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToTimeHookFunc(time.RFC3339), mapstructure.StringToSliceHookFunc(","), + mapstructure.TextUnmarshallerHookFunc(), )), ) logging.OnError(err).Fatal("unable to read default config") @@ -139,6 +140,7 @@ func MustNewSteps(v *viper.Viper) *Steps { mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToTimeHookFunc(time.RFC3339), mapstructure.StringToSliceHookFunc(","), + mapstructure.TextUnmarshallerHookFunc(), )), ) logging.OnError(err).Fatal("unable to read steps") diff --git a/cmd/start/config.go b/cmd/start/config.go index c96386521f..1e36d3310a 100644 --- a/cmd/start/config.go +++ b/cmd/start/config.go @@ -31,44 +31,48 @@ import ( "github.com/zitadel/zitadel/internal/query/projection" static_config "github.com/zitadel/zitadel/internal/static/config" metrics "github.com/zitadel/zitadel/internal/telemetry/metrics/config" + profiler "github.com/zitadel/zitadel/internal/telemetry/profiler/config" tracing "github.com/zitadel/zitadel/internal/telemetry/tracing/config" ) type Config struct { - Log *logging.Config - Port uint16 - ExternalPort uint16 - ExternalDomain string - ExternalSecure bool - TLS network.TLS - HTTP2HostHeader string - HTTP1HostHeader string - WebAuthNName string - Database database.Config - Tracing tracing.Config - Metrics metrics.Config - Projections projection.Config - Auth auth_es.Config - Admin admin_es.Config - UserAgentCookie *middleware.UserAgentCookieConfig - OIDC oidc.Config - SAML saml.Config - Login login.Config - Console console.Config - AssetStorage static_config.AssetStorageConfig - InternalAuthZ internal_authz.Config - SystemDefaults systemdefaults.SystemDefaults - EncryptionKeys *encryption.EncryptionKeyConfig - DefaultInstance command.InstanceSetup - AuditLogRetention time.Duration - SystemAPIUsers map[string]*internal_authz.SystemAPIUser - CustomerPortal string - Machine *id.Config - Actions *actions.Config - Eventstore *eventstore.Config - LogStore *logstore.Configs - Quotas *QuotasConfig - Telemetry *handlers.TelemetryPusherConfig + Log *logging.Config + Port uint16 + ExternalPort uint16 + ExternalDomain string + ExternalSecure bool + TLS network.TLS + InstanceHostHeaders []string + PublicHostHeaders []string + HTTP2HostHeader string + HTTP1HostHeader string + WebAuthNName string + Database database.Config + Tracing tracing.Config + Metrics metrics.Config + Profiler profiler.Config + Projections projection.Config + Auth auth_es.Config + Admin admin_es.Config + UserAgentCookie *middleware.UserAgentCookieConfig + OIDC oidc.Config + SAML saml.Config + Login login.Config + Console console.Config + AssetStorage static_config.AssetStorageConfig + InternalAuthZ internal_authz.Config + SystemDefaults systemdefaults.SystemDefaults + EncryptionKeys *encryption.EncryptionKeyConfig + DefaultInstance command.InstanceSetup + AuditLogRetention time.Duration + SystemAPIUsers map[string]*internal_authz.SystemAPIUser + CustomerPortal string + Machine *id.Config + Actions *actions.Config + Eventstore *eventstore.Config + LogStore *logstore.Configs + Quotas *QuotasConfig + Telemetry *handlers.TelemetryPusherConfig } type QuotasConfig struct { @@ -98,6 +102,7 @@ func MustNewConfig(v *viper.Viper) *Config { mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToTimeHookFunc(time.RFC3339), mapstructure.StringToSliceHookFunc(","), + mapstructure.TextUnmarshallerHookFunc(), )), ) logging.OnError(err).Fatal("unable to read config") @@ -111,6 +116,9 @@ func MustNewConfig(v *viper.Viper) *Config { err = config.Metrics.NewMeter() logging.OnError(err).Fatal("unable to set meter") + err = config.Profiler.NewProfiler() + logging.OnError(err).Fatal("unable to set profiler") + id.Configure(config.Machine) actions.SetHTTPConfig(&config.Actions.HTTP) diff --git a/cmd/start/start.go b/cmd/start/start.go index 0969c5388a..0ecff76a9b 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -34,16 +34,18 @@ import ( "github.com/zitadel/zitadel/internal/api" "github.com/zitadel/zitadel/internal/api/assets" internal_authz "github.com/zitadel/zitadel/internal/api/authz" - action_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/action/v3alpha" "github.com/zitadel/zitadel/internal/api/grpc/admin" "github.com/zitadel/zitadel/internal/api/grpc/auth" feature_v2 "github.com/zitadel/zitadel/internal/api/grpc/feature/v2" feature_v2beta "github.com/zitadel/zitadel/internal/api/grpc/feature/v2beta" + idp_v2 "github.com/zitadel/zitadel/internal/api/grpc/idp/v2" "github.com/zitadel/zitadel/internal/api/grpc/management" oidc_v2 "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2" oidc_v2beta "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2beta" org_v2 "github.com/zitadel/zitadel/internal/api/grpc/org/v2" org_v2beta "github.com/zitadel/zitadel/internal/api/grpc/org/v2beta" + action_v3_alpha "github.com/zitadel/zitadel/internal/api/grpc/resources/action/v3alpha" + "github.com/zitadel/zitadel/internal/api/grpc/resources/webkey/v3" session_v2 "github.com/zitadel/zitadel/internal/api/grpc/session/v2" session_v2beta "github.com/zitadel/zitadel/internal/api/grpc/session/v2beta" settings_v2 "github.com/zitadel/zitadel/internal/api/grpc/settings/v2" @@ -59,6 +61,7 @@ import ( "github.com/zitadel/zitadel/internal/api/robots_txt" "github.com/zitadel/zitadel/internal/api/saml" "github.com/zitadel/zitadel/internal/api/ui/console" + "github.com/zitadel/zitadel/internal/api/ui/console/path" "github.com/zitadel/zitadel/internal/api/ui/login" auth_es "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing" "github.com/zitadel/zitadel/internal/authz" @@ -346,7 +349,7 @@ func startAPIs( } oidcPrefixes := []string{"/.well-known/openid-configuration", "/oidc/v1", "/oauth/v2"} // always set the origin in the context if available in the http headers, no matter for what protocol - router.Use(middleware.WithOrigin(config.ExternalSecure)) + router.Use(middleware.WithOrigin(config.ExternalSecure, config.HTTP1HostHeader, config.HTTP2HostHeader, config.InstanceHostHeaders, config.PublicHostHeaders)) systemTokenVerifier, err := internal_authz.StartSystemTokenVerifierFromConfig(http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure), config.SystemAPIUsers) if err != nil { return nil, err @@ -374,7 +377,7 @@ func startAPIs( http_util.WithMaxAge(int(math.Floor(config.Quotas.Access.ExhaustedCookieMaxAge.Seconds()))), ) limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, &config.Quotas.Access.AccessConfig) - apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.HTTP2HostHeader, config.HTTP1HostHeader, config.ExternalDomain, limitingAccessInterceptor) + apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.ExternalDomain, append(config.InstanceHostHeaders, config.PublicHostHeaders...), limitingAccessInterceptor) if err != nil { return nil, fmt.Errorf("error creating api %w", err) } @@ -396,25 +399,25 @@ func startAPIs( if err := apis.RegisterServer(ctx, system.CreateServer(commands, queries, config.Database.DatabaseName(), config.DefaultInstance, config.ExternalDomain), tlsConfig); err != nil { return nil, err } - if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, config.SystemDefaults, config.ExternalSecure, keys.User, config.AuditLogRetention), tlsConfig); err != nil { + if err := apis.RegisterServer(ctx, admin.CreateServer(config.Database.DatabaseName(), commands, queries, keys.User, config.AuditLogRetention), tlsConfig); err != nil { return nil, err } - if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User, config.ExternalSecure), tlsConfig); err != nil { + if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, keys.User), tlsConfig); err != nil { return nil, err } - if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User, config.ExternalSecure), tlsConfig); err != nil { + if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, keys.User), tlsConfig); err != nil { return nil, err } - if err := apis.RegisterService(ctx, user_v2beta.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(config.ExternalSecure), idp.SAMLRootURL(config.ExternalSecure), assets.AssetAPI(config.ExternalSecure), permissionCheck)); err != nil { + if err := apis.RegisterService(ctx, user_v2beta.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(), idp.SAMLRootURL(), assets.AssetAPI(), permissionCheck)); err != nil { return nil, err } - if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(config.ExternalSecure), idp.SAMLRootURL(config.ExternalSecure), assets.AssetAPI(config.ExternalSecure), permissionCheck)); err != nil { + if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(), idp.SAMLRootURL(), assets.AssetAPI(), permissionCheck)); err != nil { return nil, err } if err := apis.RegisterService(ctx, session_v2beta.CreateServer(commands, queries)); err != nil { return nil, err } - if err := apis.RegisterService(ctx, settings_v2beta.CreateServer(commands, queries, config.ExternalSecure)); err != nil { + if err := apis.RegisterService(ctx, settings_v2beta.CreateServer(commands, queries)); err != nil { return nil, err } if err := apis.RegisterService(ctx, org_v2beta.CreateServer(commands, queries, permissionCheck)); err != nil { @@ -426,7 +429,7 @@ func startAPIs( if err := apis.RegisterService(ctx, session_v2.CreateServer(commands, queries)); err != nil { return nil, err } - if err := apis.RegisterService(ctx, settings_v2.CreateServer(commands, queries, config.ExternalSecure)); err != nil { + if err := apis.RegisterService(ctx, settings_v2.CreateServer(commands, queries)); err != nil { return nil, err } if err := apis.RegisterService(ctx, org_v2.CreateServer(commands, queries, permissionCheck)); err != nil { @@ -435,17 +438,23 @@ func startAPIs( if err := apis.RegisterService(ctx, feature_v2.CreateServer(commands, queries)); err != nil { return nil, err } - if err := apis.RegisterService(ctx, action_v3_alpha.CreateServer(commands, queries, domain.AllFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil { + if err := apis.RegisterService(ctx, idp_v2.CreateServer(commands, queries, permissionCheck)); err != nil { + return nil, err + } + if err := apis.RegisterService(ctx, action_v3_alpha.CreateServer(config.SystemDefaults, commands, queries, domain.AllFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil { return nil, err } if err := apis.RegisterService(ctx, user_schema_v3_alpha.CreateServer(commands, queries)); err != nil { return nil, err } - instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader, config.ExternalDomain, login.IgnoreInstanceEndpoints...) + if err := apis.RegisterService(ctx, webkey.CreateServer(commands, queries)); err != nil { + return nil, err + } + instanceInterceptor := middleware.InstanceInterceptor(queries, config.ExternalDomain, login.IgnoreInstanceEndpoints...) assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge) apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle)) - apis.RegisterHandlerOnPrefix(idp.HandlerPrefix, idp.NewHandler(commands, queries, keys.IDPConfig, config.ExternalSecure, instanceInterceptor.Handler)) + apis.RegisterHandlerOnPrefix(idp.HandlerPrefix, idp.NewHandler(commands, queries, keys.IDPConfig, instanceInterceptor.Handler)) userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, id.SonyFlakeGenerator(), config.ExternalSecure, login.EndpointResources, login.EndpointExternalLoginCallbackFormPost, login.EndpointSAMLACS) if err != nil { @@ -482,8 +491,8 @@ func startAPIs( if err != nil { return nil, fmt.Errorf("unable to start console: %w", err) } - apis.RegisterHandlerOnPrefix(console.HandlerPrefix, c) - consolePath := console.HandlerPrefix + "/" + apis.RegisterHandlerOnPrefix(path.HandlerPrefix, c) + consolePath := path.HandlerPrefix + "/" l, err := login.CreateLogin( config.Login, commands, diff --git a/console/package.json b/console/package.json index 70390d87e1..524ebe833f 100644 --- a/console/package.json +++ b/console/package.json @@ -28,8 +28,8 @@ "@fortawesome/angular-fontawesome": "^0.13.0", "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-brands-svg-icons": "^6.4.2", - "@grpc/grpc-js": "^1.9.3", - "@netlify/framework-info": "^9.8.10", + "@grpc/grpc-js": "^1.11.1", + "@netlify/framework-info": "^9.8.13", "@ngx-translate/core": "^15.0.0", "angular-oauth2-oidc": "^15.0.1", "angularx-qrcode": "^16.0.0", @@ -42,7 +42,7 @@ "google-protobuf": "^3.21.2", "grpc-web": "^1.4.1", "i18n-iso-countries": "^7.7.0", - "libphonenumber-js": "^1.10.49", + "libphonenumber-js": "^1.11.4", "material-design-icons-iconfont": "^6.1.1", "moment": "^2.29.4", "ngx-color": "^9.0.0", @@ -50,7 +50,7 @@ "rxjs": "~7.8.0", "tinycolor2": "^1.6.0", "tslib": "^2.6.2", - "uuid": "^9.0.1", + "uuid": "^10.0.0", "zone.js": "~0.13.3" }, "devDependencies": { @@ -60,24 +60,24 @@ "@angular-eslint/eslint-plugin-template": "16.2.0", "@angular-eslint/schematics": "16.2.0", "@angular-eslint/template-parser": "16.2.0", - "@angular/cli": "^16.2.2", + "@angular/cli": "^16.2.14", "@angular/compiler-cli": "^16.2.5", "@angular/language-service": "^16.2.5", - "@bufbuild/buf": "^1.23.1", + "@bufbuild/buf": "^1.34.0", "@types/file-saver": "^2.0.7", "@types/google-protobuf": "^3.15.3", "@types/jasmine": "~5.1.4", "@types/jasminewd2": "~2.0.13", - "@types/jsonwebtoken": "^9.0.5", + "@types/jsonwebtoken": "^9.0.6", "@types/node": "^20.7.0", "@types/opentype.js": "^1.3.8", "@types/qrcode": "^1.5.2", - "@types/uuid": "^9.0.7", - "@typescript-eslint/eslint-plugin": "^5.59.11", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.60.1", "codelyzer": "^6.0.2", "eslint": "^8.50.0", - "jasmine-core": "~4.6.0", + "jasmine-core": "~5.2.0", "jasmine-spec-reporter": "~7.0.0", "karma": "^6.4.2", "karma-chrome-launcher": "^3.2.0", diff --git a/console/src/app/modules/app-card/app-card.component.html b/console/src/app/modules/app-card/app-card.component.html index a6cc480ac6..6840e4e28e 100644 --- a/console/src/app/modules/app-card/app-card.component.html +++ b/console/src/app/modules/app-card/app-card.component.html @@ -6,7 +6,7 @@ useragent: type === OIDCAppType.OIDC_APP_TYPE_USER_AGENT, native: type === OIDCAppType.OIDC_APP_TYPE_NATIVE, api: isApiApp, - saml: type === 'SAML' + saml: type === 'SAML', }" > diff --git a/console/src/app/modules/avatar/avatar.component.html b/console/src/app/modules/avatar/avatar.component.html index 7be0728c83..94461ab01f 100644 --- a/console/src/app/modules/avatar/avatar.component.html +++ b/console/src/app/modules/avatar/avatar.component.html @@ -9,7 +9,7 @@ fontSize: fontSize - 1 + 'px', fontWeight: fontWeight, background: (themeService.isDarkTheme | async) ? color[900] : color[300], - color: (themeService.isDarkTheme | async) ? color[200] : color[900] + color: (themeService.isDarkTheme | async) ? color[200] : color[900], }" [ngClass]="{ active: active }" > diff --git a/console/src/app/modules/display-json-dialog/display-json-dialog.component.html b/console/src/app/modules/display-json-dialog/display-json-dialog.component.html index 1e38fd5c52..24df49a959 100644 --- a/console/src/app/modules/display-json-dialog/display-json-dialog.component.html +++ b/console/src/app/modules/display-json-dialog/display-json-dialog.component.html @@ -66,8 +66,8 @@ mode: { name: 'javascript', json: true, - statementIndent: 2 - } + statementIndent: 2, + }, }" > diff --git a/console/src/app/modules/idp-table/idp-table.component.html b/console/src/app/modules/idp-table/idp-table.component.html index db4f04216b..7188040897 100644 --- a/console/src/app/modules/idp-table/idp-table.component.html +++ b/console/src/app/modules/idp-table/idp-table.component.html @@ -101,7 +101,7 @@ class="state" [ngClass]="{ active: idp.state === IDPState.IDP_STATE_ACTIVE, - inactive: idp.state === IDPState.IDP_STATE_INACTIVE + inactive: idp.state === IDPState.IDP_STATE_INACTIVE, }" >{{ 'IDP.STATES.' + idp.state | translate }} @@ -142,7 +142,7 @@ ? 'iam.idp.write' : serviceType === PolicyComponentServiceType.MGMT ? 'org.idp.write' - : '' + : '', ] | hasRole | async) === false @@ -162,7 +162,7 @@ ? 'iam.idp.write' : serviceType === PolicyComponentServiceType.MGMT ? 'org.idp.write' - : '' + : '', ] | hasRole | async) === false @@ -186,7 +186,7 @@ ? 'iam.idp.write' : serviceType === PolicyComponentServiceType.MGMT ? 'org.idp.write' - : '' + : '', ] | hasRole | async) === false diff --git a/console/src/app/modules/info-row/info-row.component.html b/console/src/app/modules/info-row/info-row.component.html index 6824d2e2d1..db68931eeb 100644 --- a/console/src/app/modules/info-row/info-row.component.html +++ b/console/src/app/modules/info-row/info-row.component.html @@ -6,7 +6,7 @@ class="state" [ngClass]="{ active: user.state === UserState.USER_STATE_ACTIVE, - inactive: user.state === UserState.USER_STATE_INACTIVE + inactive: user.state === UserState.USER_STATE_INACTIVE, }" > {{ 'USER.DATA.STATE' + user.state | translate }} @@ -57,7 +57,7 @@ class="state" [ngClass]="{ active: instance.state === State.INSTANCE_STATE_RUNNING, - inactive: instance.state === State.INSTANCE_STATE_STOPPED || instance.state === State.INSTANCE_STATE_STOPPING + inactive: instance.state === State.INSTANCE_STATE_STOPPED || instance.state === State.INSTANCE_STATE_STOPPING, }" > {{ 'IAM.STATE.' + instance.state | translate }} @@ -164,7 +164,7 @@ class="state" [ngClass]="{ active: project.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE, }" > {{ 'PROJECT.STATE.' + project.state | translate }} @@ -199,7 +199,7 @@ class="state" [ngClass]="{ active: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE, - inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE + inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE, }" > {{ 'PROJECT.STATE.' + grantedProject.state | translate }} diff --git a/console/src/app/modules/info-section/info-section.component.html b/console/src/app/modules/info-section/info-section.component.html index 277944ba51..b27fdea148 100644 --- a/console/src/app/modules/info-section/info-section.component.html +++ b/console/src/app/modules/info-section/info-section.component.html @@ -5,7 +5,7 @@ warn: type === 'WARN', alert: type === 'ALERT', success: type === 'SUCCESS', - fit: fitWidth + fit: fitWidth, }" > diff --git a/console/src/app/modules/onboarding/onboarding.component.html b/console/src/app/modules/onboarding/onboarding.component.html index 60398abb74..ea89494051 100644 --- a/console/src/app/modules/onboarding/onboarding.component.html +++ b/console/src/app/modules/onboarding/onboarding.component.html @@ -64,14 +64,14 @@
diff --git a/console/src/app/modules/org-context/org-context.component.html b/console/src/app/modules/org-context/org-context.component.html index 154cb0dbd7..9c0bf6b1e4 100644 --- a/console/src/app/modules/org-context/org-context.component.html +++ b/console/src/app/modules/org-context/org-context.component.html @@ -21,7 +21,7 @@ mat-button [ngClass]="{ active: pinnedorg.id === org.id, - 'border-bottom': pinned.selected.length && i === pinned.selected.length - 1 + 'border-bottom': pinned.selected.length && i === pinned.selected.length - 1, }" [disabled]="!pinnedorg.id" *ngFor="let pinnedorg of pinned.selected; index as i" diff --git a/console/src/app/modules/org-table/org-table.component.html b/console/src/app/modules/org-table/org-table.component.html index b16310d1d8..042988054b 100644 --- a/console/src/app/modules/org-table/org-table.component.html +++ b/console/src/app/modules/org-table/org-table.component.html @@ -70,7 +70,7 @@ class="state" [ngClass]="{ active: org.state === OrgState.ORG_STATE_ACTIVE, - inactive: org.state === OrgState.ORG_STATE_INACTIVE + inactive: org.state === OrgState.ORG_STATE_INACTIVE, }" *ngIf="org.state" >{{ 'ORG.STATE.' + org.state | translate }}{{ 'SETTING.SMS.SMSPROVIDERSTATE.' + twilio.state | translate }} diff --git a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html index 5f78230409..13c154b1cf 100644 --- a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html +++ b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html @@ -48,7 +48,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -152,7 +152,7 @@ ? 'iam.policy.delete' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.delete' - : '' + : '', ] | hasRole | async) === false @@ -176,7 +176,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -243,7 +243,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -273,7 +273,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -314,7 +314,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -344,7 +344,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -387,7 +387,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -409,7 +409,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -432,7 +432,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -455,7 +455,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -482,7 +482,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -504,7 +504,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -527,7 +527,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -549,7 +549,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -594,7 +594,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -632,7 +632,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -671,7 +671,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false @@ -699,7 +699,7 @@ ? 'iam.policy.write' : serviceType === PolicyComponentServiceType.MGMT ? 'policy.write' - : '' + : '', ] | hasRole | async) === false diff --git a/console/src/app/modules/project-members/project-members.component.html b/console/src/app/modules/project-members/project-members.component.html index 4be94376c1..9f42d32c37 100644 --- a/console/src/app/modules/project-members/project-members.component.html +++ b/console/src/app/modules/project-members/project-members.component.html @@ -24,7 +24,7 @@ ? $any(project)?.id : projectType === ProjectType.PROJECTTYPE_GRANTED ? $any(project)?.projectId - : '' + : '', ] | hasRole | async @@ -36,7 +36,7 @@ ? $any(project)?.id : projectType === ProjectType.PROJECTTYPE_GRANTED ? $any(project)?.projectId - : '' + : '', ] | hasRole | async @@ -52,7 +52,7 @@ : projectType === ProjectType.PROJECTTYPE_GRANTED ? $any(project)?.projectId : '', - 'project.member.delete' + 'project.member.delete', ]" >
@@ -85,7 +85,7 @@ matTooltip="{{ 'PROJECT.STATE.' + shortcut.state | translate }}" [ngClass]="{ active: shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: shortcut.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: shortcut.state === ProjectState.PROJECT_STATE_INACTIVE, }" >
@@ -124,7 +124,7 @@ matTooltip="{{ 'PROJECT.STATE.' + shortcut.state | translate }}" [ngClass]="{ active: shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: shortcut.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: shortcut.state === ProjectState.PROJECT_STATE_INACTIVE, }" > @@ -174,7 +174,7 @@ matTooltip="{{ 'PROJECT.STATE.' + shortcut.state | translate }}" [ngClass]="{ active: shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: shortcut.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: shortcut.state === ProjectState.PROJECT_STATE_INACTIVE, }" > diff --git a/console/src/app/modules/smtp-table/smtp-table.component.html b/console/src/app/modules/smtp-table/smtp-table.component.html index 91d244f8b1..3359eda596 100644 --- a/console/src/app/modules/smtp-table/smtp-table.component.html +++ b/console/src/app/modules/smtp-table/smtp-table.component.html @@ -12,7 +12,7 @@ '/instance/smtpprovider/sendgrid/create', '/instance/smtpprovider/mailchimp/create', '/instance/smtpprovider/brevo/create', - '/instance/smtpprovider/outlook/create' + '/instance/smtpprovider/outlook/create', ]" [timestamp]="configsResult?.details?.viewTimestamp" [selection]="selection" diff --git a/console/src/app/pages/actions/action-table/action-table.component.html b/console/src/app/pages/actions/action-table/action-table.component.html index 1f68faa6f4..a54a97379c 100644 --- a/console/src/app/pages/actions/action-table/action-table.component.html +++ b/console/src/app/pages/actions/action-table/action-table.component.html @@ -71,7 +71,7 @@ class="state" [ngClass]="{ active: action.state === ActionState.ACTION_STATE_ACTIVE, - inactive: action.state === ActionState.ACTION_STATE_INACTIVE + inactive: action.state === ActionState.ACTION_STATE_INACTIVE, }" > {{ 'FLOWS.STATES.' + action.state | translate }} {{ 'FLOWS.STATES.' + action.state | translate }} diff --git a/console/src/app/pages/grants/grants.component.html b/console/src/app/pages/grants/grants.component.html index 03a5c2ca90..5eef251b5f 100644 --- a/console/src/app/pages/grants/grants.component.html +++ b/console/src/app/pages/grants/grants.component.html @@ -18,7 +18,7 @@ 'creationDate', 'changeDate', 'roleNamesList', - 'actions' + 'actions', ]" [disableWrite]="(['user.grant.write$'] | hasRole | async) === false" [disableDelete]="(['user.grant.delete$'] | hasRole | async) === false" diff --git a/console/src/app/pages/home/home.component.html b/console/src/app/pages/home/home.component.html index 6eee775556..c5c3485ea9 100644 --- a/console/src/app/pages/home/home.component.html +++ b/console/src/app/pages/home/home.component.html @@ -21,14 +21,14 @@
@@ -45,14 +45,14 @@
@@ -69,14 +69,14 @@
diff --git a/console/src/app/pages/projects/apps/app-create/app-create.component.html b/console/src/app/pages/projects/apps/app-create/app-create.component.html index af6a5328ed..2e6787b036 100644 --- a/console/src/app/pages/projects/apps/app-create/app-create.component.html +++ b/console/src/app/pages/projects/apps/app-create/app-create.component.html @@ -233,7 +233,7 @@ [options]="{ lineNumbers: true, theme: 'material', - mode: 'application/xml' + mode: 'application/xml', }" >
@@ -524,7 +524,7 @@ [options]="{ lineNumbers: true, theme: 'material', - mode: 'application/xml' + mode: 'application/xml', }" >
diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html index 0f795200b1..c034af991e 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html @@ -218,7 +218,7 @@ [options]="{ lineNumbers: true, theme: 'material', - mode: 'application/xml' + mode: 'application/xml', }" >
diff --git a/console/src/app/pages/projects/owned-projects/owned-project-detail/applications/applications.component.html b/console/src/app/pages/projects/owned-projects/owned-project-detail/applications/applications.component.html index 1feee4cc93..e8d93a6654 100644 --- a/console/src/app/pages/projects/owned-projects/owned-project-detail/applications/applications.component.html +++ b/console/src/app/pages/projects/owned-projects/owned-project-detail/applications/applications.component.html @@ -65,7 +65,7 @@ class="state" [ngClass]="{ active: app.state === AppState.APP_STATE_ACTIVE, - inactive: app.state === AppState.APP_STATE_INACTIVE + inactive: app.state === AppState.APP_STATE_INACTIVE, }" > {{ 'APP.PAGES.DETAIL.STATE.' + app?.state | translate }} diff --git a/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-illustration/project-grant-illustration.component.html b/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-illustration/project-grant-illustration.component.html index fa1829ab45..7966dc21f2 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-illustration/project-grant-illustration.component.html +++ b/console/src/app/pages/projects/owned-projects/project-grant-detail/project-grant-illustration/project-grant-illustration.component.html @@ -30,7 +30,7 @@ matTooltip="{{ 'PROJECT.STATE.' + grantedProject.state | translate }}" [ngClass]="{ active: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE, - inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE + inactive: grantedProject.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE, }" >
diff --git a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html index 92d4459525..07d5baaa8c 100644 --- a/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html +++ b/console/src/app/pages/projects/owned-projects/project-grants/project-grants.component.html @@ -104,7 +104,7 @@ class="state" [ngClass]="{ active: grant.state === ProjectGrantState.PROJECT_GRANT_STATE_ACTIVE, - inactive: grant.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE + inactive: grant.state === ProjectGrantState.PROJECT_GRANT_STATE_INACTIVE, }" > {{ 'PROJECT.GRANT.STATES.' + grant.state | translate }} diff --git a/console/src/app/pages/projects/project-grid/project-grid.component.html b/console/src/app/pages/projects/project-grid/project-grid.component.html index df618192ed..9cbc1f9e96 100644 --- a/console/src/app/pages/projects/project-grid/project-grid.component.html +++ b/console/src/app/pages/projects/project-grid/project-grid.component.html @@ -24,7 +24,7 @@ class="state-dot" [ngClass]="{ active: item.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: item.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: item.state === ProjectState.PROJECT_STATE_INACTIVE, }" >
@@ -62,7 +62,7 @@ class="state-dot" [ngClass]="{ active: item.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: item.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: item.state === ProjectState.PROJECT_STATE_INACTIVE, }" > diff --git a/console/src/app/pages/projects/project-list/project-list.component.html b/console/src/app/pages/projects/project-list/project-list.component.html index 77c340b1cd..d51d9f9ba2 100644 --- a/console/src/app/pages/projects/project-list/project-list.component.html +++ b/console/src/app/pages/projects/project-list/project-list.component.html @@ -95,7 +95,7 @@ class="state" [ngClass]="{ active: project.state === ProjectState.PROJECT_STATE_ACTIVE, - inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE + inactive: project.state === ProjectState.PROJECT_STATE_INACTIVE, }" *ngIf="project.state" >{{ 'PROJECT.STATE.' + project.state | translate }}{{ 'USER.PASSWORDLESS.STATE.' + mfa.state | translate }} diff --git a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.html b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.html index 3e1705f81a..04cc701c08 100644 --- a/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.html +++ b/console/src/app/pages/users/user-detail/auth-user-detail/auth-user-mfa/auth-user-mfa.component.html @@ -57,7 +57,7 @@ class="state" [ngClass]="{ active: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY, - inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY + inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY, }" >{{ 'USER.MFA.STATE.' + mfa.state | translate }} diff --git a/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html index 3e46560d0e..6726f98f98 100644 --- a/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html +++ b/console/src/app/pages/users/user-detail/user-detail/passwordless/passwordless.component.html @@ -43,7 +43,7 @@ class="state" [ngClass]="{ active: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY, - inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY + inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY, }" >{{ 'USER.PASSWORDLESS.STATE.' + mfa.state | translate }} diff --git a/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.html b/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.html index 0369be9356..a6d0bf652f 100644 --- a/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.html +++ b/console/src/app/pages/users/user-detail/user-detail/user-mfa/user-mfa.component.html @@ -41,7 +41,7 @@ class="state" [ngClass]="{ active: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_READY, - inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY + inactive: mfa.state === AuthFactorState.AUTH_FACTOR_STATE_NOT_READY, }" > {{ 'USER.MFA.STATE.' + mfa.state | translate }} diff --git a/console/src/app/pages/users/user-list/user-table/user-table.component.html b/console/src/app/pages/users/user-list/user-table/user-table.component.html index 3be48e7fab..cc81a4d4c0 100644 --- a/console/src/app/pages/users/user-list/user-table/user-table.component.html +++ b/console/src/app/pages/users/user-list/user-table/user-table.component.html @@ -57,11 +57,14 @@ - + + +