-
Notifications
You must be signed in to change notification settings - Fork 0
/
ui_embed.go
116 lines (108 loc) · 2.74 KB
/
ui_embed.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package ui_embed
import (
"embed"
"fmt"
"github.com/99designs/gqlgen/graphql/playground"
"io/fs"
"net/http"
"strings"
)
// UI routes list
//go:generate go run routegen/routegen.go
// UI embedded files
//
//go:embed embed
var uiFiles embed.FS
// GetUISanitizer removes sensitive values from a request, to ensure clients can't do shenanigans with them
func GetUISanitizer(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
r.Header.Set("page_select", "")
r.Header.Set("page_extra", "")
r.Header.Set("proxyTo", "")
handler(w, r)
}
}
func isIdentifierChar(c rune) bool {
return c == '_' || c == '-' ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9')
}
func GetUIHandler() http.Handler {
subFiles, _ := fs.Sub(uiFiles, "embed/dist")
subServer := http.FileServer(http.FS(subFiles))
indexHTML, err := uiFiles.ReadFile("embed/dist/index.html")
if err != nil {
panic(fmt.Errorf("error reading embedded UI files: %w", err))
}
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
isRoute := false
for _, rt := range uiRoutes {
if r.URL.Path == rt {
isRoute = true
break
}
}
if (r.URL.Path == "/") ||
(r.URL.Path == "/index.html") ||
isRoute {
pageSel := r.Header.Get("page_select")
if pageSel == "" {
unauth := r.Header.Get("unauthorized")
if unauth == "true" {
pageSel = "unauthorized"
}
}
for _, c := range pageSel {
if !isIdentifierChar(c) {
pageSel = "unauthorized"
break
}
}
dataValues := r.Header.Values("page_extra")
if pageSel != "" {
dataValues = append(dataValues, fmt.Sprintf("page_select=%s", pageSel))
}
if len(dataValues) == 0 {
_, _ = w.Write(indexHTML)
} else {
replaceText := ""
for _, v := range dataValues {
splitV := strings.SplitN(v, "=", 2)
if len(splitV) != 2 {
continue
}
checkOK := true
for _, s := range []string{splitV[0], splitV[1]} {
for _, c := range s {
if !isIdentifierChar(c) {
checkOK = false
break
}
}
}
if !checkOK {
continue
}
replaceText += fmt.Sprintf("\"%s\": \"%s\", ", splitV[0], splitV[1])
}
repHTML := strings.Replace(string(indexHTML), "//$!&@SERVER_DATA@&!$//", replaceText, 1)
_, _ = w.Write([]byte(repHTML))
}
} else {
subServer.ServeHTTP(w, r)
}
})
return mux
}
func PlaygroundHandler(w http.ResponseWriter, req *http.Request) {
p := req.URL.Query().Get("proxyTo")
endpoint := "/query"
title := "GraphQL Playground"
if p != "" {
endpoint = fmt.Sprintf("/proxy/%s/query", p)
title = fmt.Sprintf("GraphQL Playground (%s)", p)
}
playground.Handler(title, endpoint)(w, req)
}