From 5fea1d94fce0e6fa4b17dae87a31c0c79d2f5e5c Mon Sep 17 00:00:00 2001 From: Pierre-Emmanuel Jacquier <15922119+pierre-emmanuelJ@users.noreply.github.com> Date: Mon, 18 May 2020 11:20:19 +0200 Subject: [PATCH] Add basic auth, fix xtream path (#40) Signed-off-by: Pierre-Emmanuel Jacquier <15922119+pierre-emmanuelJ@users.noreply.github.com> --- cmd/root.go | 8 ++++---- pkg/config/config.go | 19 ++++++++++++++++--- pkg/server/handlers.go | 6 +++--- pkg/server/routes.go | 4 ++-- pkg/server/server.go | 15 ++++++++++----- pkg/server/xtreamHandles.go | 4 ++-- pkg/xtream-proxy/xtream-proxy.go | 2 +- 7 files changed, 38 insertions(+), 20 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index ebcf79b..914cda7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -74,12 +74,12 @@ var rootCmd = &cobra.Command{ Port: viper.GetInt64("port"), }, RemoteURL: remoteHostURL, - XtreamUser: xtreamUser, - XtreamPassword: xtreamPassword, + XtreamUser: config.CredentialString(xtreamUser), + XtreamPassword: config.CredentialString(xtreamPassword), XtreamBaseURL: xtreamBaseURL, M3UCacheExpiration: viper.GetInt("m3u-cache-expiration"), - User: viper.GetString("user"), - Password: viper.GetString("password"), + User: config.CredentialString(viper.GetString("user")), + Password: config.CredentialString(viper.GetString("password")), HTTPS: viper.GetBool("https"), M3UFileName: viper.GetString("m3u-file-name"), CustomEndpoint: viper.GetString("custom-endpoint"), diff --git a/pkg/config/config.go b/pkg/config/config.go index c60241b..66b5c1c 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -22,6 +22,19 @@ import ( "net/url" ) +// CredentialString represents an iptv-proxy credential. +type CredentialString string + +// PathEscape escapes the credential for an url path. +func (c CredentialString) PathEscape() string { + return url.PathEscape(string(c)) +} + +// String returns the credential string. +func (c CredentialString) String() string { + return string(c) +} + // HostConfiguration containt host infos type HostConfiguration struct { Hostname string @@ -31,13 +44,13 @@ type HostConfiguration struct { // ProxyConfig Contain original m3u playlist and HostConfiguration type ProxyConfig struct { HostConfig *HostConfiguration - XtreamUser string - XtreamPassword string + XtreamUser CredentialString + XtreamPassword CredentialString XtreamBaseURL string M3UCacheExpiration int M3UFileName string CustomEndpoint string RemoteURL *url.URL HTTPS bool - User, Password string + User, Password CredentialString } diff --git a/pkg/server/handlers.go b/pkg/server/handlers.go index b60f5c9..c010233 100644 --- a/pkg/server/handlers.go +++ b/pkg/server/handlers.go @@ -111,7 +111,7 @@ func (c *Config) hlsStream(ctx *gin.Context, oriURL *url.URL) { return } body := string(b) - body = strings.ReplaceAll(body, "/"+c.XtreamUser+"/"+c.XtreamPassword+"/", "/"+c.User+"/"+c.Password+"/") + body = strings.ReplaceAll(body, "/"+c.XtreamUser.String()+"/"+c.XtreamPassword.String()+"/", "/"+c.User.String()+"/"+c.Password.String()+"/") ctx.Data(http.StatusOK, hlsResp.Header.Get("Content-Type"), []byte(body)) return } @@ -140,7 +140,7 @@ func (c *Config) authenticate(ctx *gin.Context) { ctx.AbortWithError(http.StatusBadRequest, err) return } - if c.ProxyConfig.User != authReq.Username || c.ProxyConfig.Password != authReq.Password { + if c.ProxyConfig.User.String() != authReq.Username || c.ProxyConfig.Password.String() != authReq.Password { ctx.AbortWithStatus(http.StatusUnauthorized) } } @@ -162,7 +162,7 @@ func (c *Config) appAuthenticate(ctx *gin.Context) { return } log.Printf("[iptv-proxy] %v | %s |App Auth\n", time.Now().Format("2006/01/02 - 15:04:05"), ctx.ClientIP()) - if c.ProxyConfig.User != q["username"][0] || c.ProxyConfig.Password != q["password"][0] { + if c.ProxyConfig.User.String() != q["username"][0] || c.ProxyConfig.Password.String() != q["password"][0] { ctx.AbortWithStatus(http.StatusUnauthorized) } diff --git a/pkg/server/routes.go b/pkg/server/routes.go index 0b4be4f..5bd226c 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -34,8 +34,8 @@ func (c *Config) routes(r *gin.RouterGroup) { if c.ProxyConfig.XtreamBaseURL != "" { c.xtreamRoutes(r) if strings.Contains(c.XtreamBaseURL, c.RemoteURL.Host) && - c.XtreamUser == c.RemoteURL.Query().Get("username") && - c.XtreamPassword == c.RemoteURL.Query().Get("password") { + c.XtreamUser.String() == c.RemoteURL.Query().Get("username") && + c.XtreamPassword.String() == c.RemoteURL.Query().Get("password") { r.GET("/"+c.M3UFileName, c.authenticate, c.xtreamGetAuto) // XXX Private need: for external Android app diff --git a/pkg/server/server.go b/pkg/server/server.go index e3acbb9..046bdb7 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -22,7 +22,7 @@ import ( "fmt" "net/url" "os" - "path/filepath" + "strings" "github.com/jamesnetherton/m3u" "github.com/pierre-emmanuelJ/iptv-proxy/pkg/config" @@ -136,17 +136,22 @@ func (c *Config) replaceURL(uri string, xtream bool) (string, error) { path := oriURL.EscapedPath() if xtream { - path = fmt.Sprintf("/%s", filepath.Base(path)) + path = strings.ReplaceAll(path, c.XtreamUser.PathEscape(), c.User.PathEscape()) + path = strings.ReplaceAll(path, c.XtreamPassword.PathEscape(), c.Password.PathEscape()) + } + + basicAuth := oriURL.User.String() + if basicAuth != "" { + basicAuth += "@" } newURI := fmt.Sprintf( - "%s://%s:%d%s/%s/%s%s", + "%s://%s%s:%d%s%s", protocol, + basicAuth, c.HostConfig.Hostname, c.HostConfig.Port, customEnd, - url.QueryEscape(c.User), - url.QueryEscape(c.Password), path, ) diff --git a/pkg/server/xtreamHandles.go b/pkg/server/xtreamHandles.go index eaafaef..beba4b3 100644 --- a/pkg/server/xtreamHandles.go +++ b/pkg/server/xtreamHandles.go @@ -160,7 +160,7 @@ func (c *Config) xtreamPlayerAPI(ctx *gin.Context, q url.Values) { action = q["action"][0] } - client, err := xtreamapi.New(c.XtreamUser, c.XtreamPassword, c.XtreamBaseURL) + client, err := xtreamapi.New(c.XtreamUser.String(), c.XtreamPassword.String(), c.XtreamBaseURL) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return @@ -183,7 +183,7 @@ func (c *Config) xtreamPlayerAPI(ctx *gin.Context, q url.Values) { } func (c *Config) xtreamXMLTV(ctx *gin.Context) { - client, err := xtreamapi.New(c.XtreamUser, c.XtreamPassword, c.XtreamBaseURL) + client, err := xtreamapi.New(c.XtreamUser.String(), c.XtreamPassword.String(), c.XtreamBaseURL) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return diff --git a/pkg/xtream-proxy/xtream-proxy.go b/pkg/xtream-proxy/xtream-proxy.go index 7b19923..7a74d4b 100644 --- a/pkg/xtream-proxy/xtream-proxy.go +++ b/pkg/xtream-proxy/xtream-proxy.go @@ -149,7 +149,7 @@ func (c *Client) Action(config *config.ProxyConfig, action string, q url.Values) } respBody, err = c.GetEPG(q["stream_id"][0]) default: - respBody, err = c.login(config.User, config.Password, protocol+"://"+config.HostConfig.Hostname, int(config.HostConfig.Port), protocol) + respBody, err = c.login(config.User.String(), config.Password.String(), protocol+"://"+config.HostConfig.Hostname, int(config.HostConfig.Port), protocol) } return