2015-02-11 02:29:52 +02:00
|
|
|
package confirm
|
|
|
|
|
|
|
|
import (
|
2015-02-16 23:27:29 +02:00
|
|
|
"bytes"
|
|
|
|
"crypto/md5"
|
|
|
|
"encoding/base64"
|
2015-02-22 10:09:52 +02:00
|
|
|
"errors"
|
2015-02-11 02:29:52 +02:00
|
|
|
"html/template"
|
2015-02-16 23:27:29 +02:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2015-02-22 10:09:52 +02:00
|
|
|
"reflect"
|
2015-02-16 23:27:29 +02:00
|
|
|
"strings"
|
2015-02-11 02:29:52 +02:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"gopkg.in/authboss.v0"
|
|
|
|
"gopkg.in/authboss.v0/internal/mocks"
|
|
|
|
)
|
|
|
|
|
|
|
|
func setup() *Confirm {
|
2015-04-01 00:27:47 +02:00
|
|
|
ab := authboss.New()
|
|
|
|
ab.Storer = mocks.NewMockStorer()
|
|
|
|
ab.LayoutHTMLEmail = template.Must(template.New("").Parse(`email ^_^`))
|
|
|
|
ab.LayoutTextEmail = template.Must(template.New("").Parse(`email`))
|
2015-02-11 02:29:52 +02:00
|
|
|
|
|
|
|
c := &Confirm{}
|
2015-04-01 00:27:47 +02:00
|
|
|
if err := c.Initialize(ab); err != nil {
|
2015-02-11 02:29:52 +02:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirm_Initialize(t *testing.T) {
|
2015-04-01 00:27:47 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ab := authboss.New()
|
2015-02-11 02:29:52 +02:00
|
|
|
c := &Confirm{}
|
2015-04-01 00:27:47 +02:00
|
|
|
if err := c.Initialize(ab); err == nil {
|
2015-02-11 02:29:52 +02:00
|
|
|
t.Error("Should cry about not having a storer.")
|
|
|
|
}
|
|
|
|
|
|
|
|
c = setup()
|
|
|
|
|
2015-03-03 21:23:49 +02:00
|
|
|
if c.emailHTMLTemplates == nil {
|
|
|
|
t.Error("Missing HTML email templates")
|
|
|
|
}
|
|
|
|
if c.emailTextTemplates == nil {
|
|
|
|
t.Error("Missing text email templates")
|
2015-02-11 02:29:52 +02:00
|
|
|
}
|
|
|
|
}
|
2015-02-16 23:27:29 +02:00
|
|
|
|
|
|
|
func TestConfirm_Routes(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
c := &Confirm{}
|
|
|
|
if c.Routes()["/confirm"] == nil {
|
|
|
|
t.Error("Expected confirm route.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirm_Storage(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2015-04-01 00:27:47 +02:00
|
|
|
c := &Confirm{Authboss: authboss.New()}
|
2015-02-16 23:27:29 +02:00
|
|
|
storage := c.Storage()
|
|
|
|
|
|
|
|
if authboss.String != storage[StoreConfirmToken] {
|
|
|
|
t.Error("Expect StoreConfirmToken to be a string.")
|
|
|
|
}
|
|
|
|
if authboss.Bool != storage[StoreConfirmed] {
|
|
|
|
t.Error("Expect StoreConfirmed to be a bool.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirm_BeforeGet(t *testing.T) {
|
2015-04-01 00:27:47 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
2015-02-16 23:27:29 +02:00
|
|
|
c := setup()
|
2015-04-01 00:27:47 +02:00
|
|
|
ctx := c.NewContext()
|
2015-02-16 23:27:29 +02:00
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
if _, err := c.beforeGet(ctx); err == nil {
|
2015-02-22 10:09:52 +02:00
|
|
|
t.Error("Should stop the get due to attribute missing:", err)
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.User = authboss.Attributes{
|
|
|
|
StoreConfirmed: false,
|
|
|
|
}
|
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
if interrupt, err := c.beforeGet(ctx); interrupt != authboss.InterruptAccountNotConfirmed {
|
2015-02-22 10:09:52 +02:00
|
|
|
t.Error("Should stop the get due to non-confirm:", interrupt)
|
|
|
|
} else if err != nil {
|
|
|
|
t.Error(err)
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.User = authboss.Attributes{
|
|
|
|
StoreConfirmed: true,
|
|
|
|
}
|
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
if interrupt, err := c.beforeGet(ctx); interrupt != authboss.InterruptNone || err != nil {
|
2015-02-22 10:09:52 +02:00
|
|
|
t.Error(interrupt, err)
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirm_AfterRegister(t *testing.T) {
|
2015-04-01 00:27:47 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
2015-02-16 23:27:29 +02:00
|
|
|
c := setup()
|
2015-04-01 00:27:47 +02:00
|
|
|
ctx := c.NewContext()
|
2015-02-16 23:27:29 +02:00
|
|
|
log := &bytes.Buffer{}
|
2015-04-01 00:27:47 +02:00
|
|
|
c.LogWriter = log
|
|
|
|
c.Mailer = authboss.LogMailer(log)
|
|
|
|
c.PrimaryID = authboss.StoreUsername
|
2015-02-16 23:27:29 +02:00
|
|
|
|
|
|
|
sentEmail := false
|
|
|
|
|
|
|
|
goConfirmEmail = func(c *Confirm, to, token string) {
|
|
|
|
c.confirmEmail(to, token)
|
|
|
|
sentEmail = true
|
|
|
|
}
|
|
|
|
|
2015-03-16 23:42:45 +02:00
|
|
|
if err := c.afterRegister(ctx); err != errUserMissing {
|
2015-02-22 10:09:52 +02:00
|
|
|
t.Error("Expected it to die with user error:", err)
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
|
2015-04-01 00:27:47 +02:00
|
|
|
ctx.User = authboss.Attributes{c.PrimaryID: "username"}
|
2015-03-16 23:42:45 +02:00
|
|
|
if err := c.afterRegister(ctx); err == nil || err.(authboss.AttributeErr).Name != "email" {
|
2015-02-22 10:09:52 +02:00
|
|
|
t.Error("Expected it to die with e-mail address error:", err)
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx.User[authboss.StoreEmail] = "a@a.com"
|
|
|
|
log.Reset()
|
2015-03-16 23:42:45 +02:00
|
|
|
c.afterRegister(ctx)
|
2015-02-16 23:27:29 +02:00
|
|
|
if str := log.String(); !strings.Contains(str, "Subject: Confirm New Account") {
|
|
|
|
t.Error("Expected it to send an e-mail:", str)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !sentEmail {
|
|
|
|
t.Error("Expected it to send an e-mail.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirm_ConfirmHandlerErrors(t *testing.T) {
|
2015-04-01 00:27:47 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
2015-02-16 23:27:29 +02:00
|
|
|
c := setup()
|
|
|
|
log := &bytes.Buffer{}
|
2015-04-01 00:27:47 +02:00
|
|
|
c.LogWriter = log
|
|
|
|
c.Mailer = authboss.LogMailer(log)
|
2015-02-16 23:27:29 +02:00
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
URL string
|
|
|
|
Confirmed bool
|
2015-02-22 10:09:52 +02:00
|
|
|
Error error
|
2015-02-16 23:27:29 +02:00
|
|
|
}{
|
2015-02-22 10:09:52 +02:00
|
|
|
{"http://localhost", false, authboss.ClientDataErr{FormValueConfirm}},
|
|
|
|
{"http://localhost?cnf=c$ats", false,
|
2015-02-25 00:45:37 +02:00
|
|
|
authboss.ErrAndRedirect{Location: "/", Err: errors.New("confirm: token failed to decode \"c$ats\" => illegal base64 data at input byte 1\n")},
|
2015-02-22 10:09:52 +02:00
|
|
|
},
|
|
|
|
{"http://localhost?cnf=SGVsbG8sIHBsYXlncm91bmQ=", false,
|
2015-02-25 00:45:37 +02:00
|
|
|
authboss.ErrAndRedirect{Location: "/", Err: errors.New(`confirm: token not found`)},
|
2015-02-22 10:09:52 +02:00
|
|
|
},
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range tests {
|
|
|
|
r, _ := http.NewRequest("GET", test.URL, nil)
|
|
|
|
w := httptest.NewRecorder()
|
2015-04-01 00:27:47 +02:00
|
|
|
ctx, _ := c.ContextFromRequest(r)
|
2015-02-16 23:27:29 +02:00
|
|
|
|
2015-02-22 10:09:52 +02:00
|
|
|
err := c.confirmHandler(ctx, w, r)
|
|
|
|
if err == nil {
|
2015-03-16 23:51:44 +02:00
|
|
|
t.Fatalf("%d) Expected an error", i)
|
2015-02-22 10:09:52 +02:00
|
|
|
}
|
2015-02-16 23:27:29 +02:00
|
|
|
|
2015-02-22 10:09:52 +02:00
|
|
|
if !reflect.DeepEqual(err, test.Error) {
|
|
|
|
t.Errorf("Expected: %v, got: %v", test.Error, err)
|
2015-02-16 23:27:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
is, ok := ctx.User.Bool(StoreConfirmed)
|
|
|
|
if ok && is {
|
|
|
|
t.Error("The user should not be confirmed.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirm_Confirm(t *testing.T) {
|
2015-04-01 00:27:47 +02:00
|
|
|
t.Parallel()
|
|
|
|
|
2015-02-16 23:27:29 +02:00
|
|
|
c := setup()
|
2015-04-01 00:27:47 +02:00
|
|
|
ctx := c.NewContext()
|
2015-02-16 23:27:29 +02:00
|
|
|
log := &bytes.Buffer{}
|
2015-04-01 00:27:47 +02:00
|
|
|
c.LogWriter = log
|
|
|
|
c.PrimaryID = authboss.StoreUsername
|
|
|
|
c.Mailer = authboss.LogMailer(log)
|
2015-02-16 23:27:29 +02:00
|
|
|
|
|
|
|
// Create a token
|
|
|
|
token := []byte("hi")
|
|
|
|
sum := md5.Sum(token)
|
|
|
|
|
|
|
|
// Create the "database"
|
|
|
|
storer := mocks.NewMockStorer()
|
2015-04-01 00:27:47 +02:00
|
|
|
c.Storer = storer
|
2015-02-16 23:27:29 +02:00
|
|
|
user := authboss.Attributes{
|
|
|
|
authboss.StoreUsername: "usern",
|
|
|
|
StoreConfirmToken: base64.StdEncoding.EncodeToString(sum[:]),
|
|
|
|
}
|
|
|
|
storer.Users["usern"] = user
|
|
|
|
|
|
|
|
// Make a request with session and context support.
|
|
|
|
r, _ := http.NewRequest("GET", "http://localhost?cnf="+base64.URLEncoding.EncodeToString(token), nil)
|
|
|
|
w := httptest.NewRecorder()
|
2015-04-01 00:27:47 +02:00
|
|
|
ctx, _ = c.ContextFromRequest(r)
|
2015-02-22 10:09:52 +02:00
|
|
|
ctx.CookieStorer = mocks.NewMockClientStorer()
|
2015-02-16 23:27:29 +02:00
|
|
|
session := mocks.NewMockClientStorer()
|
|
|
|
ctx.User = user
|
|
|
|
ctx.SessionStorer = session
|
|
|
|
|
|
|
|
c.confirmHandler(ctx, w, r)
|
2015-02-25 09:45:55 +02:00
|
|
|
if w.Code != http.StatusFound {
|
2015-02-16 23:27:29 +02:00
|
|
|
t.Error("Expected a redirect after success:", w.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
if log.Len() != 0 {
|
|
|
|
t.Error("Expected a clean log on success:", log.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
is, ok := ctx.User.Bool(StoreConfirmed)
|
|
|
|
if !ok || !is {
|
|
|
|
t.Error("The user should be confirmed.")
|
|
|
|
}
|
|
|
|
|
|
|
|
tok, ok := ctx.User.String(StoreConfirmToken)
|
|
|
|
if ok && len(tok) != 0 {
|
|
|
|
t.Error("Confirm token should have been wiped out.")
|
|
|
|
}
|
|
|
|
|
|
|
|
if key, ok := ctx.SessionStorer.Get(authboss.SessionKey); !ok || len(key) == 0 {
|
|
|
|
t.Error("Should have logged the user in.")
|
|
|
|
}
|
2015-02-24 21:04:27 +02:00
|
|
|
if success, ok := ctx.SessionStorer.Get(authboss.FlashSuccessKey); !ok || len(success) == 0 {
|
2015-02-16 23:27:29 +02:00
|
|
|
t.Error("Should have left a nice message.")
|
|
|
|
}
|
|
|
|
}
|