// Test that only valid previlege and password can be updated
func Test_updateAM(t *testing.T) {
	privilege := make(map[string]interface{})
	for k, v := range usersPrivilege {
		privilege[k] = v
	}
	privilege["undef"] = ""
	userPwd, _ := password.NewUserPwd(defaultPassword, defaultSalt)
	userAm, _ := NewUserAm(SuperUserPermission, defaultPassword, defaultSalt)
	pwd := ""
	for p, _ := range privilege {
		for i := 0; i < password.MaxPasswordLength; i++ {
			pOk := IsValidPrivilege(p)
			pwdOk := userPwd.IsNewPwdValid([]byte(pwd))
			ok := pOk == nil && pwdOk == nil
			updatePOk := userAm.UpdateUserPrivilege(p)
			updatePwdOk := userAm.UpdateUserPwd(defaultUserName, userAm.Pwd.Password, []byte(pwd))
			updateOk := updatePOk == nil && updatePwdOk == nil
			if ok == false && updateOk == true {
				t.Errorf("Test fail: Successfully updated user AM with invalid parameters: privilege '%v' (%v) password '%v' (%v)",
					p, pOk, pwd, pwdOk)
				t.FailNow()
			} else if ok == true && updateOk == false {
				t.Errorf("Test fail: Error while updating user AM with valid parameters: privilege '%v' (%v) password '%v' (%v), error: update privilege: %v, update password %v",
					p, pOk, pwd, pwdOk, updatePOk, updatePwdOk)
				t.FailNow()
			}
			pwd += "a"
		}
	}
}
// Test that a new user AM is generated only when all the parameters are valid
func Test_addValidAM(t *testing.T) {
	usersName := []string{defaultUserName, ""}
	privilege := make(map[string]interface{})
	for k, v := range usersPrivilege {
		privilege[k] = v
	}
	privilege["undef"] = ""
	userPwd, _ := password.NewUserPwd(defaultPassword, defaultSalt)
	pwd := ""
	for _, userName := range usersName {
		for p, _ := range privilege {
			for i := 0; i < password.MaxPasswordLength; i++ {
				ok := en.IsEntityNameValid(userName) == nil &&
					IsValidPrivilege(p) == nil &&
					userPwd.IsNewPwdValid([]byte(pwd)) == nil
				_, err := NewUserAm(p, []byte(pwd), defaultSalt)
				if ok == false && err == nil {
					t.Errorf("Test fail: Successfully generated new AM with invalid parameters: user name '%v' (%v), privilege '%v' (%v) password '%v' (%v)",
						userName, en.IsEntityNameValid(userName), p, IsValidPrivilege(p), pwd, userPwd.IsNewPwdValid([]byte(pwd)))
					t.FailNow()
				} else if ok == true && err != nil {
					t.Errorf("Test fail: Error while generated new AM with valid parameters: user name '%v' (%v), privilege '%v' (%v) password '%v' (%v), error: %v",
						userName, en.IsEntityNameValid(userName), p, IsValidPrivilege(p), pwd, userPwd.IsNewPwdValid([]byte(pwd)), err)
					t.FailNow()
				}
				pwd += "a"
			}
		}
	}
}
// Generate and return a new Account Management object using the given priviledge, password and salt (in case they are valid)
func NewUserAm(privilege string, pass []byte, saltData []byte) (*AmUserInfo, error) {
	err := IsValidPrivilege(privilege)
	if err != nil {
		return nil, err
	}
	// was userPwd := password.UserPwd{Password: pass, Expiration: getPwdExpiration(id), Salt: saltData}
	userPwd, err := password.NewUserPwd(pass, saltData)
	if err != nil {
		return nil, err
	}
	return &AmUserInfo{Pwd: *userPwd, Privilege: privilege}, nil
}
func GenerateUserData(el *EntityManager, usersName []string, secret []byte, salt []byte) {
	el.AddUser(usersName[0])
	amData, _ := am.NewUserAm(am.SuperUserPermission, secret, salt)
	el.AddPropertyToEntity(usersName[0], stc.AmPropertyName, amData)
	otpData, _ := otp.NewSimpleOtpUser(secret)
	el.AddPropertyToEntity(usersName[0], stc.OtpPropertyName, otpData)
	pwdData, _ := password.NewUserPwd(secret, salt)
	el.AddPropertyToEntity(usersName[0], stc.PwdPropertyName, pwdData)
	ocraData, _ := ocra.NewOcraUser([]byte("ABCD1234"), "OCRA-1:HOTP-SHA512-8:C-QH08-T1M-S064-PSHA256")
	el.AddPropertyToEntity(usersName[0], stc.OcraPropertyName, ocraData)

	el.AddUser(usersName[1])
	el.AddPropertyToEntity(usersName[1], stc.OtpPropertyName, otpData)
}
func (p pwdRestful) restAddPwd(request *restful.Request, response *restful.Response) {
	var secret secretData
	name := request.PathParameter(userIdParam)

	err := request.ReadEntity(&secret)
	if err != nil {
		p.setError(response, http.StatusBadRequest, err)
		return
	}
	data, err := password.NewUserPwd([]byte(secret.Password), p.saltStr)
	if err != nil {
		p.setError(response, http.StatusBadRequest, err)
		return
	}
	p.st.UsersList.AddPropertyToEntity(name, stc.PwdPropertyName, data)
	response.WriteHeader(http.StatusCreated)
	response.WriteEntity(p.getUrlPath(request, name))
}
// Example of how to use the reset password function:
// This function resets the current password,
// selects a new password with short expiration time
// and lets the user use it exactly once
func ExampleUserPwd_ResetPasword() {
	id := "User1"
	pwd := []byte("a1b2c3d")

	saltStr, _ := salt.GetRandomSalt(10)
	userPwd, _ := password.NewUserPwd(pwd, saltStr)
	tmpPwd, _ := userPwd.ResetPasword()
	tPwd, _ := salt.GenerateSaltedPassword(tmpPwd, 1, 100, saltStr, -1)
	newPwd := password.GetHashedPwd(tPwd)
	err := userPwd.IsPasswordMatch(newPwd)
	if err != nil {
		fmt.Printf("Check of newly generated password: '******' for user: %v failed, error: %v\n", newPwd, id, err)
	} else {
		fmt.Printf("Entity %v, after reseting password '%v' verified successfuly\n", id, newPwd)
	}
	err = userPwd.IsPasswordMatch(newPwd)
	if err == nil {
		fmt.Printf("Error: Newly generated password: '******' could be used only once\n", newPwd)
	} else {
		fmt.Printf("Newly generated password: '******', for entity: %v, can only be used once\n", newPwd, id)
	}
}
// Example of how to use the password.
// 1. Create a new password.
// 2. Verify that the initial password is set correctly
// 3. Change the user's password
// 4. Verify that the old password is not valid anymore
// 5. Verify that the new password is valid
// 6. Verify that the old password can't be used any more
//     (at least not as long as it remains in the old passwords list)
func ExampleUserPwd() {
	id := "User-1"
	pwd := []byte("a1b2c3d")
	saltStr, _ := salt.GetRandomSalt(8)

	userPwd, _ := password.NewUserPwd(pwd, saltStr)
	tPwd, _ := salt.GenerateSaltedPassword(pwd, minPasswordLength, maxPasswordLength, saltStr, -1)
	newPwd := password.GetHashedPwd(tPwd)
	err := userPwd.IsPasswordMatch(newPwd)
	if err != nil {
		fmt.Println("Ravid: error", err)
	}
	userNewPwd := []byte(string(pwd) + "a")
	newPwd, err = userPwd.UpdatePassword(userPwd.Password, userNewPwd)
	if err != nil {
		fmt.Printf("Password update for user %v to new password '%v' (%v) failed, error: %v\n", id, newPwd, string(userNewPwd), err)
	} else {
		fmt.Printf("User: '******', updated password to '%v' (%v)\n", id, newPwd, string(userNewPwd))
	}
	err = userPwd.IsPasswordMatch(newPwd)
	if err != nil {
		fmt.Printf("Check of the new password: '******' (%v) for user: %v failed, error: %v\n", newPwd, string(userNewPwd), id, err)
	} else {
		fmt.Printf("User: '******', new password '%v' (%v) verified successfuly\n", id, newPwd, string(userNewPwd))
	}
	err = userPwd.IsPasswordMatch(pwd)
	if err == nil {
		fmt.Printf("Error: Old password: '******' (%v) for user: %v accepted\n", pwd, string(pwd), id)
	} else {
		fmt.Printf("User: '******', Note that the old password '%v' (%v) can't be used anymore\n", id, pwd, string(pwd))
	}
	newPwd, err = userPwd.UpdatePassword(userPwd.Password, pwd)
	if err == nil {
		fmt.Printf("Error: Password '%v' (typed password %v) for user %v was alredy used\n", newPwd, string(pwd), id)
	} else {
		fmt.Printf("Entity: '%v', Note that the old password (entered password) %v as it was already used\n", id, string(pwd))
	}
}
func Test_AddCheckRemovePwdUserProperty(t *testing.T) {
	moduleData, _ := password.NewUserPwd(secret, salt)

	testAddCheckRemoveUserProperty(t, stc.PwdPropertyName, moduleData)
}