1
0
forked from baron/baron-sso

Merge branch 'dev' into feature/rbac-simplification-and-remove-dev-switcher

This commit is contained in:
2026-06-02 18:36:44 +09:00
88 changed files with 7453 additions and 2180 deletions

View File

@@ -99,6 +99,70 @@ func sanitizeUserMetadata(metadata map[string]any) map[string]any {
return sanitized
}
func sanitizeUserRepresentativeTenants(ctx context.Context, tenantService service.TenantService, metadata map[string]any, appointments []map[string]any) (bool, error) {
if tenantService == nil || metadata == nil {
return false, nil
}
cleared := false
clearMetadataPrimary := func() {
delete(metadata, "primaryTenantId")
delete(metadata, "primaryTenantSlug")
delete(metadata, "primaryTenantName")
delete(metadata, "primaryTenantIsOwner")
cleared = true
}
if isNonPublicRepresentativeTenant(ctx, tenantService, normalizeMetadataString(metadata["primaryTenantId"]), normalizeMetadataString(metadata["primaryTenantSlug"])) {
clearMetadataPrimary()
}
clearAppointment := func(appointment map[string]any) {
if isPrimary, ok := metadataBoolFromMap(appointment, "isPrimary", "primary", "representative", "isRepresentative"); !ok || !isPrimary {
return
}
tenantID := normalizeMetadataString(appointment["tenantId"])
tenantSlug := normalizeMetadataString(appointment["tenantSlug"])
if tenantSlug == "" {
tenantSlug = normalizeMetadataString(appointment["slug"])
}
if !isNonPublicRepresentativeTenant(ctx, tenantService, tenantID, tenantSlug) {
return
}
appointment["isPrimary"] = false
appointment["primary"] = false
appointment["representative"] = false
appointment["isRepresentative"] = false
clearMetadataPrimary()
}
for _, appointment := range appointments {
clearAppointment(appointment)
}
if rawAppointments, ok := metadata["additionalAppointments"].([]any); ok {
for _, rawAppointment := range rawAppointments {
if appointment, ok := rawAppointment.(map[string]any); ok {
clearAppointment(appointment)
}
}
}
return cleared, nil
}
func isNonPublicRepresentativeTenant(ctx context.Context, tenantService service.TenantService, tenantID string, tenantSlug string) bool {
var tenant *domain.Tenant
var err error
if strings.TrimSpace(tenantID) != "" {
tenant, err = tenantService.GetTenant(ctx, strings.TrimSpace(tenantID))
} else if strings.TrimSpace(tenantSlug) != "" {
tenant, err = tenantService.GetTenantBySlug(ctx, strings.TrimSpace(tenantSlug))
}
if err != nil || tenant == nil {
return false
}
visibility := tenantVisibility(tenant.Config)
return visibility == "internal" || visibility == "private"
}
func primaryTenantIDFromRequest(primaryTenantID string, metadata map[string]any, appointments []map[string]any) string {
if value := strings.TrimSpace(primaryTenantID); value != "" {
return value
@@ -651,6 +715,20 @@ func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
}
req.CompanyCode = tenantSlug
req.Metadata = sanitizeUserMetadata(mergeUserAppointmentMetadata(req.Metadata, req.AdditionalAppointments, req.PrimaryTenantID, req.PrimaryTenantName, req.PrimaryTenantIsOwner))
representativeCleared := false
if h.TenantService != nil {
cleared, err := sanitizeUserRepresentativeTenants(c.Context(), h.TenantService, req.Metadata, req.AdditionalAppointments)
if err != nil {
return errorJSON(c, fiber.StatusBadRequest, err.Error())
}
representativeCleared = cleared
if cleared {
req.PrimaryTenantID = ""
req.PrimaryTenantName = ""
req.PrimaryTenantIsOwner = nil
req.CompanyCode = ""
}
}
email := strings.TrimSpace(req.Email)
if email == "" {
@@ -725,7 +803,11 @@ func (h *UserHandler) CreateUser(c *fiber.Ctx) error {
// [Resolve TenantID and Custom Login IDs before Kratos creation]
var tenantID string
requestedPrimaryTenantID := primaryTenantIDFromRequest(req.PrimaryTenantID, req.Metadata, req.AdditionalAppointments)
primaryAppointments := req.AdditionalAppointments
if representativeCleared {
primaryAppointments = nil
}
requestedPrimaryTenantID := primaryTenantIDFromRequest(req.PrimaryTenantID, req.Metadata, primaryAppointments)
if req.CompanyCode == "" && h.TenantService != nil {
if requestedPrimaryTenantID != "" {
if tenant, err := h.TenantService.GetTenant(c.Context(), requestedPrimaryTenantID); err == nil && tenant != nil {
@@ -1971,6 +2053,18 @@ func (h *UserHandler) UpdateUser(c *fiber.Ctx) error {
}
req.CompanyCode = tenantSlug
req.Metadata = sanitizeUserMetadata(mergeUserAppointmentMetadata(req.Metadata, req.AdditionalAppointments, req.PrimaryTenantID, req.PrimaryTenantName, req.PrimaryTenantIsOwner))
if h.TenantService != nil {
cleared, err := sanitizeUserRepresentativeTenants(c.Context(), h.TenantService, req.Metadata, req.AdditionalAppointments)
if err != nil {
return errorJSON(c, fiber.StatusBadRequest, err.Error())
}
if cleared {
req.PrimaryTenantID = ""
req.PrimaryTenantName = ""
req.PrimaryTenantIsOwner = nil
req.CompanyCode = nil
}
}
if req.Role != nil {
if requester == nil || domain.NormalizeRole(requester.Role) != domain.RoleSuperAdmin {
return errorJSON(c, fiber.StatusForbidden, "forbidden: only super admin can change user role")