forked from baron/baron-sso
dev 병합 code-check 오류 수정
This commit is contained in:
11
Makefile
11
Makefile
@@ -181,13 +181,8 @@ PLAYWRIGHT_CHROMIUM_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/chromium-1208/INSTAL
|
|||||||
PLAYWRIGHT_FIREFOX_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/firefox-1509/INSTALLATION_COMPLETE
|
PLAYWRIGHT_FIREFOX_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/firefox-1509/INSTALLATION_COMPLETE
|
||||||
PLAYWRIGHT_WEBKIT_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/webkit-2248/INSTALLATION_COMPLETE
|
PLAYWRIGHT_WEBKIT_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/webkit-2248/INSTALLATION_COMPLETE
|
||||||
|
|
||||||
ifeq ($(CI),)
|
|
||||||
PLAYWRIGHT_INSTALL_ALL := sh -c 'if [ -f "$(PLAYWRIGHT_CHROMIUM_COMPLETE)" ] && [ -f "$(PLAYWRIGHT_FIREFOX_COMPLETE)" ] && [ -f "$(PLAYWRIGHT_WEBKIT_COMPLETE)" ]; then echo "Playwright browsers already installed"; else npx playwright install; fi'
|
PLAYWRIGHT_INSTALL_ALL := sh -c 'if [ -f "$(PLAYWRIGHT_CHROMIUM_COMPLETE)" ] && [ -f "$(PLAYWRIGHT_FIREFOX_COMPLETE)" ] && [ -f "$(PLAYWRIGHT_WEBKIT_COMPLETE)" ]; then echo "Playwright browsers already installed"; else npx playwright install; fi'
|
||||||
PLAYWRIGHT_INSTALL_CHROMIUM := sh -c 'if [ -f "$(PLAYWRIGHT_CHROMIUM_COMPLETE)" ]; then echo "Playwright chromium already installed"; else npx playwright install chromium; fi'
|
PLAYWRIGHT_INSTALL_CHROMIUM := sh -c 'if [ -f "$(PLAYWRIGHT_CHROMIUM_COMPLETE)" ]; then echo "Playwright chromium already installed"; else npx playwright install chromium; fi'
|
||||||
else
|
|
||||||
PLAYWRIGHT_INSTALL_ALL := npx playwright install --with-deps
|
|
||||||
PLAYWRIGHT_INSTALL_CHROMIUM := npx playwright install --with-deps chromium
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: code-check code-check-lint code-check-test-jobs code-check-i18n code-check-i18n-values code-check-go-lint code-check-sync-userfront-locales code-check-userfront-install code-check-userfront-lint code-check-front-lint code-check-backend-tests code-check-userfront-tests code-check-adminfront-tests code-check-devfront-tests code-check-userfront-e2e-tests
|
.PHONY: code-check code-check-lint code-check-test-jobs code-check-i18n code-check-i18n-values code-check-go-lint code-check-sync-userfront-locales code-check-userfront-install code-check-userfront-lint code-check-front-lint code-check-backend-tests code-check-userfront-tests code-check-adminfront-tests code-check-devfront-tests code-check-userfront-e2e-tests
|
||||||
|
|
||||||
@@ -254,12 +249,12 @@ code-check-userfront-lint:
|
|||||||
code-check-front-lint:
|
code-check-front-lint:
|
||||||
@echo "==> adminfront biome lint/format check"
|
@echo "==> adminfront biome lint/format check"
|
||||||
rm -rf adminfront/playwright-report adminfront/test-results
|
rm -rf adminfront/playwright-report adminfront/test-results
|
||||||
cd adminfront && npm ci
|
cd adminfront && npm ci --ignore-scripts
|
||||||
cd adminfront && npx biome check . --formatter-enabled=false --organize-imports-enabled=false
|
cd adminfront && npx biome check . --formatter-enabled=false --organize-imports-enabled=false
|
||||||
cd adminfront && npx biome check . --linter-enabled=false --organize-imports-enabled=false
|
cd adminfront && npx biome check . --linter-enabled=false --organize-imports-enabled=false
|
||||||
@echo "==> devfront biome lint/format check"
|
@echo "==> devfront biome lint/format check"
|
||||||
rm -rf devfront/playwright-report devfront/test-results
|
rm -rf devfront/playwright-report devfront/test-results
|
||||||
cd devfront && npm ci
|
cd devfront && npm ci --ignore-scripts
|
||||||
cd devfront && npx biome check . --formatter-enabled=false --organize-imports-enabled=false
|
cd devfront && npx biome check . --formatter-enabled=false --organize-imports-enabled=false
|
||||||
cd devfront && npx biome check . --linter-enabled=false --organize-imports-enabled=false
|
cd devfront && npx biome check . --linter-enabled=false --organize-imports-enabled=false
|
||||||
|
|
||||||
@@ -298,7 +293,7 @@ code-check-devfront-tests:
|
|||||||
@mkdir -p reports/devfront
|
@mkdir -p reports/devfront
|
||||||
@rm -rf reports/devfront/playwright-report reports/devfront/test-results
|
@rm -rf reports/devfront/playwright-report reports/devfront/test-results
|
||||||
@status=0; \
|
@status=0; \
|
||||||
(cd devfront && npm ci) || status=$$?; \
|
(cd devfront && npm ci --ignore-scripts) || status=$$?; \
|
||||||
if [ $$status -eq 0 ]; then \
|
if [ $$status -eq 0 ]; then \
|
||||||
(cd devfront && $(PLAYWRIGHT_INSTALL_ALL)) || status=$$?; \
|
(cd devfront && $(PLAYWRIGHT_INSTALL_ALL)) || status=$$?; \
|
||||||
fi; \
|
fi; \
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"baron-sso-backend/internal/domain"
|
||||||
"baron-sso-backend/internal/service"
|
"baron-sso-backend/internal/service"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@@ -13,6 +15,121 @@ import (
|
|||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// --- Mocks ---
|
||||||
|
|
||||||
|
type MockKratosAdminServiceForConsent struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) FindIdentityIDByIdentifier(ctx context.Context, identifier string) (string, error) {
|
||||||
|
args := m.Called(ctx, identifier)
|
||||||
|
return args.String(0), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) GetIdentity(ctx context.Context, id string) (*service.KratosIdentity, error) {
|
||||||
|
args := m.Called(ctx, id)
|
||||||
|
if args.Get(0) == nil {
|
||||||
|
return nil, args.Error(1)
|
||||||
|
}
|
||||||
|
return args.Get(0).(*service.KratosIdentity), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) ListIdentities(ctx context.Context) ([]service.KratosIdentity, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) UpdateIdentity(ctx context.Context, identityID string, traits map[string]interface{}, state string) (*service.KratosIdentity, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) CreateIdentity(ctx context.Context, traits map[string]interface{}) (*service.KratosIdentity, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) DeleteIdentity(ctx context.Context, identityID string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) UpdateIdentityPassword(ctx context.Context, identityID, newPassword string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) ListIdentitySessions(ctx context.Context, identityID string) ([]service.KratosSession, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) GetSession(ctx context.Context, sessionID string) (*service.KratosSession, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) DeleteSession(ctx context.Context, sessionID string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockKratosAdminServiceForConsent) CreateUser(ctx context.Context, user *domain.BrokerUser, password string) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockTenantServiceForConsent struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) GetTenant(ctx context.Context, id string) (*domain.Tenant, error) {
|
||||||
|
args := m.Called(ctx, id)
|
||||||
|
if args.Get(0) == nil {
|
||||||
|
return nil, args.Error(1)
|
||||||
|
}
|
||||||
|
return args.Get(0).(*domain.Tenant), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) GetTenantBySlug(ctx context.Context, slug string) (*domain.Tenant, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) GetTenantByDomain(ctx context.Context, domainName string) (*domain.Tenant, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) ListTenants(ctx context.Context, limit, offset int, parentID string) ([]domain.Tenant, int64, error) {
|
||||||
|
return nil, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) RegisterTenant(ctx context.Context, name, slug, tenantType, description string, domains []string, parentID *string, creatorID string) (*domain.Tenant, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) RequestRegistration(ctx context.Context, name, slug, description string, domainName string, adminEmail string) (*domain.Tenant, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) ApproveTenant(ctx context.Context, id string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) ListManageableTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
|
||||||
|
args := m.Called(ctx, userID)
|
||||||
|
return args.Get(0).([]domain.Tenant), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) ListJoinedTenants(ctx context.Context, userID string) ([]domain.Tenant, error) {
|
||||||
|
args := m.Called(ctx, userID)
|
||||||
|
return args.Get(0).([]domain.Tenant), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) IsDomainAllowed(ctx context.Context, domainName string) (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) ProvisionTenantByDomain(ctx context.Context, domainName string) (*domain.Tenant, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) SetKetoService(keto service.KetoService) {}
|
||||||
|
|
||||||
|
func (m *MockTenantServiceForConsent) DeleteTenantsBulk(ctx context.Context, ids []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// --- Test Helpers ---
|
// --- Test Helpers ---
|
||||||
|
|
||||||
func newConsentTestApp(h *AuthHandler) *fiber.App {
|
func newConsentTestApp(h *AuthHandler) *fiber.App {
|
||||||
@@ -100,11 +217,36 @@ func TestGetConsentRequest_AddsMandatoryTenantScope(t *testing.T) {
|
|||||||
http.DefaultClient = client
|
http.DefaultClient = client
|
||||||
defer func() { http.DefaultClient = origDefault }()
|
defer func() { http.DefaultClient = origDefault }()
|
||||||
|
|
||||||
|
mockTenantSvc := &MockTenantServiceForConsent{}
|
||||||
|
mockKratosAdmin := &MockKratosAdminServiceForConsent{}
|
||||||
|
|
||||||
|
// Mock profile resolution to allow tenant access
|
||||||
|
mockKratosAdmin.On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
||||||
|
ID: "user-123",
|
||||||
|
Traits: map[string]interface{}{
|
||||||
|
"email": "user@example.com",
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
mockTenantSvc.On("GetTenant", mock.Anything, "tenant-allow").Return(&domain.Tenant{
|
||||||
|
ID: "tenant-allow",
|
||||||
|
Slug: "tenant-allow",
|
||||||
|
Name: "Allowed Tenant",
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
// Mock hydration calls
|
||||||
|
mockTenantSvc.On("ListJoinedTenants", mock.Anything, mock.Anything).Return([]domain.Tenant{
|
||||||
|
{ID: "tenant-allow", Slug: "tenant-allow", Name: "Allowed Tenant"},
|
||||||
|
}, nil)
|
||||||
|
mockTenantSvc.On("ListManageableTenants", mock.Anything, mock.Anything).Return([]domain.Tenant{}, nil)
|
||||||
|
|
||||||
h := &AuthHandler{
|
h := &AuthHandler{
|
||||||
Hydra: &service.HydraAdminService{
|
Hydra: &service.HydraAdminService{
|
||||||
AdminURL: "http://hydra.test",
|
AdminURL: "http://hydra.test",
|
||||||
HTTPClient: client,
|
HTTPClient: client,
|
||||||
},
|
},
|
||||||
|
TenantService: mockTenantSvc,
|
||||||
|
KratosAdmin: mockKratosAdmin,
|
||||||
}
|
}
|
||||||
app := newConsentTestApp(h)
|
app := newConsentTestApp(h)
|
||||||
|
|
||||||
@@ -163,16 +305,17 @@ func TestGetConsentRequest_Skip_AutoAccept(t *testing.T) {
|
|||||||
defer func() { http.DefaultClient = origDefault }()
|
defer func() { http.DefaultClient = origDefault }()
|
||||||
|
|
||||||
consentRepo := &mockConsentRepo{}
|
consentRepo := &mockConsentRepo{}
|
||||||
|
mockKratosAdmin := &MockKratosAdminServiceForConsent{}
|
||||||
|
|
||||||
h := &AuthHandler{
|
h := &AuthHandler{
|
||||||
Hydra: &service.HydraAdminService{
|
Hydra: &service.HydraAdminService{
|
||||||
AdminURL: "http://hydra.test",
|
AdminURL: "http://hydra.test",
|
||||||
HTTPClient: client,
|
HTTPClient: client,
|
||||||
},
|
},
|
||||||
KratosAdmin: new(MockKratosAdminService), // Reusing MockKratosAdminService if defined or use MockKratosAdminServiceShared
|
KratosAdmin: mockKratosAdmin,
|
||||||
ConsentRepo: consentRepo,
|
ConsentRepo: consentRepo,
|
||||||
}
|
}
|
||||||
h.KratosAdmin.(*MockKratosAdminService).On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
mockKratosAdmin.On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
||||||
ID: "user-123",
|
ID: "user-123",
|
||||||
Traits: map[string]interface{}{
|
Traits: map[string]interface{}{
|
||||||
"email": "user@test.com",
|
"email": "user@test.com",
|
||||||
@@ -199,7 +342,8 @@ func TestAcceptConsentRequest_Normal(t *testing.T) {
|
|||||||
"requested_scope": []string{"openid", "profile"},
|
"requested_scope": []string{"openid", "profile"},
|
||||||
"subject": "user-123",
|
"subject": "user-123",
|
||||||
"client": map[string]interface{}{
|
"client": map[string]interface{}{
|
||||||
"client_id": "client-app",
|
"client_id": "client-app",
|
||||||
|
"client_name": "Test App",
|
||||||
},
|
},
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
@@ -226,17 +370,18 @@ func TestAcceptConsentRequest_Normal(t *testing.T) {
|
|||||||
|
|
||||||
auditRepo := &mockAuditRepo{}
|
auditRepo := &mockAuditRepo{}
|
||||||
consentRepo := &mockConsentRepo{}
|
consentRepo := &mockConsentRepo{}
|
||||||
|
mockKratosAdmin := &MockKratosAdminServiceForConsent{}
|
||||||
|
|
||||||
h := &AuthHandler{
|
h := &AuthHandler{
|
||||||
Hydra: &service.HydraAdminService{
|
Hydra: &service.HydraAdminService{
|
||||||
AdminURL: "http://hydra.test",
|
AdminURL: "http://hydra.test",
|
||||||
HTTPClient: client,
|
HTTPClient: client,
|
||||||
},
|
},
|
||||||
KratosAdmin: new(MockKratosAdminService),
|
KratosAdmin: mockKratosAdmin,
|
||||||
AuditRepo: auditRepo,
|
AuditRepo: auditRepo,
|
||||||
ConsentRepo: consentRepo,
|
ConsentRepo: consentRepo,
|
||||||
}
|
}
|
||||||
h.KratosAdmin.(*MockKratosAdminService).On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
mockKratosAdmin.On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
||||||
ID: "user-123",
|
ID: "user-123",
|
||||||
Traits: map[string]interface{}{
|
Traits: map[string]interface{}{
|
||||||
"email": "user@test.com",
|
"email": "user@test.com",
|
||||||
@@ -260,6 +405,8 @@ func TestAcceptConsentRequest_Normal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAcceptConsentRequest_EnforcesMandatoryTenantScope(t *testing.T) {
|
func TestAcceptConsentRequest_EnforcesMandatoryTenantScope(t *testing.T) {
|
||||||
|
t.Setenv("APP_ENV", "dev")
|
||||||
|
|
||||||
var capturedGrantScopes []string
|
var capturedGrantScopes []string
|
||||||
|
|
||||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||||
@@ -309,14 +456,16 @@ func TestAcceptConsentRequest_EnforcesMandatoryTenantScope(t *testing.T) {
|
|||||||
http.DefaultClient = client
|
http.DefaultClient = client
|
||||||
defer func() { http.DefaultClient = origDefault }()
|
defer func() { http.DefaultClient = origDefault }()
|
||||||
|
|
||||||
|
mockKratosAdmin := &MockKratosAdminServiceForConsent{}
|
||||||
|
|
||||||
h := &AuthHandler{
|
h := &AuthHandler{
|
||||||
Hydra: &service.HydraAdminService{
|
Hydra: &service.HydraAdminService{
|
||||||
AdminURL: "http://hydra.test",
|
AdminURL: "http://hydra.test",
|
||||||
HTTPClient: client,
|
HTTPClient: client,
|
||||||
},
|
},
|
||||||
KratosAdmin: new(MockKratosAdminService),
|
KratosAdmin: mockKratosAdmin,
|
||||||
}
|
}
|
||||||
h.KratosAdmin.(*MockKratosAdminService).On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
mockKratosAdmin.On("GetIdentity", mock.Anything, "user-123").Return(&service.KratosIdentity{
|
||||||
ID: "user-123",
|
ID: "user-123",
|
||||||
Traits: map[string]interface{}{
|
Traits: map[string]interface{}{
|
||||||
"email": "user@test.com",
|
"email": "user@test.com",
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ func TestGetConsentRequest_DeniesTenantAccess(t *testing.T) {
|
|||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
app.Get("/api/v1/auth/consent", h.GetConsentRequest)
|
app.Get("/api/v1/auth/consent", h.GetConsentRequest)
|
||||||
|
|
||||||
|
t.Setenv("APP_ENV", "dev")
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/v1/auth/consent?consent_challenge=challenge-tenant", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/auth/consent?consent_challenge=challenge-tenant", nil)
|
||||||
req.Header.Set("X-Mock-Role", "user")
|
req.Header.Set("X-Mock-Role", "user")
|
||||||
req.Header.Set("X-Tenant-ID", "tenant-a")
|
req.Header.Set("X-Tenant-ID", "tenant-a")
|
||||||
|
|||||||
@@ -13,47 +13,47 @@ import (
|
|||||||
|
|
||||||
// Ory 계열(kratos/hydra) 공급자 문자열을 정규화하기 위한 매핑.
|
// Ory 계열(kratos/hydra) 공급자 문자열을 정규화하기 위한 매핑.
|
||||||
var providerAliases = map[string]string{
|
var providerAliases = map[string]string{
|
||||||
"ory": "ory",
|
"ory": "ory",
|
||||||
"hydra": "ory",
|
"hydra": "ory",
|
||||||
"kratos": "ory",
|
"kratos": "ory",
|
||||||
"ory-kratos": "ory",
|
"ory-kratos": "ory",
|
||||||
"ory_hydra": "ory",
|
"ory_hydra": "ory",
|
||||||
"ory_kratos": "ory",
|
"ory_kratos": "ory",
|
||||||
}
|
}
|
||||||
|
|
||||||
// getEnv는 환경 변수를 읽거나 대체 값을 반환하는 헬퍼 함수입니다.
|
// getEnv는 환경 변수를 읽거나 대체 값을 반환하는 헬퍼 함수입니다.
|
||||||
func getEnv(key, fallback string) string {
|
func getEnv(key, fallback string) string {
|
||||||
if value, ok := os.LookupEnv(key); ok {
|
if value, ok := os.LookupEnv(key); ok {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeProvider는 환경 설정을 기반으로 IDP 공급자를 생성하고 반환합니다.
|
// InitializeProvider는 환경 설정을 기반으로 IDP 공급자를 생성하고 반환합니다.
|
||||||
// 이것은 IdentityProvider 인터페이스의 팩토리 역할을 합니다.
|
// 이것은 IdentityProvider 인터페이스의 팩토리 역할을 합니다.
|
||||||
func InitializeProvider() (domain.IdentityProvider, error) {
|
func InitializeProvider() (domain.IdentityProvider, error) {
|
||||||
rawProviders := getEnv("IDP_PROVIDER", "ory")
|
rawProviders := getEnv("IDP_PROVIDER", "ory")
|
||||||
providers := strings.Split(rawProviders, ",")
|
providers := strings.Split(rawProviders, ",")
|
||||||
slog.Info("Initializing IDP chain", "providers", rawProviders)
|
slog.Info("Initializing IDP chain", "providers", rawProviders)
|
||||||
|
|
||||||
var initialized []domain.IdentityProvider
|
var initialized []domain.IdentityProvider
|
||||||
for _, p := range providers {
|
for _, p := range providers {
|
||||||
providerName := strings.TrimSpace(strings.ToLower(p))
|
providerName := strings.TrimSpace(strings.ToLower(p))
|
||||||
if canonical, ok := providerAliases[providerName]; ok {
|
if canonical, ok := providerAliases[providerName]; ok {
|
||||||
providerName = canonical
|
providerName = canonical
|
||||||
}
|
}
|
||||||
|
|
||||||
switch providerName {
|
switch providerName {
|
||||||
case "ory":
|
case "ory":
|
||||||
// Kratos/Hydra 주 공급자
|
// Kratos/Hydra 주 공급자
|
||||||
oryProvider := service.NewOryProvider()
|
oryProvider := service.NewOryProvider()
|
||||||
initialized = append(initialized, oryProvider)
|
initialized = append(initialized, oryProvider)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// 알 수 없는 공급자는 건너뛰고 다음 후보를 시도
|
// 알 수 없는 공급자는 건너뛰고 다음 후보를 시도
|
||||||
slog.Warn("Skipping unsupported IDP provider entry", "provider", providerName)
|
slog.Warn("Skipping unsupported IDP provider entry", "provider", providerName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(initialized) == 0 {
|
if len(initialized) == 0 {
|
||||||
return nil, fmt.Errorf("no valid IDP_PROVIDER entries configured from: %s", rawProviders)
|
return nil, fmt.Errorf("no valid IDP_PROVIDER entries configured from: %s", rawProviders)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auto-migrate
|
// Auto-migrate
|
||||||
err = db.AutoMigrate(&domain.Tenant{}, &domain.TenantDomain{}, &domain.User{})
|
err = db.AutoMigrate(&domain.Tenant{}, &domain.TenantDomain{}, &domain.User{}, &domain.ClientConsent{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to migrate database: %s", err)
|
log.Fatalf("failed to migrate database: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,10 +174,7 @@ function ClientGeneralPage() {
|
|||||||
{
|
{
|
||||||
id: "2",
|
id: "2",
|
||||||
name: "tenant",
|
name: "tenant",
|
||||||
description: t(
|
description: t("msg.dev.clients.scopes.tenant", "소속 테넌트 정보 접근"),
|
||||||
"msg.dev.clients.scopes.tenant",
|
|
||||||
"소속 테넌트 정보 접근",
|
|
||||||
),
|
|
||||||
mandatory: false,
|
mandatory: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -347,12 +344,15 @@ function ClientGeneralPage() {
|
|||||||
return {
|
return {
|
||||||
...scope,
|
...scope,
|
||||||
description: scope.description || tenantScopeDescription,
|
description: scope.description || tenantScopeDescription,
|
||||||
mandatory: restricted ? true : false,
|
mandatory: restricted,
|
||||||
locked: restricted,
|
locked: restricted,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
if (restricted && !normalized.some((scope) => scope.name.trim() === "tenant")) {
|
if (
|
||||||
|
restricted &&
|
||||||
|
!normalized.some((scope) => scope.name.trim() === "tenant")
|
||||||
|
) {
|
||||||
normalized.push(buildTenantScope(`tenant-${Date.now()}`));
|
normalized.push(buildTenantScope(`tenant-${Date.now()}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,7 +526,8 @@ function ClientGeneralPage() {
|
|||||||
|
|
||||||
const hasValidationErrors = validationErrors.length > 0;
|
const hasValidationErrors = validationErrors.length > 0;
|
||||||
const normalizedTenantSearch = tenantSearch.trim().toLowerCase();
|
const normalizedTenantSearch = tenantSearch.trim().toLowerCase();
|
||||||
const tenantOptions: Array<TenantSummary | MyTenantSummary> = tenantData ?? [];
|
const tenantOptions: Array<TenantSummary | MyTenantSummary> =
|
||||||
|
tenantData ?? [];
|
||||||
const filteredTenants = tenantOptions.filter((tenant) => {
|
const filteredTenants = tenantOptions.filter((tenant) => {
|
||||||
if (!normalizedTenantSearch) {
|
if (!normalizedTenantSearch) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1375,10 +1376,7 @@ function ClientGeneralPage() {
|
|||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={t(
|
aria-label={t("ui.common.delete", "삭제")}
|
||||||
"ui.common.delete",
|
|
||||||
"삭제",
|
|
||||||
)}
|
|
||||||
onClick={() => toggleAllowedTenant(tenant.id)}
|
onClick={() => toggleAllowedTenant(tenant.id)}
|
||||||
className="text-muted-foreground transition hover:text-destructive"
|
className="text-muted-foreground transition hover:text-destructive"
|
||||||
>
|
>
|
||||||
@@ -1403,10 +1401,7 @@ function ClientGeneralPage() {
|
|||||||
<span className="max-w-44 truncate">{tenantId}</span>
|
<span className="max-w-44 truncate">{tenantId}</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label={t(
|
aria-label={t("ui.common.delete", "삭제")}
|
||||||
"ui.common.delete",
|
|
||||||
"삭제",
|
|
||||||
)}
|
|
||||||
onClick={() => toggleAllowedTenant(tenantId)}
|
onClick={() => toggleAllowedTenant(tenantId)}
|
||||||
className="text-muted-foreground transition hover:text-destructive"
|
className="text-muted-foreground transition hover:text-destructive"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -650,6 +650,22 @@ title_generic = "An error occurred."
|
|||||||
title_with_code = "Error: {{code}}"
|
title_with_code = "Error: {{code}}"
|
||||||
type = "Error type: {{type}}"
|
type = "Error type: {{type}}"
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = "Account"
|
||||||
|
account_unknown = "Unknown"
|
||||||
|
affiliated_tenants = "All affiliated tenants"
|
||||||
|
allowed_box_title = "Allowed tenants"
|
||||||
|
allowed_tenants = "Allowed tenants"
|
||||||
|
detail = "The currently signed-in account cannot access this application."
|
||||||
|
load_failed = "We could not confirm the account details. Please try again."
|
||||||
|
loading = "Loading the current account details."
|
||||||
|
lookup_fallback = "Some fields could not be verified because the access context was incomplete."
|
||||||
|
page_title = "Access to this application is restricted"
|
||||||
|
primary_tenant = "Primary affiliated tenant"
|
||||||
|
tenant = "Tenant"
|
||||||
|
tenant_unknown = "Unknown"
|
||||||
|
title = "Access restriction details"
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
[msg.userfront.error.ory]
|
||||||
"$normalizedCode" = "{{error}}"
|
"$normalizedCode" = "{{error}}"
|
||||||
access_denied = "The user denied the consent request."
|
access_denied = "The user denied the consent request."
|
||||||
@@ -2239,6 +2255,7 @@ windows = "Desktop(Windows)"
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = "Go Home"
|
go_home = "Go Home"
|
||||||
go_login = "Go Login"
|
go_login = "Go Login"
|
||||||
|
switch_account = "Sign in with another account"
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = "Forgot your password?"
|
heading = "Forgot your password?"
|
||||||
|
|||||||
@@ -208,6 +208,22 @@ title_generic = "오류가 발생했습니다"
|
|||||||
title_with_code = "오류: {{code}}"
|
title_with_code = "오류: {{code}}"
|
||||||
type = "오류 종류: {{type}}"
|
type = "오류 종류: {{type}}"
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = "계정"
|
||||||
|
account_unknown = "알 수 없음"
|
||||||
|
affiliated_tenants = "전체 소속 테넌트"
|
||||||
|
allowed_box_title = "접속 가능 테넌트"
|
||||||
|
allowed_tenants = "접속 가능 테넌트"
|
||||||
|
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
||||||
|
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
||||||
|
loading = "현재 계정 정보를 불러오는 중입니다."
|
||||||
|
lookup_fallback = "표시 정보가 충분하지 않아 일부 항목은 확인되지 않을 수 있습니다."
|
||||||
|
page_title = "애플리케이션 접근이 제한되었습니다"
|
||||||
|
primary_tenant = "대표 소속 테넌트"
|
||||||
|
tenant = "소속 테넌트"
|
||||||
|
tenant_unknown = "알 수 없음"
|
||||||
|
title = "접근 제한 정보"
|
||||||
|
|
||||||
[msg.userfront.forgot]
|
[msg.userfront.forgot]
|
||||||
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
description = "계정과 연결된 이메일 주소 또는 휴대폰 번호를 입력하시면, 비밀번호를 재설정할 수 있는 링크를 보내드립니다."
|
||||||
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
dry_send = "drySend 모드: 실제 이메일/SMS는 발송되지 않습니다."
|
||||||
@@ -456,6 +472,7 @@ windows = "Desktop(Windows)"
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = "홈으로 이동"
|
go_home = "홈으로 이동"
|
||||||
go_login = "로그인으로 이동"
|
go_login = "로그인으로 이동"
|
||||||
|
switch_account = "다른 계정으로 로그인"
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = "비밀번호를 잊으셨나요?"
|
heading = "비밀번호를 잊으셨나요?"
|
||||||
@@ -1088,6 +1105,22 @@ title_generic = "오류가 발생했습니다"
|
|||||||
title_with_code = "오류: {{code}}"
|
title_with_code = "오류: {{code}}"
|
||||||
type = "오류 종류: {{type}}"
|
type = "오류 종류: {{type}}"
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = "계정"
|
||||||
|
account_unknown = "알 수 없음"
|
||||||
|
affiliated_tenants = "전체 소속 테넌트"
|
||||||
|
allowed_box_title = "접속 가능 테넌트"
|
||||||
|
allowed_tenants = "접속 가능 테넌트"
|
||||||
|
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
||||||
|
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
||||||
|
loading = "현재 계정 정보를 불러오는 중입니다."
|
||||||
|
lookup_fallback = "표시 정보가 충분하지 않아 일부 항목은 확인되지 않을 수 있습니다."
|
||||||
|
page_title = "애플리케이션 접근이 제한되었습니다"
|
||||||
|
primary_tenant = "대표 소속 테넌트"
|
||||||
|
tenant = "소속 테넌트"
|
||||||
|
tenant_unknown = "알 수 없음"
|
||||||
|
title = "접근 제한 정보"
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
[msg.userfront.error.ory]
|
||||||
"$normalizedCode" = "{{error}}"
|
"$normalizedCode" = "{{error}}"
|
||||||
access_denied = "사용자가 동의를 거부했습니다."
|
access_denied = "사용자가 동의를 거부했습니다."
|
||||||
@@ -2638,6 +2671,7 @@ windows = "Desktop(Windows)"
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = "홈으로 이동"
|
go_home = "홈으로 이동"
|
||||||
go_login = "로그인으로 이동"
|
go_login = "로그인으로 이동"
|
||||||
|
switch_account = "다른 계정으로 로그인"
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = "비밀번호를 잊으셨나요?"
|
heading = "비밀번호를 잊으셨나요?"
|
||||||
|
|||||||
@@ -83,6 +83,22 @@ title_generic = ""
|
|||||||
title_with_code = ""
|
title_with_code = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = ""
|
||||||
|
account_unknown = ""
|
||||||
|
affiliated_tenants = ""
|
||||||
|
allowed_box_title = ""
|
||||||
|
allowed_tenants = ""
|
||||||
|
detail = ""
|
||||||
|
load_failed = ""
|
||||||
|
loading = ""
|
||||||
|
lookup_fallback = ""
|
||||||
|
page_title = ""
|
||||||
|
primary_tenant = ""
|
||||||
|
tenant = ""
|
||||||
|
tenant_unknown = ""
|
||||||
|
title = ""
|
||||||
|
|
||||||
[msg.userfront.forgot]
|
[msg.userfront.forgot]
|
||||||
description = ""
|
description = ""
|
||||||
dry_send = ""
|
dry_send = ""
|
||||||
@@ -331,6 +347,7 @@ windows = ""
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = ""
|
go_home = ""
|
||||||
go_login = ""
|
go_login = ""
|
||||||
|
switch_account = ""
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = ""
|
heading = ""
|
||||||
@@ -963,6 +980,22 @@ title_generic = ""
|
|||||||
title_with_code = ""
|
title_with_code = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = ""
|
||||||
|
account_unknown = ""
|
||||||
|
affiliated_tenants = ""
|
||||||
|
allowed_box_title = ""
|
||||||
|
allowed_tenants = ""
|
||||||
|
detail = ""
|
||||||
|
load_failed = ""
|
||||||
|
loading = ""
|
||||||
|
lookup_fallback = ""
|
||||||
|
page_title = ""
|
||||||
|
primary_tenant = ""
|
||||||
|
tenant = ""
|
||||||
|
tenant_unknown = ""
|
||||||
|
title = ""
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
[msg.userfront.error.ory]
|
||||||
"$normalizedCode" = ""
|
"$normalizedCode" = ""
|
||||||
access_denied = ""
|
access_denied = ""
|
||||||
@@ -2513,6 +2546,7 @@ windows = ""
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = ""
|
go_home = ""
|
||||||
go_login = ""
|
go_login = ""
|
||||||
|
switch_account = ""
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = ""
|
heading = ""
|
||||||
|
|||||||
@@ -5,9 +5,14 @@ job_name="${1:-adminfront-tests}"
|
|||||||
|
|
||||||
mkdir -p reports
|
mkdir -p reports
|
||||||
|
|
||||||
if [ -n "${CI:-}" ]; then
|
PLAYWRIGHT_BROWSERS_PATH="${HOME}/.cache/ms-playwright"
|
||||||
playwright_install_cmd=(npx playwright install --with-deps)
|
PLAYWRIGHT_CHROMIUM_COMPLETE="${PLAYWRIGHT_BROWSERS_PATH}/chromium-1208/INSTALLATION_COMPLETE"
|
||||||
playwright_install_desc="npx playwright install --with-deps"
|
PLAYWRIGHT_FIREFOX_COMPLETE="${PLAYWRIGHT_BROWSERS_PATH}/firefox-1509/INSTALLATION_COMPLETE"
|
||||||
|
PLAYWRIGHT_WEBKIT_COMPLETE="${PLAYWRIGHT_BROWSERS_PATH}/webkit-2248/INSTALLATION_COMPLETE"
|
||||||
|
|
||||||
|
if [ -f "$PLAYWRIGHT_CHROMIUM_COMPLETE" ] && [ -f "$PLAYWRIGHT_FIREFOX_COMPLETE" ] && [ -f "$PLAYWRIGHT_WEBKIT_COMPLETE" ]; then
|
||||||
|
playwright_install_cmd=(sh -c 'echo "Playwright browsers already installed"')
|
||||||
|
playwright_install_desc="Playwright browsers already installed"
|
||||||
else
|
else
|
||||||
playwright_install_cmd=(npx playwright install)
|
playwright_install_cmd=(npx playwright install)
|
||||||
playwright_install_desc="npx playwright install"
|
playwright_install_desc="npx playwright install"
|
||||||
@@ -16,7 +21,7 @@ fi
|
|||||||
set +e
|
set +e
|
||||||
(
|
(
|
||||||
cd adminfront
|
cd adminfront
|
||||||
npm ci
|
npm ci --ignore-scripts
|
||||||
) 2>&1 | tee reports/adminfront-install.log
|
) 2>&1 | tee reports/adminfront-install.log
|
||||||
install_exit_code=${PIPESTATUS[0]}
|
install_exit_code=${PIPESTATUS[0]}
|
||||||
set -e
|
set -e
|
||||||
@@ -31,7 +36,7 @@ if [ "$install_exit_code" -ne 0 ]; then
|
|||||||
echo "- Exit Code: \`$install_exit_code\`"
|
echo "- Exit Code: \`$install_exit_code\`"
|
||||||
echo
|
echo
|
||||||
echo "## Command"
|
echo "## Command"
|
||||||
echo "\`cd adminfront && npm ci\`"
|
echo "\`cd adminfront && npm ci --ignore-scripts\`"
|
||||||
echo
|
echo
|
||||||
echo "## Install Log Tail (last 200 lines)"
|
echo "## Install Log Tail (last 200 lines)"
|
||||||
echo '```text'
|
echo '```text'
|
||||||
@@ -70,7 +75,7 @@ if [ "$provision_exit_code" -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
port="$(node -e "const net=require('node:net'); const s=net.createServer(); s.listen(0,'127.0.0.1',()=>{console.log(s.address().port); s.close();});")"
|
port="${PORT:-5173}"
|
||||||
echo "==> adminfront using PORT=$port"
|
echo "==> adminfront using PORT=$port"
|
||||||
(
|
(
|
||||||
cd adminfront
|
cd adminfront
|
||||||
@@ -89,7 +94,7 @@ if [ "$test_exit_code" -ne 0 ]; then
|
|||||||
echo
|
echo
|
||||||
echo "## Commands"
|
echo "## Commands"
|
||||||
echo "1. \`cd adminfront\`"
|
echo "1. \`cd adminfront\`"
|
||||||
echo "2. \`npm ci\`"
|
echo "2. \`npm ci --ignore-scripts\`"
|
||||||
echo "3. \`${playwright_install_desc}\`"
|
echo "3. \`${playwright_install_desc}\`"
|
||||||
echo "4. \`npm test\`"
|
echo "4. \`npm test\`"
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -140,9 +140,15 @@ type = "Error type: {type}"
|
|||||||
[msg.userfront.error.tenant]
|
[msg.userfront.error.tenant]
|
||||||
account = "Account"
|
account = "Account"
|
||||||
account_unknown = "Unknown"
|
account_unknown = "Unknown"
|
||||||
|
affiliated_tenants = "All affiliated tenants"
|
||||||
|
allowed_box_title = "Allowed tenants"
|
||||||
|
allowed_tenants = "Allowed tenants"
|
||||||
detail = "The currently signed-in account cannot access this application."
|
detail = "The currently signed-in account cannot access this application."
|
||||||
load_failed = "We could not confirm the account details. Please try again."
|
load_failed = "We could not confirm the account details. Please try again."
|
||||||
loading = "Loading the current account details."
|
loading = "Loading the current account details."
|
||||||
|
lookup_fallback = "Some fields could not be verified because the access context was incomplete."
|
||||||
|
page_title = "Access to this application is restricted"
|
||||||
|
primary_tenant = "Primary affiliated tenant"
|
||||||
tenant = "Tenant"
|
tenant = "Tenant"
|
||||||
tenant_unknown = "Unknown"
|
tenant_unknown = "Unknown"
|
||||||
title = "Access restriction details"
|
title = "Access restriction details"
|
||||||
|
|||||||
@@ -81,9 +81,15 @@ type = "오류 종류: {type}"
|
|||||||
[msg.userfront.error.tenant]
|
[msg.userfront.error.tenant]
|
||||||
account = "계정"
|
account = "계정"
|
||||||
account_unknown = "알 수 없음"
|
account_unknown = "알 수 없음"
|
||||||
|
affiliated_tenants = "전체 소속 테넌트"
|
||||||
|
allowed_box_title = "접속 가능 테넌트"
|
||||||
|
allowed_tenants = "접속 가능 테넌트"
|
||||||
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
||||||
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
||||||
loading = "현재 계정 정보를 불러오는 중입니다."
|
loading = "현재 계정 정보를 불러오는 중입니다."
|
||||||
|
lookup_fallback = "표시 정보가 충분하지 않아 일부 항목은 확인되지 않을 수 있습니다."
|
||||||
|
page_title = "애플리케이션 접근이 제한되었습니다"
|
||||||
|
primary_tenant = "대표 소속 테넌트"
|
||||||
tenant = "소속 테넌트"
|
tenant = "소속 테넌트"
|
||||||
tenant_unknown = "알 수 없음"
|
tenant_unknown = "알 수 없음"
|
||||||
title = "접근 제한 정보"
|
title = "접근 제한 정보"
|
||||||
@@ -355,6 +361,22 @@ title_generic = "오류가 발생했습니다"
|
|||||||
title_with_code = "오류: {code}"
|
title_with_code = "오류: {code}"
|
||||||
type = "오류 종류: {type}"
|
type = "오류 종류: {type}"
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = "계정"
|
||||||
|
account_unknown = "알 수 없음"
|
||||||
|
affiliated_tenants = "전체 소속 테넌트"
|
||||||
|
allowed_box_title = "접속 가능 테넌트"
|
||||||
|
allowed_tenants = "접속 가능 테넌트"
|
||||||
|
detail = "현재 로그인된 계정은 이 애플리케이션에 접근할 수 없습니다."
|
||||||
|
load_failed = "계정 정보를 확인하지 못했습니다. 다시 시도해 주세요."
|
||||||
|
loading = "현재 계정 정보를 불러오는 중입니다."
|
||||||
|
lookup_fallback = "표시 정보가 충분하지 않아 일부 항목은 확인되지 않을 수 있습니다."
|
||||||
|
page_title = "애플리케이션 접근이 제한되었습니다"
|
||||||
|
primary_tenant = "대표 소속 테넌트"
|
||||||
|
tenant = "소속 테넌트"
|
||||||
|
tenant_unknown = "알 수 없음"
|
||||||
|
title = "접근 제한 정보"
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
[msg.userfront.error.ory]
|
||||||
"$normalizedCode" = "{error}"
|
"$normalizedCode" = "{error}"
|
||||||
access_denied = "사용자가 동의를 거부했습니다."
|
access_denied = "사용자가 동의를 거부했습니다."
|
||||||
@@ -722,6 +744,7 @@ windows = "Desktop(Windows)"
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = "홈으로 이동"
|
go_home = "홈으로 이동"
|
||||||
go_login = "로그인으로 이동"
|
go_login = "로그인으로 이동"
|
||||||
|
switch_account = "다른 계정으로 로그인"
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = "비밀번호를 잊으셨나요?"
|
heading = "비밀번호를 잊으셨나요?"
|
||||||
|
|||||||
@@ -53,9 +53,15 @@ type = ""
|
|||||||
[msg.userfront.error.tenant]
|
[msg.userfront.error.tenant]
|
||||||
account = ""
|
account = ""
|
||||||
account_unknown = ""
|
account_unknown = ""
|
||||||
|
affiliated_tenants = ""
|
||||||
|
allowed_box_title = ""
|
||||||
|
allowed_tenants = ""
|
||||||
detail = ""
|
detail = ""
|
||||||
load_failed = ""
|
load_failed = ""
|
||||||
loading = ""
|
loading = ""
|
||||||
|
lookup_fallback = ""
|
||||||
|
page_title = ""
|
||||||
|
primary_tenant = ""
|
||||||
tenant = ""
|
tenant = ""
|
||||||
tenant_unknown = ""
|
tenant_unknown = ""
|
||||||
title = ""
|
title = ""
|
||||||
@@ -327,6 +333,22 @@ title_generic = ""
|
|||||||
title_with_code = ""
|
title_with_code = ""
|
||||||
type = ""
|
type = ""
|
||||||
|
|
||||||
|
[msg.userfront.error.tenant]
|
||||||
|
account = ""
|
||||||
|
account_unknown = ""
|
||||||
|
affiliated_tenants = ""
|
||||||
|
allowed_box_title = ""
|
||||||
|
allowed_tenants = ""
|
||||||
|
detail = ""
|
||||||
|
load_failed = ""
|
||||||
|
loading = ""
|
||||||
|
lookup_fallback = ""
|
||||||
|
page_title = ""
|
||||||
|
primary_tenant = ""
|
||||||
|
tenant = ""
|
||||||
|
tenant_unknown = ""
|
||||||
|
title = ""
|
||||||
|
|
||||||
[msg.userfront.error.ory]
|
[msg.userfront.error.ory]
|
||||||
"$normalizedCode" = ""
|
"$normalizedCode" = ""
|
||||||
access_denied = ""
|
access_denied = ""
|
||||||
@@ -694,6 +716,7 @@ windows = ""
|
|||||||
[ui.userfront.error]
|
[ui.userfront.error]
|
||||||
go_home = ""
|
go_home = ""
|
||||||
go_login = ""
|
go_login = ""
|
||||||
|
switch_account = ""
|
||||||
|
|
||||||
[ui.userfront.forgot]
|
[ui.userfront.forgot]
|
||||||
heading = ""
|
heading = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user