// Copyright 2022 E99p1ant. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package auth import ( "github.com/flamego/recaptcha" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/tamakyi/TamaBox/internal/captcha" "github.com/tamakyi/TamaBox/internal/context" "github.com/tamakyi/TamaBox/internal/db" "github.com/tamakyi/TamaBox/internal/form" "github.com/tamakyi/TamaBox/internal/i18n" "github.com/tamakyi/TamaBox/internal/shared" ) func Login(ctx context.Context) { ctx.Success("auth/login") } func LoginAction(ctx context.Context, f form.Login, recaptcha recaptcha.RecaptchaV3) { if ctx.HasError() { ctx.Success("auth/login") return } // Check captcha code (unified: recaptcha, turnstile, or math). uri := ctx.Request().Request.RequestURI // Keep the query when redirecting. ok, err := captcha.Verify(f.Recaptcha, shared.ResolveClientIP(ctx.Request().Request), ctx.Session, recaptcha, ctx.Lang()) if err != nil { logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to check captcha") ctx.SetErrorFlash(err.Error()) ctx.Redirect(uri) return } if !ok { ctx.SetErrorFlash(i18n.T(ctx.Lang(), "captcha.error")) ctx.Redirect(uri) return } user, err := db.Users.Authenticate(ctx.Request().Context(), f.Email, f.Password) if err != nil { if errors.Is(err, db.ErrBadCredential) { ctx.SetErrorFlash(i18n.T(ctx.Lang(), "auth.errBadCredential")) } else { logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to authenticate user") ctx.SetInternalErrorFlash() } ctx.Redirect(uri) return } to := shared.SafeRedirectTarget(ctx.Query("to")) if to == "" { to = "/_/" + user.Domain } // 会话固定防护:登录认证成功后、写入用户标识之前,重新生成会话 ID, // 使登录前种下的匿名会话失效,防止攻击者借固定会话 ID 劫持已认证会话。 if err := ctx.Session.RegenerateID(ctx.ResponseWriter(), ctx.Request().Request); err != nil { logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to regenerate session ID on login") ctx.SetInternalErrorFlash() ctx.Redirect(uri) return } ctx.Session.Set("uid", user.ID) ctx.Session.Set("pwd_ver", user.PasswordVersion) ctx.Redirect(to) }