2015-03-16 23:42:45 +02:00
|
|
|
// Package mocks defines implemented interfaces for testing modules
|
2015-01-24 02:24:34 +02:00
|
|
|
package mocks
|
|
|
|
|
2015-01-25 08:19:22 +02:00
|
|
|
import (
|
2017-02-24 02:13:25 +02:00
|
|
|
"context"
|
2015-08-02 20:51:35 +02:00
|
|
|
"io"
|
2015-01-25 08:19:22 +02:00
|
|
|
"net/http"
|
2015-08-02 20:51:35 +02:00
|
|
|
"net/url"
|
|
|
|
"strings"
|
2015-02-11 09:03:02 +02:00
|
|
|
"time"
|
2015-01-25 08:19:22 +02:00
|
|
|
|
2017-02-22 01:04:30 +02:00
|
|
|
"github.com/pkg/errors"
|
2017-07-31 04:39:33 +02:00
|
|
|
"github.com/volatiletech/authboss"
|
2015-01-25 08:19:22 +02:00
|
|
|
)
|
2015-01-24 02:24:34 +02:00
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// User represents all possible fields a authboss User may have
|
|
|
|
type User struct {
|
2015-02-11 09:03:02 +02:00
|
|
|
Username string
|
|
|
|
Email string
|
|
|
|
Password string
|
|
|
|
RecoverToken string
|
|
|
|
RecoverTokenExpiry time.Time
|
2015-02-16 23:27:29 +02:00
|
|
|
ConfirmToken string
|
|
|
|
Confirmed bool
|
2018-02-28 07:20:55 +02:00
|
|
|
AttemptCount int
|
|
|
|
LastAttempt time.Time
|
|
|
|
Locked time.Time
|
2018-03-09 04:39:51 +02:00
|
|
|
|
|
|
|
OAuth2UID string
|
|
|
|
OAuth2Provider string
|
|
|
|
OAuth2Token string
|
|
|
|
OAuth2Refresh string
|
|
|
|
OAuth2Expiry time.Time
|
2018-02-26 01:20:57 +02:00
|
|
|
|
|
|
|
Arbitrary map[string]string
|
2015-01-24 02:24:34 +02:00
|
|
|
}
|
|
|
|
|
2018-03-06 03:47:11 +02:00
|
|
|
func (m User) GetPID() string { return m.Email }
|
|
|
|
func (m User) GetEmail() string { return m.Email }
|
|
|
|
func (m User) GetUsername() string { return m.Username }
|
|
|
|
func (m User) GetPassword() string { return m.Password }
|
|
|
|
func (m User) GetRecoverToken() string { return m.RecoverToken }
|
|
|
|
func (m User) GetRecoverExpiry() time.Time { return m.RecoverTokenExpiry }
|
|
|
|
func (m User) GetConfirmToken() string { return m.ConfirmToken }
|
|
|
|
func (m User) GetConfirmed() bool { return m.Confirmed }
|
|
|
|
func (m User) GetAttemptCount() int { return m.AttemptCount }
|
|
|
|
func (m User) GetLastAttempt() time.Time { return m.LastAttempt }
|
|
|
|
func (m User) GetLocked() time.Time { return m.Locked }
|
2018-03-09 04:39:51 +02:00
|
|
|
func (m User) IsOAuth2User() bool { return len(m.OAuth2Provider) != 0 }
|
|
|
|
func (m User) GetOAuth2UID() string { return m.OAuth2UID }
|
|
|
|
func (m User) GetOAuth2Provider() string { return m.OAuth2Provider }
|
|
|
|
func (m User) GetOAuth2AccessToken() string { return m.OAuth2Token }
|
|
|
|
func (m User) GetOAuth2RefreshToken() string { return m.OAuth2Refresh }
|
|
|
|
func (m User) GetOAuth2Expiry() time.Time { return m.OAuth2Expiry }
|
2018-03-06 03:47:11 +02:00
|
|
|
func (m User) GetArbitrary() map[string]string { return m.Arbitrary }
|
2018-02-16 20:31:55 +02:00
|
|
|
|
2018-02-20 18:58:59 +02:00
|
|
|
func (m *User) PutPID(email string) { m.Email = email }
|
|
|
|
func (m *User) PutUsername(username string) { m.Username = username }
|
|
|
|
func (m *User) PutEmail(email string) { m.Email = email }
|
|
|
|
func (m *User) PutPassword(password string) { m.Password = password }
|
|
|
|
func (m *User) PutRecoverToken(recoverToken string) { m.RecoverToken = recoverToken }
|
2018-03-06 03:47:11 +02:00
|
|
|
func (m *User) PutRecoverExpiry(recoverTokenExpiry time.Time) {
|
2017-02-24 02:13:25 +02:00
|
|
|
m.RecoverTokenExpiry = recoverTokenExpiry
|
2015-03-14 01:23:43 +02:00
|
|
|
}
|
2018-02-20 18:58:59 +02:00
|
|
|
func (m *User) PutConfirmToken(confirmToken string) { m.ConfirmToken = confirmToken }
|
|
|
|
func (m *User) PutConfirmed(confirmed bool) { m.Confirmed = confirmed }
|
2018-02-28 07:20:55 +02:00
|
|
|
func (m *User) PutAttemptCount(attemptCount int) { m.AttemptCount = attemptCount }
|
|
|
|
func (m *User) PutLastAttempt(attemptTime time.Time) { m.LastAttempt = attemptTime }
|
|
|
|
func (m *User) PutLocked(locked time.Time) { m.Locked = locked }
|
2018-03-09 04:39:51 +02:00
|
|
|
func (m *User) PutOAuth2UID(uid string) { m.OAuth2UID = uid }
|
|
|
|
func (m *User) PutOAuth2Provider(provider string) { m.OAuth2Provider = provider }
|
|
|
|
func (m *User) PutOAuth2AccessToken(token string) { m.OAuth2Token = token }
|
|
|
|
func (m *User) PutOAuth2RefreshToken(refresh string) { m.OAuth2Refresh = refresh }
|
|
|
|
func (m *User) PutOAuth2Expiry(expiry time.Time) { m.OAuth2Expiry = expiry }
|
2018-02-26 01:20:57 +02:00
|
|
|
func (m *User) PutArbitrary(arb map[string]string) { m.Arbitrary = arb }
|
2015-03-14 01:23:43 +02:00
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// ServerStorer should be valid for any module storer defined in authboss.
|
|
|
|
type ServerStorer struct {
|
2018-01-30 02:24:42 +02:00
|
|
|
Users map[string]*User
|
2017-02-24 02:13:25 +02:00
|
|
|
RMTokens map[string][]string
|
|
|
|
}
|
2015-03-14 01:23:43 +02:00
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// NewServerStorer constructor
|
|
|
|
func NewServerStorer() *ServerStorer {
|
|
|
|
return &ServerStorer{
|
2018-01-30 02:24:42 +02:00
|
|
|
Users: make(map[string]*User),
|
2017-02-24 02:13:25 +02:00
|
|
|
RMTokens: make(map[string][]string),
|
2015-03-14 01:23:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 01:20:57 +02:00
|
|
|
// New constructs a blank user to later be created
|
|
|
|
func (s *ServerStorer) New(context.Context) authboss.User {
|
|
|
|
return &User{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a user
|
|
|
|
func (s *ServerStorer) Create(ctx context.Context, user authboss.User) error {
|
|
|
|
u := user.(*User)
|
|
|
|
if _, ok := s.Users[u.Email]; ok {
|
|
|
|
return authboss.ErrUserFound
|
|
|
|
}
|
|
|
|
s.Users[u.Email] = u
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-02-20 18:58:59 +02:00
|
|
|
// Load a user
|
|
|
|
func (s *ServerStorer) Load(ctx context.Context, key string) (authboss.User, error) {
|
|
|
|
user, ok := s.Users[key]
|
|
|
|
if ok {
|
|
|
|
return user, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, authboss.ErrUserNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save a user
|
|
|
|
func (s *ServerStorer) Save(ctx context.Context, user authboss.User) error {
|
|
|
|
u := user.(*User)
|
2018-02-26 01:20:57 +02:00
|
|
|
if _, ok := s.Users[u.Email]; !ok {
|
|
|
|
return authboss.ErrUserNotFound
|
|
|
|
}
|
2018-02-20 18:58:59 +02:00
|
|
|
s.Users[u.Email] = u
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-03-09 04:39:51 +02:00
|
|
|
// NewFromOAuth2 finds a user with the given details, or returns a new one
|
|
|
|
func (s *ServerStorer) NewFromOAuth2(ctx context.Context, provider string, details map[string]string) (authboss.OAuth2User, error) {
|
|
|
|
uid := details["uid"]
|
|
|
|
email := details["email"]
|
|
|
|
name := details["name"]
|
|
|
|
pid := authboss.MakeOAuth2PID(provider, uid)
|
|
|
|
|
|
|
|
u, ok := s.Users[pid]
|
|
|
|
if ok {
|
|
|
|
u.Username = name
|
|
|
|
u.Email = email
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &User{
|
|
|
|
OAuth2UID: uid,
|
|
|
|
OAuth2Provider: provider,
|
|
|
|
Email: email,
|
|
|
|
Username: name,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SaveOAuth2 creates a user if not found, or updates one that exists.
|
|
|
|
func (s *ServerStorer) SaveOAuth2(ctx context.Context, user authboss.OAuth2User) error {
|
|
|
|
u := user.(*User)
|
|
|
|
|
|
|
|
pid := authboss.MakeOAuth2PID(u.OAuth2Provider, u.OAuth2UID)
|
|
|
|
// Since we don't have to differentiate between insert/update in a map, we just overwrite
|
|
|
|
s.Users[pid] = u
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-03-06 03:47:11 +02:00
|
|
|
// LoadByConfirmToken finds a user by his confirm token
|
|
|
|
func (s *ServerStorer) LoadByConfirmToken(ctx context.Context, token string) (authboss.ConfirmableUser, error) {
|
2018-02-27 17:14:30 +02:00
|
|
|
for _, v := range s.Users {
|
|
|
|
if v.ConfirmToken == token {
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, authboss.ErrUserNotFound
|
|
|
|
}
|
|
|
|
|
2018-03-06 03:47:11 +02:00
|
|
|
// LoadByRecoverToken finds a user by his recover token
|
|
|
|
func (s *ServerStorer) LoadByRecoverToken(ctx context.Context, token string) (authboss.RecoverableUser, error) {
|
|
|
|
for _, v := range s.Users {
|
|
|
|
if v.RecoverToken == token {
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, authboss.ErrUserNotFound
|
|
|
|
}
|
|
|
|
|
2018-03-08 01:13:06 +02:00
|
|
|
// AddRememberToken for remember me
|
|
|
|
func (s *ServerStorer) AddRememberToken(key, token string) error {
|
|
|
|
arr := s.RMTokens[key]
|
|
|
|
s.RMTokens[key] = append(arr, token)
|
2015-01-24 02:24:34 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-03-08 01:13:06 +02:00
|
|
|
// DelRememberTokens for a user
|
|
|
|
func (s *ServerStorer) DelRememberTokens(key string) error {
|
|
|
|
delete(s.RMTokens, key)
|
2015-01-24 02:24:34 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-03-08 01:13:06 +02:00
|
|
|
// UseRememberToken if it exists, deleting it in the process
|
|
|
|
func (s *ServerStorer) UseRememberToken(givenKey, token string) (err error) {
|
2018-03-09 23:11:08 +02:00
|
|
|
arr, ok := s.RMTokens[givenKey]
|
|
|
|
if !ok {
|
|
|
|
return authboss.ErrTokenNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tok := range arr {
|
|
|
|
if tok == token {
|
|
|
|
if len(arr) == 1 {
|
2018-03-08 01:13:06 +02:00
|
|
|
delete(s.RMTokens, givenKey)
|
2015-03-16 00:00:37 +02:00
|
|
|
return nil
|
2015-01-24 02:24:34 +02:00
|
|
|
}
|
2018-03-09 23:11:08 +02:00
|
|
|
|
|
|
|
arr[i] = arr[len(arr)-1]
|
|
|
|
s.RMTokens[givenKey] = arr[:len(arr)-2]
|
|
|
|
return nil
|
2015-01-24 02:24:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 00:00:37 +02:00
|
|
|
return authboss.ErrTokenNotFound
|
2015-01-24 02:24:34 +02:00
|
|
|
}
|
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// FailStorer is used for testing module initialize functions that recover more than the base storer
|
|
|
|
type FailStorer struct {
|
|
|
|
User
|
2017-02-24 02:13:25 +02:00
|
|
|
}
|
2015-02-12 02:38:09 +02:00
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
// Create fails
|
2018-01-30 02:24:42 +02:00
|
|
|
func (FailStorer) Create(context.Context) error {
|
2015-02-12 02:38:09 +02:00
|
|
|
return errors.New("fail storer: create")
|
|
|
|
}
|
2015-03-16 23:42:45 +02:00
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// Save fails
|
|
|
|
func (FailStorer) Save(context.Context) error {
|
2015-02-12 02:38:09 +02:00
|
|
|
return errors.New("fail storer: put")
|
|
|
|
}
|
2015-03-16 23:42:45 +02:00
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// Load fails
|
|
|
|
func (FailStorer) Load(context.Context) error {
|
2017-02-24 02:13:25 +02:00
|
|
|
return errors.New("fail storer: get")
|
2015-02-12 02:38:09 +02:00
|
|
|
}
|
|
|
|
|
2018-02-16 20:31:55 +02:00
|
|
|
// ClientState is used for testing the client stores on context
|
2018-02-01 03:07:11 +02:00
|
|
|
type ClientState struct {
|
2015-02-12 02:38:09 +02:00
|
|
|
Values map[string]string
|
|
|
|
GetShouldFail bool
|
|
|
|
}
|
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// NewClientState constructs a ClientStorer
|
|
|
|
func NewClientState(data ...string) *ClientState {
|
|
|
|
if len(data) != 0 && len(data)%2 != 0 {
|
2015-02-25 01:01:56 +02:00
|
|
|
panic("It should be a key value list of arguments.")
|
2015-02-12 02:38:09 +02:00
|
|
|
}
|
2015-02-25 01:01:56 +02:00
|
|
|
|
|
|
|
values := make(map[string]string)
|
|
|
|
|
|
|
|
for i := 0; i < len(data)-1; i += 2 {
|
|
|
|
values[data[i]] = data[i+1]
|
|
|
|
}
|
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
return &ClientState{Values: values}
|
2015-02-12 02:38:09 +02:00
|
|
|
}
|
2015-01-24 02:24:34 +02:00
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
// Get a key's value
|
2018-02-01 03:07:11 +02:00
|
|
|
func (m *ClientState) Get(key string) (string, bool) {
|
2015-02-12 02:38:09 +02:00
|
|
|
if m.GetShouldFail {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
v, ok := m.Values[key]
|
2015-01-24 02:24:34 +02:00
|
|
|
return v, ok
|
|
|
|
}
|
2015-03-16 23:42:45 +02:00
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// Put a value
|
|
|
|
func (m *ClientState) Put(key, val string) { m.Values[key] = val }
|
2015-02-21 08:02:55 +02:00
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// Del a key/value pair
|
|
|
|
func (m *ClientState) Del(key string) { delete(m.Values, key) }
|
|
|
|
|
|
|
|
// ClientStateRW stores things that would originally
|
|
|
|
// go in a session, or a map, in memory!
|
|
|
|
type ClientStateRW struct {
|
|
|
|
ClientValues map[string]string
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewClientRW takes the data from a client state
|
|
|
|
// and returns.
|
|
|
|
func NewClientRW() *ClientStateRW {
|
|
|
|
return &ClientStateRW{
|
|
|
|
ClientValues: make(map[string]string),
|
2015-02-21 08:02:55 +02:00
|
|
|
}
|
|
|
|
}
|
2015-03-16 23:42:45 +02:00
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// ReadState from memory
|
2018-03-08 02:41:58 +02:00
|
|
|
func (c *ClientStateRW) ReadState(*http.Request) (authboss.ClientState, error) {
|
2018-02-01 03:07:11 +02:00
|
|
|
return &ClientState{Values: c.ClientValues}, nil
|
|
|
|
}
|
2015-03-16 23:42:45 +02:00
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
// WriteState to memory
|
|
|
|
func (c *ClientStateRW) WriteState(w http.ResponseWriter, cstate authboss.ClientState, cse []authboss.ClientStateEvent) error {
|
2018-02-15 00:18:03 +02:00
|
|
|
for _, e := range cse {
|
|
|
|
switch e.Kind {
|
|
|
|
case authboss.ClientStateEventPut:
|
|
|
|
c.ClientValues[e.Key] = e.Value
|
|
|
|
case authboss.ClientStateEventDel:
|
|
|
|
delete(c.ClientValues, e.Key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-01 03:07:11 +02:00
|
|
|
return nil
|
|
|
|
}
|
2015-01-25 08:19:22 +02:00
|
|
|
|
2018-02-26 01:20:57 +02:00
|
|
|
// Request returns a new request with optional key-value body (form-post)
|
2018-01-30 02:24:42 +02:00
|
|
|
func Request(method string, postKeyValues ...string) *http.Request {
|
2015-08-02 20:51:35 +02:00
|
|
|
var body io.Reader
|
2015-08-02 21:54:53 +02:00
|
|
|
location := "http://localhost"
|
2015-08-02 20:51:35 +02:00
|
|
|
|
|
|
|
if len(postKeyValues) > 0 {
|
|
|
|
urlValues := make(url.Values)
|
|
|
|
for i := 0; i < len(postKeyValues); i += 2 {
|
|
|
|
urlValues.Set(postKeyValues[i], postKeyValues[i+1])
|
2015-01-25 08:19:22 +02:00
|
|
|
}
|
2015-08-02 21:54:53 +02:00
|
|
|
|
|
|
|
if method == "POST" || method == "PUT" {
|
|
|
|
body = strings.NewReader(urlValues.Encode())
|
|
|
|
} else {
|
|
|
|
location += "?" + urlValues.Encode()
|
|
|
|
}
|
2015-01-25 08:19:22 +02:00
|
|
|
}
|
|
|
|
|
2015-08-02 21:54:53 +02:00
|
|
|
req, err := http.NewRequest(method, location, body)
|
2015-01-25 08:19:22 +02:00
|
|
|
if err != nil {
|
|
|
|
panic(err.Error())
|
|
|
|
}
|
|
|
|
|
2015-08-02 20:51:35 +02:00
|
|
|
if len(postKeyValues) > 0 {
|
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
2015-01-25 08:19:22 +02:00
|
|
|
}
|
|
|
|
|
2015-08-02 20:51:35 +02:00
|
|
|
return req
|
2015-01-25 08:19:22 +02:00
|
|
|
}
|
2015-02-09 09:08:33 +02:00
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// Mailer helps simplify mailer testing by storing the last sent email
|
|
|
|
type Mailer struct {
|
2015-02-12 02:38:09 +02:00
|
|
|
Last authboss.Email
|
|
|
|
SendErr string
|
|
|
|
}
|
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// NewMailer constructs a mailer
|
|
|
|
func NewMailer() *Mailer {
|
|
|
|
return &Mailer{}
|
2015-02-09 09:08:33 +02:00
|
|
|
}
|
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
// Send an e-mail
|
2018-01-30 02:24:42 +02:00
|
|
|
func (m *Mailer) Send(ctx context.Context, email authboss.Email) error {
|
2015-02-12 02:38:09 +02:00
|
|
|
if len(m.SendErr) > 0 {
|
|
|
|
return errors.New(m.SendErr)
|
|
|
|
}
|
|
|
|
|
2015-02-09 09:08:33 +02:00
|
|
|
m.Last = email
|
|
|
|
return nil
|
|
|
|
}
|
2015-02-25 01:01:56 +02:00
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// AfterCallback is a callback that knows if it was called
|
|
|
|
type AfterCallback struct {
|
2015-02-25 01:01:56 +02:00
|
|
|
HasBeenCalled bool
|
2018-02-16 20:31:55 +02:00
|
|
|
Fn authboss.EventHandler
|
2015-02-25 01:01:56 +02:00
|
|
|
}
|
|
|
|
|
2018-01-30 02:24:42 +02:00
|
|
|
// NewAfterCallback constructs a new aftercallback.
|
|
|
|
func NewAfterCallback() *AfterCallback {
|
|
|
|
m := AfterCallback{}
|
2015-02-25 01:01:56 +02:00
|
|
|
|
2018-02-16 20:31:55 +02:00
|
|
|
m.Fn = func(http.ResponseWriter, *http.Request, bool) (bool, error) {
|
2015-02-25 01:01:56 +02:00
|
|
|
m.HasBeenCalled = true
|
2018-02-16 20:31:55 +02:00
|
|
|
return false, nil
|
2015-02-25 01:01:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return &m
|
|
|
|
}
|
2018-02-20 18:58:59 +02:00
|
|
|
|
|
|
|
// Renderer mock
|
|
|
|
type Renderer struct {
|
|
|
|
Pages []string
|
|
|
|
|
|
|
|
// Render call variables
|
|
|
|
Context context.Context
|
|
|
|
Page string
|
|
|
|
Data authboss.HTMLData
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasLoadedViews ensures the views were loaded
|
|
|
|
func (r *Renderer) HasLoadedViews(pages ...string) error {
|
|
|
|
if len(r.Pages) != len(pages) {
|
|
|
|
return errors.Errorf("want: %d loaded views, got: %d", len(pages), len(r.Pages))
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, want := range pages {
|
|
|
|
got := r.Pages[i]
|
|
|
|
if want != got {
|
|
|
|
return errors.Errorf("want: %s [%d], got: %s", want, i, got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load nothing but store the pages that were loaded
|
|
|
|
func (r *Renderer) Load(pages ...string) error {
|
|
|
|
r.Pages = append(r.Pages, pages...)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render nothing, but record the arguments into the renderer
|
|
|
|
func (r *Renderer) Render(ctx context.Context, page string, data authboss.HTMLData) ([]byte, string, error) {
|
|
|
|
r.Context = ctx
|
|
|
|
r.Page = page
|
|
|
|
r.Data = data
|
|
|
|
return nil, "text/html", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Responder records how a request was responded to
|
|
|
|
type Responder struct {
|
|
|
|
Status int
|
|
|
|
Page string
|
|
|
|
Data authboss.HTMLData
|
|
|
|
}
|
|
|
|
|
|
|
|
// Respond stores the arguments in the struct
|
|
|
|
func (r *Responder) Respond(w http.ResponseWriter, req *http.Request, code int, page string, data authboss.HTMLData) error {
|
|
|
|
r.Status = code
|
|
|
|
r.Page = page
|
|
|
|
r.Data = data
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Redirector stores the redirect options passed to it and writes the Code
|
|
|
|
// to the ResponseWriter.
|
|
|
|
type Redirector struct {
|
|
|
|
Options authboss.RedirectOptions
|
|
|
|
}
|
|
|
|
|
|
|
|
// Redirect a request
|
|
|
|
func (r *Redirector) Redirect(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error {
|
|
|
|
r.Options = ro
|
2018-02-26 01:20:57 +02:00
|
|
|
if len(ro.RedirectPath) == 0 {
|
|
|
|
panic("no redirect path on redirect call")
|
|
|
|
}
|
2018-02-20 18:58:59 +02:00
|
|
|
http.Redirect(w, req, ro.RedirectPath, ro.Code)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-02-27 17:14:30 +02:00
|
|
|
// Emailer that holds the options it was given
|
|
|
|
type Emailer struct {
|
|
|
|
Email authboss.Email
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send an e-mail
|
|
|
|
func (e *Emailer) Send(ctx context.Context, email authboss.Email) error {
|
|
|
|
e.Email = email
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-02-20 18:58:59 +02:00
|
|
|
// BodyReader reads the body of a request and returns some values
|
|
|
|
type BodyReader struct {
|
2018-02-26 01:20:57 +02:00
|
|
|
Return authboss.Validator
|
2018-02-20 18:58:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read the return values
|
|
|
|
func (b BodyReader) Read(page string, r *http.Request) (authboss.Validator, error) {
|
|
|
|
return b.Return, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Values is returned from the BodyReader
|
|
|
|
type Values struct {
|
|
|
|
PID string
|
|
|
|
Password string
|
2018-02-27 17:14:30 +02:00
|
|
|
Token string
|
2018-03-08 01:17:22 +02:00
|
|
|
Remember bool
|
2018-02-26 01:20:57 +02:00
|
|
|
|
|
|
|
Errors []error
|
2018-02-20 18:58:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPID from values
|
|
|
|
func (v Values) GetPID() string {
|
|
|
|
return v.PID
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPassword from values
|
|
|
|
func (v Values) GetPassword() string {
|
|
|
|
return v.Password
|
|
|
|
}
|
|
|
|
|
2018-02-27 17:14:30 +02:00
|
|
|
// GetToken from values
|
|
|
|
func (v Values) GetToken() string {
|
|
|
|
return v.Token
|
|
|
|
}
|
|
|
|
|
2018-03-08 01:17:22 +02:00
|
|
|
// GetShouldRemember gets the value that tells
|
|
|
|
// the remember module if it should remember the user
|
|
|
|
func (v Values) GetShouldRemember() bool {
|
|
|
|
return v.Remember
|
|
|
|
}
|
|
|
|
|
2018-02-20 18:58:59 +02:00
|
|
|
// Validate the values
|
|
|
|
func (v Values) Validate() []error {
|
2018-02-26 01:20:57 +02:00
|
|
|
return v.Errors
|
|
|
|
}
|
|
|
|
|
|
|
|
// ArbValues is arbitrary value storage
|
|
|
|
type ArbValues struct {
|
|
|
|
Values map[string]string
|
|
|
|
Errors []error
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPID gets the pid
|
|
|
|
func (a ArbValues) GetPID() string {
|
|
|
|
return a.Values["email"]
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPassword gets the password
|
|
|
|
func (a ArbValues) GetPassword() string {
|
|
|
|
return a.Values["password"]
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetValues returns all values
|
|
|
|
func (a ArbValues) GetValues() map[string]string {
|
|
|
|
return a.Values
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate nothing
|
|
|
|
func (a ArbValues) Validate() []error {
|
|
|
|
return a.Errors
|
2018-02-20 18:58:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Logger logs to the void
|
|
|
|
type Logger struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
// Info logging
|
|
|
|
func (l Logger) Info(string) {}
|
|
|
|
|
|
|
|
// Error logging
|
|
|
|
func (l Logger) Error(string) {}
|
|
|
|
|
|
|
|
// Router records the routes that were registered
|
|
|
|
type Router struct {
|
|
|
|
Gets []string
|
|
|
|
Posts []string
|
|
|
|
Deletes []string
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServeHTTP does nothing
|
|
|
|
func (Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get records the path in the router
|
|
|
|
func (r *Router) Get(path string, _ http.Handler) {
|
|
|
|
r.Gets = append(r.Gets, path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Post records the path in the router
|
|
|
|
func (r *Router) Post(path string, _ http.Handler) {
|
|
|
|
r.Posts = append(r.Posts, path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete records the path in the router
|
|
|
|
func (r *Router) Delete(path string, _ http.Handler) {
|
|
|
|
r.Deletes = append(r.Deletes, path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasGets ensures all gets routes are present
|
|
|
|
func (r *Router) HasGets(gets ...string) error {
|
|
|
|
return r.hasRoutes(gets, r.Gets)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasPosts ensures all gets routes are present
|
|
|
|
func (r *Router) HasPosts(posts ...string) error {
|
|
|
|
return r.hasRoutes(posts, r.Posts)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HasDeletes ensures all gets routes are present
|
|
|
|
func (r *Router) HasDeletes(deletes ...string) error {
|
|
|
|
return r.hasRoutes(deletes, r.Deletes)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Router) hasRoutes(want []string, got []string) error {
|
|
|
|
if len(got) != len(want) {
|
|
|
|
return errors.Errorf("want: %d get routes, got: %d", len(want), len(got))
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, w := range want {
|
|
|
|
g := got[i]
|
|
|
|
if w != g {
|
|
|
|
return errors.Errorf("wanted route: %s [%d], but got: %s", w, i, g)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ErrorHandler just holds the last error
|
|
|
|
type ErrorHandler struct {
|
|
|
|
Error error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrap an http method
|
|
|
|
func (e *ErrorHandler) Wrap(handler func(w http.ResponseWriter, r *http.Request) error) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if err := handler(w, r); err != nil {
|
|
|
|
e.Error = err
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|