From e1a68f75f7b034f1ef9e45f26de584f13e355589 Mon Sep 17 00:00:00 2001 From: "Marvin A. Ruder" Date: Sun, 7 Jul 2024 23:08:14 +0200 Subject: [PATCH 1/2] feat(auth): Allow to hide username / password login form when OAuth is enabled (#518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ๐Ÿš€ Feature: Allow to hide username / password login form when OAuth is enabled * Hide โ€œSign inโ€ password form * Disable routes related to password authentication * Change styling of OAuth provider buttons * Open OAuth page in same tab * Fix consistent usage of informal language in de-DE locale Fixes #489 Signed-off-by: Marvin A. Ruder * fix: order of new config variables --------- Signed-off-by: Marvin A. Ruder Co-authored-by: Elias Schneider --- backend/prisma/seed/config.seed.ts | 29 ++++--- backend/src/auth/auth.service.ts | 9 +++ frontend/src/components/auth/SignInForm.tsx | 86 +++++++++++++-------- frontend/src/i18n/translations/de-DE.ts | 6 +- frontend/src/i18n/translations/en-US.ts | 4 + 5 files changed, 89 insertions(+), 45 deletions(-) diff --git a/backend/prisma/seed/config.seed.ts b/backend/prisma/seed/config.seed.ts index 99e1ea0..0c9e211 100644 --- a/backend/prisma/seed/config.seed.ts +++ b/backend/prisma/seed/config.seed.ts @@ -71,7 +71,6 @@ const configVariables: ConfigVariables = { enableShareEmailRecipients: { type: "boolean", defaultValue: "false", - secret: false, }, shareRecipientsSubject: { @@ -148,6 +147,11 @@ const configVariables: ConfigVariables = { type: "boolean", defaultValue: "true", }, + "disablePassword": { + type: "boolean", + defaultValue: "false", + secret: false, + }, "github-enabled": { type: "boolean", defaultValue: "false", @@ -229,7 +233,7 @@ const configVariables: ConfigVariables = { defaultValue: "", obscured: true, }, - } + }, }; type ConfigVariables = { @@ -281,12 +285,15 @@ async function seedConfigVariables() { async function migrateConfigVariables() { const existingConfigVariables = await prisma.config.findMany(); + const orderMap: { [category: string]: number } = {}; for (const existingConfigVariable of existingConfigVariables) { const configVariable = configVariables[existingConfigVariable.category]?.[ - existingConfigVariable.name + existingConfigVariable.name ]; + + // Delete the config variable if it doesn't exist in the seed if (!configVariable) { await prisma.config.delete({ where: { @@ -297,15 +304,11 @@ async function migrateConfigVariables() { }, }); - // Update the config variable if the metadata changed - } else if ( - JSON.stringify({ - ...configVariable, - name: existingConfigVariable.name, - category: existingConfigVariable.category, - value: existingConfigVariable.value, - }) != JSON.stringify(existingConfigVariable) - ) { + // Update the config variable if it exists in the seed + } else { + const variableOrder = Object.keys( + configVariables[existingConfigVariable.category] + ).indexOf(existingConfigVariable.name); await prisma.config.update({ where: { name_category: { @@ -318,8 +321,10 @@ async function migrateConfigVariables() { name: existingConfigVariable.name, category: existingConfigVariable.category, value: existingConfigVariable.value, + order: variableOrder, }, }); + orderMap[existingConfigVariable.category] = variableOrder + 1; } } } diff --git a/backend/src/auth/auth.service.ts b/backend/src/auth/auth.service.ts index f40b518..588720a 100644 --- a/backend/src/auth/auth.service.ts +++ b/backend/src/auth/auth.service.ts @@ -61,6 +61,9 @@ export class AuthService { if (!dto.email && !dto.username) throw new BadRequestException("Email or username is required"); + if (this.config.get("oauth.disablePassword")) + throw new ForbiddenException("Password sign in is disabled"); + const user = await this.prisma.user.findFirst({ where: { OR: [{ email: dto.email }, { username: dto.username }], @@ -94,6 +97,9 @@ export class AuthService { } async requestResetPassword(email: string) { + if (this.config.get("oauth.disablePassword")) + throw new ForbiddenException("Password sign in is disabled"); + const user = await this.prisma.user.findFirst({ where: { email }, include: { resetPasswordToken: true }, @@ -119,6 +125,9 @@ export class AuthService { } async resetPassword(token: string, newPassword: string) { + if (this.config.get("oauth.disablePassword")) + throw new ForbiddenException("Password sign in is disabled"); + const user = await this.prisma.user.findFirst({ where: { resetPasswordToken: { token } }, }); diff --git a/frontend/src/components/auth/SignInForm.tsx b/frontend/src/components/auth/SignInForm.tsx index 7696066..de6436d 100644 --- a/frontend/src/components/auth/SignInForm.tsx +++ b/frontend/src/components/auth/SignInForm.tsx @@ -28,6 +28,19 @@ import toast from "../../utils/toast.util"; import { safeRedirectPath } from "../../utils/router.util"; const useStyles = createStyles((theme) => ({ + signInWith: { + fontWeight: 500, + "&:before": { + content: "''", + flex: 1, + display: "block", + }, + "&:after": { + content: "''", + flex: 1, + display: "block", + }, + }, or: { "&:before": { content: "''", @@ -128,49 +141,58 @@ const SignInForm = ({ redirectPath }: { redirectPath: string }) => { )} -
{ - signIn(values.emailOrUsername, values.password); - })} - > - - - {config.get("smtp.enabled") && ( - - - - - - )} - - + {config.get("oauth.disablePassword") || ( +
{ + signIn(values.emailOrUsername, values.password); + })} + > + + + {config.get("smtp.enabled") && ( + + + + + + )} + + + )} {oauth.length > 0 && ( - - - {t("signIn.oauth.or")} - + + {config.get("oauth.disablePassword") ? ( + + {t("signIn.oauth.signInWith")} + + ) : ( + + {t("signIn.oauth.or")} + + )} {oauth.map((provider) => ( ))} diff --git a/frontend/src/i18n/translations/de-DE.ts b/frontend/src/i18n/translations/de-DE.ts index d3aa42a..8d1bbb5 100644 --- a/frontend/src/i18n/translations/de-DE.ts +++ b/frontend/src/i18n/translations/de-DE.ts @@ -34,6 +34,7 @@ export default { "signIn.notify.totp-required.title": "Zwei-Faktor-Authentifizierung benรถtigt", "signIn.notify.totp-required.description": "Bitte fรผge deinen Zwei-Faktor-Authentifizierungscode ein", "signIn.oauth.or": "ODER", + "signIn.oauth.signInWith": "Anmelden mit", "signIn.oauth.github": "GitHub", "signIn.oauth.google": "Google", "signIn.oauth.microsoft": "Microsoft", @@ -348,6 +349,9 @@ export default { "admin.config.oauth.allow-registration.description": "Benutzern erlauben, sich รผber Soziale Netzwerke zu registrieren", "admin.config.oauth.ignore-totp": "TOTP ignorieren", "admin.config.oauth.ignore-totp.description": "Gibt an, ob TOTP ignoriert werden soll, wenn sich der Benutzer รผber Soziale Netzwerke anmeldet", + "admin.config.oauth.disable-password": "Anmelden mit Passwort deaktivieren", + "admin.config.oauth.disable-password.description": + "Deaktiviert das Anmelden mit Passwort\nStelle vor Aktivierung dieser Konfiguration sicher, dass ein OAuth-Provider korrekt konfiguriert ist, um nicht ausgesperrt zu werden.", "admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled.description": "GitHub Anmeldung erlaubt", "admin.config.oauth.github-client-id": "GitHub Client-ID", @@ -401,7 +405,7 @@ export default { "error.msg.no_email": "Kann die E-Mail-Adresse von dem Konto {0} nicht abrufen.", "error.msg.already_linked": "Das Konto {0} ist bereits mit einem anderen Konto verknรผpft.", "error.msg.not_linked": "Das Konto {0} wurde noch nicht mit einem Konto verknรผpft.", - "error.msg.unverified_account": "Dieses Konto {0} wurde noch nicht verifiziert, bitte versuchen Sie es nach der Verifikation erneut.", + "error.msg.unverified_account": "Dieses Konto {0} wurde noch nicht verifiziert, bitte versuche es nach der Verifikation erneut.", "error.msg.discord_guild_permission_denied": "Du bist nicht berechtigt, Dich anzumelden.", "error.msg.cannot_get_user_info": "Deine Benutzerinformationen kรถnnen nicht von diesem Konto {0} abgerufen werden.", "error.param.provider_github": "GitHub", diff --git a/frontend/src/i18n/translations/en-US.ts b/frontend/src/i18n/translations/en-US.ts index 0959695..0b6d201 100644 --- a/frontend/src/i18n/translations/en-US.ts +++ b/frontend/src/i18n/translations/en-US.ts @@ -44,6 +44,7 @@ export default { "signIn.notify.totp-required.description": "Please enter your two-factor authentication code", "signIn.oauth.or": "OR", + "signIn.oauth.signInWith": "Sign in with", "signIn.oauth.github": "GitHub", "signIn.oauth.google": "Google", "signIn.oauth.microsoft": "Microsoft", @@ -479,6 +480,9 @@ export default { "admin.config.oauth.ignore-totp": "Ignore TOTP", "admin.config.oauth.ignore-totp.description": "Whether to ignore TOTP when user using social login", + "admin.config.oauth.disable-password": "Disable password login", + "admin.config.oauth.disable-password.description": + "Whether to disable password login\nMake sure that an OAuth provider is properly configured before activating this configuration to avoid being locked out.", "admin.config.oauth.github-enabled": "GitHub", "admin.config.oauth.github-enabled.description": "Whether GitHub login is enabled", From fccf57e9e4d19020ae740752c3770c06c210e73e Mon Sep 17 00:00:00 2001 From: Elias Schneider Date: Sun, 7 Jul 2024 23:08:28 +0200 Subject: [PATCH 2/2] chore(translations): update translations via Crowdin (#520) * New translations en-us.ts (Hungarian) * New translations en-us.ts (Korean) --- frontend/src/i18n/translations/hu-HU.ts | 4 +-- frontend/src/i18n/translations/ko-KR.ts | 36 ++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/frontend/src/i18n/translations/hu-HU.ts b/frontend/src/i18n/translations/hu-HU.ts index f883c6b..723b710 100644 --- a/frontend/src/i18n/translations/hu-HU.ts +++ b/frontend/src/i18n/translations/hu-HU.ts @@ -294,8 +294,8 @@ export default { "admin.config.general.app-url.description": "A Pingvin Share megosztรกskezelล‘re mutatรณ hivatkozรกs", "admin.config.general.show-home-page": "Kezdล‘lap mutatรกsa", "admin.config.general.show-home-page.description": "A kezdล‘lap mutatรกsรกnak ki- รฉs bekapcsolรกsa", - "admin.config.general.session-duration": "Session Duration", - "admin.config.general.session-duration.description": "Time in hours after which a user must log in again (default: 3 months).", + "admin.config.general.session-duration": "Munkamenet idล‘tartama", + "admin.config.general.session-duration.description": "Annak az idล‘tartamnak a megadรกsa, amit kรถvetล‘en a felhasznรกlรณnak ismรฉt be kell jelentkeznie (alapรฉrtรฉk: 3 hรณnap).", "admin.config.general.logo": "Logรณ", "admin.config.general.logo.description": "A logรณ szemรฉlyessรฉ tรฉtelรฉhez tรถltsรถn fel egy รบj kรฉpet. A formรกtum legyen PNG, az oldalarรกny 1:1.", "admin.config.general.logo.placeholder": "Kรฉp kivรกlasztรกsa", diff --git a/frontend/src/i18n/translations/ko-KR.ts b/frontend/src/i18n/translations/ko-KR.ts index c3739f5..12ef24f 100644 --- a/frontend/src/i18n/translations/ko-KR.ts +++ b/frontend/src/i18n/translations/ko-KR.ts @@ -44,10 +44,10 @@ export default { "signup.title": "๊ณ„์ • ๋งŒ๋“ค๊ธฐ", "signup.description": "์ด๋ฏธ ๊ณ„์ •์ด ์žˆ์œผ์‹ ๊ฐ€์š”?", "signup.button.signin": "๋กœ๊ทธ์ธ", - "signup.input.username": "์‚ฌ์šฉ์ž ์ด๋ฆ„", - "signup.input.username.placeholder": "๋‹น์‹ ์˜ ์‚ฌ์šฉ์ง€ ์ด๋ฆ„", + "signup.input.username": "์‚ฌ์šฉ์ž๋ช…", + "signup.input.username.placeholder": "๊ท€ํ•˜์˜ ์‚ฌ์šฉ์ž๋ช…", "signup.input.email": "์ด๋ฉ”์ผ", - "signup.input.email.placeholder": "๋‹น์‹ ์˜ ์ด๋ฉ”์ผ", + "signup.input.email.placeholder": "๊ท€ํ•˜์˜ ์ด๋ฉ”์ผ", "signup.button.submit": "์‹œ์ž‘ํ•˜๊ธฐ", // END /auth/signup // /auth/totp @@ -258,13 +258,13 @@ export default { // /share/[id] "share.title": "๊ณต์œ  {shareId}", "share.description": "๋‚ด๊ฐ€ ๋‹น์‹ ๊ณผ ๊ณต์œ ํ•œ ๊ฒƒ์„ ๋ณด์„ธ์š”!", - "share.error.visitor-limit-exceeded.title": "๋ฐฉ๋ฌธ์ž ์ œํ•œ ์ดˆ๊ณผ", - "share.error.visitor-limit-exceeded.description": "The visitor limit from this share has been exceeded.", + "share.error.visitor-limit-exceeded.title": "๋ฐฉ๋ฌธ์ž ํ•œ๋„ ์ดˆ๊ณผ", + "share.error.visitor-limit-exceeded.description": "์ด ๊ณต์œ ์˜ ๋ฐฉ๋ฌธ์ž ํ•œ๋„๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค.", "share.error.removed.title": "๊ณต์œ ๊ฐ€ ์‚ญ์ œ๋จ", "share.error.not-found.title": "๊ณต์œ ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", "share.error.not-found.description": "๋‹น์‹ ์ด ์ฐพ๋Š” ๊ณต์œ ๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.", "share.modal.password.title": "๋น„๋ฐ€๋ฒˆํ˜ธ ํ•„์š”", - "share.modal.password.description": "์ด ๊ณต์œ ์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ๊ณต์œ ์˜ ์•”ํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์‹ญ์‹œ์˜ค.", + "share.modal.password.description": "์ด ๊ณต์œ ์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ๊ณต์œ ์˜ ์•”ํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์‹ญ์‹œ์˜ค.", "share.modal.password": "๋น„๋ฐ€๋ฒˆํ˜ธ", "share.modal.error.invalid-password": "์ž˜๋ชป๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ", "share.button.download-all": "๋ชจ๋‘ ๋‹ค์šด๋กœ๋“œ", @@ -289,13 +289,13 @@ export default { "admin.config.category.smtp": "SMTP", "admin.config.category.oauth": "์†Œ์…œ ๋กœ๊ทธ์ธ", "admin.config.general.app-name": "์•ฑ ์ด๋ฆ„", - "admin.config.general.app-name.description": "Name of the application", + "admin.config.general.app-name.description": "์ด ์•ฑ์˜ ์ด๋ฆ„", "admin.config.general.app-url": "์•ฑ URL", "admin.config.general.app-url.description": "Pingvin Share๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” URL", "admin.config.general.show-home-page": "ํ™ˆ ํŽ˜์ด์ง€ ํ‘œ์‹œ", - "admin.config.general.show-home-page.description": "ํ™ˆ ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์ ๊ฒ€ํ•˜์‹ญ์‹œ์˜ค.", - "admin.config.general.session-duration": "Session Duration", - "admin.config.general.session-duration.description": "Time in hours after which a user must log in again (default: 3 months).", + "admin.config.general.show-home-page.description": "ํ™ˆ ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ• ์ง€ ์—ฌ๋ถ€", + "admin.config.general.session-duration": "์„ธ์…˜ ๊ธฐ๊ฐ„", + "admin.config.general.session-duration.description": "์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์•ผ ํ•˜๋Š” ์‹œ๊ฐ„ (๊ธฐ๋ณธ๊ฐ’: 3๊ฐœ์›”)", "admin.config.general.logo": "๋กœ๊ณ ", "admin.config.general.logo.description": "์ƒˆ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜์—ฌ ๋กœ๊ณ ๋ฅผ ๋ณ€๊ฒฝํ•˜์‹ญ์‹œ์˜ค. ์ด๋ฏธ์ง€๋Š” PNG์—ฌ์•ผ ํ•˜๋ฉฐ 1:1 ๋น„์œจ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.", "admin.config.general.logo.placeholder": "์ด๋ฏธ์ง€ ์„ ํƒ", @@ -305,9 +305,9 @@ export default { "admin.config.email.share-recipients-subject.description": "๊ณต์œ  ์ˆ˜์‹ ์ž์—๊ฒŒ ์ „์†ก๋˜๋Š” ์ด๋ฉ”์ผ์˜ ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.", "admin.config.email.share-recipients-message": "์ˆ˜์‹ ์ž ๋ฉ”์‹œ์ง€ ๊ณต์œ ", "admin.config.email.share-recipients-message.description": "๊ณต์œ  ์ˆ˜์‹ ์ž์—๊ฒŒ ๋ณด๋‚ด๋Š” ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ณ€์ˆ˜:\n {creator} - ๊ณต์œ  ์ž‘์„ฑ์ž์˜ ์‚ฌ์šฉ์ž ์ด๋ฆ„\n {shareUrl} - ๊ณต์œ ์˜ URL\n {desc} - ๊ณต์œ ์— ๋Œ€ํ•œ ์„ค๋ช…\n {expires} - ๊ณต์œ  ๋งŒ๋ฃŒ์ผ\n ๋ณ€์ˆ˜๋Š” ์‹ค์ œ ๊ฐ’์œผ๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.", - "admin.config.email.reverse-share-subject": "์—ญ๊ณต์œ  ์ œ๋ชฉ", + "admin.config.email.reverse-share-subject": "์—ญ๋ฐฉํ–ฅ ๊ณต์œ  ์ œ๋ชฉ", "admin.config.email.reverse-share-subject.description": "๋ˆ„๊ตฐ๊ฐ€ ๋‹น์‹ ์ด ๊ณต์œ ํ•œ ์—ญ๋ฐฉํ–ฅ ๊ณต์œ  ๋งํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณต์œ ๋ฅผ ์ƒ์„ฑํ–ˆ์„ ๋•Œ ์ „์†ก๋˜๋Š” ์ด๋ฉ”์ผ์˜ ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.", - "admin.config.email.reverse-share-message": "์—ญ๊ณต์œ  ๋ฉ”์‹œ์ง€", + "admin.config.email.reverse-share-message": "์—ญ๋ฐฉํ–ฅ ๊ณต์œ  ๋ฉ”์‹œ์ง€", "admin.config.email.reverse-share-message.description": "๋ˆ„๊ตฐ๊ฐ€ ๊ท€ํ•˜์˜ ์—ญ๋ฐฉํ–ฅ ๊ณต์œ  ๋งํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณต์œ ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ์ „์†ก๋˜๋Š” ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.. {shareUrl} ์€ ์ž‘์„ฑ์ž ์ด๋ฆ„ ๋ฐ ๊ณต์œ  URL๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค.", "admin.config.email.reset-password-subject": "๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ์ œ๋ชฉ", "admin.config.email.reset-password-subject.description": "์‚ฌ์šฉ์ž๊ฐ€ ์•”ํ˜ธ ์žฌ์„ค์ •์„ ์š”์ฒญํ•  ๋•Œ ์ „์†ก๋˜๋Š” ๋ฉ”์ผ์˜ ์ œ๋ชฉ์ž…๋‹ˆ๋‹ค.", @@ -321,16 +321,16 @@ export default { "admin.config.share.allow-registration.description": "๋“ฑ๋ก ๊ฐ€๋Šฅ ์—ฌ๋ถ€", "admin.config.share.allow-unauthenticated-shares": "์ธ์ฆ๋˜์ง€ ์•Š์€ ๊ณต์œ  ํ—ˆ์šฉ", "admin.config.share.allow-unauthenticated-shares.description": "์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ๊ณต์œ ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€", - "admin.config.share.max-expiration": "์ตœ๋Œ€ ๋งŒ๋ฃŒ์ผ", - "admin.config.share.max-expiration.description": "์ตœ๋Œ€ ๊ณต์œ  ๋งŒ๋ฃŒ ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค. ๋งŒ๋ฃŒ ๊ธฐ๊ฐ„์„ ์„ค์ •ํ•˜์ง€ ์•Š๋Š”๊ฒฝ์šฐ 0์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.", + "admin.config.share.max-expiration": "์ตœ๋Œ€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„", + "admin.config.share.max-expiration.description": "๊ณต์œ ์˜ ์ตœ๋Œ€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„. ๋ฌด์ œํ•œ ๋งŒ๋ฃŒ๋ฅผ ํ—ˆ์šฉํ•˜๋ ค๋ฉด 0์œผ๋กœ ์„ค์ •ํ•˜์„ธ์š”.", "admin.config.share.max-size": "์ตœ๋Œ€ ํฌ๊ธฐ", - "admin.config.share.max-size.description": "๊ณต์œ  ์ตœ๋Œ€ ํฌ๊ธฐ - ๋ฐ”์ดํŠธ", - "admin.config.share.zip-compression-level": "์••์ถ• ๋ ˆ๋ฒจ", + "admin.config.share.max-size.description": "๊ณต์œ ์˜ ์ตœ๋Œ€ ํฌ๊ธฐ (๋ฐ”์ดํŠธ)", + "admin.config.share.zip-compression-level": "Zip ์••์ถ• ๋ ˆ๋ฒจ", "admin.config.share.zip-compression-level.description": "ํŒŒ์ผ ํฌ๊ธฐ์™€ ์••์ถ• ์†๋„ ๊ฐ„์˜ ๊ท ํ˜•์„ ๋งž์ถ”๋„๋ก ๋ ˆ๋ฒจ์„ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ์œ ํšจํ•œ ๊ฐ’์˜ ๋ฒ”์œ„๋Š” 0์—์„œ 9๊นŒ์ง€์ด๋ฉฐ, 0์€ ์••์ถ•๋˜์ง€ ์•Š๊ณ  9๋Š” ์ตœ๋Œ€ ์••์ถ•์ž…๋‹ˆ๋‹ค. ", "admin.config.share.chunk-size": "์ฒญํฌ ํฌ๊ธฐ", "admin.config.share.chunk-size.description": "์—…๋กœ๋“œํ•  ์ฒญํฌ ํฌ๊ธฐ(๋ฐ”์ดํŠธ ๋‹จ์œ„)๋ฅผ ์กฐ์ •ํ•˜์—ฌ ์ธํ„ฐ๋„ท ์—ฐ๊ฒฐ์— ๋”ฐ๋ผ ํšจ์œจ์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ์˜ ๊ท ํ˜•์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ๋” ์ž‘์€ ์ฒญํฌ๋Š” ๋ถˆ์•ˆ์ •ํ•œ ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ ์„ฑ๊ณต๋ฅ ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ณ , ๋” ํฐ ์ฒญํฌ๋Š” ์•ˆ์ •์ ์ธ ์—ฐ๊ฒฐ์— ๋Œ€ํ•œ ์—…๋กœ๋“œ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.", - "admin.config.share.auto-open-share-modal": "Auto open create share modal", - "admin.config.share.auto-open-share-modal.description": "The share creation modal automatically appears when a user selects files, eliminating the need to manually click the button.", + "admin.config.share.auto-open-share-modal": "๊ณต์œ  ์ƒ์„ฑ ์ฐฝ ์ž๋™ ์—ด๊ธฐ", + "admin.config.share.auto-open-share-modal.description": "์‚ฌ์šฉ์ž๊ฐ€ ํŒŒ์ผ์„ ์„ ํƒํ•˜๋ฉด ๊ณต์œ  ์ƒ์„ฑ ์ฐฝ์ด ์ž๋™์œผ๋กœ ๋‚˜ํƒ€๋‚˜์„œ ๋ฒ„ํŠผ์„ ์ˆ˜๋™์œผ๋กœ ํด๋ฆญํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.", "admin.config.smtp.enabled": "ํ™œ์„ฑํ™”๋จ", "admin.config.smtp.enabled.description": "SMTP ์‚ฌ์šฉ ์—ฌ๋ถ€ SMTP ์„œ๋ฒ„์˜ ํ˜ธ์ŠคํŠธ, ํฌํŠธ, ์ „์ž ๋ฉ”์ผ, ์‚ฌ์šฉ์ž ๋ฐ ์•”ํ˜ธ๋ฅผ ์ž…๋ ฅํ•œ ๊ฒฝ์šฐ์—๋งŒ true๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.", "admin.config.smtp.host": "ํ˜ธ์ŠคํŠธ",