You've already forked pocketbase
							
							
				mirror of
				https://github.com/pocketbase/pocketbase.git
				synced 2025-10-31 16:47:43 +02:00 
			
		
		
		
	[#6607] allowed manually changing the password from the create/update hooks
This commit is contained in:
		| @@ -31,7 +31,7 @@ | ||||
| - Soft-deprecated the `$http.send`'s `result.raw` field in favor of `result.body` that contains the response body as plain bytes slice to avoid the discrepancies between Go and the JSVM when casting binary data to string. | ||||
|   (@todo update docs to use the new field) | ||||
|  | ||||
| - Minor UI fixes (_removed the superuser fields from the auth record create/update body examples, etc._). | ||||
| - Other minor improvements (_removed the superuser fields from the auth record create/update body examples, allowed programmatically updating the auth record password from the create/update hooks, etc._). | ||||
|  | ||||
|  | ||||
| ## v0.26.6 | ||||
|   | ||||
| @@ -27,9 +27,10 @@ type RecordUpsert struct { | ||||
| 	accessLevel int | ||||
|  | ||||
| 	// extra password fields | ||||
| 	password        string | ||||
| 	passwordConfirm string | ||||
| 	oldPassword     string | ||||
| 	disablePasswordValidations bool | ||||
| 	password                   string | ||||
| 	passwordConfirm            string | ||||
| 	oldPassword                string | ||||
| } | ||||
|  | ||||
| // NewRecordUpsert creates a new [RecordUpsert] form from the provided [core.App] and [core.Record] instances | ||||
| @@ -130,6 +131,8 @@ func (form *RecordUpsert) validateFormFields() error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	form.syncPasswordFields() | ||||
|  | ||||
| 	isNew := form.record.IsNew() | ||||
|  | ||||
| 	original := form.record.Original() | ||||
| @@ -165,17 +168,17 @@ func (form *RecordUpsert) validateFormFields() error { | ||||
| 			validation.Key( | ||||
| 				"password", | ||||
| 				validation.When( | ||||
| 					(isNew || form.passwordConfirm != "" || form.oldPassword != ""), | ||||
| 					!form.disablePasswordValidations && (isNew || form.passwordConfirm != "" || form.oldPassword != ""), | ||||
| 					validation.Required, | ||||
| 				), | ||||
| 			), | ||||
| 			validation.Key( | ||||
| 				"passwordConfirm", | ||||
| 				validation.When( | ||||
| 					(isNew || form.password != "" || form.oldPassword != ""), | ||||
| 					!form.disablePasswordValidations && (isNew || form.password != "" || form.oldPassword != ""), | ||||
| 					validation.Required, | ||||
| 				), | ||||
| 				validation.By(validators.Equal(form.password)), | ||||
| 				validation.When(!form.disablePasswordValidations, validation.By(validators.Equal(form.password))), | ||||
| 			), | ||||
| 			validation.Key( | ||||
| 				"oldPassword", | ||||
| @@ -183,7 +186,7 @@ func (form *RecordUpsert) validateFormFields() error { | ||||
| 				// - form.HasManageAccess() is not satisfied | ||||
| 				// - changing the existing password | ||||
| 				validation.When( | ||||
| 					!isNew && !form.HasManageAccess() && (form.password != "" || form.passwordConfirm != ""), | ||||
| 					!form.disablePasswordValidations && !isNew && !form.HasManageAccess() && (form.password != "" || form.passwordConfirm != ""), | ||||
| 					validation.Required, | ||||
| 					validation.By(form.checkOldPassword), | ||||
| 				), | ||||
| @@ -287,3 +290,27 @@ func (form *RecordUpsert) Submit() error { | ||||
| 	// run record validations and persist in db | ||||
| 	return form.app.SaveWithContext(form.ctx, form.record) | ||||
| } | ||||
|  | ||||
| // syncPasswordFields syncs the form's auth password fields with their | ||||
| // corresponding record field values. | ||||
| // | ||||
| // This could be useful in case the password fields were programmatically set | ||||
| // directly by modifying the related record model. | ||||
| func (form *RecordUpsert) syncPasswordFields() { | ||||
| 	if !form.record.Collection().IsAuth() { | ||||
| 		return // not an auth collection | ||||
| 	} | ||||
|  | ||||
| 	form.disablePasswordValidations = false | ||||
|  | ||||
| 	rawPassword := form.record.GetRaw(core.FieldNamePassword) | ||||
| 	if v, ok := rawPassword.(*core.PasswordFieldValue); ok && v != nil { | ||||
| 		if | ||||
| 		// programmatically set custom plain password value | ||||
| 		(v.Plain != "" && v.Plain != form.password) || | ||||
| 			// random generated password for new record | ||||
| 			(v.Plain == "" && v.Hash != "" && form.record.IsNew()) { | ||||
| 			form.disablePasswordValidations = true | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -887,6 +887,119 @@ func TestRecordUpsertSubmitSuccess(t *testing.T) { | ||||
| 	testFilesCount(t, testApp, record, 2) // the file + attrs | ||||
| } | ||||
|  | ||||
| func TestRecordUpsertPasswordsSync(t *testing.T) { | ||||
| 	testApp, _ := tests.NewTestApp() | ||||
| 	defer testApp.Cleanup() | ||||
|  | ||||
| 	users, err := testApp.FindCollectionByNameOrId("users") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	t.Run("new user without password", func(t *testing.T) { | ||||
| 		record := core.NewRecord(users) | ||||
|  | ||||
| 		form := forms.NewRecordUpsert(testApp, record) | ||||
|  | ||||
| 		err := form.Submit() | ||||
|  | ||||
| 		tests.TestValidationErrors(t, err, []string{"password", "passwordConfirm"}) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("new user with manual password", func(t *testing.T) { | ||||
| 		record := core.NewRecord(users) | ||||
|  | ||||
| 		form := forms.NewRecordUpsert(testApp, record) | ||||
|  | ||||
| 		record.SetPassword("1234567890") | ||||
|  | ||||
| 		err := form.Submit() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Expected no errors, got %v", err) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("new user with random password", func(t *testing.T) { | ||||
| 		record := core.NewRecord(users) | ||||
|  | ||||
| 		form := forms.NewRecordUpsert(testApp, record) | ||||
|  | ||||
| 		record.SetRandomPassword() | ||||
|  | ||||
| 		err := form.Submit() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Expected no errors, got %v", err) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("update user with no password change", func(t *testing.T) { | ||||
| 		record, err := testApp.FindAuthRecordByEmail(users, "test@example.com") | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		oldHash := record.GetString("password:hash") | ||||
|  | ||||
| 		form := forms.NewRecordUpsert(testApp, record) | ||||
|  | ||||
| 		err = form.Submit() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Expected no errors, got %v", err) | ||||
| 		} | ||||
|  | ||||
| 		newHash := record.GetString("password:hash") | ||||
| 		if newHash == "" || newHash != oldHash { | ||||
| 			t.Fatal("Expected no password change") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("update user with manual password change", func(t *testing.T) { | ||||
| 		record, err := testApp.FindAuthRecordByEmail(users, "test@example.com") | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		oldHash := record.GetString("password:hash") | ||||
|  | ||||
| 		form := forms.NewRecordUpsert(testApp, record) | ||||
|  | ||||
| 		record.SetPassword("1234567890") | ||||
|  | ||||
| 		err = form.Submit() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Expected no errors, got %v", err) | ||||
| 		} | ||||
|  | ||||
| 		newHash := record.GetString("password:hash") | ||||
| 		if newHash == "" || newHash == oldHash { | ||||
| 			t.Fatal("Expected password change") | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("update user with random password change", func(t *testing.T) { | ||||
| 		record, err := testApp.FindAuthRecordByEmail(users, "test@example.com") | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		oldHash := record.GetString("password:hash") | ||||
|  | ||||
| 		form := forms.NewRecordUpsert(testApp, record) | ||||
|  | ||||
| 		record.SetRandomPassword() | ||||
|  | ||||
| 		err = form.Submit() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("Expected no errors, got %v", err) | ||||
| 		} | ||||
|  | ||||
| 		newHash := record.GetString("password:hash") | ||||
| 		if newHash == "" || newHash == oldHash { | ||||
| 			t.Fatal("Expected password change") | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // ------------------------------------------------------------------- | ||||
|  | ||||
| func testFilesCount(t *testing.T, app core.App, record *core.Record, count int) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user