Merge branch 'master' of gitlab.com:pawnstar/sos-nextjs

main
Ashelyn Dawn 5 years ago
commit 51f26f5692

@ -17,18 +17,39 @@ router.post('/', parseJSON, loginValidation, async (req, res) => {
req.body.password
)
// TODO: Create session
if(!user){
return res.status(422).json({errors: [{
param: 'email',
msg: 'Invalid login'
},{
param: 'password',
msg: ' '
}]})
}
const session = await db.session.create(
user.uuid,
req.ip,
req.get('User Agent') || "",
req.get('Referrer') || "",
null
)
req.session.uuid = session.uuid
if(user)
res.json(user)
else
res.status(400).json({errors: [{param: 'password', msg: 'Invalid login'}]})
})
// TODO: Login link stuff
router.get('/', async (req, res) => {
// TODO: Get current user and session stuff
res.json(req.user)
})
// TODO: de-auth session
router.get('/logout', (req, res) => {
req.session = null
res.redirect('/')
})
module.exports = router;

@ -14,16 +14,14 @@ router.use((req, res, next)=>{
next()
})
router.use(require('cookie-session')({name: 'sos-session', secret: process.env.COOKIE_SECRET}))
router.use(require('./middleware/session'))
router.use('/auth', require('./auth'))
router.use('/users/', require('./users'))
router.use('/items/', require('./items'))
router.use('/images/', require('./images'))
router.use('/categories/', require('./categories'))
router.get('/', (req, res)=>{
res.json({test: true})
})
router.use((req, res, next)=>{
const err = new Error('Not found')
err.status = 404

@ -0,0 +1,20 @@
const db = require('../../db')
const sessionMiddleware = (req, res, next)=>{
(async ()=>{
let session = await db.session.validate(req.session.uuid);
if(!session) return;
// Update last active
session = await db.session.update(req.session.uuid);
// Attach updated session object to request
req.sessionObj = session;
if(session && session.user)
req.user = session.user;
})()
.then(next).catch(next);
}
module.exports = sessionMiddleware;

@ -17,7 +17,15 @@ router.post('/', parseJSON, registerValidation, async (req, res) => {
req.body.password
)
// TODO: Create session
const session = await db.session.create(
user.uuid,
req.ip,
req.get('User Agent') || "",
req.get('Referrer') || "",
null
)
req.session.uuid = session.uuid
res.json(user)
})

@ -26,7 +26,7 @@ const Header = ({user}) => (
):(
<>
<li><Link href="/account"><a>Account</a></Link></li>
<li><Link href="/logout"><a>Log out</a></Link></li>
<li><Link href="/api/auth/logout"><a>Log out</a></Link></li>
</>
)
}

