Skip to content

Commit 95dcb7b

Browse files
Merge pull request #260 from supertokens/input-validation-fix
fix: Input validation fix for emailpassword APIs
2 parents a2cce63 + e2b6e3c commit 95dcb7b

File tree

8 files changed

+179
-8
lines changed

8 files changed

+179
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [unreleased]
99

10+
## [0.10.6]
11+
12+
- Fixes panic issue in input validation for emailpassword APIs - https://github.com/supertokens/supertokens-golang/issues/254
13+
1014
## [0.10.5] - 2023-03-31
1115

1216
- Adds search APIs to the dashboard recipe

recipe/emailpassword/api/generatePasswordResetToken.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func GeneratePasswordResetToken(apiImplementation epmodels.APIInterface, options
3939
return err
4040
}
4141

42-
formFields, err := validateFormFieldsOrThrowError(options.Config.ResetPasswordUsingTokenFeature.FormFieldsForGenerateTokenForm, formFieldsRaw["formFields"].([]interface{}))
42+
formFields, err := validateFormFieldsOrThrowError(options.Config.ResetPasswordUsingTokenFeature.FormFieldsForGenerateTokenForm, formFieldsRaw["formFields"])
4343
if err != nil {
4444
return err
4545
}

recipe/emailpassword/api/passwordReset.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func PasswordReset(apiImplementation epmodels.APIInterface, options epmodels.API
3939
return err
4040
}
4141

42-
formFields, err := validateFormFieldsOrThrowError(options.Config.ResetPasswordUsingTokenFeature.FormFieldsForPasswordResetForm, formFieldsRaw["formFields"].([]interface{}))
42+
formFields, err := validateFormFieldsOrThrowError(options.Config.ResetPasswordUsingTokenFeature.FormFieldsForPasswordResetForm, formFieldsRaw["formFields"])
4343
if err != nil {
4444
return err
4545
}

recipe/emailpassword/api/signin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func SignInAPI(apiImplementation epmodels.APIInterface, options epmodels.APIOpti
3838
return err
3939
}
4040

41-
formFields, err := validateFormFieldsOrThrowError(options.Config.SignInFeature.FormFields, formFieldsRaw["formFields"].([]interface{}))
41+
formFields, err := validateFormFieldsOrThrowError(options.Config.SignInFeature.FormFields, formFieldsRaw["formFields"])
4242
if err != nil {
4343
return err
4444
}

recipe/emailpassword/api/signup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func SignUpAPI(apiImplementation epmodels.APIInterface, options epmodels.APIOpti
3939
return err
4040
}
4141

42-
formFields, err := validateFormFieldsOrThrowError(options.Config.SignUpFeature.FormFields, formFieldsRaw["formFields"].([]interface{}))
42+
formFields, err := validateFormFieldsOrThrowError(options.Config.SignUpFeature.FormFields, formFieldsRaw["formFields"])
4343
if err != nil {
4444
return err
4545
}

recipe/emailpassword/api/utils.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,30 @@ import (
2424
"github.com/supertokens/supertokens-golang/recipe/emailpassword/errors"
2525
)
2626

27-
func validateFormFieldsOrThrowError(configFormFields []epmodels.NormalisedFormField, formFieldsRaw []interface{}) ([]epmodels.TypeFormField, error) {
27+
func validateFormFieldsOrThrowError(configFormFields []epmodels.NormalisedFormField, formFieldsRaw interface{}) ([]epmodels.TypeFormField, error) {
2828
if formFieldsRaw == nil {
2929
return nil, defaultErrors.New("Missing input param: formFields")
3030
}
3131

32-
if len(formFieldsRaw) == 0 {
32+
if _, ok := formFieldsRaw.([]interface{}); !ok {
3333
return nil, defaultErrors.New("formFields must be an array")
3434
}
3535

3636
var formFields []epmodels.TypeFormField
37-
for _, rawFormField := range formFieldsRaw {
37+
for _, rawFormField := range formFieldsRaw.([]interface{}) {
38+
39+
if _, ok := rawFormField.(map[string]interface{}); !ok {
40+
return nil, defaultErrors.New("formFields must be an array of objects containing id and value of type string")
41+
}
42+
43+
if _, ok := rawFormField.(map[string]interface{})["id"].(string); !ok {
44+
return nil, defaultErrors.New("formFields must be an array of objects containing id and value of type string")
45+
}
46+
47+
if _, ok := rawFormField.(map[string]interface{})["value"].(string); !ok {
48+
return nil, defaultErrors.New("formFields must be an array of objects containing id and value of type string")
49+
}
50+
3851
jsonformField, err := json.Marshal(rawFormField)
3952
if err != nil {
4053
return nil, err

recipe/emailpassword/formFieldValidator_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@
1717
package emailpassword
1818

1919
import (
20+
"bytes"
21+
"encoding/json"
22+
"io/ioutil"
23+
"net/http"
24+
"net/http/httptest"
25+
"strings"
2026
"testing"
2127

2228
"github.com/stretchr/testify/assert"
29+
"github.com/supertokens/supertokens-golang/supertokens"
30+
"github.com/supertokens/supertokens-golang/test/unittesting"
2331
)
2432

2533
func TestDefaultEmailValidator(t *testing.T) {
@@ -56,3 +64,149 @@ func TestDefaultPasswordValidator(t *testing.T) {
5664

5765
assert.Equal(t, "Password must contain at least one alphabet", *defaultPasswordValidator("234235234523"))
5866
}
67+
68+
func TestInvalidAPIInputForFormFields(t *testing.T) {
69+
configValue := supertokens.TypeInput{
70+
Supertokens: &supertokens.ConnectionInfo{
71+
ConnectionURI: "http://localhost:8080",
72+
},
73+
AppInfo: supertokens.AppInfo{
74+
APIDomain: "api.supertokens.io",
75+
AppName: "SuperTokens",
76+
WebsiteDomain: "supertokens.io",
77+
},
78+
RecipeList: []supertokens.Recipe{
79+
Init(nil),
80+
},
81+
}
82+
83+
BeforeEach()
84+
unittesting.StartUpST("localhost", "8080")
85+
defer AfterEach()
86+
err := supertokens.Init(configValue)
87+
if err != nil {
88+
t.Error(err.Error())
89+
}
90+
mux := http.NewServeMux()
91+
testServer := httptest.NewServer(supertokens.Middleware(mux))
92+
defer testServer.Close()
93+
94+
objToJson := func(obj interface{}) []byte {
95+
jsonBytes, err := json.Marshal(obj)
96+
assert.NoError(t, err)
97+
return jsonBytes
98+
}
99+
100+
testCases := []struct {
101+
input interface{}
102+
expected string
103+
}{
104+
{
105+
input: map[string]interface{}{},
106+
expected: "Missing input param: formFields",
107+
},
108+
{
109+
input: map[string]interface{}{
110+
"formFields": "abcd",
111+
},
112+
expected: "formFields must be an array",
113+
},
114+
{
115+
input: map[string]interface{}{
116+
"formFields": []string{"hello"},
117+
},
118+
expected: "formFields must be an array of objects containing id and value of type string",
119+
},
120+
{
121+
input: map[string]interface{}{
122+
"formFields": []map[string]interface{}{
123+
{
124+
"hello": "world",
125+
},
126+
},
127+
},
128+
expected: "formFields must be an array of objects containing id and value of type string",
129+
},
130+
{
131+
input: map[string]interface{}{
132+
"formFields": []map[string]interface{}{
133+
{
134+
"id": 1,
135+
},
136+
},
137+
},
138+
expected: "formFields must be an array of objects containing id and value of type string",
139+
},
140+
{
141+
input: map[string]interface{}{
142+
"formFields": []map[string]interface{}{
143+
{
144+
"id": 1,
145+
"value": "world",
146+
},
147+
},
148+
},
149+
expected: "formFields must be an array of objects containing id and value of type string",
150+
},
151+
{
152+
input: map[string]interface{}{
153+
"formFields": []map[string]interface{}{
154+
{
155+
"id": "hello",
156+
"value": 1,
157+
},
158+
},
159+
},
160+
expected: "formFields must be an array of objects containing id and value of type string",
161+
},
162+
{
163+
input: map[string]interface{}{
164+
"formFields": []map[string]interface{}{
165+
{
166+
"value": 1,
167+
},
168+
},
169+
},
170+
expected: "formFields must be an array of objects containing id and value of type string",
171+
},
172+
{
173+
input: map[string]interface{}{
174+
"formFields": []map[string]interface{}{
175+
{
176+
"id": "hello",
177+
},
178+
},
179+
},
180+
expected: "formFields must be an array of objects containing id and value of type string",
181+
},
182+
{
183+
input: map[string]interface{}{
184+
"formFields": []map[string]interface{}{
185+
{
186+
"value": "world",
187+
},
188+
},
189+
},
190+
expected: "formFields must be an array of objects containing id and value of type string",
191+
},
192+
}
193+
194+
APIs := []string{
195+
"/auth/signup",
196+
"/auth/signin",
197+
"/auth/user/password/reset/token",
198+
"/auth/user/password/reset",
199+
}
200+
201+
for _, testCase := range testCases {
202+
for _, api := range APIs {
203+
resp, err := http.Post(testServer.URL+api, "application/json", bytes.NewBuffer(objToJson(testCase.input)))
204+
assert.NoError(t, err)
205+
assert.Equal(t, 500, resp.StatusCode)
206+
data, err := ioutil.ReadAll(resp.Body)
207+
assert.NoError(t, err)
208+
errorMessage := strings.Trim(string(data), "\n \t")
209+
assert.Equal(t, testCase.expected, errorMessage)
210+
}
211+
}
212+
}

supertokens/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const (
2121
)
2222

2323
// VERSION current version of the lib
24-
const VERSION = "0.10.5"
24+
const VERSION = "0.10.6"
2525

2626
var (
2727
cdiSupported = []string{"2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14", "2.15", "2.16", "2.17", "2.18", "2.19", "2.20"}

0 commit comments

Comments
 (0)