Created
November 5, 2017 21:05
-
-
Save evilsoft/6e74befcb940c03adec01ee588472f05 to your computer and use it in GitHub Desktop.
Using a ReaderT for database interaction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { validateUser } = require('../data/users') | |
const { | |
compose, curry, objOf | |
} = require('crocks') | |
module.exports = ({ config, express, jwt, knex }) => { | |
const { jwtSecret } = config | |
const router = express.Router() | |
const setCookie = res => payload => { | |
res.cookie('token', jwt.sign(payload, jwtSecret)) | |
res.redirect('/') | |
} | |
const render = curry( | |
(res, locals) => res.render('login', locals) | |
) | |
router.get('/', (req, res) => { | |
render(res, {}) | |
}) | |
router.post('/', (req, res) => { | |
const { body } = req | |
validateUser({ knex }, body) | |
.fork( | |
compose(render(res), objOf('flash')), | |
setCookie(res) | |
) | |
}) | |
router.get('/logout', (req, res) => { | |
res.redirect('/') | |
}) | |
return router | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Async = require('crocks/Async') | |
const ReaderT = require('crocks/Reader/ReaderT') | |
const crypto = require('crypto') | |
const assign = require('crocks/helpers/assign') | |
const assoc = require('crocks/helpers/assoc') | |
const B = require('crocks/combinators/composeB') | |
const curry = require('crocks/helpers/curry') | |
const K = require('crocks/combinators/constant') | |
const head = require('crocks/Maybe/head') | |
const map = require('crocks/pointfree/map') | |
const maybeToAsync = require('crocks/Async/maybeToAsync') | |
const safe = require('crocks/Maybe/safe') | |
const AsyncReader = ReaderT(Async) | |
const { ask, liftFn } = AsyncReader | |
const { fromPromise } = Async | |
const table = 'users' | |
const unique = [ 'email', 'userName' ] | |
// liftQuery :: (a -> Promise b e) -> AsyncReader Object (Async e b) | |
const liftQuery = fn => | |
ask() | |
.chain(liftFn(fromPromise(fn))) | |
// mergeEnv :: Object -> Object | |
const mergeEnv = | |
assign({ table, unique }) | |
// maybeEqual :: a -> a -> Maybe a | |
const maybeEqual = curry( | |
x => safe(y => y === x) | |
) | |
// hash :: Object -> String | |
const hash = ({ salt='', data }) => | |
crypto.createHash('md5') | |
.update(data.concat(salt), 'utf8') | |
.digest('hex') | |
// hashPassword :: Record -> Object | |
const hashPassword = rec => { | |
const { password: data, salt } = rec | |
return assoc('password', hash({ data, salt }), rec) | |
} | |
// compareHashed :: String -> Object -> Object | |
const compareHashed = curry( | |
(hashed, { password, id }) => | |
B(map(K({ id })), maybeEqual(password))(hashed) | |
) | |
// getCreds :: Creds -> AsyncReader Object (Async e [ Record ]) | |
const getCreds = ({ username }) => | |
liftQuery(({ knex, table }) => | |
knex(table) | |
.select([ 'id', 'password', 'salt' ]) | |
.where({ userName: username }) | |
.orWhere({ email: username }) | |
) | |
// validatePassword :: Object -> Record -> Async e Record | |
const validatePassword = curry( | |
(creds, rec) => { | |
const { salt, id, password: hashed } = rec | |
const { password } = creds | |
return Async.of(hashPassword({ id, salt, password })) | |
.chain(maybeToAsync('Invalid Credentials', compareHashed(hashed))) | |
} | |
) | |
// validateUser :: Object -> Creds -> Async e Record | |
exports.validateUser = curry( | |
(env, creds) => | |
AsyncReader.of(creds) | |
.chain(getCreds) | |
.chain(liftFn(maybeToAsync('Invalid Credentials', head))) | |
.chain(liftFn(validatePassword(creds))) | |
.runWith(mergeEnv(env)) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment