-
Notifications
You must be signed in to change notification settings - Fork 0
/
middleware.go
129 lines (112 loc) · 3.32 KB
/
middleware.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
// Copyright (c) 2017-2019 The Bitum developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"net/http"
"net/http/httputil"
"runtime/debug"
"time"
www "github.com/bitum-project/politeia/politeiawww/api/www/v1"
"github.com/bitum-project/politeia/util"
)
// isLoggedIn ensures that a user is logged in before calling the next
// function.
func (p *politeiawww) isLoggedIn(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Debugf("isLoggedIn: %v %v %v %v", remoteAddr(r), r.Method,
r.URL, r.Proto)
id, err := p.getSessionUUID(r)
if err != nil {
util.RespondWithJSON(w, http.StatusUnauthorized, www.ErrorReply{
ErrorCode: int64(www.ErrorStatusNotLoggedIn),
})
return
}
// Check if user is authenticated
if id == "" {
util.RespondWithJSON(w, http.StatusUnauthorized, www.ErrorReply{
ErrorCode: int64(www.ErrorStatusNotLoggedIn),
})
return
}
f(w, r)
}
}
// isLoggedInAsAdmin ensures that a user is logged in as an admin user
// before calling the next function.
func (p *politeiawww) isLoggedInAsAdmin(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Debugf("isLoggedInAsAdmin: %v %v %v %v", remoteAddr(r),
r.Method, r.URL, r.Proto)
// Check if user is admin
isAdmin, err := p.isAdmin(w, r)
if err != nil {
log.Errorf("isLoggedInAsAdmin: isAdmin %v", err)
util.RespondWithJSON(w, http.StatusUnauthorized, www.ErrorReply{
ErrorCode: int64(www.ErrorStatusNotLoggedIn),
})
return
}
if !isAdmin {
util.RespondWithJSON(w, http.StatusForbidden, www.ErrorReply{})
return
}
f(w, r)
}
}
// logging logs all incoming commands before calling the next funxtion.
//
// NOTE: LOGGING WILL LOG PASSWORDS IF TRACING IS ENABLED.
func logging(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Trace incoming request
log.Tracef("%v", newLogClosure(func() string {
trace, err := httputil.DumpRequest(r, true)
if err != nil {
trace = []byte(fmt.Sprintf("logging: "+
"DumpRequest %v", err))
}
return string(trace)
}))
// Log incoming connection
log.Infof("%v %v %v %v", remoteAddr(r), r.Method, r.URL, r.Proto)
f(w, r)
}
}
// closeBody closes the request body.
func closeBody(f http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
f(w, r)
r.Body.Close()
}
}
func remoteAddr(r *http.Request) string {
via := r.RemoteAddr
xff := r.Header.Get(www.Forward)
if xff != "" {
return fmt.Sprintf("%v via %v", xff, r.RemoteAddr)
}
return via
}
// recoverMiddleware recovers from any panics by logging the panic and
// returning a 500 response.
func recoverMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
errorCode := time.Now().Unix()
log.Criticalf("%v %v %v %v Internal error %v: %v", remoteAddr(r),
r.Method, r.URL, r.Proto, errorCode, err)
log.Criticalf("Stacktrace (THIS IS AN ACTUAL PANIC): %s",
debug.Stack())
util.RespondWithJSON(w, http.StatusInternalServerError,
www.ErrorReply{
ErrorCode: errorCode,
})
}
}()
next.ServeHTTP(w, r)
})
}