Install and use prettier

This commit is contained in:
2021-09-24 20:24:39 -05:00
parent 996e3610ac
commit d4d904d165
21 changed files with 358 additions and 323 deletions

View File

@@ -1,16 +1,17 @@
const express = require('express')
const app = express()
const passport = require('passport')
const {
users
} = require('./controllers')
const express = require("express");
const app = express();
const passport = require("passport");
const { users } = require("./controllers");
/**
* Configure Passport
*/
try { require('./config/passport')(passport) }
catch (error) { console.log(error) }
try {
require("./config/passport")(passport);
} catch (error) {
console.log(error);
}
/**
* Configure Express.js Middleware
@@ -18,26 +19,24 @@ catch (error) { console.log(error) }
// Enable CORS
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', '*')
res.header('Access-Control-Allow-Headers', '*')
res.header('x-powered-by', 'serverless-express')
next()
})
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("x-powered-by", "serverless-express");
next();
});
// Initialize Passport and restore authentication state, if any, from the session
app.use(passport.initialize())
app.use(passport.session())
app.use(passport.initialize());
app.use(passport.session());
// Enable JSON use
app.use(express.json())
app.use(express.json());
// Since Express doesn't support error handling of promises out of the box,
// this handler enables that
const asyncHandler = fn => (req, res, next) => {
return Promise
.resolve(fn(req, res, next))
.catch(next);
const asyncHandler = (fn) => (req, res, next) => {
return Promise.resolve(fn(req, res, next)).catch(next);
};
/**
@@ -45,37 +44,43 @@ const asyncHandler = fn => (req, res, next) => {
*/
app.options(`*`, (req, res) => {
res.status(200).send()
})
res.status(200).send();
});
app.post(`/users/register`, asyncHandler(users.register))
app.post(`/users/register`, asyncHandler(users.register));
app.post(`/users/login`, asyncHandler(users.login))
app.post(`/users/login`, asyncHandler(users.login));
app.get(`/test/`, (req, res) => {
res.status(200).send('Request received')
})
res.status(200).send("Request received");
});
/**
* Routes - Protected
*/
app.post(`/user`, passport.authenticate('jwt', { session: false }), asyncHandler(users.get))
app.post(
`/user`,
passport.authenticate("jwt", { session: false }),
asyncHandler(users.get)
);
/**
* Routes - Catch-All
*/
app.get(`/*`, (req, res) => {
res.status(404).send('Route not found')
})
res.status(404).send("Route not found");
});
/**
* Error Handler
*/
app.use(function (err, req, res, next) {
console.error(err)
res.status(500).json({ error: `Internal Serverless Error - "${err.message}"` })
})
console.error(err);
res
.status(500)
.json({ error: `Internal Serverless Error - "${err.message}"` });
});
module.exports = app
module.exports = app;

View File

@@ -2,26 +2,30 @@
* Config: Passport.js
*/
const StrategyJWT = require('passport-jwt').Strategy
const ExtractJWT = require('passport-jwt').ExtractJwt
const { users } = require('../models')
const { comparePassword } = require('../utils')
const StrategyJWT = require("passport-jwt").Strategy;
const ExtractJWT = require("passport-jwt").ExtractJwt;
const { users } = require("../models");
const { comparePassword } = require("../utils");
module.exports = (passport) => {
const options = {};
options.jwtFromRequest = ExtractJWT.fromAuthHeaderAsBearerToken();
options.secretOrKey = process.env.tokenSecret; // Change this to only use your own secret token
const options = {}
options.jwtFromRequest = ExtractJWT.fromAuthHeaderAsBearerToken()
options.secretOrKey = process.env.tokenSecret || 'secret_j91jasf0j1asfkl' // Change this to only use your own secret token
passport.use(
new StrategyJWT(options, async (jwtPayload, done) => {
let user;
try {
user = await users.getById(jwtPayload.id);
} catch (error) {
console.log(error);
return done(error, null);
}
passport.use(new StrategyJWT(options, async (jwtPayload, done) => {
let user
try { user = await users.getById(jwtPayload.id) }
catch (error) {
console.log(error)
return done(error, null)
}
if (!user) { return done(null, false) }
return done(null, user)
}))
}
if (!user) {
return done(null, false);
}
return done(null, user);
})
);
};

View File

