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