From 29b0e41218c9e270dc62bbdeef5bd856087b5f0f Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Mon, 1 Jan 2024 19:50:20 +0100 Subject: [PATCH] [overlays] Add WebDAV support for remote Overlay editing Signed-off-by: Knut Ahlers --- authMiddleware.go | 13 +++++++++-- docs/content/overlays/_index.md | 22 ++++++++++++++++++ internal/apimodules/overlays/dav.go | 29 ++++++++++++++++++++++++ internal/apimodules/overlays/overlays.go | 14 ++++++++++++ plugins_core.go | 13 +++++++---- 5 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 internal/apimodules/overlays/dav.go diff --git a/authMiddleware.go b/authMiddleware.go index 1bf9062..a2fa887 100644 --- a/authMiddleware.go +++ b/authMiddleware.go @@ -43,8 +43,17 @@ func fillAuthToken(token *configAuthToken) error { func writeAuthMiddleware(h http.Handler, module string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - token := r.Header.Get("Authorization") - if token == "" { + _, pass, hasBasicAuth := r.BasicAuth() + + var token string + switch { + case hasBasicAuth && pass != "": + token = pass + + case r.Header.Get("Authorization") != "": + token = r.Header.Get("Authorization") + + default: http.Error(w, "auth not successful", http.StatusForbidden) return } diff --git a/docs/content/overlays/_index.md b/docs/content/overlays/_index.md index cb8edd4..e5cce55 100644 --- a/docs/content/overlays/_index.md +++ b/docs/content/overlays/_index.md @@ -40,3 +40,25 @@ Here you can see the Debug Overlay configured with: As those parameters are configured through the URL hash (`#...`) they are never sent to the server, therefore are not logged in any access-logs and exist only in the local URL. So with a custom overlay you would put `https://your-bot.example.com/overlays/myoverlay.html#token=55cdb1e4-c776-4467-8560-a47a4abc55de` into your OBS browser source and your overlay would be able to communicate with the bot. The debug-overlay can be used to view all events received within the bot you can react on in overlays and bot rules. + +## Remote editing Overlays with local Editor + +In order to enable you to edit the overlays remotely when hosting the bot on a server the bot exposes a WebDAV interface you can locally mount and work on using your favorite editor. To mount the WebDAV I recommend [rclone](https://rclone.org/). You will need the URL your bot is available at and a token with `overlays` permission: + +``` +# rclone obscure 55cdb1e4-c776-4467-8560-a47a4abc55de +MqO0FLdbg3txom2IpUMsVVIqnHwYDefms4EKRqoV1MGhCFkBmWnhvVRdqTyCSFtmvP-AYg + +# cat /tmp/rclone.conf +[bot] +type = webdav +url = https://your-bot.example.com/overlays/dav/ +user = dav +pass = MqO0FLdbg3txom2IpUMsVVIqnHwYDefms4EKRqoV1MGhCFkBmWnhvVRdqTyCSFtmvP-AYg + +# rclone --config /tmp/rclone.conf mount bot:/ /tmp/bot-overlays + +# code /tmp/bot-overlays +``` + +What I've done here is to obscure the token (`rclone` wants the token to be in an obscured format), create a config containing the WebDAV remote, mount the WebDAV remote to a local directory and open it with VSCode to edit the overlays. When saving the files locally `rclone` will upload them to the bot and refreshing the overlay in your browser / OBS will give you the new version. diff --git a/internal/apimodules/overlays/dav.go b/internal/apimodules/overlays/dav.go new file mode 100644 index 0000000..9794e6a --- /dev/null +++ b/internal/apimodules/overlays/dav.go @@ -0,0 +1,29 @@ +package overlays + +import ( + "net/http" + "os" + + "github.com/sirupsen/logrus" + "golang.org/x/net/webdav" +) + +func getDAVHandler() http.HandlerFunc { + overlaysDir := os.Getenv("OVERLAYS_DIR") + if ds, err := os.Stat(overlaysDir); err != nil || overlaysDir == "" || !ds.IsDir() { + return http.NotFound + } + + return (&webdav.Handler{ + Prefix: "/overlays/dav", + FileSystem: webdav.Dir(overlaysDir), + LockSystem: webdav.NewMemLS(), + Logger: func(r *http.Request, err error) { + logger := logrus.WithField("module", "overlays-dav") + if err != nil { + logger = logger.WithError(err) + } + logger.Debugf("%s %s", r.Method, r.URL) + }, + }).ServeHTTP +} diff --git a/internal/apimodules/overlays/overlays.go b/internal/apimodules/overlays/overlays.go index 1ff8e77..80dc2e0 100644 --- a/internal/apimodules/overlays/overlays.go +++ b/internal/apimodules/overlays/overlays.go @@ -154,6 +154,20 @@ func Register(args plugins.RegistrationArguments) (err error) { return fmt.Errorf("registering API route: %w", err) } + if err = args.RegisterAPIRoute(plugins.HTTPRouteRegistrationArgs{ + Description: "Shares the overlays folder as WebDAV filesystem", + HandlerFunc: getDAVHandler(), + IsPrefix: true, + Module: "overlays", + Name: "WebDAV Overlays", + Path: "/dav/", + RequiresWriteAuth: true, + ResponseType: plugins.HTTPRouteResponseTypeMultiple, + SkipDocumentation: true, + }); err != nil { + return fmt.Errorf("registering API route: %w", err) + } + if err = args.RegisterAPIRoute(plugins.HTTPRouteRegistrationArgs{ HandlerFunc: handleServeOverlayAsset, IsPrefix: true, diff --git a/plugins_core.go b/plugins_core.go index 0233fcf..06f6861 100644 --- a/plugins_core.go +++ b/plugins_core.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" + "github.com/gorilla/mux" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "gopkg.in/irc.v4" @@ -134,13 +135,15 @@ func registerRoute(route plugins.HTTPRouteRegistrationArgs) error { hdl = writeAuthMiddleware(hdl, route.Module) } + var muxRoute *mux.Route if route.IsPrefix { - r.PathPrefix(route.Path). - Handler(hdl). - Methods(route.Method) + muxRoute = r.PathPrefix(route.Path).Handler(hdl) } else { - r.Handle(route.Path, hdl). - Methods(route.Method) + muxRoute = r.Handle(route.Path, hdl) + } + + if route.Method != "" { + muxRoute.Methods(route.Method) } if !route.SkipDocumentation {