diff --git a/.gitignore b/.gitignore index 65082f81..c554cbcc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ vendor/* /build/out/ /.sass-cache /extra +/extra.d /src/i18n/*.mo server.key server.csr diff --git a/go/channelling/context.go b/go/channelling/context.go index 1315e2f5..c805a370 100644 --- a/go/channelling/context.go +++ b/go/channelling/context.go @@ -21,14 +21,21 @@ package channelling +import ( + "html/template" +) + type Context struct { - App string // Main client script - Cfg *Config - Host string - Ssl bool - Csp bool - Languages []string - Room string `json:"-"` - Scheme string `json:"-"` - Origin string `json:",omitempty"` + App string // Main client script + Cfg *Config + Host string + Ssl bool + Csp bool + Languages []string + Room string `json:"-"` + Scheme string `json:"-"` + Origin string `json:",omitempty"` + S string `json:",omitempty"` + ExtraDHead template.HTML `json:"-"` + ExtraDBody template.HTML `json:"-"` } diff --git a/html/head.html b/html/head.html index 5efedc9e..f9a95ec3 100644 --- a/html/head.html +++ b/html/head.html @@ -11,4 +11,5 @@ <%template "extra-head" .%> -<%end%> \ No newline at end of file +<%.ExtraDHead%> +<%end%> diff --git a/html/main.html b/html/main.html index 9cf277e3..ed9539c3 100644 --- a/html/main.html +++ b/html/main.html @@ -9,5 +9,6 @@ <%template "extra-body" .%> +<%.ExtraDBody%> -<%end%> \ No newline at end of file +<%end%> diff --git a/server.conf.in b/server.conf.in index 54ba2cb1..1c5d5917 100644 --- a/server.conf.in +++ b/server.conf.in @@ -101,14 +101,20 @@ serverRealm = local ; Full path to an extra templates directory. Templates in this directory ending ; with .html will be parsed on startup and can be used to fill the supported ; extra-* template slots. If the extra folder has a sub folder "static", the -; resources in this static folder will be available as /extra/static/filename +; resources in this static folder will be available as /extra/static/... ; relative to your servers base URL. ;extra = /usr/share/spreed-webrtc-server/extra +; Full path to an extra.d directory. Subfolders in this directory will be +; searched for head.html and body.html on startup. If found, those templates +; will be automatically included for the web client. In addition, +; sub-folder/static will be made available by URL at /extra.d/static//... +; relative to your servers base URL. ; URL relative to the servers base path for a plugin javascript file which is ; automatically loaded on web client start for all users. You can put your ; plugin in the extra/static folder (see above) or provide another folder using ; a front end webserver. Check the doc folder for more info about plugins and ; examples. +;extra.d = /usr/share/spreed-webrtc-server/extra.d ;plugin = extra/static/myplugin.js ; Content-Security-Policy HTTP response header value. ; Spreed WebRTC requires inline styles, WebSocket connection to itself and diff --git a/src/app/spreed-webrtc-server/handler_room.go b/src/app/spreed-webrtc-server/handler_room.go index df968384..58753eed 100644 --- a/src/app/spreed-webrtc-server/handler_room.go +++ b/src/app/spreed-webrtc-server/handler_room.go @@ -70,7 +70,19 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { } // Prepare context to deliver to HTML.. - context := &channelling.Context{Cfg: config, App: "main", Host: r.Host, Scheme: scheme, Ssl: ssl, Csp: csp, Languages: langs, Room: room} + context := &channelling.Context{ + Cfg: config, + App: "main", + Host: r.Host, + Scheme: scheme, + Ssl: ssl, + Csp: csp, + Languages: langs, + Room: room, + S: config.S, + ExtraDHead: templatesExtraDHead, + ExtraDBody: templatesExtraDBody, + } // Get URL parameters. r.ParseForm() @@ -79,10 +91,10 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { // See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details. if _, ok := r.Form["_escaped_fragment_"]; ok { // Render crawlerPage template.. - err = templates.ExecuteTemplate(w, "crawlerPage", &context) + err = templates.ExecuteTemplate(w, "crawlerPage", context) } else { // Render mainPage template. - err = templates.ExecuteTemplate(w, "mainPage", &context) + err = templates.ExecuteTemplate(w, "mainPage", context) } if err != nil { diff --git a/src/app/spreed-webrtc-server/main.go b/src/app/spreed-webrtc-server/main.go index 4051bfba..49fcc2f0 100644 --- a/src/app/spreed-webrtc-server/main.go +++ b/src/app/spreed-webrtc-server/main.go @@ -22,11 +22,13 @@ package main import ( + "bytes" "crypto/rand" "encoding/hex" "flag" "fmt" "html/template" + "io/ioutil" "log" "net/http" _ "net/http/pprof" @@ -53,6 +55,8 @@ var version = "unreleased" var defaultConfig = "./server.conf" var templates *template.Template +var templatesExtraDHead template.HTML +var templatesExtraDBody template.HTML var config *channelling.Config func runner(runtime phoenix.Runtime) error { @@ -208,6 +212,45 @@ func runner(runtime phoenix.Runtime) error { log.Printf("Loaded extra templates from: %s", extraFolder) } + // Load extra.d folder + extraDFolder, err := runtime.GetString("app", "extra.d") + if err == nil { + if !httputils.HasDirPath(extraFolder) { + return fmt.Errorf("Configured extra '%s' is not a directory.", extraFolder) + } + var headBuf bytes.Buffer + var bodyBuf bytes.Buffer + context := &channelling.Context{ + Cfg: config, + } + if extras, err := ioutil.ReadDir(extraDFolder); err == nil { + // ioutil.ReadDir is sorted by name which is what we want here. + for _, extra := range extras { + if !extra.IsDir() { + continue + } + context.S = fmt.Sprintf("extra.d/%s/%s", config.S, extra.Name()) + extraDTemplates := template.New("") + extraDTemplates.Delims("<%", "%>") + extraBase := path.Join(extraDFolder, extra.Name()) + extraDTemplates.ParseFiles(path.Join(extraBase, "head.html"), path.Join(extraBase, "body.html")) + if headTemplate := extraDTemplates.Lookup("head.html"); headTemplate != nil { + if err := headTemplate.Execute(&headBuf, context); err != nil { + log.Println("Failed to parse extra.d template", extraBase, "head.html", err) + } + + } + if bodyTemplate := extraDTemplates.Lookup("body.html"); bodyTemplate != nil { + if err := bodyTemplate.Execute(&bodyBuf, context); err != nil { + log.Println("Failed to parse extra.d template", extraBase, "body.html", err) + } + } + } + } + templatesExtraDHead = template.HTML(headBuf.String()) + templatesExtraDBody = template.HTML(bodyBuf.String()) + } + // Define incoming channeling API limit it byte. Larger messages will be discarded. incomingCodecLimit := 1024 * 1024 // 1MB @@ -326,13 +369,20 @@ func runner(runtime phoenix.Runtime) error { // Add extra/static support if configured and exists. if extraFolder != "" { - extraFolderStatic := path.Join(extraFolder, "static") + extraFolderStatic, _ := filepath.Abs(path.Join(extraFolder, "static")) if _, err = os.Stat(extraFolderStatic); err == nil { r.Handle("/extra/static/{path:.*}", http.StripPrefix(fmt.Sprintf("%sextra", config.B), httputils.FileStaticServer(http.Dir(extraFolder)))) log.Printf("Added URL handler /extra/static/... for static files in %s/...\n", extraFolderStatic) } } + // Add extra.d/static support if configured. + if extraDFolder != "" { + extraDFolderStatic, _ := filepath.Abs(extraDFolder) + r.Handle("/extra.d/static/{ver}/{extra}/{path:.*}", http.StripPrefix(fmt.Sprintf("%sextra.d/static", config.B), rewriteExtraDUrl(httputils.FileStaticServer(http.Dir(extraDFolderStatic))))) + log.Printf("Added URL handler /extra.d/static/... for static files in %s/.../static/... \n", extraDFolderStatic) + } + // Finally add websocket handler. r.Handle("/ws", makeWSHandler(statsManager, sessionManager, codec, channellingAPI, users)) diff --git a/src/app/spreed-webrtc-server/utils.go b/src/app/spreed-webrtc-server/utils.go index b0c6f55b..b8be303e 100644 --- a/src/app/spreed-webrtc-server/utils.go +++ b/src/app/spreed-webrtc-server/utils.go @@ -1,8 +1,11 @@ package main import ( + "fmt" "net/http" + "github.com/gorilla/mux" + "github.com/strukturag/goacceptlanguageparser" ) @@ -15,3 +18,23 @@ func getRequestLanguages(r *http.Request, supportedLanguages []string) []string } return langs } + +func rewriteExtraDUrl(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + extra, ok := vars["extra"] + if !ok { + http.NotFound(w, r) + return + } + path, ok := vars["path"] + if !ok { + http.NotFound(w, r) + return + } + + r.URL.Path = fmt.Sprintf("%s/static/%s", extra, path) + h.ServeHTTP(w, r) + }) +}