Some basic shell

This commit is contained in:
Robert Hall
2018-09-22 15:06:36 -06:00
parent 0831388c62
commit d97a4693e1
6 changed files with 157 additions and 8 deletions

23
app/auth/db.js Normal file
View File

@@ -0,0 +1,23 @@
// WARNING: THIS HELPER FILE IS NOT GOOD PRACTICE AND ONLY HERE FOR CONVENIENCE
// use a real database for persisting users instead
// const Users = [{
// username: 'general-zod',
// email: 'general.zod@krypton.com',
// hash: '',
// }, {
// username: 'kal-el',
// email: 'kal-el@krypton.com',
// hash: '',
// }];
const Users = [];
export default {
find(key, value) {
return Users.find(user => user[key] === value);
},
add(user) {
Users.push(user);
return user;
},
};

95
app/auth/setup.js Normal file
View File

@@ -0,0 +1,95 @@
import passport from 'passport';
import jwt from 'jsonwebtoken';
import bcrypt from 'bcrypt';
import { Strategy as LocalStrategy } from 'passport-local';
// WARNING: use a database instead of persistent memory to store users
// THE FOLLOWING IS BAD PRACTICE AND WILL NOT SCALE!!!
// It's only here for convenience.
import db from './db';
const env = process.env.NODE_ENV;
export function authSetup(app) {
passport.use(new LocalStrategy(async(username, password, done) => {
try {
const user = db.find('username', username);
if (user) {
const match = await bcrypt.compare(password, user.hash);
if (!match) {
return done(null, false, { message: `${user.username} is not authentic to that password.` });
}
done(null, { username: user.username, email: user.email });
} else {
return done(null, false, { message: `${username} does not exist.` });
}
} catch (error) {
done(error);
}
}));
app.use(passport.initialize());
app.post('/auth/signup', async(req, res, next) => {
try {
const { username, email, password } = req.body;
const userExists = db.find('username', username);
const emailExists = db.find('email', email);
if (userExists || emailExists) {
res.end(JSON.stringify({ userExists: !!userExists, emailExists: !!emailExists }));
}
const user = db.add({
username,
email,
hash: await bcrypt.hash(password, 10),
});
const userToSendToClient = { username: user.username, email: user.email };
// generate a signed son web token with the contents of user object and return it in the response
const month = 60 * 60 * 24 * 30;
const token = jwt.sign(userToSendToClient, config.JWT_SECRET, { expiresIn: month });
res.cookie('ds', token, {
// httpOnly: false,
secure: env === 'production' ? true : false,
maxAge: 1000 * month,
});
res.status(200).send({ userToSendToClient });
} catch (error) {
res.status(400).send({ error: 'req body should take the form { username, password }' });
}
});
app.post('/auth/local/login', (req, res) => {
passport.authenticate('local', { session: false, successRedirect: '/', failureRedirect: '/login' }, (err, user) => {
if (err || !user) {
return res.status(400).json({
message: 'Something went wrong.',
user: user ? user : false,
});
}
req.login(user, { session: false }, error => {
if (error) {
res.send(error);
}
// generate a signed son web token with the contents of user object and return it in the response
const month = 60 * 60 * 24 * 30;
const token = jwt.sign(user, config.JWT_SECRET, { expiresIn: month });
return res.cookie('ds', token, {
// httpOnly: false,
secure: env === 'production' ? true : false,
maxAge: 1000 * month,
}).json(user);
})
})(req, res);
});
app.post('/auth/logout', (req, res) => {
req.logout();
res.end('ok');
});
}

View File

@@ -1,18 +1,35 @@
import sirv from 'sirv';
import polka from 'polka';
// import bodyParser from 'body-parser';
// import cookieParser from 'cookie-parser';
import { authSetup } from './auth/setup';
import sapper from 'sapper';
import compression from 'compression';
// import { Store } from 'svelte/store.js';
// import { validate } from '../routes/_services/auth-check.js';
import { manifest } from './manifest/server.js';
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
polka() // You can also use Express
.use(
compression({ threshold: 0 }),
sirv('assets', { dev }),
sapper({ manifest })
)
.listen(PORT, err => {
const app = polka() // You can also use Express
polka()
app.use(compression({ threshold: 0 }))
app.use(sirv('assets', { dev }))
// app.use(bodyParser.json())
// app.use(bodyParser.urlencoded({ extended: true }))
// app.use(cookieParser())
authSetup(app)
app.use(sapper({
manifest,
store: req => {
// const user = validate(req);
// return new Store({ user: user.unauthorized ? null : user });
},
}))
app.listen(PORT, err => {
if (err) console.log('error', err);
})

View File

@@ -6,6 +6,9 @@
<!-- for the blog link, we're using rel=prefetch so that Sapper prefetches
the blog data when we hover over the link or tap it on a touchscreen -->
<li><a rel=prefetch class='{segment === "blog" ? "selected" : ""}' href='blog'>blog</a></li>
<li><a class='{segment === "login" ? "selected" : ""}' href='login'>log in</a></li>
<li><a class='{segment === "signup" ? "selected" : ""}' href='signup'>sign up</a></li>
<li><span>sign out</span></li>
</ul>
</nav>
@@ -48,9 +51,10 @@
bottom: -1px;
}
a {
a, span {
text-decoration: none;
padding: 1em 0.5em;
display: block;
cursor: pointer;
}
</style>

5
routes/login.html Normal file
View File

@@ -0,0 +1,5 @@
<svelte:head>
<title>Log In</title>
</svelte:head>
<h1>Log In</h1>

5
routes/signup.html Normal file
View File

@@ -0,0 +1,5 @@
<svelte:head>
<title>Sign Up</title>
</svelte:head>
<h1>Sign Up</h1>