2022-07-04 15:47:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-11-29 11:43:01 +00:00
|
|
|
"aunefyren/wrapperr/files"
|
2023-10-25 13:14:02 +00:00
|
|
|
"aunefyren/wrapperr/middlewares"
|
|
|
|
"aunefyren/wrapperr/models"
|
2022-11-29 11:43:01 +00:00
|
|
|
"aunefyren/wrapperr/routes"
|
|
|
|
"aunefyren/wrapperr/utilities"
|
2022-07-04 15:47:59 +00:00
|
|
|
"flag"
|
|
|
|
"fmt"
|
2023-10-24 14:36:21 +00:00
|
|
|
"io"
|
2022-07-04 15:47:59 +00:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
"github.com/gin-contrib/cors"
|
|
|
|
"github.com/gin-gonic/gin"
|
2022-07-27 11:02:54 +00:00
|
|
|
|
|
|
|
_ "time/tzdata"
|
2022-07-04 15:47:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
2022-11-29 11:43:01 +00:00
|
|
|
utilities.PrintASCII()
|
2023-10-25 13:14:02 +00:00
|
|
|
gin.SetMode(gin.ReleaseMode)
|
2022-07-04 15:47:59 +00:00
|
|
|
|
|
|
|
// Create and define file for logging
|
2023-10-24 14:36:21 +00:00
|
|
|
logFile, err := os.OpenFile("config/wrapperr.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
|
2022-07-04 15:47:59 +00:00
|
|
|
if err != nil {
|
2023-10-24 14:36:21 +00:00
|
|
|
fmt.Println("Failed to load log file. Error: " + err.Error())
|
2022-07-04 15:47:59 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2023-10-24 14:36:21 +00:00
|
|
|
// Set log file as log destination
|
|
|
|
log.SetOutput(logFile)
|
|
|
|
fmt.Println("Log file set.")
|
|
|
|
|
|
|
|
// Load config file
|
2022-11-29 11:43:01 +00:00
|
|
|
config, err := files.GetConfig()
|
2022-07-04 15:47:59 +00:00
|
|
|
if err != nil {
|
2022-12-11 16:39:53 +00:00
|
|
|
fmt.Println("Failed to load configuration file. Error: " + err.Error())
|
2022-07-04 15:47:59 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
2023-10-24 14:36:21 +00:00
|
|
|
var mw io.Writer
|
|
|
|
// Set log file is logging is enabled
|
|
|
|
if config.UseLogs {
|
|
|
|
out := os.Stdout
|
|
|
|
mw = io.MultiWriter(out, logFile)
|
|
|
|
} else {
|
|
|
|
out := os.Stdout
|
|
|
|
mw = io.MultiWriter(out)
|
|
|
|
}
|
|
|
|
// Get pipe reader and writer | writes to pipe writer come out pipe reader
|
|
|
|
_, w, _ := os.Pipe()
|
|
|
|
|
|
|
|
// Replace stdout,stderr with pipe writer | all writes to stdout, stderr will go through pipe instead (log.print, log)
|
|
|
|
os.Stdout = w
|
|
|
|
os.Stderr = w
|
|
|
|
|
|
|
|
// writes with log.Print should also write to mw
|
|
|
|
log.SetOutput(mw)
|
|
|
|
|
2022-07-04 15:47:59 +00:00
|
|
|
// Set time zone from config if it is not empty
|
|
|
|
if config.Timezone != "" {
|
|
|
|
loc, err := time.LoadLocation(config.Timezone)
|
|
|
|
if err != nil {
|
2023-02-03 16:57:05 +00:00
|
|
|
|
2023-10-24 14:36:21 +00:00
|
|
|
log.Println("Failed to set time zone from config. Error: " + err.Error())
|
|
|
|
log.Println("Removing value...")
|
2022-07-04 15:47:59 +00:00
|
|
|
|
|
|
|
config.Timezone = ""
|
2022-11-29 11:43:01 +00:00
|
|
|
err = files.SaveConfig(config)
|
2022-07-04 15:47:59 +00:00
|
|
|
if err != nil {
|
2023-10-24 14:36:21 +00:00
|
|
|
log.Println("Failed to set new time zone in the config. Error: " + err.Error())
|
|
|
|
log.Println("Exiting...")
|
2022-07-04 15:47:59 +00:00
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
time.Local = loc
|
2023-10-24 14:36:21 +00:00
|
|
|
log.Println("Timezone set to " + config.Timezone + ".")
|
2022-07-04 15:47:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-03 16:57:05 +00:00
|
|
|
// Print current version
|
2023-10-24 14:36:21 +00:00
|
|
|
log.Println("Running version " + config.WrapperrVersion + ".")
|
2022-07-04 15:47:59 +00:00
|
|
|
|
|
|
|
// Define port variable with the port from the config file as default
|
|
|
|
var port int
|
|
|
|
flag.IntVar(&port, "port", config.WrapperrPort, "The port Wrapperr is listening on.")
|
|
|
|
|
|
|
|
// Parse the flags from input
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
// Alert what port is in use
|
2023-10-24 14:36:21 +00:00
|
|
|
log.Println("Starting Wrapperr on port " + strconv.Itoa(port) + ".")
|
2022-07-04 15:47:59 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
// Initialize Router
|
|
|
|
router := initRouter(config)
|
2023-10-27 12:34:41 +00:00
|
|
|
|
|
|
|
// Get TSL
|
|
|
|
certFound := files.CheckCertFiles()
|
|
|
|
|
|
|
|
// Start server
|
|
|
|
if certFound {
|
|
|
|
log.Println("Starting using HTTPS.")
|
|
|
|
certPath, certKeyPath := files.GetCertPaths()
|
|
|
|
log.Fatal(router.RunTLS(":"+strconv.Itoa(port), certPath, certKeyPath))
|
|
|
|
} else {
|
|
|
|
log.Println("Starting using HTTP.")
|
|
|
|
log.Fatal(router.Run(":" + strconv.Itoa(port)))
|
|
|
|
}
|
2023-10-25 13:14:02 +00:00
|
|
|
}
|
2022-07-04 15:47:59 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
func initRouter(config models.WrapperrConfig) *gin.Engine {
|
2022-12-03 12:06:48 +00:00
|
|
|
var root string
|
|
|
|
if config.WrapperrRoot != "" {
|
|
|
|
root = "/" + config.WrapperrRoot
|
|
|
|
} else {
|
|
|
|
root = ""
|
|
|
|
}
|
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
router := gin.Default()
|
|
|
|
|
|
|
|
router.LoadHTMLGlob("web/*/*.html")
|
|
|
|
|
|
|
|
// API endpoint
|
|
|
|
api := router.Group(root + "/api")
|
|
|
|
{
|
|
|
|
// Requires no auth token
|
|
|
|
open := api.Group("")
|
|
|
|
{
|
|
|
|
open.POST("/get/wrapperr-version", routes.ApiGetWrapperrVersion)
|
|
|
|
open.POST("/get/admin-state", routes.ApiGetAdminState)
|
|
|
|
open.POST("/get/functions", routes.ApiGetFunctions)
|
|
|
|
open.POST("/create/admin", routes.ApiCreateAdmin)
|
|
|
|
open.POST("/get/config-state", routes.ApiWrapperrConfigured)
|
|
|
|
open.POST("/login/admin", routes.ApiLogInAdmin)
|
|
|
|
open.POST("/get/tautulli-connection", routes.ApiGetTautulliConncection)
|
|
|
|
open.POST("/get/share-link", routes.ApiGetShareLink)
|
|
|
|
open.POST("/login/plex-auth", routes.ApiLoginPlexAuth)
|
|
|
|
}
|
2022-12-09 16:38:23 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
// Can be user auth based on config
|
|
|
|
both := api.Group("")
|
|
|
|
{
|
|
|
|
both.POST("/create/share-link", routes.ApiCreateShareLink)
|
|
|
|
both.POST("/get/statistics", routes.ApiWrapperGetStatistics)
|
|
|
|
}
|
2022-12-09 16:38:23 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
// Must include an auth token (With Plex auth)
|
|
|
|
auth := api.Group("").Use(middlewares.AuthMiddleware(false))
|
|
|
|
{
|
|
|
|
auth.POST("/get/login-url", routes.ApiGetLoginURL)
|
|
|
|
auth.POST("/validate/plex-auth", routes.ApiValidatePlexAuth)
|
|
|
|
auth.POST("/get/user-share-link", routes.ApiGetUserShareLink)
|
|
|
|
auth.POST("/delete/user-share-link", routes.ApiDeleteUserShareLink)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must include an auth token (With admin)
|
|
|
|
admin := api.Group("").Use(middlewares.AuthMiddleware(true))
|
|
|
|
{
|
|
|
|
admin.POST("/validate/admin", routes.ApiValidateAdmin)
|
|
|
|
admin.POST("/get/config", routes.ApiGetConfig)
|
|
|
|
admin.POST("/set/config", routes.ApiSetConfig)
|
|
|
|
admin.POST("/update/admin", routes.ApiUpdateAdmin)
|
|
|
|
admin.POST("/get/log", routes.ApiGetLog)
|
2023-10-28 14:43:59 +00:00
|
|
|
admin.POST("/get/timezones", routes.ApiGetTimezones)
|
2023-10-29 17:03:55 +00:00
|
|
|
admin.POST("/get/cache-statistics", routes.ApiWrapperCacheStatistics)
|
|
|
|
admin.POST("/get/users", routes.ApiGetUsers)
|
|
|
|
admin.POST("/get/users/:userId", routes.ApiGetUser)
|
2023-10-30 12:30:01 +00:00
|
|
|
admin.POST("/sync/users", routes.ApiSyncTautulliUsers)
|
2023-10-25 13:14:02 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-04 15:47:59 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
router.Use(cors.New(cors.Config{
|
|
|
|
AllowOrigins: []string{"*"},
|
|
|
|
// AllowAllOrigins: true,
|
|
|
|
AllowMethods: []string{"GET", "POST"},
|
|
|
|
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "Access-Control-Allow-Origin"},
|
|
|
|
ExposeHeaders: []string{"Content-Length"},
|
|
|
|
AllowCredentials: true,
|
|
|
|
AllowOriginFunc: func(origin string) bool { return true },
|
|
|
|
MaxAge: 12 * time.Hour,
|
|
|
|
}))
|
|
|
|
|
|
|
|
// Static endpoint for different directories
|
|
|
|
router.Static(root+"/assets", "./web/assets")
|
|
|
|
router.Static(root+"/js", "./web/js")
|
|
|
|
|
|
|
|
// Static endpoint for homepage
|
|
|
|
router.GET(root+"/", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "frontpage.html", nil)
|
|
|
|
})
|
2023-10-22 12:25:41 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
// Static endpoint for admin functions
|
|
|
|
router.GET(root+"/admin", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "admin.html", nil)
|
|
|
|
})
|
2023-10-22 12:25:41 +00:00
|
|
|
|
2023-10-28 14:43:59 +00:00
|
|
|
// Static endpoint for Tautulli admin functions
|
|
|
|
router.GET(root+"/admin/tautulli", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "tautulli.html", nil)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Static endpoint for admin settings functions
|
|
|
|
router.GET(root+"/admin/settings", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "settings.html", nil)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Static endpoint for admin customization functions
|
|
|
|
router.GET(root+"/admin/customization", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "customization.html", nil)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Static endpoint for admin caching functions
|
|
|
|
router.GET(root+"/admin/caching", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "caching.html", nil)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Static endpoint for admin log functions
|
|
|
|
router.GET(root+"/admin/logs", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "logs.html", nil)
|
|
|
|
})
|
|
|
|
|
2023-10-29 17:03:55 +00:00
|
|
|
// Static endpoint for admin users functions
|
|
|
|
router.GET(root+"/admin/users", func(c *gin.Context) {
|
|
|
|
c.HTML(http.StatusOK, "users.html", nil)
|
|
|
|
})
|
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
// Static endpoint for robots.txt
|
|
|
|
router.GET(root+"/robots.txt", func(c *gin.Context) {
|
|
|
|
TXTfile, err := os.ReadFile("./web/txt/robots.txt")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("Reading robots.txt threw error trying to open the file. Error: " + err.Error())
|
|
|
|
}
|
|
|
|
c.Data(http.StatusOK, "text/plain", TXTfile)
|
|
|
|
})
|
2023-10-22 12:25:41 +00:00
|
|
|
|
2023-10-25 13:14:02 +00:00
|
|
|
return router
|
2022-07-04 15:47:59 +00:00
|
|
|
}
|