NOISSUE - Obtain email host from env (#3098)

Signed-off-by: WashingtonKK <washingtonkigan@gmail.com>
This commit is contained in:
Washington Kigani Kamadi
2025-09-01 16:21:01 +03:00
committed by GitHub
parent 6a27594751
commit af35396601
22 changed files with 78 additions and 266 deletions
+23 -23
View File
@@ -67,28 +67,28 @@ const (
)
type config struct {
LogLevel string `env:"SMQ_USERS_LOG_LEVEL" envDefault:"info"`
AdminEmail string `env:"SMQ_USERS_ADMIN_EMAIL" envDefault:"admin@example.com"`
AdminPassword string `env:"SMQ_USERS_ADMIN_PASSWORD" envDefault:"12345678"`
AdminUsername string `env:"SMQ_USERS_ADMIN_USERNAME" envDefault:"admin"`
AdminFirstName string `env:"SMQ_USERS_ADMIN_FIRST_NAME" envDefault:"super"`
AdminLastName string `env:"SMQ_USERS_ADMIN_LAST_NAME" envDefault:"admin"`
PassRegexText string `env:"SMQ_USERS_PASS_REGEX" envDefault:"^.{8,}$"`
ResetURL string `env:"SMQ_TOKEN_RESET_ENDPOINT" envDefault:"/reset-request"`
JaegerURL url.URL `env:"SMQ_JAEGER_URL" envDefault:"http://localhost:4318/v1/traces"`
SendTelemetry bool `env:"SMQ_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `env:"SMQ_USERS_INSTANCE_ID" envDefault:""`
ESURL string `env:"SMQ_ES_URL" envDefault:"nats://localhost:4222"`
TraceRatio float64 `env:"SMQ_JAEGER_TRACE_RATIO" envDefault:"1.0"`
SelfRegister bool `env:"SMQ_USERS_ALLOW_SELF_REGISTER" envDefault:"false"`
OAuthUIRedirectURL string `env:"SMQ_OAUTH_UI_REDIRECT_URL" envDefault:"http://localhost:9095/domains"`
OAuthUIErrorURL string `env:"SMQ_OAUTH_UI_ERROR_URL" envDefault:"http://localhost:9095/error"`
DeleteInterval time.Duration `env:"SMQ_USERS_DELETE_INTERVAL" envDefault:"24h"`
DeleteAfter time.Duration `env:"SMQ_USERS_DELETE_AFTER" envDefault:"720h"`
SpicedbHost string `env:"SMQ_SPICEDB_HOST" envDefault:"localhost"`
SpicedbPort string `env:"SMQ_SPICEDB_PORT" envDefault:"50051"`
SpicedbPreSharedKey string `env:"SMQ_SPICEDB_PRE_SHARED_KEY" envDefault:"12345678"`
PassRegex *regexp.Regexp
LogLevel string `env:"SMQ_USERS_LOG_LEVEL" envDefault:"info"`
AdminEmail string `env:"SMQ_USERS_ADMIN_EMAIL" envDefault:"admin@example.com"`
AdminPassword string `env:"SMQ_USERS_ADMIN_PASSWORD" envDefault:"12345678"`
AdminUsername string `env:"SMQ_USERS_ADMIN_USERNAME" envDefault:"admin"`
AdminFirstName string `env:"SMQ_USERS_ADMIN_FIRST_NAME" envDefault:"super"`
AdminLastName string `env:"SMQ_USERS_ADMIN_LAST_NAME" envDefault:"admin"`
PassRegexText string `env:"SMQ_USERS_PASS_REGEX" envDefault:"^.{8,}$"`
JaegerURL url.URL `env:"SMQ_JAEGER_URL" envDefault:"http://localhost:4318/v1/traces"`
SendTelemetry bool `env:"SMQ_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `env:"SMQ_USERS_INSTANCE_ID" envDefault:""`
ESURL string `env:"SMQ_ES_URL" envDefault:"nats://localhost:4222"`
TraceRatio float64 `env:"SMQ_JAEGER_TRACE_RATIO" envDefault:"1.0"`
SelfRegister bool `env:"SMQ_USERS_ALLOW_SELF_REGISTER" envDefault:"false"`
OAuthUIRedirectURL string `env:"SMQ_OAUTH_UI_REDIRECT_URL" envDefault:"http://localhost:9095/domains"`
OAuthUIErrorURL string `env:"SMQ_OAUTH_UI_ERROR_URL" envDefault:"http://localhost:9095/error"`
DeleteInterval time.Duration `env:"SMQ_USERS_DELETE_INTERVAL" envDefault:"24h"`
DeleteAfter time.Duration `env:"SMQ_USERS_DELETE_AFTER" envDefault:"720h"`
SpicedbHost string `env:"SMQ_SPICEDB_HOST" envDefault:"localhost"`
SpicedbPort string `env:"SMQ_SPICEDB_PORT" envDefault:"50051"`
SpicedbPreSharedKey string `env:"SMQ_SPICEDB_PRE_SHARED_KEY" envDefault:"12345678"`
PasswordResetURLPrefix string `env:"SMQ_PASSWORD_RESET_URL_PREFIX" envDefault:"http://localhost:8080"`
PassRegex *regexp.Regexp
}
func main() {
@@ -264,7 +264,7 @@ func newService(ctx context.Context, authz smqauthz.Authorization, token grpcTok
// Creating users service
repo := postgres.NewRepository(database)
emailerClient, err := emailer.New(c.ResetURL, &ec)
emailerClient, err := emailer.New(fmt.Sprintf("%s/reset-request", c.PasswordResetURLPrefix), &ec)
if err != nil {
logger.Error(fmt.Sprintf("failed to configure e-mailing util: %s", err.Error()))
}
+1 -2
View File
@@ -235,7 +235,6 @@ SMQ_USERS_ADMIN_LAST_NAME=admin
SMQ_USERS_PASS_REGEX=^.{8,}$
SMQ_USERS_ACCESS_TOKEN_DURATION=15m
SMQ_USERS_REFRESH_TOKEN_DURATION=24h
SMQ_TOKEN_RESET_ENDPOINT=/reset-request
SMQ_USERS_HTTP_HOST=users
SMQ_USERS_HTTP_PORT=9002
SMQ_USERS_HTTP_SERVER_CERT=
@@ -257,12 +256,12 @@ SMQ_USERS_ADMIN_PASSWORD=12345678
SMQ_USERS_PASS_REGEX=^.{8,}$
SMQ_USERS_ACCESS_TOKEN_DURATION=15m
SMQ_USERS_REFRESH_TOKEN_DURATION=24h
SMQ_TOKEN_RESET_ENDPOINT=/reset-request
SMQ_USERS_ALLOW_SELF_REGISTER=true
SMQ_OAUTH_UI_REDIRECT_URL=http://localhost:9095${SMQ_UI_PATH_PREFIX}/tokens/secure
SMQ_OAUTH_UI_ERROR_URL=http://localhost:9095${SMQ_UI_PATH_PREFIX}/error
SMQ_USERS_DELETE_INTERVAL=24h
SMQ_USERS_DELETE_AFTER=720h
SMQ_PASSWORD_RESET_URL_PREFIX=http://localhost:9001
#### Users Client Config
SMQ_USERS_URL=users:9002
+1 -1
View File
@@ -835,7 +835,6 @@ services:
SMQ_USERS_PASS_REGEX: ${SMQ_USERS_PASS_REGEX}
SMQ_USERS_ACCESS_TOKEN_DURATION: ${SMQ_USERS_ACCESS_TOKEN_DURATION}
SMQ_USERS_REFRESH_TOKEN_DURATION: ${SMQ_USERS_REFRESH_TOKEN_DURATION}
SMQ_TOKEN_RESET_ENDPOINT: ${SMQ_TOKEN_RESET_ENDPOINT}
SMQ_USERS_HTTP_HOST: ${SMQ_USERS_HTTP_HOST}
SMQ_USERS_HTTP_PORT: ${SMQ_USERS_HTTP_PORT}
SMQ_USERS_HTTP_SERVER_CERT: ${SMQ_USERS_HTTP_SERVER_CERT}
@@ -882,6 +881,7 @@ services:
SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY}
SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST}
SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT}
SMQ_PASSWORD_RESET_URL_PREFIX: ${SMQ_PASSWORD_RESET_URL_PREFIX}
ports:
- ${SMQ_USERS_HTTP_PORT}:${SMQ_USERS_HTTP_PORT}
networks:
+2 -4
View File
@@ -1409,16 +1409,14 @@ func TestResetPasswordRequest(t *testing.T) {
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("GenerateResetToken", mock.Anything, tc.email, defHost).Return(tc.svcErr)
svcCall1 := svc.On("SendPasswordReset", mock.Anything, mock.Anything, tc.email, user.Credentials.Username, tc.issueRes.AccessToken).Return(nil)
svcCall := svc.On("SendPasswordReset", mock.Anything, tc.email).Return(tc.svcErr)
err := mgsdk.ResetPasswordRequest(context.Background(), tc.email)
assert.Equal(t, tc.err, err)
if tc.err == nil {
ok := svcCall.Parent.AssertCalled(t, "GenerateResetToken", mock.Anything, tc.email, defHost)
ok := svcCall.Parent.AssertCalled(t, "SendPasswordReset", mock.Anything, tc.email)
assert.True(t, ok)
}
svcCall.Unset()
svcCall1.Unset()
})
}
}
-2
View File
@@ -18,7 +18,6 @@ The service is configured using the environment variables presented in the follo
| SMQ_USERS_ADMIN_EMAIL | Default user, created on startup | <admin@example.com> |
| SMQ_USERS_ADMIN_PASSWORD | Default user password, created on startup | 12345678 |
| SMQ_USERS_PASS_REGEX | Password regex | ^.{8,}$ |
| SMQ_TOKEN_RESET_ENDPOINT | Password request reset endpoint, for constructing link | /reset-request |
| SMQ_USERS_HTTP_HOST | Users service HTTP host | localhost |
| SMQ_USERS_HTTP_PORT | Users service HTTP port | 9002 |
| SMQ_USERS_HTTP_SERVER_CERT | Path to the PEM encoded server certificate file | "" |
@@ -79,7 +78,6 @@ SMQ_USERS_LOG_LEVEL=info \
SMQ_USERS_ADMIN_EMAIL=admin@example.com \
SMQ_USERS_ADMIN_PASSWORD=12345678 \
SMQ_USERS_PASS_REGEX="^.{8,}$" \
SMQ_TOKEN_RESET_ENDPOINT="/reset-request" \
SMQ_USERS_HTTP_HOST=localhost \
SMQ_USERS_HTTP_PORT=9002 \
SMQ_USERS_HTTP_SERVER_CERT="" \
+1 -11
View File
@@ -1695,14 +1695,6 @@ func TestPasswordResetRequest(t *testing.T) {
status: http.StatusBadRequest,
err: apiutil.ErrValidation,
},
{
desc: "password reset request with empty host",
data: fmt.Sprintf(`{"email": "%s", "host": "%s"}`, testemail, ""),
contentType: contentType,
referer: "",
status: http.StatusBadRequest,
err: apiutil.ErrValidation,
},
{
desc: "password reset request with invalid email",
data: fmt.Sprintf(`{"email": "%s", "host": "%s"}`, "invalid", testhost),
@@ -1749,13 +1741,11 @@ func TestPasswordResetRequest(t *testing.T) {
referer: tc.referer,
body: strings.NewReader(tc.data),
}
svcCall := svc.On("GenerateResetToken", mock.Anything, mock.Anything, mock.Anything).Return(tc.generateErr)
svcCall1 := svc.On("SendPasswordReset", mock.Anything, mock.Anything, mock.Anything, mock.Anything, validToken).Return(tc.err)
svcCall := svc.On("SendPasswordReset", mock.Anything, mock.Anything).Return(tc.generateErr)
res, err := req.make()
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
svcCall.Unset()
svcCall1.Unset()
})
}
}
+1 -1
View File
@@ -255,7 +255,7 @@ func passwordResetRequestEndpoint(svc users.Service) endpoint.Endpoint {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
if err := svc.GenerateResetToken(ctx, req.Email, req.Host); err != nil {
if err := svc.SendPasswordReset(ctx, req.Email); err != nil {
return nil, err
}
-4
View File
@@ -284,16 +284,12 @@ func (req tokenReq) validate() error {
type passResetReq struct {
Email string `json:"email"`
Host string `json:"host"`
}
func (req passResetReq) validate() error {
if req.Email == "" {
return apiutil.ErrMissingEmail
}
if req.Host == "" {
return apiutil.ErrMissingHost
}
return nil
}
-10
View File
@@ -587,7 +587,6 @@ func TestPasswResetReqValidate(t *testing.T) {
desc: "valid request",
req: passResetReq{
Email: "example@example.com",
Host: "example.com",
},
err: nil,
},
@@ -595,18 +594,9 @@ func TestPasswResetReqValidate(t *testing.T) {
desc: "empty email",
req: passResetReq{
Email: "",
Host: "example.com",
},
err: apiutil.ErrMissingEmail,
},
{
desc: "empty host",
req: passResetReq{
Email: "example@example.com",
Host: "",
},
err: apiutil.ErrMissingHost,
},
}
for _, c := range cases {
err := c.req.validate()
-1
View File
@@ -441,7 +441,6 @@ func decodePasswordResetRequest(_ context.Context, r *http.Request) (any, error)
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
}
req.Host = r.Header.Get("Referer")
return req, nil
}
+1 -1
View File
@@ -6,5 +6,5 @@ package users
// Emailer wrapper around the email.
type Emailer interface {
// SendPasswordReset sends an email to the user with a link to reset the password.
SendPasswordReset(To []string, host, user, token string) error
SendPasswordReset(To []string, user, token string) error
}
+6 -3
View File
@@ -20,10 +20,13 @@ type emailer struct {
// New creates new emailer utility.
func New(url string, c *email.Config) (users.Emailer, error) {
e, err := email.New(c)
return &emailer{resetURL: url, agent: e}, err
return &emailer{
resetURL: url,
agent: e,
}, err
}
func (e *emailer) SendPasswordReset(to []string, host, user, token string) error {
url := fmt.Sprintf("%s%s?token=%s", host, e.resetURL, token)
func (e *emailer) SendPasswordReset(to []string, user, token string) error {
url := fmt.Sprintf("%s?token=%s", e.resetURL, token)
return e.agent.Send(to, "", "Password Reset Request", "", user, url, "")
}
+4 -20
View File
@@ -304,19 +304,18 @@ func (es *eventStore) Identify(ctx context.Context, session authn.Session) (stri
return userID, nil
}
func (es *eventStore) GenerateResetToken(ctx context.Context, email, host string) error {
err := es.svc.GenerateResetToken(ctx, email, host)
func (es *eventStore) SendPasswordReset(ctx context.Context, email string) error {
err := es.svc.SendPasswordReset(ctx, email)
if err != nil {
return err
}
event := generateResetTokenEvent{
event := sendPasswordResetEvent{
email: email,
host: host,
requestID: middleware.GetReqID(ctx),
}
return es.Publish(ctx, resetTokenStream, event)
return es.Publish(ctx, sendPasswordResetStream, event)
}
func (es *eventStore) IssueToken(ctx context.Context, username, secret string) (*grpcTokenV1.Token, error) {
@@ -366,21 +365,6 @@ func (es *eventStore) ResetSecret(ctx context.Context, session authn.Session, se
return es.Publish(ctx, resetSecretStream, event)
}
func (es *eventStore) SendPasswordReset(ctx context.Context, host, email, user, token string) error {
if err := es.svc.SendPasswordReset(ctx, host, email, user, token); err != nil {
return err
}
event := sendPasswordResetEvent{
host: host,
email: email,
user: user,
requestID: middleware.GetReqID(ctx),
}
return es.Publish(ctx, sendPasswordResetStream, event)
}
func (es *eventStore) OAuthCallback(ctx context.Context, user users.User) (users.User, error) {
token, err := es.svc.OAuthCallback(ctx, user)
if err != nil {
+2 -6
View File
@@ -200,8 +200,8 @@ func (am *authorizationMiddleware) UpdateProfilePicture(ctx context.Context, ses
return am.svc.UpdateProfilePicture(ctx, session, id, usr)
}
func (am *authorizationMiddleware) GenerateResetToken(ctx context.Context, email, host string) error {
return am.svc.GenerateResetToken(ctx, email, host)
func (am *authorizationMiddleware) SendPasswordReset(ctx context.Context, email string) error {
return am.svc.SendPasswordReset(ctx, email)
}
func (am *authorizationMiddleware) UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (users.User, error) {
@@ -224,10 +224,6 @@ func (am *authorizationMiddleware) ResetSecret(ctx context.Context, session auth
return am.svc.ResetSecret(ctx, session, secret)
}
func (am *authorizationMiddleware) SendPasswordReset(ctx context.Context, host, email, user, token string) error {
return am.svc.SendPasswordReset(ctx, host, email, user, token)
}
func (am *authorizationMiddleware) UpdateRole(ctx context.Context, session authn.Session, user users.User) (users.User, error) {
if session.Type == authn.PersonalAccessToken {
if err := am.authz.AuthorizePAT(ctx, smqauthz.PatReq{
+4 -24
View File
@@ -314,23 +314,22 @@ func (lm *loggingMiddleware) UpdateProfilePicture(ctx context.Context, session a
return lm.svc.UpdateProfilePicture(ctx, session, id, user)
}
// GenerateResetToken logs the generate_reset_token request. It logs the time it took to complete the request.
// SendPasswordReset logs the send_password_reset request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) GenerateResetToken(ctx context.Context, email, host string) (err error) {
func (lm *loggingMiddleware) SendPasswordReset(ctx context.Context, email string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.String("host", host),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Generate reset token failed", args...)
return
}
lm.logger.Info("Generate reset token completed successfully", args...)
lm.logger.Info("Send password reset completed successfully", args...)
}(time.Now())
return lm.svc.GenerateResetToken(ctx, email, host)
return lm.svc.SendPasswordReset(ctx, email)
}
// ResetSecret logs the reset_secret request. It logs the time it took to complete the request.
@@ -351,25 +350,6 @@ func (lm *loggingMiddleware) ResetSecret(ctx context.Context, session authn.Sess
return lm.svc.ResetSecret(ctx, session, secret)
}
// SendPasswordReset logs the send_password_reset request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) SendPasswordReset(ctx context.Context, host, email, user, token string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.String("host", host),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Send password reset failed", args...)
return
}
lm.logger.Info("Send password reset completed successfully", args...)
}(time.Now())
return lm.svc.SendPasswordReset(ctx, host, email, user, token)
}
// UpdateRole logs the update_user_role request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateRole(ctx context.Context, session authn.Session, user users.User) (c users.User, err error) {
+5 -14
View File
@@ -147,13 +147,13 @@ func (ms *metricsMiddleware) UpdateProfilePicture(ctx context.Context, session a
return ms.svc.UpdateProfilePicture(ctx, session, id, user)
}
// GenerateResetToken instruments GenerateResetToken method with metrics.
func (ms *metricsMiddleware) GenerateResetToken(ctx context.Context, email, host string) error {
// SendPasswordReset instruments SendPasswordReset method with metrics.
func (ms *metricsMiddleware) SendPasswordReset(ctx context.Context, email string) error {
defer func(begin time.Time) {
ms.counter.With("method", "generate_reset_token").Add(1)
ms.latency.With("method", "generate_reset_token").Observe(time.Since(begin).Seconds())
ms.counter.With("method", "send_password_reset").Add(1)
ms.latency.With("method", "send_password_reset").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.GenerateResetToken(ctx, email, host)
return ms.svc.SendPasswordReset(ctx, email)
}
// ResetSecret instruments ResetSecret method with metrics.
@@ -165,15 +165,6 @@ func (ms *metricsMiddleware) ResetSecret(ctx context.Context, session authn.Sess
return ms.svc.ResetSecret(ctx, session, secret)
}
// SendPasswordReset instruments SendPasswordReset method with metrics.
func (ms *metricsMiddleware) SendPasswordReset(ctx context.Context, host, email, user, token string) error {
defer func(begin time.Time) {
ms.counter.With("method", "send_password_reset").Add(1)
ms.latency.With("method", "send_password_reset").Observe(time.Since(begin).Seconds())
}(time.Now())
return ms.svc.SendPasswordReset(ctx, host, email, user, token)
}
// UpdateRole instruments UpdateRole method with metrics.
func (ms *metricsMiddleware) UpdateRole(ctx context.Context, session authn.Session, user users.User) (users.User, error) {
defer func(begin time.Time) {
+8 -14
View File
@@ -39,16 +39,16 @@ func (_m *Emailer) EXPECT() *Emailer_Expecter {
}
// SendPasswordReset provides a mock function for the type Emailer
func (_mock *Emailer) SendPasswordReset(To []string, host string, user string, token string) error {
ret := _mock.Called(To, host, user, token)
func (_mock *Emailer) SendPasswordReset(To []string, user string, token string) error {
ret := _mock.Called(To, user, token)
if len(ret) == 0 {
panic("no return value specified for SendPasswordReset")
}
var r0 error
if returnFunc, ok := ret.Get(0).(func([]string, string, string, string) error); ok {
r0 = returnFunc(To, host, user, token)
if returnFunc, ok := ret.Get(0).(func([]string, string, string) error); ok {
r0 = returnFunc(To, user, token)
} else {
r0 = ret.Error(0)
}
@@ -62,14 +62,13 @@ type Emailer_SendPasswordReset_Call struct {
// SendPasswordReset is a helper method to define mock.On call
// - To []string
// - host string
// - user string
// - token string
func (_e *Emailer_Expecter) SendPasswordReset(To interface{}, host interface{}, user interface{}, token interface{}) *Emailer_SendPasswordReset_Call {
return &Emailer_SendPasswordReset_Call{Call: _e.mock.On("SendPasswordReset", To, host, user, token)}
func (_e *Emailer_Expecter) SendPasswordReset(To interface{}, user interface{}, token interface{}) *Emailer_SendPasswordReset_Call {
return &Emailer_SendPasswordReset_Call{Call: _e.mock.On("SendPasswordReset", To, user, token)}
}
func (_c *Emailer_SendPasswordReset_Call) Run(run func(To []string, host string, user string, token string)) *Emailer_SendPasswordReset_Call {
func (_c *Emailer_SendPasswordReset_Call) Run(run func(To []string, user string, token string)) *Emailer_SendPasswordReset_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 []string
if args[0] != nil {
@@ -83,15 +82,10 @@ func (_c *Emailer_SendPasswordReset_Call) Run(run func(To []string, host string,
if args[2] != nil {
arg2 = args[2].(string)
}
var arg3 string
if args[3] != nil {
arg3 = args[3].(string)
}
run(
arg0,
arg1,
arg2,
arg3,
)
})
return _c
@@ -102,7 +96,7 @@ func (_c *Emailer_SendPasswordReset_Call) Return(err error) *Emailer_SendPasswor
return _c
}
func (_c *Emailer_SendPasswordReset_Call) RunAndReturn(run func(To []string, host string, user string, token string) error) *Emailer_SendPasswordReset_Call {
func (_c *Emailer_SendPasswordReset_Call) RunAndReturn(run func(To []string, user string, token string) error) *Emailer_SendPasswordReset_Call {
_c.Call.Return(run)
return _c
}
+8 -89
View File
@@ -250,69 +250,6 @@ func (_c *Service_Enable_Call) RunAndReturn(run func(ctx context.Context, sessio
return _c
}
// GenerateResetToken provides a mock function for the type Service
func (_mock *Service) GenerateResetToken(ctx context.Context, email string, host string) error {
ret := _mock.Called(ctx, email, host)
if len(ret) == 0 {
panic("no return value specified for GenerateResetToken")
}
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = returnFunc(ctx, email, host)
} else {
r0 = ret.Error(0)
}
return r0
}
// Service_GenerateResetToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateResetToken'
type Service_GenerateResetToken_Call struct {
*mock.Call
}
// GenerateResetToken is a helper method to define mock.On call
// - ctx context.Context
// - email string
// - host string
func (_e *Service_Expecter) GenerateResetToken(ctx interface{}, email interface{}, host interface{}) *Service_GenerateResetToken_Call {
return &Service_GenerateResetToken_Call{Call: _e.mock.On("GenerateResetToken", ctx, email, host)}
}
func (_c *Service_GenerateResetToken_Call) Run(run func(ctx context.Context, email string, host string)) *Service_GenerateResetToken_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
var arg1 string
if args[1] != nil {
arg1 = args[1].(string)
}
var arg2 string
if args[2] != nil {
arg2 = args[2].(string)
}
run(
arg0,
arg1,
arg2,
)
})
return _c
}
func (_c *Service_GenerateResetToken_Call) Return(err error) *Service_GenerateResetToken_Call {
_c.Call.Return(err)
return _c
}
func (_c *Service_GenerateResetToken_Call) RunAndReturn(run func(ctx context.Context, email string, host string) error) *Service_GenerateResetToken_Call {
_c.Call.Return(run)
return _c
}
// Identify provides a mock function for the type Service
func (_mock *Service) Identify(ctx context.Context, session authn.Session) (string, error) {
ret := _mock.Called(ctx, session)
@@ -930,16 +867,16 @@ func (_c *Service_SearchUsers_Call) RunAndReturn(run func(ctx context.Context, p
}
// SendPasswordReset provides a mock function for the type Service
func (_mock *Service) SendPasswordReset(ctx context.Context, host string, email string, user string, token string) error {
ret := _mock.Called(ctx, host, email, user, token)
func (_mock *Service) SendPasswordReset(ctx context.Context, email string) error {
ret := _mock.Called(ctx, email)
if len(ret) == 0 {
panic("no return value specified for SendPasswordReset")
}
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, string, string, string, string) error); ok {
r0 = returnFunc(ctx, host, email, user, token)
if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = returnFunc(ctx, email)
} else {
r0 = ret.Error(0)
}
@@ -953,15 +890,12 @@ type Service_SendPasswordReset_Call struct {
// SendPasswordReset is a helper method to define mock.On call
// - ctx context.Context
// - host string
// - email string
// - user string
// - token string
func (_e *Service_Expecter) SendPasswordReset(ctx interface{}, host interface{}, email interface{}, user interface{}, token interface{}) *Service_SendPasswordReset_Call {
return &Service_SendPasswordReset_Call{Call: _e.mock.On("SendPasswordReset", ctx, host, email, user, token)}
func (_e *Service_Expecter) SendPasswordReset(ctx interface{}, email interface{}) *Service_SendPasswordReset_Call {
return &Service_SendPasswordReset_Call{Call: _e.mock.On("SendPasswordReset", ctx, email)}
}
func (_c *Service_SendPasswordReset_Call) Run(run func(ctx context.Context, host string, email string, user string, token string)) *Service_SendPasswordReset_Call {
func (_c *Service_SendPasswordReset_Call) Run(run func(ctx context.Context, email string)) *Service_SendPasswordReset_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
@@ -971,24 +905,9 @@ func (_c *Service_SendPasswordReset_Call) Run(run func(ctx context.Context, host
if args[1] != nil {
arg1 = args[1].(string)
}
var arg2 string
if args[2] != nil {
arg2 = args[2].(string)
}
var arg3 string
if args[3] != nil {
arg3 = args[3].(string)
}
var arg4 string
if args[4] != nil {
arg4 = args[4].(string)
}
run(
arg0,
arg1,
arg2,
arg3,
arg4,
)
})
return _c
@@ -999,7 +918,7 @@ func (_c *Service_SendPasswordReset_Call) Return(err error) *Service_SendPasswor
return _c
}
func (_c *Service_SendPasswordReset_Call) RunAndReturn(run func(ctx context.Context, host string, email string, user string, token string) error) *Service_SendPasswordReset_Call {
func (_c *Service_SendPasswordReset_Call) RunAndReturn(run func(ctx context.Context, email string) error) *Service_SendPasswordReset_Call {
_c.Call.Return(run)
return _c
}
+2 -7
View File
@@ -269,7 +269,7 @@ func (svc service) UpdateEmail(ctx context.Context, session authn.Session, userI
return user, nil
}
func (svc service) GenerateResetToken(ctx context.Context, email, host string) error {
func (svc service) SendPasswordReset(ctx context.Context, email string) error {
user, err := svc.users.RetrieveByEmail(ctx, email)
if err != nil {
return errors.Wrap(svcerr.ErrViewEntity, err)
@@ -284,7 +284,7 @@ func (svc service) GenerateResetToken(ctx context.Context, email, host string) e
return errors.Wrap(errRecoveryToken, err)
}
return svc.SendPasswordReset(ctx, host, email, user.Credentials.Username, token.AccessToken)
return svc.email.SendPasswordReset([]string{email}, user.Credentials.Username, token.AccessToken)
}
func (svc service) ResetSecret(ctx context.Context, session authn.Session, secret string) error {
@@ -358,11 +358,6 @@ func (svc service) UpdateUsername(ctx context.Context, session authn.Session, id
return updatedUser, nil
}
func (svc service) SendPasswordReset(_ context.Context, host, email, user, token string) error {
to := []string{email}
return svc.email.SendPasswordReset(to, host, user, token)
}
func (svc service) UpdateRole(ctx context.Context, session authn.Session, usr User) (User, error) {
if err := svc.checkSuperAdmin(ctx, session); err != nil {
return User{}, err
+3 -7
View File
@@ -1526,13 +1526,12 @@ func TestRefreshToken(t *testing.T) {
}
}
func TestGenerateResetToken(t *testing.T) {
func TestSendPasswordReset(t *testing.T) {
svc, auth, cRepo, _, e := newService()
cases := []struct {
desc string
email string
host string
retrieveByEmailResponse users.User
issueResponse *grpcTokenV1.Token
retrieveByEmailErr error
@@ -1542,7 +1541,6 @@ func TestGenerateResetToken(t *testing.T) {
{
desc: "generate reset token for existing user",
email: "existingemail@example.com",
host: "examplehost",
retrieveByEmailResponse: user,
issueResponse: &grpcTokenV1.Token{AccessToken: validToken, RefreshToken: &validToken, AccessType: "3"},
err: nil,
@@ -1550,7 +1548,6 @@ func TestGenerateResetToken(t *testing.T) {
{
desc: "generate reset token for user with non-existing user",
email: "example@example.com",
host: "examplehost",
retrieveByEmailResponse: users.User{
ID: testsutil.GenerateUUID(t),
Email: "",
@@ -1561,7 +1558,6 @@ func TestGenerateResetToken(t *testing.T) {
{
desc: "generate reset token with failed to issue token",
email: "existingemail@example.com",
host: "examplehost",
retrieveByEmailResponse: user,
issueResponse: &grpcTokenV1.Token{},
issueErr: svcerr.ErrAuthorization,
@@ -1573,8 +1569,8 @@ func TestGenerateResetToken(t *testing.T) {
t.Run(tc.desc, func(t *testing.T) {
repoCall := cRepo.On("RetrieveByEmail", context.Background(), tc.email).Return(tc.retrieveByEmailResponse, tc.retrieveByEmailErr)
authCall := auth.On("Issue", context.Background(), mock.Anything).Return(tc.issueResponse, tc.issueErr)
svcCall := e.On("SendPasswordReset", []string{tc.email}, tc.host, user.Credentials.Username, validToken).Return(tc.err)
err := svc.GenerateResetToken(context.Background(), tc.email, tc.host)
svcCall := e.On("SendPasswordReset", []string{tc.email}, user.Credentials.Username, validToken).Return(tc.err)
err := svc.SendPasswordReset(context.Background(), tc.email)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
repoCall.Parent.AssertCalled(t, "RetrieveByEmail", context.Background(), tc.email)
repoCall.Unset()
+4 -16
View File
@@ -145,15 +145,14 @@ func (tm *tracingMiddleware) UpdateProfilePicture(ctx context.Context, session a
return tm.svc.UpdateProfilePicture(ctx, session, id, usr)
}
// GenerateResetToken traces the "GenerateResetToken" operation of the wrapped users.Service.
func (tm *tracingMiddleware) GenerateResetToken(ctx context.Context, email, host string) error {
ctx, span := tracing.StartSpan(ctx, tm.tracer, "svc_generate_reset_token", trace.WithAttributes(
// SendPasswordReset traces the "SendPasswordReset" operation of the wrapped users.Service.
func (tm *tracingMiddleware) SendPasswordReset(ctx context.Context, email string) error {
ctx, span := tracing.StartSpan(ctx, tm.tracer, "svc_send_password_reset", trace.WithAttributes(
attribute.String("email", email),
attribute.String("host", host),
))
defer span.End()
return tm.svc.GenerateResetToken(ctx, email, host)
return tm.svc.SendPasswordReset(ctx, email)
}
// ResetSecret traces the "ResetSecret" operation of the wrapped users.Service.
@@ -164,17 +163,6 @@ func (tm *tracingMiddleware) ResetSecret(ctx context.Context, session authn.Sess
return tm.svc.ResetSecret(ctx, session, secret)
}
// SendPasswordReset traces the "SendPasswordReset" operation of the wrapped users.Service.
func (tm *tracingMiddleware) SendPasswordReset(ctx context.Context, host, email, user, token string) error {
ctx, span := tracing.StartSpan(ctx, tm.tracer, "svc_send_password_reset", trace.WithAttributes(
attribute.String("email", email),
attribute.String("user", user),
))
defer span.End()
return tm.svc.SendPasswordReset(ctx, host, email, user, token)
}
// ViewProfile traces the "ViewProfile" operation of the wrapped users.Service.
func (tm *tracingMiddleware) ViewProfile(ctx context.Context, session authn.Session) (users.User, error) {
ctx, span := tracing.StartSpan(ctx, tm.tracer, "svc_view_profile")
+2 -6
View File
@@ -179,9 +179,8 @@ type Service interface {
// UpdateProfilePicture updates the user's profile picture.
UpdateProfilePicture(ctx context.Context, session authn.Session, id string, usr UserReq) (User, error)
// GenerateResetToken email where mail will be sent.
// host is used for generating reset link.
GenerateResetToken(ctx context.Context, email, host string) error
// SendPasswordReset generates reset password link and sends it to the user via email.
SendPasswordReset(ctx context.Context, email string) error
// UpdateSecret updates the user's secret.
UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (User, error)
@@ -190,9 +189,6 @@ type Service interface {
// token can be authentication token or secret reset token.
ResetSecret(ctx context.Context, session authn.Session, secret string) error
// SendPasswordReset sends reset password link to email.
SendPasswordReset(ctx context.Context, host, email, user, token string) error
// UpdateRole updates the user's Role.
UpdateRole(ctx context.Context, session authn.Session, user User) (User, error)