markerdmann / authboss

The boss of http auth.
MIT License
0 stars 1 forks source link

Use Go's ParseAddress for email validation #1

Open markerdmann opened 1 month ago

markerdmann commented 1 month ago

Currently, Authboss uses a regular expression to validate email addresses. However, the Go standard library provides a more robust and comprehensive email validation function called ParseAddress in the net/mail package.

To improve the email validation in Authboss, we should leverage the ParseAddress function instead of relying on a regular expression. This will ensure that email addresses are validated according to the complex rules outlined in the message.go file of the net/mail package.

Proposed changes:

  1. Add a new ValidationFunction option to the Rules struct in Authboss. This option should accept a function of type func(string) bool, allowing custom validation logic to be provided.

  2. Update the email validation logic in Authboss to use the ParseAddress function from the net/mail package by default. This can be achieved by creating a new validation function that wraps ParseAddress and returns a boolean indicating whether the email address is valid or not.

  3. Introduce a new boolean option to allow opting out of the ParseAddress validation and reverting to the previous regular expression-based validation. This option should be set to false by default, meaning that ParseAddress will be used unless explicitly disabled.

  4. Update the relevant documentation and examples to reflect the changes in email validation and the new options available.

Backward Compatibility: To maintain backward compatibility, the new ParseAddress validation should be introduced in a minor version release of Authboss. The boolean option to opt out of ParseAddress validation will allow existing users to continue using the regular expression-based validation if needed.

Please let me know if you have any questions or concerns regarding this change. I'm happy to provide further clarification or assist with the implementation.

Checklist - [X] Modify `defaults/rules.go` ✓ https://github.com/markerdmann/authboss/commit/2dd1a8b2d5c6e04e349db59ededa767d4f050158 [Edit](https://github.com/markerdmann/authboss/edit/sweep/use_gos_parseaddress_for_email_validatio_d2035/defaults/rules.go) - [X] Modify `defaults/rules.go` ✓ https://github.com/markerdmann/authboss/commit/2dd1a8b2d5c6e04e349db59ededa767d4f050158 [Edit](https://github.com/markerdmann/authboss/edit/sweep/use_gos_parseaddress_for_email_validatio_d2035/defaults/rules.go) - [X] Create `defaults/email.go` ✓ https://github.com/markerdmann/authboss/commit/2dd1a8b2d5c6e04e349db59ededa767d4f050158 [Edit](https://github.com/markerdmann/authboss/edit/sweep/use_gos_parseaddress_for_email_validatio_d2035/defaults/email.go) - [X] Modify `defaults/rules.go` ✓ https://github.com/markerdmann/authboss/commit/2dd1a8b2d5c6e04e349db59ededa767d4f050158 [Edit](https://github.com/markerdmann/authboss/edit/sweep/use_gos_parseaddress_for_email_validatio_d2035/defaults/rules.go)
sweep-ai[bot] commented 1 month ago

🚀 Here's the PR! #3

See Sweep's progress at the progress dashboard!
💎 Sweep Pro: I'm using GPT-4. You have unlimited GPT-4 tickets. (tracking ID: 150cd3e1f7)
Install Sweep Configs: Pull Request

[!TIP] I can email you next time I complete a pull request if you set up your email here!


Actions (click)


Step 1: 🔎 Searching

I found the following snippets in your repository. I will now analyze these snippets and come up with a plan.

Some code snippets I think are relevant in decreasing order of relevance (click to expand). If some file is missing from here, you can mention the path in the ticket description. https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/defaults/rules.go#L1-L201 https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/defaults/rules_test.go#L1-L170 https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/config.go#L1-L286 https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/defaults/validation.go#L1-L74 https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/defaults/validation_test.go#L1-L86

Step 2: ⌨️ Coding

type Rules struct { // FieldName is the name of the field this is intended to validate. FieldName string // MatchError describes the MustMatch regexp to a user. Required bool MatchError string MustMatch *regexp.Regexp MinLength, MaxLength int MinLetters int MinLower, MinUpper int MinNumeric int MinSymbols int AllowWhitespace bool } type Rules struct { // FieldName is the name of the field this is intended to validate. FieldName string // MatchError describes the MustMatch regexp to a user. Required bool MatchError string MustMatch *regexp.Regexp MinLength, MaxLength int MinLetters int MinLower, MinUpper int MinNumeric int MinSymbols int AllowWhitespace bool // ValidationFunction is a custom validation function that can be provided // to validate the field value. It should return true if the value is valid // and false otherwise. ValidationFunction func(string) bool // UseRegexValidation controls whether to use the regular expression-based // validation or the custom ValidationFunction. If set to true, the regular // expression-based validation will be used. If set to false, the custom // ValidationFunction will be used if provided. UseRegexValidation bool }

import "net/mail" func validateEmail(email string) bool { _, err := mail.ParseAddress(email) return err == nil }

Update the Errors method of the Rules struct to use the custom validation function or the regular expression-based validation based on the UseRegexValidation field.

// Errors returns an array of errors for each validation error that // is present in the given string. Returns nil if there are no errors. func (r Rules) Errors(toValidate string) authboss.ErrorList { errs := make(authboss.ErrorList, 0) ln := len(toValidate) if r.Required && (ln == 0 || blankRegex.MatchString(toValidate)) { return append(errs, FieldError{r.FieldName, errors.New("Cannot be blank")}) } if r.MustMatch != nil { if !r.MustMatch.MatchString(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New(r.MatchError)}) } } if (r.MinLength > 0 && ln < r.MinLength) || (r.MaxLength > 0 && ln > r.MaxLength) { errs = append(errs, FieldError{r.FieldName, errors.New(r.lengthErr())}) } upper, lower, numeric, symbols, whitespace := tallyCharacters(toValidate) if upper+lower < r.MinLetters { errs = append(errs, FieldError{r.FieldName, errors.New(r.charErr())}) } if upper < r.MinUpper { errs = append(errs, FieldError{r.FieldName, errors.New(r.upperErr())}) } if lower < r.MinLower { errs = append(errs, FieldError{r.FieldName, errors.New(r.lowerErr())}) } if numeric < r.MinNumeric { errs = append(errs, FieldError{r.FieldName, errors.New(r.numericErr())}) } if symbols < r.MinSymbols { errs = append(errs, FieldError{r.FieldName, errors.New(r.symbolErr())}) } if !r.AllowWhitespace && whitespace > 0 { errs = append(errs, FieldError{r.FieldName, errors.New("No whitespace permitted")}) } if len(errs) == 0 { return nil } return errs } // Errors returns an array of errors for each validation error that // is present in the given string. Returns nil if there are no errors. func (r Rules) Errors(toValidate string) authboss.ErrorList { errs := make(authboss.ErrorList, 0) ln := len(toValidate) if r.Required && (ln == 0 || blankRegex.MatchString(toValidate)) { return append(errs, FieldError{r.FieldName, errors.New("Cannot be blank")}) } if r.UseRegexValidation { if r.MustMatch != nil { if !r.MustMatch.MatchString(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New(r.MatchError)}) } } } else if r.ValidationFunction != nil { if !r.ValidationFunction(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New("Invalid value")}) } } if (r.MinLength > 0 && ln < r.MinLength) || (r.MaxLength > 0 && ln > r.MaxLength) { errs = append(errs, FieldError{r.FieldName, errors.New(r.lengthErr())}) } upper, lower, numeric, symbols, whitespace := tallyCharacters(toValidate) if upper+lower < r.MinLetters { errs = append(errs, FieldError{r.FieldName, errors.New(r.charErr())}) } if upper < r.MinUpper { errs = append(errs, FieldError{r.FieldName, errors.New(r.upperErr())}) } if lower < r.MinLower { errs = append(errs, FieldError{r.FieldName, errors.New(r.lowerErr())}) } if numeric < r.MinNumeric { errs = append(errs, FieldError{r.FieldName, errors.New(r.numericErr())}) } if symbols < r.MinSymbols { errs = append(errs, FieldError{r.FieldName, errors.New(r.symbolErr())}) } if !r.AllowWhitespace && whitespace > 0 { errs = append(errs, FieldError{r.FieldName, errors.New("No whitespace permitted")}) } if len(errs) == 0 { return nil } return errs }

// Rules defines a ruleset by which a string can be validated. // The errors it produces are english only, with some basic pluralization. type Rules struct { // FieldName is the name of the field this is intended to validate. FieldName string // MatchError describes the MustMatch regexp to a user. Required bool MatchError string MustMatch *regexp.Regexp MinLength, MaxLength int MinLetters int MinLower, MinUpper int MinNumeric int MinSymbols int AllowWhitespace bool } // Rules defines a ruleset by which a string can be validated. // The errors it produces are english only, with some basic pluralization. type Rules struct { // FieldName is the name of the field this is intended to validate. FieldName string // MatchError describes the MustMatch regexp to a user. Required bool MatchError string MustMatch *regexp.Regexp MinLength, MaxLength int MinLetters int MinLower, MinUpper int MinNumeric int MinSymbols int AllowWhitespace bool // ValidationFunction is a custom validation function that can be provided // to validate the field value. It should return true if the value is valid // and false otherwise. ValidationFunction func(string) bool // UseRegexValidation controls whether to use the regular expression-based // validation or the custom ValidationFunction. If set to true, the regular // expression-based validation will be used. If set to false, the custom // ValidationFunction will be used if provided. UseRegexValidation bool }


Step 3: 🔁 Code Review

I have finished reviewing the code for completeness. I did not find errors for sweep/use_gos_parseaddress_for_email_validatio.


🎉 Latest improvements to Sweep:
  • New dashboard launched for real-time tracking of Sweep issues, covering all stages from search to coding.
  • Integration of OpenAI's latest Assistant API for more efficient and reliable code planning and editing, improving speed by 3x.
  • Use the GitHub issues extension for creating Sweep issues directly from your editor.

💡 To recreate the pull request edit the issue title or description. Something wrong? Let us know.

This is an automated message generated by Sweep AI.

sweep-ai[bot] commented 1 month ago

🚀 Here's the PR! #6

See Sweep's progress at the progress dashboard!
💎 Sweep Pro: I'm using GPT-4. You have unlimited GPT-4 tickets. (tracking ID: f262599ede)
Install Sweep Configs: Pull Request

[!TIP] I can email you next time I complete a pull request if you set up your email here!


Actions (click)


Step 1: 🔎 Searching

I found the following snippets in your repository. I will now analyze these snippets and come up with a plan.

Some code snippets I think are relevant in decreasing order of relevance (click to expand). If some file is missing from here, you can mention the path in the ticket description. https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/defaults/rules.go#L1-L201 https://github.com/markerdmann/authboss/blob/0ab40e48437ad4b4284818880abe701860e98d60/validation.go#L1-L67

Step 2: ⌨️ Coding

type Rules struct { // FieldName is the name of the field this is intended to validate. FieldName string // MatchError describes the MustMatch regexp to a user. Required bool MatchError string MustMatch *regexp.Regexp MinLength, MaxLength int MinLetters int MinLower, MinUpper int MinNumeric int MinSymbols int AllowWhitespace bool } type Rules struct { // FieldName is the name of the field this is intended to validate. FieldName string // MatchError describes the MustMatch regexp to a user. Required bool MatchError string MustMatch *regexp.Regexp MinLength, MaxLength int MinLetters int MinLower, MinUpper int MinNumeric int MinSymbols int AllowWhitespace bool // ValidationFunction is a custom validation function that can be provided // to validate the field value. It should return true if the value is valid. ValidationFunction func(string) bool // UseRegexValidation determines whether to use the regular expression-based // validation or the ParseAddress validation for email addresses. // If set to true, the regular expression-based validation will be used. // If set to false (default), the ParseAddress validation will be used. UseRegexValidation bool }

func (r Rules) Errors(toValidate string) authboss.ErrorList { errs := make(authboss.ErrorList, 0) ln := len(toValidate) if r.Required && (ln == 0 || blankRegex.MatchString(toValidate)) { return append(errs, FieldError{r.FieldName, errors.New("Cannot be blank")}) } if r.MustMatch != nil { if !r.MustMatch.MatchString(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New(r.MatchError)}) } } if (r.MinLength > 0 && ln < r.MinLength) || (r.MaxLength > 0 && ln > r.MaxLength) { errs = append(errs, FieldError{r.FieldName, errors.New(r.lengthErr())}) } upper, lower, numeric, symbols, whitespace := tallyCharacters(toValidate) if upper+lower < r.MinLetters { errs = append(errs, FieldError{r.FieldName, errors.New(r.charErr())}) } if upper < r.MinUpper { errs = append(errs, FieldError{r.FieldName, errors.New(r.upperErr())}) } if lower < r.MinLower { errs = append(errs, FieldError{r.FieldName, errors.New(r.lowerErr())}) } if numeric < r.MinNumeric { errs = append(errs, FieldError{r.FieldName, errors.New(r.numericErr())}) } if symbols < r.MinSymbols { errs = append(errs, FieldError{r.FieldName, errors.New(r.symbolErr())}) } if !r.AllowWhitespace && whitespace > 0 { errs = append(errs, FieldError{r.FieldName, errors.New("No whitespace permitted")}) } if len(errs) == 0 { return nil } return errs } import "net/mail" func (r Rules) Errors(toValidate string) authboss.ErrorList { errs := make(authboss.ErrorList, 0) ln := len(toValidate) if r.Required && (ln == 0 || blankRegex.MatchString(toValidate)) { return append(errs, FieldError{r.FieldName, errors.New("Cannot be blank")}) } if r.ValidationFunction != nil { if !r.ValidationFunction(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New("Invalid value")}) } } else if r.FieldName == "email" { if r.UseRegexValidation { if r.MustMatch != nil { if !r.MustMatch.MatchString(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New(r.MatchError)}) } } } else { if _, err := mail.ParseAddress(toValidate); err != nil { errs = append(errs, FieldError{r.FieldName, errors.New("Invalid email address")}) } } } else { if r.MustMatch != nil { if !r.MustMatch.MatchString(toValidate) { errs = append(errs, FieldError{r.FieldName, errors.New(r.MatchError)}) } } } if (r.MinLength > 0 && ln < r.MinLength) || (r.MaxLength > 0 && ln > r.MaxLength) { errs = append(errs, FieldError{r.FieldName, errors.New(r.lengthErr())}) } upper, lower, numeric, symbols, whitespace := tallyCharacters(toValidate) if upper+lower < r.MinLetters { errs = append(errs, FieldError{r.FieldName, errors.New(r.charErr())}) } if upper < r.MinUpper { errs = append(errs, FieldError{r.FieldName, errors.New(r.upperErr())}) } if lower < r.MinLower { errs = append(errs, FieldError{r.FieldName, errors.New(r.lowerErr())}) } if numeric < r.MinNumeric { errs = append(errs, FieldError{r.FieldName, errors.New(r.numericErr())}) } if symbols < r.MinSymbols { errs = append(errs, FieldError{r.FieldName, errors.New(r.symbolErr())}) } if !r.AllowWhitespace && whitespace > 0 { errs = append(errs, FieldError{r.FieldName, errors.New("No whitespace permitted")}) } if len(errs) == 0 { return nil } return errs }

package defaults import "net/mail" // validateEmail checks if the given email address is valid using the ParseAddress // function from the net/mail package. func validateEmail(email string) bool { _, err := mail.ParseAddress(email) return err == nil }

import ( "fmt" "regexp" "unicode" "github.com/friendsofgo/errors" "github.com/volatiletech/authboss/v3" ) import ( "fmt" "regexp" "unicode" "github.com/friendsofgo/errors" "github.com/volatiletech/authboss/v3" "net/mail" )


Step 3: 🔁 Code Review

I have finished reviewing the code for completeness. I did not find errors for sweep/use_gos_parseaddress_for_email_validatio_d2035.


🎉 Latest improvements to Sweep:
  • New dashboard launched for real-time tracking of Sweep issues, covering all stages from search to coding.
  • Integration of OpenAI's latest Assistant API for more efficient and reliable code planning and editing, improving speed by 3x.
  • Use the GitHub issues extension for creating Sweep issues directly from your editor.

💡 To recreate the pull request edit the issue title or description. Something wrong? Let us know.

This is an automated message generated by Sweep AI.