SSR 注册页与 /api/register 共用 CaptchaService,防刷同时保留换一张无 JS 刷新。 Co-authored-by: Cursor <cursoragent@cursor.com>
141 lines
5.2 KiB
Go
141 lines
5.2 KiB
Go
package routers
|
||
|
||
import (
|
||
"fmt"
|
||
"io/fs"
|
||
"net/http"
|
||
"os"
|
||
"path/filepath"
|
||
|
||
"git.iioio.com/freefire/jiang13-forum/config"
|
||
"git.iioio.com/freefire/jiang13-forum/modules/auth"
|
||
webpublic "git.iioio.com/freefire/jiang13-forum/public"
|
||
"git.iioio.com/freefire/jiang13-forum/routers/api"
|
||
"git.iioio.com/freefire/jiang13-forum/routers/install"
|
||
webpages "git.iioio.com/freefire/jiang13-forum/routers/web"
|
||
"git.iioio.com/freefire/jiang13-forum/services"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
func Setup(cfg *config.Config) (*gin.Engine, error) {
|
||
gin.SetMode(gin.ReleaseMode)
|
||
r := gin.New()
|
||
r.Use(gin.Recovery())
|
||
r.Use(gin.Logger())
|
||
|
||
if err := services.EnsureInstallLockFromExistingData(cfg.DataDir); err != nil {
|
||
fmt.Fprintf(os.Stderr, "警告: 安装锁检查失败: %v\n", err)
|
||
}
|
||
|
||
if sub, err := fs.Sub(webpublic.Assets, "assets"); err == nil {
|
||
ssrFiles := http.StripPrefix("/ssr-assets", http.FileServer(http.FS(sub)))
|
||
r.GET("/ssr-assets/*filepath", func(c *gin.Context) {
|
||
c.Header("Cache-Control", "public, max-age=86400")
|
||
ssrFiles.ServeHTTP(c.Writer, c.Request)
|
||
})
|
||
}
|
||
|
||
r.Use(install.Guard(cfg.DataDir))
|
||
|
||
filter := services.NewSensitiveFilter()
|
||
settingsSvc := services.NewForumSettingsService()
|
||
services.EnsureFilterWordsInSettings(settingsSvc, cfg.FilterWordsPath(), filter)
|
||
|
||
authSvc := services.NewAuthService(cfg.JWTSecret, filter, settingsSvc)
|
||
userSvc := services.NewUserService(filter, settingsSvc)
|
||
boardSvc := services.NewBoardService()
|
||
boardSvc.EnsureDefaultBoard()
|
||
postSvc := services.NewPostService(filter, settingsSvc)
|
||
commentSvc := services.NewCommentService(filter, settingsSvc)
|
||
messageSvc := services.NewMessageService(filter, settingsSvc)
|
||
reportSvc := services.NewReportService(filter, settingsSvc, messageSvc, postSvc, commentSvc)
|
||
backupSvc := services.NewBackupService(cfg.DBPath(), cfg.DataDir)
|
||
limiter := services.NewRateLimiter(settingsSvc)
|
||
captchaSvc := services.NewCaptchaService()
|
||
mailSvc := services.NewMailService(settingsSvc)
|
||
emailCodeSvc := services.NewEmailCodeService(mailSvc)
|
||
notifySvc := services.NewNotifyService(messageSvc, mailSvc, settingsSvc)
|
||
friendLinkApplySvc := services.NewFriendLinkApplyService(settingsSvc, messageSvc)
|
||
oidcSvc, err := services.NewOIDCService(cfg, settingsSvc)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// Gitea 仓库同步后置:本阶段不启动后台同步,亦不挂管理入口
|
||
giteaSvc := services.NewGiteaService(settingsSvc)
|
||
|
||
uploadStore := services.NewUploadStore(cfg.DataDir, settingsSvc)
|
||
if err := uploadStore.ReloadFromSettings(settingsSvc); err != nil {
|
||
fmt.Fprintf(os.Stderr, "警告: 对象存储初始化失败,暂用本地磁盘: %v\n", err)
|
||
_ = uploadStore.Apply(services.StorageConfig{Type: "local"})
|
||
}
|
||
go func() {
|
||
if n, err := uploadStore.SyncMediaIndex(); err != nil {
|
||
fmt.Fprintf(os.Stderr, "警告: 媒体索引同步失败: %v\n", err)
|
||
} else if n > 0 {
|
||
fmt.Fprintf(os.Stderr, "媒体索引已同步 %d 条\n", n)
|
||
}
|
||
}()
|
||
|
||
sitePageSvc := services.NewSitePageService(filter)
|
||
|
||
h := &api.Handlers{
|
||
Cfg: cfg, Store: uploadStore, Auth: authSvc, User: userSvc, Board: boardSvc,
|
||
Post: postSvc, Comment: commentSvc, Message: messageSvc, Notify: notifySvc, Report: reportSvc,
|
||
Backup: backupSvc,
|
||
Filter: filter, Limiter: limiter, Settings: settingsSvc,
|
||
Captcha: captchaSvc, Mail: mailSvc, EmailCode: emailCodeSvc,
|
||
OIDC: oidcSvc, Gitea: giteaSvc,
|
||
Points: services.NewPointsService(), Badge: services.NewBadgeService(),
|
||
SitePage: sitePageSvc,
|
||
FriendLinkApply: friendLinkApplySvc,
|
||
}
|
||
authMW := auth.NewAuthMiddleware(authSvc)
|
||
|
||
install.Register(r, install.Deps{
|
||
DataDir: cfg.DataDir, JWTSecret: cfg.JWTSecret,
|
||
Auth: authSvc, Settings: settingsSvc,
|
||
})
|
||
|
||
webpages.Register(r, webpages.Deps{
|
||
DataDir: cfg.DataDir, JWTSecret: cfg.JWTSecret,
|
||
Settings: settingsSvc, Auth: authSvc, User: userSvc,
|
||
Board: boardSvc, Post: postSvc, Comment: commentSvc,
|
||
Message: messageSvc, Filter: filter,
|
||
Limiter: limiter, EmailCode: emailCodeSvc, Store: uploadStore,
|
||
Points: services.NewPointsService(),
|
||
FriendLink: friendLinkApplySvc,
|
||
Mail: mailSvc,
|
||
SitePage: sitePageSvc,
|
||
Report: reportSvc,
|
||
Captcha: captchaSvc,
|
||
}, authMW)
|
||
|
||
r.GET("/media/thumb/*filepath", h.ServeImageThumb)
|
||
r.Static("/uploads", filepath.Join(cfg.DataDir, "uploads"))
|
||
r.GET("/health", h.APIHealth)
|
||
r.GET("/robots.txt", h.RobotsTxt)
|
||
r.GET("/sitemap.xml", h.SitemapXML)
|
||
// 机器注册辅助(与 SSR 注册共用 CaptchaService)
|
||
r.GET("/api/captcha", h.APICaptcha)
|
||
r.POST("/api/register", h.APIRegister)
|
||
|
||
// OIDC Provider(外部机器 / Gitea SSO)
|
||
r.GET("/.well-known/openid-configuration", h.OIDCDiscovery)
|
||
r.GET("/oauth/jwks", h.OIDCJWKS)
|
||
r.GET("/oauth/authorize", authMW.OptionalAuth(), h.OIDCAuthorize)
|
||
r.POST("/oauth/token", h.OIDCToken)
|
||
r.GET("/oauth/userinfo", h.OIDCUserInfo)
|
||
r.POST("/oauth/userinfo", h.OIDCUserInfo)
|
||
r.GET("/oauth/logout", h.OIDCLogout)
|
||
r.POST("/oauth/logout", h.OIDCLogout)
|
||
|
||
// 精简机器 API:健康检查已注册;保留只读探测与 OIDC,论坛 UI 不再走 /api
|
||
r.NoRoute(webpages.Deps{
|
||
DataDir: cfg.DataDir, JWTSecret: cfg.JWTSecret,
|
||
Settings: settingsSvc, Auth: authSvc,
|
||
Board: boardSvc, Post: postSvc, Comment: commentSvc,
|
||
}.NotFound)
|
||
|
||
return r, nil
|
||
}
|