github.com/volatiletech/authboss@v2.4.1+incompatible/mocks/mocks.go (about) 1 // Package mocks defines implemented interfaces for testing modules 2 package mocks 3 4 import ( 5 "context" 6 "io" 7 "net/http" 8 "net/url" 9 "strings" 10 "time" 11 12 "github.com/pkg/errors" 13 "github.com/volatiletech/authboss" 14 ) 15 16 // User represents all possible fields a authboss User may have 17 type User struct { 18 Username string 19 Email string 20 Password string 21 RecoverSelector string 22 RecoverVerifier string 23 RecoverTokenExpiry time.Time 24 ConfirmSelector string 25 ConfirmVerifier string 26 Confirmed bool 27 AttemptCount int 28 LastAttempt time.Time 29 Locked time.Time 30 31 OAuth2UID string 32 OAuth2Provider string 33 OAuth2Token string 34 OAuth2Refresh string 35 OAuth2Expiry time.Time 36 37 OTPs string 38 TOTPSecretKey string 39 SMSPhoneNumber string 40 RecoveryCodes string 41 42 SMSPhoneNumberSeed string 43 44 Arbitrary map[string]string 45 } 46 47 // GetPID from user 48 func (u User) GetPID() string { return u.Email } 49 50 // GetEmail from user 51 func (u User) GetEmail() string { return u.Email } 52 53 // GetUsername from user 54 func (u User) GetUsername() string { return u.Username } 55 56 // GetPassword from user 57 func (u User) GetPassword() string { return u.Password } 58 59 // GetRecoverSelector from user 60 func (u User) GetRecoverSelector() string { return u.RecoverSelector } 61 62 // GetRecoverVerifier from user 63 func (u User) GetRecoverVerifier() string { return u.RecoverVerifier } 64 65 // GetRecoverExpiry from user 66 func (u User) GetRecoverExpiry() time.Time { return u.RecoverTokenExpiry } 67 68 // GetConfirmSelector from user 69 func (u User) GetConfirmSelector() string { return u.ConfirmSelector } 70 71 // GetConfirmVerifier from user 72 func (u User) GetConfirmVerifier() string { return u.ConfirmVerifier } 73 74 // GetConfirmed from user 75 func (u User) GetConfirmed() bool { return u.Confirmed } 76 77 // GetAttemptCount from user 78 func (u User) GetAttemptCount() int { return u.AttemptCount } 79 80 // GetLastAttempt from user 81 func (u User) GetLastAttempt() time.Time { return u.LastAttempt } 82 83 // GetLocked from user 84 func (u User) GetLocked() time.Time { return u.Locked } 85 86 // IsOAuth2User returns true if the user is an oauth2 user 87 func (u User) IsOAuth2User() bool { return len(u.OAuth2Provider) != 0 } 88 89 // GetOAuth2UID from user 90 func (u User) GetOAuth2UID() string { return u.OAuth2UID } 91 92 // GetOAuth2Provider from user 93 func (u User) GetOAuth2Provider() string { return u.OAuth2Provider } 94 95 // GetOAuth2AccessToken from user 96 func (u User) GetOAuth2AccessToken() string { return u.OAuth2Token } 97 98 // GetOAuth2RefreshToken from user 99 func (u User) GetOAuth2RefreshToken() string { return u.OAuth2Refresh } 100 101 // GetOAuth2Expiry from user 102 func (u User) GetOAuth2Expiry() time.Time { return u.OAuth2Expiry } 103 104 // GetArbitrary from user 105 func (u User) GetArbitrary() map[string]string { return u.Arbitrary } 106 107 // GetOTPs from user 108 func (u User) GetOTPs() string { return u.OTPs } 109 110 // GetTOTPSecretKey from user 111 func (u User) GetTOTPSecretKey() string { return u.TOTPSecretKey } 112 113 // GetSMSPhoneNumber from user 114 func (u User) GetSMSPhoneNumber() string { return u.SMSPhoneNumber } 115 116 // GetSMSPhoneNumber from user 117 func (u User) GetSMSPhoneNumberSeed() string { return u.SMSPhoneNumberSeed } 118 119 // GetRecoveryCodes from user 120 func (u User) GetRecoveryCodes() string { return u.RecoveryCodes } 121 122 // PutPID into user 123 func (u *User) PutPID(email string) { u.Email = email } 124 125 // PutUsername into user 126 func (u *User) PutUsername(username string) { u.Username = username } 127 128 // PutEmail into user 129 func (u *User) PutEmail(email string) { u.Email = email } 130 131 // PutPassword into user 132 func (u *User) PutPassword(password string) { u.Password = password } 133 134 // PutRecoverSelector into user 135 func (u *User) PutRecoverSelector(recoverSelector string) { u.RecoverSelector = recoverSelector } 136 137 // PutRecoverVerifier into user 138 func (u *User) PutRecoverVerifier(recoverVerifier string) { u.RecoverVerifier = recoverVerifier } 139 140 // PutRecoverExpiry into user 141 func (u *User) PutRecoverExpiry(recoverTokenExpiry time.Time) { 142 u.RecoverTokenExpiry = recoverTokenExpiry 143 } 144 145 // PutConfirmSelector into user 146 func (u *User) PutConfirmSelector(confirmSelector string) { u.ConfirmSelector = confirmSelector } 147 148 // PutConfirmVerifier into user 149 func (u *User) PutConfirmVerifier(confirmVerifier string) { u.ConfirmVerifier = confirmVerifier } 150 151 // PutConfirmed into user 152 func (u *User) PutConfirmed(confirmed bool) { u.Confirmed = confirmed } 153 154 // PutAttemptCount into user 155 func (u *User) PutAttemptCount(attemptCount int) { u.AttemptCount = attemptCount } 156 157 // PutLastAttempt into user 158 func (u *User) PutLastAttempt(attemptTime time.Time) { u.LastAttempt = attemptTime } 159 160 // PutLocked into user 161 func (u *User) PutLocked(locked time.Time) { u.Locked = locked } 162 163 // PutOAuth2UID into user 164 func (u *User) PutOAuth2UID(uid string) { u.OAuth2UID = uid } 165 166 // PutOAuth2Provider into user 167 func (u *User) PutOAuth2Provider(provider string) { u.OAuth2Provider = provider } 168 169 // PutOAuth2AccessToken into user 170 func (u *User) PutOAuth2AccessToken(token string) { u.OAuth2Token = token } 171 172 // PutOAuth2RefreshToken into user 173 func (u *User) PutOAuth2RefreshToken(refresh string) { u.OAuth2Refresh = refresh } 174 175 // PutOAuth2Expiry into user 176 func (u *User) PutOAuth2Expiry(expiry time.Time) { u.OAuth2Expiry = expiry } 177 178 // PutArbitrary into user 179 func (u *User) PutArbitrary(arb map[string]string) { u.Arbitrary = arb } 180 181 // PutOTPs into user 182 func (u *User) PutOTPs(otps string) { u.OTPs = otps } 183 184 // PutTOTPSecretKey into user 185 func (u *User) PutTOTPSecretKey(key string) { u.TOTPSecretKey = key } 186 187 // PutSMSPhoneNumber into user 188 func (u *User) PutSMSPhoneNumber(number string) { u.SMSPhoneNumber = number } 189 190 // PutRecoveryCodes into user 191 func (u *User) PutRecoveryCodes(codes string) { u.RecoveryCodes = codes } 192 193 // ServerStorer should be valid for any module storer defined in authboss. 194 type ServerStorer struct { 195 Users map[string]*User 196 RMTokens map[string][]string 197 } 198 199 // NewServerStorer constructor 200 func NewServerStorer() *ServerStorer { 201 return &ServerStorer{ 202 Users: make(map[string]*User), 203 RMTokens: make(map[string][]string), 204 } 205 } 206 207 // New constructs a blank user to later be created 208 func (s *ServerStorer) New(context.Context) authboss.User { 209 return &User{} 210 } 211 212 // Create a user 213 func (s *ServerStorer) Create(ctx context.Context, user authboss.User) error { 214 u := user.(*User) 215 if _, ok := s.Users[u.Email]; ok { 216 return authboss.ErrUserFound 217 } 218 s.Users[u.Email] = u 219 return nil 220 } 221 222 // Load a user 223 func (s *ServerStorer) Load(ctx context.Context, key string) (authboss.User, error) { 224 user, ok := s.Users[key] 225 if ok { 226 return user, nil 227 } 228 229 return nil, authboss.ErrUserNotFound 230 } 231 232 // Save a user 233 func (s *ServerStorer) Save(ctx context.Context, user authboss.User) error { 234 u := user.(*User) 235 if _, ok := s.Users[u.Email]; !ok { 236 return authboss.ErrUserNotFound 237 } 238 s.Users[u.Email] = u 239 return nil 240 } 241 242 // NewFromOAuth2 finds a user with the given details, or returns a new one 243 func (s *ServerStorer) NewFromOAuth2(ctx context.Context, provider string, details map[string]string) (authboss.OAuth2User, error) { 244 uid := details["uid"] 245 email := details["email"] 246 name := details["name"] 247 pid := authboss.MakeOAuth2PID(provider, uid) 248 249 u, ok := s.Users[pid] 250 if ok { 251 u.Username = name 252 u.Email = email 253 return u, nil 254 } 255 256 return &User{ 257 OAuth2UID: uid, 258 OAuth2Provider: provider, 259 Email: email, 260 Username: name, 261 }, nil 262 } 263 264 // SaveOAuth2 creates a user if not found, or updates one that exists. 265 func (s *ServerStorer) SaveOAuth2(ctx context.Context, user authboss.OAuth2User) error { 266 u := user.(*User) 267 268 pid := authboss.MakeOAuth2PID(u.OAuth2Provider, u.OAuth2UID) 269 // Since we don't have to differentiate between 270 // insert/update in a map, we just overwrite 271 s.Users[pid] = u 272 return nil 273 } 274 275 // LoadByConfirmSelector finds a user by his confirm selector 276 func (s *ServerStorer) LoadByConfirmSelector(ctx context.Context, selector string) (authboss.ConfirmableUser, error) { 277 for _, v := range s.Users { 278 if v.ConfirmSelector == selector { 279 return v, nil 280 } 281 } 282 283 return nil, authboss.ErrUserNotFound 284 } 285 286 // LoadByRecoverSelector finds a user by his recover token 287 func (s *ServerStorer) LoadByRecoverSelector(ctx context.Context, selector string) (authboss.RecoverableUser, error) { 288 for _, v := range s.Users { 289 if v.RecoverSelector == selector { 290 return v, nil 291 } 292 } 293 294 return nil, authboss.ErrUserNotFound 295 } 296 297 // AddRememberToken for remember me 298 func (s *ServerStorer) AddRememberToken(ctx context.Context, key, token string) error { 299 arr := s.RMTokens[key] 300 s.RMTokens[key] = append(arr, token) 301 return nil 302 } 303 304 // DelRememberTokens for a user 305 func (s *ServerStorer) DelRememberTokens(ctx context.Context, key string) error { 306 delete(s.RMTokens, key) 307 return nil 308 } 309 310 // UseRememberToken if it exists, deleting it in the process 311 func (s *ServerStorer) UseRememberToken(ctx context.Context, givenKey, token string) (err error) { 312 arr, ok := s.RMTokens[givenKey] 313 if !ok { 314 return authboss.ErrTokenNotFound 315 } 316 317 for i, tok := range arr { 318 if tok == token { 319 if len(arr) == 1 { 320 delete(s.RMTokens, givenKey) 321 return nil 322 } 323 324 arr[i] = arr[len(arr)-1] 325 s.RMTokens[givenKey] = arr[:len(arr)-2] 326 return nil 327 } 328 } 329 330 return authboss.ErrTokenNotFound 331 } 332 333 // FailStorer is used for testing module initialize functions that 334 // recover more than the base storer 335 type FailStorer struct { 336 User 337 } 338 339 // Create fails 340 func (FailStorer) Create(context.Context) error { 341 return errors.New("fail storer: create") 342 } 343 344 // Save fails 345 func (FailStorer) Save(context.Context) error { 346 return errors.New("fail storer: put") 347 } 348 349 // Load fails 350 func (FailStorer) Load(context.Context) error { 351 return errors.New("fail storer: get") 352 } 353 354 // ClientState is used for testing the client stores on context 355 type ClientState struct { 356 Values map[string]string 357 GetShouldFail bool 358 } 359 360 // NewClientState constructs a ClientStorer 361 func NewClientState(data ...string) *ClientState { 362 if len(data) != 0 && len(data)%2 != 0 { 363 panic("It should be a key value list of arguments.") 364 } 365 366 values := make(map[string]string) 367 368 for i := 0; i < len(data)-1; i += 2 { 369 values[data[i]] = data[i+1] 370 } 371 372 return &ClientState{Values: values} 373 } 374 375 // Get a key's value 376 func (m *ClientState) Get(key string) (string, bool) { 377 if m.GetShouldFail { 378 return "", false 379 } 380 381 v, ok := m.Values[key] 382 return v, ok 383 } 384 385 // Put a value 386 func (m *ClientState) Put(key, val string) { m.Values[key] = val } 387 388 // Del a key/value pair 389 func (m *ClientState) Del(key string) { delete(m.Values, key) } 390 391 // ClientStateRW stores things that would originally 392 // go in a session, or a map, in memory! 393 type ClientStateRW struct { 394 ClientValues map[string]string 395 } 396 397 // NewClientRW takes the data from a client state 398 // and returns. 399 func NewClientRW() *ClientStateRW { 400 return &ClientStateRW{ 401 ClientValues: make(map[string]string), 402 } 403 } 404 405 // ReadState from memory 406 func (c *ClientStateRW) ReadState(*http.Request) (authboss.ClientState, error) { 407 return &ClientState{Values: c.ClientValues}, nil 408 } 409 410 // WriteState to memory 411 func (c *ClientStateRW) WriteState(w http.ResponseWriter, cstate authboss.ClientState, cse []authboss.ClientStateEvent) error { 412 for _, e := range cse { 413 switch e.Kind { 414 case authboss.ClientStateEventPut: 415 c.ClientValues[e.Key] = e.Value 416 case authboss.ClientStateEventDel: 417 delete(c.ClientValues, e.Key) 418 case authboss.ClientStateEventDelAll: 419 c.ClientValues = make(map[string]string) 420 } 421 } 422 423 return nil 424 } 425 426 // Request returns a new request with optional key-value body (form-post) 427 func Request(method string, postKeyValues ...string) *http.Request { 428 var body io.Reader 429 location := "http://localhost" 430 431 if len(postKeyValues) > 0 { 432 urlValues := make(url.Values) 433 for i := 0; i < len(postKeyValues); i += 2 { 434 urlValues.Set(postKeyValues[i], postKeyValues[i+1]) 435 } 436 437 if method == "POST" || method == "PUT" { 438 body = strings.NewReader(urlValues.Encode()) 439 } else { 440 location += "?" + urlValues.Encode() 441 } 442 } 443 444 req, err := http.NewRequest(method, location, body) 445 if err != nil { 446 panic(err.Error()) 447 } 448 449 if len(postKeyValues) > 0 { 450 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 451 } 452 453 return req 454 } 455 456 // Mailer helps simplify mailer testing by storing the last sent email 457 type Mailer struct { 458 Last authboss.Email 459 SendErr string 460 } 461 462 // NewMailer constructs a mailer 463 func NewMailer() *Mailer { 464 return &Mailer{} 465 } 466 467 // Send an e-mail 468 func (m *Mailer) Send(ctx context.Context, email authboss.Email) error { 469 if len(m.SendErr) > 0 { 470 return errors.New(m.SendErr) 471 } 472 473 m.Last = email 474 return nil 475 } 476 477 // AfterCallback is a callback that knows if it was called 478 type AfterCallback struct { 479 HasBeenCalled bool 480 Fn authboss.EventHandler 481 } 482 483 // NewAfterCallback constructs a new aftercallback. 484 func NewAfterCallback() *AfterCallback { 485 m := AfterCallback{} 486 487 m.Fn = func(http.ResponseWriter, *http.Request, bool) (bool, error) { 488 m.HasBeenCalled = true 489 return false, nil 490 } 491 492 return &m 493 } 494 495 // Renderer mock 496 type Renderer struct { 497 Pages []string 498 499 // Render call variables 500 Context context.Context 501 Page string 502 Data authboss.HTMLData 503 } 504 505 // HasLoadedViews ensures the views were loaded 506 func (r *Renderer) HasLoadedViews(pages ...string) error { 507 if len(r.Pages) != len(pages) { 508 return errors.Errorf("want: %d loaded views, got: %d", len(pages), len(r.Pages)) 509 } 510 511 for i, want := range pages { 512 got := r.Pages[i] 513 if want != got { 514 return errors.Errorf("want: %s [%d], got: %s", want, i, got) 515 } 516 } 517 518 return nil 519 } 520 521 // Load nothing but store the pages that were loaded 522 func (r *Renderer) Load(pages ...string) error { 523 r.Pages = append(r.Pages, pages...) 524 return nil 525 } 526 527 // Render nothing, but record the arguments into the renderer 528 func (r *Renderer) Render(ctx context.Context, page string, data authboss.HTMLData) ([]byte, string, error) { 529 r.Context = ctx 530 r.Page = page 531 r.Data = data 532 return nil, "text/html", nil 533 } 534 535 // Responder records how a request was responded to 536 type Responder struct { 537 Status int 538 Page string 539 Data authboss.HTMLData 540 } 541 542 // Respond stores the arguments in the struct 543 func (r *Responder) Respond(w http.ResponseWriter, req *http.Request, code int, page string, data authboss.HTMLData) error { 544 r.Status = code 545 r.Page = page 546 r.Data = data 547 548 return nil 549 } 550 551 // Redirector stores the redirect options passed to it and writes the Code 552 // to the ResponseWriter. 553 type Redirector struct { 554 Options authboss.RedirectOptions 555 } 556 557 // Redirect a request 558 func (r *Redirector) Redirect(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error { 559 r.Options = ro 560 if len(ro.RedirectPath) == 0 { 561 panic("no redirect path on redirect call") 562 } 563 http.Redirect(w, req, ro.RedirectPath, ro.Code) 564 return nil 565 } 566 567 // Emailer that holds the options it was given 568 type Emailer struct { 569 Email authboss.Email 570 } 571 572 // Send an e-mail 573 func (e *Emailer) Send(ctx context.Context, email authboss.Email) error { 574 e.Email = email 575 return nil 576 } 577 578 // BodyReader reads the body of a request and returns some values 579 type BodyReader struct { 580 Return authboss.Validator 581 } 582 583 // Read the return values 584 func (b BodyReader) Read(page string, r *http.Request) (authboss.Validator, error) { 585 return b.Return, nil 586 } 587 588 // Values is returned from the BodyReader 589 type Values struct { 590 PID string 591 Password string 592 Token string 593 Code string 594 Recovery string 595 PhoneNumber string 596 Remember bool 597 598 Errors []error 599 } 600 601 // GetPID from values 602 func (v Values) GetPID() string { 603 return v.PID 604 } 605 606 // GetPassword from values 607 func (v Values) GetPassword() string { 608 return v.Password 609 } 610 611 // GetToken from values 612 func (v Values) GetToken() string { 613 return v.Token 614 } 615 616 // GetCode from values 617 func (v Values) GetCode() string { 618 return v.Code 619 } 620 621 // GetPhoneNumber from values 622 func (v Values) GetPhoneNumber() string { 623 return v.PhoneNumber 624 } 625 626 // GetRecoveryCode from values 627 func (v Values) GetRecoveryCode() string { 628 return v.Recovery 629 } 630 631 // GetShouldRemember gets the value that tells 632 // the remember module if it should remember the user 633 func (v Values) GetShouldRemember() bool { 634 return v.Remember 635 } 636 637 // Validate the values 638 func (v Values) Validate() []error { 639 return v.Errors 640 } 641 642 // ArbValues is arbitrary value storage 643 type ArbValues struct { 644 Values map[string]string 645 Errors []error 646 } 647 648 // GetPID gets the pid 649 func (a ArbValues) GetPID() string { 650 return a.Values["email"] 651 } 652 653 // GetPassword gets the password 654 func (a ArbValues) GetPassword() string { 655 return a.Values["password"] 656 } 657 658 // GetValues returns all values 659 func (a ArbValues) GetValues() map[string]string { 660 return a.Values 661 } 662 663 // Validate nothing 664 func (a ArbValues) Validate() []error { 665 return a.Errors 666 } 667 668 // Logger logs to the void 669 type Logger struct { 670 } 671 672 // Info logging 673 func (l Logger) Info(string) {} 674 675 // Error logging 676 func (l Logger) Error(string) {} 677 678 // Router records the routes that were registered 679 type Router struct { 680 Gets []string 681 Posts []string 682 Deletes []string 683 } 684 685 // ServeHTTP does nothing 686 func (Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { 687 } 688 689 // Get records the path in the router 690 func (r *Router) Get(path string, _ http.Handler) { 691 r.Gets = append(r.Gets, path) 692 } 693 694 // Post records the path in the router 695 func (r *Router) Post(path string, _ http.Handler) { 696 r.Posts = append(r.Posts, path) 697 } 698 699 // Delete records the path in the router 700 func (r *Router) Delete(path string, _ http.Handler) { 701 r.Deletes = append(r.Deletes, path) 702 } 703 704 // HasGets ensures all gets routes are present 705 func (r *Router) HasGets(gets ...string) error { 706 return r.hasRoutes(gets, r.Gets) 707 } 708 709 // HasPosts ensures all gets routes are present 710 func (r *Router) HasPosts(posts ...string) error { 711 return r.hasRoutes(posts, r.Posts) 712 } 713 714 // HasDeletes ensures all gets routes are present 715 func (r *Router) HasDeletes(deletes ...string) error { 716 return r.hasRoutes(deletes, r.Deletes) 717 } 718 719 func (r *Router) hasRoutes(want []string, got []string) error { 720 if len(got) != len(want) { 721 return errors.Errorf("want: %d get routes, got: %d", len(want), len(got)) 722 } 723 724 for i, w := range want { 725 g := got[i] 726 if w != g { 727 return errors.Errorf("wanted route: %s [%d], but got: %s", w, i, g) 728 } 729 } 730 731 return nil 732 } 733 734 // ErrorHandler just holds the last error 735 type ErrorHandler struct { 736 Error error 737 } 738 739 // Wrap an http method 740 func (e *ErrorHandler) Wrap(handler func(w http.ResponseWriter, r *http.Request) error) http.Handler { 741 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 742 if err := handler(w, r); err != nil { 743 e.Error = err 744 } 745 }) 746 }