Skip to content

Commit

Permalink
Add support for any type in value field instead of only string
Browse files Browse the repository at this point in the history
  • Loading branch information
deepjyoti30-st committed Sep 23, 2024
1 parent b314858 commit 893054a
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 18 deletions.
36 changes: 30 additions & 6 deletions recipe/emailpassword/api/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ func MakeAPIImplementation() epmodels.APIInterface {
var email string
for _, formField := range formFields {
if formField.ID == "email" {
email = formField.Value
valueAsString, parseErr := withValueAsString(formField.Value, "Email value needs to be a string")
if parseErr != nil {
return epmodels.GeneratePasswordResetTokenPOSTResponse{}, parseErr
}
email = valueAsString
}
}

Expand Down Expand Up @@ -102,7 +106,11 @@ func MakeAPIImplementation() epmodels.APIInterface {
var newPassword string
for _, formField := range formFields {
if formField.ID == "password" {
newPassword = formField.Value
valueAsString, parseErr := withValueAsString(formField.Value, "Password value needs to be a string")
if parseErr != nil {
return epmodels.ResetPasswordPOSTResponse{}, parseErr
}
newPassword = valueAsString
}
}

Expand All @@ -127,9 +135,17 @@ func MakeAPIImplementation() epmodels.APIInterface {
var password string
for _, formField := range formFields {
if formField.ID == "email" {
email = formField.Value
valueAsString, parseErr := withValueAsString(formField.Value, "Email value needs to be a string")
if parseErr != nil {
return epmodels.SignInPOSTResponse{}, parseErr
}
email = valueAsString
} else if formField.ID == "password" {
password = formField.Value
valueAsString, parseErr := withValueAsString(formField.Value, "Password value needs to be a string")
if parseErr != nil {
return epmodels.SignInPOSTResponse{}, parseErr
}
password = valueAsString
}
}

Expand Down Expand Up @@ -165,9 +181,17 @@ func MakeAPIImplementation() epmodels.APIInterface {
var password string
for _, formField := range formFields {
if formField.ID == "email" {
email = formField.Value
valueAsString, parseErr := withValueAsString(formField.Value, "Email value needs to be a string")
if parseErr != nil {
return epmodels.SignUpPOSTResponse{}, parseErr
}
email = valueAsString
} else if formField.ID == "password" {
password = formField.Value
valueAsString, parseErr := withValueAsString(formField.Value, "Password value needs to be a string")
if parseErr != nil {
return epmodels.SignUpPOSTResponse{}, parseErr
}
password = valueAsString
}
}

Expand Down
37 changes: 27 additions & 10 deletions recipe/emailpassword/api/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ import (
"github.com/supertokens/supertokens-golang/supertokens"
)

func withValueAsString(emailValue interface{}, errorStr string) (string, error) {
// Throw error if the value is not a string
valueAsString, asStrOk := emailValue.(string)
if !asStrOk {
return "", fmt.Errorf(errorStr)
}

return valueAsString, nil
}

func validateFormFieldsOrThrowError(configFormFields []epmodels.NormalisedFormField, formFieldsRaw interface{}, tenantId string) ([]epmodels.TypeFormField, error) {
if formFieldsRaw == nil {
return nil, supertokens.BadInputError{
Expand Down Expand Up @@ -56,14 +66,6 @@ func validateFormFieldsOrThrowError(configFormFields []epmodels.NormalisedFormFi
}
}

if rawFormField.(map[string]interface{})["value"] != nil {
if _, ok := rawFormField.(map[string]interface{})["value"].(string); !ok {
return nil, supertokens.BadInputError{
Msg: "formFields must be an array of objects containing id and value of type string",
}
}
}

jsonformField, err := json.Marshal(rawFormField)
if err != nil {
return nil, err
Expand All @@ -75,9 +77,15 @@ func validateFormFieldsOrThrowError(configFormFields []epmodels.NormalisedFormFi
}

if formField.ID == "email" {
valueAsString, parseErr := withValueAsString(formField.Value, "Email value needs to be a string")
if parseErr != nil {
return nil, supertokens.BadInputError{
Msg: "Email value must be a string",
}
}
formFields = append(formFields, epmodels.TypeFormField{
ID: formField.ID,
Value: strings.TrimSpace(formField.Value),
Value: strings.TrimSpace(valueAsString),
})
} else {
formFields = append(formFields, epmodels.TypeFormField{
Expand Down Expand Up @@ -106,7 +114,16 @@ func validateFormOrThrowError(configFormFields []epmodels.NormalisedFormField, i
}
}

isValidInput := input.Value != ""
isValidInput := true
if input.Value == nil {
isValidInput = false
} else {
// If it is a string, it shouldn't be empty.
valueAsStr, err := withValueAsString(input.Value, "")
if err == nil && strings.TrimSpace(valueAsStr) == "" {
isValidInput = false
}
}

// If the field is not option and input is invalid, we should
// throw a validation error.
Expand Down
88 changes: 88 additions & 0 deletions recipe/emailpassword/authFlow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,94 @@ import (
"github.com/supertokens/supertokens-golang/test/unittesting"
)

func TestGoodCaseInputWithOptionalAndBoolean(t *testing.T) {
optionalVal := true
configValue := supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
ConnectionURI: "http://localhost:8080",
},
AppInfo: supertokens.AppInfo{
APIDomain: "api.supertokens.io",
AppName: "SuperTokens",
WebsiteDomain: "supertokens.io",
},
RecipeList: []supertokens.Recipe{
Init(&epmodels.TypeInput{
SignUpFeature: &epmodels.TypeInputSignUp{
FormFields: []epmodels.TypeInputFormField{
{
ID: "autoVerify",
Optional: &optionalVal,
},
},
},
}),
session.Init(&sessmodels.TypeInput{
GetTokenTransferMethod: func(req *http.Request, forCreateNewSession bool, userContext supertokens.UserContext) sessmodels.TokenTransferMethod {
return sessmodels.CookieTransferMethod
},
}),
},
}

BeforeEach()
unittesting.StartUpST("localhost", "8080")
defer AfterEach()
err := supertokens.Init(configValue)
if err != nil {
t.Error(err.Error())
}
mux := http.NewServeMux()
testServer := httptest.NewServer(supertokens.Middleware(mux))
defer testServer.Close()

formFields := map[string][]map[string]interface{}{
"formFields": {
{
"id": "password",
"value": "validpass123",
},
{
"id": "email",
"value": "[email protected]",
},
{
"id": "autoVerify",
"value": false,
},
},
}

postBody, err := json.Marshal(formFields)
if err != nil {
t.Error(err.Error())
}

resp, err := http.Post(testServer.URL+"/auth/signup", "application/json", bytes.NewBuffer(postBody))

if err != nil {
t.Error(err.Error())
}

assert.Equal(t, 200, resp.StatusCode)

dataInBytes, err := io.ReadAll(resp.Body)
if err != nil {
t.Error(err.Error())
}
resp.Body.Close()

var data map[string]interface{}
err = json.Unmarshal(dataInBytes, &data)
if err != nil {
t.Error(err.Error())
}

assert.Equal(t, "OK", data["status"])
assert.NotNil(t, data["user"].(map[string]interface{})["id"])
assert.Equal(t, "[email protected]", data["user"].(map[string]interface{})["email"])
}

func TestRightRidButRecipeMissingReturns404(t *testing.T) {
configValue := supertokens.TypeInput{
Supertokens: &supertokens.ConnectionInfo{
Expand Down
4 changes: 2 additions & 2 deletions recipe/emailpassword/epmodels/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ type TypeInput struct {
}

type TypeFormField struct {
ID string `json:"id"`
Value string `json:"value"`
ID string `json:"id"`
Value interface{} `json:"value"`
}

type CreateResetPasswordLinkResponse struct {
Expand Down
10 changes: 10 additions & 0 deletions recipe/emailpassword/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ func defaultPasswordValidator(value interface{}, tenantId string) *string {
// length >= 8 && < 100
// must have a number and a character

if (value) == nil {
msg := "Field is not optional"
return &msg
}

if reflect.TypeOf(value).Kind() != reflect.String {
msg := "Development bug: Please make sure the password field yields a string"
return &msg
Expand All @@ -243,6 +248,11 @@ func defaultPasswordValidator(value interface{}, tenantId string) *string {
}

func defaultEmailValidator(value interface{}, tenantId string) *string {
if (value) == nil {
msg := "Field is not optional"
return &msg
}

if reflect.TypeOf(value).Kind() != reflect.String {
msg := "Development bug: Please make sure the email field yields a string"
return &msg
Expand Down

0 comments on commit 893054a

Please sign in to comment.