mirror of
https://github.com/volatiletech/authboss.git
synced 2024-11-24 08:42:17 +02:00
24fc6196c7
- This addresses the problem of having to update multiple times during one request. It's hard to have a nice interface especially with JWT because you always end up having to decode the request, encode new response, write header, then a second write to it comes, and where do you grab the value from? Often you don't have access to the response as a "read" structure. So we store it as events instead, and play those events against the original data right before the response is written to set the headers.
130 lines
3.9 KiB
Go
130 lines
3.9 KiB
Go
package authboss
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// Data store constants for attribute names.
|
|
const (
|
|
StoreEmail = "email"
|
|
StoreUsername = "username"
|
|
StorePassword = "password"
|
|
)
|
|
|
|
// Data store constants for OAuth2 attribute names.
|
|
const (
|
|
StoreOAuth2UID = "oauth2_uid"
|
|
StoreOAuth2Provider = "oauth2_provider"
|
|
StoreOAuth2Token = "oauth2_token"
|
|
StoreOAuth2Refresh = "oauth2_refresh"
|
|
StoreOAuth2Expiry = "oauth2_expiry"
|
|
)
|
|
|
|
var (
|
|
// ErrUserNotFound should be returned from Get when the record is not found.
|
|
ErrUserNotFound = errors.New("user not found")
|
|
// ErrTokenNotFound should be returned from UseToken when the record is not found.
|
|
ErrTokenNotFound = errors.New("token not found")
|
|
// ErrUserFound should be returned from Create when the primaryID of the record is found.
|
|
ErrUserFound = errors.New("user found")
|
|
)
|
|
|
|
// StoreLoader represents the data store that's capable of loading users
|
|
// and giving them a context with which to store themselves.
|
|
type StoreLoader interface {
|
|
// Load will be passed the PrimaryID and return pre-loaded storer (meaning
|
|
// Storer.Load will not be called)
|
|
Load(ctx context.Context, key string) (Storer, error)
|
|
}
|
|
|
|
// Storer represents a user that also knows how to put himself into the db.
|
|
// It has functions for each piece of data it requires.
|
|
// Note that you should only persist data once Save() has been called.
|
|
type Storer interface {
|
|
PutEmail(ctx context.Context, email string) error
|
|
PutUsername(ctx context.Context, username string) error
|
|
PutPassword(ctx context.Context, password string) error
|
|
|
|
GetEmail(ctx context.Context) (email string, err error)
|
|
GetUsername(ctx context.Context) (username string, err error)
|
|
GetPassword(ctx context.Context) (password string, err error)
|
|
|
|
// Save the state.
|
|
Save(ctx context.Context) error
|
|
|
|
// Load the state based on the properties that have been given (typically
|
|
// an e-mail/username).
|
|
Load(ctx context.Context) error
|
|
}
|
|
|
|
// TODO(aarondl): Document & move to Register module
|
|
// ArbitraryStorer allows arbitrary data from the web form through. You should
|
|
// definitely only pull the keys you want from the map, since this is unfiltered
|
|
// input from a web request and is an attack vector.
|
|
type ArbitraryStorer interface {
|
|
Storer
|
|
|
|
// PutArbitrary allows arbitrary fields defined by the authboss library
|
|
// consumer to add fields to the user registration piece.
|
|
PutArbitrary(ctx context.Context, arbitrary map[string]string) error
|
|
// GetArbitrary is used only to display the arbitrary data back to the user
|
|
// when the form is reset.
|
|
GetArbitrary(ctx context.Context) (arbitrary map[string]string, err error)
|
|
}
|
|
|
|
// OAuth2Storer allows reading and writing values relating to OAuth2
|
|
type OAuth2Storer interface {
|
|
Storer
|
|
|
|
IsOAuth2User(ctx context.Context) (bool, error)
|
|
|
|
PutUID(ctx context.Context, uid string) error
|
|
PutProvider(ctx context.Context, provider string) error
|
|
PutToken(ctx context.Context, token string) error
|
|
PutRefreshToken(ctx context.Context, refreshToken string) error
|
|
PutExpiry(ctx context.Context, expiry time.Duration) error
|
|
|
|
GetUID(ctx context.Context) (uid string, err error)
|
|
GetProvider(ctx context.Context) (provider string, err error)
|
|
GetToken(ctx context.Context) (token string, err error)
|
|
GetRefreshToken(ctx context.Context) (refreshToken string, err error)
|
|
GetExpiry(ctx context.Context) (expiry time.Duration, err error)
|
|
}
|
|
|
|
func camelToUnder(in string) string {
|
|
out := bytes.Buffer{}
|
|
for i := 0; i < len(in); i++ {
|
|
chr := in[i]
|
|
if chr >= 'A' && chr <= 'Z' {
|
|
if i > 0 {
|
|
out.WriteByte('_')
|
|
}
|
|
out.WriteByte(chr + 'a' - 'A')
|
|
} else {
|
|
out.WriteByte(chr)
|
|
}
|
|
}
|
|
return out.String()
|
|
}
|
|
|
|
func underToCamel(in string) string {
|
|
out := bytes.Buffer{}
|
|
for i := 0; i < len(in); i++ {
|
|
chr := in[i]
|
|
|
|
if first := i == 0; first || chr == '_' {
|
|
if !first {
|
|
i++
|
|
}
|
|
out.WriteByte(in[i] - 'a' + 'A')
|
|
} else {
|
|
out.WriteByte(chr)
|
|
}
|
|
}
|
|
return out.String()
|
|
}
|