2021-02-02 18:09:02 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"html/template"
|
|
|
|
"io/fs"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2021-02-19 16:12:14 +00:00
|
|
|
"github.com/fatih/color"
|
2021-02-02 18:09:02 +00:00
|
|
|
"github.com/gin-contrib/pprof"
|
|
|
|
"github.com/gin-contrib/static"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
swaggerFiles "github.com/swaggo/files"
|
|
|
|
ginSwagger "github.com/swaggo/gin-swagger"
|
|
|
|
)
|
|
|
|
|
|
|
|
// loads HTML templates. If [files]/html_templates is set, alternative files inside the directory are loaded in place of the internal templates.
|
|
|
|
func (app *appContext) loadHTML(router *gin.Engine) {
|
|
|
|
customPath := app.config.Section("files").Key("html_templates").MustString("")
|
|
|
|
templatePath := "html"
|
|
|
|
htmlFiles, err := fs.ReadDir(localFS, templatePath)
|
|
|
|
if err != nil {
|
|
|
|
app.err.Fatalf("Couldn't access template directory: \"%s\"", templatePath)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
loadFiles := make([]string, len(htmlFiles))
|
|
|
|
for i, f := range htmlFiles {
|
|
|
|
if _, err := os.Stat(filepath.Join(customPath, f.Name())); os.IsNotExist(err) {
|
|
|
|
app.debug.Printf("Using default \"%s\"", f.Name())
|
2021-02-08 12:03:22 +00:00
|
|
|
loadFiles[i] = FSJoin(templatePath, f.Name())
|
2021-02-02 18:09:02 +00:00
|
|
|
} else {
|
|
|
|
app.info.Printf("Using custom \"%s\"", f.Name())
|
|
|
|
loadFiles[i] = filepath.Join(filepath.Join(customPath, f.Name()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmpl, err := template.ParseFS(localFS, loadFiles...)
|
|
|
|
if err != nil {
|
|
|
|
app.err.Fatalf("Failed to load templates: %v", err)
|
|
|
|
}
|
|
|
|
router.SetHTMLTemplate(tmpl)
|
|
|
|
}
|
|
|
|
|
|
|
|
// sets gin logger.
|
|
|
|
func setGinLogger(router *gin.Engine, debugMode bool) {
|
2021-02-19 16:12:14 +00:00
|
|
|
sprintf := color.New(color.Faint).SprintfFunc()
|
2021-02-02 18:09:02 +00:00
|
|
|
if debugMode {
|
|
|
|
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
2021-02-19 16:12:14 +00:00
|
|
|
return sprintf("[GIN/DEBUG] %s: %s(%s) => %d in %s; %s\n",
|
2021-02-02 18:09:02 +00:00
|
|
|
param.TimeStamp.Format("15:04:05"),
|
|
|
|
param.Method,
|
|
|
|
param.Path,
|
|
|
|
param.StatusCode,
|
|
|
|
param.Latency,
|
|
|
|
func() string {
|
|
|
|
if param.ErrorMessage != "" {
|
|
|
|
return "Error: " + param.ErrorMessage
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}(),
|
|
|
|
)
|
|
|
|
}))
|
|
|
|
} else {
|
|
|
|
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
2021-02-19 16:12:14 +00:00
|
|
|
return sprintf("[GIN] %s(%s) => %d\n",
|
2021-02-02 18:09:02 +00:00
|
|
|
param.Method,
|
|
|
|
param.Path,
|
|
|
|
param.StatusCode,
|
|
|
|
)
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (app *appContext) loadRouter(address string, debug bool) *gin.Engine {
|
|
|
|
if debug {
|
|
|
|
gin.SetMode(gin.DebugMode)
|
|
|
|
} else {
|
|
|
|
gin.SetMode(gin.ReleaseMode)
|
|
|
|
}
|
|
|
|
router := gin.New()
|
|
|
|
|
|
|
|
setGinLogger(router, debug)
|
|
|
|
|
|
|
|
router.Use(gin.Recovery())
|
|
|
|
app.loadHTML(router)
|
|
|
|
router.Use(static.Serve("/", app.webFS))
|
|
|
|
router.NoRoute(app.NoRouteHandler)
|
2021-03-23 21:59:04 +00:00
|
|
|
if *PPROF {
|
2021-02-02 18:09:02 +00:00
|
|
|
app.debug.Println("Loading pprof")
|
|
|
|
pprof.Register(router)
|
|
|
|
}
|
|
|
|
SRV = &http.Server{
|
|
|
|
Addr: address,
|
|
|
|
Handler: router,
|
|
|
|
}
|
|
|
|
return router
|
|
|
|
}
|
|
|
|
|
|
|
|
func (app *appContext) loadRoutes(router *gin.Engine) {
|
|
|
|
routePrefixes := []string{app.URLBase}
|
|
|
|
if app.URLBase != "" {
|
|
|
|
routePrefixes = append(routePrefixes, "")
|
|
|
|
}
|
2023-06-16 13:43:37 +00:00
|
|
|
|
|
|
|
userPageEnabled := app.config.Section("user_page").Key("enabled").MustBool(true) && app.config.Section("ui").Key("jellyfin_login").MustBool(true)
|
|
|
|
|
2021-02-02 18:09:02 +00:00
|
|
|
for _, p := range routePrefixes {
|
|
|
|
router.GET(p+"/lang/:page", app.GetLanguages)
|
|
|
|
router.Use(static.Serve(p+"/", app.webFS))
|
|
|
|
router.GET(p+"/", app.AdminPage)
|
2021-03-30 21:41:28 +00:00
|
|
|
|
|
|
|
if app.config.Section("password_resets").Key("link_reset").MustBool(false) {
|
|
|
|
router.GET(p+"/reset", app.ResetPassword)
|
2021-06-07 12:46:46 +00:00
|
|
|
if app.config.Section("password_resets").Key("set_password").MustBool(false) {
|
|
|
|
router.POST(p+"/reset", app.ResetSetPassword)
|
|
|
|
}
|
2021-03-30 21:41:28 +00:00
|
|
|
}
|
|
|
|
|
2021-02-02 18:09:02 +00:00
|
|
|
router.GET(p+"/accounts", app.AdminPage)
|
|
|
|
router.GET(p+"/settings", app.AdminPage)
|
|
|
|
router.GET(p+"/lang/:page/:file", app.ServeLang)
|
|
|
|
router.GET(p+"/token/login", app.getTokenLogin)
|
|
|
|
router.GET(p+"/token/refresh", app.getTokenRefresh)
|
|
|
|
router.POST(p+"/newUser", app.NewUser)
|
|
|
|
router.Use(static.Serve(p+"/invite/", app.webFS))
|
|
|
|
router.GET(p+"/invite/:invCode", app.InviteProxy)
|
2022-01-10 01:55:48 +00:00
|
|
|
if app.config.Section("captcha").Key("enabled").MustBool(false) {
|
|
|
|
router.GET(p+"/captcha/gen/:invCode", app.GenCaptcha)
|
|
|
|
router.GET(p+"/captcha/img/:invCode/:captchaID", app.GetCaptcha)
|
|
|
|
router.POST(p+"/captcha/verify/:invCode/:captchaID/:text", app.VerifyCaptcha)
|
|
|
|
}
|
2021-05-07 20:53:29 +00:00
|
|
|
if telegramEnabled {
|
2021-05-07 17:20:35 +00:00
|
|
|
router.GET(p+"/invite/:invCode/telegram/verified/:pin", app.TelegramVerifiedInvite)
|
2021-05-07 00:08:12 +00:00
|
|
|
}
|
2021-05-21 20:35:25 +00:00
|
|
|
if discordEnabled {
|
|
|
|
router.GET(p+"/invite/:invCode/discord/verified/:pin", app.DiscordVerifiedInvite)
|
2021-05-23 18:50:03 +00:00
|
|
|
if app.config.Section("discord").Key("provide_invite").MustBool(false) {
|
|
|
|
router.GET(p+"/invite/:invCode/discord/invite", app.DiscordServerInvite)
|
|
|
|
}
|
2021-05-21 20:35:25 +00:00
|
|
|
}
|
2021-05-29 16:43:11 +00:00
|
|
|
if matrixEnabled {
|
|
|
|
router.GET(p+"/invite/:invCode/matrix/verified/:userID/:pin", app.MatrixCheckPIN)
|
|
|
|
router.POST(p+"/invite/:invCode/matrix/user", app.MatrixSendPIN)
|
2021-05-30 10:47:41 +00:00
|
|
|
router.POST(p+"/users/matrix", app.MatrixConnect)
|
2021-05-29 16:43:11 +00:00
|
|
|
}
|
2023-06-16 13:43:37 +00:00
|
|
|
if userPageEnabled {
|
|
|
|
router.GET(p+"/my/account", app.MyUserPage)
|
|
|
|
router.GET(p+"/my/token/login", app.getUserTokenLogin)
|
|
|
|
router.GET(p+"/my/token/refresh", app.getUserTokenRefresh)
|
|
|
|
}
|
2021-02-02 18:09:02 +00:00
|
|
|
}
|
|
|
|
if *SWAGGER {
|
2021-02-19 16:12:14 +00:00
|
|
|
app.info.Print(warning("\n\nWARNING: Swagger should not be used on a public instance.\n\n"))
|
2021-02-02 18:09:02 +00:00
|
|
|
for _, p := range routePrefixes {
|
|
|
|
router.GET(p+"/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
|
|
|
}
|
|
|
|
}
|
2023-06-16 13:43:37 +00:00
|
|
|
|
2021-02-02 18:09:02 +00:00
|
|
|
api := router.Group("/", app.webAuth())
|
2023-06-16 13:43:37 +00:00
|
|
|
|
|
|
|
var user *gin.RouterGroup
|
|
|
|
if userPageEnabled {
|
|
|
|
user = router.Group("/my", app.userAuth())
|
|
|
|
}
|
|
|
|
|
2021-02-02 18:09:02 +00:00
|
|
|
for _, p := range routePrefixes {
|
|
|
|
router.POST(p+"/logout", app.Logout)
|
2021-02-19 14:51:36 +00:00
|
|
|
api.DELETE(p+"/users", app.DeleteUsers)
|
2021-02-02 18:09:02 +00:00
|
|
|
api.GET(p+"/users", app.GetUsers)
|
|
|
|
api.POST(p+"/users", app.NewUserAdmin)
|
2021-02-28 17:52:24 +00:00
|
|
|
api.POST(p+"/users/extend", app.ExtendExpiry)
|
2021-04-12 20:28:36 +00:00
|
|
|
api.POST(p+"/users/enable", app.EnableDisableUsers)
|
2021-02-02 18:09:02 +00:00
|
|
|
api.POST(p+"/invites", app.GenerateInvite)
|
|
|
|
api.GET(p+"/invites", app.GetInvites)
|
|
|
|
api.DELETE(p+"/invites", app.DeleteInvite)
|
|
|
|
api.POST(p+"/invites/profile", app.SetProfile)
|
|
|
|
api.GET(p+"/profiles", app.GetProfiles)
|
|
|
|
api.POST(p+"/profiles/default", app.SetDefaultProfile)
|
|
|
|
api.POST(p+"/profiles", app.CreateProfile)
|
|
|
|
api.DELETE(p+"/profiles", app.DeleteProfile)
|
|
|
|
api.POST(p+"/invites/notify", app.SetNotify)
|
|
|
|
api.POST(p+"/users/emails", app.ModifyEmails)
|
2022-01-08 16:20:31 +00:00
|
|
|
api.POST(p+"/users/labels", app.ModifyLabels)
|
2022-01-09 19:29:17 +00:00
|
|
|
api.POST(p+"/users/accounts-admin", app.SetAccountsAdmin)
|
2021-02-02 18:09:02 +00:00
|
|
|
// api.POST(p + "/setDefaults", app.SetDefaults)
|
|
|
|
api.POST(p+"/users/settings", app.ApplySettings)
|
2021-02-18 14:58:53 +00:00
|
|
|
api.POST(p+"/users/announce", app.Announce)
|
2021-07-10 15:43:27 +00:00
|
|
|
|
|
|
|
api.GET(p+"/users/announce", app.GetAnnounceTemplates)
|
|
|
|
api.POST(p+"/users/announce/template", app.SaveAnnounceTemplate)
|
|
|
|
api.GET(p+"/users/announce/:name", app.GetAnnounceTemplate)
|
|
|
|
api.DELETE(p+"/users/announce/:name", app.DeleteAnnounceTemplate)
|
|
|
|
|
2021-10-13 14:04:22 +00:00
|
|
|
api.POST(p+"/users/password-reset", app.AdminPasswordReset)
|
|
|
|
|
2021-03-07 15:23:44 +00:00
|
|
|
api.GET(p+"/config/update", app.CheckUpdate)
|
|
|
|
api.POST(p+"/config/update", app.ApplyUpdate)
|
2021-05-02 19:41:08 +00:00
|
|
|
api.GET(p+"/config/emails", app.GetCustomEmails)
|
|
|
|
api.GET(p+"/config/emails/:id", app.GetCustomEmailTemplate)
|
|
|
|
api.POST(p+"/config/emails/:id", app.SetCustomEmail)
|
|
|
|
api.POST(p+"/config/emails/:id/state/:state", app.SetCustomEmailState)
|
2021-02-02 18:09:02 +00:00
|
|
|
api.GET(p+"/config", app.GetConfig)
|
|
|
|
api.POST(p+"/config", app.ModifyConfig)
|
|
|
|
api.POST(p+"/restart", app.restart)
|
2021-12-30 17:54:27 +00:00
|
|
|
api.GET(p+"/logs", app.GetLog)
|
2021-05-30 21:35:34 +00:00
|
|
|
if telegramEnabled || discordEnabled || matrixEnabled {
|
2021-05-07 17:20:35 +00:00
|
|
|
api.GET(p+"/telegram/pin", app.TelegramGetPin)
|
|
|
|
api.GET(p+"/telegram/verified/:pin", app.TelegramVerified)
|
|
|
|
api.POST(p+"/users/telegram", app.TelegramAddUser)
|
2023-02-05 00:23:16 +00:00
|
|
|
api.DELETE(p+"/users/telegram", app.UnlinkTelegram)
|
|
|
|
api.DELETE(p+"/users/discord", app.UnlinkDiscord)
|
|
|
|
api.DELETE(p+"/users/matrix", app.UnlinkMatrix)
|
2023-01-30 13:55:38 +00:00
|
|
|
}
|
|
|
|
if emailEnabled {
|
2021-05-21 20:35:25 +00:00
|
|
|
api.POST(p+"/users/contact", app.SetContactMethods)
|
2021-05-07 17:20:35 +00:00
|
|
|
}
|
2021-05-22 20:42:15 +00:00
|
|
|
if discordEnabled {
|
|
|
|
api.GET(p+"/users/discord/:username", app.DiscordGetUsers)
|
|
|
|
api.POST(p+"/users/discord", app.DiscordConnect)
|
|
|
|
}
|
2021-02-02 18:09:02 +00:00
|
|
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
|
|
|
api.GET(p+"/ombi/users", app.OmbiUsers)
|
2021-11-13 18:53:53 +00:00
|
|
|
api.POST(p+"/profiles/ombi/:profile", app.SetOmbiProfile)
|
|
|
|
api.DELETE(p+"/profiles/ombi/:profile", app.DeleteOmbiProfile)
|
2021-02-02 18:09:02 +00:00
|
|
|
}
|
2021-05-30 21:35:34 +00:00
|
|
|
api.POST(p+"/matrix/login", app.MatrixLogin)
|
|
|
|
|
2023-06-16 13:43:37 +00:00
|
|
|
if userPageEnabled {
|
|
|
|
user.GET(p+"/hello", app.HelloWorld)
|
|
|
|
}
|
2021-02-02 18:09:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (app *appContext) loadSetup(router *gin.Engine) {
|
|
|
|
router.GET("/lang/:page", app.GetLanguages)
|
|
|
|
router.GET("/", app.ServeSetup)
|
|
|
|
router.POST("/jellyfin/test", app.TestJF)
|
|
|
|
router.POST("/config", app.ModifyConfig)
|
|
|
|
}
|