diff --git a/components/access-keys/new-item.tsx b/components/access-keys/new-item.tsx
index 256a0903..21abed88 100644
--- a/components/access-keys/new-item.tsx
+++ b/components/access-keys/new-item.tsx
@@ -15,6 +15,7 @@ import { useAccessKeys } from "@/hooks/use-access-keys"
import { useApi } from "@/contexts/api-context"
import { makeRandomString } from "@/lib/functions"
import { cn } from "@/lib/utils"
+import { isSecretKeyValid } from "@/lib/secret-key"
interface AccessKeysNewItemProps {
visible: boolean
@@ -105,8 +106,8 @@ export function AccessKeysNewItem({ visible, onVisibleChange, onSuccess, onNotic
}
if (!secretKey) {
newErrors.secretKey = t("Please enter Secret Key")
- } else if (secretKey.length < 8 || secretKey.length > 40) {
- newErrors.secretKey = t("Secret Key length must be between 8 and 40 characters")
+ } else if (!isSecretKeyValid(secretKey)) {
+ newErrors.secretKey = t("Secret Key must be at least 8 bytes")
}
if (!name) {
newErrors.name = t("Please enter name")
diff --git a/components/account/change-password-dialog.tsx b/components/account/change-password-dialog.tsx
index 72080ae7..ef6599e0 100644
--- a/components/account/change-password-dialog.tsx
+++ b/components/account/change-password-dialog.tsx
@@ -10,9 +10,7 @@ import { Field, FieldContent, FieldDescription, FieldError, FieldLabel } from "@
import { Alert, AlertDescription } from "@/components/ui/alert"
import { useAccount } from "@/hooks/use-account"
import { useMessage } from "@/lib/feedback/message"
-
-/** Mirrors the server's `SECRET_KEY_MIN_LEN`. */
-const PASSWORD_MIN_LENGTH = 8
+import { isSecretKeyValid } from "@/lib/secret-key"
interface ChangePasswordDialogProps {
open: boolean
@@ -66,8 +64,8 @@ export function ChangePasswordDialog({ open, onOpenChange, onChanged }: ChangePa
current: current ? "" : t("Please enter your current password"),
next: !next
? t("Please enter new password")
- : next.length < PASSWORD_MIN_LENGTH
- ? t("Password must be at least 8 characters")
+ : !isSecretKeyValid(next)
+ ? t("Password must be at least 8 bytes")
: next === current
? t("The new password must be different from the current one")
: "",
@@ -164,7 +162,6 @@ export function ChangePasswordDialog({ open, onOpenChange, onChanged }: ChangePa
type="password"
autoComplete="new-password"
spellCheck={false}
- minLength={PASSWORD_MIN_LENGTH}
required
disabled={submitting}
aria-invalid={Boolean(errors.next)}
@@ -172,7 +169,7 @@ export function ChangePasswordDialog({ open, onOpenChange, onChanged }: ChangePa
/>
- {t("At least 8 characters. This is also your S3 secret key.")}
+ {t("At least 8 bytes. This is also your S3 secret key.")}
{errors.next}
diff --git a/components/user/edit-form.tsx b/components/user/edit-form.tsx
index 38cd29ad..e8a1e445 100644
--- a/components/user/edit-form.tsx
+++ b/components/user/edit-form.tsx
@@ -13,6 +13,7 @@ import { usePermissions } from "@/hooks/use-permissions"
import { usePolicies } from "@/hooks/use-policies"
import { useGroups } from "@/hooks/use-groups"
import { useMessage } from "@/lib/feedback/message"
+import { isSecretKeyValid } from "@/lib/secret-key"
import { getAvailableUserEditTabs } from "@/lib/user-edit-tabs"
import { UserEditSecretKey } from "./edit/secret-key"
import { UserEditGroups } from "./edit/groups"
@@ -177,8 +178,8 @@ export function UserEditForm({ open, onOpenChange, row, onSuccess }: UserEditFor
const validate = () => {
const newErrors = { secretKey: "" }
- if (secretKey && !/^.{8,40}$/.test(secretKey)) {
- newErrors.secretKey = t("password length cannot be less than 8 characters and greater than 40 characters")
+ if (secretKey && !isSecretKeyValid(secretKey)) {
+ newErrors.secretKey = t("Password must be at least 8 bytes")
}
setErrors(newErrors)
return !newErrors.secretKey
diff --git a/components/user/edit/access-keys.tsx b/components/user/edit/access-keys.tsx
index b8e11a63..627b6cbc 100644
--- a/components/user/edit/access-keys.tsx
+++ b/components/user/edit/access-keys.tsx
@@ -24,6 +24,7 @@ import { useDialog } from "@/lib/feedback/dialog"
import { useMessage } from "@/lib/feedback/message"
import { formatDateTime, makeRandomString } from "@/lib/functions"
import { cn } from "@/lib/utils"
+import { isSecretKeyValid } from "@/lib/secret-key"
import { useTranslation } from "react-i18next"
import type { ColumnDef } from "@tanstack/react-table"
@@ -169,8 +170,8 @@ function UserAccessKeysNewDialog({ open, onOpenChange, userName, onSuccess, onNo
if (!secretKey) {
nextErrors.secretKey = t("Please enter Secret Key")
- } else if (secretKey.length < 8 || secretKey.length > 40) {
- nextErrors.secretKey = t("Secret Key length must be between 8 and 40 characters")
+ } else if (!isSecretKeyValid(secretKey)) {
+ nextErrors.secretKey = t("Secret Key must be at least 8 bytes")
}
if (!name) {
diff --git a/components/user/new-form.tsx b/components/user/new-form.tsx
index 227608e2..2006f4fd 100644
--- a/components/user/new-form.tsx
+++ b/components/user/new-form.tsx
@@ -16,6 +16,7 @@ import { useUsers } from "@/hooks/use-users"
import { usePolicies } from "@/hooks/use-policies"
import { useGroups } from "@/hooks/use-groups"
import { cn } from "@/lib/utils"
+import { isSecretKeyValid } from "@/lib/secret-key"
interface UserNewFormProps {
open: boolean
@@ -25,8 +26,6 @@ interface UserNewFormProps {
const USERNAME_MIN_LENGTH = 3
const USERNAME_MAX_LENGTH = 128
-const PASSWORD_MIN_LENGTH = 8
-const PASSWORD_MAX_LENGTH = 40
export function UserNewForm({ open, onOpenChange, onSuccess }: UserNewFormProps) {
const { t } = useTranslation()
@@ -115,8 +114,8 @@ export function UserNewForm({ open, onOpenChange, onSuccess }: UserNewFormProps)
}
if (!secretKey.trim()) {
newErrors.secretKey = t("Please enter password")
- } else if (secretKey.length < PASSWORD_MIN_LENGTH || secretKey.length > PASSWORD_MAX_LENGTH) {
- newErrors.secretKey = t("password length cannot be less than 8 characters and greater than 40 characters")
+ } else if (!isSecretKeyValid(secretKey)) {
+ newErrors.secretKey = t("Password must be at least 8 bytes")
}
setErrors(newErrors)
return !newErrors.accessKey && !newErrors.secretKey
@@ -218,8 +217,6 @@ export function UserNewForm({ open, onOpenChange, onSuccess }: UserNewFormProps)
value={secretKey}
onChange={(e) => setSecretKey(e.target.value)}
type="password"
- minLength={PASSWORD_MIN_LENGTH}
- maxLength={PASSWORD_MAX_LENGTH}
autoComplete="new-password"
spellCheck={false}
required
diff --git a/i18n/locales/ar-MA.json b/i18n/locales/ar-MA.json
index c98bdb10..089f2e1f 100644
--- a/i18n/locales/ar-MA.json
+++ b/i18n/locales/ar-MA.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "يجب أن تتكون كلمة المرور من 8 بايتات على الأقل",
+ "Secret Key must be at least 8 bytes": "يجب أن يتكون المفتاح السري من 8 بايتات على الأقل",
+ "At least 8 bytes. This is also your S3 secret key.": "8 بايتات على الأقل. هذا أيضًا مفتاح S3 السري الخاص بك."
}
diff --git a/i18n/locales/de-DE.json b/i18n/locales/de-DE.json
index 380c551f..46985f25 100644
--- a/i18n/locales/de-DE.json
+++ b/i18n/locales/de-DE.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Das Passwort muss mindestens 8 Bytes lang sein",
+ "Secret Key must be at least 8 bytes": "Der geheime Schlüssel muss mindestens 8 Bytes lang sein",
+ "At least 8 bytes. This is also your S3 secret key.": "Mindestens 8 Bytes. Dies ist auch Ihr geheimer S3-Schlüssel."
}
diff --git a/i18n/locales/en-US.json b/i18n/locales/en-US.json
index 90e410b9..e3666bab 100644
--- a/i18n/locales/en-US.json
+++ b/i18n/locales/en-US.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Password must be at least 8 bytes",
+ "Secret Key must be at least 8 bytes": "Secret Key must be at least 8 bytes",
+ "At least 8 bytes. This is also your S3 secret key.": "At least 8 bytes. This is also your S3 secret key."
}
diff --git a/i18n/locales/es-ES.json b/i18n/locales/es-ES.json
index 54fbe3fe..5d7d4865 100644
--- a/i18n/locales/es-ES.json
+++ b/i18n/locales/es-ES.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "La contraseña debe tener al menos 8 bytes",
+ "Secret Key must be at least 8 bytes": "La clave secreta debe tener al menos 8 bytes",
+ "At least 8 bytes. This is also your S3 secret key.": "Al menos 8 bytes. Esta también es su clave secreta de S3."
}
diff --git a/i18n/locales/fr-FR.json b/i18n/locales/fr-FR.json
index 0426e82f..5f5a8c82 100644
--- a/i18n/locales/fr-FR.json
+++ b/i18n/locales/fr-FR.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Le mot de passe doit contenir au moins 8 octets",
+ "Secret Key must be at least 8 bytes": "La clé secrète doit contenir au moins 8 octets",
+ "At least 8 bytes. This is also your S3 secret key.": "Au moins 8 octets. Il s’agit aussi de votre clé secrète S3."
}
diff --git a/i18n/locales/id-ID.json b/i18n/locales/id-ID.json
index f3ac36d5..76ada96b 100644
--- a/i18n/locales/id-ID.json
+++ b/i18n/locales/id-ID.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Kata sandi harus berisi minimal 8 byte",
+ "Secret Key must be at least 8 bytes": "Kunci rahasia harus berisi minimal 8 byte",
+ "At least 8 bytes. This is also your S3 secret key.": "Minimal 8 byte. Ini juga merupakan kunci rahasia S3 Anda."
}
diff --git a/i18n/locales/it-IT.json b/i18n/locales/it-IT.json
index fa30363e..00c95fd3 100644
--- a/i18n/locales/it-IT.json
+++ b/i18n/locales/it-IT.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "La password deve contenere almeno 8 byte",
+ "Secret Key must be at least 8 bytes": "La chiave segreta deve contenere almeno 8 byte",
+ "At least 8 bytes. This is also your S3 secret key.": "Almeno 8 byte. Questa è anche la chiave segreta S3."
}
diff --git a/i18n/locales/ja-JP.json b/i18n/locales/ja-JP.json
index 0d0c6dad..d57ab562 100644
--- a/i18n/locales/ja-JP.json
+++ b/i18n/locales/ja-JP.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "パスワードは8バイト以上必要です",
+ "Secret Key must be at least 8 bytes": "シークレットキーは8バイト以上必要です",
+ "At least 8 bytes. This is also your S3 secret key.": "8バイト以上。これはS3シークレットキーでもあります。"
}
diff --git a/i18n/locales/ko-KR.json b/i18n/locales/ko-KR.json
index 90285d62..d0340644 100644
--- a/i18n/locales/ko-KR.json
+++ b/i18n/locales/ko-KR.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "비밀번호는 최소 8바이트여야 합니다",
+ "Secret Key must be at least 8 bytes": "시크릿 키는 최소 8바이트여야 합니다",
+ "At least 8 bytes. This is also your S3 secret key.": "최소 8바이트입니다. S3 시크릿 키로도 사용됩니다."
}
diff --git a/i18n/locales/pt-BR.json b/i18n/locales/pt-BR.json
index 679cde46..de99ad1b 100644
--- a/i18n/locales/pt-BR.json
+++ b/i18n/locales/pt-BR.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "A senha deve ter pelo menos 8 bytes",
+ "Secret Key must be at least 8 bytes": "A chave secreta deve ter pelo menos 8 bytes",
+ "At least 8 bytes. This is also your S3 secret key.": "Pelo menos 8 bytes. Esta também é sua chave secreta S3."
}
diff --git a/i18n/locales/ru-RU.json b/i18n/locales/ru-RU.json
index 46b0e6e3..9eec445c 100644
--- a/i18n/locales/ru-RU.json
+++ b/i18n/locales/ru-RU.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Пароль должен содержать не менее 8 байт",
+ "Secret Key must be at least 8 bytes": "Секретный ключ должен содержать не менее 8 байт",
+ "At least 8 bytes. This is also your S3 secret key.": "Не менее 8 байт. Это также ваш секретный ключ S3."
}
diff --git a/i18n/locales/tr-TR.json b/i18n/locales/tr-TR.json
index d0a96fc8..3397b877 100644
--- a/i18n/locales/tr-TR.json
+++ b/i18n/locales/tr-TR.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Parola en az 8 bayt olmalıdır",
+ "Secret Key must be at least 8 bytes": "Gizli anahtar en az 8 bayt olmalıdır",
+ "At least 8 bytes. This is also your S3 secret key.": "En az 8 bayt. Bu aynı zamanda S3 gizli anahtarınızdır."
}
diff --git a/i18n/locales/vi-VN.json b/i18n/locales/vi-VN.json
index ba2a07b6..94333697 100644
--- a/i18n/locales/vi-VN.json
+++ b/i18n/locales/vi-VN.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "You do not have permission to control backfill",
"You do not have permission to view this bucket's migration settings.": "You do not have permission to view this bucket's migration settings.",
"Your migration configuration changes will be lost.": "Your migration configuration changes will be lost.",
- "pull failures": "pull failures"
+ "pull failures": "pull failures",
+ "Password must be at least 8 bytes": "Mật khẩu phải có ít nhất 8 byte",
+ "Secret Key must be at least 8 bytes": "Khóa bí mật phải có ít nhất 8 byte",
+ "At least 8 bytes. This is also your S3 secret key.": "Ít nhất 8 byte. Đây cũng là khóa bí mật S3 của bạn."
}
diff --git a/i18n/locales/zh-CN.json b/i18n/locales/zh-CN.json
index d900377f..cf343376 100644
--- a/i18n/locales/zh-CN.json
+++ b/i18n/locales/zh-CN.json
@@ -2226,5 +2226,8 @@
"You do not have permission to control backfill": "你没有控制回填任务的权限",
"You do not have permission to view this bucket's migration settings.": "你没有查看此存储桶迁移设置的权限。",
"Your migration configuration changes will be lost.": "对迁移配置的更改将会丢失。",
- "pull failures": "次拉取失败"
+ "pull failures": "次拉取失败",
+ "Password must be at least 8 bytes": "密码至少需要 8 个字节",
+ "Secret Key must be at least 8 bytes": "Secret Key 至少需要 8 个字节",
+ "At least 8 bytes. This is also your S3 secret key.": "至少 8 个字节。这也是您的 S3 Secret Key。"
}
diff --git a/lib/secret-key.ts b/lib/secret-key.ts
new file mode 100644
index 00000000..d8dc013e
--- /dev/null
+++ b/lib/secret-key.ts
@@ -0,0 +1,4 @@
+/** Matches the server's Secret Key length validation without changing the value. */
+export function isSecretKeyValid(secretKey: string): boolean {
+ return new TextEncoder().encode(secretKey).length >= 8
+}
diff --git a/tests/lib/iam-remaining-safety.test.js b/tests/lib/iam-remaining-safety.test.js
index 0147e226..bc2b0a49 100644
--- a/tests/lib/iam-remaining-safety.test.js
+++ b/tests/lib/iam-remaining-safety.test.js
@@ -27,7 +27,7 @@ test("change password proves knowledge of the current secret before rotating it"
// change the account's credentials.
assert.match(source, /changePassword\(current, next\)/)
assert.match(source, /autoComplete="current-password"/)
- assert.match(source, /PASSWORD_MIN_LENGTH = 8/)
+ assert.match(source, /!isSecretKeyValid\(next\)/)
assert.match(source, /