@@ -1,5 +1,5 @@
const users = require('./users')
const users = require("./users");
module.exports = {
users,
}
};

View File

@@ -2,80 +2,85 @@
* Controllers: Users
*/
const jwt = require('jsonwebtoken')
const { users } = require('../models')
const { comparePassword } = require('../utils')
const jwt = require("jsonwebtoken");
const { users } = require("../models");
const { comparePassword } = require("../utils");
/**
* Save
* @param {*} req
* @param {*} res
* @param {*} req
* @param {*} res
* @param {*} next
*/
const register = async (req, res, next) => {
try {
await users.register(req.body)
await users.register(req.body);
} catch (error) {
return res.status(400).json({ error: error.message })
return res.status(400).json({ error: error.message });
}
let user
let user;
try {
user = await users.getByEmail(req.body.email)
user = await users.getByEmail(req.body.email);
} catch (error) {
console.log(error)
return next(error, null)
console.log(error);
return next(error, null);
}
const token = jwt.sign(user, process.env.tokenSecret, {
expiresIn: 604800 // 1 week
})
expiresIn: 604800, // 1 week
});
res.json({ message: 'Authentication successful', token })
}
res.json({ message: "Authentication successful", token });
};
/**
* Sign a user in
* @param {*} req
* @param {*} res
* @param {*} next
* @param {*} req
* @param {*} res
* @param {*} next
*/
const login = async (req, res, next) => {
let user
try { user = await users.getByEmail(req.body.email) }
catch (error) { return done(error, null) }
if (!user) {
return res.status(404).send({ error: 'Authentication failed. User not found.' })
let user;
try {
user = await users.getByEmail(req.body.email);
} catch (error) {
return done(error, null);
}
const isCorrect = comparePassword(req.body.password, user.password)
if (!user) {
return res
.status(404)
.send({ error: "Authentication failed. User not found." });
}
const isCorrect = comparePassword(req.body.password, user.password);
if (!isCorrect) {
return res.status(401).send({ error: 'Authentication failed. Wrong password.' })
return res
.status(401)
.send({ error: "Authentication failed. Wrong password." });
}
const token = jwt.sign(user, process.env.tokenSecret, {
expiresIn: 604800 // 1 week
})
expiresIn: 604800, // 1 week
});
res.json({ message: 'Authentication successful', token })
}
res.json({ message: "Authentication successful", token });
};
/**
* Get a user
* @param {*} req
* @param {*} res
* @param {*} next
* @param {*} req
* @param {*} res
* @param {*} next
*/
const get = async (req, res, next) => {
const user = users.convertToPublicFormat(req.user)
res.json({ user })
}
const user = users.convertToPublicFormat(req.user);
res.json({ user });
};
module.exports = {
register,
login,
get,
}
};

View File

@@ -1,5 +1,5 @@
const users = require('./users')
const users = require("./users");
module.exports = {
users,
}
};

View File

