refactor: full refactor of user management
This commit is contained in:
parent
bbc37c0202
commit
9d028897bd
10 changed files with 328 additions and 225 deletions
|
|
@ -29,7 +29,7 @@ function authenticateUser(username, password) {
|
|||
|
||||
const getUserData = context => {
|
||||
const lidCookie = context.req.cookies && context.req.cookies.lid
|
||||
if (!lidCookie) throw new AuthenticationError()
|
||||
if (!lidCookie) return
|
||||
|
||||
const user = context.req.session.user
|
||||
return user
|
||||
|
|
@ -145,26 +145,78 @@ const setup2FA = (username, password, rememberMe, secret, codeConfirmation, cont
|
|||
context.req.session.user = finalUser
|
||||
if (rememberMe) context.req.session.cookie.maxAge = REMEMBER_ME_AGE
|
||||
|
||||
return true
|
||||
return users.save2FASecret(user.id, secret)
|
||||
})
|
||||
.then(() => true)
|
||||
}
|
||||
|
||||
const createResetPasswordToken = userID => {
|
||||
return users.getUserById(userID)
|
||||
.then(user => {
|
||||
if (!user) throw new authErrors.InvalidCredentialsError()
|
||||
return users.createAuthToken(user.id, 'reset_password')
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
const changeUserRole = (code, id, newRole, context) => {
|
||||
const action = (id, newRole) => users.changeUserRole(id, newRole)
|
||||
|
||||
if (!code) {
|
||||
return action(id, newRole)
|
||||
}
|
||||
|
||||
return confirm2FA(code, context)
|
||||
.then(() => action(id, newRole))
|
||||
}
|
||||
|
||||
const createReset2FAToken = userID => {
|
||||
return users.getUserById(userID)
|
||||
.then(user => {
|
||||
if (!user) throw new authErrors.InvalidCredentialsError()
|
||||
return users.createAuthToken(user.id, 'reset_twofa')
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
const enableUser = (code, id, context) => {
|
||||
const action = id => users.enableUser(id)
|
||||
|
||||
if (!code) {
|
||||
return action(id)
|
||||
}
|
||||
|
||||
return confirm2FA(code, context)
|
||||
.then(() => action(id))
|
||||
}
|
||||
|
||||
const disableUser = (code, id, context) => {
|
||||
const action = id => users.disableUser(id)
|
||||
|
||||
if (!code) {
|
||||
return action(id)
|
||||
}
|
||||
|
||||
return confirm2FA(code, context)
|
||||
.then(() => action(id))
|
||||
}
|
||||
|
||||
const createResetPasswordToken = (code, userID, context) => {
|
||||
const action = userID => {
|
||||
return users.getUserById(userID)
|
||||
.then(user => {
|
||||
if (!user) throw new authErrors.InvalidCredentialsError()
|
||||
return users.createAuthToken(user.id, 'reset_password')
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
return action(userID)
|
||||
}
|
||||
|
||||
return confirm2FA(code, context)
|
||||
.then(() => action(userID))
|
||||
}
|
||||
|
||||
const createReset2FAToken = (code, userID, context) => {
|
||||
const action = userID => {
|
||||
return users.getUserById(userID)
|
||||
.then(user => {
|
||||
if (!user) throw new authErrors.InvalidCredentialsError()
|
||||
return users.createAuthToken(user.id, 'reset_twofa')
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
return action(userID)
|
||||
}
|
||||
|
||||
return confirm2FA(code, context)
|
||||
.then(() => action(userID))
|
||||
}
|
||||
|
||||
const createRegisterToken = (username, role) => {
|
||||
|
|
@ -220,6 +272,9 @@ module.exports = {
|
|||
login,
|
||||
input2FA,
|
||||
setup2FA,
|
||||
changeUserRole,
|
||||
enableUser,
|
||||
disableUser,
|
||||
createResetPasswordToken,
|
||||
createReset2FAToken,
|
||||
createRegisterToken,
|
||||
|
|
|
|||
|
|
@ -15,16 +15,16 @@ const resolver = {
|
|||
validateReset2FALink: (...[, { token }]) => authentication.validateReset2FALink(token)
|
||||
},
|
||||
Mutation: {
|
||||
enableUser: (...[, { id }]) => users.enableUser(id),
|
||||
disableUser: (...[, { id }]) => users.disableUser(id),
|
||||
enableUser: (...[, { confirmationCode, id }, context]) => authentication.enableUser(confirmationCode, id, context),
|
||||
disableUser: (...[, { confirmationCode, id }, context]) => authentication.disableUser(confirmationCode, id, context),
|
||||
deleteSession: (...[, { sid }, context]) => authentication.deleteSession(sid, context),
|
||||
deleteUserSessions: (...[, { username }]) => sessionManager.deleteSessionsByUsername(username),
|
||||
changeUserRole: (...[, { id, newRole }]) => users.changeUserRole(id, newRole),
|
||||
changeUserRole: (...[, { confirmationCode, id, newRole }, context]) => authentication.changeUserRole(confirmationCode, id, newRole, context),
|
||||
login: (...[, { username, password }]) => authentication.login(username, password),
|
||||
input2FA: (...[, { username, password, rememberMe, code }, context]) => authentication.input2FA(username, password, rememberMe, code, context),
|
||||
setup2FA: (...[, { username, password, rememberMe, secret, codeConfirmation }, context]) => authentication.setup2FA(username, password, rememberMe, secret, codeConfirmation, context),
|
||||
createResetPasswordToken: (...[, { userID }]) => authentication.createResetPasswordToken(userID),
|
||||
createReset2FAToken: (...[, { userID }]) => authentication.createReset2FAToken(userID),
|
||||
createResetPasswordToken: (...[, { confirmationCode, userID }, context]) => authentication.createResetPasswordToken(confirmationCode, userID, context),
|
||||
createReset2FAToken: (...[, { confirmationCode, userID }, context]) => authentication.createReset2FAToken(confirmationCode, userID, context),
|
||||
createRegisterToken: (...[, { username, role }]) => authentication.createRegisterToken(username, role),
|
||||
register: (...[, { token, username, password, role }]) => authentication.register(token, username, password, role),
|
||||
resetPassword: (...[, { token, userID, newPassword }, context]) => authentication.resetPassword(token, userID, newPassword, context),
|
||||
|
|
|
|||
|
|
@ -57,17 +57,17 @@ const typeDef = `
|
|||
}
|
||||
|
||||
type Mutation {
|
||||
enableUser(id: ID!): User @auth(requires: [SUPERUSER])
|
||||
disableUser(id: ID!): User @auth(requires: [SUPERUSER])
|
||||
enableUser(confirmationCode: String, id: ID!): User @auth(requires: [SUPERUSER])
|
||||
disableUser(confirmationCode: String, id: ID!): User @auth(requires: [SUPERUSER])
|
||||
deleteSession(sid: String!): UserSession @auth(requires: [SUPERUSER])
|
||||
deleteUserSessions(username: String!): [UserSession] @auth(requires: [SUPERUSER])
|
||||
changeUserRole(id: ID!, newRole: String!): User @auth(requires: [SUPERUSER])
|
||||
changeUserRole(confirmationCode: String, id: ID!, newRole: String!): User @auth(requires: [SUPERUSER])
|
||||
toggleUserEnable(id: ID!): User @auth(requires: [SUPERUSER])
|
||||
login(username: String!, password: String!): String
|
||||
input2FA(username: String!, password: String!, code: String!, rememberMe: Boolean!): Boolean
|
||||
setup2FA(username: String!, password: String!, rememberMe: Boolean!, secret: String!, codeConfirmation: String!): Boolean
|
||||
createResetPasswordToken(userID: ID!): ResetToken @auth(requires: [SUPERUSER])
|
||||
createReset2FAToken(userID: ID!): ResetToken @auth(requires: [SUPERUSER])
|
||||
createResetPasswordToken(confirmationCode: String, userID: ID!): ResetToken @auth(requires: [SUPERUSER])
|
||||
createReset2FAToken(confirmationCode: String, userID: ID!): ResetToken @auth(requires: [SUPERUSER])
|
||||
createRegisterToken(username: String!, role: String!): RegistrationToken @auth(requires: [SUPERUSER])
|
||||
register(token: String!, username: String!, password: String!, role: String!): Boolean
|
||||
resetPassword(token: String!, userID: ID!, newPassword: String!): Boolean
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { CodeInput } from 'src/components/inputs/base'
|
|||
import { H2, P } from 'src/components/typography'
|
||||
|
||||
import styles from './Login.styles'
|
||||
import { STATES } from './states'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
|
|
@ -47,7 +48,12 @@ const Input2FAState = ({ state, dispatch }) => {
|
|||
const [invalidToken, setInvalidToken] = useState(false)
|
||||
|
||||
const handle2FAChange = value => {
|
||||
dispatch({ type: 'twoFAField', payload: value })
|
||||
dispatch({
|
||||
type: STATES.INPUT_2FA,
|
||||
payload: {
|
||||
twoFAField: value
|
||||
}
|
||||
})
|
||||
setInvalidToken(false)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useQuery, useMutation } from '@apollo/react-hooks'
|
||||
import { useQuery } from '@apollo/react-hooks'
|
||||
import { makeStyles, Box, Chip } from '@material-ui/core'
|
||||
import gql from 'graphql-tag'
|
||||
import * as R from 'ramda'
|
||||
|
|
@ -14,7 +14,6 @@ import styles from './UserManagement.styles'
|
|||
import ChangeRoleModal from './modals/ChangeRoleModal'
|
||||
import CreateUserModal from './modals/CreateUserModal'
|
||||
import EnableUserModal from './modals/EnableUserModal'
|
||||
import Input2FAModal from './modals/Input2FAModal'
|
||||
import Reset2FAModal from './modals/Reset2FAModal'
|
||||
import ResetPasswordModal from './modals/ResetPasswordModal'
|
||||
|
||||
|
|
@ -34,98 +33,21 @@ const GET_USERS = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const CHANGE_USER_ROLE = gql`
|
||||
mutation changeUserRole($id: ID!, $newRole: String!) {
|
||||
changeUserRole(id: $id, newRole: $newRole) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const ENABLE_USER = gql`
|
||||
mutation enableUser($id: ID!) {
|
||||
enableUser(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const DISABLE_USER = gql`
|
||||
mutation disableUser($id: ID!) {
|
||||
disableUser(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const CREATE_RESET_PASSWORD_TOKEN = gql`
|
||||
mutation createResetPasswordToken($userID: ID!) {
|
||||
createResetPasswordToken(userID: $userID) {
|
||||
token
|
||||
user_id
|
||||
expire
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const CREATE_RESET_2FA_TOKEN = gql`
|
||||
mutation createReset2FAToken($userID: ID!) {
|
||||
createReset2FAToken(userID: $userID) {
|
||||
token
|
||||
user_id
|
||||
expire
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const Users = () => {
|
||||
const classes = useStyles()
|
||||
|
||||
const { userData } = useContext(AppContext)
|
||||
|
||||
const { data: userResponse } = useQuery(GET_USERS)
|
||||
|
||||
const [changeUserRole] = useMutation(CHANGE_USER_ROLE, {
|
||||
refetchQueries: () => ['users']
|
||||
})
|
||||
|
||||
const [enableUser] = useMutation(ENABLE_USER, {
|
||||
refetchQueries: () => ['users']
|
||||
})
|
||||
|
||||
const [disableUser] = useMutation(DISABLE_USER, {
|
||||
refetchQueries: () => ['users']
|
||||
})
|
||||
|
||||
const [createResetPasswordToken] = useMutation(CREATE_RESET_PASSWORD_TOKEN, {
|
||||
onCompleted: ({ createResetPasswordToken: token }) => {
|
||||
setResetPasswordUrl(
|
||||
`https://localhost:3001/resetpassword?t=${token.token}`
|
||||
)
|
||||
toggleResetPasswordModal()
|
||||
}
|
||||
})
|
||||
|
||||
const [createReset2FAToken] = useMutation(CREATE_RESET_2FA_TOKEN, {
|
||||
onCompleted: ({ createReset2FAToken: token }) => {
|
||||
setReset2FAUrl(`https://localhost:3001/reset2fa?t=${token.token}`)
|
||||
toggleReset2FAModal()
|
||||
}
|
||||
})
|
||||
|
||||
const [userInfo, setUserInfo] = useState(null)
|
||||
|
||||
const [showCreateUserModal, setShowCreateUserModal] = useState(false)
|
||||
const toggleCreateUserModal = () =>
|
||||
setShowCreateUserModal(!showCreateUserModal)
|
||||
|
||||
const [showResetPasswordModal, setShowResetPasswordModal] = useState(false)
|
||||
const [resetPasswordUrl, setResetPasswordUrl] = useState('')
|
||||
const toggleResetPasswordModal = () =>
|
||||
setShowResetPasswordModal(!showResetPasswordModal)
|
||||
|
||||
const [showReset2FAModal, setShowReset2FAModal] = useState(false)
|
||||
const [reset2FAUrl, setReset2FAUrl] = useState('')
|
||||
const toggleReset2FAModal = () => setShowReset2FAModal(!showReset2FAModal)
|
||||
|
||||
const [showRoleModal, setShowRoleModal] = useState(false)
|
||||
|
|
@ -135,11 +57,7 @@ const Users = () => {
|
|||
const toggleEnableUserModal = () =>
|
||||
setShowEnableUserModal(!showEnableUserModal)
|
||||
|
||||
const [showInputConfirmModal, setShowInputConfirmModal] = useState(false)
|
||||
const toggleInputConfirmModal = () =>
|
||||
setShowInputConfirmModal(!showInputConfirmModal)
|
||||
|
||||
const [action, setAction] = useState(null)
|
||||
const [userInfo, setUserInfo] = useState(null)
|
||||
|
||||
const elements = [
|
||||
{
|
||||
|
|
@ -212,22 +130,7 @@ const Users = () => {
|
|||
className={classes.actionChip}
|
||||
onClick={() => {
|
||||
setUserInfo(u)
|
||||
if (u.role === 'superuser') {
|
||||
setAction(() =>
|
||||
createResetPasswordToken.bind(null, {
|
||||
variables: {
|
||||
userID: u.id
|
||||
}
|
||||
})
|
||||
)
|
||||
toggleInputConfirmModal()
|
||||
} else {
|
||||
createResetPasswordToken({
|
||||
variables: {
|
||||
userID: u.id
|
||||
}
|
||||
})
|
||||
}
|
||||
toggleResetPasswordModal()
|
||||
}}
|
||||
/>
|
||||
<Chip
|
||||
|
|
@ -236,22 +139,7 @@ const Users = () => {
|
|||
className={classes.actionChip}
|
||||
onClick={() => {
|
||||
setUserInfo(u)
|
||||
if (u.role === 'superuser') {
|
||||
setAction(() => () =>
|
||||
createReset2FAToken({
|
||||
variables: {
|
||||
userID: u.id
|
||||
}
|
||||
})
|
||||
)
|
||||
toggleInputConfirmModal()
|
||||
} else {
|
||||
createReset2FAToken({
|
||||
variables: {
|
||||
userID: u.id
|
||||
}
|
||||
})
|
||||
}
|
||||
toggleReset2FAModal()
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
|
@ -298,35 +186,26 @@ const Users = () => {
|
|||
<ResetPasswordModal
|
||||
showModal={showResetPasswordModal}
|
||||
toggleModal={toggleResetPasswordModal}
|
||||
resetPasswordURL={resetPasswordUrl}
|
||||
user={userInfo}
|
||||
requiresConfirmation={userInfo?.role === 'superuser'}
|
||||
/>
|
||||
<Reset2FAModal
|
||||
showModal={showReset2FAModal}
|
||||
toggleModal={toggleReset2FAModal}
|
||||
reset2FAURL={reset2FAUrl}
|
||||
user={userInfo}
|
||||
requiresConfirmation={userInfo?.role === 'superuser'}
|
||||
/>
|
||||
<ChangeRoleModal
|
||||
showModal={showRoleModal}
|
||||
toggleModal={toggleRoleModal}
|
||||
user={userInfo}
|
||||
confirm={changeUserRole}
|
||||
inputConfirmToggle={toggleInputConfirmModal}
|
||||
setAction={setAction}
|
||||
requiresConfirmation={userInfo?.role === 'superuser'}
|
||||
/>
|
||||
<EnableUserModal
|
||||
showModal={showEnableUserModal}
|
||||
toggleModal={toggleEnableUserModal}
|
||||
user={userInfo}
|
||||
confirm={userInfo?.enabled ? disableUser : enableUser}
|
||||
inputConfirmToggle={toggleInputConfirmModal}
|
||||
setAction={setAction}
|
||||
/>
|
||||
<Input2FAModal
|
||||
showModal={showInputConfirmModal}
|
||||
toggleModal={toggleInputConfirmModal}
|
||||
action={action}
|
||||
requiresConfirmation={userInfo?.role === 'superuser'}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import React from 'react'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
import Modal from 'src/components/Modal'
|
||||
import { Button } from 'src/components/buttons'
|
||||
|
|
@ -7,24 +9,65 @@ import { Info2, P } from 'src/components/typography'
|
|||
|
||||
import styles from '../UserManagement.styles'
|
||||
|
||||
import Input2FAModal from './Input2FAModal'
|
||||
|
||||
const CHANGE_USER_ROLE = gql`
|
||||
mutation changeUserRole(
|
||||
$confirmationCode: String
|
||||
$id: ID!
|
||||
$newRole: String!
|
||||
) {
|
||||
changeUserRole(
|
||||
confirmationCode: $confirmationCode
|
||||
id: $id
|
||||
newRole: $newRole
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const ChangeRoleModal = ({
|
||||
showModal,
|
||||
toggleModal,
|
||||
user,
|
||||
confirm,
|
||||
inputConfirmToggle,
|
||||
setAction
|
||||
requiresConfirmation
|
||||
}) => {
|
||||
const classes = useStyles()
|
||||
|
||||
const [changeUserRole] = useMutation(CHANGE_USER_ROLE, {
|
||||
refetchQueries: () => ['users']
|
||||
})
|
||||
|
||||
const [confirmation, setConfirmation] = useState(null)
|
||||
|
||||
const submit = () => {
|
||||
changeUserRole({
|
||||
variables: {
|
||||
confirmationCode: confirmation,
|
||||
id: user.id,
|
||||
newRole: user.role === 'superuser' ? 'user' : 'superuser'
|
||||
}
|
||||
})
|
||||
handleClose()
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setConfirmation(null)
|
||||
toggleModal()
|
||||
}
|
||||
|
||||
return (
|
||||
showModal && (
|
||||
(showModal && requiresConfirmation && !confirmation && (
|
||||
<Input2FAModal
|
||||
showModal={showModal}
|
||||
handleClose={handleClose}
|
||||
setConfirmation={setConfirmation}
|
||||
/>
|
||||
)) ||
|
||||
(showModal && (
|
||||
<Modal
|
||||
closeOnBackdropClick={true}
|
||||
width={450}
|
||||
|
|
@ -40,25 +83,12 @@ const ChangeRoleModal = ({
|
|||
</P>
|
||||
<P className={classes.info}>Do you wish to proceed?</P>
|
||||
<div className={classes.footer}>
|
||||
<Button
|
||||
className={classes.submit}
|
||||
onClick={() => {
|
||||
setAction(() =>
|
||||
confirm.bind(null, {
|
||||
variables: {
|
||||
id: user.id,
|
||||
newRole: user.role === 'superuser' ? 'user' : 'superuser'
|
||||
}
|
||||
})
|
||||
)
|
||||
inputConfirmToggle()
|
||||
handleClose()
|
||||
}}>
|
||||
<Button className={classes.submit} onClick={() => submit()}>
|
||||
Confirm
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import React from 'react'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
import Modal from 'src/components/Modal'
|
||||
import { Button } from 'src/components/buttons'
|
||||
|
|
@ -7,24 +9,75 @@ import { Info2, P } from 'src/components/typography'
|
|||
|
||||
import styles from '../UserManagement.styles'
|
||||
|
||||
import Input2FAModal from './Input2FAModal'
|
||||
|
||||
const ENABLE_USER = gql`
|
||||
mutation enableUser($confirmationCode: String, $id: ID!) {
|
||||
enableUser(confirmationCode: $confirmationCode, id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const DISABLE_USER = gql`
|
||||
mutation disableUser($confirmationCode: String, $id: ID!) {
|
||||
disableUser(confirmationCode: $confirmationCode, id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const EnableUserModal = ({
|
||||
showModal,
|
||||
toggleModal,
|
||||
user,
|
||||
confirm,
|
||||
inputConfirmToggle,
|
||||
setAction
|
||||
requiresConfirmation
|
||||
}) => {
|
||||
const classes = useStyles()
|
||||
|
||||
const [enableUser] = useMutation(ENABLE_USER, {
|
||||
refetchQueries: () => ['users']
|
||||
})
|
||||
|
||||
const [disableUser] = useMutation(DISABLE_USER, {
|
||||
refetchQueries: () => ['users']
|
||||
})
|
||||
|
||||
const [confirmation, setConfirmation] = useState(null)
|
||||
|
||||
const submit = () => {
|
||||
user?.enabled
|
||||
? disableUser({
|
||||
variables: {
|
||||
confirmationCode: confirmation,
|
||||
id: user.id
|
||||
}
|
||||
})
|
||||
: enableUser({
|
||||
variables: {
|
||||
confirmationCode: confirmation,
|
||||
id: user.id
|
||||
}
|
||||
})
|
||||
handleClose()
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setConfirmation(null)
|
||||
toggleModal()
|
||||
}
|
||||
|
||||
return (
|
||||
showModal && (
|
||||
(showModal && requiresConfirmation && !confirmation && (
|
||||
<Input2FAModal
|
||||
showModal={showModal}
|
||||
handleClose={handleClose}
|
||||
setConfirmation={setConfirmation}
|
||||
/>
|
||||
)) ||
|
||||
(showModal && (
|
||||
<Modal
|
||||
closeOnBackdropClick={true}
|
||||
width={450}
|
||||
|
|
@ -58,32 +111,12 @@ const EnableUserModal = ({
|
|||
</>
|
||||
)}
|
||||
<div className={classes.footer}>
|
||||
<Button
|
||||
className={classes.submit}
|
||||
onClick={() => {
|
||||
if (user.role === 'superuser') {
|
||||
setAction(() =>
|
||||
confirm.bind(null, {
|
||||
variables: {
|
||||
id: user.id
|
||||
}
|
||||
})
|
||||
)
|
||||
inputConfirmToggle()
|
||||
} else {
|
||||
confirm({
|
||||
variables: {
|
||||
id: user.id
|
||||
}
|
||||
})
|
||||
}
|
||||
handleClose()
|
||||
}}>
|
||||
<Button className={classes.submit} onClick={() => submit()}>
|
||||
Confirm
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const CONFIRM_2FA = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const Input2FAModal = ({ showModal, toggleModal, action, vars }) => {
|
||||
const Input2FAModal = ({ showModal, handleClose, setConfirmation }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
const [twoFACode, setTwoFACode] = useState('')
|
||||
|
|
@ -29,21 +29,15 @@ const Input2FAModal = ({ showModal, toggleModal, action, vars }) => {
|
|||
setInvalidCode(false)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
const onContinue = () => {
|
||||
setConfirmation(twoFACode)
|
||||
setTwoFACode('')
|
||||
setInvalidCode(false)
|
||||
toggleModal()
|
||||
}
|
||||
|
||||
const [confirm2FA, { error: queryError }] = useLazyQuery(CONFIRM_2FA, {
|
||||
onCompleted: ({ confirm2FA: success }) => {
|
||||
if (!success) {
|
||||
setInvalidCode(true)
|
||||
} else {
|
||||
action()
|
||||
handleClose()
|
||||
}
|
||||
}
|
||||
onCompleted: ({ confirm2FA: success }) =>
|
||||
!success ? setInvalidCode(true) : onContinue()
|
||||
})
|
||||
|
||||
const getErrorMsg = () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import React from 'react'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
import Modal from 'src/components/Modal'
|
||||
import { Info2, P, Mono } from 'src/components/typography'
|
||||
|
|
@ -7,17 +9,65 @@ import CopyToClipboard from 'src/pages/Transactions/CopyToClipboard'
|
|||
|
||||
import styles from '../UserManagement.styles'
|
||||
|
||||
import Input2FAModal from './Input2FAModal'
|
||||
|
||||
const CREATE_RESET_2FA_TOKEN = gql`
|
||||
mutation createReset2FAToken($confirmationCode: String, $userID: ID!) {
|
||||
createReset2FAToken(confirmationCode: $confirmationCode, userID: $userID) {
|
||||
token
|
||||
user_id
|
||||
expire
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const Reset2FAModal = ({ showModal, toggleModal, reset2FAURL, user }) => {
|
||||
const Reset2FAModal = ({
|
||||
showModal,
|
||||
toggleModal,
|
||||
user,
|
||||
requiresConfirmation
|
||||
}) => {
|
||||
const classes = useStyles()
|
||||
const [reset2FAUrl, setReset2FAUrl] = useState('')
|
||||
|
||||
const [createReset2FAToken, { loading }] = useMutation(
|
||||
CREATE_RESET_2FA_TOKEN,
|
||||
{
|
||||
onCompleted: ({ createReset2FAToken: token }) => {
|
||||
setReset2FAUrl(`https://localhost:3001/reset2fa?t=${token.token}`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const [confirmation, setConfirmation] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
showModal &&
|
||||
(confirmation || !requiresConfirmation) &&
|
||||
createReset2FAToken({
|
||||
variables: {
|
||||
confirmationCode: confirmation,
|
||||
userID: user?.id
|
||||
}
|
||||
})
|
||||
}, [confirmation, createReset2FAToken, requiresConfirmation, showModal, user])
|
||||
|
||||
const handleClose = () => {
|
||||
setConfirmation(null)
|
||||
toggleModal()
|
||||
}
|
||||
|
||||
return (
|
||||
showModal && (
|
||||
(showModal && requiresConfirmation && !confirmation && (
|
||||
<Input2FAModal
|
||||
showModal={showModal}
|
||||
handleClose={handleClose}
|
||||
setConfirmation={setConfirmation}
|
||||
/>
|
||||
)) ||
|
||||
(showModal && (confirmation || !requiresConfirmation) && !loading && (
|
||||
<Modal
|
||||
closeOnBackdropClick={true}
|
||||
width={500}
|
||||
|
|
@ -38,13 +88,13 @@ const Reset2FAModal = ({ showModal, toggleModal, reset2FAURL, user }) => {
|
|||
className={classes.link}
|
||||
buttonClassname={classes.copyToClipboard}
|
||||
wrapperClassname={classes.linkWrapper}>
|
||||
{reset2FAURL}
|
||||
{reset2FAUrl}
|
||||
</CopyToClipboard>
|
||||
</strong>
|
||||
</Mono>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { useMutation } from '@apollo/react-hooks'
|
||||
import { makeStyles } from '@material-ui/core/styles'
|
||||
import React from 'react'
|
||||
import gql from 'graphql-tag'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
import Modal from 'src/components/Modal'
|
||||
import { Info2, P, Mono } from 'src/components/typography'
|
||||
|
|
@ -7,22 +9,76 @@ import CopyToClipboard from 'src/pages/Transactions/CopyToClipboard'
|
|||
|
||||
import styles from '../UserManagement.styles'
|
||||
|
||||
import Input2FAModal from './Input2FAModal'
|
||||
|
||||
const CREATE_RESET_PASSWORD_TOKEN = gql`
|
||||
mutation createResetPasswordToken($confirmationCode: String, $userID: ID!) {
|
||||
createResetPasswordToken(
|
||||
confirmationCode: $confirmationCode
|
||||
userID: $userID
|
||||
) {
|
||||
token
|
||||
user_id
|
||||
expire
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const ResetPasswordModal = ({
|
||||
showModal,
|
||||
toggleModal,
|
||||
resetPasswordURL,
|
||||
user
|
||||
user,
|
||||
requiresConfirmation
|
||||
}) => {
|
||||
const classes = useStyles()
|
||||
const [resetPasswordUrl, setResetPasswordUrl] = useState('')
|
||||
|
||||
const [createResetPasswordToken, { loading }] = useMutation(
|
||||
CREATE_RESET_PASSWORD_TOKEN,
|
||||
{
|
||||
onCompleted: ({ createResetPasswordToken: token }) => {
|
||||
setResetPasswordUrl(
|
||||
`https://localhost:3001/resetpassword?t=${token.token}`
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const [confirmation, setConfirmation] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
showModal &&
|
||||
(confirmation || !requiresConfirmation) &&
|
||||
createResetPasswordToken({
|
||||
variables: {
|
||||
confirmationCode: confirmation,
|
||||
userID: user?.id
|
||||
}
|
||||
})
|
||||
}, [
|
||||
confirmation,
|
||||
createResetPasswordToken,
|
||||
showModal,
|
||||
user,
|
||||
requiresConfirmation
|
||||
])
|
||||
|
||||
const handleClose = () => {
|
||||
setConfirmation(null)
|
||||
toggleModal()
|
||||
}
|
||||
|
||||
return (
|
||||
showModal && (
|
||||
(showModal && requiresConfirmation && !confirmation && (
|
||||
<Input2FAModal
|
||||
showModal={showModal}
|
||||
handleClose={handleClose}
|
||||
setConfirmation={setConfirmation}
|
||||
/>
|
||||
)) ||
|
||||
(showModal && (confirmation || !requiresConfirmation) && !loading && (
|
||||
<Modal
|
||||
closeOnBackdropClick={true}
|
||||
width={500}
|
||||
|
|
@ -42,13 +98,13 @@ const ResetPasswordModal = ({
|
|||
className={classes.link}
|
||||
buttonClassname={classes.copyToClipboard}
|
||||
wrapperClassname={classes.linkWrapper}>
|
||||
{resetPasswordURL}
|
||||
{resetPasswordUrl}
|
||||
</CopyToClipboard>
|
||||
</strong>
|
||||
</Mono>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue