feat: db uses asynclocalstorage set schema

feat: set user input related header in public route requests to identify schema
fix: small fixes
This commit is contained in:
Sérgio Salgado 2021-09-22 19:21:00 +01:00
parent 7135a03654
commit 990ab32583
10 changed files with 58 additions and 15 deletions

View file

@ -2,9 +2,7 @@ const { asyncLocalStorage, defaultStore } = require('./async-storage')
const computeSchema = (req, res, next) => { const computeSchema = (req, res, next) => {
const store = defaultStore() const store = defaultStore()
asyncLocalStorage.run(store, () => { return asyncLocalStorage.run(store, () => next())
next()
})
} }
module.exports = computeSchema module.exports = computeSchema

View file

@ -38,7 +38,10 @@ const _task = (obj, opts, cb) => {
}) })
} }
const getSchema = () => 'public' const getSchema = () => {
const store = asyncLocalStorage.getStore() ?? defaultStore()
return asyncLocalStorage.run(store, () => store.get('schema'))
}
const getDefaultSchema = () => 'ERROR_SCHEMA' const getDefaultSchema = () => 'ERROR_SCHEMA'
const searchPathWrapper = (t, cb) => { const searchPathWrapper = (t, cb) => {

View file

@ -44,8 +44,9 @@ app.use(express.json())
app.use(express.urlencoded({ extended: true })) // support encoded bodies app.use(express.urlencoded({ extended: true })) // support encoded bodies
app.use(express.static(path.resolve(__dirname, '..', '..', 'public'))) app.use(express.static(path.resolve(__dirname, '..', '..', 'public')))
app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL)) app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL))
app.use(session)
app.use(computeSchema) app.use(computeSchema)
app.use(findOperatorId)
app.use(session)
const apolloServer = new ApolloServer({ const apolloServer = new ApolloServer({
typeDefs, typeDefs,

View file

@ -1,7 +1,7 @@
const users = require('../../users') const users = require('../../users')
const buildApolloContext = async ({ req, res }) => { const buildApolloContext = async ({ req, res }) => {
if (!req.session.user) return { req } if (!req.session.user) return { req, res }
const user = await users.verifyAndUpdateUser( const user = await users.verifyAndUpdateUser(
req.session.user.id, req.session.user.id,
@ -14,12 +14,15 @@ const buildApolloContext = async ({ req, res }) => {
req.session.ipAddress = req.ip req.session.ipAddress = req.ip
req.session.lastUsed = new Date(Date.now()).toISOString() req.session.lastUsed = new Date(Date.now()).toISOString()
req.session.user.id = user.id req.session.user.id = user.id
req.session.user.username = user.username
req.session.user.role = user.role req.session.user.role = user.role
res.set('role', user.role) res.set('role', user.role)
res.cookie('email', user.username)
res.set('Access-Control-Expose-Headers', 'role') res.set('Access-Control-Expose-Headers', 'role')
return { req } return { req, res }
} }
module.exports = buildApolloContext module.exports = buildApolloContext

View file

@ -31,7 +31,6 @@ const verifyTxRoutes = require('./routes/verifyTxRoutes')
const verifyPromoCodeRoutes = require('./routes/verifyPromoCodeRoutes') const verifyPromoCodeRoutes = require('./routes/verifyPromoCodeRoutes')
const app = express() const app = express()
const localApp = express()
const configRequiredRoutes = [ const configRequiredRoutes = [
'/poll', '/poll',
@ -85,4 +84,4 @@ app.use((req, res) => {
res.status(404).json({ error: 'No such route' }) res.status(404).json({ error: 'No such route' })
}) })
module.exports = { app, localApp } module.exports = { app }

View file

@ -56,7 +56,17 @@ const Input2FAState = ({ state, dispatch }) => {
const [input2FA, { error: mutationError }] = useMutation(INPUT_2FA, { const [input2FA, { error: mutationError }] = useMutation(INPUT_2FA, {
onCompleted: ({ input2FA: success }) => { onCompleted: ({ input2FA: success }) => {
success ? getUserData() : setInvalidToken(true) if (success) {
return getUserData({
context: {
headers: {
email: state.clientField,
'Access-Control-Expose-Headers': 'email'
}
}
})
}
return setInvalidToken(true)
} }
}) })
@ -82,6 +92,11 @@ const Input2FAState = ({ state, dispatch }) => {
password: state.passwordField, password: state.passwordField,
code: state.twoFAField, code: state.twoFAField,
rememberMe: state.rememberMeField rememberMe: state.rememberMeField
},
context: {
headers: {
email: state.clientField
}
} }
}) })
} }

View file

@ -53,6 +53,11 @@ const LoginState = ({ state, dispatch }) => {
variables: { variables: {
username, username,
password password
},
context: {
headers: {
email: username
}
} }
}) })