@@ -2,135 +2,132 @@
* Model: Users
*/
const AWS = require('aws-sdk')
const shortid = require('shortid')
const utils = require('../utils')
const AWS = require("aws-sdk");
const shortid = require("shortid");
const utils = require("../utils");
const dynamodb = new AWS.DynamoDB.DocumentClient({
region: process.env.AWS_REGION
})
region: process.env.AWS_REGION,
});
/**
* Register user
* @param {string} user.email User email
* @param {string} user.password User password
*/
const register = async(user = {}) => {
const register = async (user = {}) => {
// Validate
if (!user.email) {
throw new Error(`"email" is required`)
throw new Error(`"email" is required`);
}
if (!user.password) {
throw new Error(`"password" is required`)
throw new Error(`"password" is required`);
}
if (!utils.validateEmailAddress(user.email)) {
throw new Error(`"${user.email}" is not a valid email address`)
throw new Error(`"${user.email}" is not a valid email address`);
}
// Check if user is already registered
const existingUser = await getByEmail(user.email)
const existingUser = await getByEmail(user.email);
if (existingUser) {
throw new Error(`A user with email "${user.email}" is already registered`)
throw new Error(`A user with email "${user.email}" is already registered`);
}
user.password = utils.hashPassword(user.password)
user.password = utils.hashPassword(user.password);
// Save
const params = {
TableName: process.env.db,
Item: {
hk: user.email,
sk: 'user',
sk: "user",
sk2: shortid.generate(),
createdAt: Date.now(),
updatedAt: Date.now(),
password: user.password,
}
}
},
};
await dynamodb.put(params).promise()
}
await dynamodb.put(params).promise();
};
/**
* Get user by email address
* @param {string} email
*/
const getByEmail = async(email) => {
const getByEmail = async (email) => {
// Validate
if (!email) {
throw new Error(`"email" is required`)
throw new Error(`"email" is required`);
}
if (!utils.validateEmailAddress(email)) {
throw new Error(`"${email}" is not a valid email address`)
throw new Error(`"${email}" is not a valid email address`);
}
// Query
const params = {
TableName: process.env.db,
KeyConditionExpression: 'hk = :hk',
ExpressionAttributeValues: { ':hk': email }
}
KeyConditionExpression: "hk = :hk",
ExpressionAttributeValues: { ":hk": email },
};
let user = await dynamodb.query(params).promise()
let user = await dynamodb.query(params).promise();
user = user.Items && user.Items[0] ? user.Items[0] : null
user = user.Items && user.Items[0] ? user.Items[0] : null;
if (user) {
user.id = user.sk2
user.email = user.hk
user.id = user.sk2;
user.email = user.hk;
}
return user
}
return user;
};
/**
* Get user by id
* @param {string} id
*/
const getById = async(id) => {
const getById = async (id) => {
// Validate
if (!id) {
throw new Error(`"id" is required`)
throw new Error(`"id" is required`);
}
// Query
const params = {
TableName: process.env.db,
IndexName: process.env.dbIndex1,
KeyConditionExpression: 'sk2 = :sk2 and sk = :sk',
ExpressionAttributeValues: { ':sk2': id, ':sk': 'user' }
}
let user = await dynamodb.query(params).promise()
KeyConditionExpression: "sk2 = :sk2 and sk = :sk",
ExpressionAttributeValues: { ":sk2": id, ":sk": "user" },
};
let user = await dynamodb.query(params).promise();
user = user.Items && user.Items[0] ? user.Items[0] : null
user = user.Items && user.Items[0] ? user.Items[0] : null;
if (user) {
user.id = user.sk2
user.email = user.hk
user.id = user.sk2;
user.email = user.hk;
}
return user
}
return user;
};
/**
* Convert user record to public format
* This hides the keys used for the dynamodb's single table design and returns human-readable properties.
* @param {*} user
* @param {*} user
*/
const convertToPublicFormat = (user = {}) => {
user.email = user.hk || null
user.id = user.sk2 || null
if (user.hk) delete user.hk
if (user.sk) delete user.sk
if (user.sk2) delete user.sk2
if (user.password) delete user.password
return user
}
user.email = user.hk || null;
user.id = user.sk2 || null;
if (user.hk) delete user.hk;
if (user.sk) delete user.sk;
if (user.sk2) delete user.sk2;
if (user.password) delete user.password;
return user;
};
module.exports = {
register,
getByEmail,
getById,
convertToPublicFormat,
}
};

View File

@@ -1,7 +1,6 @@
{
"name": "serverless-fullstack-app-api",
"name": "forgetmenot",
"version": "1.0.0",
"description": "",
"main": "app.js",
"dependencies": {
"bcryptjs": "^2.4.3",
@@ -15,6 +14,7 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
"author": "Ben Ramey <benramey@fastmail.com>",
"license": "ISC",
"description": ""
}

View File

@@ -1,35 +1,36 @@
/**
* Utils
* Utils
*/
const bcrypt = require('bcryptjs')
const bcrypt = require("bcryptjs");
/**
* Validate email address
*/
const validateEmailAddress = (email) => {
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return re.test(String(email).toLowerCase())
}
var re =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
};
/**
* Hash password
* @param {*} user
* @param {*} user
*/
const hashPassword = (password) => {
const salt = bcrypt.genSaltSync(10)
return bcrypt.hashSync(password, salt)
}
const salt = bcrypt.genSaltSync(10);
return bcrypt.hashSync(password, salt);
};
/**
* Compare password
*/
const comparePassword = (candidatePassword, trustedPassword) => {
return bcrypt.compareSync(candidatePassword, trustedPassword)
}
return bcrypt.compareSync(candidatePassword, trustedPassword);
};
module.exports = {
hashPassword,
comparePassword,
validateEmailAddress
}
validateEmailAddress,
};