2023-10-10 13:20:53 +00:00
package handlers
import (
"context"
"database/sql"
"fmt"
"testing"
"time"
2024-09-26 07:14:33 +00:00
"github.com/muhlemmer/gu"
2023-10-10 13:20:53 +00:00
"github.com/stretchr/testify/assert"
2023-11-22 10:56:43 +00:00
"go.uber.org/mock/gomock"
2023-10-10 13:20:53 +00:00
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/crypto"
2024-09-26 07:14:33 +00:00
"github.com/zitadel/zitadel/internal/domain"
2023-10-10 13:20:53 +00:00
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/eventstore/repository"
es_repo_mock "github.com/zitadel/zitadel/internal/eventstore/repository/mock"
2024-09-12 04:27:29 +00:00
"github.com/zitadel/zitadel/internal/notification/channels/email"
2023-10-10 13:20:53 +00:00
channel_mock "github.com/zitadel/zitadel/internal/notification/channels/mock"
2024-10-31 14:57:17 +00:00
"github.com/zitadel/zitadel/internal/notification/channels/set"
2024-09-06 13:11:36 +00:00
"github.com/zitadel/zitadel/internal/notification/channels/sms"
2023-10-10 13:20:53 +00:00
"github.com/zitadel/zitadel/internal/notification/channels/smtp"
2024-09-26 07:14:33 +00:00
"github.com/zitadel/zitadel/internal/notification/channels/twilio"
2023-10-10 13:20:53 +00:00
"github.com/zitadel/zitadel/internal/notification/channels/webhook"
"github.com/zitadel/zitadel/internal/notification/handlers/mock"
2024-04-03 10:43:43 +00:00
"github.com/zitadel/zitadel/internal/notification/messages"
2023-10-10 13:20:53 +00:00
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/notification/types"
"github.com/zitadel/zitadel/internal/query"
2024-04-03 10:43:43 +00:00
"github.com/zitadel/zitadel/internal/repository/session"
2023-10-10 13:20:53 +00:00
"github.com/zitadel/zitadel/internal/repository/user"
)
const (
orgID = "org1"
policyID = "policy1"
userID = "user1"
codeID = "event1"
logoURL = "logo.png"
eventOrigin = "https://triggered.here"
2024-09-26 07:14:33 +00:00
eventOriginDomain = "triggered.here"
2023-10-10 13:20:53 +00:00
assetsPath = "/assets/v1"
preferredLoginName = "loginName1"
lastEmail = "last@email.com"
verifiedEmail = "verified@email.com"
2024-09-26 07:14:33 +00:00
lastPhone = "+41797654321"
verifiedPhone = "+41791234567"
2023-10-10 13:20:53 +00:00
instancePrimaryDomain = "primary.domain"
externalDomain = "external.domain"
externalPort = 3000
externalSecure = false
externalProtocol = "http"
defaultOTPEmailTemplate = "/otp/verify?loginName={{.LoginName}}&code={{.Code}}"
2024-04-24 15:50:58 +00:00
authRequestID = "authRequestID"
2024-09-26 07:14:33 +00:00
smsProviderID = "smsProviderID"
emailProviderID = "emailProviderID"
verificationID = "verificationID"
2023-10-10 13:20:53 +00:00
)
func Test_userNotifier_reduceInitCodeAdded ( t * testing . T ) {
expectMailSubject := "Initialize User"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanInitCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanInitialCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanInitCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanInitialCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
} ,
} , w
} ,
} , {
name : "button url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
2024-04-24 15:50:58 +00:00
expectContent := fmt . Sprintf ( "%s/ui/login/user/init?authRequestID=%s&code=%s&loginname=%s&orgID=%s&passwordset=%t&userID=%s" , eventOrigin , "" , testCode , preferredLoginName , orgID , false , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanInitCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanInitialCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "button url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
2024-04-24 15:50:58 +00:00
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/user/init?authRequestID=%s&code=%s&loginname=%s&orgID=%s&passwordset=%t&userID=%s" , externalProtocol , instancePrimaryDomain , externalPort , "" , testCode , preferredLoginName , orgID , false , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanInitCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanInitialCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
} ,
} , w
} ,
2024-04-24 15:50:58 +00:00
} , {
name : "button url without event trigger url with authRequestID" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/user/init?authRequestID=%s&code=%s&loginname=%s&orgID=%s&passwordset=%t&userID=%s" , externalProtocol , instancePrimaryDomain , externalPort , authRequestID , testCode , preferredLoginName , orgID , false , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2024-04-24 15:50:58 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanInitCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanInitialCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
AuthRequestID : authRequestID ,
} ,
} , w
} ,
2023-10-10 13:20:53 +00:00
} }
// TODO: Why don't we have an url template on user.HumanInitialCodeAddedEvent?
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
stmt , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reduceInitCodeAdded ( a . event )
2023-10-19 10:19:10 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
err = stmt . Execute ( nil , "" )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
func Test_userNotifier_reduceEmailCodeAdded ( t * testing . T ) {
expectMailSubject := "Verify email"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanEmailVerificationCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanEmailCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanEmailVerificationCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanEmailCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
} ,
} , w
} ,
} , {
name : "button url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
2024-04-24 15:50:58 +00:00
expectContent := fmt . Sprintf ( "%s/ui/login/mail/verification?authRequestID=%s&code=%s&orgID=%s&userID=%s" , eventOrigin , "" , testCode , orgID , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanEmailVerificationCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanEmailCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "button url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
2024-04-24 15:50:58 +00:00
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/mail/verification?authRequestID=%s&code=%s&orgID=%s&userID=%s" , externalProtocol , instancePrimaryDomain , externalPort , "" , testCode , orgID , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanEmailVerificationCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanEmailCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
} ,
} , w
} ,
2024-04-24 15:50:58 +00:00
} , {
name : "button url without event trigger url with authRequestID" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/mail/verification?authRequestID=%s&code=%s&orgID=%s&userID=%s" , externalProtocol , instancePrimaryDomain , externalPort , authRequestID , testCode , orgID , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2024-04-24 15:50:58 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanEmailVerificationCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanEmailCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
AuthRequestID : authRequestID ,
} ,
} , w
} ,
2023-10-10 13:20:53 +00:00
} , {
name : "button url with url template and event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
urlTemplate := "https://my.custom.url/org/{{.OrgID}}/user/{{.UserID}}/verify/{{.Code}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "https://my.custom.url/org/%s/user/%s/verify/%s" , orgID , userID , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanEmailVerificationCodeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanEmailCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : urlTemplate ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} }
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
stmt , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reduceEmailCodeAdded ( a . event )
2023-10-19 10:19:10 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
err = stmt . Execute ( nil , "" )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
func Test_userNotifier_reducePasswordCodeAdded ( t * testing . T ) {
expectMailSubject := "Reset password"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
expectTemplateQueries ( queries , givenTemplate )
2024-09-26 07:14:33 +00:00
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { } ) . Return ( nil )
2023-10-10 13:20:53 +00:00
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
2024-09-26 07:14:33 +00:00
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { } ) . Return ( nil )
2023-10-10 13:20:53 +00:00
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
} ,
} , w
} ,
} , {
name : "button url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
2024-04-24 15:50:58 +00:00
expectContent := fmt . Sprintf ( "%s/ui/login/password/init?authRequestID=%s&code=%s&orgID=%s&userID=%s" , eventOrigin , "" , testCode , orgID , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
2024-09-26 07:14:33 +00:00
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { } ) . Return ( nil )
2023-10-10 13:20:53 +00:00
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "button url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
2024-04-24 15:50:58 +00:00
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/password/init?authRequestID=%s&code=%s&orgID=%s&userID=%s" , externalProtocol , instancePrimaryDomain , externalPort , "" , testCode , orgID , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
2024-09-26 07:14:33 +00:00
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { } ) . Return ( nil )
2023-10-10 13:20:53 +00:00
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
} ,
} , w
} ,
2024-04-24 15:50:58 +00:00
} , {
name : "button url without event trigger url with authRequestID" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/password/init?authRequestID=%s&code=%s&orgID=%s&userID=%s" , externalProtocol , instancePrimaryDomain , externalPort , authRequestID , testCode , orgID , userID )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2024-04-24 15:50:58 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
2024-09-26 07:14:33 +00:00
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { } ) . Return ( nil )
2024-04-24 15:50:58 +00:00
return fields {
queries : queries ,
commands : commands ,
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
AuthRequestID : authRequestID ,
} ,
} , w
} ,
2023-10-10 13:20:53 +00:00
} , {
name : "button url with url template and event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
urlTemplate := "https://my.custom.url/org/{{.OrgID}}/user/{{.UserID}}/verify/{{.Code}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "https://my.custom.url/org/%s/user/%s/verify/%s" , orgID , userID , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
2024-09-26 07:14:33 +00:00
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { } ) . Return ( nil )
2023-10-10 13:20:53 +00:00
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : urlTemplate ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
2024-09-26 07:14:33 +00:00
} , {
name : "external code" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
expectContent := "We received a password reset request. Please use the button below to reset your password. (Code ) If you didn't ask for this mail, please ignore it."
w . messageSMS = & messages . SMS {
SenderPhoneNumber : "senderNumber" ,
RecipientPhoneNumber : lastPhone ,
Content : expectContent ,
}
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . PasswordCodeSent ( gomock . Any ( ) , orgID , userID , & senders . CodeGeneratorInfo { ID : smsProviderID , VerificationID : verificationID } ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanPasswordCodeAddedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : nil ,
Expiry : 0 ,
URLTemplate : "" ,
CodeReturned : false ,
NotificationType : domain . NotificationTypeSms ,
GeneratorID : smsProviderID ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} ,
}
2023-10-10 13:20:53 +00:00
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
stmt , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reducePasswordCodeAdded ( a . event )
2023-10-19 10:19:10 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
err = stmt . Execute ( nil , "" )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
func Test_userNotifier_reduceDomainClaimed ( t * testing . T ) {
expectMailSubject := "Domain has been claimed"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . UserDomainClaimedSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
} , args {
event : & user . DomainClaimedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . UserDomainClaimedSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
} , args {
event : & user . DomainClaimedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
} ,
} , w
} ,
} }
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
stmt , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reduceDomainClaimed ( a . event )
2023-10-19 10:19:10 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
err = stmt . Execute ( nil , "" )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
func Test_userNotifier_reducePasswordlessCodeRequested ( t * testing . T ) {
expectMailSubject := "Add Passwordless Login"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanPasswordlessInitCodeSent ( gomock . Any ( ) , userID , orgID , codeID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordlessInitCodeRequestedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
ID : codeID ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanPasswordlessInitCodeSent ( gomock . Any ( ) , userID , orgID , codeID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordlessInitCodeRequestedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
ID : codeID ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
} ,
} , w
} ,
} , {
name : "button url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectContent := fmt . Sprintf ( "%s/ui/login/login/passwordless/init?userID=%s&orgID=%s&codeID=%s&code=%s" , eventOrigin , userID , orgID , codeID , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanPasswordlessInitCodeSent ( gomock . Any ( ) , userID , orgID , codeID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanPasswordlessInitCodeRequestedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
ID : codeID ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "button url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectContent := fmt . Sprintf ( "%s://%s:%d/ui/login/login/passwordless/init?userID=%s&orgID=%s&codeID=%s&code=%s" , externalProtocol , instancePrimaryDomain , externalPort , userID , orgID , codeID , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanPasswordlessInitCodeSent ( gomock . Any ( ) , userID , orgID , codeID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & user . HumanPasswordlessInitCodeRequestedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
ID : codeID ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : "" ,
CodeReturned : false ,
} ,
} , w
} ,
} , {
name : "button url with url template and event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
urlTemplate := "https://my.custom.url/org/{{.OrgID}}/user/{{.UserID}}/verify/{{.Code}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "https://my.custom.url/org/%s/user/%s/verify/%s" , orgID , userID , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . HumanPasswordlessInitCodeSent ( gomock . Any ( ) , userID , orgID , codeID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & user . HumanPasswordlessInitCodeRequestedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
ID : codeID ,
Code : code ,
Expiry : time . Hour ,
URLTemplate : urlTemplate ,
CodeReturned : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} }
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
stmt , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reducePasswordlessCodeRequested ( a . event )
2023-10-19 10:19:10 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
err = stmt . Execute ( nil , "" )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
func Test_userNotifier_reducePasswordChanged ( t * testing . T ) {
expectMailSubject := "Password of user has changed"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
queries . EXPECT ( ) . NotificationPolicyByOrg ( gomock . Any ( ) , gomock . Any ( ) , orgID , gomock . Any ( ) ) . Return ( & query . NotificationPolicy {
PasswordChange : true ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . PasswordChangeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
} , args {
event : & user . HumanPasswordChangedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { lastEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
queries . EXPECT ( ) . NotificationPolicyByOrg ( gomock . Any ( ) , gomock . Any ( ) , orgID , gomock . Any ( ) ) . Return ( & query . NotificationPolicy {
PasswordChange : true ,
} , nil )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
commands . EXPECT ( ) . PasswordChangeSent ( gomock . Any ( ) , orgID , userID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
} , args {
event : & user . HumanPasswordChangedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
} ,
} , w
} ,
} }
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
stmt , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reducePasswordChanged ( a . event )
2023-10-19 10:19:10 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
err = stmt . Execute ( nil , "" )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
func Test_userNotifier_reduceOTPEmailChallenged ( t * testing . T ) {
expectMailSubject := "Verify One-Time Password"
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s%s/%s/%s" , eventOrigin , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { verifiedEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
expectTemplateQueries ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
commands . EXPECT ( ) . OTPEmailSent ( gomock . Any ( ) , userID , orgID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & session . OTPEmailChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTmpl : "" ,
ReturnCode : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
expectContent := fmt . Sprintf ( "%s://%s:%d%s/%s/%s" , externalProtocol , instancePrimaryDomain , externalPort , assetsPath , policyID , logoURL )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { verifiedEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , "testcode" )
expectTemplateQueries ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
commands . EXPECT ( ) . OTPEmailSent ( gomock . Any ( ) , userID , orgID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & session . OTPEmailChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTmpl : "" ,
ReturnCode : false ,
} ,
} , w
} ,
} , {
name : "button url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "%s/otp/verify?loginName=%s&code=%s" , eventOrigin , preferredLoginName , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { verifiedEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
commands . EXPECT ( ) . OTPEmailSent ( gomock . Any ( ) , userID , orgID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & session . OTPEmailChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
URLTmpl : "" ,
ReturnCode : false ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "button url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
testCode := "testcode"
expectContent := fmt . Sprintf ( "%s://%s:%d/otp/verify?loginName=%s&code=%s" , externalProtocol , instancePrimaryDomain , externalPort , preferredLoginName , testCode )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { verifiedEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
expectTemplateQueries ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
commands . EXPECT ( ) . OTPEmailSent ( gomock . Any ( ) , userID , orgID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
} , args {
event : & session . OTPEmailChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
ReturnCode : false ,
} ,
} , w
} ,
} , {
name : "button url with url template and event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.URL}}"
urlTemplate := "https://my.custom.url/user/{{.LoginName}}/verify"
testCode := "testcode"
expectContent := fmt . Sprintf ( "https://my.custom.url/user/%s/verify" , preferredLoginName )
2024-09-26 07:14:33 +00:00
w . message = & messages . Email {
2023-10-10 13:20:53 +00:00
Recipients : [ ] string { verifiedEmail } ,
Subject : expectMailSubject ,
Content : expectContent ,
}
codeAlg , code := cryptoValue ( t , ctrl , testCode )
expectTemplateQueries ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
commands . EXPECT ( ) . OTPEmailSent ( gomock . Any ( ) , userID , orgID ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
2023-10-19 10:19:10 +00:00
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
2023-10-10 13:20:53 +00:00
userDataCrypto : codeAlg ,
SMSTokenCrypto : nil ,
} , args {
event : & session . OTPEmailChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : code ,
Expiry : time . Hour ,
ReturnCode : false ,
URLTmpl : urlTemplate ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} }
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
2023-12-05 11:12:01 +00:00
_ , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reduceSessionOTPEmailChallenged ( a . event )
2023-10-10 13:20:53 +00:00
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
2024-09-26 07:14:33 +00:00
func Test_userNotifier_reduceOTPSMSChallenged ( t * testing . T ) {
tests := [ ] struct {
name string
test func ( * gomock . Controller , * mock . MockQueries , * mock . MockCommands ) ( fields , args , want )
} { {
name : "asset url with event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
testCode := ""
expiry := 0 * time . Hour
2024-10-22 14:59:16 +00:00
expectContent := fmt . Sprintf ( ` % [ 1 ] s is your one - time password for % [ 2 ] s . Use it within the next % [ 3 ] s .
2024-09-26 07:14:33 +00:00
@ % [ 2 ] s # % [ 1 ] s ` , testCode , eventOriginDomain , expiry )
w . messageSMS = & messages . SMS {
SenderPhoneNumber : "senderNumber" ,
RecipientPhoneNumber : verifiedPhone ,
Content : expectContent ,
}
expectTemplateQueriesSMS ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
commands . EXPECT ( ) . OTPSMSSent ( gomock . Any ( ) , userID , orgID , & senders . CodeGeneratorInfo { ID : smsProviderID , VerificationID : verificationID } ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
} , args {
event : & session . OTPSMSChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : nil ,
Expiry : expiry ,
CodeReturned : false ,
GeneratorID : smsProviderID ,
TriggeredAtOrigin : eventOrigin ,
} ,
} , w
} ,
} , {
name : "asset url without event trigger url" ,
test : func ( ctrl * gomock . Controller , queries * mock . MockQueries , commands * mock . MockCommands ) ( f fields , a args , w want ) {
givenTemplate := "{{.LogoURL}}"
testCode := ""
expiry := 0 * time . Hour
2024-10-22 14:59:16 +00:00
expectContent := fmt . Sprintf ( ` % [ 1 ] s is your one - time password for % [ 2 ] s . Use it within the next % [ 3 ] s .
2024-09-26 07:14:33 +00:00
@ % [ 2 ] s # % [ 1 ] s ` , testCode , instancePrimaryDomain , expiry )
w . messageSMS = & messages . SMS {
SenderPhoneNumber : "senderNumber" ,
RecipientPhoneNumber : verifiedPhone ,
Content : expectContent ,
}
expectTemplateQueriesSMS ( queries , givenTemplate )
queries . EXPECT ( ) . SessionByID ( gomock . Any ( ) , gomock . Any ( ) , userID , gomock . Any ( ) ) . Return ( & query . Session { } , nil )
queries . EXPECT ( ) . SearchInstanceDomains ( gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . InstanceDomains {
Domains : [ ] * query . InstanceDomain { {
Domain : instancePrimaryDomain ,
IsPrimary : true ,
} } ,
} , nil )
commands . EXPECT ( ) . OTPSMSSent ( gomock . Any ( ) , userID , orgID , & senders . CodeGeneratorInfo { ID : smsProviderID , VerificationID : verificationID } ) . Return ( nil )
return fields {
queries : queries ,
commands : commands ,
es : eventstore . NewEventstore ( & eventstore . Config {
Querier : es_repo_mock . NewRepo ( t ) . ExpectFilterEvents ( ) . MockQuerier ,
} ) ,
} , args {
event : & session . OTPSMSChallengedEvent {
BaseEvent : * eventstore . BaseEventFromRepo ( & repository . Event {
AggregateID : userID ,
ResourceOwner : sql . NullString { String : orgID } ,
CreationDate : time . Now ( ) . UTC ( ) ,
} ) ,
Code : nil ,
Expiry : expiry ,
CodeReturned : false ,
GeneratorID : smsProviderID ,
} ,
} , w
} ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
ctrl := gomock . NewController ( t )
queries := mock . NewMockQueries ( ctrl )
commands := mock . NewMockCommands ( ctrl )
f , a , w := tt . test ( ctrl , queries , commands )
_ , err := newUserNotifier ( t , ctrl , queries , f , a , w ) . reduceSessionOTPSMSChallenged ( a . event )
if w . err != nil {
w . err ( t , err )
} else {
assert . NoError ( t , err )
}
} )
}
}
2023-10-10 13:20:53 +00:00
type fields struct {
queries * mock . MockQueries
commands * mock . MockCommands
es * eventstore . Eventstore
userDataCrypto crypto . EncryptionAlgorithm
SMSTokenCrypto crypto . EncryptionAlgorithm
}
type args struct {
event eventstore . Event
}
type want struct {
2024-09-26 07:14:33 +00:00
message * messages . Email
messageSMS * messages . SMS
err assert . ErrorAssertionFunc
2023-10-10 13:20:53 +00:00
}
2023-12-05 11:12:01 +00:00
func newUserNotifier ( t * testing . T , ctrl * gomock . Controller , queries * mock . MockQueries , f fields , a args , w want ) * userNotifier {
2023-10-10 13:20:53 +00:00
queries . EXPECT ( ) . NotificationProviderByIDAndType ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . AnyTimes ( ) . Return ( & query . DebugNotificationProvider { } , nil )
smtpAlg , _ := cryptoValue ( t , ctrl , "smtppw" )
channel := channel_mock . NewMockNotificationChannel ( ctrl )
if w . err == nil {
2024-09-26 07:14:33 +00:00
if w . message != nil {
w . message . TriggeringEvent = a . event
channel . EXPECT ( ) . HandleMessage ( w . message ) . Return ( nil )
}
if w . messageSMS != nil {
w . messageSMS . TriggeringEvent = a . event
channel . EXPECT ( ) . HandleMessage ( w . messageSMS ) . DoAndReturn ( func ( message * messages . SMS ) error {
message . VerificationID = gu . Ptr ( verificationID )
return nil
} )
}
2023-10-10 13:20:53 +00:00
}
return & userNotifier {
commands : f . commands ,
queries : NewNotificationQueries (
f . queries ,
f . es ,
externalDomain ,
externalPort ,
externalSecure ,
"" ,
f . userDataCrypto ,
smtpAlg ,
f . SMSTokenCrypto ,
) ,
otpEmailTmpl : defaultOTPEmailTemplate ,
2024-09-12 04:27:29 +00:00
channels : & channels {
Chain : * senders . ChainChannels ( channel ) ,
EmailConfig : & email . Config {
ProviderConfig : & email . Provider {
2024-09-26 07:14:33 +00:00
ID : "emailProviderID" ,
Description : "description" ,
2024-09-12 04:27:29 +00:00
} ,
SMTPConfig : & smtp . Config {
SMTP : smtp . SMTP {
Host : "host" ,
User : "user" ,
Password : "password" ,
} ,
Tls : true ,
From : "from" ,
FromName : "fromName" ,
ReplyToAddress : "replyToAddress" ,
} ,
WebhookConfig : nil ,
} ,
2024-09-26 07:14:33 +00:00
SMSConfig : & sms . Config {
ProviderConfig : & sms . Provider {
ID : "smsProviderID" ,
Description : "description" ,
} ,
TwilioConfig : & twilio . Config {
SID : "sid" ,
Token : "token" ,
SenderNumber : "senderNumber" ,
VerifyServiceSID : "verifyServiceSID" ,
} ,
} ,
2024-09-12 04:27:29 +00:00
} ,
2023-10-10 13:20:53 +00:00
}
}
var _ types . ChannelChains = ( * channels ) ( nil )
type channels struct {
senders . Chain
2024-09-12 04:27:29 +00:00
EmailConfig * email . Config
2024-09-26 07:14:33 +00:00
SMSConfig * sms . Config
2023-10-10 13:20:53 +00:00
}
2024-09-12 04:27:29 +00:00
func ( c * channels ) Email ( context . Context ) ( * senders . Chain , * email . Config , error ) {
return & c . Chain , c . EmailConfig , nil
2023-10-10 13:20:53 +00:00
}
2024-09-06 13:11:36 +00:00
func ( c * channels ) SMS ( context . Context ) ( * senders . Chain , * sms . Config , error ) {
2024-09-26 07:14:33 +00:00
return & c . Chain , c . SMSConfig , nil
2023-10-10 13:20:53 +00:00
}
func ( c * channels ) Webhook ( context . Context , webhook . Config ) ( * senders . Chain , error ) {
return & c . Chain , nil
}
2024-10-31 14:57:17 +00:00
func ( c * channels ) SecurityTokenEvent ( context . Context , set . Config ) ( * senders . Chain , error ) {
return & c . Chain , nil
}
2023-10-10 13:20:53 +00:00
func expectTemplateQueries ( queries * mock . MockQueries , template string ) {
2023-12-05 11:12:01 +00:00
queries . EXPECT ( ) . GetInstanceRestrictions ( gomock . Any ( ) ) . Return ( query . Restrictions {
AllowedLanguages : [ ] language . Tag { language . English } ,
} , nil )
2023-10-10 13:20:53 +00:00
queries . EXPECT ( ) . ActiveLabelPolicyByOrg ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . LabelPolicy {
ID : policyID ,
Light : query . Theme {
LogoURL : logoURL ,
} ,
} , nil )
queries . EXPECT ( ) . MailTemplateByOrg ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . MailTemplate { Template : [ ] byte ( template ) } , nil )
2023-11-21 12:11:38 +00:00
queries . EXPECT ( ) . GetNotifyUserByID ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . NotifyUser {
2023-10-10 13:20:53 +00:00
ID : userID ,
ResourceOwner : orgID ,
LastEmail : lastEmail ,
VerifiedEmail : verifiedEmail ,
PreferredLoginName : preferredLoginName ,
2024-09-26 07:14:33 +00:00
LastPhone : lastPhone ,
VerifiedPhone : verifiedPhone ,
} , nil )
queries . EXPECT ( ) . GetDefaultLanguage ( gomock . Any ( ) ) . Return ( language . English )
queries . EXPECT ( ) . CustomTextListByTemplate ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Times ( 2 ) . Return ( & query . CustomTexts { } , nil )
}
func expectTemplateQueriesSMS ( queries * mock . MockQueries , template string ) {
queries . EXPECT ( ) . GetInstanceRestrictions ( gomock . Any ( ) ) . Return ( query . Restrictions {
AllowedLanguages : [ ] language . Tag { language . English } ,
} , nil )
queries . EXPECT ( ) . ActiveLabelPolicyByOrg ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . LabelPolicy {
ID : policyID ,
Light : query . Theme {
LogoURL : logoURL ,
} ,
} , nil )
queries . EXPECT ( ) . GetNotifyUserByID ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Return ( & query . NotifyUser {
ID : userID ,
ResourceOwner : orgID ,
LastEmail : lastEmail ,
VerifiedEmail : verifiedEmail ,
PreferredLoginName : preferredLoginName ,
LastPhone : lastPhone ,
VerifiedPhone : verifiedPhone ,
2023-10-10 13:20:53 +00:00
} , nil )
queries . EXPECT ( ) . GetDefaultLanguage ( gomock . Any ( ) ) . Return ( language . English )
queries . EXPECT ( ) . CustomTextListByTemplate ( gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) , gomock . Any ( ) ) . Times ( 2 ) . Return ( & query . CustomTexts { } , nil )
}
func cryptoValue ( t * testing . T , ctrl * gomock . Controller , value string ) ( * crypto . MockEncryptionAlgorithm , * crypto . CryptoValue ) {
encAlg := crypto . NewMockEncryptionAlgorithm ( ctrl )
encAlg . EXPECT ( ) . Algorithm ( ) . AnyTimes ( ) . Return ( "enc" )
encAlg . EXPECT ( ) . EncryptionKeyID ( ) . AnyTimes ( ) . Return ( "id" )
encAlg . EXPECT ( ) . DecryptionKeyIDs ( ) . AnyTimes ( ) . Return ( [ ] string { "id" } )
encAlg . EXPECT ( ) . DecryptString ( gomock . Any ( ) , gomock . Any ( ) ) . AnyTimes ( ) . Return ( value , nil )
encAlg . EXPECT ( ) . Encrypt ( gomock . Any ( ) ) . AnyTimes ( ) . Return ( make ( [ ] byte , 0 ) , nil )
code , err := crypto . Encrypt ( nil , encAlg )
assert . NoError ( t , err )
return encAlg , code
}