github.com/decred/politeia@v1.4.0/politeiawww/legacy/cmsuser_test.go (about)

     1  // Copyright (c) 2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package legacy
     6  
     7  import (
     8  	"encoding/hex"
     9  	"testing"
    10  	"time"
    11  
    12  	cms "github.com/decred/politeia/politeiawww/api/cms/v1"
    13  	www "github.com/decred/politeia/politeiawww/api/www/v1"
    14  	"github.com/decred/politeia/politeiawww/cmd/shared"
    15  	"github.com/decred/politeia/politeiawww/legacy/user"
    16  	"github.com/decred/politeia/util"
    17  )
    18  
    19  func TestInviteNewUser(t *testing.T) {
    20  	p, cleanup := newTestCMSwww(t)
    21  	defer cleanup()
    22  
    23  	emailVerified := "test1@example.org"
    24  	inviteUserReq := cms.InviteNewUser{
    25  		Email:     emailVerified,
    26  		Temporary: false,
    27  	}
    28  	reply, err := p.processInviteNewUser(inviteUserReq)
    29  	if err != nil {
    30  		t.Fatalf("error inviting user %v", err)
    31  	}
    32  
    33  	id, err := shared.NewIdentity()
    34  	if err != nil {
    35  		t.Fatalf("error another generating identity")
    36  	}
    37  	registerReq := cms.RegisterUser{
    38  		Email:             emailVerified,
    39  		Username:          "test1",
    40  		Password:          "password",
    41  		VerificationToken: reply.VerificationToken,
    42  		PublicKey:         hex.EncodeToString(id.Public.Key[:]),
    43  	}
    44  	_, err = p.processRegisterUser(registerReq)
    45  	if err != nil {
    46  		t.Fatalf("error registering user %v", err)
    47  	}
    48  
    49  	emailFreshToken := "test2@example.org"
    50  	inviteUserReq = cms.InviteNewUser{
    51  		Email:     emailFreshToken,
    52  		Temporary: false,
    53  	}
    54  	replyFresh, err := p.processInviteNewUser(inviteUserReq)
    55  	if err != nil {
    56  		t.Fatalf("error inviting user %v", err)
    57  	}
    58  
    59  	var tests = []struct {
    60  		name       string
    61  		email      string
    62  		wantError  error
    63  		tokenEmpty bool
    64  		tokenFresh bool
    65  	}{
    66  		{
    67  			"success",
    68  			"test@example.com",
    69  			nil,
    70  			false,
    71  			false,
    72  		},
    73  		{
    74  			"success new token",
    75  			emailFreshToken,
    76  			nil,
    77  			false,
    78  			true,
    79  		},
    80  		{
    81  			"success already verified",
    82  			emailVerified,
    83  			nil,
    84  			true,
    85  			false,
    86  		},
    87  		{
    88  			"error malformed",
    89  			"testemailmalformed",
    90  			www.UserError{
    91  				ErrorCode: www.ErrorStatusMalformedEmail,
    92  			},
    93  			false,
    94  			false,
    95  		},
    96  	}
    97  
    98  	for _, v := range tests {
    99  		t.Run(v.name, func(t *testing.T) {
   100  			inviteUserReq := cms.InviteNewUser{
   101  				Email:     v.email,
   102  				Temporary: false,
   103  			}
   104  			replyInvite, err := p.processInviteNewUser(inviteUserReq)
   105  
   106  			got := errToStr(err)
   107  			want := errToStr(v.wantError)
   108  			if got != want {
   109  				t.Errorf("got error %v, want %v", got, want)
   110  				return
   111  			}
   112  			// exit tests if err was received since error matched as expected
   113  			if err != nil {
   114  				return
   115  			}
   116  			if replyInvite == nil {
   117  				t.Errorf("invite reply should not be nil here")
   118  				return
   119  			}
   120  			if v.tokenEmpty && len(replyInvite.VerificationToken) > 0 {
   121  				// If token is expected to be empty
   122  				t.Errorf("expecting an empty verification token but got %v",
   123  					replyInvite.VerificationToken)
   124  			}
   125  			if !v.tokenEmpty && len(replyInvite.VerificationToken) == 0 {
   126  				// If token is expected to be non-empty
   127  				t.Errorf("expecting an non-empty verification token but got empty")
   128  			}
   129  			if v.tokenFresh &&
   130  				replyInvite.VerificationToken == replyFresh.VerificationToken {
   131  				// If token is expected to be fresh from one previously received
   132  				t.Errorf("expecting fresh token but got the same")
   133  			}
   134  		})
   135  	}
   136  
   137  	emailFirst := "testtemp1@example.org"
   138  
   139  	emailSecond := "testtemp2@example.org"
   140  
   141  	var testsTempInvite = []struct {
   142  		name                   string
   143  		email                  string
   144  		temp                   bool
   145  		expectedContractorType cms.ContractorTypeT
   146  	}{
   147  		{
   148  			"success",
   149  			emailFirst,
   150  			false,
   151  			cms.ContractorTypeNominee,
   152  		},
   153  		{
   154  			"success temp",
   155  			emailSecond,
   156  			true,
   157  			cms.ContractorTypeTemp,
   158  		},
   159  	}
   160  
   161  	for _, v := range testsTempInvite {
   162  		t.Run(v.name, func(t *testing.T) {
   163  			inviteUserReq := cms.InviteNewUser{
   164  				Email:     v.email,
   165  				Temporary: v.temp,
   166  			}
   167  			_, err := p.processInviteNewUser(inviteUserReq)
   168  			if err != nil {
   169  				t.Errorf("error inviting user %v %v", v.email, err)
   170  				return
   171  			}
   172  			u, err := p.userByEmail(v.email)
   173  			if err != nil {
   174  				t.Errorf("error getting user by email %v %v", v.email, err)
   175  				return
   176  			}
   177  
   178  			cmsUser, err := p.getCMSUserByID(u.ID.String())
   179  			if err != nil {
   180  				t.Errorf("error getting cms user by id %v %v", u.ID.String(),
   181  					err)
   182  				return
   183  			}
   184  
   185  			if cmsUser.ContractorType != v.expectedContractorType {
   186  				t.Errorf("unexpected contractor type got %v, want %v",
   187  					cmsUser.ContractorType, v.expectedContractorType)
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  func TestRegisterUser(t *testing.T) {
   194  	p, cleanup := newTestCMSwww(t)
   195  	defer cleanup()
   196  
   197  	// Create user identity and save it to disk
   198  	id, err := shared.NewIdentity()
   199  	if err != nil {
   200  		t.Fatalf("error generating identity")
   201  	}
   202  
   203  	email := "test1@example.org"
   204  	username := "test1"
   205  	pwd := "password1"
   206  
   207  	inviteUserReq := cms.InviteNewUser{
   208  		Email:     email,
   209  		Temporary: false,
   210  	}
   211  	reply, err := p.processInviteNewUser(inviteUserReq)
   212  	if err != nil {
   213  		t.Fatalf("error inviting user %v", err)
   214  	}
   215  
   216  	// Create another user identity and save it to disk
   217  	idFresh, err := shared.NewIdentity()
   218  	if err != nil {
   219  		t.Fatalf("error another generating identity")
   220  	}
   221  	emailFresh := "test2@example.org"
   222  	usernameFresh := "test2"
   223  
   224  	inviteUserReqFresh := cms.InviteNewUser{
   225  		Email:     emailFresh,
   226  		Temporary: false,
   227  	}
   228  	replyFresh, err := p.processInviteNewUser(inviteUserReqFresh)
   229  	if err != nil {
   230  		t.Fatalf("error inviting user %v", err)
   231  	}
   232  
   233  	usernameTooShort := "a"
   234  	usernameTooLong := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
   235  	usernameRegExp := "?blahg!"
   236  
   237  	passwordTooShort := "a"
   238  
   239  	usernameExpired := "test3"
   240  	emailExpired := "test3@example.org"
   241  	tokenb, err := util.Random(www.VerificationTokenSize)
   242  	if err != nil {
   243  		t.Fatalf("unable to generate verification token %v", err)
   244  	}
   245  	d := time.Duration(www.VerificationExpiryHours) * time.Hour
   246  	expiry := time.Now().Add(-1 * d).Unix()
   247  
   248  	idExpired, err := shared.NewIdentity()
   249  	if err != nil {
   250  		t.Fatalf("error another generating identity")
   251  	}
   252  
   253  	// Create a new User record
   254  	u := user.User{
   255  		Email:                     emailExpired,
   256  		Username:                  emailExpired,
   257  		NewUserVerificationToken:  tokenb,
   258  		NewUserVerificationExpiry: expiry,
   259  	}
   260  	err = p.db.UserNew(u)
   261  	if err != nil {
   262  		t.Fatalf("error creating expired token user %v", err)
   263  	}
   264  
   265  	usr, err := p.db.UserGetByUsername(u.Username)
   266  	if err != nil {
   267  		t.Fatalf("error getting user by username %v", err)
   268  	}
   269  	p.setUserEmailsCache(usr.Email, usr.ID)
   270  	var tests = []struct {
   271  		name      string
   272  		email     string
   273  		username  string
   274  		pwd       string
   275  		token     string
   276  		wantError error
   277  		pubkey    string
   278  	}{
   279  		{
   280  			"success",
   281  			email,
   282  			username,
   283  			pwd,
   284  			reply.VerificationToken,
   285  			nil,
   286  			hex.EncodeToString(id.Public.Key[:]),
   287  		},
   288  		{
   289  			"error expired verification token",
   290  			emailExpired,
   291  			usernameExpired,
   292  			pwd,
   293  			hex.EncodeToString(tokenb),
   294  			www.UserError{
   295  				ErrorCode: www.ErrorStatusVerificationTokenExpired,
   296  			},
   297  			hex.EncodeToString(idExpired.Public.Key[:]),
   298  		},
   299  		{
   300  			"error invalid verification",
   301  			emailFresh,
   302  			usernameFresh,
   303  			pwd,
   304  			"123456",
   305  			www.UserError{
   306  				ErrorCode: www.ErrorStatusVerificationTokenInvalid,
   307  			},
   308  			hex.EncodeToString(idFresh.Public.Key[:]),
   309  		},
   310  		{
   311  			"error wrong verification",
   312  			emailFresh,
   313  			usernameFresh,
   314  			pwd,
   315  			"this is an invalid verification token",
   316  			www.UserError{
   317  				ErrorCode: www.ErrorStatusVerificationTokenInvalid,
   318  			},
   319  			hex.EncodeToString(idFresh.Public.Key[:]),
   320  		},
   321  		{
   322  			"error duplicate pubkey",
   323  			emailFresh,
   324  			usernameFresh,
   325  			pwd,
   326  			replyFresh.VerificationToken,
   327  			www.UserError{
   328  				ErrorCode: www.ErrorStatusDuplicatePublicKey,
   329  			},
   330  			hex.EncodeToString(id.Public.Key[:]),
   331  		},
   332  		{
   333  			"error invalid pubkey",
   334  			emailFresh,
   335  			usernameFresh,
   336  			pwd,
   337  			replyFresh.VerificationToken,
   338  			www.UserError{
   339  				ErrorCode: www.ErrorStatusInvalidPublicKey,
   340  			},
   341  			"this is a bad pubkey",
   342  		},
   343  		{
   344  			"error duplicate username",
   345  			emailFresh,
   346  			username,
   347  			pwd,
   348  			"12345",
   349  			www.UserError{
   350  				ErrorCode: www.ErrorStatusDuplicateUsername,
   351  			},
   352  			hex.EncodeToString(idFresh.Public.Key[:]),
   353  		},
   354  		{
   355  			"error malformed username too short",
   356  			emailFresh,
   357  			usernameTooShort,
   358  			pwd,
   359  			"123456",
   360  			www.UserError{
   361  				ErrorCode: www.ErrorStatusMalformedUsername,
   362  			},
   363  			hex.EncodeToString(idFresh.Public.Key[:]),
   364  		},
   365  		{
   366  			"error malformed username too long",
   367  			emailFresh,
   368  			usernameTooLong,
   369  			pwd,
   370  			"123456",
   371  			www.UserError{
   372  				ErrorCode: www.ErrorStatusMalformedUsername,
   373  			},
   374  			hex.EncodeToString(idFresh.Public.Key[:]),
   375  		},
   376  		{
   377  			"error malformed username reg exp",
   378  			emailFresh,
   379  			usernameRegExp,
   380  			pwd,
   381  			"123456",
   382  			www.UserError{
   383  				ErrorCode: www.ErrorStatusMalformedUsername,
   384  			},
   385  			hex.EncodeToString(idFresh.Public.Key[:]),
   386  		},
   387  		{
   388  			"error malformed password too short",
   389  			emailFresh,
   390  			usernameFresh,
   391  			passwordTooShort,
   392  			"123456",
   393  			www.UserError{
   394  				ErrorCode: www.ErrorStatusMalformedPassword,
   395  			},
   396  			hex.EncodeToString(idFresh.Public.Key[:]),
   397  		},
   398  		{
   399  			"success fresh",
   400  			emailFresh,
   401  			usernameFresh,
   402  			pwd,
   403  			replyFresh.VerificationToken,
   404  			nil,
   405  			hex.EncodeToString(idFresh.Public.Key[:]),
   406  		},
   407  		{
   408  			"error user not found",
   409  			"notfound@example.org",
   410  			"notfound",
   411  			pwd,
   412  			"123456",
   413  			www.UserError{
   414  				ErrorCode: www.ErrorStatusVerificationTokenInvalid,
   415  			},
   416  			hex.EncodeToString(idFresh.Public.Key[:]),
   417  		},
   418  	}
   419  
   420  	for _, v := range tests {
   421  		t.Run(v.name, func(t *testing.T) {
   422  			registerReq := cms.RegisterUser{
   423  				Email:             v.email,
   424  				Username:          v.username,
   425  				Password:          v.pwd,
   426  				VerificationToken: v.token,
   427  				PublicKey:         v.pubkey,
   428  			}
   429  			_, err = p.processRegisterUser(registerReq)
   430  			got := errToStr(err)
   431  			want := errToStr(v.wantError)
   432  			if got != want {
   433  				t.Errorf("got error %v, want %v", got, want)
   434  			}
   435  		})
   436  	}
   437  }