Impl magic login logic && checkin logic

Signed-off-by: Asai Neko <sugar@sne.moe>
This commit is contained in:
2025-12-25 00:37:02 +08:00
parent cd2bcd597c
commit bd726f80ea
10 changed files with 54 additions and 15 deletions

View File

@@ -13,7 +13,8 @@ email:
resend_api_key: abc resend_api_key: abc
from: from:
secrets: secrets:
jwt: something jwt_secret: something
turnstile: something turnstile_secret: something
ttl: ttl:
magic_link: 15000 magic_link_ttl: 15000
jwt_ttl: 86400000

View File

@@ -29,10 +29,11 @@ type email struct {
} }
type secrets struct { type secrets struct {
jwt string `yaml:"jwt"` jwt_secret string `yaml:"jwt_secret"`
turnstile string `yaml:"turnstile"` turnstile_secret string `yaml:"turnstile_secret"`
} }
type ttl struct { type ttl struct {
magic_token string `yaml:"magin_token"` magic_link_ttl string `yaml:"magic_link_ttl"`
jwt_ttl string `yaml:"jwt_ttl"`
} }

View File

@@ -28,8 +28,8 @@ func (self *User) GetByUserId(userId string) error {
return nil return nil
} }
func (self *User) SetCheckinState(email string, state bool) error { func (self *User) SetCheckinState(userId uuid.UUID, state bool) error {
if err := Database.Where("email = ?", email).First(&self).Error; err != nil { if err := Database.Where("user_id = ?", userId).First(&self).Error; err != nil {
return err return err
} }
self.Checkin = state self.Checkin = state

View File

@@ -17,7 +17,7 @@ type Claims struct {
} }
func JWTAuth() gin.HandlerFunc { func JWTAuth() gin.HandlerFunc {
var JwtSecret = []byte(viper.GetString("secrets.jwt")) var JwtSecret = []byte(viper.GetString("secrets.jwt_secret"))
return func(c *gin.Context) { return func(c *gin.Context) {
auth := c.GetHeader("Authorization") auth := c.GetHeader("Authorization")
if auth == "" { if auth == "" {
@@ -66,7 +66,7 @@ func GenerateToken(userID uuid.UUID, application string) (string, error) {
claims := Claims{ claims := Claims{
UserID: userID, UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(viper.GetDuration("ttl.jwt_ttl"))),
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: application, Issuer: application,
}, },

View File

@@ -5,6 +5,8 @@ import (
"encoding/base64" "encoding/base64"
"sync" "sync"
"time" "time"
"github.com/spf13/viper"
) )
type Token struct { type Token struct {
@@ -17,7 +19,7 @@ var (
) )
// Generate magic token // Generate magic token
func NewMagicToken(email string, ttl time.Duration) (string, error) { func NewMagicToken(email string) (string, error) {
b := make([]byte, 32) b := make([]byte, 32)
if _, err := rand.Read(b); err != nil { if _, err := rand.Read(b); err != nil {
return "", err return "", err
@@ -27,7 +29,7 @@ func NewMagicToken(email string, ttl time.Duration) (string, error) {
store.Store(token, Token{ store.Store(token, Token{
Email: email, Email: email,
ExpiresAt: time.Now().Add(ttl), ExpiresAt: time.Now().Add(viper.GetDuration("ttl.magic_link_ttl")),
}) })
return token, nil return token, nil

View File

@@ -10,7 +10,7 @@ import (
func VerifyTurnstile(token, ip string) (bool, error) { func VerifyTurnstile(token, ip string) (bool, error) {
form := url.Values{} form := url.Values{}
form.Set("secret", viper.GetString("secrets.turnstile")) form.Set("secret", viper.GetString("secrets.turnstile_secret"))
form.Set("response", token) form.Set("response", token)
form.Set("remoteip", ip) form.Set("remoteip", ip)

View File

@@ -5,7 +5,6 @@ import (
"nixcn-cms/internal/crypto/jwt" "nixcn-cms/internal/crypto/jwt"
"nixcn-cms/pkgs/magiclink" "nixcn-cms/pkgs/magiclink"
"nixcn-cms/pkgs/turnstile" "nixcn-cms/pkgs/turnstile"
"time"
"github.com/google/uuid" "github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -35,7 +34,7 @@ func RequestMagicLink(c *gin.Context) {
} }
// Generate magic token // Generate magic token
token, err := magiclink.NewMagicToken(req.Email, 15*time.Minute) token, err := magiclink.NewMagicToken(req.Email)
if err != nil { if err != nil {
c.JSON(500, gin.H{"error": "internal error"}) c.JSON(500, gin.H{"error": "internal error"})
return return

View File

@@ -0,0 +1,24 @@
package checkin
import (
"net/http"
"nixcn-cms/data"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func Checkin(ctx *gin.Context) {
data := new(data.User)
userId, ok := ctx.Get("user_id")
if !ok {
ctx.JSON(http.StatusUnauthorized, gin.H{
"status": "unauthorized",
})
return
}
data.SetCheckinState(userId.(uuid.UUID), true)
ctx.JSON(http.StatusOK, gin.H{
"status": "success",
})
}

11
service/info/handler.go Normal file
View File

@@ -0,0 +1,11 @@
package info
import (
"nixcn-cms/internal/crypto/jwt"
"github.com/gin-gonic/gin"
)
func Handler(r *gin.RouterGroup) {
r.Use(jwt.JWTAuth())
}

1
service/info/userinfo.go Normal file
View File

@@ -0,0 +1 @@
package info