feat: auto userdata fetch
fix: gql directives and overall minor fixes
This commit is contained in:
parent
3f6c0e6037
commit
9fa97725ec
22 changed files with 94 additions and 127 deletions
|
|
@ -11,13 +11,11 @@ const cookieParser = require('cookie-parser')
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
const { ApolloServer, AuthenticationError } = require('apollo-server-express')
|
const { ApolloServer, AuthenticationError } = require('apollo-server-express')
|
||||||
const _ = require('lodash/fp')
|
const _ = require('lodash/fp')
|
||||||
const pify = require('pify')
|
|
||||||
|
|
||||||
const options = require('../options')
|
const options = require('../options')
|
||||||
const users = require('../users')
|
const users = require('../users')
|
||||||
|
|
||||||
const session = require('./middlewares/session')
|
const session = require('./middlewares/session')
|
||||||
const authRouter = require('./routes/auth')
|
|
||||||
const { AuthDirective } = require('./graphql/directives')
|
const { AuthDirective } = require('./graphql/directives')
|
||||||
const { typeDefs, resolvers } = require('./graphql/schema')
|
const { typeDefs, resolvers } = require('./graphql/schema')
|
||||||
|
|
||||||
|
|
@ -86,7 +84,6 @@ app.use(cors({ credentials: true, origin: devMode && 'https://localhost:3001' })
|
||||||
|
|
||||||
app.use('/id-card-photo', serveStatic(idPhotoCardBasedir, { index: false }))
|
app.use('/id-card-photo', serveStatic(idPhotoCardBasedir, { index: false }))
|
||||||
app.use('/front-camera-photo', serveStatic(frontCameraBasedir, { index: false }))
|
app.use('/front-camera-photo', serveStatic(frontCameraBasedir, { index: false }))
|
||||||
app.use(authRouter)
|
|
||||||
|
|
||||||
// Everything not on graphql or api/register is redirected to the front-end
|
// Everything not on graphql or api/register is redirected to the front-end
|
||||||
app.get('*', (req, res) => res.sendFile(path.resolve(__dirname, '..', '..', 'public', 'index.html')))
|
app.get('*', (req, res) => res.sendFile(path.resolve(__dirname, '..', '..', 'public', 'index.html')))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
const otplib = require('otplib')
|
const otplib = require('otplib')
|
||||||
const bcrypt = require('bcrypt')
|
const bcrypt = require('bcrypt')
|
||||||
|
const { AuthenticationError } = require('apollo-server-express')
|
||||||
|
|
||||||
const loginHelper = require('../../services/login')
|
const loginHelper = require('../../services/login')
|
||||||
const T = require('../../../time')
|
const T = require('../../../time')
|
||||||
|
|
@ -27,7 +28,7 @@ function authenticateUser(username, password) {
|
||||||
|
|
||||||
const getUserData = context => {
|
const getUserData = context => {
|
||||||
const lidCookie = context.req.cookies && context.req.cookies.lid
|
const lidCookie = context.req.cookies && context.req.cookies.lid
|
||||||
if (!lidCookie) throw new authErrors.InvalidCredentialsError()
|
if (!lidCookie) throw new AuthenticationError()
|
||||||
|
|
||||||
const user = context.req.session.user
|
const user = context.req.session.user
|
||||||
return user
|
return user
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
bills: [Bill]
|
bills: [Bill] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
blacklist: [Blacklist]
|
blacklist: [Blacklist] @auth
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
deleteBlacklistRow(cryptoCode: String!, address: String!): Blacklist
|
deleteBlacklistRow(cryptoCode: String!, address: String!): Blacklist @auth
|
||||||
insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist
|
insertBlacklistRow(cryptoCode: String!, address: String!): Blacklist @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
countries: [Country]
|
countries: [Country] @auth
|
||||||
languages: [Language]
|
languages: [Language] @auth
|
||||||
accountsConfig: [AccountConfig]
|
accountsConfig: [AccountConfig] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
currencies: [Currency]
|
currencies: [Currency] @auth
|
||||||
cryptoCurrencies: [CryptoCurrency]
|
cryptoCurrencies: [CryptoCurrency] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,12 +54,12 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
customers: [Customer]
|
customers: [Customer] @auth
|
||||||
customer(customerId: ID!): Customer
|
customer(customerId: ID!): Customer @auth
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
setCustomer(customerId: ID!, customerInput: CustomerInput): Customer
|
setCustomer(customerId: ID!, customerInput: CustomerInput): Customer @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
funding: [CoinFunds]
|
funding: [CoinFunds] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
machineLogs(deviceId: ID!, from: Date, until: Date, limit: Int, offset: Int): [MachineLog]
|
machineLogs(deviceId: ID!, from: Date, until: Date, limit: Int, offset: Int): [MachineLog] @auth
|
||||||
machineLogsCsv(deviceId: ID!, from: Date, until: Date, limit: Int, offset: Int): String
|
machineLogsCsv(deviceId: ID!, from: Date, until: Date, limit: Int, offset: Int): String @auth
|
||||||
serverLogs(from: Date, until: Date, limit: Int, offset: Int): [ServerLog]
|
serverLogs(from: Date, until: Date, limit: Int, offset: Int): [ServerLog] @auth
|
||||||
serverLogsCsv(from: Date, until: Date, limit: Int, offset: Int): String
|
serverLogsCsv(from: Date, until: Date, limit: Int, offset: Int): String @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,12 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
machines: [Machine]
|
machines: [Machine] @auth
|
||||||
machine(deviceId: ID!): Machine
|
machine(deviceId: ID!): Machine @auth
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
machineAction(deviceId:ID!, action: MachineAction!, cashbox: Int, cassette1: Int, cassette2: Int, newName: String): Machine
|
machineAction(deviceId:ID!, action: MachineAction!, cashbox: Int, cassette1: Int, cassette2: Int, newName: String): Machine @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,14 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
notifications: [Notification]
|
notifications: [Notification] @auth
|
||||||
alerts: [Notification]
|
alerts: [Notification] @auth
|
||||||
hasUnreadNotifications: Boolean
|
hasUnreadNotifications: Boolean @auth
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
toggleClearNotification(id: ID!, read: Boolean!): Notification
|
toggleClearNotification(id: ID!, read: Boolean!): Notification @auth
|
||||||
clearAllNotifications: Notification
|
clearAllNotifications: Notification @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ const { gql } = require('apollo-server-express')
|
||||||
|
|
||||||
const typeDef = gql`
|
const typeDef = gql`
|
||||||
type Mutation {
|
type Mutation {
|
||||||
createPairingTotem(name: String!): String
|
createPairingTotem(name: String!): String @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,12 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
promoCodes: [PromoCode]
|
promoCodes: [PromoCode] @auth
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
createPromoCode(code: String!, discount: Int!): PromoCode
|
createPromoCode(code: String!, discount: Int!): PromoCode @auth
|
||||||
deletePromoCode(codeId: ID!): PromoCode
|
deletePromoCode(codeId: ID!): PromoCode @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
cryptoRates: JSONObject
|
cryptoRates: JSONObject @auth
|
||||||
fiatRates: [Rate]
|
fiatRates: [Rate] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@ const { gql } = require('apollo-server-express')
|
||||||
|
|
||||||
const typeDef = gql`
|
const typeDef = gql`
|
||||||
type Query {
|
type Query {
|
||||||
accounts: JSONObject
|
accounts: JSONObject @auth
|
||||||
config: JSONObject
|
config: JSONObject @auth
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
saveAccounts(accounts: JSONObject): JSONObject
|
saveAccounts(accounts: JSONObject): JSONObject @auth
|
||||||
# resetAccounts(schemaVersion: Int): JSONObject
|
# resetAccounts(schemaVersion: Int): JSONObject @auth
|
||||||
saveConfig(config: JSONObject): JSONObject
|
saveConfig(config: JSONObject): JSONObject @auth
|
||||||
# resetConfig(schemaVersion: Int): JSONObject
|
# resetConfig(schemaVersion: Int): JSONObject @auth
|
||||||
# migrateConfigAndAccounts: JSONObject
|
# migrateConfigAndAccounts: JSONObject @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
uptime: [ProcessStatus]
|
uptime: [ProcessStatus] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const typeDef = gql`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
transactions(from: Date, until: Date, limit: Int, offset: Int, deviceId: ID): [Transaction]
|
transactions(from: Date, until: Date, limit: Int, offset: Int, deviceId: ID): [Transaction] @auth
|
||||||
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String
|
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ const { gql } = require('apollo-server-express')
|
||||||
|
|
||||||
const typeDef = gql`
|
const typeDef = gql`
|
||||||
type Query {
|
type Query {
|
||||||
serverVersion: String!
|
serverVersion: String! @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
const express = require('express')
|
|
||||||
const router = express.Router()
|
|
||||||
|
|
||||||
const getUserData = function (req, res, next) {
|
|
||||||
const lidCookie = req.cookies && req.cookies.lid
|
|
||||||
if (!lidCookie) {
|
|
||||||
res.sendStatus(403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = req.session.user
|
|
||||||
return res.status(200).json({ message: 'Success', user: user })
|
|
||||||
}
|
|
||||||
|
|
||||||
router.get('/user-data', getUserData)
|
|
||||||
|
|
||||||
module.exports = router
|
|
||||||
14
lib/users.js
14
lib/users.js
|
|
@ -162,13 +162,19 @@ function changeUserRole (id, newRole) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableUser (id) {
|
function enableUser (id) {
|
||||||
const sql = `UPDATE users SET enabled=true WHERE id=$1`
|
return db.tx(t => {
|
||||||
return db.none(sql, [id])
|
const q1 = t.none(`UPDATE users SET enabled=true WHERE id=$1`, [id])
|
||||||
|
const q2 = t.none(`DELETE FROM user_sessions WHERE sess -> 'user' ->> 'id'=$1`, [id])
|
||||||
|
return t.batch([q1, q2])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableUser (id) {
|
function disableUser (id) {
|
||||||
const sql = `UPDATE users SET enabled=false WHERE id=$1`
|
return db.tx(t => {
|
||||||
return db.none(sql, [id])
|
const q1 = t.none(`UPDATE users SET enabled=false WHERE id=$1`, [id])
|
||||||
|
const q2 = t.none(`DELETE FROM user_sessions WHERE sess -> 'user' ->> 'id'=$1`, [id])
|
||||||
|
return t.batch([q1, q2])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useQuery } from '@apollo/react-hooks'
|
||||||
import CssBaseline from '@material-ui/core/CssBaseline'
|
import CssBaseline from '@material-ui/core/CssBaseline'
|
||||||
import Grid from '@material-ui/core/Grid'
|
import Grid from '@material-ui/core/Grid'
|
||||||
import {
|
import {
|
||||||
|
|
@ -6,10 +7,11 @@ import {
|
||||||
MuiThemeProvider,
|
MuiThemeProvider,
|
||||||
makeStyles
|
makeStyles
|
||||||
} from '@material-ui/core/styles'
|
} from '@material-ui/core/styles'
|
||||||
import { axios } from '@use-hooks/axios'
|
import gql from 'graphql-tag'
|
||||||
import { create } from 'jss'
|
import { create } from 'jss'
|
||||||
import extendJss from 'jss-plugin-extend'
|
import extendJss from 'jss-plugin-extend'
|
||||||
import React, { useContext, useEffect, useState } from 'react'
|
import * as R from 'ramda'
|
||||||
|
import React, { useContext, useState, useEffect } from 'react'
|
||||||
import {
|
import {
|
||||||
useLocation,
|
useLocation,
|
||||||
useHistory,
|
useHistory,
|
||||||
|
|
@ -73,7 +75,28 @@ const Main = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
const { wizardTested, userData } = useContext(AppContext)
|
const { wizardTested, userData, setUserData } = useContext(AppContext)
|
||||||
|
|
||||||
|
const GET_USER_DATA = gql`
|
||||||
|
query userData {
|
||||||
|
userData {
|
||||||
|
id
|
||||||
|
username
|
||||||
|
role
|
||||||
|
enabled
|
||||||
|
last_accessed
|
||||||
|
last_accessed_from
|
||||||
|
last_accessed_address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const { data: userResponse, loading } = useQuery(GET_USER_DATA)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!R.equals(userData, userResponse?.userData) && !loading)
|
||||||
|
setUserData(userResponse?.userData)
|
||||||
|
}, [loading, setUserData, userData, userResponse])
|
||||||
|
|
||||||
const route = location.pathname
|
const route = location.pathname
|
||||||
|
|
||||||
|
|
@ -109,9 +132,7 @@ const Main = () => {
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className={contentClassName}>
|
<div className={contentClassName}>{!loading && <Routes />}</div>
|
||||||
<Routes />
|
|
||||||
</div>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -121,31 +142,10 @@ const Main = () => {
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [wizardTested, setWizardTested] = useState(false)
|
const [wizardTested, setWizardTested] = useState(false)
|
||||||
const [userData, setUserData] = useState(null)
|
const [userData, setUserData] = useState(null)
|
||||||
const [loading, setLoading] = useState(true)
|
|
||||||
|
|
||||||
const url =
|
|
||||||
process.env.NODE_ENV === 'development' ? 'https://localhost:8070' : ''
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
axios({
|
|
||||||
method: 'GET',
|
|
||||||
url: `${url}/user-data`,
|
|
||||||
withCredentials: true
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
setLoading(false)
|
|
||||||
if (res.status === 200) setUserData(res.data.user)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
setLoading(false)
|
|
||||||
if (err.status === 403) setUserData(null)
|
|
||||||
})
|
|
||||||
}, [url])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider
|
<AppContext.Provider
|
||||||
value={{ wizardTested, setWizardTested, userData, setUserData }}>
|
value={{ wizardTested, setWizardTested, userData, setUserData }}>
|
||||||
{!loading && (
|
|
||||||
<Router>
|
<Router>
|
||||||
<ApolloProvider>
|
<ApolloProvider>
|
||||||
<StylesProvider jss={jss}>
|
<StylesProvider jss={jss}>
|
||||||
|
|
@ -156,7 +156,6 @@ const App = () => {
|
||||||
</StylesProvider>
|
</StylesProvider>
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
</Router>
|
</Router>
|
||||||
)}
|
|
||||||
</AppContext.Provider>
|
</AppContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { ApolloClient } from 'apollo-client'
|
||||||
import { ApolloLink } from 'apollo-link'
|
import { ApolloLink } from 'apollo-link'
|
||||||
import { onError } from 'apollo-link-error'
|
import { onError } from 'apollo-link-error'
|
||||||
import { HttpLink } from 'apollo-link-http'
|
import { HttpLink } from 'apollo-link-http'
|
||||||
import * as R from 'ramda'
|
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { useHistory, useLocation } from 'react-router-dom'
|
import { useHistory, useLocation } from 'react-router-dom'
|
||||||
|
|
||||||
|
|
@ -19,12 +18,10 @@ const getClient = (history, location, setUserData) =>
|
||||||
onError(({ graphQLErrors, networkError }) => {
|
onError(({ graphQLErrors, networkError }) => {
|
||||||
if (graphQLErrors)
|
if (graphQLErrors)
|
||||||
graphQLErrors.forEach(({ message, locations, path, extensions }) => {
|
graphQLErrors.forEach(({ message, locations, path, extensions }) => {
|
||||||
handle(
|
if (extensions?.code === 'UNAUTHENTICATED') {
|
||||||
{ message, locations, path, extensions },
|
setUserData(null)
|
||||||
history,
|
if (location.pathname !== '/login') history.push('/login')
|
||||||
location,
|
}
|
||||||
setUserData
|
|
||||||
)
|
|
||||||
console.log(
|
console.log(
|
||||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
||||||
)
|
)
|
||||||
|
|
@ -52,22 +49,6 @@ const getClient = (history, location, setUserData) =>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const handle = (apolloError, ...args) => {
|
|
||||||
const handler = {
|
|
||||||
UNAUTHENTICATED: (...args) => {
|
|
||||||
const history = args[0]
|
|
||||||
const location = args[1]
|
|
||||||
const setUserData = args[2]
|
|
||||||
setUserData(null)
|
|
||||||
if (location.pathname !== '/login') history.push('/login')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!R.has(apolloError.extensions?.code, handler)) return apolloError
|
|
||||||
|
|
||||||
return handler[apolloError.extensions?.code](...args)
|
|
||||||
}
|
|
||||||
|
|
||||||
const Provider = ({ children }) => {
|
const Provider = ({ children }) => {
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue