mirror of
https://github.com/pocketbase/pocketbase.git
synced 2025-03-20 06:21:06 +02:00
98 lines
3.3 KiB
Go
98 lines
3.3 KiB
Go
|
package apis
|
||
|
|
||
|
import (
|
||
|
"database/sql"
|
||
|
"errors"
|
||
|
|
||
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||
|
"github.com/go-ozzo/ozzo-validation/v4/is"
|
||
|
"github.com/pocketbase/pocketbase/core"
|
||
|
"github.com/pocketbase/pocketbase/tools/list"
|
||
|
)
|
||
|
|
||
|
func recordAuthWithPassword(e *core.RequestEvent) error {
|
||
|
collection, err := findAuthCollection(e)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if !collection.PasswordAuth.Enabled {
|
||
|
return e.ForbiddenError("The collection is not configured to allow password authentication.", nil)
|
||
|
}
|
||
|
|
||
|
form := &authWithPasswordForm{}
|
||
|
if err = e.BindBody(form); err != nil {
|
||
|
return firstApiError(err, e.BadRequestError("An error occurred while loading the submitted data.", err))
|
||
|
}
|
||
|
if err = form.validate(collection); err != nil {
|
||
|
return firstApiError(err, e.BadRequestError("An error occurred while validating the submitted data.", err))
|
||
|
}
|
||
|
|
||
|
var foundRecord *core.Record
|
||
|
var foundErr error
|
||
|
|
||
|
if form.IdentityField != "" {
|
||
|
foundRecord, foundErr = e.App.FindFirstRecordByData(collection.Id, form.IdentityField, form.Identity)
|
||
|
} else {
|
||
|
// prioritize email lookup
|
||
|
isEmail := is.EmailFormat.Validate(form.Identity) == nil
|
||
|
if isEmail && list.ExistInSlice(core.FieldNameEmail, collection.PasswordAuth.IdentityFields) {
|
||
|
foundRecord, foundErr = e.App.FindAuthRecordByEmail(collection.Id, form.Identity)
|
||
|
}
|
||
|
|
||
|
// search by the other identity fields
|
||
|
if !isEmail || foundErr != nil {
|
||
|
for _, name := range collection.PasswordAuth.IdentityFields {
|
||
|
if !isEmail && name == core.FieldNameEmail {
|
||
|
continue // no need to search by the email field if it is not an email
|
||
|
}
|
||
|
|
||
|
foundRecord, foundErr = e.App.FindFirstRecordByData(collection.Id, name, form.Identity)
|
||
|
if foundErr == nil {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ignore not found errors to allow custom record find implementations
|
||
|
if foundErr != nil && !errors.Is(foundErr, sql.ErrNoRows) {
|
||
|
return e.InternalServerError("", foundErr)
|
||
|
}
|
||
|
|
||
|
event := new(core.RecordAuthWithPasswordRequestEvent)
|
||
|
event.RequestEvent = e
|
||
|
event.Collection = collection
|
||
|
event.Record = foundRecord
|
||
|
event.Identity = form.Identity
|
||
|
event.Password = form.Password
|
||
|
event.IdentityField = form.IdentityField
|
||
|
|
||
|
return e.App.OnRecordAuthWithPasswordRequest().Trigger(event, func(e *core.RecordAuthWithPasswordRequestEvent) error {
|
||
|
if e.Record == nil || !e.Record.ValidatePassword(e.Password) {
|
||
|
return e.BadRequestError("Failed to authenticate.", errors.New("invalid login credentials"))
|
||
|
}
|
||
|
|
||
|
return RecordAuthResponse(e.RequestEvent, e.Record, core.MFAMethodPassword, nil)
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// -------------------------------------------------------------------
|
||
|
|
||
|
type authWithPasswordForm struct {
|
||
|
Identity string `form:"identity" json:"identity"`
|
||
|
Password string `form:"password" json:"password"`
|
||
|
|
||
|
// IdentityField specifies the field to use to search for the identity
|
||
|
// (leave it empty for "auto" detection).
|
||
|
IdentityField string `form:"identityField" json:"identityField"`
|
||
|
}
|
||
|
|
||
|
func (form *authWithPasswordForm) validate(collection *core.Collection) error {
|
||
|
return validation.ValidateStruct(form,
|
||
|
validation.Field(&form.Identity, validation.Required, validation.Length(1, 255)),
|
||
|
validation.Field(&form.Password, validation.Required, validation.Length(1, 255)),
|
||
|
validation.Field(&form.IdentityField, validation.In(list.ToInterfaceSlice(collection.PasswordAuth.IdentityFields)...)),
|
||
|
)
|
||
|
}
|