2021-07-17 16:29:50 +00:00
package resolvers
import (
"context"
2021-07-18 03:55:20 +00:00
"fmt"
2021-07-17 16:29:50 +00:00
"log"
"strings"
"time"
2021-07-28 10:13:08 +00:00
"github.com/authorizerdev/authorizer/server/constants"
2022-01-22 19:54:41 +00:00
"github.com/authorizerdev/authorizer/server/cookie"
2022-02-28 15:56:49 +00:00
"github.com/authorizerdev/authorizer/server/crypto"
2021-07-23 16:27:44 +00:00
"github.com/authorizerdev/authorizer/server/db"
2022-01-21 08:04:04 +00:00
"github.com/authorizerdev/authorizer/server/db/models"
2022-01-17 06:02:13 +00:00
"github.com/authorizerdev/authorizer/server/email"
"github.com/authorizerdev/authorizer/server/envstore"
2021-07-23 16:27:44 +00:00
"github.com/authorizerdev/authorizer/server/graph/model"
2022-01-22 19:54:41 +00:00
"github.com/authorizerdev/authorizer/server/sessionstore"
"github.com/authorizerdev/authorizer/server/token"
2021-07-23 16:27:44 +00:00
"github.com/authorizerdev/authorizer/server/utils"
2021-07-17 16:29:50 +00:00
)
2022-01-17 06:02:13 +00:00
// SignupResolver is a resolver for signup mutation
func SignupResolver ( ctx context . Context , params model . SignUpInput ) ( * model . AuthResponse , error ) {
2021-07-28 10:13:08 +00:00
gc , err := utils . GinContextFromContext ( ctx )
var res * model . AuthResponse
if err != nil {
return res , err
}
2022-03-16 17:19:18 +00:00
if envstore . EnvStoreObj . GetBoolStoreEnvVariable ( constants . EnvKeyDisableSignUp ) {
return res , fmt . Errorf ( ` signup is disabled for this instance ` )
}
2022-02-28 02:25:01 +00:00
if envstore . EnvStoreObj . GetBoolStoreEnvVariable ( constants . EnvKeyDisableBasicAuthentication ) {
2021-07-28 10:13:08 +00:00
return res , fmt . Errorf ( ` basic authentication is disabled for this instance ` )
}
2022-03-16 17:19:18 +00:00
2021-07-20 22:04:03 +00:00
if params . ConfirmPassword != params . Password {
2021-12-20 17:51:27 +00:00
return res , fmt . Errorf ( ` password and confirm password does not match ` )
2021-07-17 16:29:50 +00:00
}
2022-03-17 10:05:07 +00:00
if ! utils . IsValidPassword ( params . Password ) {
return res , fmt . Errorf ( ` password is not valid. It needs to be at least 6 characters long and contain at least one number, one uppercase letter, one lowercase letter and one special character ` )
}
2021-07-17 16:29:50 +00:00
params . Email = strings . ToLower ( params . Email )
if ! utils . IsValidEmail ( params . Email ) {
2021-07-18 03:55:20 +00:00
return res , fmt . Errorf ( ` invalid email address ` )
2021-07-17 16:29:50 +00:00
}
// find user with email
2022-01-21 08:04:04 +00:00
existingUser , err := db . Provider . GetUserByEmail ( params . Email )
2021-07-17 16:29:50 +00:00
if err != nil {
2021-12-17 15:55:07 +00:00
log . Println ( "user with email " + params . Email + " not found" )
2021-07-17 16:29:50 +00:00
}
2021-12-22 10:08:51 +00:00
if existingUser . EmailVerifiedAt != nil {
2021-07-17 16:29:50 +00:00
// email is verified
2021-12-20 17:51:27 +00:00
return res , fmt . Errorf ( ` %s has already signed up ` , params . Email )
2021-12-22 10:08:51 +00:00
} else if existingUser . ID != "" && existingUser . EmailVerifiedAt == nil {
2021-12-20 17:51:27 +00:00
return res , fmt . Errorf ( "%s has already signed up. please complete the email verification process or reset the password" , params . Email )
2021-07-17 16:29:50 +00:00
}
2021-12-20 17:51:27 +00:00
2021-12-24 13:12:32 +00:00
inputRoles := [ ] string { }
if len ( params . Roles ) > 0 {
// check if roles exists
2022-02-28 02:25:01 +00:00
if ! utils . IsValidRoles ( envstore . EnvStoreObj . GetSliceStoreEnvVariable ( constants . EnvKeyRoles ) , params . Roles ) {
2021-12-24 13:12:32 +00:00
return res , fmt . Errorf ( ` invalid roles ` )
} else {
inputRoles = params . Roles
}
} else {
2022-02-28 02:25:01 +00:00
inputRoles = envstore . EnvStoreObj . GetSliceStoreEnvVariable ( constants . EnvKeyDefaultRoles )
2021-12-24 13:12:32 +00:00
}
2022-01-21 08:04:04 +00:00
user := models . User {
2021-07-17 17:09:50 +00:00
Email : params . Email ,
2021-07-17 16:29:50 +00:00
}
2021-09-20 05:06:26 +00:00
user . Roles = strings . Join ( inputRoles , "," )
2022-02-28 15:56:49 +00:00
password , _ := crypto . EncryptPassword ( params . Password )
2021-12-22 10:01:45 +00:00
user . Password = & password
2021-07-17 17:09:50 +00:00
2021-12-22 05:21:12 +00:00
if params . GivenName != nil {
2021-12-22 10:01:45 +00:00
user . GivenName = params . GivenName
2021-07-17 16:29:50 +00:00
}
2021-12-22 05:21:12 +00:00
if params . FamilyName != nil {
2021-12-22 10:01:45 +00:00
user . FamilyName = params . FamilyName
2021-07-17 16:29:50 +00:00
}
2021-12-22 05:21:12 +00:00
if params . MiddleName != nil {
2021-12-22 10:01:45 +00:00
user . MiddleName = params . MiddleName
2021-12-22 05:21:12 +00:00
}
if params . Nickname != nil {
2021-12-22 10:01:45 +00:00
user . Nickname = params . Nickname
2021-12-22 05:21:12 +00:00
}
if params . Gender != nil {
2021-12-22 10:01:45 +00:00
user . Gender = params . Gender
2021-12-22 05:21:12 +00:00
}
if params . Birthdate != nil {
2021-12-22 10:01:45 +00:00
user . Birthdate = params . Birthdate
2021-12-22 05:21:12 +00:00
}
if params . PhoneNumber != nil {
2021-12-22 10:01:45 +00:00
user . PhoneNumber = params . PhoneNumber
2021-12-22 05:21:12 +00:00
}
if params . Picture != nil {
2021-12-22 10:01:45 +00:00
user . Picture = params . Picture
2021-12-22 05:21:12 +00:00
}
2022-01-17 06:02:13 +00:00
user . SignupMethods = constants . SignupMethodBasicAuth
2022-02-28 02:25:01 +00:00
if envstore . EnvStoreObj . GetBoolStoreEnvVariable ( constants . EnvKeyDisableEmailVerification ) {
2021-12-22 10:08:51 +00:00
now := time . Now ( ) . Unix ( )
user . EmailVerifiedAt = & now
2021-07-28 10:13:08 +00:00
}
2022-01-21 08:04:04 +00:00
user , err = db . Provider . AddUser ( user )
2021-07-17 16:29:50 +00:00
if err != nil {
return res , err
}
2021-10-13 16:41:41 +00:00
roles := strings . Split ( user . Roles , "," )
2022-01-22 19:54:41 +00:00
userToReturn := user . AsAPIUser ( )
2021-07-28 10:13:08 +00:00
2022-01-31 06:05:24 +00:00
hostname := utils . GetHost ( gc )
2022-02-28 02:25:01 +00:00
if ! envstore . EnvStoreObj . GetBoolStoreEnvVariable ( constants . EnvKeyDisableEmailVerification ) {
2021-07-28 10:13:08 +00:00
// insert verification request
2022-03-08 07:06:26 +00:00
_ , nonceHash , err := utils . GenerateNonce ( )
2022-03-02 12:12:31 +00:00
if err != nil {
return res , err
}
2022-01-17 06:02:13 +00:00
verificationType := constants . VerificationTypeBasicAuthSignup
2022-03-15 03:23:48 +00:00
redirectURL := utils . GetAppURL ( gc )
2022-03-16 16:22:45 +00:00
if params . RedirectURI != nil {
redirectURL = * params . RedirectURI
}
2022-03-08 07:06:26 +00:00
verificationToken , err := token . CreateVerificationToken ( params . Email , verificationType , hostname , nonceHash , redirectURL )
2021-07-28 10:13:08 +00:00
if err != nil {
2022-03-02 12:12:31 +00:00
return res , err
2021-07-28 10:13:08 +00:00
}
2022-01-21 08:04:04 +00:00
db . Provider . AddVerificationRequest ( models . VerificationRequest {
2022-03-08 07:06:26 +00:00
Token : verificationToken ,
Identifier : verificationType ,
ExpiresAt : time . Now ( ) . Add ( time . Minute * 30 ) . Unix ( ) ,
Email : params . Email ,
Nonce : nonceHash ,
RedirectURI : redirectURL ,
2021-07-28 10:13:08 +00:00
} )
// exec it as go routin so that we can reduce the api latency
2022-03-02 12:12:31 +00:00
go email . SendVerificationMail ( params . Email , verificationToken , hostname )
2021-07-28 10:13:08 +00:00
res = & model . AuthResponse {
Message : ` Verification email has been sent. Please check your inbox ` ,
User : userToReturn ,
}
} else {
2022-03-02 12:12:31 +00:00
scope := [ ] string { "openid" , "email" , "profile" }
2022-03-09 06:23:34 +00:00
if params . Scope != nil && len ( scope ) > 0 {
scope = params . Scope
}
2021-07-28 10:13:08 +00:00
2022-03-02 12:12:31 +00:00
authToken , err := token . CreateAuthToken ( gc , user , roles , scope )
2022-01-22 19:54:41 +00:00
if err != nil {
return res , err
}
2022-03-02 12:12:31 +00:00
sessionstore . SetState ( authToken . FingerPrintHash , authToken . FingerPrint + "@" + user . ID )
cookie . SetSession ( gc , authToken . FingerPrintHash )
go utils . SaveSessionInDB ( gc , user . ID )
expiresIn := int64 ( 1800 )
2022-01-22 19:54:41 +00:00
2021-07-28 10:13:08 +00:00
res = & model . AuthResponse {
2021-12-22 05:21:12 +00:00
Message : ` Signed up successfully. ` ,
2022-01-22 19:54:41 +00:00
AccessToken : & authToken . AccessToken . Token ,
2022-03-02 12:12:31 +00:00
ExpiresIn : & expiresIn ,
2021-12-22 05:21:12 +00:00
User : userToReturn ,
2021-07-28 10:13:08 +00:00
}
2021-07-17 16:29:50 +00:00
}
return res , nil
}