| package handler |
|
|
| import ( |
| "github.com/gin-gonic/gin" |
|
|
| "github.com/Wei-Shaw/sub2api/internal/pkg/response" |
| middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" |
| "github.com/Wei-Shaw/sub2api/internal/service" |
| ) |
|
|
| |
| type TotpHandler struct { |
| totpService *service.TotpService |
| } |
|
|
| |
| func NewTotpHandler(totpService *service.TotpService) *TotpHandler { |
| return &TotpHandler{ |
| totpService: totpService, |
| } |
| } |
|
|
| |
| type TotpStatusResponse struct { |
| Enabled bool `json:"enabled"` |
| EnabledAt *int64 `json:"enabled_at,omitempty"` |
| FeatureEnabled bool `json:"feature_enabled"` |
| } |
|
|
| |
| |
| func (h *TotpHandler) GetStatus(c *gin.Context) { |
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not authenticated") |
| return |
| } |
|
|
| status, err := h.totpService.GetStatus(c.Request.Context(), subject.UserID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| resp := TotpStatusResponse{ |
| Enabled: status.Enabled, |
| FeatureEnabled: status.FeatureEnabled, |
| } |
|
|
| if status.EnabledAt != nil { |
| ts := status.EnabledAt.Unix() |
| resp.EnabledAt = &ts |
| } |
|
|
| response.Success(c, resp) |
| } |
|
|
| |
| type TotpSetupRequest struct { |
| EmailCode string `json:"email_code"` |
| Password string `json:"password"` |
| } |
|
|
| |
| type TotpSetupResponse struct { |
| Secret string `json:"secret"` |
| QRCodeURL string `json:"qr_code_url"` |
| SetupToken string `json:"setup_token"` |
| Countdown int `json:"countdown"` |
| } |
|
|
| |
| |
| func (h *TotpHandler) InitiateSetup(c *gin.Context) { |
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not authenticated") |
| return |
| } |
|
|
| var req TotpSetupRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| |
| req = TotpSetupRequest{} |
| } |
|
|
| result, err := h.totpService.InitiateSetup(c.Request.Context(), subject.UserID, req.EmailCode, req.Password) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, TotpSetupResponse{ |
| Secret: result.Secret, |
| QRCodeURL: result.QRCodeURL, |
| SetupToken: result.SetupToken, |
| Countdown: result.Countdown, |
| }) |
| } |
|
|
| |
| type TotpEnableRequest struct { |
| TotpCode string `json:"totp_code" binding:"required,len=6"` |
| SetupToken string `json:"setup_token" binding:"required"` |
| } |
|
|
| |
| |
| func (h *TotpHandler) Enable(c *gin.Context) { |
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not authenticated") |
| return |
| } |
|
|
| var req TotpEnableRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| if err := h.totpService.CompleteSetup(c.Request.Context(), subject.UserID, req.TotpCode, req.SetupToken); err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, gin.H{"success": true}) |
| } |
|
|
| |
| type TotpDisableRequest struct { |
| EmailCode string `json:"email_code"` |
| Password string `json:"password"` |
| } |
|
|
| |
| |
| func (h *TotpHandler) Disable(c *gin.Context) { |
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not authenticated") |
| return |
| } |
|
|
| var req TotpDisableRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| if err := h.totpService.Disable(c.Request.Context(), subject.UserID, req.EmailCode, req.Password); err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, gin.H{"success": true}) |
| } |
|
|
| |
| |
| func (h *TotpHandler) GetVerificationMethod(c *gin.Context) { |
| method := h.totpService.GetVerificationMethod(c.Request.Context()) |
| response.Success(c, method) |
| } |
|
|
| |
| |
| func (h *TotpHandler) SendVerifyCode(c *gin.Context) { |
| subject, ok := middleware2.GetAuthSubjectFromContext(c) |
| if !ok { |
| response.Unauthorized(c, "User not authenticated") |
| return |
| } |
|
|
| if err := h.totpService.SendVerifyCode(c.Request.Context(), subject.UserID); err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, gin.H{"success": true}) |
| } |
|
|