package service_auth import ( "context" "net/url" "nixcn-cms/internal/authcode" "nixcn-cms/internal/email" "nixcn-cms/internal/exception" "nixcn-cms/internal/turnstile" "nixcn-cms/service/shared" "github.com/spf13/viper" ) type MagicData struct { ClientId string `json:"client_id"` RedirectUri string `json:"redirect_uri"` State string `json:"state"` Email string `json:"email"` TurnstileToken string `json:"turnstile_token"` ClientIP string `json:"client_ip"` } type MagicPayload struct { Context context.Context Data *MagicData } type MagicResponse struct { Uri string `json:"uri"` } type MagicResult struct { Common shared.CommonResult Data *MagicResponse } func (self *AuthServiceImpl) Magic(payload *MagicPayload) (result *MagicResult) { var ok bool var err error if viper.GetBool("server.debug_mode") { goto BypassCfTurnstile } ok, err = turnstile.VerifyTurnstile(payload.Data.TurnstileToken, payload.Data.ClientIP) if err != nil || !ok { exception := new(exception.Builder). SetStatus(exception.StatusUser). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicTurnstileFailed). SetError(err). Throw(payload.Context) result = &MagicResult{ Common: shared.CommonResult{ HttpCode: 403, Exception: exception, }, Data: nil, } return } BypassCfTurnstile: code, err := authcode.NewAuthCode(payload.Context, payload.Data.ClientId, payload.Data.Email) if err != nil { exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicCodeGenFailed). SetError(err). Throw(payload.Context) result = &MagicResult{ Common: shared.CommonResult{ HttpCode: 500, Exception: exception, }, Data: nil, } return } externalUrl := viper.GetString("server.external_url") url, err := url.Parse(externalUrl) if err != nil { exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicInvalidExternalUrl). SetError(err). Throw(payload.Context) result = &MagicResult{ Common: shared.CommonResult{ HttpCode: 500, Exception: exception, }, Data: nil, } return } url.Path = "/api/v1/auth/redirect" query := url.Query() query.Set("code", code) query.Set("redirect_uri", payload.Data.RedirectUri) query.Set("state", payload.Data.State) query.Set("client_id", payload.Data.ClientId) url.RawQuery = query.Encode() debugMode := viper.GetBool("server.debug_mode") if debugMode { uriData := struct { Uri string `json:"uri"` }{url.String()} exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeCommon). SetOriginal(exception.CommonSuccess). SetError(nil). Throw(payload.Context) result = &MagicResult{ Common: shared.CommonResult{ HttpCode: 200, Exception: exception, }, Data: &MagicResponse{uriData.Uri}, } return } else { emailClient, err := new(email.Client).NewSMTPClient() if err != nil { exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeSpecific). SetOriginal(exception.AuthMagicInvalidEmailConfig). SetError(err). Throw(payload.Context) result = &MagicResult{ Common: shared.CommonResult{ HttpCode: 500, Exception: exception, }, Data: nil, } return } emailClient.Send( "NixCN CMS ", payload.Data.Email, "NixCN CMS Email Verify", "

Click the link below to verify your email. This link will expire in 10 minutes.

"+url.String()+"", ) } exception := new(exception.Builder). SetStatus(exception.StatusServer). SetService(exception.ServiceAuth). SetEndpoint(exception.EndpointAuthServiceMagic). SetType(exception.TypeCommon). SetOriginal(exception.CommonSuccess). SetError(nil). Throw(payload.Context) result = &MagicResult{ Common: shared.CommonResult{ HttpCode: 200, Exception: exception, }, Data: nil, } return }