Define ExternalURL as a net/url.URL and add tests and sanitization

Closes: https://github.com/happyDomain/happydomain/issues/9
This commit is contained in:
nemunaire 2023-09-07 09:56:27 +02:00
parent 691516a558
commit 4e17658d88
4 changed files with 32 additions and 8 deletions

View File

@ -83,8 +83,9 @@ func DeclareRoutes(cfg *config.Options, router *gin.Engine) {
declareUsersAuthRoutes(cfg, apiAuthRoutes)
// Expose Swagger
if cfg.ExternalURL != "" {
docs.SwaggerInfo.Host = cfg.ExternalURL[strings.Index(cfg.ExternalURL, "://")+3:]
if cfg.ExternalURL.URL.Host != "" {
tmp := cfg.ExternalURL.URL.String()
docs.SwaggerInfo.Host = tmp[strings.Index(tmp, "://")+3:]
} else {
docs.SwaggerInfo.Host = fmt.Sprintf("localhost%s", cfg.Bind[strings.Index(cfg.Bind, ":"):])
}

View File

@ -37,7 +37,6 @@ import (
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
@ -154,7 +153,7 @@ func logout(opts *config.Options, c *gin.Context) {
-1,
opts.BaseURL+"/",
"",
opts.DevProxy == "" && !strings.HasPrefix(opts.ExternalURL, "http://"),
opts.DevProxy == "" && opts.ExternalURL.URL.Scheme != "http",
true,
)
c.Status(http.StatusNoContent)
@ -260,7 +259,7 @@ func completeAuth(opts *config.Options, c *gin.Context, userprofile UserProfile)
30*24*3600, // maxAge
opts.BaseURL+"/", // path
"", // domain
opts.DevProxy == "" && !strings.HasPrefix(opts.ExternalURL, "http://"), // secure
opts.DevProxy == "" && opts.ExternalURL.URL.Scheme != "http", // secure
true, // httpOnly
)

View File

@ -43,7 +43,7 @@ func (o *Options) declareFlags() {
flag.StringVar(&o.DevProxy, "dev", o.DevProxy, "Proxify traffic to this host for static assets")
flag.StringVar(&o.AdminBind, "admin-bind", o.AdminBind, "Bind port/socket for administration interface")
flag.StringVar(&o.Bind, "bind", ":8081", "Bind port/socket")
flag.StringVar(&o.ExternalURL, "externalurl", o.ExternalURL, "Begining of the URL, before the base, that should be used eg. in mails")
flag.Var(&o.ExternalURL, "externalurl", "Begining of the URL, before the base, that should be used eg. in mails")
flag.StringVar(&o.BaseURL, "baseurl", o.BaseURL, "URL prepended to each URL")
flag.StringVar(&o.DefaultNameServer, "default-ns", o.DefaultNameServer, "Adress to the default name server")
flag.Var(&o.StorageEngine, "storage-engine", fmt.Sprintf("Select the storage engine between %v", storage.GetStorageEngines()))

View File

@ -36,6 +36,7 @@ import (
"flag"
"fmt"
"log"
"net/url"
"os"
"path"
"strings"
@ -54,7 +55,7 @@ type Options struct {
// ExternalURL keeps the URL used in communications (such as email,
// ...), when it needs to use complete URL, not only relative parts.
ExternalURL string
ExternalURL URL
// BaseURL is the relative path where begins the root of the app.
BaseURL string
@ -94,11 +95,13 @@ func (o *Options) BuildURL_noescape(url string, args ...interface{}) string {
//
// Should be called only one time.
func ConsolidateConfig() (opts *Options, err error) {
u, _ := url.Parse("http://localhost:8081")
// Define defaults options
opts = &Options{
Bind: ":8081",
AdminBind: "./happydomain.sock",
ExternalURL: "http://localhost:8081",
ExternalURL: URL{URL: u},
BaseURL: "/",
DefaultNameServer: "127.0.0.1:53",
StorageEngine: storage.StorageEngine("leveldb"),
@ -148,6 +151,27 @@ func ConsolidateConfig() (opts *Options, err error) {
opts.BaseURL = ""
}
if opts.ExternalURL.URL.Host == "" || opts.ExternalURL.URL.Scheme == "" {
u, err2 := url.Parse("http://" + opts.ExternalURL.URL.String())
if err2 == nil {
opts.ExternalURL.URL = u
} else {
err = fmt.Errorf("You defined an external URL without a scheme. The expected value is eg. http://localhost:8081")
return
}
}
if len(opts.ExternalURL.URL.Path) > 1 {
if opts.BaseURL != "" && opts.BaseURL != opts.ExternalURL.URL.Path {
err = fmt.Errorf("You defined both baseurl and a path to externalurl that are different. Define only one of those.")
return
}
opts.BaseURL = path.Clean(opts.ExternalURL.URL.Path)
}
opts.ExternalURL.URL.Path = ""
opts.ExternalURL.URL.Fragment = ""
opts.ExternalURL.URL.RawQuery = ""
if len(opts.JWTSecretKey) == 0 {
opts.JWTSecretKey = make([]byte, 32)
_, err = rand.Read(opts.JWTSecretKey)