[overlays] Add WebDAV support for remote Overlay editing

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2024-01-01 19:50:20 +01:00
parent c78356f68f
commit 29b0e41218
Signed by: luzifer
SSH key fingerprint: SHA256:/xtE5lCgiRDQr8SLxHMS92ZBlACmATUmF1crK16Ks4E
5 changed files with 84 additions and 7 deletions

View file

@ -43,8 +43,17 @@ func fillAuthToken(token *configAuthToken) error {
func writeAuthMiddleware(h http.Handler, module string) http.Handler { func writeAuthMiddleware(h http.Handler, module string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization") _, pass, hasBasicAuth := r.BasicAuth()
if token == "" {
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) http.Error(w, "auth not successful", http.StatusForbidden)
return return
} }

View file

@ -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. 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. 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.

View file

@ -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
}

View file

@ -154,6 +154,20 @@ func Register(args plugins.RegistrationArguments) (err error) {
return fmt.Errorf("registering API route: %w", err) 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{ if err = args.RegisterAPIRoute(plugins.HTTPRouteRegistrationArgs{
HandlerFunc: handleServeOverlayAsset, HandlerFunc: handleServeOverlayAsset,
IsPrefix: true, IsPrefix: true,

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/gorilla/mux"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/irc.v4" "gopkg.in/irc.v4"
@ -134,13 +135,15 @@ func registerRoute(route plugins.HTTPRouteRegistrationArgs) error {
hdl = writeAuthMiddleware(hdl, route.Module) hdl = writeAuthMiddleware(hdl, route.Module)
} }
var muxRoute *mux.Route
if route.IsPrefix { if route.IsPrefix {
r.PathPrefix(route.Path). muxRoute = r.PathPrefix(route.Path).Handler(hdl)
Handler(hdl).
Methods(route.Method)
} else { } else {
r.Handle(route.Path, hdl). muxRoute = r.Handle(route.Path, hdl)
Methods(route.Method) }
if route.Method != "" {
muxRoute.Methods(route.Method)
} }
if !route.SkipDocumentation { if !route.SkipDocumentation {