-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathroutes.go
180 lines (159 loc) · 5.4 KB
/
routes.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package foxkit
import (
"context"
"fmt"
"net/http"
"os"
"time"
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v9"
)
// configures the Trusted proxies list
func ConfigRouter(router *gin.Engine, trustedProxy []string) {
if os.Getenv("GIN_MODE") == "release" {
// turn on proxy support
ErrorFatal("Router", router.SetTrustedProxies(trustedProxy))
} else {
// turn off proxy support for debugging
ErrorFatal("Router", router.SetTrustedProxies(nil))
}
}
// returns a static health message
func GetHealth(c *gin.Context) {
c.Data(http.StatusOK, "application/json", []byte(`{"status":"ok"}`))
}
// returns that the server is not a teapot
func ImTeaPot(c *gin.Context) {
c.String(http.StatusTeapot, "418: I'm a teapot")
}
// returns that the combined coffee/tea pot is temporarily out of coffee
func CoffeOut(c *gin.Context) {
c.Data(http.StatusServiceUnavailable, "application/json", []byte(`{"error":"true","message":"Temporary out of coffee, please try again later!"}`))
}
// returns 204 for CORS
func CORS(c *gin.Context) {
c.Status(http.StatusNoContent)
}
// redirects to the given url
func Redirect(url string) gin.HandlerFunc {
return func(c *gin.Context) {
c.Redirect(http.StatusPermanentRedirect, url)
}
}
// starts the router on the given IP and port
func StartRouter(router *gin.Engine, bind string) {
if err := router.Run(bind); err != nil {
ErrorFatal("FoxKit", err)
}
}
// returns true, if the client requested json format, also sets the response to 406, if not
func JsonRequested(c *gin.Context, appName string) bool {
if c.GetHeader("Content-Type") != "application/json" {
c.AbortWithStatus(http.StatusNotAcceptable)
LogEvent(appName, "Received request with wrong Content-Type header")
return false
}
return true
}
// bind the received json to the given struct, sets the status to 400 if false,
// 406 if no json was requested
func BindJson(c *gin.Context, obj interface{}, appName string) bool {
// check if a json was requested
if !JsonRequested(c, appName) {
return false
}
// Bind json, return bad request on error
if err := c.BindJSON(obj); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
LogError(appName, err)
return false
}
return true
}
// Binds an URI to the given struct, sets 400 on false
func BindURI(c *gin.Context, obj interface{}, appName string) bool {
// bind URI and handle error
if err := c.BindUri(obj); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
LogError("FoxBow", err)
return false
}
return true
}
// returns true if an error happened, sets the status to 500 if true
func CheckError(c *gin.Context, err *error, appName string) bool {
if *err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
LogError(appName, *err)
return true
}
return false
}
// checks if the password matches the hash, sets the HTTP code to 500 on DB failure / 401 if the password is wrong
func CheckPassword(c *gin.Context, hash, password *string) bool {
match, err := ComparePasswordAndHash(password, hash)
if CheckError(c, &err, "FoxKit") {
return false
} else if !match {
c.AbortWithStatus(http.StatusUnauthorized)
LogEvent("FoxKit", "loginUser(): Invalid password received")
return false
}
return true
}
// checks if the session is valid, sets the HTTP code to 500 on DB error / 401 on non-valid if false
func CheckSession(ctx *context.Context, c *gin.Context, userID, token *string, redisClient *redis.Client, sessionTime time.Duration) bool {
valid, err := ValidateSession(ctx, userID, token, redisClient, sessionTime)
if CheckError(c, &err, "FoxKit") {
c.AbortWithStatus(http.StatusInternalServerError)
LogError("FoxKit", err)
return false
} else if !valid {
c.AbortWithStatus(http.StatusUnauthorized)
LogEvent("FoxKit", "Received invalid session")
return false
}
return true
}
// checks if both token match, sets the HTTP code to 400 on encoding failure / 401 on token miss match
func CheckToken(c *gin.Context, stringOne, stringTwo *string) bool {
match, err := RandomStringCompare(stringOne, stringTwo)
if err != nil {
c.AbortWithStatus(http.StatusBadRequest)
LogError("FoxKit", err)
return false
} else if !match {
c.AbortWithStatus(http.StatusUnauthorized)
LogEvent("FoxKit", "Received invalid Token")
return false
}
return true
}
// validates the captcha and returns (valid, error) when error is true, http code is set to 500
func ValidateCaptcha(c *gin.Context, secret string, response *string, hostname string, maxAge time.Duration) (bool, bool) {
var captcha HCaptchaResponse
err := captcha.Get(&secret, response)
if CheckError(c, &err, "FoxKit") {
return false, true
}
valid, err := captcha.Valid(hostname, maxAge)
if err != nil {
// the error is caused by a bad request
LogEvent("FoxKit", err.Error())
return false, false
}
return valid, false
}
// checks the string and generates an error message
func CheckStringR(parameter *string, paramName string, minLength, maxLength uint32, asciiOnly bool) (bool, string) {
minSize, maxSize, ascii := CheckStringFull(*parameter, minLength, maxLength)
if !minSize {
return false, fmt.Sprintf("%s too small, must be longer than %d characters", paramName, minLength)
} else if !maxSize {
return false, fmt.Sprintf("%s too long, must be smaller than %d characters", paramName, maxLength)
} else if asciiOnly && !ascii {
return false, fmt.Sprintf("%s contains invalid characters, only ascii characters are allowed", paramName)
}
// everything is ok
return true, ""
}