diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index f85e185ecd..baca5175e1 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -710,7 +710,8 @@ DefaultInstance: ErrorMsgPopup: false # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_ERRORMSGPOPUP DisableWatermark: false # ZITADEL_DEFAULTINSTANCE_LABELPOLICY_DISABLEWATERMARK LockoutPolicy: - MaxAttempts: 0 # ZITADEL_DEFAULTINSTANCE_LOCKOUTPOLICY_MAXATTEMPTS + MaxPasswordAttempts: 0 # ZITADEL_DEFAULTINSTANCE_LOCKOUTPOLICY_MAXPASSWORDATTEMPTS + 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 # Sets the default values for lifetime and expiration for OIDC in each newly created instance diff --git a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html index 9a515d1890..6591d4613b 100644 --- a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html +++ b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html @@ -17,17 +17,49 @@
- {{ lockoutData.maxPasswordAttempts }} -
- {{ 'POLICY.DATA.MAXATTEMPTS' | translate }} + {{ 'POLICY.DATA.MAXPASSWORDATTEMPTS' | translate }} + +
+
+
+
+ + {{ lockoutData.maxOtpAttempts }} + +
+ +
+ {{ 'POLICY.DATA.MAXOTPATTEMPTS' | translate }}
diff --git a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.ts b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.ts index ad4ff29b4f..e56857770d 100644 --- a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.ts +++ b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.ts @@ -91,24 +91,36 @@ export class PasswordLockoutPolicyComponent implements OnInit { } } - public incrementMaxAttempts(): void { + public incrementPasswordMaxAttempts(): void { if (this.lockoutData?.maxPasswordAttempts !== undefined) { this.lockoutData.maxPasswordAttempts++; } } - public decrementMaxAttempts(): void { + public decrementPasswordMaxAttempts(): void { if (this.lockoutData?.maxPasswordAttempts && this.lockoutData?.maxPasswordAttempts > 0) { this.lockoutData.maxPasswordAttempts--; } } + public incrementOTPMaxAttempts(): void { + if (this.lockoutData?.maxOtpAttempts !== undefined) { + this.lockoutData.maxOtpAttempts++; + } + } + + public decrementOTPMaxAttempts(): void { + if (this.lockoutData?.maxOtpAttempts && this.lockoutData?.maxOtpAttempts > 0) { + this.lockoutData.maxOtpAttempts--; + } + } + public savePolicy(): void { let promise: Promise; if (this.lockoutData) { if (this.service instanceof AdminService) { promise = this.service - .updateLockoutPolicy(this.lockoutData.maxPasswordAttempts) + .updateLockoutPolicy(this.lockoutData.maxPasswordAttempts, this.lockoutData.maxOtpAttempts) .then(() => { this.toast.showInfo('POLICY.TOAST.SET', true); this.fetchData(); @@ -119,7 +131,7 @@ export class PasswordLockoutPolicyComponent implements OnInit { } else { if ((this.lockoutData as LockoutPolicy.AsObject).isDefault) { promise = (this.service as ManagementService) - .addCustomLockoutPolicy(this.lockoutData.maxPasswordAttempts) + .addCustomLockoutPolicy(this.lockoutData.maxPasswordAttempts, this.lockoutData.maxOtpAttempts) .then(() => { this.toast.showInfo('POLICY.TOAST.SET', true); this.fetchData(); @@ -129,7 +141,7 @@ export class PasswordLockoutPolicyComponent implements OnInit { }); } else { promise = (this.service as ManagementService) - .updateCustomLockoutPolicy(this.lockoutData.maxPasswordAttempts) + .updateCustomLockoutPolicy(this.lockoutData.maxPasswordAttempts, this.lockoutData.maxOtpAttempts) .then(() => { this.toast.showInfo('POLICY.TOAST.SET', true); this.fetchData(); diff --git a/console/src/app/services/admin.service.ts b/console/src/app/services/admin.service.ts index 17c8f1b323..7149317ab4 100644 --- a/console/src/app/services/admin.service.ts +++ b/console/src/app/services/admin.service.ts @@ -957,9 +957,13 @@ export class AdminService { return this.grpcService.admin.getLockoutPolicy(req, null).then((resp) => resp.toObject()); } - public updateLockoutPolicy(maxAttempts: number): Promise { + public updateLockoutPolicy( + maxPasswordAttempts: number, + maxOTPAttempts: number, + ): Promise { const req = new UpdateLockoutPolicyRequest(); - req.setMaxPasswordAttempts(maxAttempts); + req.setMaxPasswordAttempts(maxPasswordAttempts); + req.setMaxOtpAttempts(maxOTPAttempts); return this.grpcService.admin.updateLockoutPolicy(req, null).then((resp) => resp.toObject()); } diff --git a/console/src/app/services/mgmt.service.ts b/console/src/app/services/mgmt.service.ts index ae975a228d..0e3c0b3062 100644 --- a/console/src/app/services/mgmt.service.ts +++ b/console/src/app/services/mgmt.service.ts @@ -1587,9 +1587,13 @@ export class ManagementService { return this.grpcService.mgmt.getLockoutPolicy(req, null).then((resp) => resp.toObject()); } - public addCustomLockoutPolicy(maxAttempts: number): Promise { + public addCustomLockoutPolicy( + maxPasswordAttempts: number, + maxOTPAttempts: number, + ): Promise { const req = new AddCustomLockoutPolicyRequest(); - req.setMaxPasswordAttempts(maxAttempts); + req.setMaxPasswordAttempts(maxPasswordAttempts); + req.setMaxOtpAttempts(maxOTPAttempts); return this.grpcService.mgmt.addCustomLockoutPolicy(req, null).then((resp) => resp.toObject()); } @@ -1599,9 +1603,13 @@ export class ManagementService { return this.grpcService.mgmt.resetLockoutPolicyToDefault(req, null).then((resp) => resp.toObject()); } - public updateCustomLockoutPolicy(maxAttempts: number): Promise { + public updateCustomLockoutPolicy( + maxPasswordAttempts: number, + maxOTPAttempts: number, + ): Promise { const req = new UpdateCustomLockoutPolicyRequest(); - req.setMaxPasswordAttempts(maxAttempts); + req.setMaxPasswordAttempts(maxPasswordAttempts); + req.setMaxOtpAttempts(maxOTPAttempts); return this.grpcService.mgmt.updateCustomLockoutPolicy(req, null).then((resp) => resp.toObject()); } diff --git a/console/src/assets/i18n/bg.json b/console/src/assets/i18n/bg.json index 2ddcec25c4..6add8de104 100644 --- a/console/src/assets/i18n/bg.json +++ b/console/src/assets/i18n/bg.json @@ -1653,7 +1653,8 @@ "HASLOWERCASE": "има малки букви", "HASUPPERCASE": "има главни букви", "SHOWLOCKOUTFAILURES": "показва грешки при блокиране", - "MAXATTEMPTS": "Максимален брой опити за парола", + "MAXPASSWORDATTEMPTS": "Максимален брой опити за парола", + "MAXOTPATTEMPTS": "Максимален брой опити за OTP", "EXPIREWARNDAYS": "Предупреждение за изтичане след ден", "MAXAGEDAYS": "Максимална възраст в дни", "USERLOGINMUSTBEDOMAIN": "Добавяне на домейн на организация като суфикс към имената за вход", diff --git a/console/src/assets/i18n/cs.json b/console/src/assets/i18n/cs.json index c893c5d8c3..c2c875c78c 100644 --- a/console/src/assets/i18n/cs.json +++ b/console/src/assets/i18n/cs.json @@ -1660,7 +1660,8 @@ "HASLOWERCASE": "obsahuje malá písmena", "HASUPPERCASE": "obsahuje velká písmena", "SHOWLOCKOUTFAILURES": "zobrazit neúspěšné pokusy o uzamčení", - "MAXATTEMPTS": "Maximální počet pokusů o heslo", + "MAXPASSWORDATTEMPTS": "Maximální počet pokusů o heslo", + "MAXOTPATTEMPTS": "Maximální počet pokusů o OTP", "EXPIREWARNDAYS": "Upozornění na expiraci po dni", "MAXAGEDAYS": "Maximální stáří v dnech", "USERLOGINMUSTBEDOMAIN": "Přidat doménu organizace jako příponu k přihlašovacím jménům", diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index e0f403b07b..f4d1cf8e6c 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -1659,7 +1659,8 @@ "HASLOWERCASE": "erfordert Kleinbuchstaben", "HASUPPERCASE": "erfordert Grossbuchstaben", "SHOWLOCKOUTFAILURES": "Zeige Anzahl Anmeldeversuche", - "MAXATTEMPTS": "Maximale Anzahl an Versuchen", + "MAXPASSWORDATTEMPTS": "Maximale Anzahl an Passwort Versuchen", + "MAXOTPATTEMPTS": "Maximale Anzahl an OTP Versuchen", "EXPIREWARNDAYS": "Ablauf Warnung nach Tagen", "MAXAGEDAYS": "Maximale Gültigkeit in Tagen", "USERLOGINMUSTBEDOMAIN": "Organisationsdomain dem Loginname hinzufügen", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 72cee6c0f3..0427a4af5b 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -1660,7 +1660,8 @@ "HASLOWERCASE": "must include a lowercase letter", "HASUPPERCASE": "must include an uppercase letter", "SHOWLOCKOUTFAILURES": "show lockout failures", - "MAXATTEMPTS": "Password maximum Attempts", + "MAXPASSWORDATTEMPTS": "Password maximum attempts", + "MAXOTPATTEMPTS": "OTP maximum attempts", "EXPIREWARNDAYS": "Expiration Warning after day", "MAXAGEDAYS": "Max Age in days", "USERLOGINMUSTBEDOMAIN": "Add organization domain as suffix to loginnames", diff --git a/console/src/assets/i18n/es.json b/console/src/assets/i18n/es.json index 819c078905..e5630cd0a8 100644 --- a/console/src/assets/i18n/es.json +++ b/console/src/assets/i18n/es.json @@ -1661,7 +1661,8 @@ "HASLOWERCASE": "tiene minúsculas", "HASUPPERCASE": "tiene mayúsculas", "SHOWLOCKOUTFAILURES": "mostrar fallos de bloqueo", - "MAXATTEMPTS": "Intentos máximos", + "MAXPASSWORDATTEMPTS": "Intentos máximos de contraseña", + "MAXOTPATTEMPTS": "Intentos máximos de OTP", "EXPIREWARNDAYS": "Aviso de expiración después de estos días: ", "MAXAGEDAYS": "Antigüedad máxima en días", "USERLOGINMUSTBEDOMAIN": "Añadir el dominio de la organización como sufijo de los nombres de inicio de sesión", diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json index b88bed51b4..929dce791a 100644 --- a/console/src/assets/i18n/fr.json +++ b/console/src/assets/i18n/fr.json @@ -1659,7 +1659,8 @@ "HASLOWERCASE": "a minuscule", "HASUPPERCASE": "a majuscule", "SHOWLOCKOUTFAILURES": "montrer les échecs de verrouillage", - "MAXATTEMPTS": "Mot de passe maximum Tentatives", + "MAXPASSWORDATTEMPTS": "Mot de passe maximum tentatives", + "MAXOTPATTEMPTS": "Maximal de tentatives OTP", "EXPIREWARNDAYS": "Expiration Avertissement après le jour", "MAXAGEDAYS": "Âge maximum en jours", "USERLOGINMUSTBEDOMAIN": "Le nom de connexion de l'utilisateur doit contenir le nom de domaine de l'organisation", diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index 5d1cc463ea..747e857157 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -1659,7 +1659,8 @@ "HASLOWERCASE": "ha la minuscola", "HASUPPERCASE": "ha la maiuscola", "SHOWLOCKOUTFAILURES": "mostra i fallimenti del blocco", - "MAXATTEMPTS": "Massimo numero di tentativi di password", + "MAXPASSWORDATTEMPTS": "Massimo numero di tentativi di password", + "MAXOTPATTEMPTS": "Massimo numero di tentativi di OTP", "EXPIREWARNDAYS": "Avviso scadenza dopo il giorno", "MAXAGEDAYS": "Lunghezza massima in giorni", "USERLOGINMUSTBEDOMAIN": "Nome utente deve contenere il dominio dell' organizzazione", diff --git a/console/src/assets/i18n/ja.json b/console/src/assets/i18n/ja.json index 6036a62fe6..dd8130b6dd 100644 --- a/console/src/assets/i18n/ja.json +++ b/console/src/assets/i18n/ja.json @@ -1656,7 +1656,8 @@ "HASLOWERCASE": "小文字を含める", "HASUPPERCASE": "大文字を含める", "SHOWLOCKOUTFAILURES": "ロックアウトの失敗を表示する", - "MAXATTEMPTS": "パスワードの最大試行", + "MAXPASSWORDATTEMPTS": "パスワードの最大試行", + "MAXOTPATTEMPTS": "最大OTP試行回数", "EXPIREWARNDAYS": "有効期限の翌日以降の警告", "MAXAGEDAYS": "最大有効期限", "USERLOGINMUSTBEDOMAIN": "ログイン名の接尾辞として組織ドメインを追加する", diff --git a/console/src/assets/i18n/mk.json b/console/src/assets/i18n/mk.json index c7e68f3dad..f12c16f09b 100644 --- a/console/src/assets/i18n/mk.json +++ b/console/src/assets/i18n/mk.json @@ -1661,7 +1661,8 @@ "HASLOWERCASE": "има мали букви", "HASUPPERCASE": "има големи букви", "SHOWLOCKOUTFAILURES": "прикажи неуспешни заклучувања", - "MAXATTEMPTS": "Максимален број на обиди за лозинка", + "MAXPASSWORDATTEMPTS": "Максимален број на обиди за лозинка", + "MAXOTPATTEMPTS": "Максимални обиди за OTP", "EXPIREWARNDAYS": "Предупредување за истекување по ден", "MAXAGEDAYS": "Максимална возраст во денови", "USERLOGINMUSTBEDOMAIN": "Додади организациски домен како суфикс на корисничките имиња", diff --git a/console/src/assets/i18n/nl.json b/console/src/assets/i18n/nl.json index 1bfe7214b2..1da10f8e57 100644 --- a/console/src/assets/i18n/nl.json +++ b/console/src/assets/i18n/nl.json @@ -1660,7 +1660,8 @@ "HASLOWERCASE": "heeft kleine letters", "HASUPPERCASE": "heeft hoofdletters", "SHOWLOCKOUTFAILURES": "toon lockout mislukkingen", - "MAXATTEMPTS": "Maximum pogingen voor wachtwoord", + "MAXPASSWORDATTEMPTS": "Maximum pogingen voor wachtwoord", + "MAXOTPATTEMPTS": "Maximale OTP-pogingen", "EXPIREWARNDAYS": "Vervaldatum Waarschuwing na dag", "MAXAGEDAYS": "Maximale Leeftijd in dagen", "USERLOGINMUSTBEDOMAIN": "Voeg organisatie domein toe als achtervoegsel aan inlognamen", diff --git a/console/src/assets/i18n/pl.json b/console/src/assets/i18n/pl.json index e1b632cd3e..ef572b7beb 100644 --- a/console/src/assets/i18n/pl.json +++ b/console/src/assets/i18n/pl.json @@ -1659,7 +1659,8 @@ "HASLOWERCASE": "zawiera małe litery", "HASUPPERCASE": "zawiera duże litery", "SHOWLOCKOUTFAILURES": "pokaż blokady nieudanych prób", - "MAXATTEMPTS": "Maksymalna liczba prób wprowadzenia hasła", + "MAXPASSWORDATTEMPTS": "Maksymalna liczba prób wprowadzenia hasła", + "MAXOTPATTEMPTS": "Maksymalna liczba prób OTP", "EXPIREWARNDAYS": "Ostrzeżenie o wygaśnięciu po dniu", "MAXAGEDAYS": "Maksymalny wiek w dniach", "USERLOGINMUSTBEDOMAIN": "Dodaj domenę organizacji jako przyrostek do nazw logowania", diff --git a/console/src/assets/i18n/pt.json b/console/src/assets/i18n/pt.json index 4cbcfe4e16..9fdb634ab6 100644 --- a/console/src/assets/i18n/pt.json +++ b/console/src/assets/i18n/pt.json @@ -1661,7 +1661,8 @@ "HASLOWERCASE": "tem letra minúscula", "HASUPPERCASE": "tem letra maiúscula", "SHOWLOCKOUTFAILURES": "mostrar falhas de bloqueio", - "MAXATTEMPTS": "Máximo de tentativas de senha", + "MAXPASSWORDATTEMPTS": "Máximo de tentativas de senha", + "MAXOTPATTEMPTS": "Máximo de tentativas de OTP", "EXPIREWARNDAYS": "Aviso de expiração após dias", "MAXAGEDAYS": "Idade máxima em dias", "USERLOGINMUSTBEDOMAIN": "Adicionar domínio da organização como sufixo aos nomes de login", diff --git a/console/src/assets/i18n/ru.json b/console/src/assets/i18n/ru.json index 2f2c63e0e5..ff38f488d4 100644 --- a/console/src/assets/i18n/ru.json +++ b/console/src/assets/i18n/ru.json @@ -1729,7 +1729,8 @@ "HASLOWERCASE": "Содержит нижний регистр", "HASUPPERCASE": "Содержит верхний регистр", "SHOWLOCKOUTFAILURES": "Показать ошибки блокировки", - "MAXATTEMPTS": "Максимальное количество попыток пароля", + "MAXPASSWORDATTEMPTS": "Максимальное количество попыток пароля", + "MAXOTPATTEMPTS": "Максимальное количество попыток OTP", "EXPIREWARNDAYS": "Предупреждение об истечении срока действия после дня", "MAXAGEDAYS": "Максимальный возраст в днях", "USERLOGINMUSTBEDOMAIN": "Добавить домен организации в качестве суффикса к именам логина", diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json index d4a8c7ead4..57d5ba2490 100644 --- a/console/src/assets/i18n/zh.json +++ b/console/src/assets/i18n/zh.json @@ -1658,7 +1658,8 @@ "HASLOWERCASE": "包含小写字母", "HASUPPERCASE": "包含大写字母", "SHOWLOCKOUTFAILURES": "显示锁定失败", - "MAXATTEMPTS": "密码最大尝试次数", + "MAXPASSWORDATTEMPTS": "密码最大尝试次数", + "MAXOTPATTEMPTS": "最多尝试 OTP 次数", "EXPIREWARNDAYS": "密码过期警告", "MAXAGEDAYS": "Max Age in days", "USERLOGINMUSTBEDOMAIN": "用户名必须包含组织域名", diff --git a/console/yarn.lock b/console/yarn.lock index 7b6584a842..de6a28e268 100644 --- a/console/yarn.lock +++ b/console/yarn.lock @@ -2103,18 +2103,6 @@ protobufjs "^7.2.4" yargs "^17.7.2" -"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": - version "9.3.0" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" - integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== - -"@hapi/topo@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" - integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== - dependencies: - "@hapi/hoek" "^9.0.0" - "@humanwhocodes/config-array@^0.11.11": version "0.11.11" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" @@ -3193,23 +3181,6 @@ "@angular-devkit/schematics" "16.2.2" jsonc-parser "3.2.0" -"@sideway/address@^4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" - integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== - dependencies: - "@hapi/hoek" "^9.0.0" - -"@sideway/formula@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" - integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== - -"@sideway/pinpoint@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" - integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== - "@sigstore/protobuf-specs@^0.1.0": version "0.1.0" resolved "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz" @@ -4246,30 +4217,11 @@ big.js@^5.2.2: resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -bin-build@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bin-build/-/bin-build-3.0.0.tgz#c5780a25a8a9f966d8244217e6c1f5082a143861" - integrity sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA== - dependencies: - decompress "^4.0.0" - download "^6.2.2" - execa "^0.7.0" - p-map-series "^1.0.0" - tempfile "^2.0.0" - binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bl@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" - integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" @@ -4391,35 +4343,12 @@ browserstack@^1.5.1: dependencies: https-proxy-agent "^2.2.1" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -4527,16 +4456,6 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -caw@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" - integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== - dependencies: - get-proxy "^2.0.0" - isurl "^1.0.0-alpha5" - tunnel-agent "^0.6.0" - url-to-options "^1.0.1" - chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" @@ -4741,7 +4660,7 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.11.0, commander@^2.20.0, commander@^2.8.1: +commander@^2.11.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -4776,14 +4695,6 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -config-chain@^1.1.11: - version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - connect-history-api-fallback@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz" @@ -4804,7 +4715,7 @@ console-control-strings@^1.1.0: resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== -content-disposition@0.5.4, content-disposition@^0.5.2: +content-disposition@0.5.4: version "0.5.4" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== @@ -4903,15 +4814,6 @@ critters@0.0.20: postcss "^8.4.23" pretty-bytes "^5.3.0" -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A== - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" @@ -5050,66 +4952,6 @@ decimal.js@^10.2.1: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== -decompress-response@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== - dependencies: - mimic-response "^1.0.0" - -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw== - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - deep-is@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" @@ -5275,28 +5117,6 @@ dotenv@~10.0.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -download@^6.2.2: - version "6.2.5" - resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" - integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== - dependencies: - caw "^2.0.0" - content-disposition "^0.5.2" - decompress "^4.0.0" - ext-name "^5.0.0" - file-type "5.2.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^7.0.0" - make-dir "^1.0.0" - p-event "^1.0.0" - pify "^3.0.0" - -duplexer3@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" - integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== - duplexer@^0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" @@ -5369,7 +5189,7 @@ encoding@^0.1.13: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.4.1: +end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -5687,19 +5507,6 @@ events@^3.2.0: resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw== - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^5.0.0: version "5.1.1" resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" @@ -5757,21 +5564,6 @@ express@^4.17.3: utils-merge "1.0.1" vary "~1.1.2" -ext-list@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" - integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== - dependencies: - mime-db "^1.28.0" - -ext-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" - integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== - dependencies: - ext-list "^2.0.0" - sort-keys-length "^1.0.0" - extend@^3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" @@ -5863,13 +5655,6 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== - dependencies: - pend "~1.2.0" - figures@3.2.0, figures@^3.0.0: version "3.2.0" resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" @@ -5889,21 +5674,6 @@ file-saver@^2.0.5: resolved "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz" integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== -file-type@5.2.0, file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ== - -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA== - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - filelist@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz" @@ -5911,20 +5681,6 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ== - -filenamify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" - integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" @@ -6179,26 +5935,6 @@ get-package-type@^0.1.0: resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-proxy@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" - integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== - dependencies: - npm-conf "^1.1.0" - -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA== - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== - get-stream@^6.0.0: version "6.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" @@ -6336,27 +6072,7 @@ google-protobuf@^3.21.2: resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz" integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== -got@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6418,23 +6134,11 @@ has-proto@^1.0.1: resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" @@ -6811,11 +6515,6 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww== - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" @@ -6826,13 +6525,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg== - dependencies: - is-extglob "^1.0.0" - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -6845,33 +6537,16 @@ is-interactive@^1.0.0: resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -is-invalid-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34" - integrity sha512-aZMG0T3F34mTg4eTdszcGXx54oiZ4NtHSft3hWNJMGJXUUqdIj3cOZuHcU0nCWWcY3jd7yRe/3AEm3vSNTpBGQ== - dependencies: - is-glob "^2.0.0" - is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ== - is-number@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== - is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz" @@ -6896,11 +6571,6 @@ is-path-inside@^3.0.3: resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== - is-plain-obj@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz" @@ -6923,16 +6593,6 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-retry-allowed@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - -is-stream@^1.0.0, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" @@ -6948,13 +6608,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-valid-path@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df" - integrity sha512-+kwPrVDu9Ms03L90Qaml+79+6DZHqHyRoANI6IsZJ/g8frhnfchDOBCa0RbQ6/kdHt5CS5OeIEyrYznNuVN+8A== - dependencies: - is-invalid-path "^0.1.0" - is-what@^3.14.1: version "3.14.1" resolved "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz" @@ -7041,14 +6694,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - jackspeak@^2.0.3: version "2.2.0" resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz" @@ -7113,17 +6758,6 @@ jiti@^1.18.2: resolved "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz" integrity sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg== -joi@^17.4.0: - version "17.12.2" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.12.2.tgz#283a664dabb80c7e52943c557aab82faea09f521" - integrity sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw== - dependencies: - "@hapi/hoek" "^9.3.0" - "@hapi/topo" "^5.1.0" - "@sideway/address" "^4.1.5" - "@sideway/formula" "^3.0.1" - "@sideway/pinpoint" "^2.0.0" - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -7508,19 +7142,6 @@ long@^5.0.0: resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -7552,13 +7173,6 @@ magic-string@0.30.1: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - make-dir@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" @@ -7667,7 +7281,7 @@ micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -7694,11 +7308,6 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-response@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - mini-css-extract-plugin@2.7.6: version "2.7.6" resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz" @@ -7933,11 +7542,6 @@ node-addon-api@^3.0.0, node-addon-api@^3.2.1: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== -node-downloader-helper@^2.1.6: - version "2.1.9" - resolved "https://registry.yarnpkg.com/node-downloader-helper/-/node-downloader-helper-2.1.9.tgz#a59ee7276b2bf708bbac2cc5872ad28fc7cd1b0e" - integrity sha512-FSvAol2Z8UP191sZtsUZwHIN0eGoGue3uEXGdWIH5228e9KH1YHXT7fN8Oa33UGf+FbqGTQg3sJfrRGzmVCaJA== - node-forge@^1: version "1.3.1" resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" @@ -7964,18 +7568,6 @@ node-gyp@^9.0.0: tar "^6.1.2" which "^2.0.2" -node-jq@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/node-jq/-/node-jq-4.3.1.tgz#c2a082210745fd1c54df5965b9ba5d046fce9d68" - integrity sha512-5iU9L/7j8ZNHwhxDRJXgyza6JnEKqdkNcJ9+ul5HZnhConhg/v9JdvA9agJ8XA+qBgGr1MK/MeHDrdK1tL2QAA== - dependencies: - bin-build "^3.0.0" - is-valid-path "^0.1.1" - joi "^17.4.0" - node-downloader-helper "^2.1.6" - strip-final-newline "^2.0.0" - tempfile "^3.0.0" - node-releases@^2.0.12: version "2.0.13" resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz" @@ -8030,14 +7622,6 @@ npm-bundled@^3.0.0: dependencies: npm-normalize-package-bin "^3.0.0" -npm-conf@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - npm-install-checks@^6.0.0: version "6.1.1" resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz" @@ -8090,13 +7674,6 @@ npm-registry-fetch@^14.0.0: npm-package-arg "^10.0.0" proc-log "^3.0.0" -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" @@ -8284,18 +7861,6 @@ os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - -p-event@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085" - integrity sha512-hV1zbA7gwqPVFcapfeATaNjQ3J0NuzorHPyG8GPL9g/Y/TplWVBVoCKCXL6Ej2zscrCEv195QNWJXuBH6XZuzA== - dependencies: - p-timeout "^1.1.1" - p-filter@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-3.0.0.tgz#ce50e03b24b23930e11679ab8694bd09a2d7ed35" @@ -8303,11 +7868,6 @@ p-filter@^3.0.0: dependencies: p-map "^5.1.0" -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" @@ -8350,13 +7910,6 @@ p-locate@^6.0.0: dependencies: p-limit "^4.0.0" -p-map-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" - integrity sha512-4k9LlvY6Bo/1FcIdV33wqZQES0Py+iKISU9Uc8p8AjWoZPnFKMpVIVD3s0EYn4jzLh1I+WeUZkJ0Yoa4Qfw3Kg== - dependencies: - p-reduce "^1.0.0" - p-map@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" @@ -8371,11 +7924,6 @@ p-map@^5.1.0: dependencies: aggregate-error "^4.0.0" -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha512-3Tx1T3oM1xO/Y8Gj0sWyE78EIJZ+t+aEmXUdvQgvGmSMri7aPTHoovbXEreWKkL5j21Er60XAWLTzKbAKYOujQ== - p-retry@^4.5.0: version "4.6.2" resolved "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz" @@ -8384,13 +7932,6 @@ p-retry@^4.5.0: "@types/retry" "0.12.0" retry "^0.13.1" -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha512-gb0ryzr+K2qFqFv6qi3khoeqMZF/+ajxQipEF6NteZVnvz9tzdsfAVj3lYtn1gAXvH5lfLwfxEII799gt/mRIA== - dependencies: - p-finally "^1.0.0" - p-try@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" @@ -8500,11 +8041,6 @@ path-is-inside@^1.0.1: resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== -path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" @@ -8533,11 +8069,6 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" @@ -8553,16 +8084,11 @@ picomatch@2.3.1, picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.0.0, pify@^2.3.0: +pify@^2.0.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== - pify@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" @@ -8685,11 +8211,6 @@ prelude-ls@^1.2.1: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg== - prettier-plugin-organize-imports@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz#77967f69d335e9c8e6e5d224074609309c62845e" @@ -8733,11 +8254,6 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== - protobufjs@^7.0.0, protobufjs@^7.2.4: version "7.2.5" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.5.tgz#45d5c57387a6d29a17aab6846dcc283f9b8e7f2d" @@ -8795,11 +8311,6 @@ prr@~1.0.1: resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - psl@^1.1.28, psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -8926,7 +8437,7 @@ read-pkg@^7.1.0: parse-json "^5.2.0" type-fest "^2.0.0" -readable-stream@^2.0.1, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: +readable-stream@^2.0.1, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -9164,7 +8675,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -9242,13 +8753,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -seek-bzip@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" - integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== - dependencies: - commander "^2.8.1" - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz" @@ -9385,13 +8889,6 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -9399,11 +8896,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" @@ -9423,7 +8915,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -9510,20 +9002,6 @@ socks@^2.6.2: ip "^2.0.0" smart-buffer "^4.2.0" -sort-keys-length@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" - integrity sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw== - dependencies: - sort-keys "^1.0.0" - -sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - integrity sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg== - dependencies: - is-plain-obj "^1.0.0" - "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" @@ -9738,18 +9216,6 @@ strip-bom@^3.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" @@ -9760,13 +9226,6 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-outer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - strong-log-transformer@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz" @@ -9822,19 +9281,6 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - tar-stream@~2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" @@ -9858,32 +9304,6 @@ tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== - -temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - -tempfile@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" - integrity sha512-ZOn6nJUgvgC09+doCEF3oB+r3ag7kUvlsXEGX069QRD60p+P3uP7XG9N2/at+EyIRGSN//ZY3LyEotA1YpmjuA== - dependencies: - temp-dir "^1.0.0" - uuid "^3.0.1" - -tempfile@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-3.0.0.tgz#5376a3492de7c54150d0cc0612c3f00e2cdaf76c" - integrity sha512-uNFCg478XovRi85iD42egu+eSFUmmka750Jy7L5tfHI5hQKKtbPnxaSaXAbBqCDYrw3wx4tXjKwci4/QmsZJxw== - dependencies: - temp-dir "^2.0.0" - uuid "^3.3.2" - terser-webpack-plugin@^5.3.7: version "5.3.8" resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz" @@ -9929,7 +9349,7 @@ text-table@0.2.0, text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -through@X.X.X, through@^2.3.4, through@^2.3.6, through@^2.3.8: +through@X.X.X, through@^2.3.4, through@^2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -9939,11 +9359,6 @@ thunky@^1.0.2: resolved "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -timed-out@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== - tiny-inflate@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz" @@ -9975,11 +9390,6 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" @@ -10027,13 +9437,6 @@ tree-kill@1.2.2: resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg== - dependencies: - escape-string-regexp "^1.0.2" - tsconfig-paths@^4.1.2: version "4.2.0" resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz" @@ -10131,14 +9534,6 @@ ua-parser-js@^0.7.30: resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz" integrity sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g== -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - unicode-canonical-property-names-ecmascript@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" @@ -10225,13 +9620,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA== - dependencies: - prepend-http "^1.0.1" - url-parse@^1.5.3: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" @@ -10240,11 +9628,6 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A== - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" @@ -10255,7 +9638,7 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@^3.0.1, uuid@^3.3.2: +uuid@^3.3.2: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -10544,7 +9927,7 @@ which-module@^2.0.0: resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which@^1.2.1, which@^1.2.9: +which@^1.2.1: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -10647,11 +10030,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^4.0.0: version "4.0.3" resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" @@ -10662,11 +10040,6 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== - yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" @@ -10738,14 +10111,6 @@ yargs@^16.1.1: y18n "^5.0.5" yargs-parser "^20.2.2" -yauzl@^2.4.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" diff --git a/docs/docs/guides/manage/console/default-settings.mdx b/docs/docs/guides/manage/console/default-settings.mdx index c29bb8d53d..a715f8a4db 100644 --- a/docs/docs/guides/manage/console/default-settings.mdx +++ b/docs/docs/guides/manage/console/default-settings.mdx @@ -20,7 +20,7 @@ When you configure your default settings, you can set the following: - [**Login Behavior and Access**](#login-behavior-and-access): Multifactor Authentication Options and Enforcement, Define whether Passwordless authentication methods are allowed or not, Set Login Lifetimes and advanced behavour for the login interface. - [**Identity Providers**](#identity-providers): Define IDPs which are available for all organizations - [**Password Complexity**](#password-complexity): Requirements for Passwords ex. Symbols, Numbers, min length and more. -- [**Lockout**](#lockout): Set the maximum attempts a user can try to enter the password. When the number is exceeded, the user gets locked out and has to be unlocked. +- [**Lockout**](#lockout): Set the maximum attempts a user can try to enter the password or any (T)OTP method. When the number is exceeded, the user gets locked out and has to be unlocked. - [**Domain settings**](#domain-settings): Whether users use their email or the generated username to login. Other Validation, SMTP settings - [**Branding**](#branding): Appearance of the login interface. - [**Message Texts**](#message-texts): Text and internationalization for emails @@ -189,6 +189,7 @@ Define when an account should be locked. The following settings are available: - Maximum Password Attempts: When the user has reached the maximum password attempts the account will be locked, If this is set to 0 the lockout will not trigger. +- Maximum OTP Attempts: When the user has reached the maximum (T)OTP attempts the account will be locked, If this is set to 0 the lockout will not trigger. If an account is locked, the administrator has to unlock it in the ZITADEL console diff --git a/docs/docs/guides/manage/console/organizations.mdx b/docs/docs/guides/manage/console/organizations.mdx index 99092c304e..6763a09670 100644 --- a/docs/docs/guides/manage/console/organizations.mdx +++ b/docs/docs/guides/manage/console/organizations.mdx @@ -108,7 +108,7 @@ Those settings are the same as on your instance. - [**Login Behavior and Access**](./default-settings#login-behaviour-and-access): Multifactor Authentication Options and Enforcement, Define whether Passwordless authentication methods are allowed or not, Set Login Lifetimes and advanced behavour for the login interface. - [**Identity Providers**](./default-settings#identity-providers): Define IDPs which are available for all organizations - [**Password Complexity**](./default-settings#password-complexity): Requirements for Passwords ex. Symbols, Numbers, min length and more. -- [**Lockout**](./default-settings#lockout): Set the maximum attempts a user can try to enter the password. When the number is exceeded, the user gets locked out and has to be unlocked. +- [**Lockout**](./default-settings#lockout): Set the maximum attempts a user can try to enter the password or any (T)OTP method. When the number is exceeded, the user gets locked out and has to be unlocked. - [**Verified domains**](/docs/guides/manage/console/organizations#verify-your-domain-name): This is where you manage your organization specific domains which can be used to build usernames - [**Domain settings**](./default-settings#domain-settings): Whether users use their email or the generated username to login. Other Validation, SMTP settings - [**Branding**](./default-settings#branding): Appearance of the login interface. diff --git a/docs/static/img/guides/console/lockout.png b/docs/static/img/guides/console/lockout.png index 8f6c170d3b..8b87718fc9 100644 Binary files a/docs/static/img/guides/console/lockout.png and b/docs/static/img/guides/console/lockout.png differ diff --git a/internal/api/grpc/admin/export.go b/internal/api/grpc/admin/export.go index e47d1f04f7..679ae0271c 100644 --- a/internal/api/grpc/admin/export.go +++ b/internal/api/grpc/admin/export.go @@ -491,13 +491,14 @@ func (s *Server) getLockoutPolicy(ctx context.Context, orgID string) (_ *managem ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() - queriedLockout, err := s.query.LockoutPolicyByOrg(ctx, false, orgID, false) + queriedLockout, err := s.query.LockoutPolicyByOrg(ctx, false, orgID) if err != nil { return nil, err } if !queriedLockout.IsDefault { return &management_pb.AddCustomLockoutPolicyRequest{ MaxPasswordAttempts: uint32(queriedLockout.MaxPasswordAttempts), + MaxOtpAttempts: uint32(queriedLockout.MaxOTPAttempts), }, nil } return nil, nil diff --git a/internal/api/grpc/admin/lockout_converter.go b/internal/api/grpc/admin/lockout_converter.go index 555e0c2e89..eabd5104e1 100644 --- a/internal/api/grpc/admin/lockout_converter.go +++ b/internal/api/grpc/admin/lockout_converter.go @@ -8,5 +8,6 @@ import ( func UpdateLockoutPolicyToDomain(p *admin.UpdateLockoutPolicyRequest) *domain.LockoutPolicy { return &domain.LockoutPolicy{ MaxPasswordAttempts: uint64(p.MaxPasswordAttempts), + MaxOTPAttempts: uint64(p.MaxOtpAttempts), } } diff --git a/internal/api/grpc/management/policy_lockout.go b/internal/api/grpc/management/policy_lockout.go index a36ee862d8..740a34e3a2 100644 --- a/internal/api/grpc/management/policy_lockout.go +++ b/internal/api/grpc/management/policy_lockout.go @@ -10,7 +10,7 @@ import ( ) func (s *Server) GetLockoutPolicy(ctx context.Context, req *mgmt_pb.GetLockoutPolicyRequest) (*mgmt_pb.GetLockoutPolicyResponse, error) { - policy, err := s.query.LockoutPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID, false) + policy, err := s.query.LockoutPolicyByOrg(ctx, true, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/policy_lockout_converter.go b/internal/api/grpc/management/policy_lockout_converter.go index 57910c4aba..83f5648103 100644 --- a/internal/api/grpc/management/policy_lockout_converter.go +++ b/internal/api/grpc/management/policy_lockout_converter.go @@ -8,11 +8,13 @@ import ( func AddLockoutPolicyToDomain(p *mgmt.AddCustomLockoutPolicyRequest) *domain.LockoutPolicy { return &domain.LockoutPolicy{ MaxPasswordAttempts: uint64(p.MaxPasswordAttempts), + MaxOTPAttempts: uint64(p.MaxOtpAttempts), } } func UpdateLockoutPolicyToDomain(p *mgmt.UpdateCustomLockoutPolicyRequest) *domain.LockoutPolicy { return &domain.LockoutPolicy{ MaxPasswordAttempts: uint64(p.MaxPasswordAttempts), + MaxOTPAttempts: uint64(p.MaxOtpAttempts), } } diff --git a/internal/api/grpc/policy/password_lockout_policy.go b/internal/api/grpc/policy/password_lockout_policy.go index af73f1bcef..c33076234d 100644 --- a/internal/api/grpc/policy/password_lockout_policy.go +++ b/internal/api/grpc/policy/password_lockout_policy.go @@ -10,6 +10,7 @@ func ModelLockoutPolicyToPb(policy *query.LockoutPolicy) *policy_pb.LockoutPolic return &policy_pb.LockoutPolicy{ IsDefault: policy.IsDefault, MaxPasswordAttempts: policy.MaxPasswordAttempts, + MaxOtpAttempts: policy.MaxOTPAttempts, Details: object.ToViewDetailsPb( policy.Sequence, policy.CreationDate, diff --git a/internal/api/grpc/settings/v2/settings.go b/internal/api/grpc/settings/v2/settings.go index c16178c370..11f41f26b6 100644 --- a/internal/api/grpc/settings/v2/settings.go +++ b/internal/api/grpc/settings/v2/settings.go @@ -90,7 +90,7 @@ func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.G } func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockoutSettingsRequest) (*settings.GetLockoutSettingsResponse, error) { - current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false) + current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx())) if err != nil { return nil, err } diff --git a/internal/api/grpc/settings/v2/settings_converter.go b/internal/api/grpc/settings/v2/settings_converter.go index 1bd9837127..f00bbf0f9d 100644 --- a/internal/api/grpc/settings/v2/settings_converter.go +++ b/internal/api/grpc/settings/v2/settings_converter.go @@ -160,6 +160,7 @@ func legalAndSupportSettingsToPb(current *query.PrivacyPolicy) *settings.LegalAn func lockoutSettingsToPb(current *query.LockoutPolicy) *settings.LockoutSettings { return &settings.LockoutSettings{ MaxPasswordAttempts: current.MaxPasswordAttempts, + MaxOtpAttempts: current.MaxOTPAttempts, ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault), } } diff --git a/internal/api/grpc/settings/v2/settings_converter_test.go b/internal/api/grpc/settings/v2/settings_converter_test.go index 7fcd5d96ce..d1cde07b87 100644 --- a/internal/api/grpc/settings/v2/settings_converter_test.go +++ b/internal/api/grpc/settings/v2/settings_converter_test.go @@ -339,10 +339,12 @@ func Test_legalSettingsToPb(t *testing.T) { func Test_lockoutSettingsToPb(t *testing.T) { arg := &query.LockoutPolicy{ MaxPasswordAttempts: 22, + MaxOTPAttempts: 22, IsDefault: true, } want := &settings.LockoutSettings{ MaxPasswordAttempts: 22, + MaxOtpAttempts: 22, ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE, } got := lockoutSettingsToPb(arg) diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 82a60b641f..98912c9309 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -75,7 +75,7 @@ type loginPolicyViewProvider interface { } type lockoutPolicyViewProvider interface { - LockoutPolicyByOrg(context.Context, bool, string, bool) (*query.LockoutPolicy, error) + LockoutPolicyByOrg(context.Context, bool, string) (*query.LockoutPolicy, error) } type idpProviderViewProvider interface { @@ -366,6 +366,7 @@ func lockoutPolicyToDomain(policy *query.LockoutPolicy) *domain.LockoutPolicy { }, Default: policy.IsDefault, MaxPasswordAttempts: policy.MaxPasswordAttempts, + MaxOTPAttempts: policy.MaxOTPAttempts, ShowLockOutFailures: policy.ShowFailures, } } @@ -1281,7 +1282,7 @@ func privacyPolicyToDomain(p *query.PrivacyPolicy) *domain.PrivacyPolicy { } func (repo *AuthRequestRepo) getLockoutPolicy(ctx context.Context, orgID string) (*query.LockoutPolicy, error) { - policy, err := repo.LockoutPolicyViewProvider.LockoutPolicyByOrg(ctx, false, orgID, false) + policy, err := repo.LockoutPolicyViewProvider.LockoutPolicyByOrg(ctx, false, orgID) if err != nil { return nil, err } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index 55bcf2e56d..99e0c78ec6 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -184,7 +184,7 @@ type mockLockoutPolicy struct { policy *query.LockoutPolicy } -func (m *mockLockoutPolicy) LockoutPolicyByOrg(context.Context, bool, string, bool) (*query.LockoutPolicy, error) { +func (m *mockLockoutPolicy) LockoutPolicyByOrg(context.Context, bool, string) (*query.LockoutPolicy, error) { return m.policy, nil } diff --git a/internal/command/instance.go b/internal/command/instance.go index 7f379d976b..f9f9121889 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -101,7 +101,8 @@ type InstanceSetup struct { ThemeMode domain.LabelPolicyThemeMode } LockoutPolicy struct { - MaxAttempts uint64 + MaxPasswordAttempts uint64 + MaxOTPAttempts uint64 ShouldShowLockoutFailure bool } EmailTemplate []byte @@ -271,7 +272,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str prepareAddDefaultPrivacyPolicy(instanceAgg, setup.PrivacyPolicy.TOSLink, setup.PrivacyPolicy.PrivacyLink, setup.PrivacyPolicy.HelpLink, setup.PrivacyPolicy.SupportEmail), prepareAddDefaultNotificationPolicy(instanceAgg, setup.NotificationPolicy.PasswordChange), - prepareAddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure), + prepareAddDefaultLockoutPolicy(instanceAgg, setup.LockoutPolicy.MaxPasswordAttempts, setup.LockoutPolicy.MaxOTPAttempts, setup.LockoutPolicy.ShouldShowLockoutFailure), prepareAddDefaultLabelPolicy( instanceAgg, diff --git a/internal/command/instance_converter.go b/internal/command/instance_converter.go index cf1a10b199..1ed1cc123a 100644 --- a/internal/command/instance_converter.go +++ b/internal/command/instance_converter.go @@ -109,6 +109,7 @@ func writeModelToLockoutPolicy(wm *LockoutPolicyWriteModel) *domain.LockoutPolic return &domain.LockoutPolicy{ ObjectRoot: writeModelToObjectRoot(wm.WriteModel), MaxPasswordAttempts: wm.MaxPasswordAttempts, + MaxOTPAttempts: wm.MaxOTPAttempts, ShowLockOutFailures: wm.ShowLockOutFailures, } } diff --git a/internal/command/instance_policy_password_lockout.go b/internal/command/instance_policy_password_lockout.go index 2ed88b997f..59766ae38f 100644 --- a/internal/command/instance_policy_password_lockout.go +++ b/internal/command/instance_policy_password_lockout.go @@ -12,9 +12,15 @@ import ( "github.com/zitadel/zitadel/internal/zerrors" ) -func (c *Commands) AddDefaultLockoutPolicy(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) (*domain.ObjectDetails, error) { +func (c *Commands) AddDefaultLockoutPolicy(ctx context.Context, maxPasswordAttempts, maxOTPAttempts uint64, showLockoutFailure bool) (*domain.ObjectDetails, error) { instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) - cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultLockoutPolicy(instanceAgg, maxAttempts, showLockoutFailure)) + //nolint:staticcheck + cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareAddDefaultLockoutPolicy( + instanceAgg, + maxPasswordAttempts, + maxOTPAttempts, + showLockoutFailure, + )) if err != nil { return nil, err } @@ -35,7 +41,13 @@ func (c *Commands) ChangeDefaultLockoutPolicy(ctx context.Context, policy *domai } instanceAgg := InstanceAggregateFromWriteModel(&existingPolicy.LockoutPolicyWriteModel.WriteModel) - changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, instanceAgg, policy.MaxPasswordAttempts, policy.ShowLockOutFailures) + changedEvent, hasChanged := existingPolicy.NewChangedEvent( + ctx, + instanceAgg, + policy.MaxPasswordAttempts, + policy.MaxOTPAttempts, + policy.ShowLockOutFailures, + ) if !hasChanged { return nil, zerrors.ThrowPreconditionFailed(nil, "INSTANCE-0psjF", "Errors.IAM.LockoutPolicy.NotChanged") } @@ -65,7 +77,8 @@ func (c *Commands) defaultLockoutPolicyWriteModelByID(ctx context.Context) (poli func prepareAddDefaultLockoutPolicy( a *instance.Aggregate, - maxAttempts uint64, + maxPasswordAttempts, + maxOTPAttempts uint64, showLockoutFailure bool, ) preparation.Validation { return func() (preparation.CreateCommands, error) { @@ -83,7 +96,7 @@ func prepareAddDefaultLockoutPolicy( return nil, zerrors.ThrowAlreadyExists(nil, "INSTANCE-0olDf", "Errors.Instance.LockoutPolicy.AlreadyExists") } return []eventstore.Command{ - instance.NewLockoutPolicyAddedEvent(ctx, &a.Aggregate, maxAttempts, showLockoutFailure), + instance.NewLockoutPolicyAddedEvent(ctx, &a.Aggregate, maxPasswordAttempts, maxOTPAttempts, showLockoutFailure), }, nil }, nil } diff --git a/internal/command/instance_policy_password_lockout_model.go b/internal/command/instance_policy_password_lockout_model.go index dcfa0b62ca..4d529169bb 100644 --- a/internal/command/instance_policy_password_lockout_model.go +++ b/internal/command/instance_policy_password_lockout_model.go @@ -54,11 +54,15 @@ func (wm *InstanceLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilde func (wm *InstanceLockoutPolicyWriteModel) NewChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, - maxAttempts uint64, + maxPasswordAttempts, + maxOTPAttempts uint64, showLockoutFailure bool) (*instance.LockoutPolicyChangedEvent, bool) { changes := make([]policy.LockoutPolicyChanges, 0) - if wm.MaxPasswordAttempts != maxAttempts { - changes = append(changes, policy.ChangeMaxAttempts(maxAttempts)) + if wm.MaxPasswordAttempts != maxPasswordAttempts { + changes = append(changes, policy.ChangeMaxPasswordAttempts(maxPasswordAttempts)) + } + if wm.MaxOTPAttempts != maxOTPAttempts { + changes = append(changes, policy.ChangeMaxOTPAttempts(maxOTPAttempts)) } if wm.ShowLockOutFailures != showLockoutFailure { changes = append(changes, policy.ChangeShowLockOutFailures(showLockoutFailure)) diff --git a/internal/command/instance_policy_password_lockout_test.go b/internal/command/instance_policy_password_lockout_test.go index 02d5ab488d..866399caec 100644 --- a/internal/command/instance_policy_password_lockout_test.go +++ b/internal/command/instance_policy_password_lockout_test.go @@ -22,6 +22,7 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) { type args struct { ctx context.Context maxPasswordAttempts uint64 + maxOTPAttempts uint64 showLockOutFailures bool } type res struct { @@ -44,6 +45,7 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) { instance.NewLockoutPolicyAddedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, 10, + 10, true, ), ), @@ -69,6 +71,7 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) { instance.NewLockoutPolicyAddedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, 10, + 10, true, ), ), @@ -77,6 +80,7 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), maxPasswordAttempts: 10, + maxOTPAttempts: 10, showLockOutFailures: true, }, res: res{ @@ -91,7 +95,7 @@ func TestCommandSide_AddDefaultLockoutPolicy(t *testing.T) { r := &Commands{ eventstore: tt.fields.eventstore, } - got, err := r.AddDefaultLockoutPolicy(tt.args.ctx, tt.args.maxPasswordAttempts, tt.args.showLockOutFailures) + got, err := r.AddDefaultLockoutPolicy(tt.args.ctx, tt.args.maxPasswordAttempts, tt.args.maxOTPAttempts, tt.args.showLockOutFailures) if tt.res.err == nil { assert.NoError(t, err) } @@ -135,6 +139,7 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { ctx: context.Background(), policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -152,6 +157,7 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { instance.NewLockoutPolicyAddedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, 10, + 10, true, ), ), @@ -162,6 +168,7 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { ctx: context.Background(), policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -179,12 +186,13 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { instance.NewLockoutPolicyAddedEvent(context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, 10, + 10, true, ), ), ), expectPush( - newDefaultLockoutPolicyChangedEvent(context.Background(), 20, false), + newDefaultLockoutPolicyChangedEvent(context.Background(), 20, 20, false), ), ), }, @@ -192,6 +200,7 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { ctx: context.Background(), policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 20, + MaxOTPAttempts: 20, ShowLockOutFailures: false, }, }, @@ -203,6 +212,7 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { InstanceID: "INSTANCE", }, MaxPasswordAttempts: 20, + MaxOTPAttempts: 20, ShowLockOutFailures: false, }, }, @@ -227,11 +237,12 @@ func TestCommandSide_ChangeDefaultLockoutPolicy(t *testing.T) { } } -func newDefaultLockoutPolicyChangedEvent(ctx context.Context, maxAttempts uint64, showLockoutFailure bool) *instance.LockoutPolicyChangedEvent { +func newDefaultLockoutPolicyChangedEvent(ctx context.Context, maxPasswordAttempts, maxOTPAttempts uint64, showLockoutFailure bool) *instance.LockoutPolicyChangedEvent { event, _ := instance.NewLockoutPolicyChangedEvent(ctx, &instance.NewAggregate("INSTANCE").Aggregate, []policy.LockoutPolicyChanges{ - policy.ChangeMaxAttempts(maxAttempts), + policy.ChangeMaxPasswordAttempts(maxPasswordAttempts), + policy.ChangeMaxOTPAttempts(maxOTPAttempts), policy.ChangeShowLockOutFailures(showLockoutFailure), }, ) diff --git a/internal/command/org_policy_lockout.go b/internal/command/org_policy_lockout.go index 47f98d9770..052fd9e239 100644 --- a/internal/command/org_policy_lockout.go +++ b/internal/command/org_policy_lockout.go @@ -21,7 +21,13 @@ func (c *Commands) AddLockoutPolicy(ctx context.Context, resourceOwner string, p } orgAgg := OrgAggregateFromWriteModel(&addedPolicy.WriteModel) - pushedEvents, err := c.eventstore.Push(ctx, org.NewLockoutPolicyAddedEvent(ctx, orgAgg, policy.MaxPasswordAttempts, policy.ShowLockOutFailures)) + pushedEvents, err := c.eventstore.Push(ctx, org.NewLockoutPolicyAddedEvent( + ctx, + orgAgg, + policy.MaxPasswordAttempts, + policy.MaxOTPAttempts, + policy.ShowLockOutFailures, + )) if err != nil { return nil, err } @@ -45,7 +51,7 @@ func (c *Commands) ChangeLockoutPolicy(ctx context.Context, resourceOwner string } orgAgg := OrgAggregateFromWriteModel(&existingPolicy.LockoutPolicyWriteModel.WriteModel) - changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.MaxPasswordAttempts, policy.ShowLockOutFailures) + changedEvent, hasChanged := existingPolicy.NewChangedEvent(ctx, orgAgg, policy.MaxPasswordAttempts, policy.MaxOTPAttempts, policy.ShowLockOutFailures) if !hasChanged { return nil, zerrors.ThrowPreconditionFailed(nil, "ORG-0JFSr", "Errors.Org.LockoutPolicy.NotChanged") } @@ -106,3 +112,20 @@ func (c *Commands) orgLockoutPolicyWriteModelByID(ctx context.Context, orgID str } return policy, nil } + +func (c *Commands) getLockoutPolicy(ctx context.Context, orgID string) (*domain.LockoutPolicy, error) { + orgWm, err := c.orgLockoutPolicyWriteModelByID(ctx, orgID) + if err != nil { + return nil, err + } + if orgWm.State == domain.PolicyStateActive { + return writeModelToLockoutPolicy(&orgWm.LockoutPolicyWriteModel), nil + } + instanceWm, err := c.defaultLockoutPolicyWriteModelByID(ctx) + if err != nil { + return nil, err + } + policy := writeModelToLockoutPolicy(&instanceWm.LockoutPolicyWriteModel) + policy.Default = true + return policy, nil +} diff --git a/internal/command/org_policy_lockout_model.go b/internal/command/org_policy_lockout_model.go index abf893fece..9749183e5a 100644 --- a/internal/command/org_policy_lockout_model.go +++ b/internal/command/org_policy_lockout_model.go @@ -55,11 +55,15 @@ func (wm *OrgLockoutPolicyWriteModel) Query() *eventstore.SearchQueryBuilder { func (wm *OrgLockoutPolicyWriteModel) NewChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, - maxAttempts uint64, + maxPasswordAttempts, + maxOTPAttempts uint64, showLockoutFailure bool) (*org.LockoutPolicyChangedEvent, bool) { changes := make([]policy.LockoutPolicyChanges, 0) - if wm.MaxPasswordAttempts != maxAttempts { - changes = append(changes, policy.ChangeMaxAttempts(maxAttempts)) + if wm.MaxPasswordAttempts != maxPasswordAttempts { + changes = append(changes, policy.ChangeMaxPasswordAttempts(maxPasswordAttempts)) + } + if wm.MaxOTPAttempts != maxOTPAttempts { + changes = append(changes, policy.ChangeMaxOTPAttempts(maxOTPAttempts)) } if wm.ShowLockOutFailures != showLockoutFailure { changes = append(changes, policy.ChangeShowLockOutFailures(showLockoutFailure)) diff --git a/internal/command/org_policy_lockout_test.go b/internal/command/org_policy_lockout_test.go index 1eda5f348c..89444d8dc2 100644 --- a/internal/command/org_policy_lockout_test.go +++ b/internal/command/org_policy_lockout_test.go @@ -44,6 +44,7 @@ func TestCommandSide_AddPasswordLockoutPolicy(t *testing.T) { ctx: context.Background(), policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -61,6 +62,7 @@ func TestCommandSide_AddPasswordLockoutPolicy(t *testing.T) { org.NewLockoutPolicyAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, 10, + 10, true, ), ), @@ -72,6 +74,7 @@ func TestCommandSide_AddPasswordLockoutPolicy(t *testing.T) { orgID: "org1", policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -89,6 +92,7 @@ func TestCommandSide_AddPasswordLockoutPolicy(t *testing.T) { org.NewLockoutPolicyAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, 10, + 10, true, ), ), @@ -99,6 +103,7 @@ func TestCommandSide_AddPasswordLockoutPolicy(t *testing.T) { orgID: "org1", policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -109,6 +114,7 @@ func TestCommandSide_AddPasswordLockoutPolicy(t *testing.T) { ResourceOwner: "org1", }, MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -163,6 +169,7 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { ctx: context.Background(), policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -183,6 +190,7 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { orgID: "org1", policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -200,6 +208,7 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { org.NewLockoutPolicyAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, 10, + 10, true, ), ), @@ -211,6 +220,7 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { orgID: "org1", policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 10, + MaxOTPAttempts: 10, ShowLockOutFailures: true, }, }, @@ -228,12 +238,13 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { org.NewLockoutPolicyAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, 10, + 10, true, ), ), ), expectPush( - newPasswordLockoutPolicyChangedEvent(context.Background(), "org1", 5, false), + newPasswordLockoutPolicyChangedEvent(context.Background(), "org1", 5, 5, false), ), ), }, @@ -242,6 +253,7 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { orgID: "org1", policy: &domain.LockoutPolicy{ MaxPasswordAttempts: 5, + MaxOTPAttempts: 5, ShowLockOutFailures: false, }, }, @@ -252,6 +264,7 @@ func TestCommandSide_ChangePasswordLockoutPolicy(t *testing.T) { ResourceOwner: "org1", }, MaxPasswordAttempts: 5, + MaxOTPAttempts: 5, ShowLockOutFailures: false, }, }, @@ -334,6 +347,7 @@ func TestCommandSide_RemovePasswordLockoutPolicy(t *testing.T) { org.NewLockoutPolicyAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate, 10, + 10, true, ), ), @@ -371,11 +385,12 @@ func TestCommandSide_RemovePasswordLockoutPolicy(t *testing.T) { } } -func newPasswordLockoutPolicyChangedEvent(ctx context.Context, orgID string, maxAttempts uint64, showLockoutFailure bool) *org.LockoutPolicyChangedEvent { +func newPasswordLockoutPolicyChangedEvent(ctx context.Context, orgID string, maxPasswordAttempts, maxOTPAttempts uint64, showLockoutFailure bool) *org.LockoutPolicyChangedEvent { event, _ := org.NewLockoutPolicyChangedEvent(ctx, &org.NewAggregate(orgID).Aggregate, []policy.LockoutPolicyChanges{ - policy.ChangeMaxAttempts(maxAttempts), + policy.ChangeMaxPasswordAttempts(maxPasswordAttempts), + policy.ChangeMaxOTPAttempts(maxOTPAttempts), policy.ChangeShowLockOutFailures(showLockoutFailure), }, ) diff --git a/internal/command/policy_password_lockout_model.go b/internal/command/policy_password_lockout_model.go index a931b63b65..a772cd9828 100644 --- a/internal/command/policy_password_lockout_model.go +++ b/internal/command/policy_password_lockout_model.go @@ -10,6 +10,7 @@ type LockoutPolicyWriteModel struct { eventstore.WriteModel MaxPasswordAttempts uint64 + MaxOTPAttempts uint64 ShowLockOutFailures bool State domain.PolicyState } @@ -19,12 +20,16 @@ func (wm *LockoutPolicyWriteModel) Reduce() error { switch e := event.(type) { case *policy.LockoutPolicyAddedEvent: wm.MaxPasswordAttempts = e.MaxPasswordAttempts + wm.MaxOTPAttempts = e.MaxOTPAttempts wm.ShowLockOutFailures = e.ShowLockOutFailures wm.State = domain.PolicyStateActive case *policy.LockoutPolicyChangedEvent: if e.MaxPasswordAttempts != nil { wm.MaxPasswordAttempts = *e.MaxPasswordAttempts } + if e.MaxOTPAttempts != nil { + wm.MaxOTPAttempts = *e.MaxOTPAttempts + } if e.ShowLockOutFailures != nil { wm.ShowLockOutFailures = *e.ShowLockOutFailures } diff --git a/internal/command/user_human_otp.go b/internal/command/user_human_otp.go index 21e0021d44..fd717c0de4 100644 --- a/internal/command/user_human_otp.go +++ b/internal/command/user_human_otp.go @@ -158,14 +158,37 @@ func (c *Commands) HumanCheckMFATOTP(ctx context.Context, userID, code, resource return zerrors.ThrowPreconditionFailed(nil, "COMMAND-3Mif9s", "Errors.User.MFA.OTP.NotReady") } userAgg := UserAggregateFromWriteModel(&existingOTP.WriteModel) - err = domain.VerifyTOTP(code, existingOTP.Secret, c.multifactors.OTP.CryptoMFA) - if err == nil { + verifyErr := domain.VerifyTOTP(code, existingOTP.Secret, c.multifactors.OTP.CryptoMFA) + + // recheck for additional events (failed OTP checks or locks) + recheckErr := c.eventstore.FilterToQueryReducer(ctx, existingOTP) + if recheckErr != nil { + return recheckErr + } + if existingOTP.UserLocked { + return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SF3fg", "Errors.User.Locked") + } + + // the OTP check succeeded and the user was not locked in the meantime + if verifyErr == nil { _, err = c.eventstore.Push(ctx, user.NewHumanOTPCheckSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) return err } - _, pushErr := c.eventstore.Push(ctx, user.NewHumanOTPCheckFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + + // the OTP check failed, therefore check if the limit was reached and the user must additionally be locked + commands := make([]eventstore.Command, 0, 2) + commands = append(commands, user.NewHumanOTPCheckFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + lockoutPolicy, err := c.getLockoutPolicy(ctx, resourceOwner) + if err != nil { + return err + } + if lockoutPolicy.MaxOTPAttempts > 0 && existingOTP.CheckFailedCount+1 >= lockoutPolicy.MaxOTPAttempts { + commands = append(commands, user.NewUserLockedEvent(ctx, userAgg)) + } + + _, pushErr := c.eventstore.Push(ctx, commands...) logging.OnError(pushErr).Error("error create password check failed event") - return err + return verifyErr } func (c *Commands) HumanRemoveTOTP(ctx context.Context, userID, resourceOwner string) (*domain.ObjectDetails, error) { @@ -515,14 +538,37 @@ func (c *Commands) humanCheckOTP( return zerrors.ThrowPreconditionFailed(nil, "COMMAND-S34gh", "Errors.User.Code.NotFound") } userAgg := &user.NewAggregate(userID, existingOTP.ResourceOwner()).Aggregate - err = crypto.VerifyCode(existingOTP.CodeCreationDate(), existingOTP.CodeExpiry(), existingOTP.Code(), code, c.userEncryption) - if err == nil { + verifyErr := crypto.VerifyCode(existingOTP.CodeCreationDate(), existingOTP.CodeExpiry(), existingOTP.Code(), code, c.userEncryption) + + // recheck for additional events (failed OTP checks or locks) + recheckErr := c.eventstore.FilterToQueryReducer(ctx, existingOTP) + if recheckErr != nil { + return recheckErr + } + if existingOTP.UserLocked() { + return zerrors.ThrowPreconditionFailed(nil, "COMMAND-S6h4R", "Errors.User.Locked") + } + + // the OTP check succeeded and the user was not locked in the meantime + if verifyErr == nil { _, err = c.eventstore.Push(ctx, checkSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) return err } - _, pushErr := c.eventstore.Push(ctx, checkFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + + // the OTP check failed, therefore check if the limit was reached and the user must additionally be locked + commands := make([]eventstore.Command, 0, 2) + commands = append(commands, checkFailedEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest))) + lockoutPolicy, err := c.getLockoutPolicy(ctx, resourceOwner) + if err != nil { + return err + } + if lockoutPolicy.MaxOTPAttempts > 0 && existingOTP.CheckFailedCount()+1 >= lockoutPolicy.MaxOTPAttempts { + commands = append(commands, user.NewUserLockedEvent(ctx, userAgg)) + } + + _, pushErr := c.eventstore.Push(ctx, commands...) logging.WithFields("userID", userID).OnError(pushErr).Error("otp failure check push failed") - return err + return verifyErr } func (c *Commands) totpWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *HumanTOTPWriteModel, err error) { diff --git a/internal/command/user_human_otp_model.go b/internal/command/user_human_otp_model.go index 25bd4c9ef5..43abc14349 100644 --- a/internal/command/user_human_otp_model.go +++ b/internal/command/user_human_otp_model.go @@ -12,8 +12,10 @@ import ( type HumanTOTPWriteModel struct { eventstore.WriteModel - State domain.MFAState - Secret *crypto.CryptoValue + State domain.MFAState + Secret *crypto.CryptoValue + CheckFailedCount uint64 + UserLocked bool } func NewHumanTOTPWriteModel(userID, resourceOwner string) *HumanTOTPWriteModel { @@ -33,6 +35,16 @@ func (wm *HumanTOTPWriteModel) Reduce() error { wm.State = domain.MFAStateNotReady case *user.HumanOTPVerifiedEvent: wm.State = domain.MFAStateReady + wm.CheckFailedCount = 0 + case *user.HumanOTPCheckSucceededEvent: + wm.CheckFailedCount = 0 + case *user.HumanOTPCheckFailedEvent: + wm.CheckFailedCount++ + case *user.UserLockedEvent: + wm.UserLocked = true + case *user.UserUnlockedEvent: + wm.CheckFailedCount = 0 + wm.UserLocked = false case *user.HumanOTPRemovedEvent: wm.State = domain.MFAStateRemoved case *user.UserRemovedEvent: @@ -50,6 +62,10 @@ func (wm *HumanTOTPWriteModel) Query() *eventstore.SearchQueryBuilder { EventTypes(user.HumanMFAOTPAddedType, user.HumanMFAOTPVerifiedType, user.HumanMFAOTPRemovedType, + user.HumanMFAOTPCheckSucceededType, + user.HumanMFAOTPCheckFailedType, + user.UserLockedType, + user.UserUnlockedType, user.UserRemovedType, user.UserV1MFAOTPAddedType, user.UserV1MFAOTPVerifiedType, @@ -72,6 +88,9 @@ type OTPCodeWriteModel interface { CodeCreationDate() time.Time CodeExpiry() time.Duration Code() *crypto.CryptoValue + CheckFailedCount() uint64 + UserLocked() bool + eventstore.QueryReducer } type HumanOTPSMSWriteModel struct { @@ -141,6 +160,9 @@ type HumanOTPSMSCodeWriteModel struct { code *crypto.CryptoValue codeCreationDate time.Time codeExpiry time.Duration + + checkFailedCount uint64 + userLocked bool } func (wm *HumanOTPSMSCodeWriteModel) CodeCreationDate() time.Time { @@ -155,6 +177,14 @@ func (wm *HumanOTPSMSCodeWriteModel) Code() *crypto.CryptoValue { return wm.code } +func (wm *HumanOTPSMSCodeWriteModel) CheckFailedCount() uint64 { + return wm.checkFailedCount +} + +func (wm *HumanOTPSMSCodeWriteModel) UserLocked() bool { + return wm.userLocked +} + func NewHumanOTPSMSCodeWriteModel(userID, resourceOwner string) *HumanOTPSMSCodeWriteModel { return &HumanOTPSMSCodeWriteModel{ HumanOTPSMSWriteModel: NewHumanOTPSMSWriteModel(userID, resourceOwner), @@ -163,10 +193,20 @@ func NewHumanOTPSMSCodeWriteModel(userID, resourceOwner string) *HumanOTPSMSCode func (wm *HumanOTPSMSCodeWriteModel) Reduce() error { for _, event := range wm.Events { - if e, ok := event.(*user.HumanOTPSMSCodeAddedEvent); ok { + switch e := event.(type) { + case *user.HumanOTPSMSCodeAddedEvent: wm.code = e.Code wm.codeCreationDate = e.CreationDate() wm.codeExpiry = e.Expiry + case *user.HumanOTPSMSCheckSucceededEvent: + wm.checkFailedCount = 0 + case *user.HumanOTPSMSCheckFailedEvent: + wm.checkFailedCount++ + case *user.UserLockedEvent: + wm.userLocked = true + case *user.UserUnlockedEvent: + wm.checkFailedCount = 0 + wm.userLocked = false } } return wm.HumanOTPSMSWriteModel.Reduce() @@ -179,6 +219,10 @@ func (wm *HumanOTPSMSCodeWriteModel) Query() *eventstore.SearchQueryBuilder { AggregateIDs(wm.AggregateID). EventTypes( user.HumanOTPSMSCodeAddedType, + user.HumanOTPSMSCheckSucceededType, + user.HumanOTPSMSCheckFailedType, + user.UserLockedType, + user.UserUnlockedType, user.HumanPhoneVerifiedType, user.HumanOTPSMSAddedType, user.HumanOTPSMSRemovedType, @@ -259,6 +303,9 @@ type HumanOTPEmailCodeWriteModel struct { code *crypto.CryptoValue codeCreationDate time.Time codeExpiry time.Duration + + checkFailedCount uint64 + userLocked bool } func (wm *HumanOTPEmailCodeWriteModel) CodeCreationDate() time.Time { @@ -273,6 +320,14 @@ func (wm *HumanOTPEmailCodeWriteModel) Code() *crypto.CryptoValue { return wm.code } +func (wm *HumanOTPEmailCodeWriteModel) CheckFailedCount() uint64 { + return wm.checkFailedCount +} + +func (wm *HumanOTPEmailCodeWriteModel) UserLocked() bool { + return wm.userLocked +} + func NewHumanOTPEmailCodeWriteModel(userID, resourceOwner string) *HumanOTPEmailCodeWriteModel { return &HumanOTPEmailCodeWriteModel{ HumanOTPEmailWriteModel: NewHumanOTPEmailWriteModel(userID, resourceOwner), @@ -281,10 +336,20 @@ func NewHumanOTPEmailCodeWriteModel(userID, resourceOwner string) *HumanOTPEmail func (wm *HumanOTPEmailCodeWriteModel) Reduce() error { for _, event := range wm.Events { - if e, ok := event.(*user.HumanOTPEmailCodeAddedEvent); ok { + switch e := event.(type) { + case *user.HumanOTPEmailCodeAddedEvent: wm.code = e.Code wm.codeCreationDate = e.CreationDate() wm.codeExpiry = e.Expiry + case *user.HumanOTPEmailCheckSucceededEvent: + wm.checkFailedCount = 0 + case *user.HumanOTPEmailCheckFailedEvent: + wm.checkFailedCount++ + case *user.UserLockedEvent: + wm.userLocked = true + case *user.UserUnlockedEvent: + wm.checkFailedCount = 0 + wm.userLocked = false } } return wm.HumanOTPEmailWriteModel.Reduce() @@ -297,6 +362,10 @@ func (wm *HumanOTPEmailCodeWriteModel) Query() *eventstore.SearchQueryBuilder { AggregateIDs(wm.AggregateID). EventTypes( user.HumanOTPEmailCodeAddedType, + user.HumanOTPEmailCheckSucceededType, + user.HumanOTPEmailCheckFailedType, + user.UserLockedType, + user.UserUnlockedType, user.HumanEmailVerifiedType, user.HumanOTPEmailAddedType, user.HumanOTPEmailRemovedType, diff --git a/internal/command/user_human_otp_test.go b/internal/command/user_human_otp_test.go index 490751610d..838e2357c6 100644 --- a/internal/command/user_human_otp_test.go +++ b/internal/command/user_human_otp_test.go @@ -1671,6 +1671,15 @@ func TestCommandSide_HumanCheckOTPSMS(t *testing.T) { ), ), ), + expectFilter(), // recheck + expectFilter( + eventFromEventPusher( + org.NewLockoutPolicyAddedEvent(ctx, + &org.NewAggregate("orgID").Aggregate, + 3, 3, true, + ), + ), + ), expectPush( user.NewHumanOTPSMSCheckFailedEvent(ctx, &user.NewAggregate("user1", "org1").Aggregate, @@ -1707,6 +1716,86 @@ func TestCommandSide_HumanCheckOTPSMS(t *testing.T) { err: zerrors.ThrowInvalidArgument(nil, "CODE-woT0xc", "Errors.User.Code.Invalid"), }, }, + { + name: "invalid code, max attempts reached, error", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPSMSCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("other-code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectFilter(), // recheck + expectFilter( + eventFromEventPusher( + org.NewLockoutPolicyAddedEvent(ctx, + &org.NewAggregate("orgID").Aggregate, + 1, 1, true, + ), + ), + ), + expectPush( + user.NewHumanOTPSMSCheckFailedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + user.NewUserLockedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + err: zerrors.ThrowInvalidArgument(nil, "CODE-woT0xc", "Errors.User.Code.Invalid"), + }, + }, { name: "code ok", fields: fields{ @@ -1739,6 +1828,7 @@ func TestCommandSide_HumanCheckOTPSMS(t *testing.T) { ), ), ), + expectFilter(), // recheck expectPush( user.NewHumanOTPSMSCheckSucceededEvent(ctx, &user.NewAggregate("user1", "org1").Aggregate, @@ -1777,6 +1867,65 @@ func TestCommandSide_HumanCheckOTPSMS(t *testing.T) { }, }, }, + { + name: "code ok, locked in the meantime", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPSMSAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPSMSCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectFilter( // recheck + user.NewUserLockedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + err: zerrors.ThrowPreconditionFailed(nil, "COMMAND-S6h4R", "Errors.User.Locked"), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -2616,6 +2765,15 @@ func TestCommandSide_HumanCheckOTPEmail(t *testing.T) { ), ), ), + expectFilter(), // recheck + expectFilter( + eventFromEventPusher( + org.NewLockoutPolicyAddedEvent(ctx, + &org.NewAggregate("orgID").Aggregate, + 3, 3, true, + ), + ), + ), expectPush( user.NewHumanOTPEmailCheckFailedEvent(ctx, &user.NewAggregate("user1", "org1").Aggregate, @@ -2652,6 +2810,86 @@ func TestCommandSide_HumanCheckOTPEmail(t *testing.T) { err: zerrors.ThrowInvalidArgument(nil, "CODE-woT0xc", "Errors.User.Code.Invalid"), }, }, + { + name: "invalid code, max attempts reached, error", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPEmailCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("other-code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectFilter(), // recheck + expectFilter( + eventFromEventPusher( + org.NewLockoutPolicyAddedEvent(ctx, + &org.NewAggregate("orgID").Aggregate, + 1, 1, true, + ), + ), + ), + expectPush( + user.NewHumanOTPEmailCheckFailedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + user.NewUserLockedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + err: zerrors.ThrowInvalidArgument(nil, "CODE-woT0xc", "Errors.User.Code.Invalid"), + }, + }, { name: "code ok", fields: fields{ @@ -2684,6 +2922,7 @@ func TestCommandSide_HumanCheckOTPEmail(t *testing.T) { ), ), ), + expectFilter(), // recheck expectPush( user.NewHumanOTPEmailCheckSucceededEvent(ctx, &user.NewAggregate("user1", "org1").Aggregate, @@ -2722,6 +2961,65 @@ func TestCommandSide_HumanCheckOTPEmail(t *testing.T) { }, }, }, + { + name: "code ok, locked in the meantime", + fields: fields{ + eventstore: expectEventstore( + expectFilter( + eventFromEventPusher( + user.NewHumanOTPEmailAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + eventFromEventPusherWithCreationDateNow( + user.NewHumanOTPEmailCodeAddedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("code"), + }, + time.Hour, + &user.AuthRequestInfo{ + ID: "authRequestID", + UserAgentID: "userAgentID", + BrowserInfo: &user.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + ), + ), + ), + expectFilter( // recheck + user.NewUserLockedEvent(ctx, + &user.NewAggregate("user1", "org1").Aggregate, + ), + ), + ), + userEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + }, + args: args{ + ctx: ctx, + userID: "user1", + code: "code", + resourceOwner: "org1", + authRequest: &domain.AuthRequest{ + ID: "authRequestID", + AgentID: "userAgentID", + BrowserInfo: &domain.BrowserInfo{ + UserAgent: "user-agent", + AcceptLanguage: "en", + RemoteIP: net.IP{192, 0, 2, 1}, + }, + }, + }, + res: res{ + err: zerrors.ThrowPreconditionFailed(nil, "COMMAND-S6h4R", "Errors.User.Locked"), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/command/user_human_password_test.go b/internal/command/user_human_password_test.go index bb0fa9b26f..0c2b21b3d8 100644 --- a/internal/command/user_human_password_test.go +++ b/internal/command/user_human_password_test.go @@ -1643,6 +1643,7 @@ func TestCommandSide_CheckPassword(t *testing.T) { }, lockoutPolicy: &domain.LockoutPolicy{ MaxPasswordAttempts: 1, + MaxOTPAttempts: 1, }, }, res: res{ diff --git a/internal/domain/policy_password_lockout.go b/internal/domain/policy_password_lockout.go index ddac4de427..a5c304cd69 100644 --- a/internal/domain/policy_password_lockout.go +++ b/internal/domain/policy_password_lockout.go @@ -9,5 +9,6 @@ type LockoutPolicy struct { Default bool MaxPasswordAttempts uint64 + MaxOTPAttempts uint64 ShowLockOutFailures bool } diff --git a/internal/query/lockout_policy.go b/internal/query/lockout_policy.go index 7aa650b191..64be9b0b76 100644 --- a/internal/query/lockout_policy.go +++ b/internal/query/lockout_policy.go @@ -27,6 +27,7 @@ type LockoutPolicy struct { State domain.PolicyState MaxPasswordAttempts uint64 + MaxOTPAttempts uint64 ShowFailures bool IsDefault bool @@ -69,6 +70,10 @@ var ( name: projection.LockoutPolicyMaxPasswordAttemptsCol, table: lockoutTable, } + LockoutColMaxOTPAttempts = Column{ + name: projection.LockoutPolicyMaxOTPAttemptsCol, + table: lockoutTable, + } LockoutColIsDefault = Column{ name: projection.LockoutPolicyIsDefaultCol, table: lockoutTable, @@ -77,13 +82,9 @@ var ( name: projection.LockoutPolicyStateCol, table: lockoutTable, } - LockoutPolicyOwnerRemoved = Column{ - name: projection.LockoutPolicyOwnerRemovedCol, - table: lockoutTable, - } ) -func (q *Queries) LockoutPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (policy *LockoutPolicy, err error) { +func (q *Queries) LockoutPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string) (policy *LockoutPolicy, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() @@ -96,9 +97,6 @@ func (q *Queries) LockoutPolicyByOrg(ctx context.Context, shouldTriggerBulk bool eq := sq.Eq{ LockoutColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), } - if !withOwnerRemoved { - eq[LockoutPolicyOwnerRemoved.identifier()] = false - } stmt, scan := prepareLockoutPolicyQuery(ctx, q.client) query, args, err := stmt.Where( @@ -153,6 +151,7 @@ func prepareLockoutPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Sele LockoutColResourceOwner.identifier(), LockoutColShowFailures.identifier(), LockoutColMaxPasswordAttempts.identifier(), + LockoutColMaxOTPAttempts.identifier(), LockoutColIsDefault.identifier(), LockoutColState.identifier(), ). @@ -168,6 +167,7 @@ func prepareLockoutPolicyQuery(ctx context.Context, db prepareDatabase) (sq.Sele &policy.ResourceOwner, &policy.ShowFailures, &policy.MaxPasswordAttempts, + &policy.MaxOTPAttempts, &policy.IsDefault, &policy.State, ) diff --git a/internal/query/lockout_policy_test.go b/internal/query/lockout_policy_test.go index 044f6c291b..2805ef8fdc 100644 --- a/internal/query/lockout_policy_test.go +++ b/internal/query/lockout_policy_test.go @@ -13,16 +13,17 @@ import ( ) var ( - prepareLockoutPolicyStmt = `SELECT projections.lockout_policies2.id,` + - ` projections.lockout_policies2.sequence,` + - ` projections.lockout_policies2.creation_date,` + - ` projections.lockout_policies2.change_date,` + - ` projections.lockout_policies2.resource_owner,` + - ` projections.lockout_policies2.show_failure,` + - ` projections.lockout_policies2.max_password_attempts,` + - ` projections.lockout_policies2.is_default,` + - ` projections.lockout_policies2.state` + - ` FROM projections.lockout_policies2` + + prepareLockoutPolicyStmt = `SELECT projections.lockout_policies3.id,` + + ` projections.lockout_policies3.sequence,` + + ` projections.lockout_policies3.creation_date,` + + ` projections.lockout_policies3.change_date,` + + ` projections.lockout_policies3.resource_owner,` + + ` projections.lockout_policies3.show_failure,` + + ` projections.lockout_policies3.max_password_attempts,` + + ` projections.lockout_policies3.max_otp_attempts,` + + ` projections.lockout_policies3.is_default,` + + ` projections.lockout_policies3.state` + + ` FROM projections.lockout_policies3` + ` AS OF SYSTEM TIME '-1 ms'` prepareLockoutPolicyCols = []string{ @@ -33,6 +34,7 @@ var ( "resource_owner", "show_failure", "max_password_attempts", + "max_otp_attempts", "is_default", "state", } @@ -82,6 +84,7 @@ func Test_LockoutPolicyPrepares(t *testing.T) { "ro", true, 20, + 20, true, domain.PolicyStateActive, }, @@ -96,6 +99,7 @@ func Test_LockoutPolicyPrepares(t *testing.T) { State: domain.PolicyStateActive, ShowFailures: true, MaxPasswordAttempts: 20, + MaxOTPAttempts: 20, IsDefault: true, }, }, diff --git a/internal/query/projection/lockout_policy.go b/internal/query/projection/lockout_policy.go index ceb99c2aa0..4412308b89 100644 --- a/internal/query/projection/lockout_policy.go +++ b/internal/query/projection/lockout_policy.go @@ -14,7 +14,7 @@ import ( ) const ( - LockoutPolicyTable = "projections.lockout_policies2" + LockoutPolicyTable = "projections.lockout_policies3" LockoutPolicyIDCol = "id" LockoutPolicyCreationDateCol = "creation_date" @@ -25,8 +25,8 @@ const ( LockoutPolicyResourceOwnerCol = "resource_owner" LockoutPolicyInstanceIDCol = "instance_id" LockoutPolicyMaxPasswordAttemptsCol = "max_password_attempts" + LockoutPolicyMaxOTPAttemptsCol = "max_otp_attempts" LockoutPolicyShowLockOutFailuresCol = "show_failure" - LockoutPolicyOwnerRemovedCol = "owner_removed" ) type lockoutPolicyProjection struct{} @@ -51,11 +51,10 @@ func (*lockoutPolicyProjection) Init() *old_handler.Check { handler.NewColumn(LockoutPolicyResourceOwnerCol, handler.ColumnTypeText), handler.NewColumn(LockoutPolicyInstanceIDCol, handler.ColumnTypeText), handler.NewColumn(LockoutPolicyMaxPasswordAttemptsCol, handler.ColumnTypeInt64), + handler.NewColumn(LockoutPolicyMaxOTPAttemptsCol, handler.ColumnTypeInt64, handler.Default(0)), handler.NewColumn(LockoutPolicyShowLockOutFailuresCol, handler.ColumnTypeBool), - handler.NewColumn(LockoutPolicyOwnerRemovedCol, handler.ColumnTypeBool, handler.Default(false)), }, handler.NewPrimaryKey(LockoutPolicyInstanceIDCol, LockoutPolicyIDCol), - handler.WithIndex(handler.NewIndex("owner_removed", []string{LockoutPolicyOwnerRemovedCol})), ), ) } @@ -125,6 +124,7 @@ func (p *lockoutPolicyProjection) reduceAdded(event eventstore.Event) (*handler. handler.NewCol(LockoutPolicyIDCol, policyEvent.Aggregate().ID), handler.NewCol(LockoutPolicyStateCol, domain.PolicyStateActive), handler.NewCol(LockoutPolicyMaxPasswordAttemptsCol, policyEvent.MaxPasswordAttempts), + handler.NewCol(LockoutPolicyMaxOTPAttemptsCol, policyEvent.MaxOTPAttempts), handler.NewCol(LockoutPolicyShowLockOutFailuresCol, policyEvent.ShowLockOutFailures), handler.NewCol(LockoutPolicyIsDefaultCol, isDefault), handler.NewCol(LockoutPolicyResourceOwnerCol, policyEvent.Aggregate().ResourceOwner), @@ -149,6 +149,9 @@ func (p *lockoutPolicyProjection) reduceChanged(event eventstore.Event) (*handle if policyEvent.MaxPasswordAttempts != nil { cols = append(cols, handler.NewCol(LockoutPolicyMaxPasswordAttemptsCol, *policyEvent.MaxPasswordAttempts)) } + if policyEvent.MaxOTPAttempts != nil { + cols = append(cols, handler.NewCol(LockoutPolicyMaxOTPAttemptsCol, *policyEvent.MaxOTPAttempts)) + } if policyEvent.ShowLockOutFailures != nil { cols = append(cols, handler.NewCol(LockoutPolicyShowLockOutFailuresCol, *policyEvent.ShowLockOutFailures)) } diff --git a/internal/query/projection/lockout_policy_test.go b/internal/query/projection/lockout_policy_test.go index 781f3a48c4..f44e1f4f0b 100644 --- a/internal/query/projection/lockout_policy_test.go +++ b/internal/query/projection/lockout_policy_test.go @@ -30,6 +30,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { org.AggregateType, []byte(`{ "maxPasswordAttempts": 10, + "maxOTPAttempts": 10, "showLockOutFailures": true }`), ), org.LockoutPolicyAddedEventMapper), @@ -41,7 +42,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.lockout_policies2 (creation_date, change_date, sequence, id, state, max_password_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.lockout_policies3 (creation_date, change_date, sequence, id, state, max_password_attempts, max_otp_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -49,6 +50,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { "agg-id", domain.PolicyStateActive, uint64(10), + uint64(10), true, false, "ro-id", @@ -69,6 +71,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { org.AggregateType, []byte(`{ "maxPasswordAttempts": 10, + "maxOTPAttempts": 10, "showLockOutFailures": true }`), ), org.LockoutPolicyChangedEventMapper), @@ -79,11 +82,12 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.lockout_policies2 SET (change_date, sequence, max_password_attempts, show_failure) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.lockout_policies3 SET (change_date, sequence, max_password_attempts, max_otp_attempts, show_failure) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), uint64(10), + uint64(10), true, "agg-id", "instance-id", @@ -110,7 +114,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.lockout_policies2 WHERE (id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.lockout_policies3 WHERE (id = $1) AND (instance_id = $2)", expectedArgs: []interface{}{ "agg-id", "instance-id", @@ -137,7 +141,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.lockout_policies2 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.lockout_policies3 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, @@ -156,6 +160,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { instance.AggregateType, []byte(`{ "maxPasswordAttempts": 10, + "maxOTPAttempts": 10, "showLockOutFailures": true }`), ), instance.LockoutPolicyAddedEventMapper), @@ -166,7 +171,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.lockout_policies2 (creation_date, change_date, sequence, id, state, max_password_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + expectedStmt: "INSERT INTO projections.lockout_policies3 (creation_date, change_date, sequence, id, state, max_password_attempts, max_otp_attempts, show_failure, is_default, resource_owner, instance_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", expectedArgs: []interface{}{ anyArg{}, anyArg{}, @@ -174,6 +179,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { "agg-id", domain.PolicyStateActive, uint64(10), + uint64(10), true, true, "ro-id", @@ -194,6 +200,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { instance.AggregateType, []byte(`{ "maxPasswordAttempts": 10, + "maxOTPAttempts": 10, "showLockOutFailures": true }`), ), instance.LockoutPolicyChangedEventMapper), @@ -204,11 +211,12 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.lockout_policies2 SET (change_date, sequence, max_password_attempts, show_failure) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)", + expectedStmt: "UPDATE projections.lockout_policies3 SET (change_date, sequence, max_password_attempts, max_otp_attempts, show_failure) = ($1, $2, $3, $4, $5) WHERE (id = $6) AND (instance_id = $7)", expectedArgs: []interface{}{ anyArg{}, uint64(15), uint64(10), + uint64(10), true, "agg-id", "instance-id", @@ -235,7 +243,7 @@ func TestLockoutPolicyProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.lockout_policies2 WHERE (instance_id = $1) AND (resource_owner = $2)", + expectedStmt: "DELETE FROM projections.lockout_policies3 WHERE (instance_id = $1) AND (resource_owner = $2)", expectedArgs: []interface{}{ "instance-id", "agg-id", diff --git a/internal/repository/instance/policy_password_lockout.go b/internal/repository/instance/policy_password_lockout.go index 671b539610..b05f992668 100644 --- a/internal/repository/instance/policy_password_lockout.go +++ b/internal/repository/instance/policy_password_lockout.go @@ -19,7 +19,8 @@ type LockoutPolicyAddedEvent struct { func NewLockoutPolicyAddedEvent( ctx context.Context, aggregate *eventstore.Aggregate, - maxAttempts uint64, + maxPasswordAttempts, + maxOTPAttempts uint64, showLockoutFailure bool, ) *LockoutPolicyAddedEvent { return &LockoutPolicyAddedEvent{ @@ -28,7 +29,8 @@ func NewLockoutPolicyAddedEvent( ctx, aggregate, LockoutPolicyAddedEventType), - maxAttempts, + maxPasswordAttempts, + maxOTPAttempts, showLockoutFailure), } } diff --git a/internal/repository/org/policy_password_lockout.go b/internal/repository/org/policy_password_lockout.go index e95d86eb79..8ada7f2320 100644 --- a/internal/repository/org/policy_password_lockout.go +++ b/internal/repository/org/policy_password_lockout.go @@ -20,7 +20,8 @@ type LockoutPolicyAddedEvent struct { func NewLockoutPolicyAddedEvent( ctx context.Context, aggregate *eventstore.Aggregate, - maxAttempts uint64, + maxPasswordAttempts, + maxOTPAttempts uint64, showLockoutFailure bool, ) *LockoutPolicyAddedEvent { return &LockoutPolicyAddedEvent{ @@ -29,7 +30,8 @@ func NewLockoutPolicyAddedEvent( ctx, aggregate, LockoutPolicyAddedEventType), - maxAttempts, + maxPasswordAttempts, + maxOTPAttempts, showLockoutFailure), } } diff --git a/internal/repository/policy/policy_password_lockout.go b/internal/repository/policy/policy_password_lockout.go index 8ca0737674..ec500144ef 100644 --- a/internal/repository/policy/policy_password_lockout.go +++ b/internal/repository/policy/policy_password_lockout.go @@ -15,6 +15,7 @@ type LockoutPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` MaxPasswordAttempts uint64 `json:"maxPasswordAttempts,omitempty"` + MaxOTPAttempts uint64 `json:"maxOTPAttempts,omitempty"` ShowLockOutFailures bool `json:"showLockOutFailures,omitempty"` } @@ -28,13 +29,15 @@ func (e *LockoutPolicyAddedEvent) UniqueConstraints() []*eventstore.UniqueConstr func NewLockoutPolicyAddedEvent( base *eventstore.BaseEvent, - maxAttempts uint64, + maxPasswordAttempts, + maxOTPAttempts uint64, showLockOutFailures bool, ) *LockoutPolicyAddedEvent { return &LockoutPolicyAddedEvent{ BaseEvent: *base, - MaxPasswordAttempts: maxAttempts, + MaxPasswordAttempts: maxPasswordAttempts, + MaxOTPAttempts: maxOTPAttempts, ShowLockOutFailures: showLockOutFailures, } } @@ -56,6 +59,7 @@ type LockoutPolicyChangedEvent struct { eventstore.BaseEvent `json:"-"` MaxPasswordAttempts *uint64 `json:"maxPasswordAttempts,omitempty"` + MaxOTPAttempts *uint64 `json:"maxOTPAttempts,omitempty"` ShowLockOutFailures *bool `json:"showLockOutFailures,omitempty"` } @@ -85,12 +89,18 @@ func NewLockoutPolicyChangedEvent( type LockoutPolicyChanges func(*LockoutPolicyChangedEvent) -func ChangeMaxAttempts(maxAttempts uint64) func(*LockoutPolicyChangedEvent) { +func ChangeMaxPasswordAttempts(maxAttempts uint64) func(*LockoutPolicyChangedEvent) { return func(e *LockoutPolicyChangedEvent) { e.MaxPasswordAttempts = &maxAttempts } } +func ChangeMaxOTPAttempts(maxAttempts uint64) func(*LockoutPolicyChangedEvent) { + return func(e *LockoutPolicyChangedEvent) { + e.MaxOTPAttempts = &maxAttempts + } +} + func ChangeShowLockOutFailures(showLockOutFailures bool) func(*LockoutPolicyChangedEvent) { return func(e *LockoutPolicyChangedEvent) { e.ShowLockOutFailures = &showLockOutFailures diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index 3e42109619..5211995f23 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -6650,6 +6650,12 @@ message UpdateLockoutPolicyRequest { example: "\"10\"" } ]; + uint32 max_otp_attempts = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Maximum failed attempts for a single OTP type (TOTP, SMS, Email) before the account gets locked. Attempts are reset as soon as the OTP is entered correctly. If set to 0 the account will never be locked." + example: "\"10\"" + } + ]; } message UpdateLockoutPolicyResponse { diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto index 284b070d5d..aca7ae17ca 100644 --- a/proto/zitadel/management.proto +++ b/proto/zitadel/management.proto @@ -10412,6 +10412,12 @@ message AddCustomLockoutPolicyRequest { description: "When the user has reached the maximum password attempts the account will be locked, If this is set to 0 the lockout will not trigger." } ]; + uint32 max_otp_attempts = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Maximum failed attempts for a single OTP type (TOTP, SMS, Email) before the account gets locked. Attempts are reset as soon as the OTP is entered correctly. If set to 0 the account will never be locked." + example: "\"10\"" + } + ]; } message AddCustomLockoutPolicyResponse { @@ -10424,6 +10430,12 @@ message UpdateCustomLockoutPolicyRequest { description: "When the user has reached the maximum password attempts the account will be locked, If this is set to 0 the lockout will not trigger." } ]; + uint32 max_otp_attempts = 2 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Maximum failed attempts for a single OTP type (TOTP, SMS, Email) before the account gets locked. Attempts are reset as soon as the OTP is entered correctly. If set to 0 the account will never be locked." + example: "\"10\"" + } + ]; } message UpdateCustomLockoutPolicyResponse { diff --git a/proto/zitadel/policy.proto b/proto/zitadel/policy.proto index 8fcb976d44..75d8472103 100644 --- a/proto/zitadel/policy.proto +++ b/proto/zitadel/policy.proto @@ -337,6 +337,12 @@ message LockoutPolicy { example: "\"10\"" } ]; + uint64 max_otp_attempts = 3 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Maximum failed attempts for a single OTP type (TOTP, SMS, Email) before the account gets locked. Attempts are reset as soon as the OTP is entered correctly. If set to 0 the account will never be locked." + example: "\"10\"" + } + ]; bool is_default = 4 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "defines if the organization's admin changed the policy" diff --git a/proto/zitadel/settings/v2beta/lockout_settings.proto b/proto/zitadel/settings/v2beta/lockout_settings.proto index 10786c9282..1ff10c65f0 100644 --- a/proto/zitadel/settings/v2beta/lockout_settings.proto +++ b/proto/zitadel/settings/v2beta/lockout_settings.proto @@ -20,4 +20,10 @@ message LockoutSettings { description: "resource_owner_type returns if the settings is managed on the organization or on the instance"; } ]; + uint64 max_otp_attempts = 3 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Maximum failed attempts for a single OTP type (TOTP, SMS, Email) before the account gets locked. Attempts are reset as soon as the OTP is entered correctly. If set to 0 the account will never be locked." + example: "\"10\"" + } + ]; }