forked from volatiletech/authboss
-
Notifications
You must be signed in to change notification settings - Fork 0
/
events.go
104 lines (90 loc) · 2.87 KB
/
events.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
package authboss
import (
"net/http"
)
//go:generate stringer -output stringers.go -type "Event"
// Event type is for describing events
type Event int
// Event kinds
const (
EventRegister Event = iota
EventAuth
// EventAuthHijack is used to steal the authentication process after a
// successful auth but before any session variable has been put in.
// Most useful for defining an additional step for authentication
// (like 2fa). It needs to be separate to EventAuth because other modules
// do checks that would also interrupt event handlers with an authentication
// failure so there's an ordering problem.
EventAuthHijack
EventOAuth2
EventAuthFail
EventOAuth2Fail
EventRecoverStart
EventRecoverEnd
EventGetUser
EventGetUserSession
EventPasswordReset
EventLockUser
)
// EventHandler reacts to events that are fired by Authboss controllers.
// These controllers will normally process a request by themselves, but if
// there is special consideration for example a successful login, but the
// user is locked, the lock module's controller may seize control over the
// request.
//
// Very much a controller level middleware.
type EventHandler func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error)
// Events is a collection of Events that fire before and after certain methods.
type Events struct {
before map[Event][]EventHandler
after map[Event][]EventHandler
}
// NewEvents creates a new set of before and after Events.
func NewEvents() *Events {
return &Events{
before: make(map[Event][]EventHandler),
after: make(map[Event][]EventHandler),
}
}
// Before event, call f.
func (c *Events) Before(e Event, f EventHandler) {
events := c.before[e]
events = append(events, f)
c.before[e] = events
}
// After event, call f.
func (c *Events) After(e Event, f EventHandler) {
events := c.after[e]
events = append(events, f)
c.after[e] = events
}
// FireBefore executes the handlers that were registered to fire before
// the event passed in.
//
// If it encounters an error it will stop immediately without calling
// other handlers.
//
// If a handler handles the request, it will pass this information both
// to handlers further down the chain (to let them know that w has been used)
// as well as set w to nil as a precaution.
func (c *Events) FireBefore(e Event, w http.ResponseWriter, r *http.Request) (bool, error) {
return c.call(c.before[e], w, r)
}
// FireAfter event to all the Events with a context. The error can safely be
// ignored as it is logged.
func (c *Events) FireAfter(e Event, w http.ResponseWriter, r *http.Request) (bool, error) {
return c.call(c.after[e], w, r)
}
func (c *Events) call(evs []EventHandler, w http.ResponseWriter, r *http.Request) (bool, error) {
handled := false
for _, fn := range evs {
interrupt, err := fn(w, r, handled)
if err != nil {
return false, err
}
if interrupt {
handled = true
}
}
return handled, nil
}