diff --git a/go.mod b/go.mod index c87d5df..efcf2e9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module git.solsynth.dev/hypernet/passport go 1.23.2 require ( - git.solsynth.dev/hypernet/nexus v0.0.0-20250301065153-8ac88413e0e1 + git.solsynth.dev/hypernet/nexus v0.0.0-20250322115040-e670724c4c18 git.solsynth.dev/hypernet/paperclip v0.0.0-20250310151112-1d866f317f47 git.solsynth.dev/hypernet/pusher v0.0.0-20250216145944-5fb769823a88 git.solsynth.dev/hypernet/wallet v0.0.0-20250129150034-87b94cdb5488 diff --git a/go.sum b/go.sum index 2239cc5..f16e95c 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.solsynth.dev/hypernet/nexus v0.0.0-20250301065153-8ac88413e0e1 h1:Jf5yQr8Yln2YkDQ9CwJhVYNstR2vNKPViGnR2YAZLsE= git.solsynth.dev/hypernet/nexus v0.0.0-20250301065153-8ac88413e0e1/go.mod h1:AXafZRL/2DISS37ZNngY0DreFAuBoeKu8mEDmCie8kw= +git.solsynth.dev/hypernet/nexus v0.0.0-20250322115040-e670724c4c18 h1:XyP+txtTXKThCUVKlFGqz5YGCH1V7q1i/uxkg8XNprY= +git.solsynth.dev/hypernet/nexus v0.0.0-20250322115040-e670724c4c18/go.mod h1:hif4EyzOzDAfq/4qasMOQvAa/LVmG5ibRheLKYO4Vwg= git.solsynth.dev/hypernet/paperclip v0.0.0-20250310151112-1d866f317f47 h1:fvu+bNKPTNtQocssnKbEZ66MqR0iBfAxY3HwlqnmYyE= git.solsynth.dev/hypernet/paperclip v0.0.0-20250310151112-1d866f317f47/go.mod h1:jvxq2qftz2v72x+24+cTFJdQKr9eHQTdk3KVR7cx36s= git.solsynth.dev/hypernet/pusher v0.0.0-20250216145944-5fb769823a88 h1:2HEENe9KUrdaJeNBzx9lsuXQGyzWqCgnLTKQnr8xFr8= diff --git a/pkg/internal/services/check_in.go b/pkg/internal/services/check_in.go index 0ccf7c5..e0fea0e 100644 --- a/pkg/internal/services/check_in.go +++ b/pkg/internal/services/check_in.go @@ -31,16 +31,27 @@ func CheckCanCheckIn(user models.Account) error { func GetCheckInStreak(user models.Account) (int64, error) { var streaks int64 if err := database.C.Raw(`WITH dates AS ( - SELECT DISTINCT created_at::DATE AS created_date - FROM check_in_records - WHERE created_at::DATE <= CURRENT_DATE AND account_id = ? - ), - streak AS ( - SELECT created_date, - created_date - INTERVAL '1 day' * ROW_NUMBER() OVER (ORDER BY created_date) AS grp - FROM dates - ) - SELECT COUNT(*) FROM streak WHERE grp = (SELECT MIN(grp) FROM streak);`, user.ID).Scan(&streaks).Error; err != nil { + SELECT DISTINCT created_at::DATE AS created_date + FROM check_in_records + WHERE created_at::DATE <= CURRENT_DATE + AND account_id = ? +), +streak AS ( + SELECT created_date, + created_date - INTERVAL '1 day' * (ROW_NUMBER() OVER (ORDER BY created_date)) AS grp + FROM dates +), +grouped_streaks AS ( + SELECT grp, COUNT(*) AS streak_length, MAX(created_date) AS last_date + FROM streak + GROUP BY grp +), +last_streak AS ( + SELECT streak_length + FROM grouped_streaks + WHERE last_date = (SELECT MAX(created_date) FROM dates) +) +SELECT COALESCE(streak_length, 0) FROM last_streak;`, user.ID).Scan(&streaks).Error; err != nil { return streaks, err } return streaks, nil diff --git a/pkg/internal/web/api/accounts_api.go b/pkg/internal/web/api/accounts_api.go index 42e18a7..e98e057 100644 --- a/pkg/internal/web/api/accounts_api.go +++ b/pkg/internal/web/api/accounts_api.go @@ -9,6 +9,7 @@ import ( "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" "gorm.io/gorm" + "git.solsynth.dev/hypernet/passport/pkg/internal/gap" "git.solsynth.dev/hypernet/passport/pkg/internal/web/exts" "git.solsynth.dev/hypernet/passport/pkg/authkit/models" @@ -136,7 +137,7 @@ func updateUserinfo(c *fiber.Ctx) error { } else { data.Nick = strings.TrimSpace(data.Nick) } - if !services.ValidateAccountName(data.Nick, 4, 24) { + if !services.ValidateAccountName(data.Nick, 1, 24) { return fiber.NewError(fiber.StatusBadRequest, "invalid account nick, length requires 4 to 24") } @@ -205,12 +206,13 @@ func updateAccountLanguage(c *fiber.Ctx) error { func doRegister(c *fiber.Ctx) error { var data struct { - Name string `json:"name" validate:"required,lowercase,alphanum,min=4,max=16"` - Nick string `json:"nick" validate:"required"` - Email string `json:"email" validate:"required,email"` - Password string `json:"password" validate:"required,min=4,max=32"` - Language string `json:"language" validate:"required,bcp47_language_tag"` - MagicToken string `json:"magic_token"` + Name string `json:"name" validate:"required,lowercase,alphanum,min=4,max=16"` + Nick string `json:"nick" validate:"required"` + Email string `json:"email" validate:"required,email"` + Password string `json:"password" validate:"required,min=4,max=32"` + Language string `json:"language" validate:"required,bcp47_language_tag"` + CaptchaToken string `json:"captcha_token" validate:"required"` + MagicToken string `json:"magic_token"` } if err := exts.BindAndValidate(c, &data); err != nil { @@ -223,7 +225,7 @@ func doRegister(c *fiber.Ctx) error { if _, err := strconv.Atoi(data.Name); err == nil { return fiber.NewError(fiber.StatusBadRequest, "invalid account name, cannot be pure number") } - if !services.ValidateAccountName(data.Nick, 4, 24) { + if !services.ValidateAccountName(data.Nick, 1, 24) { return fiber.NewError(fiber.StatusBadRequest, "invalid account nick, length requires 4 to 24") } if viper.GetBool("use_registration_magic_token") && len(data.MagicToken) <= 0 { @@ -236,6 +238,10 @@ func doRegister(c *fiber.Ctx) error { } } + if !gap.Nx.ValidateCaptcha(data.CaptchaToken, c.IP()) { + return fiber.NewError(fiber.StatusBadRequest, "captcha check failed") + } + if user, err := services.CreateAccount( data.Name, data.Nick, diff --git a/pkg/internal/web/api/check_in_api.go b/pkg/internal/web/api/check_in_api.go index c86e3ed..685443e 100644 --- a/pkg/internal/web/api/check_in_api.go +++ b/pkg/internal/web/api/check_in_api.go @@ -3,6 +3,7 @@ package api import ( "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "git.solsynth.dev/hypernet/passport/pkg/internal/database" + "git.solsynth.dev/hypernet/passport/pkg/internal/gap" "git.solsynth.dev/hypernet/passport/pkg/internal/services" "git.solsynth.dev/hypernet/passport/pkg/internal/web/exts" "github.com/gofiber/fiber/v2" @@ -95,6 +96,17 @@ func doCheckIn(c *fiber.Ctx) error { } user := c.Locals("user").(models.Account) + var data struct { + CaptchaToken string `json:"captcha_token" validate:"required"` + } + if err := exts.BindAndValidate(c, &data); err != nil { + return err + } + + if !gap.Nx.ValidateCaptcha(data.CaptchaToken, c.IP()) { + return fiber.NewError(fiber.StatusBadRequest, "captcha check failed") + } + if record, err := services.CheckIn(user); err != nil { return fiber.NewError(fiber.StatusBadRequest, err.Error()) } else {