diff --git a/.gitignore b/.gitignore index 06a5ef1..0bd63e2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ matacc.txt scripts/langmover/lang scripts/langmover/lang2 scripts/langmover/out +tinyproxy.conf diff --git a/api-ombi.go b/api-ombi.go index 0113885..ca148aa 100644 --- a/api-ombi.go +++ b/api-ombi.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/gin-gonic/gin" + "github.com/hrfee/mediabrowser" ) func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, error) { @@ -29,7 +30,31 @@ func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, er return ombiUser, code, err } } - return nil, 400, fmt.Errorf("Couldn't find user") + return nil, 400, fmt.Errorf("couldn't find user") +} + +// Returns a user with the given name who has been imported from Jellyfin/Emby by Ombi +func (app *appContext) getOmbiImportedUser(name string) (map[string]interface{}, int, error) { + // Ombi User Types: 3/4 = Emby, 5 = Jellyfin + ombiUsers, code, err := app.ombi.GetUsers() + if err != nil || code != 200 { + return nil, code, err + } + for _, ombiUser := range ombiUsers { + if ombiUser["userName"].(string) == name { + uType, ok := ombiUser["userType"].(int) + if !ok { // Don't know if Ombi somehow allows duplicate usernames + continue + } + if serverType == mediabrowser.JellyfinServer && uType != 5 { // Jellyfin + continue + } else if uType != 3 && uType != 4 { // Emby + continue + } + return ombiUser, code, err + } + } + return nil, 400, fmt.Errorf("couldn't find user") } // @Summary Get a list of Ombi users. @@ -107,3 +132,18 @@ func (app *appContext) DeleteOmbiProfile(gc *gin.Context) { app.storage.SetProfileKey(profileName, profile) respondBool(204, true, gc) } + +func (app *appContext) applyOmbiProfile(user map[string]interface{}, profile map[string]interface{}) (status int, err error) { + for k, v := range profile { + switch v.(type) { + case map[string]interface{}, []interface{}: + user[k] = v + default: + if v != user[k] { + user[k] = v + } + } + } + status, err = app.ombi.ModifyUser(user) + return +} diff --git a/api-users.go b/api-users.go index f30930d..ff2a0bd 100644 --- a/api-users.go +++ b/api-users.go @@ -377,30 +377,47 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc if profile.Ombi != nil && len(profile.Ombi) != 0 { template := profile.Ombi errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, template) + accountExists := false + var ombiUser map[string]interface{} if err != nil || code != 200 { - app.info.Printf("Failed to create Ombi user (%d): %s", code, err) - app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", ")) - } else { - app.info.Println("Created Ombi user") - if discordVerified || telegramVerified { - ombiUser, status, err := app.getOmbiUser(id) + // Check if on the off chance, Ombi's user importer has already added the account. + ombiUser, status, err = app.getOmbiImportedUser(req.Username) + if status == 200 && err == nil { + app.info.Println("Found existing Ombi user, applying changes") + accountExists = true + template["password"] = req.Password + status, err = app.applyOmbiProfile(ombiUser, template) if status != 200 || err != nil { - app.err.Printf("Failed to get Ombi user (%d): %v", status, err) - } else { - dID := "" - tUser := "" - if discordVerified { - dID = discordUser.ID - } - if telegramVerified { - u, _ := app.storage.GetTelegramKey(user.ID) - tUser = u.Username - } - resp, status, err := app.ombi.SetNotificationPrefs(ombiUser, dID, tUser) - if !(status == 200 || status == 204) || err != nil { - app.err.Printf("Failed to link Telegram/Discord to Ombi (%d): %v", status, err) - app.debug.Printf("Response: %v", resp) - } + app.err.Printf("Failed to modify existing Ombi user (%d): %v\n", status, err) + } + } else { + app.info.Printf("Failed to create Ombi user (%d): %s", code, err) + app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", ")) + } + } else { + ombiUser, status, err = app.getOmbiUser(id) + if status != 200 || err != nil { + app.err.Printf("Failed to get Ombi user (%d): %v", status, err) + } else { + app.info.Println("Created Ombi user") + accountExists = true + } + } + if accountExists { + if discordVerified || telegramVerified { + dID := "" + tUser := "" + if discordVerified { + dID = discordUser.ID + } + if telegramVerified { + u, _ := app.storage.GetTelegramKey(user.ID) + tUser = u.Username + } + resp, status, err := app.ombi.SetNotificationPrefs(ombiUser, dID, tUser) + if !(status == 200 || status == 204) || err != nil { + app.err.Printf("Failed to link Telegram/Discord to Ombi (%d): %v", status, err) + app.debug.Printf("Response: %v", resp) } } } @@ -1214,17 +1231,7 @@ func (app *appContext) ApplySettings(gc *gin.Context) { // newUser["userName"] = user["userName"] // newUser["alias"] = user["alias"] // newUser["emailAddress"] = user["emailAddress"] - for k, v := range ombi { - switch v.(type) { - case map[string]interface{}, []interface{}: - user[k] = v - default: - if v != user[k] { - user[k] = v - } - } - } - status, err = app.ombi.ModifyUser(user) + status, err = app.applyOmbiProfile(user, ombi) if status != 200 || err != nil { errorString += fmt.Sprintf("Apply %d: %v ", status, err) } diff --git a/api.go b/api.go index 53344eb..d9d44e4 100644 --- a/api.go +++ b/api.go @@ -182,7 +182,7 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) { } if app.config.Section("ombi").Key("enabled").MustBool(false) { // Silently fail for changing ombi passwords - if status != 200 || err != nil { + if (status != 200 && status != 204) || err != nil { app.err.Printf("Failed to get user \"%s\" from jellyfin/emby (%d): %v", username, status, err) respondBool(200, true, gc) return diff --git a/config.go b/config.go index 7053c12..c92bd63 100644 --- a/config.go +++ b/config.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + "github.com/hrfee/jfa-go/easyproxy" "gopkg.in/ini.v1" ) @@ -135,6 +136,22 @@ func (app *appContext) loadConfig() error { messagesEnabled = false } + if app.proxyEnabled = app.config.Section("advanced").Key("proxy").MustBool(false); app.proxyEnabled { + app.proxyConfig = easyproxy.ProxyConfig{} + app.proxyConfig.Protocol = easyproxy.HTTP + if strings.Contains(app.config.Section("advanced").Key("proxy_protocol").MustString("http"), "socks") { + app.proxyConfig.Protocol = easyproxy.SOCKS5 + } + app.proxyConfig.Addr = app.config.Section("advanced").Key("proxy_address").MustString("") + app.proxyConfig.User = app.config.Section("advanced").Key("proxy_user").MustString("") + app.proxyConfig.Password = app.config.Section("advanced").Key("proxy_password").MustString("") + app.proxyTransport, err = easyproxy.NewTransport(app.proxyConfig) + if err != nil { + app.err.Printf("Failed to initialize Proxy: %v\n", err) + } + app.proxyEnabled = true + } + app.MustSetValue("updates", "enabled", "true") releaseChannel := app.config.Section("updates").Key("channel").String() if app.config.Section("updates").Key("enabled").MustBool(false) { @@ -147,6 +164,9 @@ func (app *appContext) loadConfig() error { v = "git" } app.updater = newUpdater(baseURL, namespace, repo, v, commit, updater) + if app.proxyEnabled { + app.updater.SetTransport(app.proxyTransport) + } } if releaseChannel == "" { if version == "git" { diff --git a/config/config-base.json b/config/config-base.json index 01c4852..8001812 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -274,6 +274,18 @@ "value": false, "advanced": true, "description": "Navigate directly to the above URL instead of needing the user to click \"Continue\"." + }, + "login_appearance": { + "name": "Login screen appearance", + "required": false, + "requires_restart": false, + "type": "select", + "options": [ + ["clear", "Transparent"], + ["opaque", "Opaque"] + ], + "value": "clear", + "description": "Appearance of the Admin login screen." } } }, @@ -281,7 +293,8 @@ "order": [], "meta": { "name": "Advanced", - "description": "Advanced settings." + "description": "Advanced settings.", + "advanced": true }, "settings": { "tls": { @@ -318,6 +331,70 @@ "type": "text", "value": "", "description": "Path to .key file. See jfa-go wiki for more info." + }, + "auth_retry_count": { + "name": "Initial auth retry count", + "required": false, + "requires_restart": true, + "type": "number", + "value": 6, + "description": "Number of times to retry initial connection to Jellyfin before failing." + }, + "auth_retry_gap": { + "name": "Initial auth retry gap (seconds)", + "required": false, + "requires_restart": true, + "type": "number", + "value": 10, + "description": "Duration in seconds to wait between connection retries." + }, + "proxy": { + "name": "Use Proxy", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Whether or not to use a HTTP/SOCKS5 Proxy." + }, + "proxy_protocol": { + "name": "Proxy Protocol", + "depends_true": "proxy", + "required": false, + "requires_restart": true, + "type": "select", + "options": [ + ["http", "HTTP"], + ["socks", "SOCKS5"] + ], + "value": "http", + "description": "Protocol to use for proxy connection." + }, + "proxy_address": { + "name": "Proxy Address", + "depends_true": "proxy", + "required": false, + "requires_restart": true, + "type": "text", + "value": "", + "description": "Proxy address, including port." + }, + "proxy_user": { + "name": "Proxy Username", + "depends_true": "proxy", + "required": false, + "requires_restart": true, + "type": "text", + "value": "", + "description": "Leave blank for no Authentication." + }, + "proxy_password": { + "name": "Proxy Password", + "depends_true": "proxy", + "required": false, + "requires_restart": true, + "type": "password", + "value": "", + "description": "Leave blank for no Authentication." } } }, @@ -406,6 +483,14 @@ "required": "false", "description": "Click the edit icon next to the \"User Page\" Setting to add custom Markdown messages that will be shown to the user. Note message cards are not private, little effort is required for anyone to view them." }, + "show_link": { + "name": "Show Link on Admin Login page", + "required": false, + "requires_restart": false, + "type": "bool", + "value": true, + "description": "Whether or not to show a link to the \"My Account\" page on the admin login screen, to direct lost users." + }, "referrals": { "name": "User Referrals", "required": false, diff --git a/css/base.css b/css/base.css index 2c60e94..9519951 100644 --- a/css/base.css +++ b/css/base.css @@ -15,6 +15,9 @@ --border-width-4: 5px; --border-width-8: 8px; font-family: 'Hanken Grotesk', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + + --bg-light: #fff; + --bg-dark: #101010; } .light { @@ -26,11 +29,11 @@ } .dark body { - background-color: #101010; + background-color: var(--bg-dark); } html:not(.dark) body { - background-color: #fff; + background-color: var(--bg-light); } .dark select, .dark option, .dark input { diff --git a/css/modal.css b/css/modal.css index ef6536e..11a0e27 100644 --- a/css/modal.css +++ b/css/modal.css @@ -10,6 +10,24 @@ background-color: rgba(0,0,0,40%); } +.wall { + position: fixed; + z-index: 11; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: auto; +} + +html.dark .wall { + background-color: var(--bg-dark); +} + +html:not(.dark) .wall { + background-color: var(--bg-light); +} + .modal-close { float: right; color: #aaa; diff --git a/discord.go b/discord.go index 72c93c2..fcfb27f 100644 --- a/discord.go +++ b/discord.go @@ -567,13 +567,15 @@ func (d *DiscordDaemon) cmdInvite(s *dg.Session, i *dg.InteractionCreate, lang s //if mins > 0 { // expmin = mins //} - // Need to check whether requestor is linked to the admin account *possibly add Admin bool to DiscordUser struct + // Check whether requestor is linked to the admin account requesterEmail, ok := d.app.storage.GetEmailsKey(requester.JellyfinID) if !ok { d.app.err.Printf("Failed to verify admin") } if !requesterEmail.Admin { d.app.err.Printf("User is not admin") + //add response message + return } var expiryMinutes int64 = 30 @@ -625,11 +627,11 @@ func (d *DiscordDaemon) cmdInvite(s *dg.Session, i *dg.InteractionCreate, lang s d.app.debug.Printf("%s: Sending invite message", inviteCode) invname, err := d.bot.GuildMember(d.guildID, recipient.ID) invite.SendTo = invname.User.Username - msg, err := d.app.email.constructInvite(inviteCode, invite, d.app, false) if err != nil { invite.SendTo = fmt.Sprintf("Failed to send to %s", RenderDiscordUsername(recipient)) d.app.err.Printf("%s: Failed to construct invite message: %v", inviteCode, err) + //add response message } else { var err error err = d.app.discord.SendDM(msg, recipient.ID) diff --git a/easyproxy/easyproxy.go b/easyproxy/easyproxy.go new file mode 100644 index 0000000..ef6557b --- /dev/null +++ b/easyproxy/easyproxy.go @@ -0,0 +1,83 @@ +// Package easyproxy provides a method to quickly create a http.Transport or net.Conn using given proxy details (SOCKS5 or HTTP). +package easyproxy + +import ( + "crypto/tls" + "net/http" + "net/url" + + "github.com/magisterquis/connectproxy" + "golang.org/x/net/proxy" +) + +type Protocol int + +const ( + SOCKS5 Protocol = iota // SOCKS5 + HTTP // HTTP +) + +type ProxyConfig struct { + Protocol Protocol + Addr string + User string + Password string +} + +// NewTransport returns a http.Transport using the given proxy details. Leave user/pass blank if not needed. +func NewTransport(c ProxyConfig) (*http.Transport, error) { + t := &http.Transport{} + if c.Protocol == HTTP { + u := &url.URL{ + Scheme: "http", + Host: c.Addr, + } + if c.User != "" && c.Password != "" { + u.User = url.UserPassword(c.User, c.Password) + } + t.Proxy = http.ProxyURL(u) + return t, nil + } + var auth *proxy.Auth = nil + if c.User != "" && c.Password != "" { + auth = &proxy.Auth{User: c.User, Password: c.Password} + } + dialer, err := proxy.SOCKS5("tcp", c.Addr, auth, proxy.Direct) + if err != nil { + return nil, err + } + t.Dial = dialer.Dial + return t, nil +} + +// NewConn returns a tls.Conn to "addr" using the given proxy details. Leave user/pass blank if not needed. +func NewConn(c ProxyConfig, addr string, tlsConf *tls.Config) (*tls.Conn, error) { + var proxyDialer proxy.Dialer + var err error + if c.Protocol == SOCKS5 { + var auth *proxy.Auth = nil + if c.User != "" && c.Password != "" { + auth = &proxy.Auth{User: c.User, Password: c.Password} + } + proxyDialer, err = proxy.SOCKS5("tcp", c.Addr, auth, proxy.Direct) + if err != nil { + return nil, err + } + } else { + u := &url.URL{ + Scheme: "http", + Host: c.Addr, + } + if c.User != "" && c.Password != "" { + u.User = url.UserPassword(c.User, c.Password) + } + proxyDialer, err = connectproxy.New(u, proxy.Direct) + } + + dialer, err := proxyDialer.Dial("tcp", addr) + if err != nil { + return nil, err + } + conn := tls.Client(dialer, tlsConf) + return conn, nil +} diff --git a/easyproxy/go.mod b/easyproxy/go.mod new file mode 100644 index 0000000..f88550a --- /dev/null +++ b/easyproxy/go.mod @@ -0,0 +1,7 @@ +module github.com/hrfee/jfa-go/easyproxy + +go 1.20 + +require golang.org/x/net v0.15.0 + +require github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect diff --git a/easyproxy/go.sum b/easyproxy/go.sum new file mode 100644 index 0000000..a131b72 --- /dev/null +++ b/easyproxy/go.sum @@ -0,0 +1,4 @@ +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI= +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= diff --git a/email.go b/email.go index 0f517ca..9671ee4 100644 --- a/email.go +++ b/email.go @@ -19,6 +19,7 @@ import ( "github.com/gomarkdown/markdown" "github.com/gomarkdown/markdown/html" + "github.com/hrfee/jfa-go/easyproxy" "github.com/hrfee/mediabrowser" "github.com/itchyny/timefmt-go" "github.com/mailgun/mailgun-go/v4" @@ -87,7 +88,11 @@ func NewEmailer(app *appContext) *Emailer { if username == "" && password != "" { username = emailer.fromAddr } - err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, password, sslTLS, app.config.Section("smtp").Key("ssl_cert").MustString(""), app.config.Section("smtp").Key("hello_hostname").String(), app.config.Section("smtp").Key("cert_validation").MustBool(true)) + var proxyConf *easyproxy.ProxyConfig = nil + if app.proxyEnabled { + proxyConf = &app.proxyConfig + } + err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, password, sslTLS, app.config.Section("smtp").Key("ssl_cert").MustString(""), app.config.Section("smtp").Key("hello_hostname").String(), app.config.Section("smtp").Key("cert_validation").MustBool(true), proxyConf) if err != nil { app.err.Printf("Error while initiating SMTP mailer: %v", err) } @@ -113,7 +118,7 @@ type SMTP struct { } // NewSMTP returns an SMTP emailClient. -func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string, helloHostname string, validateCertificate bool) (err error) { +func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string, helloHostname string, validateCertificate bool, proxy *easyproxy.ProxyConfig) (err error) { sender := &SMTP{} sender.Client = sMail.NewSMTPClient() if sslTLS { @@ -131,12 +136,16 @@ func (emailer *Emailer) NewSMTP(server string, port int, username, password stri sender.Client.Host = server sender.Client.Port = port sender.Client.KeepAlive = false + // x509.SystemCertPool is unavailable on windows if PLATFORM == "windows" { sender.Client.TLSConfig = &tls.Config{ InsecureSkipVerify: !validateCertificate, ServerName: server, } + if proxy != nil { + sender.Client.CustomConn, err = easyproxy.NewConn(*proxy, fmt.Sprintf("%s:%d", server, port), sender.Client.TLSConfig) + } emailer.sender = sender return } @@ -156,6 +165,9 @@ func (emailer *Emailer) NewSMTP(server string, port int, username, password stri ServerName: server, RootCAs: rootCAs, } + if proxy != nil { + sender.Client.CustomConn, err = easyproxy.NewConn(*proxy, fmt.Sprintf("%s:%d", server, port), sender.Client.TLSConfig) + } emailer.sender = sender return } diff --git a/go.mod b/go.mod index 2a228e1..f2866a2 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,8 @@ replace github.com/hrfee/jfa-go/linecache => ./linecache replace github.com/hrfee/jfa-go/api => ./api +replace github.com/hrfee/jfa-go/easyproxy => ./easyproxy + require ( github.com/bwmarrin/discordgo v0.27.1 github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a @@ -31,7 +33,7 @@ require ( github.com/hrfee/jfa-go/linecache v0.0.0-20230626224816-f72960635dc3 github.com/hrfee/jfa-go/logger v0.0.0-20230626224816-f72960635dc3 github.com/hrfee/jfa-go/ombi v0.0.0-20230626224816-f72960635dc3 - github.com/hrfee/mediabrowser v0.3.10 + github.com/hrfee/mediabrowser v0.3.12 github.com/itchyny/timefmt-go v0.1.5 github.com/lithammer/shortuuid/v3 v3.0.7 github.com/mailgun/mailgun-go/v4 v4.9.1 @@ -41,7 +43,7 @@ require ( github.com/swaggo/gin-swagger v1.6.0 github.com/timshannon/badgerhold/v4 v4.0.2 github.com/writeas/go-strip-markdown v2.0.1+incompatible - github.com/xhit/go-simple-mail/v2 v2.13.0 + github.com/xhit/go-simple-mail/v2 v2.16.0 gopkg.in/ini.v1 v1.67.0 maunium.net/go/mautrix v0.15.3 ) @@ -85,11 +87,13 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/hrfee/jfa-go/easyproxy v0.0.0-00010101000000-000000000000 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.6 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect + github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect @@ -116,12 +120,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.10.0 // indirect + golang.org/x/crypto v0.13.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect golang.org/x/image v0.8.0 // indirect - golang.org/x/net v0.11.0 // indirect - golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.10.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.10.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 9192581..07de685 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -14,14 +15,11 @@ github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY= github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -40,16 +38,14 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger/v3 v3.2103.1 h1:zaX53IRg7ycxVlkd5pYdCeFp1FynD6qBGQoQql3R3Hk= github.com/dgraph-io/badger/v3 v3.2103.1/go.mod h1:dULbq6ehJ5K0cGW/1TQ9iSfUk0gbSiToDWmWmTsJ53E= github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -174,7 +170,6 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU= github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -195,7 +190,6 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -206,7 +200,6 @@ github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a h1:AWZzzFrqyjY github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= @@ -231,12 +224,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hrfee/mediabrowser v0.3.8 h1:y0iBCb6jE3QKcsiCJSYva2fFPHRn4UA+sGRzoPuJ/Dk= -github.com/hrfee/mediabrowser v0.3.8/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= -github.com/hrfee/mediabrowser v0.3.9 h1:ecBUd7LMjQrh+9SFRen2T2DzQqI7W8J7vV2lGExD0YU= -github.com/hrfee/mediabrowser v0.3.9/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= -github.com/hrfee/mediabrowser v0.3.10 h1:MUrgZQVY3mk76Bhn7PsZ4LFRhtGitkZA4FP+1qg1HFo= -github.com/hrfee/mediabrowser v0.3.10/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= +github.com/hrfee/mediabrowser v0.3.12 h1:fqDxt1be3e+ZNjAtlKc8MTqg7peo6fuGCrk2wOXo20k= +github.com/hrfee/mediabrowser v0.3.12/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= @@ -251,7 +240,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ= github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= @@ -276,8 +264,8 @@ github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaK github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailgun/mailgun-go/v4 v4.9.0 h1:wRbxvVQ5QObFewLxc1uVvipA16D8gxeiO+cBOca51Iw= -github.com/mailgun/mailgun-go/v4 v4.9.0/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40= +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI= +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg= github.com/mailgun/mailgun-go/v4 v4.9.1 h1:D/jhJXYod4RqRsNOOSrjrtAcMEnz8mPYJmeA5cueHKY= github.com/mailgun/mailgun-go/v4 v4.9.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -298,7 +286,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -337,6 +324,7 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -359,7 +347,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= @@ -384,6 +371,7 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/timshannon/badgerhold/v3 v3.0.0-20210909134927-2b6764d68c1e h1:zWSVsQaifg0cVH9VvR+cMguV7exK6U+SoW8YD1cZpR4= github.com/timshannon/badgerhold/v3 v3.0.0-20210909134927-2b6764d68c1e/go.mod h1:/Seq5xGNo8jLhSbDX3jdbeZrp4yFIpQ6/7n4TjziEWs= github.com/timshannon/badgerhold/v4 v4.0.2 h1:83OLY/NFnEaMnHEPd84bYtkLipVkjTsMbzQRYbk47g4= github.com/timshannon/badgerhold/v4 v4.0.2/go.mod h1:rh6RyXLQFsvrvcKondPQQFZnNovpRzu+gS0FlLxYuHY= @@ -408,13 +396,14 @@ github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6Fk github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE= github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5f96fFTLI= github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= +github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA= +github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -448,18 +437,14 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= -golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= golang.org/x/image v0.8.0 h1:agUcRXV/+w6L9ryntYYsF2x9fQTMd4T8fiiYXAVW6Jg= golang.org/x/image v0.8.0/go.mod h1:PwLxp3opCYg4WR2WO9P0L6ESnsD6bLTWcw8zanLMVFM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -471,7 +456,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -494,10 +478,10 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -539,10 +523,10 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -552,10 +536,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -570,8 +554,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -603,8 +585,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= @@ -633,8 +613,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.15.2 h1:fUiVajeoOR92uJoSShHbCvh7uG6lDY4ZO4Mvt90LbjU= -maunium.net/go/mautrix v0.15.2/go.mod h1:h4NwfKqE4YxGTLSgn/gawKzXAb2sF4qx8agL6QEFtGg= maunium.net/go/mautrix v0.15.3 h1:C9BHSUM0gYbuZmAtopuLjIcH5XHLb/ZjTEz7nN+0jN0= maunium.net/go/mautrix v0.15.3/go.mod h1:zLrQqdxJlLkurRCozTc9CL6FySkgZlO/kpCYxBILSLE= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/html/admin.html b/html/admin.html index 1919cb3..3c7ae1b 100644 --- a/html/admin.html +++ b/html/admin.html @@ -18,6 +18,7 @@ window.jfAdminOnly = {{ .jfAdminOnly }}; window.jfAllowAll = {{ .jfAllowAll }}; window.referralsEnabled = {{ .referralsEnabled }}; + window.loginAppearance = "{{ .loginAppearance }}"; Admin - jfa-go {{ template "header.html" . }} @@ -465,7 +466,7 @@ {{ if .userPageEnabled }}
- {{ .strings.myAccount }} + {{ .strings.myAccount }}
{{ end }}
diff --git a/html/login-modal.html b/html/login-modal.html index 2f9c3fb..e3c4a5d 100644 --- a/html/login-modal.html +++ b/html/login-modal.html @@ -7,6 +7,14 @@
{{ end }} {{ end }} + {{ if index . "userPageEnabled" }} + {{ if and .userPageEnabled .showUserPageLink }} +
+ {{ .strings.loginNotAdmin }} + {{ .strings.myAccount }} +
+ {{ end }} + {{ end }}
{{ .strings.login }} diff --git a/lang/admin/en-us.json b/lang/admin/en-us.json index 9a3bd22..e22efe8 100644 --- a/lang/admin/en-us.json +++ b/lang/admin/en-us.json @@ -123,7 +123,8 @@ "userPageLogin": "User Page: Login", "userPagePage": "User Page: Page", "buildTime": "Build Time", - "builtBy": "Built By" + "builtBy": "Built By", + "loginNotAdmin": "Not an Admin?" }, "notifications": { "changedEmailAddress": "Changed email address of {n}.", diff --git a/lang/admin/fr-fr.json b/lang/admin/fr-fr.json index 78aa356..2b08529 100644 --- a/lang/admin/fr-fr.json +++ b/lang/admin/fr-fr.json @@ -118,7 +118,14 @@ "userPagePage": "Page utilisateur : Page", "after": "Après", "before": "Avant", - "unlink": "Délier le compte" + "unlink": "Délier le compte", + "enableReferrals": "Activer Parrainage", + "enableReferralsDescription": "Offrez aux utilisateurs un lien de parrainage personnel semblable à une invitation, à envoyer à vos amis/famille. Peut provenir modèle de profil ou d’une invitation existante.", + "invite": "Inviter", + "userLabel": "Étiquette", + "userLabelDescription": "Étiquette à appliquer aux utilisateurs créés avec cette invitation.", + "disableReferrals": "Désactiver Parrainage", + "enableReferralsProfileDescription": "Donnez aux utilisateurs créés avec ce profil un lien de parrainage personnel semblable à une invitation, à envoyer à vos amis/famille. Créez une invitation avec les paramètres souhaités, puis sélectionnez-la ici. Chaque référence sera alors basée sur cette invitation. Vous pouvez supprimer l'invitation une fois terminée." }, "notifications": { "changedEmailAddress": "Adresse e-mail modifiée de {n}.", @@ -156,7 +163,9 @@ "accountConnected": "Compte connecté.", "savedAnnouncement": "Annonce enregistrée.", "setOmbiProfile": "Profil ombi enregistré.", - "errorSetOmbiProfile": "Echec de la sauvegarde du profil ombi." + "errorSetOmbiProfile": "Echec de la sauvegarde du profil ombi.", + "errorNoReferralTemplate": "Le profil ne contient pas de modèle de référence, ajoutez-en un dans les paramètres.", + "referralsEnabled": "Parrainage activer." }, "quantityStrings": { "modifySettingsFor": { @@ -214,6 +223,10 @@ "setExpiry": { "singular": "Définir l'expiration pour {n} utilisateur", "plural": "Définir l'expiration pour {n} utilisateurs" + }, + "enableReferralsFor": { + "singular": "Activer les parrainages pour {n} utilisateur", + "plural": "Activer les parrainages pour {n} utilisateur" } } } diff --git a/lang/common/fr-fr.json b/lang/common/fr-fr.json index 86ae13b..e3aeace 100644 --- a/lang/common/fr-fr.json +++ b/lang/common/fr-fr.json @@ -5,7 +5,7 @@ "strings": { "username": "Nom d'utilisateur", "password": "Mot de passe", - "emailAddress": "Adresse courriel", + "emailAddress": "Adresse Email", "name": "Nom", "submit": "Soumettre", "send": "Envoyer", @@ -29,7 +29,7 @@ "logout": "Se déconnecter", "admin": "Administrateur", "enabled": "Activé", - "disabled": "Désactivé", + "disabled": "Désactiver", "reEnable": "Ré-activé", "disable": "Désactivé", "expiry": "Expiration", @@ -40,7 +40,8 @@ "accountStatus": "Statut du compte", "notSet": "Non défini", "myAccount": "Mon compte", - "contactMethods": "Moyens de contact" + "contactMethods": "Moyens de contact", + "referrals": "Programme de parrainage" }, "notifications": { "errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.", @@ -51,16 +52,16 @@ }, "quantityStrings": { "year": { - "plural": "{n] années", - "singular": "{n] année" + "plural": "{n} années", + "singular": "{n} année" }, "day": { - "singular": "{n] jour", - "plural": "{n] jours" + "singular": "{n} jour", + "plural": "{n} jours" }, "month": { - "singular": "{n] mois", - "plural": "{n] mois" + "singular": "{n} mois", + "plural": "{n} mois" } } } diff --git a/lang/common/sv-se.json b/lang/common/sv-se.json index ff602c8..46d887a 100644 --- a/lang/common/sv-se.json +++ b/lang/common/sv-se.json @@ -23,7 +23,22 @@ "expiry": "Löper ut", "edit": "Redigera", "delete": "Radera", - "inviteRemainingUses": "Återstående användningar" + "inviteRemainingUses": "Återstående användningar", + "send": "Skicka", + "linkDiscord": "Länka Discord", + "copied": "Kopierat", + "linkTelegram": "Länka Telegram", + "contactEmail": "Kontakta via e-post", + "contactTelegram": "Kontakta via Telegram", + "refresh": "Uppdatera", + "required": "Obligatoriskt", + "contactDiscord": "Kontakt via Discord", + "linkMatrix": "Länka Matrix", + "reEnable": "Återaktivera", + "disable": "Inaktivera", + "contactMethods": "Kontaktmetoder", + "accountStatus": "Kontostatus", + "notSet": "Inte inställt" }, "notifications": { "errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.", @@ -31,6 +46,5 @@ "errorUnknown": "Okänt fel.", "error401Unauthorized": "Obehörig. Prova att uppdatera sidan.", "errorSaveSettings": "Det gick inte att spara inställningarna." - }, - "quantityStrings": {} -} \ No newline at end of file + } +} diff --git a/lang/form/fr-fr.json b/lang/form/fr-fr.json index ffd9826..e3cc4a1 100644 --- a/lang/form/fr-fr.json +++ b/lang/form/fr-fr.json @@ -7,11 +7,11 @@ "pageTitle": "Créer un compte Jellyfin", "createAccountHeader": "Création du compte", "accountDetails": "Détails", - "emailAddress": "Courriel", + "emailAddress": "Email", "username": "Nom d'utilisateur", "password": "Mot de passe", "reEnterPassword": "Confirmez mot de passe", - "reEnterPasswordInvalid": "Les mots de passe ne correspondent pas.", + "reEnterPasswordInvalid": "Les mots de passe ne sont pas pareils.", "createAccountButton": "Créer le compte", "passwordRequirementsHeader": "Mot de passe requis", "successHeader": "Succès !", @@ -35,7 +35,10 @@ "editContactMethod": "Modifier le moyen de contact", "joinTheServer": "Rejoindre le serveur :", "customMessagePlaceholderHeader": "Personnaliser cette carte", - "resetPassword": "Réinitialisation de mot de passe" + "resetPassword": "Réinitialisation mot de passe", + "referralsDescription": "Invitez vos amis et votre famille à Jellyfin avec ce lien. Revenez ici pour en obtenir un nouveau s'il expire.", + "copyReferral": "Copier le lien", + "invitedBy": "Vous avez été invité par l'utilisateur {user}." }, "validationStrings": { "length": { diff --git a/lang/setup/fr-fr.json b/lang/setup/fr-fr.json index 7ad7a19..d7b8058 100644 --- a/lang/setup/fr-fr.json +++ b/lang/setup/fr-fr.json @@ -8,7 +8,7 @@ "back": "Retour", "optional": "Optionnel", "serverType": "Type de serveur", - "disabled": "Désactivé", + "disabled": "Désactiver", "enabled": "Activé", "port": "Port", "message": "Message", diff --git a/main.go b/main.go index bfc8e8f..8156edf 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ import ( "github.com/fatih/color" "github.com/hrfee/jfa-go/common" _ "github.com/hrfee/jfa-go/docs" + "github.com/hrfee/jfa-go/easyproxy" "github.com/hrfee/jfa-go/logger" "github.com/hrfee/jfa-go/ombi" "github.com/hrfee/mediabrowser" @@ -113,6 +114,9 @@ type appContext struct { newUpdate bool // Whether whatever's in update is new. tag Tag update Update + proxyEnabled bool + proxyTransport *http.Transport + proxyConfig easyproxy.ProxyConfig internalPWRs map[string]InternalPWR ConfirmationKeys map[string]map[string]newUserDTO // Map of invite code to jwt to request confirmationKeysLock sync.Mutex @@ -390,8 +394,18 @@ func start(asDaemon, firstCall bool) { if debugMode { app.jf.Verbose = true } + + if app.proxyEnabled { + app.jf.SetTransport(app.proxyTransport) + } + var status int - _, status, err = app.jf.Authenticate(app.config.Section("jellyfin").Key("username").String(), app.config.Section("jellyfin").Key("password").String()) + retryOpts := mediabrowser.MustAuthenticateOptions{ + RetryCount: app.config.Section("advanced").Key("auth_retry_count").MustInt(6), + RetryGap: time.Duration(app.config.Section("advanced").Key("auth_retry_gap").MustInt(10)) * time.Second, + LogFailures: true, + } + _, status, err = app.jf.MustAuthenticate(app.config.Section("jellyfin").Key("username").String(), app.config.Section("jellyfin").Key("password").String(), retryOpts) if status != 200 || err != nil { app.err.Fatalf("Failed to authenticate with Jellyfin @ \"%s\" (%d): %v", server, status, err) } diff --git a/ombi/ombi.go b/ombi/ombi.go index 29a6e1c..38fa369 100644 --- a/ombi/ombi.go +++ b/ombi/ombi.go @@ -239,9 +239,9 @@ type NotificationPref struct { func (ombi *Ombi) SetNotificationPrefs(user map[string]interface{}, discordID, telegramUser string) (result string, code int, err error) { id := user["id"].(string) url := fmt.Sprintf("%s/api/v1/Identity/NotificationPreferences", ombi.server) - var data []NotificationPref + data := []NotificationPref{} if discordID != "" { - data = []NotificationPref{NotificationPref{NotifAgentDiscord, id, discordID, true}} + data = append(data, NotificationPref{NotifAgentDiscord, id, discordID, true}) } if telegramUser != "" { data = append(data, NotificationPref{NotifAgentTelegram, id, telegramUser, true}) diff --git a/router.go b/router.go index e2426cc..875ad20 100644 --- a/router.go +++ b/router.go @@ -160,12 +160,11 @@ func (app *appContext) loadRoutes(router *gin.Engine) { api := router.Group("/", app.webAuth()) - var user *gin.RouterGroup - if userPageEnabled { - user = router.Group("/my", app.userAuth()) - } - for _, p := range routePrefixes { + var user *gin.RouterGroup + if userPageEnabled { + user = router.Group(p+"/my", app.userAuth()) + } router.POST(p+"/logout", app.Logout) api.DELETE(p+"/users", app.DeleteUsers) api.GET(p+"/users", app.GetUsers) @@ -234,22 +233,22 @@ func (app *appContext) loadRoutes(router *gin.Engine) { } if userPageEnabled { - user.GET(p+"/details", app.MyDetails) - user.POST(p+"/contact", app.SetMyContactMethods) - user.POST(p+"/logout", app.LogoutUser) - user.POST(p+"/email", app.ModifyMyEmail) - user.GET(p+"/discord/invite", app.MyDiscordServerInvite) - user.GET(p+"/pin/:service", app.GetMyPIN) - user.GET(p+"/discord/verified/:pin", app.MyDiscordVerifiedInvite) - user.GET(p+"/telegram/verified/:pin", app.MyTelegramVerifiedInvite) - user.POST(p+"/matrix/user", app.MatrixSendMyPIN) - user.GET(p+"/matrix/verified/:userID/:pin", app.MatrixCheckMyPIN) - user.DELETE(p+"/discord", app.UnlinkMyDiscord) - user.DELETE(p+"/telegram", app.UnlinkMyTelegram) - user.DELETE(p+"/matrix", app.UnlinkMyMatrix) - user.POST(p+"/password", app.ChangeMyPassword) + user.GET("/details", app.MyDetails) + user.POST("/contact", app.SetMyContactMethods) + user.POST("/logout", app.LogoutUser) + user.POST("/email", app.ModifyMyEmail) + user.GET("/discord/invite", app.MyDiscordServerInvite) + user.GET("/pin/:service", app.GetMyPIN) + user.GET("/discord/verified/:pin", app.MyDiscordVerifiedInvite) + user.GET("/telegram/verified/:pin", app.MyTelegramVerifiedInvite) + user.POST("/matrix/user", app.MatrixSendMyPIN) + user.GET("/matrix/verified/:userID/:pin", app.MatrixCheckMyPIN) + user.DELETE("/discord", app.UnlinkMyDiscord) + user.DELETE("/telegram", app.UnlinkMyTelegram) + user.DELETE("/matrix", app.UnlinkMyMatrix) + user.POST("/password", app.ChangeMyPassword) if app.config.Section("user_page").Key("referrals").MustBool(false) { - user.GET(p+"/referral", app.GetMyReferral) + user.GET("/referral", app.GetMyReferral) } } } diff --git a/ts/admin.ts b/ts/admin.ts index f29fe2b..2fe99c7 100644 --- a/ts/admin.ts +++ b/ts/admin.ts @@ -163,7 +163,7 @@ window.onpopstate = (event: PopStateEvent) => { window.tabs.switch(event.state); } -const login = new Login(window.modals.login as Modal, "/"); +const login = new Login(window.modals.login as Modal, "/", window.loginAppearance); login.onLogin = () => { console.log("Logged in."); window.updater = new Updater(); diff --git a/ts/modules/login.ts b/ts/modules/login.ts index 1527e10..12e6aba 100644 --- a/ts/modules/login.ts +++ b/ts/modules/login.ts @@ -8,13 +8,21 @@ export class Login { private _endpoint: string; private _onLogin: (username: string, password: string) => void; private _logoutButton: HTMLElement = null; + private _wall: HTMLElement; + private _hasOpacityWall: boolean = false; - constructor(modal: Modal, endpoint: string) { + constructor(modal: Modal, endpoint: string, appearance: string) { this._endpoint = endpoint; this._url = window.URLBase + endpoint; if (this._url[this._url.length-1] != '/') this._url += "/"; this._modal = modal; + if (appearance == "opaque") { + this._hasOpacityWall = true; + this._wall = document.createElement("div"); + this._wall.classList.add("wall"); + this._modal.asElement().parentElement.appendChild(this._wall); + } this._form = this._modal.asElement().querySelector(".form-login") as HTMLFormElement; this._form.onsubmit = (event: SubmitEvent) => { event.preventDefault(); @@ -86,6 +94,7 @@ export class Login { if (this._onLogin) { this._onLogin(username, password); } + if (this._hasOpacityWall) this._wall.remove(); this._modal.close(); if (this._logoutButton != null) this._logoutButton.classList.remove("unfocused"); diff --git a/ts/typings/d.ts b/ts/typings/d.ts index 9aed65d..8d97410 100644 --- a/ts/typings/d.ts +++ b/ts/typings/d.ts @@ -41,6 +41,7 @@ declare interface Window { jfAdminOnly: boolean; jfAllowAll: boolean; referralsEnabled: boolean; + loginAppearance: string; } declare interface Update { diff --git a/ts/user.ts b/ts/user.ts index d11dfeb..f8e4e2b 100644 --- a/ts/user.ts +++ b/ts/user.ts @@ -556,7 +556,6 @@ changePasswordButton.addEventListener("click", () => { } }); }); -// FIXME: Submit & Validate document.addEventListener("details-reload", () => { _get("/my/details", null, (req: XMLHttpRequest) => { @@ -645,7 +644,7 @@ document.addEventListener("details-reload", () => { }); }); -const login = new Login(window.modals.login as Modal, "/my/"); +const login = new Login(window.modals.login as Modal, "/my/", "opaque"); login.onLogin = () => { console.log("Logged in."); document.querySelector(".page-container").classList.remove("unfocused"); diff --git a/updater.go b/updater.go index c6c8c62..1e0e78a 100644 --- a/updater.go +++ b/updater.go @@ -185,6 +185,11 @@ type BuildDTO struct { Tags map[string]Tag } +// SetTransport sets the http.Transport to use for requests. Can be used to set a proxy. +func (ud *Updater) SetTransport(t *http.Transport) { + ud.httpClient.Transport = t +} + func (ud *Updater) GetTag() (Tag, int, error) { if ud.buildType == off { return Tag{}, -1, nil diff --git a/user-auth.go b/user-auth.go index 40ea057..53c9ae0 100644 --- a/user-auth.go +++ b/user-auth.go @@ -1,6 +1,10 @@ package main -import "github.com/gin-gonic/gin" +import ( + "strings" + + "github.com/gin-gonic/gin" +) func (app *appContext) userAuth() gin.HandlerFunc { return app.userAuthenticate @@ -60,7 +64,11 @@ func (app *appContext) getUserTokenLogin(gc *gin.Context) { } app.debug.Printf("Token generated for non-admin user \"%s\"", username) - gc.SetCookie("user-refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/my", gc.Request.URL.Hostname(), true, true) + uri := "/my" + if strings.HasPrefix(gc.Request.RequestURI, app.URLBase) { + uri = "/accounts/my" + } + gc.SetCookie("user-refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, uri, gc.Request.URL.Hostname(), true, true) gc.JSON(200, getTokenDTO{token}) } diff --git a/views.go b/views.go index f1f7fdd..7e56900 100644 --- a/views.go +++ b/views.go @@ -175,7 +175,9 @@ func (app *appContext) AdminPage(gc *gin.Context) { "jfAdminOnly": jfAdminOnly, "jfAllowAll": jfAllowAll, "userPageEnabled": app.config.Section("user_page").Key("enabled").MustBool(false), + "showUserPageLink": app.config.Section("user_page").Key("show_link").MustBool(true), "referralsEnabled": app.config.Section("user_page").Key("enabled").MustBool(false) && app.config.Section("user_page").Key("referrals").MustBool(false), + "loginAppearance": app.config.Section("ui").Key("login_appearance").MustString("clear"), }) }