-
Notifications
You must be signed in to change notification settings - Fork 221
Expand file tree
/
Copy pathregister.go
More file actions
153 lines (125 loc) · 3.98 KB
/
register.go
File metadata and controls
153 lines (125 loc) · 3.98 KB
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
// Package register allows for user registration.
package register
import (
"context"
"net/http"
"sort"
"github.com/pkg/errors"
"github.com/volatiletech/authboss"
"golang.org/x/crypto/bcrypt"
)
// Pages
const (
PageRegister = "register"
)
func init() {
authboss.RegisterModule("register", &Register{})
}
// Register module.
type Register struct {
*authboss.Authboss
}
// Init the module.
func (r *Register) Init(ab *authboss.Authboss) (err error) {
r.Authboss = ab
if _, ok := ab.Config.Storage.Server.(authboss.CreatingServerStorer); !ok {
return errors.New("register module activated but storer could not be upgraded to CreatingServerStorer")
}
if err := ab.Config.Core.ViewRenderer.Load(PageRegister); err != nil {
return err
}
sort.Strings(ab.Config.Modules.RegisterPreserveFields)
ab.Config.Core.Router.Get("/register", ab.Config.Core.ErrorHandler.Wrap(r.Get))
ab.Config.Core.Router.Post("/register", ab.Config.Core.ErrorHandler.Wrap(r.Post))
return nil
}
// Get the register page
func (r *Register) Get(w http.ResponseWriter, req *http.Request) error {
return r.Config.Core.Responder.Respond(w, req, http.StatusOK, PageRegister, nil)
}
// Post to the register page
func (r *Register) Post(w http.ResponseWriter, req *http.Request) error {
logger := r.RequestLogger(req)
validatable, err := r.Core.BodyReader.Read(PageRegister, req)
if err != nil {
return err
}
var arbitrary map[string]string
var preserve map[string]string
if arb, ok := validatable.(authboss.ArbitraryValuer); ok {
arbitrary = arb.GetValues()
preserve = make(map[string]string)
for k, v := range arbitrary {
if hasString(r.Config.Modules.RegisterPreserveFields, k) {
preserve[k] = v
}
}
}
errs := validatable.Validate()
if errs != nil {
logger.Info("registration validation failed")
data := authboss.HTMLData{
authboss.DataValidation: authboss.ErrorMap(errs),
}
if preserve != nil {
data[authboss.DataPreserve] = preserve
}
return r.Config.Core.Responder.Respond(w, req, http.StatusOK, PageRegister, data)
}
// Get values from request
userVals := authboss.MustHaveUserValues(validatable)
pid, password := userVals.GetPID(), userVals.GetPassword()
// Put values into newly created user for storage
storer := authboss.EnsureCanCreate(r.Config.Storage.Server)
user := authboss.MustBeAuthable(storer.New(req.Context()))
pass, err := bcrypt.GenerateFromPassword([]byte(password), r.Config.Modules.BCryptCost)
if err != nil {
return err
}
user.PutPID(pid)
user.PutPassword(string(pass))
if arbUser, ok := user.(authboss.ArbitraryUser); ok && arbitrary != nil {
arbUser.PutArbitrary(arbitrary)
}
err = storer.Create(req.Context(), user)
switch {
case err == authboss.ErrUserFound:
logger.Infof("user %s attempted to re-register", pid)
errs = []error{errors.New("user already exists")}
data := authboss.HTMLData{
authboss.DataValidation: authboss.ErrorMap(errs),
}
if preserve != nil {
data[authboss.DataPreserve] = preserve
}
return r.Config.Core.Responder.Respond(w, req, http.StatusOK, PageRegister, data)
case err != nil:
return err
}
req = req.WithContext(context.WithValue(req.Context(), authboss.CTXKeyUser, user))
handled, err := r.Events.FireAfter(authboss.EventRegister, w, req)
if err != nil {
return err
} else if handled {
return nil
}
// Log the user in, but only if the response wasn't handled previously
// by a module like confirm.
authboss.PutSession(w, authboss.SessionKey, pid)
logger.Infof("registered and logged in user %s", pid)
ro := authboss.RedirectOptions{
Code: http.StatusTemporaryRedirect,
Success: "Account successfully created, you are now logged in",
RedirectPath: r.Config.Paths.RegisterOK,
}
return r.Config.Core.Redirector.Redirect(w, req, ro)
}
// hasString checks to see if a sorted (ascending) array of
// strings contains a string
func hasString(arr []string, s string) bool {
index := sort.SearchStrings(arr, s)
if index < 0 || index >= len(arr) {
return false
}
return arr[index] == s
}