Use cloudflare turnstile.

This commit is contained in:
2025-05-15 15:01:39 +08:00
parent 578aab36c3
commit f4e82092eb
11 changed files with 134 additions and 23 deletions

View File

@@ -190,8 +190,9 @@ func deleteFile(c fiber.Ctx) error {
}
func downloadFile(c fiber.Ctx) error {
cfToken := c.Query("cf_token")
ip := c.IP()
s, filename, err := service.DownloadFile(ip, c.Params("id"))
s, filename, err := service.DownloadFile(ip, c.Params("id"), cfToken)
if err != nil {
return err
}

View File

@@ -13,10 +13,11 @@ import (
func handleUserRegister(c fiber.Ctx) error {
username := c.FormValue("username")
password := c.FormValue("password")
cfToken := c.FormValue("cf_token")
if username == "" || password == "" {
return model.NewRequestError("Username and password are required")
}
user, err := service.CreateUser(username, password)
user, err := service.CreateUser(username, password, cfToken)
if err != nil {
return err
}

View File

@@ -29,8 +29,8 @@ type ServerConfig struct {
}
func init() {
filepath := filepath.Join(utils.GetStoragePath(), "config.json")
if _, err := os.Stat(filepath); os.IsNotExist(err) {
p := filepath.Join(utils.GetStoragePath(), "config.json")
if _, err := os.Stat(p); os.IsNotExist(err) {
config = &ServerConfig{
MaxUploadingSizeInMB: 20 * 1024, // 20GB
MaxFileSizeInMB: 8 * 1024, // 8GB
@@ -42,7 +42,7 @@ func init() {
ServerDescription: "Nysoure is a file sharing service.",
}
} else {
data, err := os.ReadFile(filepath)
data, err := os.ReadFile(p)
if err != nil {
panic(err)
}
@@ -96,3 +96,7 @@ func ServerName() string {
func ServerDescription() string {
return config.ServerDescription
}
func CloudflareTurnstileSecretKey() string {
return config.CloudflareTurnstileSecretKey
}

View File

@@ -385,7 +385,16 @@ func GetFile(fid string) (*model.FileView, error) {
return file.ToView(), nil
}
func DownloadFile(ip string, fid string) (string, string, error) {
func DownloadFile(ip, fid, cfToken string) (string, string, error) {
passed, err := verifyCfToken(cfToken)
if err != nil {
log.Error("failed to verify cf token: ", err)
return "", "", model.NewRequestError("failed to verify cf token")
}
if !passed {
log.Info("cf token verification failed")
return "", "", model.NewRequestError("cf token verification failed")
}
downloads, _ := ipDownloads.Load(ip)
if downloads == nil {
ipDownloads.Store(ip, 1)

View File

@@ -3,6 +3,7 @@ package service
import (
"errors"
"fmt"
"github.com/gofiber/fiber/v3/log"
"nysoure/server/config"
"nysoure/server/dao"
"nysoure/server/model"
@@ -18,7 +19,7 @@ const (
embedAvatarCount = 1
)
func CreateUser(username, password string) (model.UserViewWithToken, error) {
func CreateUser(username, password, cfToken string) (model.UserViewWithToken, error) {
if !config.AllowRegister() {
return model.UserViewWithToken{}, model.NewRequestError("User registration is not allowed")
}
@@ -28,6 +29,14 @@ func CreateUser(username, password string) (model.UserViewWithToken, error) {
if len(password) < 6 || len(password) > 20 {
return model.UserViewWithToken{}, model.NewRequestError("Password must be between 6 and 20 characters")
}
passed, err := verifyCfToken(cfToken)
if err != nil {
log.Error("Error verifying Cloudflare token:", err)
return model.UserViewWithToken{}, model.NewInternalServerError("Failed to verify Cloudflare token")
}
if !passed {
return model.UserViewWithToken{}, model.NewRequestError("invalid Cloudflare token")
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return model.UserViewWithToken{}, err

View File

@@ -1,6 +1,12 @@
package service
import "nysoure/server/dao"
import (
"bytes"
"encoding/json"
"net/http"
"nysoure/server/config"
"nysoure/server/dao"
)
func checkUserCanUpload(uid uint) (bool, error) {
user, err := dao.GetUserByID(uid)
@@ -17,3 +23,35 @@ func CheckUserIsAdmin(uid uint) (bool, error) {
}
return user.IsAdmin, nil
}
func verifyCfToken(cfToken string) (bool, error) {
if config.CloudflareTurnstileSecretKey() == "" {
return true, nil
}
client := &http.Client{}
data, _ := json.Marshal(map[string]string{
"secret": config.CloudflareTurnstileSecretKey(),
"response": cfToken,
})
reader := bytes.NewReader(data)
resp, err := client.Post("https://challenges.cloudflare.com/turnstile/v0/siteverify", "application/json", reader)
if err != nil {
return false, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return false, nil
}
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return false, err
}
if result["success"] == nil {
return false, nil
}
if result["success"].(bool) {
return true, nil
} else {
return false, nil
}
}