-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
security.go
110 lines (95 loc) · 3.49 KB
/
security.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
package main
import (
"html/template"
"log"
"net/http"
"strings"
"github.com/DblK/tinshop/utils"
)
// CORSMiddleware is a middleware to ensure right CORS headers
func (s *TinShop) CORSMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.RequestURI, "/api/") {
w.Header().Set("Access-Control-Allow-Origin", s.Shop.Config.RootShop())
w.Header().Set("Vary", "Origin")
} else {
w.Header().Set("Access-Control-Allow-Origin", "*")
}
if r.Method == http.MethodOptions {
return
}
next.ServeHTTP(w, r)
})
}
// TinfoilMiddleware is a middleware to ensure not forged query and real tinfoil client
func (s *TinShop) TinfoilMiddleware(next http.Handler) http.Handler {
shopTemplate, _ := template.ParseFS(assetData, "assets/shop.tmpl")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify all headers
headers := r.Header
if s.Shop.Config.DebugNoSecurity() {
next.ServeHTTP(w, r)
return
}
if r.RequestURI == "/" || utils.IsValidFilter(cleanPath(r.RequestURI)) {
// Check for blacklist/whitelist
var uid = strings.Join(headers["Uid"], "")
if s.Shop.Config.IsBlacklisted(uid) {
log.Println("[Security] Blacklisted switch detected...", uid)
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
// TODO: Here implement usage of IsWhitelisted
// Check for banned theme
var theme = strings.Join(headers["Theme"], "")
if s.Shop.Config.IsBannedTheme(theme) {
log.Println("[Security] Banned theme detected...", uid, theme)
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
// No User-Agent for tinfoil app
if headers["User-Agent"] != nil {
log.Println("[Security] User-Agent detected...")
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
// Be sure all tinfoil headers are present
if headers["Theme"] == nil || headers["Uid"] == nil || headers["Version"] == nil || headers["Language"] == nil || headers["Hauth"] == nil || headers["Uauth"] == nil {
log.Println("[Security] Missing some expected headers...")
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
// Enforce true tinfoil queries
// TODO: Check Uauth and Hauth headers
log.Printf("Switch %s, %s, %s, %s, %s, %s requesting %s", headers["Theme"], headers["Uid"], headers["Version"], headers["Language"], headers["Hauth"], headers["Uauth"], r.RequestURI)
// Check user password
if s.Shop.Config.ForwardAuthURL() != "" && headers["Authorization"] != nil {
log.Println("[Security] Forwarding auth to", s.Shop.Config.ForwardAuthURL())
client := &http.Client{}
req, _ := http.NewRequest("GET", s.Shop.Config.ForwardAuthURL(), nil)
req.Header.Add("Authorization", strings.Join(headers["Authorization"], ""))
req.Header.Add("Device-Id", strings.Join(headers["Uid"], ""))
resp, err := client.Do(req)
if err != nil {
log.Print(err)
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
}
}
// Call the next handler, which can be another middleware in the chain, or the final handler.
next.ServeHTTP(w, r)
})
}
func cleanPath(path string) string {
actualPath := path[1:]
if path[len(path)-1:] == "/" {
actualPath = path[1 : len(path)-1]
}
return actualPath
}