jfa-go/setup.go

232 lines
7.1 KiB
Go

package main
import (
"encoding/json"
"io/fs"
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
"github.com/hrfee/jfa-go/easyproxy"
"github.com/hrfee/mediabrowser"
)
func (app *appContext) ServeSetup(gc *gin.Context) {
lang := gc.Query("lang")
if lang == "" {
lang = "en-us"
} else if _, ok := app.storage.lang.Admin[lang]; !ok {
lang = "en-us"
}
emailLang := lang
if _, ok := app.storage.lang.Email[lang]; !ok {
emailLang = "en-us"
}
messages := map[string]map[string]string{
"ui": {
"contact_message": app.config.Section("ui").Key("contact_message").String(),
"help_message": app.config.Section("ui").Key("help_message").String(),
"success_message": app.config.Section("ui").Key("success_message").String(),
},
"messages": {
"message": app.config.Section("messages").Key("message").String(),
},
}
msg, err := json.Marshal(messages)
if err != nil {
respond(500, "Failed to fetch default values", gc)
return
}
gc.HTML(200, "setup.html", gin.H{
"cssVersion": cssVersion,
"lang": app.storage.lang.Setup[lang],
"emailLang": app.storage.lang.Email[emailLang],
"language": app.storage.lang.Setup[lang].JSON,
"messages": string(msg),
})
}
type testReq struct {
ServerType string `json:"type"`
Server string `json:"server"`
Username string `json:"username"`
Password string `json:"password"`
Proxy bool `json:"proxy"`
ProxyProtocol string `json:"proxy_protocol,omitempty"`
ProxyAddress string `json:"proxy_address,omitempty"`
ProxyUsername string `json:"proxy_user,omitempty"`
ProxyPassword string `json:"proxy_password,omitempty"`
}
func (app *appContext) TestJF(gc *gin.Context) {
var req testReq
gc.BindJSON(&req)
if !(strings.HasPrefix(req.Server, "http://") || strings.HasPrefix(req.Server, "https://")) {
req.Server = "http://" + req.Server
}
serverType := mediabrowser.JellyfinServer
if req.ServerType == "emby" {
serverType = mediabrowser.EmbyServer
}
tempjf, _ := mediabrowser.NewServer(serverType, req.Server, "jfa-go-setup", app.version, "auth", "auth", mediabrowser.NewNamedTimeoutHandler("authJF", req.Server, true), 30)
if req.Proxy {
conf := easyproxy.ProxyConfig{
Protocol: easyproxy.HTTP,
Addr: req.ProxyAddress,
User: req.ProxyUsername,
Password: req.ProxyPassword,
}
if strings.Contains(req.ProxyProtocol, "socks") {
conf.Protocol = easyproxy.SOCKS5
}
transport, err := easyproxy.NewTransport(conf)
if err != nil {
respond(400, "errorProxy", gc)
return
}
tempjf.SetTransport(transport)
}
user, status, err := tempjf.Authenticate(req.Username, req.Password)
if !(status == 200 || status == 204) || err != nil {
msg := ""
switch status {
case 0:
msg = "errorConnectionRefused"
status = 500
case 401:
msg = "errorInvalidUserPass"
case 403:
msg = "errorUserDisabled"
case 404:
msg = "error404"
}
app.info.Printf("Auth failed with code %d (%s)", status, err)
if msg != "" {
respond(status, msg, gc)
} else {
respondBool(status, false, gc)
}
return
}
if !user.Policy.IsAdministrator {
respond(403, "errorNotAdmin", gc)
return
}
gc.JSON(200, map[string]bool{"success": true})
}
// The first filesystem passed should be the localFS, to ensure the local lang files are loaded first.
func (st *Storage) loadLangSetup(filesystems ...fs.FS) error {
st.lang.Setup = map[string]setupLang{}
var english setupLang
loadedLangs := make([]map[string]bool, len(filesystems))
var load loadLangFunc
load = func(fsIndex int, fname string) error {
filesystem := filesystems[fsIndex]
index := strings.TrimSuffix(fname, filepath.Ext(fname))
lang := setupLang{}
f, err := fs.ReadFile(filesystem, FSJoin(st.lang.SetupPath, fname))
if err != nil {
return err
}
err = json.Unmarshal(f, &lang)
if err != nil {
return err
}
st.lang.Common.patchCommonStrings(&lang.Strings, index)
st.lang.Common.patchCommonNotifications(&lang.Notifications, index)
if fname != "en-us.json" {
if lang.Meta.Fallback != "" {
fallback, ok := st.lang.Setup[lang.Meta.Fallback]
err = nil
if !ok {
err = load(fsIndex, lang.Meta.Fallback+".json")
fallback = st.lang.Setup[lang.Meta.Fallback]
}
if err == nil {
loadedLangs[fsIndex][lang.Meta.Fallback+".json"] = true
patchLang(&lang.Strings, &fallback.Strings, &english.Strings)
patchLang(&lang.StartPage, &fallback.StartPage, &english.StartPage)
patchLang(&lang.Updates, &fallback.Updates, &english.Updates)
patchLang(&lang.Proxy, &fallback.Proxy, &english.Proxy)
patchLang(&lang.EndPage, &fallback.EndPage, &english.EndPage)
patchLang(&lang.Language, &fallback.Language, &english.Language)
patchLang(&lang.Login, &fallback.Login, &english.Login)
patchLang(&lang.JellyfinEmby, &fallback.JellyfinEmby, &english.JellyfinEmby)
patchLang(&lang.Email, &fallback.Email, &english.Email)
patchLang(&lang.Messages, &fallback.Messages, &english.Messages)
patchLang(&lang.Notifications, &fallback.Notifications, &english.Notifications)
patchLang(&lang.UserPage, &fallback.UserPage, &english.UserPage)
patchLang(&lang.PasswordResets, &fallback.PasswordResets, &english.PasswordResets)
patchLang(&lang.InviteEmails, &fallback.InviteEmails, &english.InviteEmails)
patchLang(&lang.PasswordValidation, &fallback.PasswordValidation, &english.PasswordValidation)
patchLang(&lang.HelpMessages, &fallback.HelpMessages, &english.HelpMessages)
}
}
if (lang.Meta.Fallback != "" && err != nil) || lang.Meta.Fallback == "" {
patchLang(&lang.Strings, &english.Strings)
patchLang(&lang.StartPage, &english.StartPage)
patchLang(&lang.Updates, &english.Updates)
patchLang(&lang.Proxy, &english.Proxy)
patchLang(&lang.EndPage, &english.EndPage)
patchLang(&lang.Language, &english.Language)
patchLang(&lang.Login, &english.Login)
patchLang(&lang.JellyfinEmby, &english.JellyfinEmby)
patchLang(&lang.Email, &english.Email)
patchLang(&lang.Messages, &english.Messages)
patchLang(&lang.Notifications, &english.Notifications)
patchLang(&lang.UserPage, &english.UserPage)
patchLang(&lang.PasswordResets, &english.PasswordResets)
patchLang(&lang.InviteEmails, &english.InviteEmails)
patchLang(&lang.PasswordValidation, &english.PasswordValidation)
patchLang(&lang.HelpMessages, &english.HelpMessages)
}
}
stringSettings, err := json.Marshal(lang)
if err != nil {
return err
}
lang.JSON = string(stringSettings)
st.lang.Setup[index] = lang
return nil
}
engFound := false
var err error
for i := range filesystems {
loadedLangs[i] = map[string]bool{}
err = load(i, "en-us.json")
if err == nil {
engFound = true
}
loadedLangs[i]["en-us.json"] = true
}
if !engFound {
return err
}
english = st.lang.Setup["en-us"]
setupLoaded := false
for i := range filesystems {
files, err := fs.ReadDir(filesystems[i], st.lang.SetupPath)
if err != nil {
return err
}
for _, f := range files {
if !loadedLangs[i][f.Name()] {
err = load(i, f.Name())
if err == nil {
setupLoaded = true
loadedLangs[i][f.Name()] = true
}
}
}
}
if !setupLoaded {
return err
}
return nil
}