@ -8,8 +8,8 @@ export default function Hero(){
return (
<div className={styles.hero}>
<div style={{backgroundImage: `url(${background})`}}>
<img class={styles.icon} src={logo}/>
<div class={styles.content}>
<img className={styles.icon} src={logo}/>
<div className={styles.content}>
<h2>Your Socks. Your Style.</h2>
<p>Are you tired of plain (boring) white socks? We've got you covered.</p>
<p>At Society of Socks we strive to give every design a unique personality that is sure to stand out from the crowd.</p>

@ -2,5 +2,6 @@ module.exports = {
user: require('./models/user'),
item: require('./models/item'),
category: require('./models/category'),
user: require('./models/user')
user: require('./models/user'),
session: require('./models/session')
}

@ -4,7 +4,7 @@ module.exports = [
idProperty: 'uuid',
properties: [
'email',
'password',
'password_hash',
'email_confirmed',
'time_registered',
'time_email_confirmed'
@ -44,6 +44,7 @@ module.exports = [
],
associations: [
{name: 'originating_link', mapId: 'loginLinkMap', columnPrefix: 'login_link_'},
{name: 'user', mapId: 'userMap', columnPrefix: 'session_user_'},
// {name: 'cart', mapId: 'cartMap', columnPrefix: 'cart_'}
]
}

@ -21,5 +21,33 @@ session.create = async (user_uuid, ip_address, user_agent, referer, origin_link_
debug(query);
const {rows} = await pg.query(query)
return joinjs.map(rows, mappings, 'sessionMap', 'session_');
return joinjs.map(rows, mappings, 'sessionMap', 'session_')[0];
}
session.validate = async (session_uuid) => {
const query = {
text: 'select * from validate_session($1)',
values: [
session_uuid
]
}
debug(query);
const {rows} = await pg.query(query)
return joinjs.map(rows, mappings, 'sessionMap', 'session_')[0];
}
session.update = async (session_uuid) => {
const query = {
text: 'select * from update_session($1)',
values: [
session_uuid
]
}
debug(query);
const {rows} = await pg.query(query)
return joinjs.map(rows, mappings, 'sessionMap', 'session_')[0];
}

@ -60,13 +60,13 @@ user.login = async (email, password) => {
if(!_user){
// Avoid early exit timing difference
await bcrypt.hash(password, saltRounds)
throw new Error("User not found")
return null
}
const passwordCorrect = await bcrypt.compare(password, _user.password_hash)
if(!passwordCorrect)
throw new Error("Password incorrect")
return null
return _user
}

@ -23,7 +23,20 @@ as $function$
begin
return query select * from v_session
where session_uuid = _session_uuid
and session_time_last_active + session_timeout_length < now();
and session_time_last_active + session_timeout_length > now();
end; $function$;
create or replace function public.update_session(_session_uuid uuid)
returns setof public.v_session
language plpgsql
as $function$
begin
update "session"
set session_time_last_active = now()
where session_uuid = _session_uuid
and now() < (select session_time_last_active + session_timeout_length);
return query select * from validate_session(_session_uuid);
end; $function$;
create or replace function public.login_user_session(_user_uuid uuid, _timeout_length interval, _ip_addr varchar(50), _user_agent varchar(500), _referer varchar(500), _link uuid)

49
package-lock.json generated

@ -2367,11 +2367,47 @@
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-session": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-1.4.0.tgz",
"integrity": "sha512-0hhwD+BUIwMXQraiZP/J7VP2YFzqo6g4WqZlWHtEHQ22t0MeZZrNBSCxC1zcaLAs8ApT3BzAKizx9gW/AP9vNA==",
"requires": {
"cookies": "0.8.0",
"debug": "2.6.9",
"on-headers": "~1.0.2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
}
}
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"cookies": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz",
"integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==",
"requires": {
"depd": "~2.0.0",
"keygrip": "~1.1.0"
},
"dependencies": {
"depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
}
}
},
"copy-concurrently": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
@ -4050,6 +4086,14 @@
"minimist": "^1.2.0"
}
},
"keygrip": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
"integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==",
"requires": {
"tsscmp": "1.0.6"
}
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@ -7326,6 +7370,11 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
},
"tsscmp": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",

@ -16,6 +16,7 @@
"base64-async": "^2.1.3",
"bcrypt": "^3.0.8",
"body-parser": "^1.19.0",
"cookie-session": "^1.4.0",
"cross-env": "^7.0.0",
"debug": "^4.1.1",
"dotenv": "^8.2.0",

@ -1,17 +1,20 @@
import React from "react"
import PropTypes from "prop-types"
import axios from 'axios'
import Header from '~/components/header'
import Footer from '~/components/footer'
import "../styles/layout.css"
const Layout = ({ Component, pageProps }) => {
// Retrieve user information
// const user = useUserSession()
Layout.getInitialProps = async ({ctx}) => {
const {data: user} = await axios.get(`/api/auth`, { headers: ctx.req ? { cookie: ctx.req.headers.cookie } : undefined })
return {user}
}
function Layout({ Component, pageProps, user }){
return (
<>
<Header />
<Header user={user} />
<main><Component {...pageProps} /></main>
<Footer/>
</>

@ -1,18 +1,31 @@
import React from 'react'
import Link from 'next/link'
import Router from 'next/router'
import isEmail from 'validator/lib/isEmail'
import axios from 'axios'
import {FormController, Input, Button} from '~/components/form'
import useErrorReducer from '../hooks/errorReducer'
export default function Login(){
const [errors, dispatch] = useErrorReducer()
const submit = async (values)=>{
const {data} = await axios.post(`/api/auth`, values)
console.log(data)
try {
await axios.post(`/api/auth`, values)
Router.push('/')
} catch (err) {
if(!err.response || err.response.status !== 422) throw err;
dispatch({
type: 'set_errors',
errors: err.response.data.errors
})
}
}
return (
<FormController onSubmit={submit}>
<FormController errors={errors} errorDispatch={dispatch} onSubmit={submit}>
<h1>Login</h1>
<Input label="Email" type="text" name="email" validate={value=>isEmail(value)} hint="Enter a valid email address" />
<Input label="Password" type="password" name="password" validate={value=>(value.length >= 8)} hint="Password must be at least 8 characters long" />

Loading…
Cancel
Save