forked from baron/baron-sso
dev 브런치 병합 후 code check
This commit is contained in:
@@ -121,6 +121,18 @@ func (m *e2eMockKratosAdminService) DeleteIdentity(ctx context.Context, identity
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *e2eMockKratosAdminService) ListIdentitySessions(ctx context.Context, identityID string) ([]service.KratosSession, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *e2eMockKratosAdminService) GetSession(ctx context.Context, sessionID string) (*service.KratosSession, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *e2eMockKratosAdminService) DeleteSession(ctx context.Context, sessionID string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func newHeadlessLoginE2EApp(h *authhandler.AuthHandler, appEnv string) *fiber.App {
|
func newHeadlessLoginE2EApp(h *authhandler.AuthHandler, appEnv string) *fiber.App {
|
||||||
app := fiber.New(fiber.Config{
|
app := fiber.New(fiber.Config{
|
||||||
DisableStartupMessage: true,
|
DisableStartupMessage: true,
|
||||||
|
|||||||
@@ -7126,6 +7126,10 @@ func isPrivateIPAddress(raw string) bool {
|
|||||||
return utils.IsPrivateOrReservedIP(raw)
|
return utils.IsPrivateOrReservedIP(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseAuditDetails(details string) (map[string]any, error) {
|
||||||
|
return utils.ParseAuditDetails(details)
|
||||||
|
}
|
||||||
|
|
||||||
func deriveSessionClientInfo(log domain.AuditLog) (string, string) {
|
func deriveSessionClientInfo(log domain.AuditLog) (string, string) {
|
||||||
details, _ := parseAuditDetails(log.Details)
|
details, _ := parseAuditDetails(log.Details)
|
||||||
clientID := ""
|
clientID := ""
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ func (m *AsyncMockUserRepo) Create(ctx context.Context, user *domain.User) error
|
|||||||
}
|
}
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AsyncMockUserRepo) Update(ctx context.Context, user *domain.User) error {
|
func (m *AsyncMockUserRepo) Update(ctx context.Context, user *domain.User) error {
|
||||||
args := m.Called(ctx, user)
|
args := m.Called(ctx, user)
|
||||||
if m.createCalled != nil {
|
if m.createCalled != nil {
|
||||||
@@ -87,6 +88,7 @@ func (m *AsyncMockUserRepo) Update(ctx context.Context, user *domain.User) error
|
|||||||
}
|
}
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *AsyncMockUserRepo) Delete(ctx context.Context, id string) error { return nil }
|
func (m *AsyncMockUserRepo) Delete(ctx context.Context, id string) error { return nil }
|
||||||
func (m *AsyncMockUserRepo) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
func (m *AsyncMockUserRepo) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ func (m *MockUserRepoForTenant) CountByTenantIDs(ctx context.Context, tenantIDs
|
|||||||
}
|
}
|
||||||
return args.Get(0).(map[string]int64), args.Error(1)
|
return args.Get(0).(map[string]int64), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockUserRepoForTenant) CountByCompanyCodes(ctx context.Context, codes []string) (map[string]int64, error) {
|
func (m *MockUserRepoForTenant) CountByCompanyCodes(ctx context.Context, codes []string) (map[string]int64, error) {
|
||||||
args := m.Called(ctx, codes)
|
args := m.Called(ctx, codes)
|
||||||
if args.Get(0) == nil {
|
if args.Get(0) == nil {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { expect, test, type Page, type Route } from '@playwright/test';
|
import { expect, test, type Locator, type Page, type Route } from '@playwright/test';
|
||||||
|
|
||||||
type RequestCapture = {
|
type RequestCapture = {
|
||||||
loginBody?: Record<string, unknown>;
|
loginBody?: Record<string, unknown>;
|
||||||
@@ -7,15 +7,26 @@ type RequestCapture = {
|
|||||||
clientLogs: string[];
|
clientLogs: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetNewPasswordName = /^(새 비밀번호|ui\.userfront\.reset\.new_password)$/;
|
||||||
|
const resetConfirmPasswordName =
|
||||||
|
/^(새 비밀번호 확인|ui\.userfront\.reset\.confirm_password)$/;
|
||||||
|
const resetSubmitButtonName = /^(비밀번호 변경|ui\.userfront\.reset\.submit)$/;
|
||||||
|
|
||||||
async function enableFlutterAccessibility(page: Page): Promise<void> {
|
async function enableFlutterAccessibility(page: Page): Promise<void> {
|
||||||
await page.waitForTimeout(300);
|
|
||||||
const button = page.getByRole('button', { name: 'Enable accessibility' });
|
const button = page.getByRole('button', { name: 'Enable accessibility' });
|
||||||
if (await button.count()) {
|
if (await button.count()) {
|
||||||
await button.click({ force: true });
|
await button.first().evaluate((node) => {
|
||||||
const placeholder = page.locator('flt-semantics-placeholder');
|
(node as HTMLElement).click();
|
||||||
if (await placeholder.count()) {
|
});
|
||||||
await placeholder.first().click({ force: true });
|
await page.waitForTimeout(200);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(300);
|
||||||
|
const placeholder = page.locator('flt-semantics-placeholder').first();
|
||||||
|
if (await placeholder.count()) {
|
||||||
|
await placeholder.evaluate((node) => {
|
||||||
|
(node as HTMLElement).click();
|
||||||
|
});
|
||||||
await page.waitForTimeout(800);
|
await page.waitForTimeout(800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +120,18 @@ async function fillAt(page: Page, x: number, y: number, value: string): Promise<
|
|||||||
await page.keyboard.type(value);
|
await page.keyboard.type(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function typeIntoAccessibleField(
|
||||||
|
page: Page,
|
||||||
|
field: Locator,
|
||||||
|
value: string,
|
||||||
|
): Promise<void> {
|
||||||
|
await field.click({ force: true });
|
||||||
|
await page.waitForTimeout(100);
|
||||||
|
await page.keyboard.press('Control+A');
|
||||||
|
await page.keyboard.press('Backspace');
|
||||||
|
await page.keyboard.type(value);
|
||||||
|
}
|
||||||
|
|
||||||
async function fillPasswordLoginForm(
|
async function fillPasswordLoginForm(
|
||||||
page: Page,
|
page: Page,
|
||||||
loginId: string,
|
loginId: string,
|
||||||
@@ -128,25 +151,29 @@ async function fillPasswordLoginForm(
|
|||||||
|
|
||||||
async function submitPasswordLogin(page: Page): Promise<void> {
|
async function submitPasswordLogin(page: Page): Promise<void> {
|
||||||
if (isMobileProject(page)) {
|
if (isMobileProject(page)) {
|
||||||
|
await enableFlutterAccessibility(page);
|
||||||
await page.getByRole('button', { name: '로그인' }).click({ force: true });
|
await page.getByRole('button', { name: '로그인' }).click({ force: true });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const coords = coordsFor(page);
|
await page.keyboard.press('Enter');
|
||||||
await page.locator('flt-glass-pane').click({
|
|
||||||
position: { x: coords.signinSubmitX, y: coords.signinSubmitY },
|
|
||||||
force: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fillResetPasswordForm(page: Page, password: string): Promise<void> {
|
async function fillResetPasswordForm(page: Page, password: string): Promise<void> {
|
||||||
|
await enableFlutterAccessibility(page);
|
||||||
|
const newPasswordInput = page.getByRole('textbox', {
|
||||||
|
name: resetNewPasswordName,
|
||||||
|
});
|
||||||
|
const confirmPasswordInput = page.getByRole('textbox', {
|
||||||
|
name: resetConfirmPasswordName,
|
||||||
|
});
|
||||||
|
if ((await newPasswordInput.count()) > 0 && (await confirmPasswordInput.count()) > 0) {
|
||||||
|
await typeIntoAccessibleField(page, newPasswordInput, password);
|
||||||
|
await typeIntoAccessibleField(page, confirmPasswordInput, password);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isMobileProject(page)) {
|
if (isMobileProject(page)) {
|
||||||
await enableFlutterAccessibility(page);
|
await page.getByRole('textbox', { name: resetNewPasswordName }).fill(password);
|
||||||
await page
|
await page.getByRole('textbox', { name: resetConfirmPasswordName }).fill(password);
|
||||||
.getByRole('textbox', { name: /^새 비밀번호$/ })
|
|
||||||
.fill(password);
|
|
||||||
await page
|
|
||||||
.getByRole('textbox', { name: /^새 비밀번호 확인$/ })
|
|
||||||
.fill(password);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const coords = coordsFor(page);
|
const coords = coordsFor(page);
|
||||||
@@ -160,8 +187,13 @@ async function fillResetPasswordForm(page: Page, password: string): Promise<void
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitResetPassword(page: Page): Promise<void> {
|
async function submitResetPassword(page: Page): Promise<void> {
|
||||||
|
await enableFlutterAccessibility(page);
|
||||||
|
const submitButton = page.getByRole('button', { name: resetSubmitButtonName });
|
||||||
|
if ((await submitButton.count()) > 0) {
|
||||||
|
await submitButton.click({ force: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isMobileProject(page)) {
|
if (isMobileProject(page)) {
|
||||||
await page.getByRole('button', { name: '비밀번호 변경' }).click({ force: true });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const coords = coordsFor(page);
|
const coords = coordsFor(page);
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ verify_code_failed = "인증 실패: {error}"
|
|||||||
[err.userfront.session]
|
[err.userfront.session]
|
||||||
missing = "활성 세션이 없습니다."
|
missing = "활성 세션이 없습니다."
|
||||||
|
|
||||||
[msg.userfront]
|
|
||||||
greeting = "안녕하세요, {name}님"
|
|
||||||
|
|
||||||
[msg.userfront.audit]
|
[msg.userfront.audit]
|
||||||
date = "접속일자: {value}"
|
date = "접속일자: {value}"
|
||||||
device = "접속환경: {value}"
|
device = "접속환경: {value}"
|
||||||
@@ -53,27 +50,6 @@ result = "인증결과: {value}"
|
|||||||
session_id = "Session ID: {value}"
|
session_id = "Session ID: {value}"
|
||||||
status = "현황: (준비중)"
|
status = "현황: (준비중)"
|
||||||
|
|
||||||
[msg.userfront.consent]
|
|
||||||
accept_error = "동의 처리에 실패했습니다: {error}"
|
|
||||||
client_id = "클라이언트 ID: {id}"
|
|
||||||
client_unknown = "알 수 없는 앱"
|
|
||||||
description = "아래 서비스가 회원님의 계정 정보에 접근하려고 합니다.\\\\n계속 진행하려면 동의 여부를 선택해 주세요."
|
|
||||||
load_error = "동의 정보를 불러오는데 실패했습니다: {error}"
|
|
||||||
missing_redirect = "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다."
|
|
||||||
redirect_notice = "동의 후 자동으로 서비스로 이동합니다."
|
|
||||||
scope_count = "총 {count}개"
|
|
||||||
|
|
||||||
[msg.userfront.consent.cancel]
|
|
||||||
confirm = "권한 동의를 취소하면 해당 서비스를 이용할 수 없습니다. 취소하시겠습니까?"
|
|
||||||
error = "취소 처리 중 오류가 발생했습니다: {error}"
|
|
||||||
|
|
||||||
[msg.userfront.consent.scope]
|
|
||||||
email = "이메일 주소 (계정 식별 및 알림 용도)"
|
|
||||||
offline_access = "오프라인 접근 (로그인 유지)"
|
|
||||||
openid = "OpenID 인증 정보 (로그인 상태 확인)"
|
|
||||||
phone = "휴대폰 번호 (본인 인증 및 알림)"
|
|
||||||
profile = "기본 프로필 정보 (이름, 사용자 식별자)"
|
|
||||||
|
|
||||||
[msg.userfront.dashboard]
|
[msg.userfront.dashboard]
|
||||||
approved_device = "승인 기기: {device}"
|
approved_device = "승인 기기: {device}"
|
||||||
approved_ip = "승인 IP: {ip}"
|
approved_ip = "승인 IP: {ip}"
|
||||||
@@ -89,27 +65,6 @@ link_open_error = "해당 링크를 열 수 없습니다."
|
|||||||
render_error = "대시보드 렌더링 오류: {error}"
|
render_error = "대시보드 렌더링 오류: {error}"
|
||||||
session_id_copied = "세션 ID가 복사되었습니다."
|
session_id_copied = "세션 ID가 복사되었습니다."
|
||||||
|
|
||||||
[msg.userfront.dashboard.activities]
|
|
||||||
empty = "연동된 앱이 없습니다."
|
|
||||||
empty_detail = "앱을 연동하면 최근 활동과 상태가 표시됩니다."
|
|
||||||
error = "연동 정보를 불러오지 못했습니다."
|
|
||||||
|
|
||||||
[msg.userfront.dashboard.approved_session]
|
|
||||||
copy_click = "{label}: {id}\\\\n클릭하면 복사됩니다."
|
|
||||||
copy_tap = "{label}: {id}\\\\n탭하면 복사됩니다."
|
|
||||||
none = "{label} 없음"
|
|
||||||
|
|
||||||
[msg.userfront.dashboard.revoke]
|
|
||||||
confirm = "{app} 앱과의 연동을 해지하시겠습니까?\\\\n해지하면 다음 로그인 시 다시 동의가 필요합니다."
|
|
||||||
error = "해지 실패: {error}"
|
|
||||||
success = "{app} 연동이 해지되었습니다."
|
|
||||||
|
|
||||||
[msg.userfront.dashboard.scopes]
|
|
||||||
empty = "요청된 권한이 없습니다."
|
|
||||||
|
|
||||||
[msg.userfront.dashboard.timeline]
|
|
||||||
load_error = "접속이력을 불러오지 못했습니다."
|
|
||||||
|
|
||||||
[msg.userfront.error]
|
[msg.userfront.error]
|
||||||
detail_contact = "관리자에게 문의해 주세요."
|
detail_contact = "관리자에게 문의해 주세요."
|
||||||
detail_generic = "오류가 발생했습니다."
|
detail_generic = "오류가 발생했습니다."
|
||||||
@@ -120,34 +75,6 @@ title_generic = "오류가 발생했습니다"
|
|||||||
title_with_code = "오류: {code}"
|
title_with_code = "오류: {code}"
|
||||||
type = "오류 종류: {type}"
|
type = "오류 종류: {type}"
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
|
||||||
"$normalizedCode" = "{error}"
|
|
||||||
access_denied = "사용자가 동의를 거부했습니다."
|
|
||||||
consent_required = "앱 접근 동의가 필요합니다."
|
|
||||||
interaction_required = "추가 상호작용이 필요합니다. 다시 시도해 주세요."
|
|
||||||
invalid_client = "클라이언트 인증 정보가 유효하지 않습니다."
|
|
||||||
invalid_grant = "인증 요청이 만료되었거나 유효하지 않습니다."
|
|
||||||
invalid_request = "잘못된 요청입니다."
|
|
||||||
invalid_scope = "요청한 권한 범위가 유효하지 않습니다."
|
|
||||||
login_required = "로그인이 필요합니다."
|
|
||||||
request_forbidden = "요청이 거부되었습니다."
|
|
||||||
server_error = "인증 서버 오류가 발생했습니다."
|
|
||||||
temporarily_unavailable = "인증 서버를 일시적으로 사용할 수 없습니다."
|
|
||||||
unauthorized_client = "해당 클라이언트는 이 요청을 수행할 수 없습니다."
|
|
||||||
unsupported_response_type = "지원하지 않는 응답 타입입니다."
|
|
||||||
|
|
||||||
[msg.userfront.error.whitelist]
|
|
||||||
"$normalizedCode" = "{error}"
|
|
||||||
bad_request = "입력값을 확인해 주세요."
|
|
||||||
invalid_session = "세션이 만료되었습니다. 다시 로그인해 주세요."
|
|
||||||
not_found = "요청한 페이지를 찾을 수 없습니다."
|
|
||||||
password_or_email_mismatch = "이메일 혹은 비밀번호가 일치하지 않습니다."
|
|
||||||
rate_limited = "요청이 많습니다. 잠시 후 다시 시도해 주세요."
|
|
||||||
recovery_expired = "재설정 링크가 만료되었습니다. 다시 요청해 주세요."
|
|
||||||
recovery_invalid = "재설정 링크가 유효하지 않습니다."
|
|
||||||
settings_disabled = "현재 계정 설정 화면은 준비 중입니다."
|
|
||||||
verification_required = "추가 인증이 필요합니다. 안내에 따라 진행해 주세요."
|
|
||||||
|
|
||||||
[msg.userfront.forgot]
|
[msg.userfront.forgot]
|
||||||
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
||||||
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||||
@@ -317,6 +244,55 @@ complete = "가입 완료"
|
|||||||
next_step = "다음 단계"
|
next_step = "다음 단계"
|
||||||
title = "회원가입"
|
title = "회원가입"
|
||||||
|
|
||||||
|
[msg.userfront]
|
||||||
|
greeting = "안녕하세요, {name}님"
|
||||||
|
|
||||||
|
[msg.userfront.audit]
|
||||||
|
date = "접속일자: {value}"
|
||||||
|
device = "접속환경: {value}"
|
||||||
|
end = "더 이상 항목이 없습니다."
|
||||||
|
ip = "접속 IP: {value}"
|
||||||
|
load_more_error = "더 불러오지 못했습니다."
|
||||||
|
result = "인증결과: {value}"
|
||||||
|
session_id = "Session ID: {value}"
|
||||||
|
status = "현황: (준비중)"
|
||||||
|
|
||||||
|
[msg.userfront.consent]
|
||||||
|
accept_error = "동의 처리에 실패했습니다: {error}"
|
||||||
|
client_id = "클라이언트 ID: {id}"
|
||||||
|
client_unknown = "알 수 없는 앱"
|
||||||
|
description = "아래 서비스가 회원님의 계정 정보에 접근하려고 합니다.\\\\n계속 진행하려면 동의 여부를 선택해 주세요."
|
||||||
|
load_error = "동의 정보를 불러오는데 실패했습니다: {error}"
|
||||||
|
missing_redirect = "동의가 처리되었으나 리다이렉트 URL을 받지 못했습니다."
|
||||||
|
redirect_notice = "동의 후 자동으로 서비스로 이동합니다."
|
||||||
|
scope_count = "총 {count}개"
|
||||||
|
|
||||||
|
[msg.userfront.consent.cancel]
|
||||||
|
confirm = "권한 동의를 취소하면 해당 서비스를 이용할 수 없습니다. 취소하시겠습니까?"
|
||||||
|
error = "취소 처리 중 오류가 발생했습니다: {error}"
|
||||||
|
|
||||||
|
[msg.userfront.consent.scope]
|
||||||
|
email = "이메일 주소 (계정 식별 및 알림 용도)"
|
||||||
|
offline_access = "오프라인 접근 (로그인 유지)"
|
||||||
|
openid = "OpenID 인증 정보 (로그인 상태 확인)"
|
||||||
|
phone = "휴대폰 번호 (본인 인증 및 알림)"
|
||||||
|
profile = "기본 프로필 정보 (이름, 사용자 식별자)"
|
||||||
|
|
||||||
|
[msg.userfront.dashboard]
|
||||||
|
approved_device = "승인 기기: {device}"
|
||||||
|
approved_ip = "승인 IP: {ip}"
|
||||||
|
audit_empty = "최근 접속 이력이 없습니다."
|
||||||
|
audit_load_error = "접속이력을 불러오지 못했습니다."
|
||||||
|
auth_method = "인증수단: {method}"
|
||||||
|
client_id = "Client ID: {id}"
|
||||||
|
client_id_missing = "Client ID 없음"
|
||||||
|
current_status = "현재 상태: {status}"
|
||||||
|
last_auth = "최근 인증: {value}"
|
||||||
|
link_missing = "이동할 페이지 주소(Client URI)가 설정되지 않았습니다."
|
||||||
|
link_open_error = "해당 링크를 열 수 없습니다."
|
||||||
|
render_error = "대시보드 렌더링 오류: {error}"
|
||||||
|
session_id_copied = "세션 ID가 복사되었습니다."
|
||||||
|
|
||||||
[msg.userfront.dashboard.activities]
|
[msg.userfront.dashboard.activities]
|
||||||
empty = "연동된 앱이 없습니다."
|
empty = "연동된 앱이 없습니다."
|
||||||
empty_detail = "앱을 연동하면 최근 활동과 상태가 표시됩니다."
|
empty_detail = "앱을 연동하면 최근 활동과 상태가 표시됩니다."
|
||||||
@@ -337,12 +313,12 @@ error = "세션 종료 실패: {error}"
|
|||||||
success = "세션이 종료되었습니다."
|
success = "세션이 종료되었습니다."
|
||||||
|
|
||||||
[msg.userfront.dashboard.approved_session]
|
[msg.userfront.dashboard.approved_session]
|
||||||
copy_click = "{label}: {id}\n클릭하면 복사됩니다."
|
copy_click = "{label}: {id}\\\\n클릭하면 복사됩니다."
|
||||||
copy_tap = "{label}: {id}\n탭하면 복사됩니다."
|
copy_tap = "{label}: {id}\\\\n탭하면 복사됩니다."
|
||||||
none = "{label} 없음"
|
none = "{label} 없음"
|
||||||
|
|
||||||
[msg.userfront.dashboard.revoke]
|
[msg.userfront.dashboard.revoke]
|
||||||
confirm = "{app} 앱과의 연동을 해지하시겠습니까?\n해지하면 다음 로그인 시 다시 동의가 필요합니다."
|
confirm = "{app} 앱과의 연동을 해지하시겠습니까?\\\\n해지하면 다음 로그인 시 다시 동의가 필요합니다."
|
||||||
error = "해지 실패: {error}"
|
error = "해지 실패: {error}"
|
||||||
success = "{app} 연동이 해지되었습니다."
|
success = "{app} 연동이 해지되었습니다."
|
||||||
|
|
||||||
@@ -352,17 +328,15 @@ empty = "요청된 권한이 없습니다."
|
|||||||
[msg.userfront.dashboard.timeline]
|
[msg.userfront.dashboard.timeline]
|
||||||
load_error = "접속이력을 불러오지 못했습니다."
|
load_error = "접속이력을 불러오지 못했습니다."
|
||||||
|
|
||||||
[msg.userfront.error.whitelist]
|
[msg.userfront.error]
|
||||||
"$normalizedCode" = "{error}"
|
detail_contact = "관리자에게 문의해 주세요."
|
||||||
bad_request = "입력값을 확인해 주세요."
|
detail_generic = "오류가 발생했습니다."
|
||||||
invalid_session = "세션이 만료되었습니다. 다시 로그인해 주세요."
|
detail_request = "요청을 처리하는 중 문제가 발생했습니다."
|
||||||
not_found = "요청한 페이지를 찾을 수 없습니다."
|
id = "오류 ID: {id}"
|
||||||
password_or_email_mismatch = "이메일 혹은 비밀번호가 일치하지 않습니다."
|
title = "인증 과정에서 오류가 발생했습니다"
|
||||||
rate_limited = "요청이 많습니다. 잠시 후 다시 시도해 주세요."
|
title_generic = "오류가 발생했습니다"
|
||||||
recovery_expired = "재설정 링크가 만료되었습니다. 다시 요청해 주세요."
|
title_with_code = "오류: {code}"
|
||||||
recovery_invalid = "재설정 링크가 유효하지 않습니다."
|
type = "오류 종류: {type}"
|
||||||
settings_disabled = "현재 계정 설정 화면은 준비 중입니다."
|
|
||||||
verification_required = "추가 인증이 필요합니다. 안내에 따라 진행해 주세요."
|
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
[msg.userfront.error.ory]
|
||||||
"$normalizedCode" = "{error}"
|
"$normalizedCode" = "{error}"
|
||||||
@@ -380,6 +354,41 @@ temporarily_unavailable = "인증 서버를 일시적으로 사용할 수 없습
|
|||||||
unauthorized_client = "해당 클라이언트는 이 요청을 수행할 수 없습니다."
|
unauthorized_client = "해당 클라이언트는 이 요청을 수행할 수 없습니다."
|
||||||
unsupported_response_type = "지원하지 않는 응답 타입입니다."
|
unsupported_response_type = "지원하지 않는 응답 타입입니다."
|
||||||
|
|
||||||
|
[msg.userfront.error.whitelist]
|
||||||
|
"$normalizedCode" = "{error}"
|
||||||
|
bad_request = "입력값을 확인해 주세요."
|
||||||
|
invalid_session = "세션이 만료되었습니다. 다시 로그인해 주세요."
|
||||||
|
not_found = "요청한 페이지를 찾을 수 없습니다."
|
||||||
|
password_or_email_mismatch = "이메일 혹은 비밀번호가 일치하지 않습니다."
|
||||||
|
rate_limited = "요청이 많습니다. 잠시 후 다시 시도해 주세요."
|
||||||
|
recovery_expired = "재설정 링크가 만료되었습니다. 다시 요청해 주세요."
|
||||||
|
recovery_invalid = "재설정 링크가 유효하지 않습니다."
|
||||||
|
settings_disabled = "현재 계정 설정 화면은 준비 중입니다."
|
||||||
|
verification_required = "추가 인증이 필요합니다. 안내에 따라 진행해 주세요."
|
||||||
|
|
||||||
|
[msg.userfront.forgot]
|
||||||
|
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
||||||
|
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||||
|
error = "전송에 실패했습니다: {error}"
|
||||||
|
input_required = "이메일 또는 휴대폰 번호를 입력해주세요."
|
||||||
|
sent = "비밀번호 재설정 링크가 전송되었습니다. 이메일 또는 SMS를 확인해주세요."
|
||||||
|
|
||||||
|
[msg.userfront.login]
|
||||||
|
cookie_check_failed = "로그인 확인 실패: {error}"
|
||||||
|
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||||
|
link_failed = "오류: {error}"
|
||||||
|
link_send_failed = "전송 실패: {error}"
|
||||||
|
link_sent_email = "입력하신 이메일로 로그인 링크를 보냈습니다."
|
||||||
|
link_sent_phone = "입력하신 번호로 로그인 링크를 보냈습니다."
|
||||||
|
link_timeout = "시간이 경과되었습니다."
|
||||||
|
no_account = "계정이 없으신가요?"
|
||||||
|
oidc_failed = "OIDC 로그인 처리에 실패했습니다. 다시 시도해 주세요."
|
||||||
|
qr_expired = "시간이 경과되었습니다."
|
||||||
|
qr_init_failed = "QR 초기화에 실패했습니다: {error}"
|
||||||
|
qr_login_required = "로그인 한 상태여야 QR 스캔으로 로그인 할 수 있습니다"
|
||||||
|
token_missing = "로그인 토큰을 확인할 수 없습니다."
|
||||||
|
verification_failed = "승인 처리에 실패했습니다: {error}"
|
||||||
|
|
||||||
[msg.userfront.login.link]
|
[msg.userfront.login.link]
|
||||||
approved = "msg.userfront.login.link.approved"
|
approved = "msg.userfront.login.link.approved"
|
||||||
helper = "입력하신 정보로 로그인 링크를 전송합니다."
|
helper = "입력하신 정보로 로그인 링크를 전송합니다."
|
||||||
|
|||||||
@@ -40,18 +40,41 @@ verify_code_failed = ""
|
|||||||
[err.userfront.session]
|
[err.userfront.session]
|
||||||
missing = ""
|
missing = ""
|
||||||
|
|
||||||
[msg.userfront]
|
[msg.userfront.error]
|
||||||
greeting = ""
|
detail_contact = ""
|
||||||
|
detail_generic = ""
|
||||||
|
detail_request = ""
|
||||||
|
id = ""
|
||||||
|
title = ""
|
||||||
|
title_generic = ""
|
||||||
|
title_with_code = ""
|
||||||
|
type = ""
|
||||||
|
|
||||||
[msg.userfront.audit]
|
[msg.userfront.forgot]
|
||||||
date = ""
|
description = ""
|
||||||
device = ""
|
dry_send = ""
|
||||||
end = ""
|
error = ""
|
||||||
ip = ""
|
input_required = ""
|
||||||
load_more_error = ""
|
sent = ""
|
||||||
result = ""
|
|
||||||
session_id = ""
|
[msg.userfront.login]
|
||||||
status = ""
|
cookie_check_failed = ""
|
||||||
|
dry_send = ""
|
||||||
|
link_failed = ""
|
||||||
|
link_send_failed = ""
|
||||||
|
link_sent_email = ""
|
||||||
|
link_sent_phone = ""
|
||||||
|
link_timeout = ""
|
||||||
|
no_account = ""
|
||||||
|
oidc_failed = ""
|
||||||
|
qr_expired = ""
|
||||||
|
qr_init_failed = ""
|
||||||
|
qr_login_required = ""
|
||||||
|
token_missing = ""
|
||||||
|
verification_failed = ""
|
||||||
|
|
||||||
|
[msg.userfront.login_success]
|
||||||
|
subtitle = ""
|
||||||
|
|
||||||
[msg.userfront.consent]
|
[msg.userfront.consent]
|
||||||
accept_error = ""
|
accept_error = ""
|
||||||
@@ -63,16 +86,6 @@ missing_redirect = ""
|
|||||||
redirect_notice = ""
|
redirect_notice = ""
|
||||||
scope_count = ""
|
scope_count = ""
|
||||||
|
|
||||||
[msg.userfront.consent.cancel]
|
|
||||||
confirm = ""
|
|
||||||
error = ""
|
|
||||||
|
|
||||||
[msg.userfront.consent.scope]
|
|
||||||
email = ""
|
|
||||||
offline_access = ""
|
|
||||||
openid = ""
|
|
||||||
phone = ""
|
|
||||||
|
|
||||||
[msg.userfront.profile]
|
[msg.userfront.profile]
|
||||||
department_missing = ""
|
department_missing = ""
|
||||||
department_required = ""
|
department_required = ""
|
||||||
@@ -206,6 +219,40 @@ complete = ""
|
|||||||
next_step = ""
|
next_step = ""
|
||||||
title = ""
|
title = ""
|
||||||
|
|
||||||
|
[msg.userfront]
|
||||||
|
greeting = ""
|
||||||
|
|
||||||
|
[msg.userfront.audit]
|
||||||
|
date = ""
|
||||||
|
device = ""
|
||||||
|
end = ""
|
||||||
|
ip = ""
|
||||||
|
load_more_error = ""
|
||||||
|
result = ""
|
||||||
|
session_id = ""
|
||||||
|
status = ""
|
||||||
|
|
||||||
|
[msg.userfront.consent]
|
||||||
|
accept_error = ""
|
||||||
|
client_id = ""
|
||||||
|
client_unknown = ""
|
||||||
|
description = ""
|
||||||
|
load_error = ""
|
||||||
|
missing_redirect = ""
|
||||||
|
redirect_notice = ""
|
||||||
|
scope_count = ""
|
||||||
|
|
||||||
|
[msg.userfront.consent.cancel]
|
||||||
|
confirm = ""
|
||||||
|
error = ""
|
||||||
|
|
||||||
|
[msg.userfront.consent.scope]
|
||||||
|
email = ""
|
||||||
|
offline_access = ""
|
||||||
|
openid = ""
|
||||||
|
phone = ""
|
||||||
|
profile = ""
|
||||||
|
|
||||||
[msg.userfront.dashboard]
|
[msg.userfront.dashboard]
|
||||||
approved_device = ""
|
approved_device = ""
|
||||||
approved_ip = ""
|
approved_ip = ""
|
||||||
|
|||||||
@@ -1032,13 +1032,22 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
|||||||
webWindow.redirectTo(redirectTo);
|
webWindow.redirectTo(redirectTo);
|
||||||
} else {}
|
} else {}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
final errorMessage = e.toString().replaceFirst('Exception: ', '');
|
||||||
|
try {
|
||||||
|
await AuthProxyService.logError(
|
||||||
|
'[PasswordLogin] $errorMessage',
|
||||||
|
error: e,
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore client-log relay failures and continue with user feedback.
|
||||||
|
}
|
||||||
if (e.toString().contains("User not registered")) {
|
if (e.toString().contains("User not registered")) {
|
||||||
_showUnregisteredDialog();
|
_showUnregisteredDialog();
|
||||||
} else {
|
} else {
|
||||||
_showError(
|
_showError(
|
||||||
tr(
|
tr(
|
||||||
'msg.userfront.login.password.failed',
|
'msg.userfront.login.password.failed',
|
||||||
params: {'error': e.toString().replaceFirst('Exception: ', '')},
|
params: {'error': errorMessage},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user