Repo .git was damaged (refs/ missing, index truncated, object store near-empty). Repaired via git init (rebuilt refs), stale index preserved as .git/index.corrupt-20260910.bak, then full worktree committed as a rollback baseline.
78 lines
2.3 KiB
Go
78 lines
2.3 KiB
Go
// 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 (
|
|
"path"
|
|
|
|
"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 := ctx.Query("to")
|
|
to = path.Clean("/" + 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)
|
|
}
|