feat: add sending otp
This commit is contained in:
parent
0fc9e8ccaa
commit
d89be44fe5
30
app/package-lock.json
generated
30
app/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^0.25.0",
|
"@authorizerdev/authorizer-react": "^0.26.0-beta.0",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
|
@ -26,9 +26,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-js": {
|
"node_modules/@authorizerdev/authorizer-js": {
|
||||||
"version": "0.14.0",
|
"version": "0.17.0-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.17.0-beta.1.tgz",
|
||||||
"integrity": "sha512-cpeeFrmG623QPLn+nf+ACHayZYqW8xokIidGikeboBDJtuAAQB50a54/7HwLHriG2FB7WvPuHQ/9LFFX//N1lg==",
|
"integrity": "sha512-jUlFUrs4Ys6LZ5hclPeRt84teygi+bA57d/IpV9GAqOrfifv70jkFeDln4+Bs0mZk74el23Xn+DR9380mqE4Cg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-fetch": "^2.6.1"
|
"node-fetch": "^2.6.1"
|
||||||
},
|
},
|
||||||
|
@ -37,11 +37,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-react": {
|
"node_modules/@authorizerdev/authorizer-react": {
|
||||||
"version": "0.25.0",
|
"version": "0.26.0-beta.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.26.0-beta.0.tgz",
|
||||||
"integrity": "sha512-Dt2rZf+cGCVb8dqcJ/9l8Trx+QeXnTdfhER6r/cq0iOnFC9MqWzQPB3RgrlUoMLHtZvKNDXIk1HvfD5hSX9lhw==",
|
"integrity": "sha512-YfyiGYBmbsp3tLWIxOrOZ/hUTCmdMXVE9SLE8m1xsFsxzJJlUhepp0AMahSbH5EyLj5bchOhOw/rzgpnDZDvMw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^0.14.0",
|
"@authorizerdev/authorizer-js": "^0.17.0-beta.1",
|
||||||
"final-form": "^4.20.2",
|
"final-form": "^4.20.2",
|
||||||
"react-final-form": "^6.5.3",
|
"react-final-form": "^6.5.3",
|
||||||
"styled-components": "^5.3.0"
|
"styled-components": "^5.3.0"
|
||||||
|
@ -852,19 +852,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": {
|
"@authorizerdev/authorizer-js": {
|
||||||
"version": "0.14.0",
|
"version": "0.17.0-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.17.0-beta.1.tgz",
|
||||||
"integrity": "sha512-cpeeFrmG623QPLn+nf+ACHayZYqW8xokIidGikeboBDJtuAAQB50a54/7HwLHriG2FB7WvPuHQ/9LFFX//N1lg==",
|
"integrity": "sha512-jUlFUrs4Ys6LZ5hclPeRt84teygi+bA57d/IpV9GAqOrfifv70jkFeDln4+Bs0mZk74el23Xn+DR9380mqE4Cg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"node-fetch": "^2.6.1"
|
"node-fetch": "^2.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@authorizerdev/authorizer-react": {
|
"@authorizerdev/authorizer-react": {
|
||||||
"version": "0.25.0",
|
"version": "0.26.0-beta.0",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.26.0-beta.0.tgz",
|
||||||
"integrity": "sha512-Dt2rZf+cGCVb8dqcJ/9l8Trx+QeXnTdfhER6r/cq0iOnFC9MqWzQPB3RgrlUoMLHtZvKNDXIk1HvfD5hSX9lhw==",
|
"integrity": "sha512-YfyiGYBmbsp3tLWIxOrOZ/hUTCmdMXVE9SLE8m1xsFsxzJJlUhepp0AMahSbH5EyLj5bchOhOw/rzgpnDZDvMw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@authorizerdev/authorizer-js": "^0.14.0",
|
"@authorizerdev/authorizer-js": "^0.17.0-beta.1",
|
||||||
"final-form": "^4.20.2",
|
"final-form": "^4.20.2",
|
||||||
"react-final-form": "^6.5.3",
|
"react-final-form": "^6.5.3",
|
||||||
"styled-components": "^5.3.0"
|
"styled-components": "^5.3.0"
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^0.25.0",
|
"@authorizerdev/authorizer-react": "^0.26.0-beta.0",
|
||||||
"@types/react": "^17.0.15",
|
"@types/react": "^17.0.15",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
"esbuild": "^0.12.17",
|
"esbuild": "^0.12.17",
|
||||||
|
|
12
dashboard/package-lock.json
generated
12
dashboard/package-lock.json
generated
|
@ -2529,7 +2529,8 @@
|
||||||
"@chakra-ui/css-reset": {
|
"@chakra-ui/css-reset": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@chakra-ui/css-reset/-/css-reset-1.1.1.tgz",
|
||||||
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg=="
|
"integrity": "sha512-+KNNHL4OWqeKia5SL858K3Qbd8WxMij9mWIilBzLD4j2KFrl/+aWFw8syMKth3NmgIibrjsljo+PU3fy2o50dg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@chakra-ui/descendant": {
|
"@chakra-ui/descendant": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
|
@ -3133,7 +3134,8 @@
|
||||||
"@graphql-typed-document-node/core": {
|
"@graphql-typed-document-node/core": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz",
|
||||||
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg=="
|
"integrity": "sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@popperjs/core": {
|
"@popperjs/core": {
|
||||||
"version": "2.11.0",
|
"version": "2.11.0",
|
||||||
|
@ -3843,7 +3845,8 @@
|
||||||
"react-icons": {
|
"react-icons": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.3.1.tgz",
|
||||||
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ=="
|
"integrity": "sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
|
@ -4029,7 +4032,8 @@
|
||||||
"use-callback-ref": {
|
"use-callback-ref": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.5.tgz",
|
||||||
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg=="
|
"integrity": "sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"use-sidecar": {
|
"use-sidecar": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
|
|
118
server/email/otp.go
Normal file
118
server/email/otp.go
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
package email
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendOtpMail to send otp email
|
||||||
|
func SendOtpMail(toEmail, otp string) error {
|
||||||
|
// The receiver needs to be in slice as the receive supports multiple receiver
|
||||||
|
Receiver := []string{toEmail}
|
||||||
|
|
||||||
|
Subject := "OTP for your multi factor authentication"
|
||||||
|
message := `
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||||
|
<meta name="x-apple-disable-message-reformatting">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta content="telephone=no" name="format-detection">
|
||||||
|
<title></title>
|
||||||
|
<!--[if (mso 16)]>
|
||||||
|
<style type="text/css">
|
||||||
|
a {}
|
||||||
|
</style>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if gte mso 9]><style>sup { font-size: 100%% !important; }</style><![endif]-->
|
||||||
|
<!--[if gte mso 9]>
|
||||||
|
<xml>
|
||||||
|
<o:OfficeDocumentSettings>
|
||||||
|
<o:AllowPNG></o:AllowPNG>
|
||||||
|
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||||
|
</o:OfficeDocumentSettings>
|
||||||
|
</xml>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body style="font-family: sans-serif;">
|
||||||
|
<div class="es-wrapper-color">
|
||||||
|
<!--[if gte mso 9]>
|
||||||
|
<v:background xmlns:v="urn:schemas-microsoft-com:vml" fill="t">
|
||||||
|
<v:fill type="tile" color="#ffffff"></v:fill>
|
||||||
|
</v:background>
|
||||||
|
<![endif]-->
|
||||||
|
<table class="es-wrapper" width="100%%" cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="esd-email-paddings" valign="top">
|
||||||
|
<table class="es-content esd-footer-popover" cellspacing="0" cellpadding="0" align="center">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="esd-stripe" align="center">
|
||||||
|
<table class="es-content-body" style="border-left:1px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-bottom:1px solid transparent;padding:20px 0px;" width="600" cellspacing="0" cellpadding="0" bgcolor="#ffffff" align="center">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="esd-structure es-p20t es-p40b es-p40r es-p40l" esd-custom-block-id="8537" align="left">
|
||||||
|
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="esd-container-frame" width="518" align="left">
|
||||||
|
<table width="100%%" cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="esd-block-image es-m-txt-c es-p5b" style="font-size:0;padding:10px" align="center"><a target="_blank" clicktracking="off"><img src="{{.org_logo}}" alt="icon" style="display: block;" title="icon" width="30"></a></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr style="background: rgb(249,250,251);padding: 10px;margin-bottom:10px;border-radius:5px;">
|
||||||
|
<td class="esd-block-text es-m-txt-c es-p15t" align="center" style="padding:10px;padding-bottom:30px;">
|
||||||
|
<p>Hey there 👋</p>
|
||||||
|
<b>{{.otp}}</b> is your one time password (OTP) for accessing {{.org_name}}. Please keep your OTP confidential and it will expire in 1 minute.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div style="position: absolute; left: -9999px; top: -9999px; margin: 0px;"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
data := make(map[string]interface{}, 3)
|
||||||
|
var err error
|
||||||
|
data["org_logo"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationLogo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data["org_name"], err = memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyOrganizationName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data["otp"] = otp
|
||||||
|
message = addEmailTemplate(message, data, "otp.tmpl")
|
||||||
|
// bodyMessage := sender.WriteHTMLEmail(Receiver, Subject, message)
|
||||||
|
|
||||||
|
err = SendMail(Receiver, Subject, message)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("error sending email: ", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
3
server/env/persist_env.go
vendored
3
server/env/persist_env.go
vendored
|
@ -221,9 +221,10 @@ func PersistEnv() error {
|
||||||
// handle derivative cases like disabling email verification & magic login
|
// handle derivative cases like disabling email verification & magic login
|
||||||
// in case SMTP is off but env is set to true
|
// in case SMTP is off but env is set to true
|
||||||
if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" {
|
if storeData[constants.EnvKeySmtpHost] == "" || storeData[constants.EnvKeySmtpUsername] == "" || storeData[constants.EnvKeySmtpPassword] == "" || storeData[constants.EnvKeySenderEmail] == "" && storeData[constants.EnvKeySmtpPort] == "" {
|
||||||
|
storeData[constants.EnvKeyIsEmailServiceEnabled] = false
|
||||||
|
|
||||||
if !storeData[constants.EnvKeyDisableEmailVerification].(bool) {
|
if !storeData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||||
storeData[constants.EnvKeyDisableEmailVerification] = true
|
storeData[constants.EnvKeyDisableEmailVerification] = true
|
||||||
storeData[constants.EnvKeyIsEmailServiceEnabled] = false
|
|
||||||
hasChanged = true
|
hasChanged = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ func InitMemStore() error {
|
||||||
constants.EnvKeyDisableLoginPage: false,
|
constants.EnvKeyDisableLoginPage: false,
|
||||||
constants.EnvKeyDisableSignUp: false,
|
constants.EnvKeyDisableSignUp: false,
|
||||||
constants.EnvKeyDisableStrongPassword: false,
|
constants.EnvKeyDisableStrongPassword: false,
|
||||||
|
constants.EnvKeyIsEmailServiceEnabled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
|
requiredEnvs := RequiredEnvStoreObj.GetRequiredEnv()
|
||||||
|
|
|
@ -160,7 +160,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for key, value := range data {
|
for key, value := range data {
|
||||||
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword {
|
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled {
|
||||||
boolValue, err := strconv.ParseBool(value)
|
boolValue, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
|
|
@ -35,13 +35,13 @@ func InviteMembersResolver(ctx context.Context, params model.InviteMemberInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this feature is only allowed if email server is configured
|
// this feature is only allowed if email server is configured
|
||||||
isEmailVerificationDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification)
|
EnvKeyIsEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error getting email verification disabled: ", err)
|
log.Debug("Error getting email verification disabled: ", err)
|
||||||
isEmailVerificationDisabled = true
|
EnvKeyIsEmailServiceEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if isEmailVerificationDisabled {
|
if !EnvKeyIsEmailServiceEnabled {
|
||||||
log.Debug("Email server is not configured")
|
log.Debug("Email server is not configured")
|
||||||
return nil, errors.New("email sending is disabled")
|
return nil, errors.New("email sending is disabled")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -13,6 +14,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/email"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
@ -99,12 +101,29 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||||
}
|
}
|
||||||
|
|
||||||
if refs.BoolValue(user.IsMultiFactorAuthEnabled) {
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) {
|
||||||
//TODO - send email based on email config
|
isEnvServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
db.Provider.UpsertOTP(ctx, &models.OTP{
|
if err != nil || !isEnvServiceEnabled {
|
||||||
|
log.Debug("Email service not enabled:")
|
||||||
|
return nil, errors.New("email service not enabled")
|
||||||
|
}
|
||||||
|
otp := utils.GenerateOTP()
|
||||||
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
Otp: utils.GenerateOTP(),
|
Otp: otp,
|
||||||
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := email.SendOtpMail(user.Email, otpData.Otp)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to send otp email: ", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return &model.AuthResponse{
|
return &model.AuthResponse{
|
||||||
Message: "Please check the OTP in your inbox",
|
Message: "Please check the OTP in your inbox",
|
||||||
ShouldShowOtpScreen: refs.NewBoolRef(true),
|
ShouldShowOtpScreen: refs.NewBoolRef(true),
|
||||||
|
|
|
@ -2,6 +2,7 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -10,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/db"
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/email"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/refs"
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/authorizerdev/authorizer/server/utils"
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
@ -17,8 +19,6 @@ import (
|
||||||
|
|
||||||
// ResendOTPResolver is a resolver for resend otp mutation
|
// ResendOTPResolver is a resolver for resend otp mutation
|
||||||
func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) {
|
func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*model.Response, error) {
|
||||||
var res *model.Response
|
|
||||||
|
|
||||||
log := log.WithFields(log.Fields{
|
log := log.WithFields(log.Fields{
|
||||||
"email": params.Email,
|
"email": params.Email,
|
||||||
})
|
})
|
||||||
|
@ -26,34 +26,57 @@ func ResendOTPResolver(ctx context.Context, params model.ResendOTPRequest) (*mod
|
||||||
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
user, err := db.Provider.GetUserByEmail(ctx, params.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to get user by email: ", err)
|
log.Debug("Failed to get user by email: ", err)
|
||||||
return res, fmt.Errorf(`user with this email not found`)
|
return nil, fmt.Errorf(`user with this email not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.RevokedTimestamp != nil {
|
if user.RevokedTimestamp != nil {
|
||||||
log.Debug("User access is revoked")
|
log.Debug("User access is revoked")
|
||||||
return res, fmt.Errorf(`user access has been revoked`)
|
return nil, fmt.Errorf(`user access has been revoked`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.EmailVerifiedAt == nil {
|
if user.EmailVerifiedAt == nil {
|
||||||
log.Debug("User email is not verified")
|
log.Debug("User email is not verified")
|
||||||
return res, fmt.Errorf(`email not verified`)
|
return nil, fmt.Errorf(`email not verified`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) {
|
if !refs.BoolValue(user.IsMultiFactorAuthEnabled) {
|
||||||
log.Debug("User multi factor authentication is not enabled")
|
log.Debug("User multi factor authentication is not enabled")
|
||||||
return res, fmt.Errorf(`multi factor authentication not enabled`)
|
return nil, fmt.Errorf(`multi factor authentication not enabled`)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO - send email based on email config
|
// get otp by email
|
||||||
db.Provider.UpsertOTP(ctx, &models.OTP{
|
otpData, err := db.Provider.GetOTPByEmail(ctx, params.Email)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get otp for given email: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if otpData == nil {
|
||||||
|
log.Debug("No otp found for given email: ", params.Email)
|
||||||
|
return &model.Response{
|
||||||
|
Message: "Failed to get for given email",
|
||||||
|
}, errors.New("failed to get otp for given email")
|
||||||
|
}
|
||||||
|
|
||||||
|
otp := utils.GenerateOTP()
|
||||||
|
otpData, err = db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
Otp: utils.GenerateOTP(),
|
Otp: otp,
|
||||||
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
res = &model.Response{
|
log.Debug("Error generating new otp: ", err)
|
||||||
Message: `OTP has been sent. Please check your inbox`,
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
go func() {
|
||||||
|
err := email.SendOtpMail(params.Email, otp)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error sending otp email: ", otp)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return &model.Response{
|
||||||
|
Message: `OTP has been sent. Please check your inbox`,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,6 +234,7 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
||||||
// handle derivative cases like disabling email verification & magic login
|
// handle derivative cases like disabling email verification & magic login
|
||||||
// in case SMTP is off but env is set to true
|
// in case SMTP is off but env is set to true
|
||||||
if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" {
|
if updatedData[constants.EnvKeySmtpHost] == "" || updatedData[constants.EnvKeySmtpUsername] == "" || updatedData[constants.EnvKeySmtpPassword] == "" || updatedData[constants.EnvKeySenderEmail] == "" && updatedData[constants.EnvKeySmtpPort] == "" {
|
||||||
|
updatedData[constants.EnvKeyIsEmailServiceEnabled] = false
|
||||||
if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) {
|
if !updatedData[constants.EnvKeyDisableEmailVerification].(bool) {
|
||||||
updatedData[constants.EnvKeyDisableEmailVerification] = true
|
updatedData[constants.EnvKeyDisableEmailVerification] = true
|
||||||
}
|
}
|
||||||
|
@ -243,6 +244,10 @@ func UpdateEnvResolver(ctx context.Context, params model.UpdateEnvInput) (*model
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if updatedData[constants.EnvKeySmtpHost] != "" || updatedData[constants.EnvKeySmtpUsername] != "" || updatedData[constants.EnvKeySmtpPassword] != "" || updatedData[constants.EnvKeySenderEmail] != "" && updatedData[constants.EnvKeySmtpPort] != "" {
|
||||||
|
updatedData[constants.EnvKeyIsEmailServiceEnabled] = true
|
||||||
|
}
|
||||||
|
|
||||||
// check the roles change
|
// check the roles change
|
||||||
if len(params.Roles) > 0 {
|
if len(params.Roles) > 0 {
|
||||||
if len(params.DefaultRoles) > 0 {
|
if len(params.DefaultRoles) > 0 {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -96,6 +97,13 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
|
|
||||||
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
||||||
|
if refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
|
isEnvServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
|
if err != nil || !isEnvServiceEnabled {
|
||||||
|
log.Debug("Email service not enabled:")
|
||||||
|
return nil, errors.New("email service not enabled, so cannot enable multi factor authentication")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isPasswordChanging := false
|
isPasswordChanging := false
|
||||||
|
|
|
@ -2,6 +2,7 @@ package resolvers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -91,6 +92,13 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
|
|
||||||
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
if params.IsMultiFactorAuthEnabled != nil && refs.BoolValue(user.IsMultiFactorAuthEnabled) != refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
||||||
|
if refs.BoolValue(params.IsMultiFactorAuthEnabled) {
|
||||||
|
isEnvServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
|
if err != nil || !isEnvServiceEnabled {
|
||||||
|
log.Debug("Email service not enabled:")
|
||||||
|
return nil, errors.New("email service not enabled, so cannot enable multi factor authentication")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.EmailVerified != nil {
|
if params.EmailVerified != nil {
|
||||||
|
|
|
@ -52,8 +52,7 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
|
|
||||||
isSignUp := user.EmailVerifiedAt == nil
|
isSignUp := user.EmailVerifiedAt == nil
|
||||||
|
|
||||||
// TODO - Add Login method in DB
|
// TODO - Add Login method in DB when we introduce OTP for social media login
|
||||||
|
|
||||||
loginMethod := constants.AuthRecipeMethodBasicAuth
|
loginMethod := constants.AuthRecipeMethodBasicAuth
|
||||||
|
|
||||||
roles := strings.Split(user.Roles, ",")
|
roles := strings.Split(user.Roles, ",")
|
||||||
|
@ -65,11 +64,7 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err = db.Provider.DeleteOTP(gc, otp)
|
db.Provider.DeleteOTP(gc, otp)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Failed to delete otp: ", err)
|
|
||||||
}
|
|
||||||
if isSignUp {
|
if isSignUp {
|
||||||
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)
|
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, loginMethod, user)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO renamae GinContextKey -> GinContext
|
// TODO re-name GinContextKey -> GinContext
|
||||||
|
|
||||||
// GinContext to get gin context from context
|
// GinContext to get gin context from context
|
||||||
func GinContextFromContext(ctx context.Context) (*gin.Context, error) {
|
func GinContextFromContext(ctx context.Context) (*gin.Context, error) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user