1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-01-24 05:17:10 +02:00
Aaron L 386133a84b Add a way to read values and validate
In order to support multiple different types of requests, there needed
to be an interface to be able to read values from a request, and
subsequently validate them to return any errors.

So we've adjusted the Validator interface to no longer validate a
request but instead validate the object it lives on.

And we've created a new BodyReader interface.
2018-02-04 18:39:25 -08:00

352 lines
8.6 KiB
Go

// Package mocks defines implemented interfaces for testing modules
package mocks
import (
"context"
"io"
"net/http"
"net/url"
"strings"
"time"
"github.com/pkg/errors"
"github.com/volatiletech/authboss"
)
// User represents all possible fields a authboss User may have
type User struct {
Username string
Email string
Password string
RecoverToken string
RecoverTokenExpiry time.Time
ConfirmToken string
Confirmed bool
Locked bool
AttemptNumber int
AttemptTime time.Time
OAuthToken string
OAuthRefresh string
OAuthExpiry time.Time
}
func (m User) GetUsername(context.Context) (string, error) { return m.Username, nil }
func (m User) GetPID(context.Context) (string, error) { return m.Email, nil }
func (m User) GetPassword(context.Context) (string, error) { return m.Password, nil }
func (m User) GetRecoverToken(context.Context) (string, error) { return m.RecoverToken, nil }
func (m User) GetRecoverTokenExpiry(context.Context) (time.Time, error) {
return m.RecoverTokenExpiry, nil
}
func (m User) GetConfirmToken(context.Context) (string, error) { return m.ConfirmToken, nil }
func (m User) GetConfirmed(context.Context) (bool, error) { return m.Confirmed, nil }
func (m User) GetLocked(context.Context) (bool, error) { return m.Locked, nil }
func (m User) GetAttemptNumber(context.Context) (int, error) { return m.AttemptNumber, nil }
func (m User) GetAttemptTime(context.Context) (time.Time, error) {
return m.AttemptTime, nil
}
func (m User) GetOAuthToken(context.Context) (string, error) { return m.OAuthToken, nil }
func (m User) GetOAuthRefresh(context.Context) (string, error) { return m.OAuthRefresh, nil }
func (m User) GetOAuthExpiry(context.Context) (time.Time, error) {
return m.OAuthExpiry, nil
}
func (m *User) SetUsername(ctx context.Context, username string) error {
m.Username = username
return nil
}
func (m *User) SetEmail(ctx context.Context, email string) error {
m.Email = email
return nil
}
func (m *User) SetPassword(ctx context.Context, password string) error {
m.Password = password
return nil
}
func (m *User) SetRecoverToken(ctx context.Context, recoverToken string) error {
m.RecoverToken = recoverToken
return nil
}
func (m *User) SetRecoverTokenExpiry(ctx context.Context, recoverTokenExpiry time.Time) error {
m.RecoverTokenExpiry = recoverTokenExpiry
return nil
}
func (m *User) SetConfirmToken(ctx context.Context, confirmToken string) error {
m.ConfirmToken = confirmToken
return nil
}
func (m *User) SetConfirmed(ctx context.Context, confirmed bool) error {
m.Confirmed = confirmed
return nil
}
func (m *User) SetLocked(ctx context.Context, locked bool) error {
m.Locked = locked
return nil
}
func (m *User) SetAttemptNumber(ctx context.Context, attemptNumber int) error {
m.AttemptNumber = attemptNumber
return nil
}
func (m *User) SetAttemptTime(ctx context.Context, attemptTime time.Time) error {
m.AttemptTime = attemptTime
return nil
}
func (m *User) SetOAuthToken(ctx context.Context, oAuthToken string) error {
m.OAuthToken = oAuthToken
return nil
}
func (m *User) SetOAuthRefresh(ctx context.Context, oAuthRefresh string) error {
m.OAuthRefresh = oAuthRefresh
return nil
}
func (m *User) SetOAuthExpiry(ctx context.Context, oAuthExpiry time.Time) error {
m.OAuthExpiry = oAuthExpiry
return nil
}
// ServerStorer should be valid for any module storer defined in authboss.
type ServerStorer struct {
Users map[string]*User
RMTokens map[string][]string
}
// NewServerStorer constructor
func NewServerStorer() *ServerStorer {
return &ServerStorer{
Users: make(map[string]*User),
RMTokens: make(map[string][]string),
}
}
/*
// TODO(aarondl): What is this?
// AddToken for remember me
func (m *Storer) AddToken(key, token string) error {
if len(m.AddTokenErr) > 0 {
return errors.New(m.AddTokenErr)
}
arr := m.Tokens[key]
m.Tokens[key] = append(arr, token)
return nil
}
// DelTokens for a user
func (m *Storer) DelTokens(key string) error {
if len(m.DelTokensErr) > 0 {
return errors.New(m.DelTokensErr)
}
delete(m.Tokens, key)
return nil
}
// UseToken if it exists, deleting it in the process
func (m *Storer) UseToken(givenKey, token string) (err error) {
if len(m.UseTokenErr) > 0 {
return errors.New(m.UseTokenErr)
}
if arr, ok := m.Tokens[givenKey]; ok {
for _, tok := range arr {
if tok == token {
return nil
}
}
}
return authboss.ErrTokenNotFound
}
// RecoverUser by the token.
func (m *Storer) RecoverUser(token string) (result interface{}, err error) {
if len(m.RecoverUserErr) > 0 {
return nil, errors.New(m.RecoverUserErr)
}
for _, user := range m.Users {
if user["recover_token"] == token {
u := &User{}
if err = user.Bind(u, false); err != nil {
panic(err)
}
return u, nil
}
}
return nil, authboss.ErrUserNotFound
}
// ConfirmUser via their token
func (m *Storer) ConfirmUser(confirmToken string) (result interface{}, err error) {
if len(m.ConfirmUserErr) > 0 {
return nil, errors.New(m.ConfirmUserErr)
}
for _, user := range m.Users {
if user["confirm_token"] == confirmToken {
u := &User{}
if err = user.Bind(u, false); err != nil {
panic(err)
}
return u, nil
}
}
return nil, authboss.ErrUserNotFound
}
*/
// FailStorer is used for testing module initialize functions that recover more than the base storer
type FailStorer struct {
User
}
// Create fails
func (FailStorer) Create(context.Context) error {
return errors.New("fail storer: create")
}
// Save fails
func (FailStorer) Save(context.Context) error {
return errors.New("fail storer: put")
}
// Load fails
func (FailStorer) Load(context.Context) error {
return errors.New("fail storer: get")
}
// ClientRW is used for testing the client stores on context
type ClientState struct {
Values map[string]string
GetShouldFail bool
}
// NewClientState constructs a ClientStorer
func NewClientState(data ...string) *ClientState {
if len(data) != 0 && len(data)%2 != 0 {
panic("It should be a key value list of arguments.")
}
values := make(map[string]string)
for i := 0; i < len(data)-1; i += 2 {
values[data[i]] = data[i+1]
}
return &ClientState{Values: values}
}
// Get a key's value
func (m *ClientState) Get(key string) (string, bool) {
if m.GetShouldFail {
return "", false
}
v, ok := m.Values[key]
return v, ok
}
// Put a value
func (m *ClientState) Put(key, val string) { m.Values[key] = val }
// 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),
}
}
// ReadState from memory
func (c *ClientStateRW) ReadState(http.ResponseWriter, *http.Request) (authboss.ClientState, error) {
return &ClientState{Values: c.ClientValues}, nil
}
// WriteState to memory
func (c *ClientStateRW) WriteState(w http.ResponseWriter, cstate authboss.ClientState, cse []authboss.ClientStateEvent) error {
return nil
}
// Request returns a new request with optional key-value body (form-post)
func Request(method string, postKeyValues ...string) *http.Request {
var body io.Reader
location := "http://localhost"
if len(postKeyValues) > 0 {
urlValues := make(url.Values)
for i := 0; i < len(postKeyValues); i += 2 {
urlValues.Set(postKeyValues[i], postKeyValues[i+1])
}
if method == "POST" || method == "PUT" {
body = strings.NewReader(urlValues.Encode())
} else {
location += "?" + urlValues.Encode()
}
}
req, err := http.NewRequest(method, location, body)
if err != nil {
panic(err.Error())
}
if len(postKeyValues) > 0 {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
return req
}
// Mailer helps simplify mailer testing by storing the last sent email
type Mailer struct {
Last authboss.Email
SendErr string
}
// NewMailer constructs a mailer
func NewMailer() *Mailer {
return &Mailer{}
}
// Send an e-mail
func (m *Mailer) Send(ctx context.Context, email authboss.Email) error {
if len(m.SendErr) > 0 {
return errors.New(m.SendErr)
}
m.Last = email
return nil
}
// AfterCallback is a callback that knows if it was called
type AfterCallback struct {
HasBeenCalled bool
Fn authboss.After
}
// NewAfterCallback constructs a new aftercallback.
func NewAfterCallback() *AfterCallback {
m := AfterCallback{}
m.Fn = func(context.Context) error {
m.HasBeenCalled = true
return nil
}
return &m
}