From afb1d12c3b7647e89617449a6ee2fe04bd6eac02 Mon Sep 17 00:00:00 2001
From: Lea Anthony
Date: Sat, 2 Oct 2021 14:04:46 +1000
Subject: [PATCH] [v2] Add meta tag to control script injection behaviour
---
...rver_dev.go => assetserver_browser_dev.go} | 52 ++++++-------
.../assetserver/assetserver_desktop.go | 43 +++++++----
v2/internal/frontend/assetserver/common.go | 73 +++++++++++++++++-
.../frontend/assetserver/common_test.go | 70 +++++++++++++++++
v2/internal/frontend/devserver/devserver.go | 4 +-
website/docs/guides/frontend.mdx | 77 +++++++++++++++++++
6 files changed, 274 insertions(+), 45 deletions(-)
rename v2/internal/frontend/assetserver/{assetserver_dev.go => assetserver_browser_dev.go} (50%)
create mode 100644 v2/internal/frontend/assetserver/common_test.go
create mode 100644 website/docs/guides/frontend.mdx
diff --git a/v2/internal/frontend/assetserver/assetserver_dev.go b/v2/internal/frontend/assetserver/assetserver_browser_dev.go
similarity index 50%
rename from v2/internal/frontend/assetserver/assetserver_dev.go
rename to v2/internal/frontend/assetserver/assetserver_browser_dev.go
index 8ab9ec918..ffe758c49 100644
--- a/v2/internal/frontend/assetserver/assetserver_dev.go
+++ b/v2/internal/frontend/assetserver/assetserver_browser_dev.go
@@ -21,63 +21,63 @@ import (
"os"
)
-type AssetServer struct {
- indexFile []byte
+type BrowserAssetServer struct {
runtimeJS []byte
assetdir string
appOptions *options.App
}
-func NewAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*AssetServer, error) {
- result := &AssetServer{
+func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) {
+ result := &BrowserAssetServer{
assetdir: assetdir,
appOptions: appOptions,
}
- err := result.init()
- if err != nil {
- return nil, err
- }
-
var buffer bytes.Buffer
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
buffer.Write(runtime.RuntimeDesktopJS)
result.runtimeJS = buffer.Bytes()
- err = result.init()
- return result, err
+ return result, nil
}
-func (a *AssetServer) loadFileFromDisk(filename string) ([]byte, error) {
+func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) {
return os.ReadFile(filepath.Join(a.assetdir, filename))
}
-func (a *AssetServer) init() error {
- var err error
- a.indexFile, err = a.loadFileFromDisk("index.html")
+func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
+ indexHTML, err := a.loadFileFromDisk("index.html")
if err != nil {
- return err
+ return nil, err
}
- a.indexFile, err = injectHTML(string(a.indexFile), ``)
+ indexHTML, err = injectHTML(string(indexHTML), ``)
if err != nil {
- return err
+ return nil, err
}
- a.indexFile, err = injectHTML(string(a.indexFile), ``)
+ wailsOptions, err := extractOptions(indexHTML)
if err != nil {
- return err
+ return nil, err
}
- a.indexFile, err = injectHTML(string(a.indexFile), ``)
- if err != nil {
- return err
+ if wailsOptions.disableRuntimeInjection == false {
+ indexHTML, err = injectHTML(string(indexHTML), ``)
+ if err != nil {
+ return nil, err
+ }
}
- return nil
+ if wailsOptions.disableBindingsInjection == false {
+ indexHTML, err = injectHTML(string(indexHTML), ``)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return indexHTML, nil
}
-func (a *AssetServer) Load(filename string) ([]byte, string, error) {
+func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
var content []byte
var err error
switch filename {
case "/":
- content = a.indexFile
+ content, err = a.processIndexHTML()
case "/wails/runtime.js":
content = a.runtimeJS
case "/wails/ipc.js":
diff --git a/v2/internal/frontend/assetserver/assetserver_desktop.go b/v2/internal/frontend/assetserver/assetserver_desktop.go
index 557fbe958..8a7039782 100644
--- a/v2/internal/frontend/assetserver/assetserver_desktop.go
+++ b/v2/internal/frontend/assetserver/assetserver_desktop.go
@@ -10,13 +10,13 @@ import (
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/logger"
"io/fs"
+ "log"
"path/filepath"
"strings"
)
type DesktopAssetServer struct {
assets debme.Debme
- indexFile []byte
runtimeJS []byte
assetdir string
logger *logger.Logger
@@ -106,27 +106,42 @@ func (a *DesktopAssetServer) init(assets embed.FS) error {
if err != nil {
return err
}
- indexHTML, err := a.assets.ReadFile("index.html")
- if err != nil {
- return err
- }
- a.indexFile, err = injectHTML(string(indexHTML), ``)
- if err != nil {
- return err
- }
- a.indexFile, err = injectHTML(string(a.indexFile), ``)
- if err != nil {
- return err
- }
return nil
}
+func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) {
+ indexHTML, err := a.ReadFile("index.html")
+ if err != nil {
+ return nil, err
+ }
+ wailsOptions, err := extractOptions(indexHTML)
+ if err != nil {
+ log.Fatal(err)
+ return nil, err
+ }
+ fmt.Printf("%+v\n", wailsOptions)
+ if wailsOptions.disableRuntimeInjection == false {
+ indexHTML, err = injectHTML(string(indexHTML), ``)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if wailsOptions.disableBindingsInjection == false {
+ indexHTML, err = injectHTML(string(indexHTML), ``)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return indexHTML, nil
+}
+
func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) {
var content []byte
var err error
switch filename {
case "/":
- content = a.indexFile
+ content, err = a.processIndexHTML()
case "/wails/runtime.js":
content = a.runtimeJS
case "/wails/ipc.js":
diff --git a/v2/internal/frontend/assetserver/common.go b/v2/internal/frontend/assetserver/common.go
index 826aee4c3..1d9c270ef 100644
--- a/v2/internal/frontend/assetserver/common.go
+++ b/v2/internal/frontend/assetserver/common.go
@@ -3,19 +3,86 @@ package assetserver
import (
"bytes"
"fmt"
+ "golang.org/x/net/html"
"strings"
)
+type optionType string
+
+const (
+ noAutoInject optionType = "noautoinject"
+ noAutoInjectRuntime optionType = "noautoinjectruntime"
+ noAutoInjectBindings optionType = "noautoinjectbindings"
+)
+
+type Options struct {
+ disableRuntimeInjection bool
+ disableBindingsInjection bool
+}
+
+func newOptions(optionString string) *Options {
+ var result = &Options{}
+ optionString = strings.ToLower(optionString)
+ options := strings.Split(optionString, ",")
+ for _, option := range options {
+ switch optionType(strings.TrimSpace(option)) {
+ case noAutoInject:
+ result.disableRuntimeInjection = true
+ result.disableBindingsInjection = true
+ case noAutoInjectBindings:
+ result.disableBindingsInjection = true
+ case noAutoInjectRuntime:
+ result.disableRuntimeInjection = true
+ }
+ }
+ return result
+}
+
func injectHTML(input string, html string) ([]byte, error) {
- splits := strings.Split(input, "
+
+ Please enter your name below �
+
+
+
+
+
+
+")
+ splits := strings.Split(input, "")
if len(splits) != 2 {
- return nil, fmt.Errorf("unable to locate a tag in your html")
+ return nil, fmt.Errorf("unable to locate a tag in your html")
}
var result bytes.Buffer
result.WriteString(splits[0])
result.WriteString(html)
- result.WriteString("")
+ result.WriteString("")
result.WriteString(splits[1])
return result.Bytes(), nil
}
+
+func extractOptions(htmldata []byte) (*Options, error) {
+ doc, err := html.Parse(bytes.NewReader(htmldata))
+ if err != nil {
+ return nil, err
+ }
+ var extractor func(*html.Node) *Options
+ extractor = func(node *html.Node) *Options {
+ if node.Type == html.ElementNode && node.Data == "meta" {
+ isWailsOptionsTag := false
+ wailsOptions := ""
+ for _, attr := range node.Attr {
+ if isWailsOptionsTag && attr.Key == "content" {
+ wailsOptions = attr.Val
+ }
+ if attr.Val == "wails-options" {
+ isWailsOptionsTag = true
+ }
+ }
+ return newOptions(wailsOptions)
+ }
+ for child := node.FirstChild; child != nil; child = child.NextSibling {
+ result := extractor(child)
+ if result != nil {
+ return result
+ }
+ }
+ return nil
+ }
+ result := extractor(doc)
+ if result == nil {
+ result = &Options{}
+ }
+ return result, nil
+}
diff --git a/v2/internal/frontend/assetserver/common_test.go b/v2/internal/frontend/assetserver/common_test.go
new file mode 100644
index 000000000..2c20b672e
--- /dev/null
+++ b/v2/internal/frontend/assetserver/common_test.go
@@ -0,0 +1,70 @@
+package assetserver
+
+import (
+ "reflect"
+ "testing"
+)
+
+const realHTML = `
+
+