From c39857c66c144d82b17d53c4bd968a1167bb5bab Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 21 Jan 2026 12:51:00 +0900 Subject: [PATCH] =?UTF-8?q?slog=20=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/cmd/server/main.go | 73 ++++++------ backend/internal/handler/admin_handler.go | 20 ++-- backend/internal/handler/auth_handler.go | 131 +++++++++++----------- backend/internal/service/ses_service.go | 11 +- backend/internal/service/sms_service.go | 13 ++- 5 files changed, 127 insertions(+), 121 deletions(-) diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 522852b1..909abe8b 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -1,27 +1,19 @@ package main import ( + "baron-sso-backend/internal/handler" + "baron-sso-backend/internal/logger" + "baron-sso-backend/internal/repository" + "baron-sso-backend/internal/service" + "fmt" "log/slog" "os" - "strings" "strconv" + "strings" "time" - - "github.com/bwmarrin/snowflake" - - "baron-sso-backend/internal/handler" - - "baron-sso-backend/internal/logger" - - "baron-sso-backend/internal/repository" - - "baron-sso-backend/internal/service" - - - - "github.com/gofiber/fiber/v2" - - + + "github.com/bwmarrin/snowflake" + "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cors" "github.com/gofiber/fiber/v2/middleware/encryptcookie" "github.com/gofiber/fiber/v2/middleware/recover" @@ -41,7 +33,6 @@ func main() { ServiceName: "baron-sso", Environment: getEnv("GO_ENV", "dev"), }) - // Initialize Snowflake Node (Node 2 for Baron) node, err := snowflake.NewNode(2) if err != nil { @@ -50,10 +41,22 @@ func main() { } // 1. Log Config on Startup - slog.Info("Starting Baron SSO Backend", + fmt.Println("============================================================") + fmt.Println(` + |\__/,| (\ + _.|o o |_ ) ) + -(((---(((-------- + `) + fmt.Println("๐Ÿš€ Baron SSO Backend Starting...") + + slog.Info("Service starting", + "service", "baron-sso", + "app_env", getEnv("APP_ENV", "dev"), + "db_port", getEnv("DB_PORT", "5532"), + "backend_port", getEnv("BACKEND_PORT", "3000"), + "frontend_port", getEnv("FRONTEND_PORT", "5000"), "frontend_url", getEnv("FRONTEND_URL", "http://ssologin.hmac.kr"), "redis_addr", getEnv("REDIS_ADDR", "redis:6379"), - "descope_id", getEnv("DESCOPE_PROJECT_ID", "not-set"), ) // 2. Initialize DB Connections @@ -80,7 +83,7 @@ func main() { // 3. Initialize Fiber app := fiber.New(fiber.Config{ - AppName: "Baron SSO Backend", + AppName: "Baron SSO Backend", DisableStartupMessage: true, // Clean logs }) @@ -94,10 +97,10 @@ func main() { // [Standardized] HTTP Request Logger Middleware using slog app.Use(func(c *fiber.Ctx) error { start := time.Now() - + // Handle request err := c.Next() - + // Log after request latency := time.Since(start) status := c.Response().StatusCode() @@ -107,7 +110,7 @@ func main() { if status < 400 { return err } - + msg := "http_request" if err != nil { msg = "http_request_error" @@ -129,7 +132,7 @@ func main() { AllowOrigins: "*", // Adjust in production AllowHeaders: "Origin, Content-Type, Accept, Authorization", AllowMethods: "GET, POST, HEAD, PUT, DELETE, PATCH, OPTIONS", - })) + })) app.Use(encryptcookie.New(encryptcookie.Config{ Key: getEnv("COOKIE_SECRET", "secret-key-must-be-32-bytes-long!"), })) @@ -185,7 +188,7 @@ func main() { // API Group api := app.Group("/api/v1") api.Post("/audit", auditHandler.CreateLog) - + // Auth Proxy Routes auth := api.Group("/auth") auth.Post("/enchanted-link/init", authHandler.InitEnchantedLink) @@ -196,7 +199,7 @@ func main() { auth.Post("/qr/init", authHandler.InitQRLogin) auth.Post("/qr/poll", authHandler.PollQRLogin) auth.Post("/qr/approve", authHandler.ScanQRLogin) - + // Admin Routes admin := api.Group("/admin") admin.Post("/users", adminHandler.CreateUser) @@ -205,10 +208,10 @@ func main() { admin.Patch("/users/:loginId", adminHandler.UpdateUser) admin.Delete("/users/:loginId", adminHandler.DeleteUser) admin.Patch("/users/:loginId/status", adminHandler.UpdateUserStatus) - + // Webhook for Descope Generic SMS Gateway auth.Post("/webhooks/descope-sms", authHandler.HandleDescopeSmsRelay) - + // Webhook for Descope Generic Email Gateway (Fake Email Strategy) auth.Post("/webhooks/descope-email", authHandler.HandleDescopeEmailRelay) @@ -229,7 +232,7 @@ func main() { slog.String("source", "client"), } for k, v := range req.Data { - // Skip svc if it's already set by the global logger to avoid confusion, + // Skip svc if it's already set by the global logger to avoid confusion, // or keep it as client_svc if k == "svc" { attrs = append(attrs, slog.Any("client_svc", v)) @@ -252,9 +255,10 @@ func main() { // Filter out noisy client navigation logs if level == slog.LevelInfo { msg := strings.ToLower(req.Message) - if strings.Contains(msg, "navigating to") || - strings.Contains(msg, "going to") || - strings.Contains(msg, "redirecting to") { + if strings.Contains(msg, "navigating to") || + strings.Contains(msg, "going to") || + strings.Contains(msg, "redirecting to") || + strings.Contains(msg, "full paths for routes") { return c.SendStatus(fiber.StatusOK) } } @@ -264,8 +268,9 @@ func main() { }) // Start Server - port := getEnv("PORT", "3000") + port := getEnv("BACKEND_PORT", "3000") slog.Info("Server listening", "port", port) + fmt.Println("============================================================") if err := app.Listen(":" + port); err != nil { slog.Error("Server failed to start", "error", err) os.Exit(1) diff --git a/backend/internal/handler/admin_handler.go b/backend/internal/handler/admin_handler.go index d54de25a..4c68e7bc 100644 --- a/backend/internal/handler/admin_handler.go +++ b/backend/internal/handler/admin_handler.go @@ -2,7 +2,7 @@ package handler import ( "context" - "log" + "log/slog" "os" "strings" "net/url" @@ -29,10 +29,10 @@ func NewAdminHandler() *AdminHandler { ManagementKey: managementKey, }) if err != nil { - log.Printf("Warning: Failed to initialize Descope Client for Admin: %v", err) + slog.Warn("Failed to initialize Descope Client for Admin", "error", err) } } else { - log.Println("Warning: DESCOPE_PROJECT_ID or DESCOPE_MANAGEMENT_KEY missing. Admin functions will fail.") + slog.Warn("DESCOPE_PROJECT_ID or DESCOPE_MANAGEMENT_KEY missing. Admin functions will fail.") } return &AdminHandler{ @@ -95,7 +95,7 @@ func (h *AdminHandler) ListUsers(c *fiber.Ctx) error { } if err != nil { - log.Printf("[Admin] ListUsers failed: %v", err) + slog.Error("[Admin] ListUsers failed", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } @@ -112,9 +112,9 @@ func (h *AdminHandler) DeleteUser(c *fiber.Ctx) error { loginID = decoded } - log.Printf("[Admin] Deleting user: %s", loginID) + slog.Info("[Admin] Deleting user", "loginID", loginID) if err := h.DescopeClient.Management.User().Delete(context.Background(), loginID); err != nil { - log.Printf("[Admin] DeleteUser failed: %v", err) + slog.Error("[Admin] DeleteUser failed", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } @@ -140,7 +140,7 @@ func (h *AdminHandler) UpdateUserStatus(c *fiber.Ctx) error { var user *descope.UserResponse var err error - log.Printf("[Admin] Updating status for %s to %s", loginID, req.Status) + slog.Info("[Admin] Updating status", "loginID", loginID, "status", req.Status) if req.Status == "enabled" || req.Status == "active" { user, err = h.DescopeClient.Management.User().Activate(context.Background(), loginID) @@ -149,7 +149,7 @@ func (h *AdminHandler) UpdateUserStatus(c *fiber.Ctx) error { } if err != nil { - log.Printf("[Admin] Status update failed: %v", err) + slog.Error("[Admin] Status update failed", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } @@ -266,11 +266,11 @@ func (h *AdminHandler) CreateUser(c *fiber.Ctx) error { userObj.Tenants = userTenants } - log.Printf("[Admin] Creating user: %s (Email: %s, Phone: %s)", req.LoginID, req.Email, normalizedPhone) + slog.Info("[Admin] Creating user", "loginID", req.LoginID, "email", req.Email, "phone", normalizedPhone) res, err := h.DescopeClient.Management.User().Create(context.Background(), req.LoginID, userObj) if err != nil { - log.Printf("[Admin] Failed to create user: %v", err) + slog.Error("[Admin] Failed to create user", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } diff --git a/backend/internal/handler/auth_handler.go b/backend/internal/handler/auth_handler.go index df498cb9..55eabd09 100644 --- a/backend/internal/handler/auth_handler.go +++ b/backend/internal/handler/auth_handler.go @@ -8,7 +8,7 @@ import ( "encoding/hex" "encoding/json" "fmt" - "log" + "log/slog" "math/rand" "os" "strings" @@ -55,35 +55,34 @@ func NewAuthHandler(redisService *service.RedisService) *AuthHandler { var descopeClient *client.DescopeClient var err error - if projectID != "" { - descopeClient, err = client.NewWithConfig(&client.Config{ - ProjectID: projectID, - ManagementKey: managementKey, - }) - if err != nil { - log.Printf("Warning: Failed to initialize Descope Client: %v", err) + if projectID != "" { + descopeClient, err = client.NewWithConfig(&client.Config{ + ProjectID: projectID, + ManagementKey: managementKey, + }) + if err != nil { + slog.Warn("Failed to initialize Descope Client", "error", err) + } + } + + return &AuthHandler{ + ProjectID: projectID, + SmsService: service.NewSmsService(), + EmailService: service.NewEmailService(), + RedisService: redisService, + DescopeClient: descopeClient, } } - - return &AuthHandler{ - ProjectID: projectID, - SmsService: service.NewSmsService(), - EmailService: service.NewEmailService(), - RedisService: redisService, - DescopeClient: descopeClient, - } -} - -// SendSms sends a verification code via SMS. (Restored for completeness) -func (h *AuthHandler) SendSms(c *fiber.Ctx) error { - var req domain.SmsRequest - if err := c.BodyParser(&req); err != nil { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) - } - - log.Printf("[SMS] Sending code to: %s", req.PhoneNumber) - sanitizedPhone := strings.ReplaceAll(req.PhoneNumber, "-", "") - + + // SendSms sends a verification code via SMS. (Restored for completeness) + func (h *AuthHandler) SendSms(c *fiber.Ctx) error { + var req domain.SmsRequest + if err := c.BodyParser(&req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) + } + + slog.Info("[SMS] Sending code", "phoneNumber", req.PhoneNumber) + sanitizedPhone := strings.ReplaceAll(req.PhoneNumber, "-", "") rand.Seed(time.Now().UnixNano()) code := fmt.Sprintf("%06d", rand.Intn(1000000)) content := fmt.Sprintf("[Baron SSO] ์ธ์ฆ๋ฒˆํ˜ธ: %s", code) @@ -124,7 +123,7 @@ func (h *AuthHandler) VerifySms(c *fiber.Ctx) error { func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error { var req domain.EnchantedLinkInitRequest if err := c.BodyParser(&req); err != nil { - log.Printf("[Enchanted] Body parse error: %v", err) + slog.Error("[Enchanted] Body parse error", "error", err) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) } @@ -135,7 +134,7 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error { token := GenerateSecureToken(3) pendingRef := GenerateSecureToken(3) - log.Printf("[Enchanted] Initiating for %s. Token: %s, PendingRef: %s", loginID, token, pendingRef) + slog.Info("[Enchanted] Initiating enchanted link", "loginID", loginID, "token", token, "pendingRef", pendingRef) // Store in Redis h.RedisService.Set(prefixSession+pendingRef, fmt.Sprintf(`{"status":"%s"}`, statusPending), defaultExpiration) @@ -152,7 +151,7 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error { if strings.Contains(loginID, "@") { // Send Email if h.EmailService == nil { - log.Printf("[Enchanted] Email Service not configured") + slog.Error("[Enchanted] Email Service not configured") return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Email service not configured"}) } @@ -169,18 +168,18 @@ func (h *AuthHandler) InitEnchantedLink(c *fiber.Ctx) error { `, link) - log.Printf("[Enchanted] Sending Email to %s via AWS SES", loginID) + slog.Info("[Enchanted] Sending Email via AWS SES", "loginID", loginID) if err := h.EmailService.SendEmail(loginID, subject, body); err != nil { - log.Printf("[Enchanted] Email Failed: %v", err) + slog.Error("[Enchanted] Email Failed", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to send Email"}) } } else { // Send SMS content := fmt.Sprintf("[Baron SSO] ๋กœ๊ทธ์ธ ๋งํฌ: %s", link) - log.Printf("[Enchanted] Sending SMS to %s via Naver Cloud", loginID) + slog.Info("[Enchanted] Sending SMS via Naver Cloud", "loginID", loginID) if err := h.SmsService.SendSms(loginID, content); err != nil { - log.Printf("[Enchanted] SMS Failed: %v", err) + slog.Error("[Enchanted] SMS Failed", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to send SMS"}) } } @@ -208,7 +207,7 @@ func (h *AuthHandler) PollEnchantedLink(c *fiber.Ctx) error { json.Unmarshal([]byte(val), &data) if data["status"] == statusSuccess { - log.Printf("[Poll] Success for ref: %s", req.PendingRef) + slog.Info("[Poll] Success", "pendingRef", req.PendingRef) return c.JSON(fiber.Map{ "sessionJwt": data["jwt"], "status": "ok", @@ -222,16 +221,16 @@ func (h *AuthHandler) PollEnchantedLink(c *fiber.Ctx) error { func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { var req domain.MagicLinkVerifyRequest if err := c.BodyParser(&req); err != nil { - log.Printf("[Verify] Body parse error: %v", err) + slog.Error("[Verify] Body parse error", "error", err) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) } - log.Printf("[Verify] Attempting to verify token: %s", req.Token) + slog.Info("[Verify] Attempting to verify token", "token", req.Token) tokenKey := prefixToken + req.Token val, err := h.RedisService.Get(tokenKey) if err != nil || val == "" { - log.Printf("[Verify] Token not found or expired in Redis: %s", req.Token) + slog.Warn("[Verify] Token not found or expired in Redis", "token", req.Token) return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid or expired token"}) } @@ -240,11 +239,11 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { pendingRef := tokenData["pendingRef"] loginID := tokenData["loginId"] - log.Printf("[Verify] Token valid. LoginID: %s, PendingRef: %s", loginID, pendingRef) + slog.Info("[Verify] Token valid", "loginID", loginID, "pendingRef", pendingRef) // 1. Generate Descope Session Directly (Management SDK) if h.DescopeClient == nil { - log.Printf("[Verify] Descope Client is nil!") + slog.Error("[Verify] Descope Client is nil!") return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Descope Client not configured"}) } @@ -260,7 +259,7 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { } } - log.Printf("[Verify] Searching for user with phone: %s", searchPhone) + slog.Info("[Verify] Searching for user", "phone", searchPhone) searchOptions := &descope.UserSearchOptions{ Phones: []string{searchPhone}, Limit: 1, @@ -272,24 +271,24 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { if errSearch == nil && len(users) > 0 { if len(users[0].LoginIDs) > 0 { targetLoginID = users[0].LoginIDs[0] - log.Printf("[Verify] User found! Existing LoginID: %s", targetLoginID) + slog.Info("[Verify] User found", "existingLoginID", targetLoginID) } else { // Should not happen for a valid user, but fallback to UserID or searchPhone - log.Printf("[Verify] User found but no LoginIDs. Using UserID.") + slog.Warn("[Verify] User found but no LoginIDs, using UserID") targetLoginID = users[0].UserID } } else { // Not found, or search error. Fallback to using the phone as LoginID. // Use the normalized phone number to ensure consistency (+82...) targetLoginID = searchPhone - log.Printf("[Verify] User not found by phone. Will use/create: %s", targetLoginID) + slog.Info("[Verify] User not found by phone, will use/create", "loginID", targetLoginID) } - log.Printf("[Verify] Generating embedded link for %s", targetLoginID) + slog.Info("[Verify] Generating embedded link", "loginID", targetLoginID) embeddedToken, err := h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), targetLoginID, nil, 0) if err != nil { if strings.Contains(err.Error(), "User not found") || strings.Contains(err.Error(), "E062108") { - log.Printf("[Verify] User %s not found. Creating...", targetLoginID) + slog.Info("[Verify] User not found, creating...", "loginID", targetLoginID) // Create User with Explicit Phone Attribute userObj := &descope.UserRequest{} @@ -301,30 +300,30 @@ func (h *AuthHandler) VerifyMagicLink(c *fiber.Ctx) error { _, errCreate := h.DescopeClient.Management.User().Create(context.Background(), targetLoginID, userObj) if errCreate != nil { - log.Printf("[Verify] Failed to create user: %v", errCreate) + slog.Error("[Verify] Failed to create user", "error", errCreate) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to create new user"}) } embeddedToken, err = h.DescopeClient.Management.User().GenerateEmbeddedLink(context.Background(), targetLoginID, nil, 0) if err != nil { - log.Printf("[Verify] Failed to generate token after creation: %v", err) + slog.Error("[Verify] Failed to generate token after creation", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to generate upstream token"}) } } else { - log.Printf("[Verify] Descope Error: %v", err) + slog.Error("[Verify] Descope Error", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to generate upstream token"}) } } - log.Printf("[Verify] Exchanging embedded token for session JWT") + slog.Info("[Verify] Exchanging embedded token for session JWT") authInfo, err := h.DescopeClient.Auth.MagicLink().Verify(context.Background(), embeddedToken, nil) if err != nil { - log.Printf("[Verify] Final verification failed: %v", err) + slog.Error("[Verify] Final verification failed", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to verify upstream token"}) } sessionToken := authInfo.SessionToken.JWT - log.Printf("[Verify] Success! Updating Redis session: %s", pendingRef) + slog.Info("[Verify] Success! Updating Redis session", "pendingRef", pendingRef) sessionData, _ := json.Marshal(map[string]string{ "status": statusSuccess, "jwt": sessionToken, @@ -348,7 +347,7 @@ func (h *AuthHandler) InitQRLogin(c *fiber.Ctx) error { } qrPayload := fmt.Sprintf("%s/approve?ref=%s", frontendURL, pendingRef) - log.Printf("[QR] Init: PendingRef=%s, URL=%s", pendingRef, qrPayload) + slog.Info("[QR] Init", "pendingRef", pendingRef, "url", qrPayload) // Redis์— ์ดˆ๊ธฐ ์ƒํƒœ ์ €์žฅ (5๋ถ„ ๋งŒ๋ฃŒ) h.RedisService.Set(prefixSession+pendingRef, fmt.Sprintf(`{"status":"%s"}`, statusPending), 5*time.Minute) @@ -378,6 +377,7 @@ func (h *AuthHandler) PollQRLogin(c *fiber.Ctx) error { json.Unmarshal([]byte(val), &data) if data["status"] == statusSuccess { + slog.Info("[QR] Poll Success", "pendingRef", req.PendingRef) return c.JSON(fiber.Map{ "status": "ok", "sessionJwt": data["jwt"], @@ -395,10 +395,11 @@ func (h *AuthHandler) ScanQRLogin(c *fiber.Ctx) error { Token string `json:"token"` // ๋ชจ๋ฐ”์ผ ์‚ฌ์šฉ์ž์˜ ์„ธ์…˜ ํ† ํฐ (๊ฒ€์ฆ์šฉ) } if err := c.BodyParser(&req); err != nil { + slog.Error("[QR] Scan body parse error", "error", err) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid body"}) } - log.Printf("[QR] Scan & Approve: PendingRef=%s", req.PendingRef) + slog.Info("[QR] Scan & Approve", "pendingRef", req.PendingRef) // 1. Redis์—์„œ ์„ธ์…˜ ํ™•์ธ val, err := h.RedisService.Get(prefixSession + req.PendingRef) @@ -430,16 +431,16 @@ func (h *AuthHandler) HandleDescopeSmsRelay(c *fiber.Ctx) error { } if err := c.BodyParser(&req); err != nil { - log.Printf("[Webhook] Body parsing failed: %v", err) + slog.Error("Webhook Body parsing failed", "error", err) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) } if req.Recipient == "" || req.Body == "" { - log.Printf("[Webhook] Missing recipient or body") + slog.Warn("Webhook missing recipient or body") return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Missing recipient or body"}) } - log.Printf("[Webhook] Received SMS request for %s", req.Recipient) + slog.Info("Received SMS request", "recipient", req.Recipient) phone := req.Recipient if strings.HasPrefix(phone, "+82") { @@ -449,11 +450,11 @@ func (h *AuthHandler) HandleDescopeSmsRelay(c *fiber.Ctx) error { phone = strings.ReplaceAll(phone, " ", "") if err := h.SmsService.SendSms(phone, req.Body); err != nil { - log.Printf("[Webhook] Failed to forward SMS to Naver: %v", err) + slog.Error("Failed to forward SMS to Naver", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to send SMS via Naver"}) } - log.Printf("[Webhook] Successfully forwarded SMS to %s", phone) + slog.Info("Successfully forwarded SMS", "phone", phone) return c.JSON(fiber.Map{"status": "ok"}) } @@ -467,11 +468,11 @@ func (h *AuthHandler) HandleDescopeEmailRelay(c *fiber.Ctx) error { } if err := c.BodyParser(&req); err != nil { - log.Printf("[Email Webhook] Body parsing failed: %v", err) + slog.Error("[Email Webhook] Body parsing failed", "error", err) return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"}) } - log.Printf("[Email Webhook] Received email request for %s", req.To) + slog.Info("[Email Webhook] Received email request", "to", req.To) // Check if it's a Fake Email for SMS if strings.HasSuffix(req.To, "@sms.baron") { @@ -484,16 +485,16 @@ func (h *AuthHandler) HandleDescopeEmailRelay(c *fiber.Ctx) error { // Send SMS with the text body (Descope template should be optimized for SMS) if err := h.SmsService.SendSms(phone, req.Text); err != nil { - log.Printf("[Email Webhook] Failed to forward Email-as-SMS: %v", err) + slog.Error("[Email Webhook] Failed to forward Email-as-SMS", "error", err) return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to send SMS"}) } - log.Printf("[Email Webhook] Successfully converted Email to SMS for %s", phone) + slog.Info("[Email Webhook] Successfully converted Email to SMS", "phone", phone) return c.JSON(fiber.Map{"status": "ok"}) } // Real Email Handling (Not implemented in this Relay) // You would need an SMTP service here if you route ALL emails through this relay. - log.Printf("[Email Webhook] Real email skipped (Not implemented): %s", req.To) + slog.Warn("[Email Webhook] Real email skipped (Not implemented)", "to", req.To) return c.Status(501).JSON(fiber.Map{"error": "Real email sending not implemented"}) } diff --git a/backend/internal/service/ses_service.go b/backend/internal/service/ses_service.go index 5eb11660..f38b37f2 100644 --- a/backend/internal/service/ses_service.go +++ b/backend/internal/service/ses_service.go @@ -3,7 +3,7 @@ package service import ( "context" "fmt" - "log" + "log/slog" "os" "baron-sso-backend/internal/domain" @@ -26,16 +26,15 @@ func NewEmailService() domain.EmailService { sender := os.Getenv("AWS_SES_SENDER") if region == "" || accessKey == "" || secretKey == "" { - log.Println("[EmailService] AWS configuration missing, email service will not work") + slog.Warn("[EmailService] AWS configuration missing, email service will not work") return nil } - cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithRegion(region), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(accessKey, secretKey, "")), ) if err != nil { - log.Printf("[EmailService] Failed to load AWS config: %v", err) + slog.Error("Failed to load AWS config", "error", err) return nil } @@ -71,9 +70,9 @@ func (s *SesServiceImpl) SendEmail(to, subject, body string) error { _, err := s.client.SendEmail(context.TODO(), input) if err != nil { - log.Printf("[EmailService] Failed to send email to %s: %v", to, err) + slog.Error("[EmailService] Failed to send email", "to", to, "error", err) } else { - log.Printf("[EmailService] Email sent successfully to %s", to) + slog.Info("[EmailService] Email sent successfully", "to", to) } return err } diff --git a/backend/internal/service/sms_service.go b/backend/internal/service/sms_service.go index 1c57c664..8ebc6059 100644 --- a/backend/internal/service/sms_service.go +++ b/backend/internal/service/sms_service.go @@ -8,7 +8,7 @@ import ( "encoding/json" "fmt" "io/ioutil" - "log" + "log/slog" "net/http" "os" "strconv" @@ -17,6 +17,7 @@ import ( "baron-sso-backend/internal/domain" ) + type SmsServiceImpl struct { accessKey string secretKey string @@ -28,7 +29,7 @@ func NewSmsService() domain.SmsService { // Sanitize sender phone number right after reading from env rawSenderPhone := os.Getenv("NAVER_SENDER_PHONE_NUMBER") sanitizedSenderPhone := strings.ReplaceAll(rawSenderPhone, "-", "") - log.Printf("[์„œ๋น„์Šค ์ดˆ๊ธฐํ™”] ๋ฐœ์‹ ์ž ๋ฒˆํ˜ธ ์ฒ˜๋ฆฌ: ์›๋ณธ='%s', ์ •์ œ ํ›„='%s'", rawSenderPhone, sanitizedSenderPhone) + slog.Info("[์„œ๋น„์Šค ์ดˆ๊ธฐํ™”] ๋ฐœ์‹ ์ž ๋ฒˆํ˜ธ ์ฒ˜๋ฆฌ", "์›๋ณธ", rawSenderPhone, "์ •์ œํ›„", sanitizedSenderPhone) return &SmsServiceImpl{ accessKey: os.Getenv("NAVER_CLOUD_ACCESS_KEY"), @@ -41,7 +42,7 @@ func NewSmsService() domain.SmsService { func (s *SmsServiceImpl) SendSms(to, content string) error { timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10) apiURL := fmt.Sprintf("https://sens.apigw.ntruss.com/sms/v2/services/%s/messages", s.serviceID) - log.Printf("Requesting SENS API URL: %s", apiURL) + slog.Info("[SmsService] Requesting SENS API URL", "url", apiURL) // Naver SENS API requires phone number without '+' sanitizedTo := strings.Replace(to, "+", "", 1) @@ -92,11 +93,11 @@ func (s *SmsServiceImpl) SendSms(to, content string) error { } if resp.StatusCode >= 300 { - log.Printf("error response from naver cloud sms api: %s", string(respBody)) + slog.Error("[SmsService] error response from naver cloud sms api", "body", string(respBody)) return fmt.Errorf("error sending sms: status code %d", resp.StatusCode) } - log.Printf("sms sent successfully: %s", string(respBody)) + slog.Info("[SmsService] sms sent successfully", "body", string(respBody)) return nil } @@ -112,4 +113,4 @@ func (s *SmsServiceImpl) makeSignature(method, url, timestamp string) (string, e } return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil -} +} \ No newline at end of file