View file

@ -69,6 +69,7 @@ const Setup2FAState = ({ state, dispatch }) => {
const { error: queryError } = useQuery(GET_2FA_SECRET, { const { error: queryError } = useQuery(GET_2FA_SECRET, {
variables: { username: state.clientField, password: state.passwordField }, variables: { username: state.clientField, password: state.passwordField },
context: { headers: { email: state.clientField } },
onCompleted: ({ get2FASecret }) => { onCompleted: ({ get2FASecret }) => {
setSecret(get2FASecret.secret) setSecret(get2FASecret.secret)
setOtpauth(get2FASecret.otpauth) setOtpauth(get2FASecret.otpauth)
@ -84,7 +85,16 @@ const Setup2FAState = ({ state, dispatch }) => {
const [setup2FA, { error: mutationError }] = useMutation(SETUP_2FA, { const [setup2FA, { error: mutationError }] = useMutation(SETUP_2FA, {
onCompleted: ({ setup2FA: success }) => { onCompleted: ({ setup2FA: success }) => {
success ? getUserData() : setInvalidToken(true) success
? getUserData({
context: {
headers: {
email: state.clientField,
'Access-Control-Expose-Headers': 'email'
}
}
})
: setInvalidToken(true)
} }
}) })
@ -155,7 +165,8 @@ const Setup2FAState = ({ state, dispatch }) => {
password: state.passwordField, password: state.passwordField,
rememberMe: state.rememberMeField, rememberMe: state.rememberMeField,
codeConfirmation: twoFAConfirmation codeConfirmation: twoFAConfirmation
} },
context: { headers: { email: state.clientField } }
}) })
}} }}
buttonClassName={classes.loginButton}> buttonClassName={classes.loginButton}>

View file

@ -8,6 +8,8 @@ import { isLoggedIn } from './utils'
const PrivateRoute = ({ ...rest }) => { const PrivateRoute = ({ ...rest }) => {
const { userData } = useContext(AppContext) const { userData } = useContext(AppContext)
console.log('isLoggedIn', isLoggedIn(userData))
return isLoggedIn(userData) ? <Route {...rest} /> : <Redirect to="/login" /> return isLoggedIn(userData) ? <Route {...rest} /> : <Redirect to="/login" />
} }

View file

@ -12,7 +12,7 @@ import AppContext from 'src/AppContext'
const URI = const URI =
process.env.NODE_ENV === 'development' ? 'https://localhost:8070' : '' process.env.NODE_ENV === 'development' ? 'https://localhost:8070' : ''
const getClient = (history, location, setUserData, setRole) => const getClient = (history, location, getUserData, setUserData, setRole) =>
new ApolloClient({ new ApolloClient({
link: ApolloLink.from([ link: ApolloLink.from([
onError(({ graphQLErrors, networkError }) => { onError(({ graphQLErrors, networkError }) => {
@ -67,8 +67,14 @@ const getClient = (history, location, setUserData, setRole) =>
const Provider = ({ children }) => { const Provider = ({ children }) => {
const history = useHistory() const history = useHistory()
const location = useLocation() const location = useLocation()
const { setUserData, setRole } = useContext(AppContext) const { userData, setUserData, setRole } = useContext(AppContext)
const client = getClient(history, location, setUserData, setRole) const client = getClient(
history,
location,
() => userData,
setUserData,
setRole
)
return <ApolloProvider client={client}>{children}</ApolloProvider> return <ApolloProvider client={client}>{children}</ApolloProvider>
} }