Skip to content

Commit 1f08095

Browse files
Merge pull request #389 from supertokens/appinfo-refactor
app info refactor
2 parents ac39010 + b6d37a3 commit 1f08095

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+902
-222
lines changed

CHANGELOG.md

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

88
## [unreleased]
99

10+
11+
## [0.17.1] - 2023-11-24
12+
13+
### Added
14+
15+
- Adds support for configuring multiple frontend domains to be used with the same backend
16+
- Added new `Origin` and `GetOrigin` properties to `AppInfo`, this can be configured to allow you to conditionally return the value of the frontend domain. This property will replace `WebsiteDomain` in a future release of `supertokens-golang`
17+
- `WebsiteDomain` inside `AppInfo` is now optional. Using `Origin` or `GetOrigin` is recommended over using `WebsiteDomain`. This is not a breaking change and using `WebsiteDomain` will continue to work.
18+
1019
## [0.17.0] - 2023-11-14
1120

1221
### Breaking change

recipe/dashboard/api/analyticsPOST.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,13 @@ func AnalyticsPost(apiInterface dashboardmodels.APIInterface, tenantId string, o
6161
}
6262
}
6363

64+
websiteDomain, err := supertokensInstance.AppInfo.GetOrigin(nil, &map[string]interface{}{})
65+
if err != nil {
66+
return analyticsPostResponse{}, err
67+
}
68+
6469
data := map[string]interface{}{
65-
"websiteDomain": supertokensInstance.AppInfo.WebsiteDomain.GetAsStringDangerous(),
70+
"websiteDomain": websiteDomain.GetAsStringDangerous(),
6671
"apiDomain": supertokensInstance.AppInfo.APIDomain.GetAsStringDangerous(),
6772
"appName": supertokensInstance.AppInfo.AppName,
6873
"sdk": "golang",

recipe/dashboard/recipe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ func (r *Recipe) getAllCORSHeaders() []string {
350350
return []string{}
351351
}
352352

353-
func (r *Recipe) handleError(err error, req *http.Request, res http.ResponseWriter) (bool, error) {
353+
func (r *Recipe) handleError(err error, req *http.Request, res http.ResponseWriter, userContext supertokens.UserContext) (bool, error) {
354354
return false, nil
355355
}
356356

recipe/emailpassword/api/implementation.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ func MakeAPIImplementation() epmodels.APIInterface {
6666
}, nil
6767
}
6868

69-
passwordResetLink := GetPasswordResetLink(
69+
passwordResetLink, err := GetPasswordResetLink(
7070
options.AppInfo,
7171
options.RecipeID,
7272
response.OK.Token,
7373
tenantId,
74+
options.Req,
75+
userContext,
7476
)
7577

7678
if err != nil {

recipe/emailpassword/api/utils.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package api
1818
import (
1919
"encoding/json"
2020
"fmt"
21+
"net/http"
2122
"strings"
2223

2324
"github.com/supertokens/supertokens-golang/recipe/emailpassword/epmodels"
@@ -125,13 +126,17 @@ func validateFormOrThrowError(configFormFields []epmodels.NormalisedFormField, i
125126
return nil
126127
}
127128

128-
func GetPasswordResetLink(appInfo supertokens.NormalisedAppinfo, recipeID string, token string, tenantId string) string {
129+
func GetPasswordResetLink(appInfo supertokens.NormalisedAppinfo, recipeID string, token string, tenantId string, request *http.Request, userContext supertokens.UserContext) (string, error) {
130+
websiteDomain, err := appInfo.GetOrigin(request, userContext)
131+
if err != nil {
132+
return "", err
133+
}
129134
return fmt.Sprintf(
130135
"%s%s/reset-password?token=%s&rid=%s&tenantId=%s",
131-
appInfo.WebsiteDomain.GetAsStringDangerous(),
136+
websiteDomain.GetAsStringDangerous(),
132137
appInfo.WebsiteBasePath.GetAsStringDangerous(),
133138
token,
134139
recipeID,
135140
tenantId,
136-
)
141+
), nil
137142
}

recipe/emailpassword/main.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,22 @@ func CreateResetPasswordLink(tenantId string, userID string, userContext ...supe
138138
return epmodels.CreateResetPasswordLinkResponse{}, err
139139
}
140140

141+
link, err := api.GetPasswordResetLink(
142+
instance.RecipeModule.GetAppInfo(),
143+
instance.RecipeModule.GetRecipeID(),
144+
tokenResponse.OK.Token,
145+
tenantId,
146+
supertokens.GetRequestFromUserContext(userContext[0]),
147+
userContext[0],
148+
)
149+
150+
if err != nil {
151+
return epmodels.CreateResetPasswordLinkResponse{}, err
152+
}
153+
141154
return epmodels.CreateResetPasswordLinkResponse{
142155
OK: &struct{ Link string }{
143-
Link: api.GetPasswordResetLink(
144-
instance.RecipeModule.GetAppInfo(),
145-
instance.RecipeModule.GetRecipeID(),
146-
tokenResponse.OK.Token,
147-
tenantId,
148-
),
156+
Link: link,
149157
},
150158
}, nil
151159
}

recipe/emailpassword/passwordReset_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,106 @@ func TestValidTokenInputAndPasswordHasChanged(t *testing.T) {
455455
assert.Equal(t, userInfo["id"], result3["user"].(map[string]interface{})["id"].(string))
456456
assert.Equal(t, userInfo["email"], result3["user"].(map[string]interface{})["email"].(string))
457457
}
458+
459+
func TestPasswordResetLinkUsesOriginFunctionIfProvided(t *testing.T) {
460+
resetURL := ""
461+
tokenInfo := ""
462+
ridInfo := ""
463+
sendEmailFunc := func(input emaildelivery.EmailType, userContext supertokens.UserContext) error {
464+
u, err := url.Parse(input.PasswordReset.PasswordResetLink)
465+
if err != nil {
466+
return err
467+
}
468+
resetURL = u.Scheme + "://" + u.Host + u.Path
469+
tokenInfo = u.Query().Get("token")
470+
ridInfo = u.Query().Get("rid")
471+
return nil
472+
}
473+
configValue := supertokens.TypeInput{
474+
Supertokens: &supertokens.ConnectionInfo{
475+
ConnectionURI: "http://localhost:8080",
476+
},
477+
AppInfo: supertokens.AppInfo{
478+
APIDomain: "api.supertokens.io",
479+
AppName: "SuperTokens",
480+
GetOrigin: func(request *http.Request, userContext supertokens.UserContext) (string, error) {
481+
// read request body
482+
decoder := json.NewDecoder(request.Body)
483+
var requestBody map[string]interface{}
484+
err := decoder.Decode(&requestBody)
485+
if err != nil {
486+
return "https://supertokens.com", nil
487+
}
488+
if requestBody["origin"] == nil {
489+
return "https://supertokens.com", nil
490+
}
491+
return requestBody["origin"].(string), nil
492+
},
493+
},
494+
RecipeList: []supertokens.Recipe{
495+
Init(&epmodels.TypeInput{
496+
EmailDelivery: &emaildelivery.TypeInput{
497+
Service: &emaildelivery.EmailDeliveryInterface{
498+
SendEmail: &sendEmailFunc,
499+
},
500+
},
501+
}),
502+
session.Init(nil),
503+
},
504+
}
505+
506+
BeforeEach()
507+
unittesting.StartUpST("localhost", "8080")
508+
defer AfterEach()
509+
err := supertokens.Init(configValue)
510+
if err != nil {
511+
t.Error(err.Error())
512+
}
513+
mux := http.NewServeMux()
514+
testServer := httptest.NewServer(supertokens.Middleware(mux))
515+
defer testServer.Close()
516+
517+
res, err := unittesting.SignupRequest("random@gmail.com", "validpass123", testServer.URL)
518+
if err != nil {
519+
t.Error(err.Error())
520+
}
521+
assert.NoError(t, err)
522+
dataInBytes, err := io.ReadAll(res.Body)
523+
if err != nil {
524+
t.Error(err.Error())
525+
}
526+
res.Body.Close()
527+
var result map[string]interface{}
528+
err = json.Unmarshal(dataInBytes, &result)
529+
if err != nil {
530+
t.Error(err.Error())
531+
}
532+
assert.Equal(t, 200, res.StatusCode)
533+
assert.Equal(t, "OK", result["status"])
534+
535+
formFields := map[string]interface{}{
536+
"origin": "localhost:2000",
537+
"formFields": []map[string]interface{}{{
538+
"id": "email",
539+
"value": "random@gmail.com",
540+
}},
541+
}
542+
543+
postBody, err := json.Marshal(formFields)
544+
if err != nil {
545+
t.Error(err.Error())
546+
}
547+
548+
resp, err := http.Post(testServer.URL+"/auth/user/password/reset/token", "application/json", bytes.NewBuffer(postBody))
549+
550+
if err != nil {
551+
t.Error(err.Error())
552+
}
553+
554+
assert.NoError(t, err)
555+
556+
assert.Equal(t, 200, resp.StatusCode)
557+
assert.Equal(t, "http://localhost:2000/auth/reset-password", resetURL)
558+
assert.NotEmpty(t, tokenInfo)
559+
assert.True(t, strings.HasPrefix(ridInfo, "emailpassword"))
560+
}

recipe/emailpassword/recipe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func (r *Recipe) getAllCORSHeaders() []string {
181181
return []string{}
182182
}
183183

184-
func (r *Recipe) handleError(err error, req *http.Request, res http.ResponseWriter) (bool, error) {
184+
func (r *Recipe) handleError(err error, req *http.Request, res http.ResponseWriter, userContext supertokens.UserContext) (bool, error) {
185185
if defaultErrors.As(err, &errors.FieldError{}) {
186186
errs := err.(errors.FieldError)
187187
return true, supertokens.Send200Response(res, map[string]interface{}{

recipe/emailverification/api/implementation.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,20 @@ func MakeAPIImplementation() evmodels.APIInterface {
122122
ID: userID,
123123
Email: email.OK.Email,
124124
}
125-
emailVerificationURL := GetEmailVerifyLink(
125+
126+
emailVerificationURL, err := GetEmailVerifyLink(
126127
options.AppInfo,
127128
response.OK.Token,
128129
options.RecipeID,
129130
sessionContainer.GetTenantIdWithContext(userContext),
131+
options.Req,
132+
userContext,
130133
)
131134

135+
if err != nil {
136+
return evmodels.GenerateEmailVerifyTokenPOSTResponse{}, err
137+
}
138+
132139
supertokens.LogDebugMessage(fmt.Sprintf("Sending email verification email to %s", email.OK.Email))
133140
err = (*options.EmailDelivery.IngredientInterfaceImpl.SendEmail)(emaildelivery.EmailType{
134141
EmailVerification: &emaildelivery.EmailVerificationType{

recipe/emailverification/api/utils.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@ package api
22

33
import (
44
"fmt"
5+
"net/http"
56

67
"github.com/supertokens/supertokens-golang/supertokens"
78
)
89

9-
func GetEmailVerifyLink(appInfo supertokens.NormalisedAppinfo, token string, recipeID string, tenantId string) string {
10+
func GetEmailVerifyLink(appInfo supertokens.NormalisedAppinfo, token string, recipeID string, tenantId string, request *http.Request, userContext supertokens.UserContext) (string, error) {
11+
websiteDomain, err := appInfo.GetOrigin(request, userContext)
12+
if err != nil {
13+
return "", err
14+
}
1015
return fmt.Sprintf(
1116
"%s%s/verify-email?token=%s&rid=%s&tenantId=%s",
12-
appInfo.WebsiteDomain.GetAsStringDangerous(),
17+
websiteDomain.GetAsStringDangerous(),
1318
appInfo.WebsiteBasePath.GetAsStringDangerous(),
1419
token,
1520
recipeID,
1621
tenantId,
17-
)
22+
), nil
1823
}

0 commit comments

Comments
 (0)