From 9f4e9db3f5a385d428d8caeaaf1a87ade50578cc Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Thu, 1 Nov 2018 20:21:36 -0400 Subject: [PATCH 1/9] test --- .sailsrc | 4 +- api/controllers/AuthController.js | 155 ++++++++++++++++++++ api/controllers/TargetController.js | 7 + api/controllers/UserController.js | 37 +++++ api/helpers/passport.js | 171 +++++++++++++++++++++++ api/hooks/passport/index.js | 15 ++ api/models/Book.js | 6 + api/models/Passport.js | 72 ++++++++++ api/models/User.js | 36 +++++ api/policies/sessionAuth.js | 14 ++ assets/js/actions/login.js | 73 ++++++++-- assets/js/lib/Ajax.js | 2 +- assets/js/login.js | 8 +- assets/styles/lib/vars.scss | 6 +- assets/styles/shared/underlineinput.scss | 5 + assets/templates/login.html | 1 + config/auth.js | 5 + config/http.js | 4 + config/passport.js | 9 ++ config/policies.js | 19 ++- config/protocols.js | 104 ++++++++++++++ config/routes.js | 33 +++-- package.json | 14 +- views/pages/index.ejs | 2 +- views/pages/temp.ejs | 2 + 25 files changed, 767 insertions(+), 37 deletions(-) create mode 100644 api/controllers/AuthController.js create mode 100644 api/controllers/TargetController.js create mode 100644 api/controllers/UserController.js create mode 100644 api/helpers/passport.js create mode 100644 api/hooks/passport/index.js create mode 100644 api/models/Passport.js create mode 100644 api/models/User.js create mode 100644 api/policies/sessionAuth.js create mode 100644 config/auth.js create mode 100644 config/passport.js create mode 100644 config/protocols.js create mode 100644 views/pages/temp.ejs diff --git a/.sailsrc b/.sailsrc index 1a67e89..8750674 100644 --- a/.sailsrc +++ b/.sailsrc @@ -1,6 +1,8 @@ { "generators": { - "modules": {} + "modules": { + "permissions-api": "sails-permissions/generator" + } }, "_generatedWith": { "sails": "1.0.2", diff --git a/api/controllers/AuthController.js b/api/controllers/AuthController.js new file mode 100644 index 0000000..f1d1ac9 --- /dev/null +++ b/api/controllers/AuthController.js @@ -0,0 +1,155 @@ +/** + * Authentication Controller + */ +// some also from https://github.com/trailsjs/sails-auth + +module.exports = { + + /** + * check if the given email has a corresponding user + */ + emailExists: async function (req, res) { + const user = await User.findOne({ + email: req.param('email') + }) + if (!user) { + return res.status(404).json({ + error: 'user does not exist' + }) + } else { + return res.json({ + status: 'ok' + }) + } + }, + /** + * opposite of emailExists + */ + emailAvailable: async function (req, res) { + const user = await User.findOne({ + email: req.param('email') + }) + if (user) { + return res.status(401).json({ + error: 'that email address is not available' + }) + } else { + return res.json({ + status: 'ok' + }) + } + }, + + /** + * Log out a user and return them to the homepage + * + * Passport exposes a logout() function on req (also aliased as logOut()) that + * can be called from any route handler which needs to terminate a login + * session. Invoking logout() will remove the req.user property and clear the + * login session (if any). + * + * For more information on logging out users in Passport.js, check out: + * http://passportjs.org/guide/logout/ + * + * @param {Object} req + * @param {Object} res + */ + logout: function (req, res) { + req.logout() + delete req.user + delete req.session.passport + req.session.authenticated = false + + if (!req.isSocket) { + res.redirect(req.query.next || '/') + } else { + res.ok() + } + }, + + /** + * Create a third-party authentication endpoint + * + * @param {Object} req + * @param {Object} res + */ + provider: async function (req, res) { + const passportHelper = await sails.helpers.passport() + passportHelper.endpoint(req, res) + }, + + /** + * Create a authentication callback endpoint + * + * This endpoint handles everything related to creating and verifying Pass- + * ports and users, both locally and from third-aprty providers. + * + * Passport exposes a login() function on req that + * can be used to establish a login session. When the login operation + * completes, user will be assigned to req.user. + * + * For more information on logging in users in Passport.js, check out: + * http://passportjs.org/guide/login/ + * + * @param {Object} req + * @param {Object} res + */ + callback: async function (req, res) { + const action = req.param('action') + const passportHelper = await sails.helpers.passport() + + function negotiateError (err) { + if (action === 'register') { + res.redirect('/register') + } else if (action === 'login') { + res.redirect('/login') + } else if (action === 'disconnect') { + res.redirect('back') + } else { + // make sure the server always returns a response to the client + // i.e passport-local bad username/email or password + res.status(401).json({ + 'error': err.toString() + }) + } + } + + passportHelper.callback(req, res, function (err, user, info, status) { + if (err || !user) { + sails.log.warn(user, err, info, status) + if (!err && info) { + return negotiateError(info) + } + return negotiateError(err) + } + + req.login(user, function (err) { + if (err) { + sails.log.warn(err) + return negotiateError(err) + } + + req.session.authenticated = true + + // redirect if there is a 'next' param + if (req.query.next) { + res.status(302).set('Location', req.query.next) + } + + sails.log.info('user', user, 'authenticated successfully') + return res.json(user) + }) + }) + }, + + /** + * Disconnect a passport from a user + * + * @param {Object} req + * @param {Object} res + */ + disconnect: async function (req, res) { + const passportHelper = await sails.helpers.passport() + passportHelper.disconnect(req, res) + } +} diff --git a/api/controllers/TargetController.js b/api/controllers/TargetController.js new file mode 100644 index 0000000..5130ba9 --- /dev/null +++ b/api/controllers/TargetController.js @@ -0,0 +1,7 @@ +module.exports = { + show: function (req, res) { + res.view('pages/temp', { + email: req.user.email + }) + } +} diff --git a/api/controllers/UserController.js b/api/controllers/UserController.js new file mode 100644 index 0000000..7eae227 --- /dev/null +++ b/api/controllers/UserController.js @@ -0,0 +1,37 @@ +/** + * UserController + * + * @description :: Server-side logic for managing Users + * @help :: See http://links.sailsjs.org/docs/controllers + */ + +module.exports = { + /** + * @override + */ + create: async function (req, res, next) { + const passportHelper = await sails.helpers.passport() + passportHelper.protocols.local.register(req.body, function (err, user) { + if (err) return res.status(500).json({ + error: err.toString() + }) + + res.json(user) + }) + }, + + update: async function (req, res, next) { + const passportHelper = await sails.helpers.passport() + passportHelper.protocols.local.update(req.body, function (err, user) { + if (err) return res.status(500).json({ + error: err.toString() + }) + + res.json(user) + }) + }, + + me: function (req, res) { + res.json(req.user) + } +} diff --git a/api/helpers/passport.js b/api/helpers/passport.js new file mode 100644 index 0000000..3e18126 --- /dev/null +++ b/api/helpers/passport.js @@ -0,0 +1,171 @@ +// api/helpers/passport.js +// from https://github.com/trailsjs/sails-auth/blob/master/api/services/passport.js + +const url = require('url') + +module.exports = { + friendlyName: 'Load PassportHelper', + description: 'Load a PassportHelper instance', + inputs: {}, + exits: { + success: { + outputFriendlyName: 'Passport helper', + outputDescription: 'A PassportHelper instance' + } + }, + fn: async function (inputs, exits) { + return exits.success(new PassportHelper()) + } +} + +const passport = require('passport') +passport.serializeUser(function (user, next) { + next(null, user.id) +}) +passport.deserializeUser(function (id, next) { + return User.findOne({id: id}) + .then(function (user) { + next(null, user) + return user + }).catch(next) +}) + +function PassportHelper () { + this.protocols = sails.config.protocols + + this.loadStrategies = function () { + const strategies = sails.config.passport + + for (const key in strategies) { + let options = {passReqToCallback: true} + let Strategy = strategies[key].strategy + if (key === 'local') { + _.extend(options, { + usernameField: 'identifier' + }) + passport.use(new Strategy(options, this.protocols.local.login)) + } else { + const protocol = strategies[key].protocol + const callbackURL = strategies[key].callback + let baseURL = '' + if (sails.config.appUrl && sails.config.appUrl !== null) { + baseURL = sails.config.appUrl + } else { + sails.log.warn('Please add \'appUrl\' to configuration') + baseURL = sails.getBaseurl() + } + + switch (protocol) { + case 'oauth2': + options.callbackURL = url.resolve(baseURL, callbackURL) + break + // other protocols (openid, etc can go here) + } + + _.extend(options, strategies[key].options) + + passport.use(new Strategy(options, this.protocols[protocol].login)) + } + } + } + this.endpoint = function (req, res) { + const strategies = sails.config.passport + const provider = req.param('provider') + + if (!_.has(strategies, provider)) return res.redirect('/login') + + passport.authenticate(provider, {})(req, res, req.next) + } + // a callback helper to split by req + this.callback = function (req, res, next) { + var provider = req.param('provider', 'local') + var action = req.param('action') + + if (provider === 'local' && action !== undefined) { + if (action === 'register' && !req.user) { + this.protocols.local.register(req, res, next) + } else if (action === 'connect' && req.user) { + this.protocols.local.connect(req, res, next) + } else if (action === 'disconnect' && req.user) { + this.protocols.local.disconnect(req, res, next) + } else { + next(new Error('Invalid action')) + } + } else { + if (action === 'disconnect' && req.user) { + this.disconnect(req, res, next) + } else { + passport.authenticate(provider, next)(req, res, req.next) + } + } + } + this.connect = async function (req, q, profile, next) { + let userAttrs = {} + let provider = profile.provider || req.param('provider') + + req.session.tokens = q.tokens + q.provider = provider + + if (!provider) { + return next(new Error('No provider identified')) + } + + // if the profile object from passport has an email, use it + if (profile.emails && profile.emails[0]) userAttrs.email = profile.emails[0].value + if (!userAttrs.email) return next(new Error('No email available')) + + const pass = await Passport.findOne({ + provider, + identifier: q.identifier.toString() + }) + + let user + + if (!req.user) { + if (!passport) { // new user signing up, create a new user + user = await User.create(userAttrs).fetch() + await Passport.create({ + ...q, + user: user.id + }) + next(null, user) + } else { // existing user logging in + if (_.has(q, 'tokens') && q.tokens !== passport.tokens) { + passport.tokens = q.tokens + } + await passport.save() + user = User.findOne(passport.user) + next(null, user) + } + } else { // user logged in and trying to add new Passport + if (!passport) { + await Passport.create({ + ...q, + user: req.user.id + }) + next(null, req.user) + } else { // no action, user already logged in and passport exists + next(null, user) + } + } + } + this.disconnect = async function (req, res, next) { + try { + const user = req.user + const provider = req.param('provider') + + const pass = Passport.findOne({ + provider, + user: user.id + }) + await Passport.destroy(pass.id) + next(null, user) + return user + } catch (e) { + next(e) + } + } + this.getPassport = function () { + return passport + } +} diff --git a/api/hooks/passport/index.js b/api/hooks/passport/index.js new file mode 100644 index 0000000..a3864d7 --- /dev/null +++ b/api/hooks/passport/index.js @@ -0,0 +1,15 @@ +let passportHook = sails.hooks.passport + +if (!passportHook) { + passportHook = function (sails) { + return { + initialize: async function (cb) { + const helper = await sails.helpers.passport() + helper.loadStrategies() + return cb() + } + } + } +} + +module.exports = passportHook diff --git a/api/models/Book.js b/api/models/Book.js index 940be66..7b002dd 100644 --- a/api/models/Book.js +++ b/api/models/Book.js @@ -12,6 +12,12 @@ module.exports = { // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ // ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗ // ╩ ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝ + id: { + type: 'number', + unique: true, + autoIncrement: true, + columnName: '_id' + }, title: {type: 'string', required: true}, author: {type: 'string'}, isbn: {type: 'string'}, diff --git a/api/models/Passport.js b/api/models/Passport.js new file mode 100644 index 0000000..c65c1c6 --- /dev/null +++ b/api/models/Passport.js @@ -0,0 +1,72 @@ +const bcrypt = require('bcrypt') + +async function hashPassword (passport) { + try { + var config = sails.config.auth.bcrypt + var salt = config.rounds + if (passport.password) { + const hash = await bcrypt.hash(passport.password, salt) + passport.password = hash + } + return passport + } catch (e) { + delete passport.password + sails.log.error(e) + throw e + } +} + +/** + * Passport.js + * + * @description :: A model definition. Represents a database table/collection/etc. + * @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models + */ + +module.exports = { + attributes: { + id: { + type: 'number', + unique: true, + autoIncrement: true, + columnName: '_id' + }, + // local, oauth2, etc + protocol: { + type: 'string', + required: true + }, + password: 'string', + accessToken: 'string', + provider: 'string', + identifier: 'string', + tokens: 'json', + + // User association + user: { + model: 'User', + required: true + } + }, + + /** + * callback run before creating a Passport + */ + beforeCreate: async function (passport, next) { + await hashPassword(passport) + return next() + }, + + /** + * callback run before updating + */ + beforeUpdate: async function (passport, next) { + await hashPassword(passport) + return next() + }, + + // methods + validatePassword: async function (password, passport) { + return bcrypt.compare(password, passport.password) + } +} diff --git a/api/models/User.js b/api/models/User.js new file mode 100644 index 0000000..08bd61e --- /dev/null +++ b/api/models/User.js @@ -0,0 +1,36 @@ +/** + * User.js + * + * @description :: A model definition. Represents a database table/collection/etc. + * @docs :: https://sailsjs.com/docs/concepts/models-and-orm/models + */ + +module.exports = { + + attributes: { + // ╔═╗╦═╗╦╔╦╗╦╔╦╗╦╦ ╦╔═╗╔═╗ + // ╠═╝╠╦╝║║║║║ ║ ║╚╗╔╝║╣ ╚═╗ + // ╩ ╩╚═╩╩ ╩╩ ╩ ╩ ╚╝ ╚═╝╚═╝ + id: { + type: 'number', + unique: true, + autoIncrement: true, + columnName: '_id' + }, + email: { + type: 'string', + unique: true, + required: true + } + + // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ + // ║╣ ║║║╠╩╗║╣ ║║╚═╗ + // ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝ + + // ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ + // ╠═╣╚═╗╚═╗║ ║║ ║╠═╣ ║ ║║ ║║║║╚═╗ + // ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝ + + } + +} diff --git a/api/policies/sessionAuth.js b/api/policies/sessionAuth.js new file mode 100644 index 0000000..1d22cbd --- /dev/null +++ b/api/policies/sessionAuth.js @@ -0,0 +1,14 @@ +/** + * sessionAuth + * + * @module :: Policy + * @description :: Simple policy to allow any authenticated user + * @docs :: http://sailsjs.org/#!documentation/policies + */ +module.exports = function (req, res, next) { + if (req.session.authenticated) { + return next() + } + res.status(403).json({ error: 'You are not permitted to perform this action.' }) + // res.redirect('/login') +} diff --git a/assets/js/actions/login.js b/assets/js/actions/login.js index 1ce5828..c35e747 100644 --- a/assets/js/actions/login.js +++ b/assets/js/actions/login.js @@ -28,10 +28,13 @@ export const setPassword = pass => ({ data: pass }) -export const setCarousel = pos => ({ - type: ACTIONS.set_carousel, - data: pos -}) +export const setCarousel = pos => (dispatch, getState) => { + dispatch(clearError()) + dispatch({ + type: ACTIONS.set_carousel, + data: pos + }) +} export const setError = data => ({ type: ACTIONS.set_error, @@ -43,22 +46,35 @@ export const clearError = () => ({ }) export const setLoggedIn = (data) => (dispatch, getState) => { - document.localStorage.setItem('roe-token', JSON.stringify(data)) + window.localStorage.setItem('roe-token', JSON.stringify(data)) window.location.href = '/app' } -export const checkEmail = email => (dispatch, getState) => { - // dispatch(setWorking(true)) +export const checkEmail = email => async (dispatch, getState) => { + dispatch(setWorking(true)) dispatch(clearError()) if (/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(email)) { - dispatch(setCarousel(2)) + try { + const res = await Ajax.post({ + url: '/auth/email_exists', + data: { + email + } + }) + dispatch(setCarousel(2)) + } catch (e) { + dispatch(setError({ + type: 'email', + error: 'An account with that email does not exist.' + })) + } } else { dispatch(setError({ type: 'email', error: 'Please enter a valid email address.' })) } - // dispatch(setWorking(false)) + dispatch(setWorking(false)) } export const checkPassword = (email, password) => async (dispatch, getState) => { @@ -67,10 +83,9 @@ export const checkPassword = (email, password) => async (dispatch, getState) => // do email + password check try { const res = await Ajax.post({ - url: '/api/token', + url: '/auth/local', data: { - grant_type: 'credentials', - email, + identifier: email, password } }) @@ -84,3 +99,37 @@ export const checkPassword = (email, password) => async (dispatch, getState) => dispatch(setWorking(false)) } } + +export const signup = (email, password) => async (dispatch, getState) => { + dispatch(setWorking(true)) + dispatch(clearError()) + if (/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(email)) { + try { + await Ajax.post({ + url: '/auth/email_available', + data: { + email + } + }) + await Ajax.post({ + url: '/register', + data: { + email, + password + } + }) + dispatch(setCarousel(2)) + } catch (e) { + dispatch(setError({ + type: 'email', + error: e.toString() + })) + } + } else { + dispatch(setError({ + type: 'email', + error: 'Please enter a valid email address.' + })) + } + dispatch(setWorking(false)) +} diff --git a/assets/js/lib/Ajax.js b/assets/js/lib/Ajax.js index b6b9439..cde43d0 100644 --- a/assets/js/lib/Ajax.js +++ b/assets/js/lib/Ajax.js @@ -104,7 +104,7 @@ export default class Ajax { } catch (e) { reject(new AjaxError(e.toString(), data, xhr)) } finally { - reject(new AjaxError(xhr.status, data, xhr)) + reject(new AjaxError(data, xhr.status, xhr)) } } diff --git a/assets/js/login.js b/assets/js/login.js index e6e6203..8524d4f 100644 --- a/assets/js/login.js +++ b/assets/js/login.js @@ -6,7 +6,7 @@ import Progress from './components/Progress' import Carousel, {CarouselItem} from './containers/Carousel' import UnderlineInput from './components/UnderlineInput' import reducer from './reducers/login' -import {setEmail, setPassword, setCarousel, checkEmail, checkPassword} from './actions/login' +import {setEmail, setPassword, setCarousel, checkEmail, checkPassword, signup} from './actions/login' import STYLE from '../styles/login.scss' @@ -55,7 +55,7 @@ class App extends React.Component { getPasswordInputs () { return [ null} + onButtonClick={() => this.dispatch(signup(this.state.user.email, this.state.user.password))} smallButton='Have an account?' onSmallButtonClick={() => this.dispatch(setCarousel(1))} footer='Sign up with your Google account' /> diff --git a/assets/styles/lib/vars.scss b/assets/styles/lib/vars.scss index ca34ecc..7d33f4b 100644 --- a/assets/styles/lib/vars.scss +++ b/assets/styles/lib/vars.scss @@ -22,8 +22,8 @@ $background-2: white; $text-dark-1: $black-1; $text-dark-2: $black-2; -$accent-1: #4423c4; -$accent-2: #4460c4; +$accent-1: #731212; +$accent-2: #9a834d; $accent-3: #D4DBF1; -$red: #FE4C52; \ No newline at end of file +$red: #FE4C52; diff --git a/assets/styles/shared/underlineinput.scss b/assets/styles/shared/underlineinput.scss index a539719..0723490 100644 --- a/assets/styles/shared/underlineinput.scss +++ b/assets/styles/shared/underlineinput.scss @@ -84,4 +84,9 @@ } } } + + & + .underlined-input, + & + .underlined-input-readonly { + margin-top: 8px + } } diff --git a/assets/templates/login.html b/assets/templates/login.html index 94568bd..a3e9c5e 100644 --- a/assets/templates/login.html +++ b/assets/templates/login.html @@ -9,6 +9,7 @@ if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %> <%= key %>="<%= item[key] %>"<% } %> /><% } %> +
diff --git a/config/auth.js b/config/auth.js new file mode 100644 index 0000000..2c988ad --- /dev/null +++ b/config/auth.js @@ -0,0 +1,5 @@ +module.exports.auth = { + bcrypt: { + rounds: 8 + } +} diff --git a/config/http.js b/config/http.js index 601ed57..1f1469c 100644 --- a/config/http.js +++ b/config/http.js @@ -42,6 +42,8 @@ module.exports.http = { 'rateLimit', 'cookieParser', 'session', + 'passportInit', + 'passportSession', 'bodyParser', 'compress', 'poweredBy', @@ -50,6 +52,8 @@ module.exports.http = { 'favicon' ], rateLimit: rateLimiter, + passportInit: require('passport').initialize(), + passportSession: require('passport').session(), /*************************************************************************** * * diff --git a/config/passport.js b/config/passport.js new file mode 100644 index 0000000..7f54c0d --- /dev/null +++ b/config/passport.js @@ -0,0 +1,9 @@ +/** +* Passport configuration +*/ + +module.exports.passport = { + local: { + strategy: require('passport-local').Strategy + } +} diff --git a/config/policies.js b/config/policies.js index c4d1bb5..4c1514c 100644 --- a/config/policies.js +++ b/config/policies.js @@ -17,6 +17,21 @@ module.exports.policies = { * * ***************************************************************************/ - // '*': true, + '*': true, -}; + UserController: { + '*': true, + update: [ 'sessionAuth' ], + me: [ 'sessionAuth' ] + }, + + AuthController: { + '*': true, + logout: [ 'sessionAuth' ], + disconnect: [ 'sessionAuth' ] + }, + + TargetController: { + '*': [ 'sessionAuth' ] + } +} diff --git a/config/protocols.js b/config/protocols.js new file mode 100644 index 0000000..ae9f9ce --- /dev/null +++ b/config/protocols.js @@ -0,0 +1,104 @@ +// Passport protocol configurations +const crypto = require('crypto') +const base64URL = require('base64url') + +module.exports.protocols = { + local: { + /** + * Validate a login request + * + * Looks up a user using the supplied identifier (email or username) and then + * attempts to find a local Passport associated with the user. If a Passport is + * found, its password is checked against the password supplied in the form. + * + * @param {Object} req + * @param {string} identifier + * @param {string} password + * @param {Function} next + */ + login: async function (req, identifier, password, next) { + if (!validateEmail(identifier)) { + return next(new Error('invalid email address'), false) + } + try { + const user = await User.findOne({ + email: identifier + }) + if (!user) throw new Error('an account with that email was not found') + + const passport = await Passport.findOne({ + protocol: 'local', + user: user.id + }) + if (passport) { + const res = await Passport.validatePassword(password, passport) + if (!res) throw new Error('incorrect password') + return next(null, user) + } else { + throw new Error('that account does not have password login enabled') + } + } catch (e) { + return next(e, false) + } + }, + register: async function (user, next) { + try { + const token = generateToken() + const password = user.password + if (!password.length) throw new Error('password cannot be blank') + delete user.password + + const newUser = await User.create(user).fetch() + try { + await Passport.create({ + protocol: 'local', + password, + user: newUser.id, + accessToken: token + }) + return next(null, token) + } catch (e) { + await User.destroy(newUser.id) + throw e + } + } catch (e) { + return next(e) + } + }, + update: async function (user, next) { + throw new Error('not implemented') + }, + connect: async function (req, res, next) { + try { + const user = req.user + const password = req.param('password') + + const pass = await Passport.findOne({ + protocol: 'local', + user: user.id + }) + if (!pass) { + await Passport.create({ + protocol: 'local', + password, + user: user.id + }) + } else { + return next(null, user) + } + } catch (e) { + return next(e) + } + } + } +} + +const EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i + +function validateEmail (email) { + return EMAIL_REGEX.test(email) +} + +function generateToken () { + return base64URL(crypto.randomBytes(48)) +} diff --git a/config/routes.js b/config/routes.js index 55635aa..1fb0f4e 100644 --- a/config/routes.js +++ b/config/routes.js @@ -22,15 +22,16 @@ module.exports.routes = { * * ***************************************************************************/ - '/': { + 'GET /': { view: 'pages/index' }, - '/login': { + 'GET /login': { view: 'pages/login' }, - '/register': { + 'GET /register': { view: 'pages/login' }, + 'GET /app': 'TargetController.show', /*************************************************************************** * * @@ -47,15 +48,25 @@ module.exports.routes = { // ╠═╣╠═╝║ ║╣ ║║║ ║║╠═╝║ ║║║║║ ║ ╚═╗ // ╩ ╩╩ ╩ ╚═╝╝╚╝═╩╝╩ ╚═╝╩╝╚╝ ╩ ╚═╝ - 'POST /api/publish': { - controller: 'books', - action: 'publish' - }, + 'POST /register': 'UserController.create', + 'GET /logout': 'AuthController.logout', - 'GET /api/books': { - controller: 'books', - action: 'list' - }, + 'POST /auth/email_exists': 'AuthController.emailExists', + 'POST /auth/email_available': 'AuthController.emailAvailable', + // 'POST /auth/local': 'AuthController.callback', + // 'POST /auth/local/:action': 'AuthController.callback', + + 'POST /auth/:provider': 'AuthController.callback', + 'POST /auth/:provider/:action': 'AuthController.callback', + + 'GET /auth/:provider': 'AuthController.provider', + 'GET /auth/:provider/callback': 'AuthController.callback', + 'GET /auth/:provider/:action': 'AuthController.callback', + + 'POST /api/publish': 'BooksController.publish', + + 'GET /api/books': 'BooksController.list', + 'GET /api/me': 'UserController.me', // ╦ ╦╔═╗╔╗ ╦ ╦╔═╗╔═╗╦╔═╔═╗ diff --git a/package.json b/package.json index 2778391..996f3b2 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,15 @@ "@sailshq/lodash": "^3.10.3", "@sailshq/socket.io-redis": "^5.2.0", "async": "2.0.1", + "base64url": "^3.0.0", + "bcrypt": "^3.0.2", "express-rate-limit": "^3.2.1", "forever": "^0.15.3", "grunt": "^1.0.3", + "passport": "^0.4.0", + "passport-github2": "^0.1.11", + "passport-google-oauth20": "^1.0.0", + "passport-local": "^1.0.0", "react": "^16.6.0", "react-dom": "^16.6.0", "sails": "^1.0.2", @@ -26,7 +32,6 @@ "@babel/polyfill": "^7.0.0", "@babel/preset-env": "^7.1.0", "@babel/preset-react": "^7.0.0", - "@sailshq/eslint": "^4.19.3", "babel-loader": "^8.0.4", "css-loader": "^1.0.1", "html-webpack-plugin": "^3.2.0", @@ -41,7 +46,7 @@ "webpack-dev-server": "^3.1.10" }, "scripts": { - "start": "npm run open:client", + "start": "npm-run-all --parallel open:client lift", "start:debug": "npm-run-all --parallel open:client debug", "start:prod": "npm-run-all --parallel build:prod lift", "open:client": "webpack-dev-server --mode development", @@ -65,5 +70,10 @@ "license": "", "engines": { "node": ">=8.10" + }, + "standard": { + "globals": [ + "sails" + ] } } diff --git a/views/pages/index.ejs b/views/pages/index.ejs index f43d01b..107b499 100644 --- a/views/pages/index.ejs +++ b/views/pages/index.ejs @@ -19,7 +19,7 @@ setTimeout(function sunrise () {

<%= __('A brand new app.') %>

You're looking at: <%= view.pathFromApp + '.' +view.ext %>

-

Go to Login: Here

+

Go to Login: Here

    diff --git a/views/pages/temp.ejs b/views/pages/temp.ejs new file mode 100644 index 0000000..640d92f --- /dev/null +++ b/views/pages/temp.ejs @@ -0,0 +1,2 @@ +authed: <%- email %>
    +Logout From ad00611f08f91a1a7ad0b25adff4a9de1236a87b Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Thu, 1 Nov 2018 20:36:26 -0400 Subject: [PATCH 2/9] rebuilt --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9fed4ba..32e9df0 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,3 @@ Note: Generators are usually run using the globally-installed `sails` CLI (comm --> [![Build Status](https://travis-ci.org/miacona96/RoE-pipe.svg?branch=master)](https://travis-ci.org/miacona96/RoE-pipe) - From 1ef6d2959dbcf5bb6cae2336e7b5122ea4fcf64f Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Mon, 5 Nov 2018 10:24:15 -0500 Subject: [PATCH 3/9] Test build syntax fixes --- api/controllers/AuthController.js | 72 +++++++------- api/controllers/BooksController.js | 34 +++---- api/controllers/TargetController.js | 4 +- api/controllers/UserController.js | 35 ++++--- api/helpers/passport.js | 148 ++++++++++++++-------------- api/hooks/passport/index.js | 14 +-- api/models/Book.js | 2 +- api/models/Passport.js | 30 +++--- api/models/User.js | 2 +- api/policies/sessionAuth.js | 6 +- assets/js/components/Progress.js | 4 +- package.json | 4 +- 12 files changed, 180 insertions(+), 175 deletions(-) diff --git a/api/controllers/AuthController.js b/api/controllers/AuthController.js index f1d1ac9..7885754 100644 --- a/api/controllers/AuthController.js +++ b/api/controllers/AuthController.js @@ -11,15 +11,15 @@ module.exports = { emailExists: async function (req, res) { const user = await User.findOne({ email: req.param('email') - }) + }); if (!user) { return res.status(404).json({ error: 'user does not exist' - }) + }); } else { return res.json({ status: 'ok' - }) + }); } }, /** @@ -28,15 +28,15 @@ module.exports = { emailAvailable: async function (req, res) { const user = await User.findOne({ email: req.param('email') - }) + }); if (user) { return res.status(401).json({ error: 'that email address is not available' - }) + }); } else { return res.json({ status: 'ok' - }) + }); } }, @@ -55,15 +55,15 @@ module.exports = { * @param {Object} res */ logout: function (req, res) { - req.logout() - delete req.user - delete req.session.passport - req.session.authenticated = false + req.logout(); + delete req.user; + delete req.session.passport; + req.session.authenticated = false; if (!req.isSocket) { - res.redirect(req.query.next || '/') + res.redirect(req.query.next || '/'); } else { - res.ok() + res.ok(); } }, @@ -74,8 +74,8 @@ module.exports = { * @param {Object} res */ provider: async function (req, res) { - const passportHelper = await sails.helpers.passport() - passportHelper.endpoint(req, res) + const passportHelper = await sails.helpers.passport(); + passportHelper.endpoint(req, res); }, /** @@ -95,51 +95,51 @@ module.exports = { * @param {Object} res */ callback: async function (req, res) { - const action = req.param('action') - const passportHelper = await sails.helpers.passport() + const action = req.param('action'); + const passportHelper = await sails.helpers.passport(); function negotiateError (err) { if (action === 'register') { - res.redirect('/register') + res.redirect('/register'); } else if (action === 'login') { - res.redirect('/login') + res.redirect('/login'); } else if (action === 'disconnect') { - res.redirect('back') + res.redirect('back'); } else { // make sure the server always returns a response to the client // i.e passport-local bad username/email or password res.status(401).json({ 'error': err.toString() - }) + }); } } - passportHelper.callback(req, res, function (err, user, info, status) { + passportHelper.callback(req, res, (err, user, info, status) => { if (err || !user) { - sails.log.warn(user, err, info, status) + sails.log.warn(user, err, info, status); if (!err && info) { - return negotiateError(info) + return negotiateError(info); } - return negotiateError(err) + return negotiateError(err); } - req.login(user, function (err) { + req.login(user, (err) => { if (err) { - sails.log.warn(err) - return negotiateError(err) + sails.log.warn(err); + return negotiateError(err); } - req.session.authenticated = true + req.session.authenticated = true; // redirect if there is a 'next' param if (req.query.next) { - res.status(302).set('Location', req.query.next) + res.status(302).set('Location', req.query.next); } - sails.log.info('user', user, 'authenticated successfully') - return res.json(user) - }) - }) + sails.log.info('user', user, 'authenticated successfully'); + return res.json(user); + }); + }); }, /** @@ -149,7 +149,7 @@ module.exports = { * @param {Object} res */ disconnect: async function (req, res) { - const passportHelper = await sails.helpers.passport() - passportHelper.disconnect(req, res) + const passportHelper = await sails.helpers.passport(); + passportHelper.disconnect(req, res); } -} +}; diff --git a/api/controllers/BooksController.js b/api/controllers/BooksController.js index c1d0f20..32311a9 100644 --- a/api/controllers/BooksController.js +++ b/api/controllers/BooksController.js @@ -8,48 +8,48 @@ module.exports = { publish: async function (req, res) { try { - const body = req.body - const host = req.hostname - let result + const body = req.body; + const host = req.hostname; + let result; - if (!host) throw new Error('Missing hostname') - if (!body) throw new Error('Missing body') + if (!host) { throw new Error('Missing hostname'); } + if (!body) {throw new Error('Missing body'); } - const bookExists = await Book.findOne(body) + const bookExists = await Book.findOne(body); if (bookExists) { - throw new Error('Version already exists') + throw new Error('Version already exists'); } else { - result = await Book.create(body) + result = await Book.create(body); } return res.json({ ...result - }) + }); } catch (e) { return res.status(400).json({ error: e.message - }) + }); } }, list: async function (req, res) { try { - const body = req.allParams() - if (!body) throw new Error('Missing parameters') + const body = req.allParams(); + if (!body) { throw new Error('Missing parameters'); } - const books = await Book.find(body) + const books = await Book.find(body); if (!books.length) { return res.status(404).json({ error: 'No books matching those parameters were found.' - }) + }); } - return res.json(books) + return res.json(books); } catch (e) { return res.status(500).json({ error: e.message - }) + }); } } -} +}; diff --git a/api/controllers/TargetController.js b/api/controllers/TargetController.js index 5130ba9..318b999 100644 --- a/api/controllers/TargetController.js +++ b/api/controllers/TargetController.js @@ -2,6 +2,6 @@ module.exports = { show: function (req, res) { res.view('pages/temp', { email: req.user.email - }) + }); } -} +}; diff --git a/api/controllers/UserController.js b/api/controllers/UserController.js index 7eae227..352543a 100644 --- a/api/controllers/UserController.js +++ b/api/controllers/UserController.js @@ -10,28 +10,31 @@ module.exports = { * @override */ create: async function (req, res, next) { - const passportHelper = await sails.helpers.passport() - passportHelper.protocols.local.register(req.body, function (err, user) { - if (err) return res.status(500).json({ - error: err.toString() - }) + const passportHelper = await sails.helpers.passport(); + passportHelper.protocols.local.register(req.body, (err, user) => { + if (err) { + return res.status(500).json({ + error: err.toString() }); + } - res.json(user) - }) + res.json(user); + }); }, update: async function (req, res, next) { - const passportHelper = await sails.helpers.passport() - passportHelper.protocols.local.update(req.body, function (err, user) { - if (err) return res.status(500).json({ - error: err.toString() - }) + const passportHelper = await sails.helpers.passport(); + passportHelper.protocols.local.update(req.body, (err, user) => { + if (err) { + return res.status(500).json({ + error: err.toString() + }); + } - res.json(user) - }) + res.json(user); + }); }, me: function (req, res) { - res.json(req.user) + res.json(req.user); } -} +}; diff --git a/api/helpers/passport.js b/api/helpers/passport.js index 3e18126..172e9ff 100644 --- a/api/helpers/passport.js +++ b/api/helpers/passport.js @@ -1,7 +1,7 @@ // api/helpers/passport.js // from https://github.com/trailsjs/sails-auth/blob/master/api/services/passport.js -const url = require('url') +const url = require('url'); module.exports = { friendlyName: 'Load PassportHelper', @@ -14,158 +14,158 @@ module.exports = { } }, fn: async function (inputs, exits) { - return exits.success(new PassportHelper()) + return exits.success(new PassportHelper()); } -} +}; -const passport = require('passport') -passport.serializeUser(function (user, next) { - next(null, user.id) -}) -passport.deserializeUser(function (id, next) { +const passport = require('passport'); +passport.serializeUser((user, next) => { + next(null, user.id); +}); +passport.deserializeUser((id, next) => { return User.findOne({id: id}) - .then(function (user) { - next(null, user) - return user - }).catch(next) -}) + .then((user) => { + next(null, user); + return user; + }).catch(next); +}); function PassportHelper () { - this.protocols = sails.config.protocols + this.protocols = sails.config.protocols; this.loadStrategies = function () { - const strategies = sails.config.passport + const strategies = sails.config.passport; for (const key in strategies) { - let options = {passReqToCallback: true} - let Strategy = strategies[key].strategy + let options = {passReqToCallback: true}; + let Strategy = strategies[key].strategy; if (key === 'local') { _.extend(options, { usernameField: 'identifier' - }) - passport.use(new Strategy(options, this.protocols.local.login)) + }); + passport.use(new Strategy(options, this.protocols.local.login)); } else { - const protocol = strategies[key].protocol - const callbackURL = strategies[key].callback - let baseURL = '' + const protocol = strategies[key].protocol; + const callbackURL = strategies[key].callback; + let baseURL = ''; if (sails.config.appUrl && sails.config.appUrl !== null) { - baseURL = sails.config.appUrl + baseURL = sails.config.appUrl; } else { - sails.log.warn('Please add \'appUrl\' to configuration') - baseURL = sails.getBaseurl() + sails.log.warn('Please add \'appUrl\' to configuration'); + baseURL = sails.getBaseurl(); } switch (protocol) { case 'oauth2': - options.callbackURL = url.resolve(baseURL, callbackURL) - break + options.callbackURL = url.resolve(baseURL, callbackURL); + break; // other protocols (openid, etc can go here) } - _.extend(options, strategies[key].options) + _.extend(options, strategies[key].options); - passport.use(new Strategy(options, this.protocols[protocol].login)) + passport.use(new Strategy(options, this.protocols[protocol].login)); } } - } + }; this.endpoint = function (req, res) { - const strategies = sails.config.passport - const provider = req.param('provider') + const strategies = sails.config.passport; + const provider = req.param('provider'); - if (!_.has(strategies, provider)) return res.redirect('/login') + if (!_.has(strategies, provider)) {return res.redirect('/login');} - passport.authenticate(provider, {})(req, res, req.next) - } + passport.authenticate(provider, {})(req, res, req.next); + }; // a callback helper to split by req this.callback = function (req, res, next) { - var provider = req.param('provider', 'local') - var action = req.param('action') + var provider = req.param('provider', 'local'); + var action = req.param('action'); if (provider === 'local' && action !== undefined) { if (action === 'register' && !req.user) { - this.protocols.local.register(req, res, next) + this.protocols.local.register(req, res, next); } else if (action === 'connect' && req.user) { - this.protocols.local.connect(req, res, next) + this.protocols.local.connect(req, res, next); } else if (action === 'disconnect' && req.user) { - this.protocols.local.disconnect(req, res, next) + this.protocols.local.disconnect(req, res, next); } else { - next(new Error('Invalid action')) + return next(new Error('Invalid action')); } } else { if (action === 'disconnect' && req.user) { - this.disconnect(req, res, next) + this.disconnect(req, res, next); } else { - passport.authenticate(provider, next)(req, res, req.next) + passport.authenticate(provider, next)(req, res, req.next); } } - } + }; this.connect = async function (req, q, profile, next) { - let userAttrs = {} - let provider = profile.provider || req.param('provider') + let userAttrs = {}; + let provider = profile.provider || req.param('provider'); - req.session.tokens = q.tokens - q.provider = provider + req.session.tokens = q.tokens; + q.provider = provider; if (!provider) { - return next(new Error('No provider identified')) + return next(new Error('No provider identified')); } // if the profile object from passport has an email, use it - if (profile.emails && profile.emails[0]) userAttrs.email = profile.emails[0].value - if (!userAttrs.email) return next(new Error('No email available')) + if (profile.emails && profile.emails[0]) {userAttrs.email = profile.emails[0].value;} + if (!userAttrs.email) {return next(new Error('No email available'));} const pass = await Passport.findOne({ provider, identifier: q.identifier.toString() - }) + }); - let user + let user; if (!req.user) { if (!passport) { // new user signing up, create a new user - user = await User.create(userAttrs).fetch() + user = await User.create(userAttrs).fetch(); await Passport.create({ ...q, user: user.id - }) - next(null, user) + }); + return next(null, user); } else { // existing user logging in if (_.has(q, 'tokens') && q.tokens !== passport.tokens) { - passport.tokens = q.tokens + passport.tokens = q.tokens; } - await passport.save() - user = User.findOne(passport.user) - next(null, user) + await passport.save(); + user = User.findOne(passport.user); + return next(null, user); } } else { // user logged in and trying to add new Passport if (!passport) { await Passport.create({ ...q, user: req.user.id - }) - next(null, req.user) + }); + return next(null, req.user); } else { // no action, user already logged in and passport exists - next(null, user) + return next(null, user); } } - } + }; this.disconnect = async function (req, res, next) { try { - const user = req.user - const provider = req.param('provider') + const user = req.user; + const provider = req.param('provider'); const pass = Passport.findOne({ provider, user: user.id - }) - await Passport.destroy(pass.id) - next(null, user) - return user + }); + await Passport.destroy(pass.id); + next(null, user); + return user; } catch (e) { - next(e) + return next(e); } - } + }; this.getPassport = function () { - return passport - } + return passport; + }; } diff --git a/api/hooks/passport/index.js b/api/hooks/passport/index.js index a3864d7..8465ba3 100644 --- a/api/hooks/passport/index.js +++ b/api/hooks/passport/index.js @@ -1,15 +1,15 @@ -let passportHook = sails.hooks.passport +let passportHook = sails.hooks.passport; if (!passportHook) { passportHook = function (sails) { return { initialize: async function (cb) { - const helper = await sails.helpers.passport() - helper.loadStrategies() - return cb() + const helper = await sails.helpers.passport(); + helper.loadStrategies(); + return cb(); } - } - } + }; + }; } -module.exports = passportHook +module.exports = passportHook; diff --git a/api/models/Book.js b/api/models/Book.js index 7b002dd..e199481 100644 --- a/api/models/Book.js +++ b/api/models/Book.js @@ -34,4 +34,4 @@ module.exports = { }, -} +}; diff --git a/api/models/Passport.js b/api/models/Passport.js index c65c1c6..cc74995 100644 --- a/api/models/Passport.js +++ b/api/models/Passport.js @@ -1,18 +1,18 @@ -const bcrypt = require('bcrypt') +const bcrypt = require('bcrypt'); async function hashPassword (passport) { try { - var config = sails.config.auth.bcrypt - var salt = config.rounds + var config = sails.config.auth.bcrypt; + var salt = config.rounds; if (passport.password) { - const hash = await bcrypt.hash(passport.password, salt) - passport.password = hash + const hash = await bcrypt.hash(passport.password, salt); + passport.password = hash; } - return passport + return passport; } catch (e) { - delete passport.password - sails.log.error(e) - throw e + delete passport.password; + sails.log.error(e); + throw e; } } @@ -53,20 +53,20 @@ module.exports = { * callback run before creating a Passport */ beforeCreate: async function (passport, next) { - await hashPassword(passport) - return next() + await hashPassword(passport); + return next(); }, /** * callback run before updating */ beforeUpdate: async function (passport, next) { - await hashPassword(passport) - return next() + await hashPassword(passport); + return next(); }, // methods validatePassword: async function (password, passport) { - return bcrypt.compare(password, passport.password) + return bcrypt.compare(password, passport.password); } -} +}; diff --git a/api/models/User.js b/api/models/User.js index 08bd61e..170fdc0 100644 --- a/api/models/User.js +++ b/api/models/User.js @@ -33,4 +33,4 @@ module.exports = { } -} +}; diff --git a/api/policies/sessionAuth.js b/api/policies/sessionAuth.js index 1d22cbd..1876c71 100644 --- a/api/policies/sessionAuth.js +++ b/api/policies/sessionAuth.js @@ -7,8 +7,8 @@ */ module.exports = function (req, res, next) { if (req.session.authenticated) { - return next() + return next(); } - res.status(403).json({ error: 'You are not permitted to perform this action.' }) + res.status(403).json({ error: 'You are not permitted to perform this action.' }); // res.redirect('/login') -} +}; diff --git a/assets/js/components/Progress.js b/assets/js/components/Progress.js index e3177c4..d2d46db 100644 --- a/assets/js/components/Progress.js +++ b/assets/js/components/Progress.js @@ -1,6 +1,6 @@ -'use strict' +'use strict'; -import React from 'react' +import React from 'react'; const Progress = props => (
    diff --git a/package.json b/package.json index 996f3b2..16306bf 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "async": "2.0.1", "base64url": "^3.0.0", "bcrypt": "^3.0.2", + "eslint-plugin-react": "^7.11.1", "express-rate-limit": "^3.2.1", "forever": "^0.15.3", "grunt": "^1.0.3", @@ -26,13 +27,14 @@ "sails-hook-sockets": "^1.4.0" }, "devDependencies": { - "@sailshq/eslint": "^4.19.3", "@babel/core": "^7.1.2", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", "@babel/polyfill": "^7.0.0", "@babel/preset-env": "^7.1.0", "@babel/preset-react": "^7.0.0", + "@sailshq/eslint": "^4.19.3", "babel-loader": "^8.0.4", + "babel-preset-es2015": "^6.24.1", "css-loader": "^1.0.1", "html-webpack-plugin": "^3.2.0", "mini-css-extract-plugin": "^0.4.4", From 0152bc6525e327dbfc9dce088cadf91118302876 Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Mon, 5 Nov 2018 10:30:14 -0500 Subject: [PATCH 4/9] Pass Travis Build Travis was treating warnings as errors and failing --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 38732f6..9a17369 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: node_js +warnings_are_errors: false node_js: - "node" deploy: From a6d410a38c1a24a71a45edb0422eb06e121a54f5 Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Mon, 5 Nov 2018 17:40:00 -0500 Subject: [PATCH 5/9] Update .travis.yml --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9a17369..0b2ab9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,4 +12,7 @@ deploy: env: "example-app-environment" bucket_name: "the-target-S3-bucket" -#script: node testfile +before_script: + - npm install + +script: sails lift From 4b5e89358086e28f4769dc115e512f67a6c0b494 Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Mon, 5 Nov 2018 20:16:54 -0500 Subject: [PATCH 6/9] Improved syntax checking --- .eslintrc | 4 +- api/hooks/passport/index.js | 2 +- api/models/User.js | 2 +- assets/js/actions/login.js | 76 ++++++++--------- assets/js/lib/Ajax.js | 164 ++++++++++++++++++------------------ assets/js/reducers/login.js | 26 +++--- config/auth.js | 2 +- config/env/development.js | 2 +- config/env/production.js | 2 +- config/http.js | 8 +- config/passport.js | 2 +- config/policies.js | 2 +- config/protocols.js | 64 +++++++------- config/routes.js | 2 +- package.json | 1 + webpack.config.js | 14 +-- 16 files changed, 188 insertions(+), 185 deletions(-) diff --git a/.eslintrc b/.eslintrc index e0b6d6b..fa6da91 100644 --- a/.eslintrc +++ b/.eslintrc @@ -28,6 +28,7 @@ "parserOptions": { "ecmaVersion": 8, + "sourceType": "module", "ecmaFeatures": { "experimentalObjectRestSpread": true } @@ -42,6 +43,7 @@ "_": true, "async": true // …and any others (e.g. `"Organization": true`) + //["error", "unix"] // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }, @@ -63,7 +65,7 @@ "ObjectExpression": 1, "ignoredNodes": ["ConditionalExpression"] }], - "linebreak-style": ["error", "unix"], + "linebreak-style": 0, "no-dupe-keys": ["error"], "no-duplicate-case": ["error"], "no-extra-semi": ["warn"], diff --git a/api/hooks/passport/index.js b/api/hooks/passport/index.js index 5a64aa3..72c98ca 100644 --- a/api/hooks/passport/index.js +++ b/api/hooks/passport/index.js @@ -13,4 +13,4 @@ if (!passportHook) { }; } -module.exports = passportHook; \ No newline at end of file +module.exports = passportHook; diff --git a/api/models/User.js b/api/models/User.js index cc78b78..170fdc0 100644 --- a/api/models/User.js +++ b/api/models/User.js @@ -33,4 +33,4 @@ module.exports = { } -}; \ No newline at end of file +}; diff --git a/assets/js/actions/login.js b/assets/js/actions/login.js index c35e747..2fe6aba 100644 --- a/assets/js/actions/login.js +++ b/assets/js/actions/login.js @@ -1,6 +1,6 @@ -'use strict' +'use strict'; -import Ajax from '../lib/Ajax' +import Ajax from '../lib/Ajax'; const ACTIONS = { set_working: 'set_working', @@ -9,50 +9,50 @@ const ACTIONS = { set_carousel: 'set_carousel', set_error: 'set_error', clear_error: 'clear_error' -} +}; -export default ACTIONS +export default ACTIONS; export const setWorking = working => ({ type: ACTIONS.set_working, data: working -}) +}); export const setEmail = email => ({ type: ACTIONS.set_user, data: email -}) +}); export const setPassword = pass => ({ type: ACTIONS.set_password, data: pass -}) +}); export const setCarousel = pos => (dispatch, getState) => { - dispatch(clearError()) + dispatch(clearError()); dispatch({ type: ACTIONS.set_carousel, data: pos - }) -} + }); +}; export const setError = data => ({ type: ACTIONS.set_error, data: data -}) +}); export const clearError = () => ({ type: ACTIONS.clear_error -}) +}); export const setLoggedIn = (data) => (dispatch, getState) => { - window.localStorage.setItem('roe-token', JSON.stringify(data)) - window.location.href = '/app' -} + window.localStorage.setItem('roe-token', JSON.stringify(data)); + window.location.href = '/app'; +}; export const checkEmail = email => async (dispatch, getState) => { - dispatch(setWorking(true)) - dispatch(clearError()) + dispatch(setWorking(true)); + dispatch(clearError()); if (/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(email)) { try { const res = await Ajax.post({ @@ -60,25 +60,25 @@ export const checkEmail = email => async (dispatch, getState) => { data: { email } - }) - dispatch(setCarousel(2)) + }); + dispatch(setCarousel(2)); } catch (e) { dispatch(setError({ type: 'email', error: 'An account with that email does not exist.' - })) + })); } } else { dispatch(setError({ type: 'email', error: 'Please enter a valid email address.' - })) + })); } - dispatch(setWorking(false)) -} + dispatch(setWorking(false)); +}; export const checkPassword = (email, password) => async (dispatch, getState) => { - dispatch(setWorking(true)) + dispatch(setWorking(true)); // do email + password check try { @@ -88,21 +88,21 @@ export const checkPassword = (email, password) => async (dispatch, getState) => identifier: email, password } - }) - dispatch(setLoggedIn(res)) + }); + dispatch(setLoggedIn(res)); // dispatch(setWorking(false)) } catch (e) { dispatch(setError({ type: 'password', error: e.toString() - })) - dispatch(setWorking(false)) + })); + dispatch(setWorking(false)); } -} +}; export const signup = (email, password) => async (dispatch, getState) => { - dispatch(setWorking(true)) - dispatch(clearError()) + dispatch(setWorking(true)); + dispatch(clearError()); if (/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(email)) { try { await Ajax.post({ @@ -110,26 +110,26 @@ export const signup = (email, password) => async (dispatch, getState) => { data: { email } - }) + }); await Ajax.post({ url: '/register', data: { email, password } - }) - dispatch(setCarousel(2)) + }); + dispatch(setCarousel(2)); } catch (e) { dispatch(setError({ type: 'email', error: e.toString() - })) + })); } } else { dispatch(setError({ type: 'email', error: 'Please enter a valid email address.' - })) + })); } - dispatch(setWorking(false)) -} + dispatch(setWorking(false)); +}; diff --git a/assets/js/lib/Ajax.js b/assets/js/lib/Ajax.js index cde43d0..80f256c 100644 --- a/assets/js/lib/Ajax.js +++ b/assets/js/lib/Ajax.js @@ -1,162 +1,162 @@ /* global XMLHttpRequest FormData */ -'use strict' +'use strict'; -let ajaxcfg = {} +let ajaxcfg = {}; class AjaxError extends Error { constructor (reason, data, xhr) { - super(reason) - this.data = data - this.xhr = xhr + super(reason); + this.data = data; + this.xhr = xhr; } } export default class Ajax { static async get (opts) { - if (!opts) opts = {} - opts.method = 'get' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'get'; + return Ajax.ajax(opts); } static async post (opts) { - if (!opts) opts = {} - opts.method = 'post' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'post'; + return Ajax.ajax(opts); } static async put (opts) { - if (!opts) opts = {} - opts.method = 'put' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'put'; + return Ajax.ajax(opts); } static async patch (opts) { - if (!opts) opts = {} - opts.method = 'patch' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'patch'; + return Ajax.ajax(opts); } static async delete (opts) { - if (!opts) opts = {} - opts.method = 'delete' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'delete'; + return Ajax.ajax(opts); } static async head (opts) { - if (!opts) opts = {} - opts.method = 'head' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'head'; + return Ajax.ajax(opts); } static async options (opts) { - if (!opts) opts = {} - opts.method = 'options' - return Ajax.ajax(opts) + if (!opts) {opts = {};} + opts.method = 'options'; + return Ajax.ajax(opts); } static ajax (opts) { return new Promise((resolve, reject) => { - if (!opts) reject(new Error('Missing required options parameter.')) + if (!opts) {reject(new Error('Missing required options parameter.'));} if (opts.method) { - if (!['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(opts.method.toLowerCase())) reject(new Error('opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.')) - opts.method = opts.method.toUpperCase() + if (!['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(opts.method.toLowerCase())) {reject(new Error('opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.'));} + opts.method = opts.method.toUpperCase(); } - var xhr = opts.xhr || new XMLHttpRequest() + var xhr = opts.xhr || new XMLHttpRequest(); - var fd = null - var qs = '' + var fd = null; + var qs = ''; if (opts.data && opts.method.toLowerCase() !== 'get') { - fd = new FormData() + fd = new FormData(); for (let key in opts.data) { - fd.append(key, opts.data[key]) + fd.append(key, opts.data[key]); } } else if (opts.data) { - qs += '?' - let params = [] + qs += '?'; + let params = []; for (let key in opts.data) { - params.push([key, opts.data[key]].join('=')) + params.push([key, opts.data[key]].join('=')); } - qs += params.join('&') + qs += params.join('&'); } xhr.onload = () => { - if (xhr.status !== 200) return xhr.onerror() - var data = xhr.response + if (xhr.status !== 200) {return xhr.onerror();} + var data = xhr.response; resolve({ data, xhr - }) - } + }); + }; xhr.onerror = () => { - var data = xhr.response + var data = xhr.response; // method not allowed if (xhr.status === 405) { - reject(new AjaxError('405 Method Not Allowed', data, xhr)) - return + reject(new AjaxError('405 Method Not Allowed', data, xhr)); + return; } else if (xhr.status === 404) { - reject(new AjaxError('404 Not Found', data, xhr)) - return + reject(new AjaxError('404 Not Found', data, xhr)); + return; } try { // if the access token is invalid, try to use the refresh token - var json = JSON.parse(data) + var json = JSON.parse(data); if (json.error === 'access_denied' && json.hint.includes('token') && json.hint.includes('invalid') && ajaxcfg.refresh_token) { - return Ajax.refresh(opts) + return Ajax.refresh(opts); } else if (json.error === 'access_denied' && json.hint.includes('token') && json.hint.includes('revoked')) { - reject(new AjaxError('token revoked', data, xhr)) + reject(new AjaxError('token revoked', data, xhr)); } } catch (e) { - reject(new AjaxError(e.toString(), data, xhr)) + reject(new AjaxError(e.toString(), data, xhr)); } finally { - reject(new AjaxError(data, xhr.status, xhr)) + reject(new AjaxError(data, xhr.status, xhr)); } - } + }; - xhr.open(opts.method || 'GET', opts.url + qs || window.location.href) + xhr.open(opts.method || 'GET', opts.url + qs || window.location.href); if (opts.headers) { - for (let key in opts.headers) xhr.setRequestHeader(key, opts.headers[key]) + for (let key in opts.headers) {xhr.setRequestHeader(key, opts.headers[key]);} } - if (ajaxcfg.access_token && !(opts.headers || {}).Authorization) xhr.setRequestHeader('Authorization', 'Bearer ' + ajaxcfg.access_token) - xhr.send(fd) - }) + if (ajaxcfg.access_token && !(opts.headers || {}).Authorization) {xhr.setRequestHeader('Authorization', 'Bearer ' + ajaxcfg.access_token);} + xhr.send(fd); + }); } static refresh (opts) { return new Promise((resolve, reject) => { - var xhr = new XMLHttpRequest() + var xhr = new XMLHttpRequest(); - var fd = new FormData() + var fd = new FormData(); const OAUTH_TOKEN_REQUEST = { grant_type: 'refresh_token', refresh_token: ajaxcfg.refresh_token, client_id: 'foxfile', client_secret: 1 - } + }; for (var key in OAUTH_TOKEN_REQUEST) { - fd.append(key, OAUTH_TOKEN_REQUEST[key]) + fd.append(key, OAUTH_TOKEN_REQUEST[key]); } // try original request xhr.onload = () => { - if (xhr.status !== 200) return xhr.onerror() - if (ajaxcfg.refresh) ajaxcfg.refresh(xhr.response) - var json = JSON.parse(xhr.response) - ajaxcfg.access_token = json.access_token - ajaxcfg.refresh_token = json.refresh_token - return Ajax.ajax(opts) - } + if (xhr.status !== 200) {return xhr.onerror();} + if (ajaxcfg.refresh) {ajaxcfg.refresh(xhr.response);} + var json = JSON.parse(xhr.response); + ajaxcfg.access_token = json.access_token; + ajaxcfg.refresh_token = json.refresh_token; + return Ajax.ajax(opts); + }; // if this fails, dont try again xhr.onerror = () => { - var data = xhr.response - reject(new AjaxError(xhr.status, data, xhr)) - } - xhr.open('POST', ajaxcfg.refresh_url) - xhr.send(fd) - }) + var data = xhr.response; + reject(new AjaxError(xhr.status, data, xhr)); + }; + xhr.open('POST', ajaxcfg.refresh_url); + xhr.send(fd); + }); } static setTokenData (tokens) { - if (!tokens) throw new Error('Missing tokens.') - if (!tokens.access_token && !tokens.refresh_token && !tokens.refresh_url) throw new Error('Missing at least one of: access_token, refresh_token, refresh_url.') - if (tokens.access_token) ajaxcfg.access_token = tokens.access_token - if (tokens.refresh_token) ajaxcfg.refresh_token = tokens.refresh_token - if (tokens.refresh_url) ajaxcfg.refresh_url = tokens.refresh_url - return true + if (!tokens) {throw new Error('Missing tokens.');} + if (!tokens.access_token && !tokens.refresh_token && !tokens.refresh_url) {throw new Error('Missing at least one of: access_token, refresh_token, refresh_url.');} + if (tokens.access_token) {ajaxcfg.access_token = tokens.access_token;} + if (tokens.refresh_token) {ajaxcfg.refresh_token = tokens.refresh_token;} + if (tokens.refresh_url) {ajaxcfg.refresh_url = tokens.refresh_url;} + return true; } static onRefresh (func) { - ajaxcfg.refresh = func + ajaxcfg.refresh = func; } } diff --git a/assets/js/reducers/login.js b/assets/js/reducers/login.js index 6495974..7a084c8 100644 --- a/assets/js/reducers/login.js +++ b/assets/js/reducers/login.js @@ -1,9 +1,9 @@ -'use strict' +'use strict'; -import Actions from '../actions/login' +import Actions from '../actions/login'; const reducer = (state = {}, action) => { - const {type, data} = action + const {type, data} = action; switch (type) { case Actions.set_user: return { @@ -11,40 +11,40 @@ const reducer = (state = {}, action) => { ...state.user, email: data } - } + }; case Actions.set_password: return { user: { ...state.user, password: data } - } + }; case Actions.set_carousel: return { carouselPosition: data - } + }; case Actions.set_working: return { working: data - } + }; case Actions.set_error: switch (data.type) { case 'email': return { emailError: data.error - } + }; case 'password': return { passwordError: data.error - } - default: return {} + }; + default: return {}; } case Actions.clear_error: return { emailError: '', passwordError: '' - } + }; } -} +}; -export default reducer +export default reducer; diff --git a/config/auth.js b/config/auth.js index 2c988ad..76ba7a7 100644 --- a/config/auth.js +++ b/config/auth.js @@ -2,4 +2,4 @@ module.exports.auth = { bcrypt: { rounds: 8 } -} +}; diff --git a/config/env/development.js b/config/env/development.js index e01af2e..22da3e5 100644 --- a/config/env/development.js +++ b/config/env/development.js @@ -367,4 +367,4 @@ module.exports = { } -} +}; diff --git a/config/env/production.js b/config/env/production.js index 6f89729..d0cee3a 100644 --- a/config/env/production.js +++ b/config/env/production.js @@ -366,4 +366,4 @@ module.exports = { } -} +}; diff --git a/config/http.js b/config/http.js index 1f1469c..0c5c845 100644 --- a/config/http.js +++ b/config/http.js @@ -9,14 +9,14 @@ * https://sailsjs.com/config/http */ -const rateLimit = require('express-rate-limit') +const rateLimit = require('express-rate-limit'); const rateLimiter = rateLimit({ windowMs: 10 * 60 * 1000, // 10 minutes max: 100, // limit each IP to 100 requests per windowMs skip (req, res) { - return !req.path.startsWith('/api') + return !req.path.startsWith('/api'); } -}) +}); module.exports.http = { @@ -69,4 +69,4 @@ module.exports.http = { // return middlewareFn; // })(), } -} +}; diff --git a/config/passport.js b/config/passport.js index 7f54c0d..8f1470a 100644 --- a/config/passport.js +++ b/config/passport.js @@ -6,4 +6,4 @@ module.exports.passport = { local: { strategy: require('passport-local').Strategy } -} +}; diff --git a/config/policies.js b/config/policies.js index 4c1514c..84b60fe 100644 --- a/config/policies.js +++ b/config/policies.js @@ -34,4 +34,4 @@ module.exports.policies = { TargetController: { '*': [ 'sessionAuth' ] } -} +}; diff --git a/config/protocols.js b/config/protocols.js index ae9f9ce..5afe4e3 100644 --- a/config/protocols.js +++ b/config/protocols.js @@ -1,6 +1,6 @@ // Passport protocol configurations -const crypto = require('crypto') -const base64URL = require('base64url') +const crypto = require('crypto'); +const base64URL = require('base64url'); module.exports.protocols = { local: { @@ -18,87 +18,87 @@ module.exports.protocols = { */ login: async function (req, identifier, password, next) { if (!validateEmail(identifier)) { - return next(new Error('invalid email address'), false) + return next(new Error('invalid email address'), false); } try { const user = await User.findOne({ email: identifier - }) - if (!user) throw new Error('an account with that email was not found') + }); + if (!user) {throw new Error('an account with that email was not found');} const passport = await Passport.findOne({ protocol: 'local', user: user.id - }) + }); if (passport) { - const res = await Passport.validatePassword(password, passport) - if (!res) throw new Error('incorrect password') - return next(null, user) + const res = await Passport.validatePassword(password, passport); + if (!res) {throw new Error('incorrect password');} + return next(null, user); } else { - throw new Error('that account does not have password login enabled') + throw new Error('that account does not have password login enabled'); } } catch (e) { - return next(e, false) + return next(e, false); } }, register: async function (user, next) { try { - const token = generateToken() - const password = user.password - if (!password.length) throw new Error('password cannot be blank') - delete user.password + const token = generateToken(); + const password = user.password; + if (!password.length) {throw new Error('password cannot be blank');} + delete user.password; - const newUser = await User.create(user).fetch() + const newUser = await User.create(user).fetch(); try { await Passport.create({ protocol: 'local', password, user: newUser.id, accessToken: token - }) - return next(null, token) + }); + return next(null, token); } catch (e) { - await User.destroy(newUser.id) - throw e + await User.destroy(newUser.id); + throw e; } } catch (e) { - return next(e) + return next(e); } }, update: async function (user, next) { - throw new Error('not implemented') + throw new Error('not implemented'); }, connect: async function (req, res, next) { try { - const user = req.user - const password = req.param('password') + const user = req.user; + const password = req.param('password'); const pass = await Passport.findOne({ protocol: 'local', user: user.id - }) + }); if (!pass) { await Passport.create({ protocol: 'local', password, user: user.id - }) + }); } else { - return next(null, user) + return next(null, user); } } catch (e) { - return next(e) + return next(e); } } } -} +}; -const EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i +const EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; function validateEmail (email) { - return EMAIL_REGEX.test(email) + return EMAIL_REGEX.test(email); } function generateToken () { - return base64URL(crypto.randomBytes(48)) + return base64URL(crypto.randomBytes(48)); } diff --git a/config/routes.js b/config/routes.js index 1fb0f4e..e4b9108 100644 --- a/config/routes.js +++ b/config/routes.js @@ -79,4 +79,4 @@ module.exports.routes = { // ╩ ╩╩╚═╝╚═╝ -} +}; diff --git a/package.json b/package.json index a02fb9c..2819b30 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "babel-loader": "^8.0.4", "babel-preset-es2015": "^6.24.1", "css-loader": "^1.0.1", + "eslint": "^5.8.0", "html-webpack-plugin": "^3.2.0", "mini-css-extract-plugin": "^0.4.4", "node-sass": "^4.9.4", diff --git a/webpack.config.js b/webpack.config.js index 232a891..6e3c068 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,10 +1,10 @@ -const HtmlWebpackPlugin = require('html-webpack-plugin') -const MiniCssExtractPlugin = require('mini-css-extract-plugin') -const webpack = require('webpack') -const path = require('path') +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const webpack = require('webpack'); +const path = require('path'); module.exports = (env, argv) => { - const mode = argv.mode || 'development' + const mode = argv.mode || 'development'; return { mode: mode || 'development', @@ -45,5 +45,5 @@ module.exports = (env, argv) => { 'process.env.NODE_ENV': JSON.stringify(mode) }) ] - } -} + }; +}; From 53744d18c6857f5990a2061a8deb44690c877337 Mon Sep 17 00:00:00 2001 From: Michael Iacona Date: Mon, 5 Nov 2018 20:33:14 -0500 Subject: [PATCH 7/9] test command --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0b2ab9e..5a85838 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,4 +15,4 @@ deploy: before_script: - npm install -script: sails lift +script: npm run lint && npm run custom-tests && echo 'Done.' From 7972729f9ee4794f0d57bdfb72e7445b5e9e36c0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2018 15:05:50 -0500 Subject: [PATCH 8/9] standardify --- Gruntfile.js | 10 ++++------ webpack.config.js | 14 +++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index e3b2847..82be2dc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -12,12 +12,10 @@ * For more information see: * https://sailsjs.com/anatomy/Gruntfile.js */ -module.exports = function(grunt) { - - var loadGruntTasks = require('sails-hook-grunt/accessible/load-grunt-tasks'); +module.exports = function (grunt) { + var loadGruntTasks = require('sails-hook-grunt/accessible/load-grunt-tasks') // Load Grunt task configurations (from `tasks/config/`) and Grunt // task registrations (from `tasks/register/`). - loadGruntTasks(__dirname, grunt); - -}; + loadGruntTasks(__dirname, grunt) +} diff --git a/webpack.config.js b/webpack.config.js index 6e3c068..232a891 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,10 +1,10 @@ -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const webpack = require('webpack'); -const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin') +const MiniCssExtractPlugin = require('mini-css-extract-plugin') +const webpack = require('webpack') +const path = require('path') module.exports = (env, argv) => { - const mode = argv.mode || 'development'; + const mode = argv.mode || 'development' return { mode: mode || 'development', @@ -45,5 +45,5 @@ module.exports = (env, argv) => { 'process.env.NODE_ENV': JSON.stringify(mode) }) ] - }; -}; + } +} From f3d3d8a5a8d0f467371e29c77d8e4c618e3f5bb3 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Nov 2018 15:06:36 -0500 Subject: [PATCH 9/9] standardify --- api/controllers/AuthController.js | 68 +++++------ api/controllers/BooksController.js | 34 +++--- api/controllers/TargetController.js | 4 +- api/controllers/UserController.js | 20 +-- api/helpers/passport.js | 144 +++++++++++----------- api/hooks/passport/index.js | 15 ++- api/models/Book.js | 7 +- api/models/Passport.js | 30 ++--- api/models/User.js | 2 +- api/policies/sessionAuth.js | 6 +- assets/js/actions/login.js | 76 ++++++------ assets/js/components/Progress.js | 4 +- assets/js/lib/Ajax.js | 168 +++++++++++++------------- assets/js/reducers/login.js | 26 ++-- config/auth.js | 2 +- config/blueprints.js | 4 +- config/bootstrap.js | 8 +- config/custom.js | 2 +- config/datastores.js | 6 +- config/env/development.js | 2 +- config/env/production.js | 6 +- config/globals.js | 4 +- config/http.js | 10 +- config/i18n.js | 4 +- config/log.js | 2 +- config/models.js | 18 +-- config/passport.js | 2 +- config/policies.js | 2 +- config/protocols.js | 64 +++++----- config/routes.js | 7 +- config/security.js | 3 +- config/session.js | 5 +- config/sockets.js | 6 +- config/views.js | 2 +- tasks/config/babel.js | 8 +- tasks/config/clean.js | 8 +- tasks/config/coffee.js | 8 +- tasks/config/concat.js | 8 +- tasks/config/copy.js | 10 +- tasks/config/cssmin.js | 8 +- tasks/config/hash.js | 14 +-- tasks/config/jst.js | 9 +- tasks/config/less.js | 8 +- tasks/config/sails-linker.js | 23 ++-- tasks/config/sync.js | 8 +- tasks/config/uglify.js | 11 +- tasks/config/watch.js | 8 +- tasks/pipeline.js | 38 +++--- tasks/register/build.js | 6 +- tasks/register/buildProd.js | 15 ++- tasks/register/compileAssets.js | 6 +- tasks/register/default.js | 8 +- tasks/register/linkAssets.js | 6 +- tasks/register/linkAssetsBuild.js | 6 +- tasks/register/linkAssetsBuildProd.js | 6 +- tasks/register/polyfill.js | 27 ++--- tasks/register/prod.js | 13 +- tasks/register/syncAssets.js | 6 +- 58 files changed, 482 insertions(+), 549 deletions(-) diff --git a/api/controllers/AuthController.js b/api/controllers/AuthController.js index 7885754..c46a6bc 100644 --- a/api/controllers/AuthController.js +++ b/api/controllers/AuthController.js @@ -11,15 +11,15 @@ module.exports = { emailExists: async function (req, res) { const user = await User.findOne({ email: req.param('email') - }); + }) if (!user) { return res.status(404).json({ error: 'user does not exist' - }); + }) } else { return res.json({ status: 'ok' - }); + }) } }, /** @@ -28,15 +28,15 @@ module.exports = { emailAvailable: async function (req, res) { const user = await User.findOne({ email: req.param('email') - }); + }) if (user) { return res.status(401).json({ error: 'that email address is not available' - }); + }) } else { return res.json({ status: 'ok' - }); + }) } }, @@ -55,15 +55,15 @@ module.exports = { * @param {Object} res */ logout: function (req, res) { - req.logout(); - delete req.user; - delete req.session.passport; - req.session.authenticated = false; + req.logout() + delete req.user + delete req.session.passport + req.session.authenticated = false if (!req.isSocket) { - res.redirect(req.query.next || '/'); + res.redirect(req.query.next || '/') } else { - res.ok(); + res.ok() } }, @@ -74,8 +74,8 @@ module.exports = { * @param {Object} res */ provider: async function (req, res) { - const passportHelper = await sails.helpers.passport(); - passportHelper.endpoint(req, res); + const passportHelper = await sails.helpers.passport() + passportHelper.endpoint(req, res) }, /** @@ -95,51 +95,51 @@ module.exports = { * @param {Object} res */ callback: async function (req, res) { - const action = req.param('action'); - const passportHelper = await sails.helpers.passport(); + const action = req.param('action') + const passportHelper = await sails.helpers.passport() function negotiateError (err) { if (action === 'register') { - res.redirect('/register'); + res.redirect('/register') } else if (action === 'login') { - res.redirect('/login'); + res.redirect('/login') } else if (action === 'disconnect') { - res.redirect('back'); + res.redirect('back') } else { // make sure the server always returns a response to the client // i.e passport-local bad username/email or password res.status(401).json({ 'error': err.toString() - }); + }) } } passportHelper.callback(req, res, (err, user, info, status) => { if (err || !user) { - sails.log.warn(user, err, info, status); + sails.log.warn(user, err, info, status) if (!err && info) { - return negotiateError(info); + return negotiateError(info) } - return negotiateError(err); + return negotiateError(err) } req.login(user, (err) => { if (err) { - sails.log.warn(err); - return negotiateError(err); + sails.log.warn(err) + return negotiateError(err) } - req.session.authenticated = true; + req.session.authenticated = true // redirect if there is a 'next' param if (req.query.next) { - res.status(302).set('Location', req.query.next); + res.status(302).set('Location', req.query.next) } - sails.log.info('user', user, 'authenticated successfully'); - return res.json(user); - }); - }); + sails.log.info('user', user, 'authenticated successfully') + return res.json(user) + }) + }) }, /** @@ -149,7 +149,7 @@ module.exports = { * @param {Object} res */ disconnect: async function (req, res) { - const passportHelper = await sails.helpers.passport(); - passportHelper.disconnect(req, res); + const passportHelper = await sails.helpers.passport() + passportHelper.disconnect(req, res) } -}; +} diff --git a/api/controllers/BooksController.js b/api/controllers/BooksController.js index 32311a9..9617b08 100644 --- a/api/controllers/BooksController.js +++ b/api/controllers/BooksController.js @@ -8,48 +8,48 @@ module.exports = { publish: async function (req, res) { try { - const body = req.body; - const host = req.hostname; - let result; + const body = req.body + const host = req.hostname + let result - if (!host) { throw new Error('Missing hostname'); } - if (!body) {throw new Error('Missing body'); } + if (!host) { throw new Error('Missing hostname') } + if (!body) { throw new Error('Missing body') } - const bookExists = await Book.findOne(body); + const bookExists = await Book.findOne(body) if (bookExists) { - throw new Error('Version already exists'); + throw new Error('Version already exists') } else { - result = await Book.create(body); + result = await Book.create(body) } return res.json({ ...result - }); + }) } catch (e) { return res.status(400).json({ error: e.message - }); + }) } }, list: async function (req, res) { try { - const body = req.allParams(); - if (!body) { throw new Error('Missing parameters'); } + const body = req.allParams() + if (!body) { throw new Error('Missing parameters') } - const books = await Book.find(body); + const books = await Book.find(body) if (!books.length) { return res.status(404).json({ error: 'No books matching those parameters were found.' - }); + }) } - return res.json(books); + return res.json(books) } catch (e) { return res.status(500).json({ error: e.message - }); + }) } } -}; +} diff --git a/api/controllers/TargetController.js b/api/controllers/TargetController.js index 75f2b38..5f44a14 100644 --- a/api/controllers/TargetController.js +++ b/api/controllers/TargetController.js @@ -3,6 +3,6 @@ module.exports = { res.view('pages/temp', { email: req.user.email - }); + }) } -}; \ No newline at end of file +} diff --git a/api/controllers/UserController.js b/api/controllers/UserController.js index 3efcaff..9751f93 100644 --- a/api/controllers/UserController.js +++ b/api/controllers/UserController.js @@ -10,31 +10,31 @@ module.exports = { * @override */ create: async function (req, res, next) { - const passportHelper = await sails.helpers.passport(); + const passportHelper = await sails.helpers.passport() passportHelper.protocols.local.register(req.body, (err, user) => { if (err) { return res.status(500).json({ - error: err.toString() }); + error: err.toString() }) } - res.json(user); - }); + res.json(user) + }) }, update: async function (req, res, next) { - const passportHelper = await sails.helpers.passport(); + const passportHelper = await sails.helpers.passport() passportHelper.protocols.local.update(req.body, (err, user) => { if (err) { return res.status(500).json({ error: err.toString() - }); + }) } - res.json(user); - }); + res.json(user) + }) }, me: function (req, res) { - res.json(req.user); + res.json(req.user) } -}; \ No newline at end of file +} diff --git a/api/helpers/passport.js b/api/helpers/passport.js index 5fe980e..081f73c 100644 --- a/api/helpers/passport.js +++ b/api/helpers/passport.js @@ -1,7 +1,7 @@ // api/helpers/passport.js // from https://github.com/trailsjs/sails-auth/blob/master/api/services/passport.js -const url = require('url'); +const url = require('url') module.exports = { friendlyName: 'Load PassportHelper', @@ -14,158 +14,158 @@ module.exports = { } }, fn: async function (inputs, exits) { - return exits.success(new PassportHelper()); + return exits.success(new PassportHelper()) } -}; +} -const passport = require('passport'); +const passport = require('passport') passport.serializeUser((user, next) => { - next(null, user.id); -}); + next(null, user.id) +}) passport.deserializeUser((id, next) => { return User.findOne({id: id}) .then((user) => { - next(null, user); - return user; - }).catch(next); -}); + next(null, user) + return user + }).catch(next) +}) function PassportHelper () { - this.protocols = sails.config.protocols; + this.protocols = sails.config.protocols this.loadStrategies = function () { - const strategies = sails.config.passport; + const strategies = sails.config.passport for (const key in strategies) { - let options = {passReqToCallback: true}; - let Strategy = strategies[key].strategy; + let options = {passReqToCallback: true} + let Strategy = strategies[key].strategy if (key === 'local') { _.extend(options, { usernameField: 'identifier' - }); - passport.use(new Strategy(options, this.protocols.local.login)); + }) + passport.use(new Strategy(options, this.protocols.local.login)) } else { - const protocol = strategies[key].protocol; - const callbackURL = strategies[key].callback; - let baseURL = ''; + const protocol = strategies[key].protocol + const callbackURL = strategies[key].callback + let baseURL = '' if (sails.config.appUrl && sails.config.appUrl !== null) { - baseURL = sails.config.appUrl; + baseURL = sails.config.appUrl } else { - sails.log.warn('Please add \'appUrl\' to configuration'); - baseURL = sails.getBaseurl(); + sails.log.warn('Please add \'appUrl\' to configuration') + baseURL = sails.getBaseurl() } switch (protocol) { case 'oauth2': - options.callbackURL = url.resolve(baseURL, callbackURL); - break; + options.callbackURL = url.resolve(baseURL, callbackURL) + break // other protocols (openid, etc can go here) } - _.extend(options, strategies[key].options); + _.extend(options, strategies[key].options) - passport.use(new Strategy(options, this.protocols[protocol].login)); + passport.use(new Strategy(options, this.protocols[protocol].login)) } } - }; + } this.endpoint = function (req, res) { - const strategies = sails.config.passport; - const provider = req.param('provider'); + const strategies = sails.config.passport + const provider = req.param('provider') - if (!_.has(strategies, provider)) {return res.redirect('/login');} + if (!_.has(strategies, provider)) { return res.redirect('/login') } - passport.authenticate(provider, {})(req, res, req.next); - }; + passport.authenticate(provider, {})(req, res, req.next) + } // a callback helper to split by req this.callback = function (req, res, next) { - var provider = req.param('provider', 'local'); - var action = req.param('action'); + var provider = req.param('provider', 'local') + var action = req.param('action') if (provider === 'local' && action !== undefined) { if (action === 'register' && !req.user) { - this.protocols.local.register(req, res, next); + this.protocols.local.register(req, res, next) } else if (action === 'connect' && req.user) { - this.protocols.local.connect(req, res, next); + this.protocols.local.connect(req, res, next) } else if (action === 'disconnect' && req.user) { - this.protocols.local.disconnect(req, res, next); + this.protocols.local.disconnect(req, res, next) } else { - return next(new Error('Invalid action')); + return next(new Error('Invalid action')) } } else { if (action === 'disconnect' && req.user) { - this.disconnect(req, res, next); + this.disconnect(req, res, next) } else { - passport.authenticate(provider, next)(req, res, req.next); + passport.authenticate(provider, next)(req, res, req.next) } } - }; + } this.connect = async function (req, q, profile, next) { - let userAttrs = {}; - let provider = profile.provider || req.param('provider'); + let userAttrs = {} + let provider = profile.provider || req.param('provider') - req.session.tokens = q.tokens; - q.provider = provider; + req.session.tokens = q.tokens + q.provider = provider if (!provider) { - return next(new Error('No provider identified')); + return next(new Error('No provider identified')) } // if the profile object from passport has an email, use it - if (profile.emails && profile.emails[0]) {userAttrs.email = profile.emails[0].value;} - if (!userAttrs.email) {return next(new Error('No email available'));} + if (profile.emails && profile.emails[0]) { userAttrs.email = profile.emails[0].value } + if (!userAttrs.email) { return next(new Error('No email available')) } const pass = await Passport.findOne({ provider, identifier: q.identifier.toString() - }); + }) - let user; + let user if (!req.user) { if (!passport) { // new user signing up, create a new user - user = await User.create(userAttrs).fetch(); + user = await User.create(userAttrs).fetch() await Passport.create({ ...q, user: user.id - }); - return next(null, user); + }) + return next(null, user) } else { // existing user logging in if (_.has(q, 'tokens') && q.tokens !== passport.tokens) { - passport.tokens = q.tokens; + passport.tokens = q.tokens } - await passport.save(); - user = User.findOne(passport.user); - return next(null, user); + await passport.save() + user = User.findOne(passport.user) + return next(null, user) } } else { // user logged in and trying to add new Passport if (!passport) { await Passport.create({ ...q, user: req.user.id - }); - return next(null, req.user); + }) + return next(null, req.user) } else { // no action, user already logged in and passport exists - return next(null, user); + return next(null, user) } } - }; + } this.disconnect = async function (req, res, next) { try { - const user = req.user; - const provider = req.param('provider'); + const user = req.user + const provider = req.param('provider') const pass = Passport.findOne({ provider, user: user.id - }); - await Passport.destroy(pass.id); - next(null, user); - return user; + }) + await Passport.destroy(pass.id) + next(null, user) + return user } catch (e) { - return next(e); + return next(e) } - }; + } this.getPassport = function () { - return passport; - }; -} \ No newline at end of file + return passport + } +} diff --git a/api/hooks/passport/index.js b/api/hooks/passport/index.js index 72c98ca..a3864d7 100644 --- a/api/hooks/passport/index.js +++ b/api/hooks/passport/index.js @@ -1,16 +1,15 @@ -let passportHook = sails.hooks.passport; - +let passportHook = sails.hooks.passport if (!passportHook) { passportHook = function (sails) { return { initialize: async function (cb) { - const helper = await sails.helpers.passport(); - helper.loadStrategies(); - return cb(); + const helper = await sails.helpers.passport() + helper.loadStrategies() + return cb() } - }; - }; + } + } } -module.exports = passportHook; +module.exports = passportHook diff --git a/api/models/Book.js b/api/models/Book.js index 145ef07..7971f47 100644 --- a/api/models/Book.js +++ b/api/models/Book.js @@ -20,17 +20,16 @@ module.exports = { title: {type: 'string', required: true}, author: {type: 'string'}, isbn: {type: 'string'}, - version: {type: 'string'}, + version: {type: 'string'} // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ // ║╣ ║║║╠╩╗║╣ ║║╚═╗ // ╚═╝╩ ╩╚═╝╚═╝═╩╝╚═╝ - // ╔═╗╔═╗╔═╗╔═╗╔═╗╦╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ // ╠═╣╚═╗╚═╗║ ║║ ║╠═╣ ║ ║║ ║║║║╚═╗ // ╩ ╩╚═╝╚═╝╚═╝╚═╝╩╩ ╩ ╩ ╩╚═╝╝╚╝╚═╝ - }, + } -}; +} diff --git a/api/models/Passport.js b/api/models/Passport.js index bc187a2..f23be50 100644 --- a/api/models/Passport.js +++ b/api/models/Passport.js @@ -1,18 +1,18 @@ -const bcrypt = require('bcrypt'); +const bcrypt = require('bcrypt') async function hashPassword (passport) { try { - var config = sails.config.auth.bcrypt; - var salt = config.rounds; + var config = sails.config.auth.bcrypt + var salt = config.rounds if (passport.password) { - const hash = await bcrypt.hash(passport.password, salt); - passport.password = hash; + const hash = await bcrypt.hash(passport.password, salt) + passport.password = hash } - return passport; + return passport } catch (e) { - delete passport.password; - sails.log.error(e); - throw e; + delete passport.password + sails.log.error(e) + throw e } } @@ -52,20 +52,20 @@ module.exports = { * callback run before creating a Passport */ beforeCreate: async function (passport, next) { - await hashPassword(passport); - return next(); + await hashPassword(passport) + return next() }, /** * callback run before updating */ beforeUpdate: async function (passport, next) { - await hashPassword(passport); - return next(); + await hashPassword(passport) + return next() }, // methods validatePassword: async function (password, passport) { - return bcrypt.compare(password, passport.password); + return bcrypt.compare(password, passport.password) } -}; +} diff --git a/api/models/User.js b/api/models/User.js index a6ee2a2..480dfe2 100644 --- a/api/models/User.js +++ b/api/models/User.js @@ -32,4 +32,4 @@ module.exports = { } -}; +} diff --git a/api/policies/sessionAuth.js b/api/policies/sessionAuth.js index 1876c71..1d22cbd 100644 --- a/api/policies/sessionAuth.js +++ b/api/policies/sessionAuth.js @@ -7,8 +7,8 @@ */ module.exports = function (req, res, next) { if (req.session.authenticated) { - return next(); + return next() } - res.status(403).json({ error: 'You are not permitted to perform this action.' }); + res.status(403).json({ error: 'You are not permitted to perform this action.' }) // res.redirect('/login') -}; +} diff --git a/assets/js/actions/login.js b/assets/js/actions/login.js index 2fe6aba..c35e747 100644 --- a/assets/js/actions/login.js +++ b/assets/js/actions/login.js @@ -1,6 +1,6 @@ -'use strict'; +'use strict' -import Ajax from '../lib/Ajax'; +import Ajax from '../lib/Ajax' const ACTIONS = { set_working: 'set_working', @@ -9,50 +9,50 @@ const ACTIONS = { set_carousel: 'set_carousel', set_error: 'set_error', clear_error: 'clear_error' -}; +} -export default ACTIONS; +export default ACTIONS export const setWorking = working => ({ type: ACTIONS.set_working, data: working -}); +}) export const setEmail = email => ({ type: ACTIONS.set_user, data: email -}); +}) export const setPassword = pass => ({ type: ACTIONS.set_password, data: pass -}); +}) export const setCarousel = pos => (dispatch, getState) => { - dispatch(clearError()); + dispatch(clearError()) dispatch({ type: ACTIONS.set_carousel, data: pos - }); -}; + }) +} export const setError = data => ({ type: ACTIONS.set_error, data: data -}); +}) export const clearError = () => ({ type: ACTIONS.clear_error -}); +}) export const setLoggedIn = (data) => (dispatch, getState) => { - window.localStorage.setItem('roe-token', JSON.stringify(data)); - window.location.href = '/app'; -}; + window.localStorage.setItem('roe-token', JSON.stringify(data)) + window.location.href = '/app' +} export const checkEmail = email => async (dispatch, getState) => { - dispatch(setWorking(true)); - dispatch(clearError()); + dispatch(setWorking(true)) + dispatch(clearError()) if (/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(email)) { try { const res = await Ajax.post({ @@ -60,25 +60,25 @@ export const checkEmail = email => async (dispatch, getState) => { data: { email } - }); - dispatch(setCarousel(2)); + }) + dispatch(setCarousel(2)) } catch (e) { dispatch(setError({ type: 'email', error: 'An account with that email does not exist.' - })); + })) } } else { dispatch(setError({ type: 'email', error: 'Please enter a valid email address.' - })); + })) } - dispatch(setWorking(false)); -}; + dispatch(setWorking(false)) +} export const checkPassword = (email, password) => async (dispatch, getState) => { - dispatch(setWorking(true)); + dispatch(setWorking(true)) // do email + password check try { @@ -88,21 +88,21 @@ export const checkPassword = (email, password) => async (dispatch, getState) => identifier: email, password } - }); - dispatch(setLoggedIn(res)); + }) + dispatch(setLoggedIn(res)) // dispatch(setWorking(false)) } catch (e) { dispatch(setError({ type: 'password', error: e.toString() - })); - dispatch(setWorking(false)); + })) + dispatch(setWorking(false)) } -}; +} export const signup = (email, password) => async (dispatch, getState) => { - dispatch(setWorking(true)); - dispatch(clearError()); + dispatch(setWorking(true)) + dispatch(clearError()) if (/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$/.test(email)) { try { await Ajax.post({ @@ -110,26 +110,26 @@ export const signup = (email, password) => async (dispatch, getState) => { data: { email } - }); + }) await Ajax.post({ url: '/register', data: { email, password } - }); - dispatch(setCarousel(2)); + }) + dispatch(setCarousel(2)) } catch (e) { dispatch(setError({ type: 'email', error: e.toString() - })); + })) } } else { dispatch(setError({ type: 'email', error: 'Please enter a valid email address.' - })); + })) } - dispatch(setWorking(false)); -}; + dispatch(setWorking(false)) +} diff --git a/assets/js/components/Progress.js b/assets/js/components/Progress.js index d2d46db..e3177c4 100644 --- a/assets/js/components/Progress.js +++ b/assets/js/components/Progress.js @@ -1,6 +1,6 @@ -'use strict'; +'use strict' -import React from 'react'; +import React from 'react' const Progress = props => (
    diff --git a/assets/js/lib/Ajax.js b/assets/js/lib/Ajax.js index 80f256c..f983b5d 100644 --- a/assets/js/lib/Ajax.js +++ b/assets/js/lib/Ajax.js @@ -1,162 +1,162 @@ /* global XMLHttpRequest FormData */ -'use strict'; +'use strict' -let ajaxcfg = {}; +let ajaxcfg = {} class AjaxError extends Error { constructor (reason, data, xhr) { - super(reason); - this.data = data; - this.xhr = xhr; + super(reason) + this.data = data + this.xhr = xhr } } export default class Ajax { static async get (opts) { - if (!opts) {opts = {};} - opts.method = 'get'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'get' + return Ajax.ajax(opts) } static async post (opts) { - if (!opts) {opts = {};} - opts.method = 'post'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'post' + return Ajax.ajax(opts) } static async put (opts) { - if (!opts) {opts = {};} - opts.method = 'put'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'put' + return Ajax.ajax(opts) } static async patch (opts) { - if (!opts) {opts = {};} - opts.method = 'patch'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'patch' + return Ajax.ajax(opts) } static async delete (opts) { - if (!opts) {opts = {};} - opts.method = 'delete'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'delete' + return Ajax.ajax(opts) } static async head (opts) { - if (!opts) {opts = {};} - opts.method = 'head'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'head' + return Ajax.ajax(opts) } static async options (opts) { - if (!opts) {opts = {};} - opts.method = 'options'; - return Ajax.ajax(opts); + if (!opts) { opts = {} } + opts.method = 'options' + return Ajax.ajax(opts) } static ajax (opts) { return new Promise((resolve, reject) => { - if (!opts) {reject(new Error('Missing required options parameter.'));} + if (!opts) { reject(new Error('Missing required options parameter.')) } if (opts.method) { - if (!['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(opts.method.toLowerCase())) {reject(new Error('opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.'));} - opts.method = opts.method.toUpperCase(); + if (!['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(opts.method.toLowerCase())) { reject(new Error('opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.')) } + opts.method = opts.method.toUpperCase() } - var xhr = opts.xhr || new XMLHttpRequest(); + var xhr = opts.xhr || new XMLHttpRequest() - var fd = null; - var qs = ''; + var fd = null + var qs = '' if (opts.data && opts.method.toLowerCase() !== 'get') { - fd = new FormData(); + fd = new FormData() for (let key in opts.data) { - fd.append(key, opts.data[key]); + fd.append(key, opts.data[key]) } } else if (opts.data) { - qs += '?'; - let params = []; + qs += '?' + let params = [] for (let key in opts.data) { - params.push([key, opts.data[key]].join('=')); + params.push([key, opts.data[key]].join('=')) } - qs += params.join('&'); + qs += params.join('&') } xhr.onload = () => { - if (xhr.status !== 200) {return xhr.onerror();} - var data = xhr.response; + if (xhr.status !== 200) { return xhr.onerror() } + var data = xhr.response resolve({ data, xhr - }); - }; + }) + } xhr.onerror = () => { - var data = xhr.response; + var data = xhr.response // method not allowed if (xhr.status === 405) { - reject(new AjaxError('405 Method Not Allowed', data, xhr)); - return; + reject(new AjaxError('405 Method Not Allowed', data, xhr)) + return } else if (xhr.status === 404) { - reject(new AjaxError('404 Not Found', data, xhr)); - return; + reject(new AjaxError('404 Not Found', data, xhr)) + return } try { // if the access token is invalid, try to use the refresh token - var json = JSON.parse(data); + var json = JSON.parse(data) if (json.error === 'access_denied' && json.hint.includes('token') && json.hint.includes('invalid') && ajaxcfg.refresh_token) { - return Ajax.refresh(opts); + return Ajax.refresh(opts) } else if (json.error === 'access_denied' && json.hint.includes('token') && json.hint.includes('revoked')) { - reject(new AjaxError('token revoked', data, xhr)); + reject(new AjaxError('token revoked', data, xhr)) } } catch (e) { - reject(new AjaxError(e.toString(), data, xhr)); + reject(new AjaxError(e.toString(), data, xhr)) } finally { - reject(new AjaxError(data, xhr.status, xhr)); + reject(new AjaxError(data, xhr.status, xhr)) } - }; - - xhr.open(opts.method || 'GET', opts.url + qs || window.location.href); - if (opts.headers) { - for (let key in opts.headers) {xhr.setRequestHeader(key, opts.headers[key]);} } - if (ajaxcfg.access_token && !(opts.headers || {}).Authorization) {xhr.setRequestHeader('Authorization', 'Bearer ' + ajaxcfg.access_token);} - xhr.send(fd); - }); + + xhr.open(opts.method || 'GET', opts.url + qs || window.location.href) + if (opts.headers) { + for (let key in opts.headers) { xhr.setRequestHeader(key, opts.headers[key]) } + } + if (ajaxcfg.access_token && !(opts.headers || {}).Authorization) { xhr.setRequestHeader('Authorization', 'Bearer ' + ajaxcfg.access_token) } + xhr.send(fd) + }) } static refresh (opts) { return new Promise((resolve, reject) => { - var xhr = new XMLHttpRequest(); + var xhr = new XMLHttpRequest() - var fd = new FormData(); + var fd = new FormData() const OAUTH_TOKEN_REQUEST = { grant_type: 'refresh_token', refresh_token: ajaxcfg.refresh_token, client_id: 'foxfile', client_secret: 1 - }; + } for (var key in OAUTH_TOKEN_REQUEST) { - fd.append(key, OAUTH_TOKEN_REQUEST[key]); + fd.append(key, OAUTH_TOKEN_REQUEST[key]) } // try original request xhr.onload = () => { - if (xhr.status !== 200) {return xhr.onerror();} - if (ajaxcfg.refresh) {ajaxcfg.refresh(xhr.response);} - var json = JSON.parse(xhr.response); - ajaxcfg.access_token = json.access_token; - ajaxcfg.refresh_token = json.refresh_token; - return Ajax.ajax(opts); - }; + if (xhr.status !== 200) { return xhr.onerror() } + if (ajaxcfg.refresh) { ajaxcfg.refresh(xhr.response) } + var json = JSON.parse(xhr.response) + ajaxcfg.access_token = json.access_token + ajaxcfg.refresh_token = json.refresh_token + return Ajax.ajax(opts) + } // if this fails, dont try again xhr.onerror = () => { - var data = xhr.response; - reject(new AjaxError(xhr.status, data, xhr)); - }; - xhr.open('POST', ajaxcfg.refresh_url); - xhr.send(fd); - }); + var data = xhr.response + reject(new AjaxError(xhr.status, data, xhr)) + } + xhr.open('POST', ajaxcfg.refresh_url) + xhr.send(fd) + }) } static setTokenData (tokens) { - if (!tokens) {throw new Error('Missing tokens.');} - if (!tokens.access_token && !tokens.refresh_token && !tokens.refresh_url) {throw new Error('Missing at least one of: access_token, refresh_token, refresh_url.');} - if (tokens.access_token) {ajaxcfg.access_token = tokens.access_token;} - if (tokens.refresh_token) {ajaxcfg.refresh_token = tokens.refresh_token;} - if (tokens.refresh_url) {ajaxcfg.refresh_url = tokens.refresh_url;} - return true; + if (!tokens) { throw new Error('Missing tokens.') } + if (!tokens.access_token && !tokens.refresh_token && !tokens.refresh_url) { throw new Error('Missing at least one of: access_token, refresh_token, refresh_url.') } + if (tokens.access_token) { ajaxcfg.access_token = tokens.access_token } + if (tokens.refresh_token) { ajaxcfg.refresh_token = tokens.refresh_token } + if (tokens.refresh_url) { ajaxcfg.refresh_url = tokens.refresh_url } + return true } static onRefresh (func) { - ajaxcfg.refresh = func; + ajaxcfg.refresh = func } } diff --git a/assets/js/reducers/login.js b/assets/js/reducers/login.js index 7a084c8..6495974 100644 --- a/assets/js/reducers/login.js +++ b/assets/js/reducers/login.js @@ -1,9 +1,9 @@ -'use strict'; +'use strict' -import Actions from '../actions/login'; +import Actions from '../actions/login' const reducer = (state = {}, action) => { - const {type, data} = action; + const {type, data} = action switch (type) { case Actions.set_user: return { @@ -11,40 +11,40 @@ const reducer = (state = {}, action) => { ...state.user, email: data } - }; + } case Actions.set_password: return { user: { ...state.user, password: data } - }; + } case Actions.set_carousel: return { carouselPosition: data - }; + } case Actions.set_working: return { working: data - }; + } case Actions.set_error: switch (data.type) { case 'email': return { emailError: data.error - }; + } case 'password': return { passwordError: data.error - }; - default: return {}; + } + default: return {} } case Actions.clear_error: return { emailError: '', passwordError: '' - }; + } } -}; +} -export default reducer; +export default reducer diff --git a/config/auth.js b/config/auth.js index 76ba7a7..2c988ad 100644 --- a/config/auth.js +++ b/config/auth.js @@ -2,4 +2,4 @@ module.exports.auth = { bcrypt: { rounds: 8 } -}; +} diff --git a/config/blueprints.js b/config/blueprints.js index e8552ef..ff18237 100644 --- a/config/blueprints.js +++ b/config/blueprints.js @@ -19,7 +19,6 @@ module.exports.blueprints = { // actions: false, - /*************************************************************************** * * * Automatically expose RESTful routes for your models? * @@ -28,7 +27,6 @@ module.exports.blueprints = { // rest: true, - /*************************************************************************** * * * Automatically expose CRUD "shortcut" routes to GET requests? * @@ -38,4 +36,4 @@ module.exports.blueprints = { // shortcuts: true, -}; +} diff --git a/config/bootstrap.js b/config/bootstrap.js index eef35d8..6847491 100644 --- a/config/bootstrap.js +++ b/config/bootstrap.js @@ -9,8 +9,7 @@ * https://sailsjs.com/config/bootstrap */ -module.exports.bootstrap = async function(done) { - +module.exports.bootstrap = async function (done) { // By convention, this is a good place to set up fake data during development. // // For example: @@ -29,6 +28,5 @@ module.exports.bootstrap = async function(done) { // Don't forget to trigger `done()` when this bootstrap function's logic is finished. // (otherwise your server will never lift, since it's waiting on the bootstrap) - return done(); - -}; + return done() +} diff --git a/config/custom.js b/config/custom.js index 827e3bf..bca7951 100644 --- a/config/custom.js +++ b/config/custom.js @@ -20,4 +20,4 @@ module.exports.custom = { // stripeSecret: 'sk_test_Zzd814nldl91104qor5911gjald', // … -}; +} diff --git a/config/datastores.js b/config/datastores.js index 3853184..0dbb212 100644 --- a/config/datastores.js +++ b/config/datastores.js @@ -15,7 +15,6 @@ module.exports.datastores = { - /*************************************************************************** * * * Your app's default datastore. * @@ -51,7 +50,6 @@ module.exports.datastores = { // adapter: 'sails-mysql', // url: 'mysql://user:password@host:port/database', - }, + } - -}; +} diff --git a/config/env/development.js b/config/env/development.js index 22da3e5..e01af2e 100644 --- a/config/env/development.js +++ b/config/env/development.js @@ -367,4 +367,4 @@ module.exports = { } -}; +} diff --git a/config/env/production.js b/config/env/production.js index d0cee3a..c254b2e 100644 --- a/config/env/production.js +++ b/config/env/production.js @@ -238,8 +238,8 @@ module.exports = { * * ***************************************************************************/ onlyAllowOrigins: [ - 'https://ec2-18-219-76-43.us-east-2.compute.amazonaws.com', - ], + 'https://ec2-18-219-76-43.us-east-2.compute.amazonaws.com' + ] /*************************************************************************** * * @@ -366,4 +366,4 @@ module.exports = { } -}; +} diff --git a/config/globals.js b/config/globals.js index b652ad8..279d789 100644 --- a/config/globals.js +++ b/config/globals.js @@ -47,6 +47,6 @@ module.exports.globals = { * * ****************************************************************************/ - sails: true, + sails: true -}; +} diff --git a/config/http.js b/config/http.js index 0c5c845..88d7de2 100644 --- a/config/http.js +++ b/config/http.js @@ -9,14 +9,14 @@ * https://sailsjs.com/config/http */ -const rateLimit = require('express-rate-limit'); +const rateLimit = require('express-rate-limit') const rateLimiter = rateLimit({ windowMs: 10 * 60 * 1000, // 10 minutes max: 100, // limit each IP to 100 requests per windowMs skip (req, res) { - return !req.path.startsWith('/api'); + return !req.path.startsWith('/api') } -}); +}) module.exports.http = { @@ -53,7 +53,7 @@ module.exports.http = { ], rateLimit: rateLimiter, passportInit: require('passport').initialize(), - passportSession: require('passport').session(), + passportSession: require('passport').session() /*************************************************************************** * * @@ -69,4 +69,4 @@ module.exports.http = { // return middlewareFn; // })(), } -}; +} diff --git a/config/i18n.js b/config/i18n.js index 0b652d2..a2f394a 100644 --- a/config/i18n.js +++ b/config/i18n.js @@ -20,7 +20,7 @@ module.exports.i18n = { * * ***************************************************************************/ - locales: ['en', 'es', 'fr', 'de'], + locales: ['en', 'es', 'fr', 'de'] /**************************************************************************** * * @@ -42,4 +42,4 @@ module.exports.i18n = { // localesDirectory: 'config/locales' -}; +} diff --git a/config/log.js b/config/log.js index 1ef07f5..ec295be 100644 --- a/config/log.js +++ b/config/log.js @@ -26,4 +26,4 @@ module.exports.log = { // level: 'info' -}; +} diff --git a/config/models.js b/config/models.js index 84680bd..132079c 100644 --- a/config/models.js +++ b/config/models.js @@ -15,7 +15,6 @@ module.exports.models = { - /*************************************************************************** * * * Whether the `.create()` and `.update()` model methods should ignore * @@ -37,7 +36,6 @@ module.exports.models = { // schema: true, - /*************************************************************************** * * * How and whether Sails will attempt to automatically rebuild the * @@ -55,7 +53,6 @@ module.exports.models = { // migrate: 'alter', - /*************************************************************************** * * * Base attributes that are included in all of your models by default. * @@ -69,10 +66,10 @@ module.exports.models = { ***************************************************************************/ attributes: { - createdAt: { type: 'number', autoCreatedAt: true, }, - updatedAt: { type: 'number', autoUpdatedAt: true, }, - id: { type: 'number', autoIncrement: true, }, - //-------------------------------------------------------------------------- + createdAt: { type: 'number', autoCreatedAt: true }, + updatedAt: { type: 'number', autoUpdatedAt: true }, + id: { type: 'number', autoIncrement: true } + // -------------------------------------------------------------------------- // /\ Using MongoDB? // || Replace `id` above with this instead: // @@ -82,10 +79,9 @@ module.exports.models = { // // Plus, don't forget to configure MongoDB as your default datastore: // https://sailsjs.com/docs/tutorials/using-mongo-db - //-------------------------------------------------------------------------- + // -------------------------------------------------------------------------- }, - /****************************************************************************** * * * The set of DEKs (data encryption keys) for at-rest encryption. * @@ -104,7 +100,6 @@ module.exports.models = { default: 'nuF29j3StsGhRTut9dIrCxCNyYegcwH30FxnZ3kkdiA=' }, - /*************************************************************************** * * * Whether or not implicit records for associations should be cleaned up * @@ -120,5 +115,4 @@ module.exports.models = { cascadeOnDestroy: true - -}; +} diff --git a/config/passport.js b/config/passport.js index 8f1470a..7f54c0d 100644 --- a/config/passport.js +++ b/config/passport.js @@ -6,4 +6,4 @@ module.exports.passport = { local: { strategy: require('passport-local').Strategy } -}; +} diff --git a/config/policies.js b/config/policies.js index 84b60fe..4c1514c 100644 --- a/config/policies.js +++ b/config/policies.js @@ -34,4 +34,4 @@ module.exports.policies = { TargetController: { '*': [ 'sessionAuth' ] } -}; +} diff --git a/config/protocols.js b/config/protocols.js index 5afe4e3..da7f609 100644 --- a/config/protocols.js +++ b/config/protocols.js @@ -1,6 +1,6 @@ // Passport protocol configurations -const crypto = require('crypto'); -const base64URL = require('base64url'); +const crypto = require('crypto') +const base64URL = require('base64url') module.exports.protocols = { local: { @@ -18,87 +18,87 @@ module.exports.protocols = { */ login: async function (req, identifier, password, next) { if (!validateEmail(identifier)) { - return next(new Error('invalid email address'), false); + return next(new Error('invalid email address'), false) } try { const user = await User.findOne({ email: identifier - }); - if (!user) {throw new Error('an account with that email was not found');} + }) + if (!user) { throw new Error('an account with that email was not found') } const passport = await Passport.findOne({ protocol: 'local', user: user.id - }); + }) if (passport) { - const res = await Passport.validatePassword(password, passport); - if (!res) {throw new Error('incorrect password');} - return next(null, user); + const res = await Passport.validatePassword(password, passport) + if (!res) { throw new Error('incorrect password') } + return next(null, user) } else { - throw new Error('that account does not have password login enabled'); + throw new Error('that account does not have password login enabled') } } catch (e) { - return next(e, false); + return next(e, false) } }, register: async function (user, next) { try { - const token = generateToken(); - const password = user.password; - if (!password.length) {throw new Error('password cannot be blank');} - delete user.password; + const token = generateToken() + const password = user.password + if (!password.length) { throw new Error('password cannot be blank') } + delete user.password - const newUser = await User.create(user).fetch(); + const newUser = await User.create(user).fetch() try { await Passport.create({ protocol: 'local', password, user: newUser.id, accessToken: token - }); - return next(null, token); + }) + return next(null, token) } catch (e) { - await User.destroy(newUser.id); - throw e; + await User.destroy(newUser.id) + throw e } } catch (e) { - return next(e); + return next(e) } }, update: async function (user, next) { - throw new Error('not implemented'); + throw new Error('not implemented') }, connect: async function (req, res, next) { try { - const user = req.user; - const password = req.param('password'); + const user = req.user + const password = req.param('password') const pass = await Passport.findOne({ protocol: 'local', user: user.id - }); + }) if (!pass) { await Passport.create({ protocol: 'local', password, user: user.id - }); + }) } else { - return next(null, user); + return next(null, user) } } catch (e) { - return next(e); + return next(e) } } } -}; +} -const EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; +const EMAIL_REGEX = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i function validateEmail (email) { - return EMAIL_REGEX.test(email); + return EMAIL_REGEX.test(email) } function generateToken () { - return base64URL(crypto.randomBytes(48)); + return base64URL(crypto.randomBytes(48)) } diff --git a/config/routes.js b/config/routes.js index e4b9108..fa0672b 100644 --- a/config/routes.js +++ b/config/routes.js @@ -66,17 +66,14 @@ module.exports.routes = { 'POST /api/publish': 'BooksController.publish', 'GET /api/books': 'BooksController.list', - 'GET /api/me': 'UserController.me', - + 'GET /api/me': 'UserController.me' // ╦ ╦╔═╗╔╗ ╦ ╦╔═╗╔═╗╦╔═╔═╗ // ║║║║╣ ╠╩╗╠═╣║ ║║ ║╠╩╗╚═╗ // ╚╩╝╚═╝╚═╝╩ ╩╚═╝╚═╝╩ ╩╚═╝ - // ╔╦╗╦╔═╗╔═╗ // ║║║║╚═╗║ // ╩ ╩╩╚═╝╚═╝ - -}; +} diff --git a/config/security.js b/config/security.js index bd57631..b794f69 100644 --- a/config/security.js +++ b/config/security.js @@ -34,7 +34,6 @@ module.exports.security = { // allowCredentials: false, // }, - /**************************************************************************** * * * By default, Sails' built-in CSRF protection is disabled to facilitate * @@ -51,4 +50,4 @@ module.exports.security = { // csrf: false -}; +} diff --git a/config/session.js b/config/session.js index c25e43b..de7544c 100644 --- a/config/session.js +++ b/config/session.js @@ -18,8 +18,7 @@ module.exports.session = { * of your users, forcing them to log in again. * * * ***************************************************************************/ - secret: 'b7f0374251c4d79227067c286fe97ea5', - + secret: 'b7f0374251c4d79227067c286fe97ea5' /*************************************************************************** * * @@ -36,4 +35,4 @@ module.exports.session = { // return !!req.path.match(req._sails.LOOKS_LIKE_ASSET_RX); // }, -}; +} diff --git a/config/sockets.js b/config/sockets.js index 9f466a0..fa13f9d 100644 --- a/config/sockets.js +++ b/config/sockets.js @@ -29,7 +29,6 @@ module.exports.sockets = { // transports: [ 'websocket' ], - /*************************************************************************** * * * `beforeConnect` * @@ -50,7 +49,6 @@ module.exports.sockets = { // // }, - /*************************************************************************** * * * `afterDisconnect` * @@ -68,7 +66,6 @@ module.exports.sockets = { // // }, - /*************************************************************************** * * * Whether to expose a 'GET /__getcookie' route that sets an HTTP-only * @@ -78,5 +75,4 @@ module.exports.sockets = { // grant3rdPartyCookie: true, - -}; +} diff --git a/config/views.js b/config/views.js index 55d0f92..a2b0bea 100644 --- a/config/views.js +++ b/config/views.js @@ -38,4 +38,4 @@ module.exports.views = { layout: 'layouts/layout' -}; +} diff --git a/tasks/config/babel.js b/tasks/config/babel.js index c9720a1..3ab4680 100644 --- a/tasks/config/babel.js +++ b/tasks/config/babel.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/babel.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('babel', { dist: { options: { @@ -25,7 +24,7 @@ module.exports = function(grunt) { } ] } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -50,5 +49,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-babel'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/clean.js b/tasks/config/clean.js index a267b8d..24ad6c7 100644 --- a/tasks/config/clean.js +++ b/tasks/config/clean.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/clean.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('clean', { dev: ['.tmp/public/**'], build: ['www'], @@ -23,7 +22,7 @@ module.exports = function(grunt) { 'www/templates', 'www/dependencies' ] - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -48,5 +47,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-clean'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/coffee.js b/tasks/config/coffee.js index 675df6d..2c2b7e4 100644 --- a/tasks/config/coffee.js +++ b/tasks/config/coffee.js @@ -10,8 +10,7 @@ * https://sailsjs.com/anatomy/tasks/config/coffee.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('coffee', { dev: { options: { @@ -27,7 +26,7 @@ module.exports = function(grunt) { ext: '.js' }] } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -52,5 +51,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-coffee'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/concat.js b/tasks/config/concat.js index 4a3530c..4b9a2cf 100644 --- a/tasks/config/concat.js +++ b/tasks/config/concat.js @@ -10,8 +10,7 @@ * https://sailsjs.com/anatomy/tasks/config/concat.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('concat', { js: { src: require('../pipeline').jsFilesToInject, @@ -21,7 +20,7 @@ module.exports = function(grunt) { src: require('../pipeline').cssFilesToInject, dest: '.tmp/public/concat/production.css' } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -46,5 +45,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-concat'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/copy.js b/tasks/config/copy.js index f06c50b..4e0eb6e 100644 --- a/tasks/config/copy.js +++ b/tasks/config/copy.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/copy.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('copy', { dev: { files: [{ @@ -35,8 +34,8 @@ module.exports = function(grunt) { src: ['**/*'], dest: '.tmp/public/dist' }] - }, - }); + } + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -61,5 +60,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-copy'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/cssmin.js b/tasks/config/cssmin.js index e3f3edf..b13efdf 100644 --- a/tasks/config/cssmin.js +++ b/tasks/config/cssmin.js @@ -11,14 +11,13 @@ * https://sailsjs.com/anatomy/tasks/config/cssmin.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('cssmin', { dist: { src: ['.tmp/public/concat/production.css'], dest: '.tmp/public/min/production.min.css' } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -43,5 +42,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-cssmin'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/hash.js b/tasks/config/hash.js index 41435ac..24ad26b 100644 --- a/tasks/config/hash.js +++ b/tasks/config/hash.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/hash.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('hash', { options: { mapping: '', @@ -18,11 +17,11 @@ module.exports = function(grunt) { destBasePath: '', flatten: false, hashLength: 8, - hashFunction: function(source, encoding){ + hashFunction: function (source, encoding) { if (!source || !encoding) { - throw new Error('Consistency violation: Cannot compute unique hash for production .css/.js cache-busting suffix, because `source` and/or `encoding` are falsey-- but they should be truthy strings! Here they are, respectively:\nsource: '+require('util').inspect(source, {depth:null})+'\nencoding: '+require('util').inspect(encoding, {depth:null})); + throw new Error('Consistency violation: Cannot compute unique hash for production .css/.js cache-busting suffix, because `source` and/or `encoding` are falsey-- but they should be truthy strings! Here they are, respectively:\nsource: ' + require('util').inspect(source, {depth: null}) + '\nencoding: ' + require('util').inspect(encoding, {depth: null})) } - return require('crypto').createHash('sha1').update(source, encoding).digest('hex'); + return require('crypto').createHash('sha1').update(source, encoding).digest('hex') } }, js: { @@ -33,7 +32,7 @@ module.exports = function(grunt) { src: '.tmp/public/min/*.css', dest: '.tmp/public/hash/' } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -58,5 +57,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-hash'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/jst.js b/tasks/config/jst.js index 5061fc5..472ffaa 100644 --- a/tasks/config/jst.js +++ b/tasks/config/jst.js @@ -10,8 +10,7 @@ * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('jst', { dev: { @@ -26,14 +25,13 @@ module.exports = function(grunt) { // default interpolation. If you want to parse templates with the default _.template behavior // (i.e. using
    <%= this.id %>
    ), there's no need to overwrite `templateSettings.interpolate`. - files: { // e.g. // 'relative/path/from/gruntfile/to/compiled/template/destination' : ['relative/path/to/sourcefiles/**/*.html'] '.tmp/public/jst.js': require('../pipeline').templateFilesToInject } } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -58,5 +56,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-jst'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/less.js b/tasks/config/less.js index 06e3a08..ab2a44f 100644 --- a/tasks/config/less.js +++ b/tasks/config/less.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/less.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('less', { dev: { files: [{ @@ -21,7 +20,7 @@ module.exports = function(grunt) { ext: '.css' }] } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -46,5 +45,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-less'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/sails-linker.js b/tasks/config/sails-linker.js index 9fe39df..d685b9b 100644 --- a/tasks/config/sails-linker.js +++ b/tasks/config/sails-linker.js @@ -11,11 +11,9 @@ * https://sailsjs.com/anatomy/tasks/config/sails-linker.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('sails-linker', { - // ╦╔═╗╦ ╦╔═╗╔═╗╔═╗╦═╗╦╔═╗╔╦╗ // ║╠═╣╚╗╔╝╠═╣╚═╗║ ╠╦╝║╠═╝ ║ // ╚╝╩ ╩ ╚╝ ╩ ╩╚═╝╚═╝╩╚═╩╩ ╩ @@ -41,7 +39,7 @@ module.exports = function(grunt) { startTag: '', endTag: '', fileTmpl: '', - appRoot: '.tmp/public', + appRoot: '.tmp/public' // relative: true // ^^ Uncomment this if compiling assets for use in PhoneGap, CDN, etc. // (but be note that this can break custom font URLs) @@ -72,7 +70,7 @@ module.exports = function(grunt) { startTag: '', endTag: '', fileTmpl: '', - appRoot: '.tmp/public', + appRoot: '.tmp/public' // relative: true // ^^ Uncomment this if compiling assets for use in PhoneGap, CDN, etc. // (but be note that this can break custom font URLs) @@ -84,7 +82,6 @@ module.exports = function(grunt) { } }, - // ╔═╗╔╦╗╦ ╦╦ ╔═╗╔═╗╦ ╦╔═╗╔═╗╔╦╗╔═╗ // ╚═╗ ║ ╚╦╝║ ║╣ ╚═╗╠═╣║╣ ║╣ ║ ╚═╗ // ╚═╝ ╩ ╩ ╩═╝╚═╝╚═╝╩ ╩╚═╝╚═╝ ╩ ╚═╝ @@ -111,7 +108,7 @@ module.exports = function(grunt) { startTag: '', endTag: '', fileTmpl: '', - appRoot: '.tmp/public', + appRoot: '.tmp/public' // relative: true // ^^ Uncomment this if compiling assets for use in PhoneGap, CDN, etc. // (but be note that this can break custom font URLs) @@ -143,7 +140,7 @@ module.exports = function(grunt) { startTag: '', endTag: '', fileTmpl: '', - appRoot: '.tmp/public', + appRoot: '.tmp/public' // relative: true // ^^ Uncomment this if compiling assets for use in PhoneGap, CDN, etc. // (but be note that this can break custom font URLs) @@ -155,7 +152,6 @@ module.exports = function(grunt) { } }, - // ╔═╗╦═╗╔═╗╔═╗╔═╗╔╦╗╔═╗╦╦ ╔═╗╔╦╗ ╦ ╦╔╦╗╔╦╗╦ ╔╦╗╔═╗╔╦╗╔═╗╦ ╔═╗╔╦╗╔═╗╔═╗ // ╠═╝╠╦╝║╣ ║ ║ ║║║║╠═╝║║ ║╣ ║║ ╠═╣ ║ ║║║║ ║ ║╣ ║║║╠═╝║ ╠═╣ ║ ║╣ ╚═╗ // ╩ ╩╚═╚═╝╚═╝╚═╝╩ ╩╩ ╩╩═╝╚═╝═╩╝ ╩ ╩ ╩ ╩ ╩╩═╝ ╩ ╚═╝╩ ╩╩ ╩═╝╩ ╩ ╩ ╚═╝╚═╝ @@ -180,7 +176,7 @@ module.exports = function(grunt) { startTag: '', endTag: '', fileTmpl: '', - appRoot: '.tmp/public', + appRoot: '.tmp/public' // relative: true // ^^ Uncomment this if compiling assets for use in PhoneGap, CDN, etc. // (but be note that this can break custom font URLs) @@ -190,9 +186,9 @@ module.exports = function(grunt) { 'views/**/*.html': ['.tmp/public/jst.js'], 'views/**/*.ejs': ['.tmp/public/jst.js'] } - }, + } - });// + })// // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -217,5 +213,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-sails-linker'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/sync.js b/tasks/config/sync.js index 23ff3b8..516ad77 100644 --- a/tasks/config/sync.js +++ b/tasks/config/sync.js @@ -10,8 +10,7 @@ * https://sailsjs.com/anatomy/tasks/config/sync.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('sync', { dev: { files: [{ @@ -20,7 +19,7 @@ module.exports = function(grunt) { dest: '.tmp/public' }] } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -45,5 +44,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-sync'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/config/uglify.js b/tasks/config/uglify.js index 31add99..e01a0d7 100644 --- a/tasks/config/uglify.js +++ b/tasks/config/uglify.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/uglify.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('uglify', { dist: { src: ['.tmp/public/concat/production.js'], @@ -24,7 +23,7 @@ module.exports = function(grunt) { 'Promise', 'File', 'Location', - 'RttcRefPlaceholder', + 'RttcRefPlaceholder' ], keep_fnames: true//eslint-disable-line }, @@ -32,7 +31,7 @@ module.exports = function(grunt) { keep_fnames: true//eslint-disable-line } } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -57,6 +56,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-uglify'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; - +} diff --git a/tasks/config/watch.js b/tasks/config/watch.js index 611e297..23483ff 100644 --- a/tasks/config/watch.js +++ b/tasks/config/watch.js @@ -9,8 +9,7 @@ * https://sailsjs.com/anatomy/tasks/config/watch.js * */ -module.exports = function(grunt) { - +module.exports = function (grunt) { grunt.config.set('watch', { assets: { @@ -27,7 +26,7 @@ module.exports = function(grunt) { 'linkAssets' ] } - }); + }) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This Grunt plugin is part of the default asset pipeline in Sails, @@ -52,5 +51,4 @@ module.exports = function(grunt) { // grunt.loadNpmTasks('grunt-contrib-watch'); // ``` // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -}; +} diff --git a/tasks/pipeline.js b/tasks/pipeline.js index 65047d7..fe0a93a 100644 --- a/tasks/pipeline.js +++ b/tasks/pipeline.js @@ -10,8 +10,6 @@ * https://sailsjs.com/anatomy/tasks/pipeline.js */ - - // ██████╗ ██╗ █████╗ ██╗███╗ ██╗ ██████╗███████╗███████╗ // ██╔══██╗██║ ██╔══██╗██║████╗ ██║ ██╔════╝██╔════╝██╔════╝ // ██████╔╝██║ ███████║██║██╔██╗ ██║ ██║ ███████╗███████╗ @@ -40,8 +38,7 @@ var cssFilesToInject = [ // in no particular order. To customize the ordering, add additional // items here, _above_ this one. 'styles/**/*.css' -]; - +] // ██████╗██╗ ██╗███████╗███╗ ██╗████████╗ ███████╗██╗██████╗ ███████╗ // ██╔════╝██║ ██║██╔════╝████╗ ██║╚══██╔══╝ ██╔════╝██║██╔══██╗██╔════╝ @@ -73,8 +70,7 @@ var jsFilesToInject = [ // in no particular order. To customize the ordering, add additional items // here, _above_ this one. 'js/**/*.js' -]; - +] // ██████╗██╗ ██╗███████╗███╗ ██╗████████╗ ███████╗██╗██████╗ ███████╗ // ██╔════╝██║ ██║██╔════╝████╗ ██║╚══██╔══╝ ██╔════╝██║██╔══██╗██╔════╝ @@ -103,9 +99,7 @@ var jsFilesToInject = [ // var templateFilesToInject = [ 'templates/**/*.html' -]; - - +] // ███╗ ███╗██╗███████╗ ██████╗ ███████╗███████╗████████╗██╗ ██╗██████╗ // ████╗ ████║██║██╔════╝██╔════╝ ██╔════╝██╔════╝╚══██╔══╝██║ ██║██╔══██╗ @@ -119,29 +113,29 @@ var templateFilesToInject = [ // the code below, unless you are modifying the default asset pipeline.** // Default path for public folder (see documentation on sailsjs.com for more information) -var tmpPath = '.tmp/public/'; +var tmpPath = '.tmp/public/' // Prefix relative paths to source files so they point to the proper locations // (i.e. where the other Grunt tasks spit them out, or in some cases, where // they reside in the first place) -module.exports.cssFilesToInject = cssFilesToInject.map((cssPath)=>{ +module.exports.cssFilesToInject = cssFilesToInject.map((cssPath) => { // If we're ignoring the file, make sure the ! is at the beginning of the path if (cssPath[0] === '!') { - return require('path').join('!' + tmpPath, cssPath.substr(1)); + return require('path').join('!' + tmpPath, cssPath.substr(1)) } - return require('path').join(tmpPath, cssPath); -}); -module.exports.jsFilesToInject = jsFilesToInject.map((jsPath)=>{ + return require('path').join(tmpPath, cssPath) +}) +module.exports.jsFilesToInject = jsFilesToInject.map((jsPath) => { // If we're ignoring the file, make sure the ! is at the beginning of the path if (jsPath[0] === '!') { - return require('path').join('!' + tmpPath, jsPath.substr(1)); + return require('path').join('!' + tmpPath, jsPath.substr(1)) } - return require('path').join(tmpPath, jsPath); -}); -module.exports.templateFilesToInject = templateFilesToInject.map((tplPath)=>{ + return require('path').join(tmpPath, jsPath) +}) +module.exports.templateFilesToInject = templateFilesToInject.map((tplPath) => { // If we're ignoring the file, make sure the ! is at the beginning of the path if (tplPath[0] === '!') { - return require('path').join('!assets/', tplPath.substr(1)); + return require('path').join('!assets/', tplPath.substr(1)) } - return require('path').join('assets/', tplPath); -}); + return require('path').join('assets/', tplPath) +}) diff --git a/tasks/register/build.js b/tasks/register/build.js index 684b10d..2e3cd81 100644 --- a/tasks/register/build.js +++ b/tasks/register/build.js @@ -10,7 +10,7 @@ * https://sailsjs.com/anatomy/tasks/register/build.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('build', [ // 'polyfill:dev', //« uncomment to ALSO transpile during development (for broader browser compat.) 'compileAssets', @@ -18,5 +18,5 @@ module.exports = function(grunt) { 'linkAssetsBuild', 'clean:build', 'copy:build' - ]); -}; + ]) +} diff --git a/tasks/register/buildProd.js b/tasks/register/buildProd.js index 67fdb89..8e72d39 100644 --- a/tasks/register/buildProd.js +++ b/tasks/register/buildProd.js @@ -11,20 +11,19 @@ * https://sailsjs.com/anatomy/tasks/register/build-prod.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('buildProd', [ - 'polyfill:prod', //« Remove this to skip transpilation in production (not recommended) + 'polyfill:prod', // « Remove this to skip transpilation in production (not recommended) 'compileAssets', - 'babel', //« Remove this to skip transpilation in production (not recommended) + 'babel', // « Remove this to skip transpilation in production (not recommended) 'concat', 'uglify', 'cssmin', - 'hash',//« Cache-busting - 'copy:beforeLinkBuildProd',//« For prettier URLs after cache-busting + 'hash', // « Cache-busting + 'copy:beforeLinkBuildProd', // « For prettier URLs after cache-busting 'linkAssetsBuildProd', 'clean:build', 'copy:build', 'clean:afterBuildProd' - ]); -}; - + ]) +} diff --git a/tasks/register/compileAssets.js b/tasks/register/compileAssets.js index b85dfa7..0a41234 100644 --- a/tasks/register/compileAssets.js +++ b/tasks/register/compileAssets.js @@ -7,12 +7,12 @@ * https://sailsjs.com/anatomy/tasks/register/compile-assets.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('compileAssets', [ 'clean:dev', 'jst:dev', 'less:dev', 'copy:dev', 'coffee:dev' - ]); -}; + ]) +} diff --git a/tasks/register/default.js b/tasks/register/default.js index e76605c..6548c02 100644 --- a/tasks/register/default.js +++ b/tasks/register/default.js @@ -13,15 +13,11 @@ * */ module.exports = function (grunt) { - - grunt.registerTask('default', [ // 'polyfill:dev', //« uncomment to ALSO transpile during development (for broader browser compat.) 'compileAssets', // 'babel', //« uncomment to ALSO transpile during development (for broader browser compat.) 'linkAssets', 'watch' - ]); - - -}; + ]) +} diff --git a/tasks/register/linkAssets.js b/tasks/register/linkAssets.js index 66f375b..fd935a2 100644 --- a/tasks/register/linkAssets.js +++ b/tasks/register/linkAssets.js @@ -7,10 +7,10 @@ * https://sailsjs.com/anatomy/tasks/register/link-assets.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('linkAssets', [ 'sails-linker:devJs', 'sails-linker:devStyles', 'sails-linker:clientSideTemplates' - ]); -}; + ]) +} diff --git a/tasks/register/linkAssetsBuild.js b/tasks/register/linkAssetsBuild.js index a5f6de0..c37a79a 100644 --- a/tasks/register/linkAssetsBuild.js +++ b/tasks/register/linkAssetsBuild.js @@ -7,10 +7,10 @@ * https://sailsjs.com/anatomy/tasks/register/link-assets-build.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('linkAssetsBuild', [ 'sails-linker:devJsBuild', 'sails-linker:devStylesBuild', 'sails-linker:clientSideTemplatesBuild' - ]); -}; + ]) +} diff --git a/tasks/register/linkAssetsBuildProd.js b/tasks/register/linkAssetsBuildProd.js index bcac82d..3a092e8 100644 --- a/tasks/register/linkAssetsBuildProd.js +++ b/tasks/register/linkAssetsBuildProd.js @@ -7,10 +7,10 @@ * https://sailsjs.com/anatomy/tasks/register/link-assets-build-prod.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('linkAssetsBuildProd', [ 'sails-linker:prodJsBuild', 'sails-linker:prodStylesBuild', 'sails-linker:clientSideTemplatesBuild' - ]); -}; + ]) +} diff --git a/tasks/register/polyfill.js b/tasks/register/polyfill.js index a77d82c..4d91a10 100644 --- a/tasks/register/polyfill.js +++ b/tasks/register/polyfill.js @@ -7,22 +7,21 @@ * https://sailsjs.com/anatomy/tasks/register/polyfill.js * */ -module.exports = function(grunt) { - grunt.registerTask('polyfill:prod', 'Add the polyfill file to the top of the list of files to concatenate', ()=>{ - grunt.config.set('concat.js.src', [require('sails-hook-grunt/accessible/babel-polyfill')].concat(grunt.config.get('concat.js.src'))); - }); - grunt.registerTask('polyfill:dev', 'Add the polyfill file to the top of the list of files to copy and link', ()=>{ +module.exports = function (grunt) { + grunt.registerTask('polyfill:prod', 'Add the polyfill file to the top of the list of files to concatenate', () => { + grunt.config.set('concat.js.src', [require('sails-hook-grunt/accessible/babel-polyfill')].concat(grunt.config.get('concat.js.src'))) + }) + grunt.registerTask('polyfill:dev', 'Add the polyfill file to the top of the list of files to copy and link', () => { grunt.config.set('copy.dev.files', grunt.config.get('copy.dev.files').concat({ expand: true, cwd: require('path').dirname(require('sails-hook-grunt/accessible/babel-polyfill')), src: require('path').basename(require('sails-hook-grunt/accessible/babel-polyfill')), dest: '.tmp/public/polyfill' - })); - var devLinkFiles = grunt.config.get('sails-linker.devJs.files'); - grunt.config.set('sails-linker.devJs.files', Object.keys(devLinkFiles).reduce((linkerConfigSoFar, glob)=>{ - linkerConfigSoFar[glob] = ['.tmp/public/polyfill/polyfill.min.js'].concat(devLinkFiles[glob]); - return linkerConfigSoFar; - }, {})); - }); -}; - + })) + var devLinkFiles = grunt.config.get('sails-linker.devJs.files') + grunt.config.set('sails-linker.devJs.files', Object.keys(devLinkFiles).reduce((linkerConfigSoFar, glob) => { + linkerConfigSoFar[glob] = ['.tmp/public/polyfill/polyfill.min.js'].concat(devLinkFiles[glob]) + return linkerConfigSoFar + }, {})) + }) +} diff --git a/tasks/register/prod.js b/tasks/register/prod.js index 9194f09..14d2753 100644 --- a/tasks/register/prod.js +++ b/tasks/register/prod.js @@ -11,17 +11,16 @@ * https://sailsjs.com/anatomy/tasks/register/prod.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('prod', [ - 'polyfill:prod', //« Remove this to skip transpilation in production (not recommended) + 'polyfill:prod', // « Remove this to skip transpilation in production (not recommended) 'compileAssets', - 'babel', //« Remove this to skip transpilation in production (not recommended) + 'babel', // « Remove this to skip transpilation in production (not recommended) 'concat', 'uglify', 'cssmin', 'sails-linker:prodJs', 'sails-linker:prodStyles', - 'sails-linker:clientSideTemplates', - ]); -}; - + 'sails-linker:clientSideTemplates' + ]) +} diff --git a/tasks/register/syncAssets.js b/tasks/register/syncAssets.js index 418459f..2e9e3e0 100644 --- a/tasks/register/syncAssets.js +++ b/tasks/register/syncAssets.js @@ -7,11 +7,11 @@ * https://sailsjs.com/anatomy/tasks/register/sync-assets.js * */ -module.exports = function(grunt) { +module.exports = function (grunt) { grunt.registerTask('syncAssets', [ 'jst:dev', 'less:dev', 'sync:dev', 'coffee:dev' - ]); -}; + ]) +}