Skip to content

Commit

Permalink
馃帹 Ghost bootstrap: optimise requires (#8121)
Browse files Browse the repository at this point in the history
* 馃帹  Ghost bootstrap: optimise requires

no issue

- require as less as possible on bootstrap

* do not load icojs on bootstrap
  • Loading branch information
kirrg001 authored and ErisDS committed Mar 13, 2017
1 parent e0cd5b5 commit 7556e68
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 140 deletions.
2 changes: 1 addition & 1 deletion core/server/api/authentication.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ authentication = {
}));
}

spamPrevention.userLogin.reset(opts.ip, tokenParts.email + 'login');
spamPrevention.userLogin().reset(opts.ip, tokenParts.email + 'login');

return models.User.changePassword({
oldPassword: oldPassword,
Expand Down
12 changes: 7 additions & 5 deletions core/server/apps/amp/lib/helpers/amp_content.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,16 @@
// there if available. The cacheId is a combination of `updated_at` and the `slug`.
var hbs = require('express-hbs'),
Promise = require('bluebird'),
Amperize = require('amperize'),
moment = require('moment'),
sanitizeHtml = require('sanitize-html'),
logging = require('../../../../logging'),
i18n = require('../../../../i18n'),
errors = require('../../../../errors'),
makeAbsoluteUrl = require('../../../../utils/make-absolute-urls'),
utils = require('../../../../utils'),
cheerio = require('cheerio'),
amperize = new Amperize(),
amperizeCache = {},
allowedAMPTags = [],
allowedAMPAttributes = {},
amperize,
cleanHTML,
ampHTML;

Expand Down Expand Up @@ -120,6 +117,9 @@ function getAmperizeHTML(html, post) {
return;
}

var Amperize = require('amperize');
amperize = amperize || new Amperize();

// make relative URLs abolute
html = makeAbsoluteUrl(html, utils.url.urlFor('home', true), post.url).html();

Expand Down Expand Up @@ -154,7 +154,9 @@ function getAmperizeHTML(html, post) {
}

function ampContent() {
var amperizeHTML = {
var sanitizeHtml = require('sanitize-html'),
cheerio = require('cheerio'),
amperizeHTML = {
amperize: getAmperizeHTML(this.html, this)
};

Expand Down
6 changes: 3 additions & 3 deletions core/server/auth/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function exchangeRefreshToken(client, refreshToken, scope, body, authInfo, done)
var token = model.toJSON();

if (token.expires > Date.now()) {
spamPrevention.userLogin.reset(authInfo.ip, body.refresh_token + 'login');
spamPrevention.userLogin().reset(authInfo.ip, body.refresh_token + 'login');

authUtils.createTokens({
clientId: token.client_id,
Expand Down Expand Up @@ -54,7 +54,7 @@ function exchangePassword(client, username, password, scope, body, authInfo, don
});
})
.then(function then(response) {
spamPrevention.userLogin.reset(authInfo.ip, username + 'login');
spamPrevention.userLogin().reset(authInfo.ip, username + 'login');
return done(null, response.access_token, response.refresh_token, {expires_in: response.expires_in});
});
})
Expand Down Expand Up @@ -83,7 +83,7 @@ function exchangeAuthorizationCode(req, res, next) {
}));
}

spamPrevention.userLogin.reset(req.authInfo.ip, req.body.authorizationCode + 'login');
spamPrevention.userLogin().reset(req.authInfo.ip, req.body.authorizationCode + 'login');

authUtils.createTokens({
clientId: req.client.id,
Expand Down
6 changes: 2 additions & 4 deletions core/server/mail/GhostMailer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,19 @@
// Handles sending email for Ghost
var _ = require('lodash'),
Promise = require('bluebird'),
nodemailer = require('nodemailer'),
validator = require('validator'),
config = require('../config'),
settingsCache = require('../settings/cache'),
i18n = require('../i18n'),
utils = require('../utils');

function GhostMailer() {
var transport = config.get('mail') && config.get('mail').transport || 'direct',
var nodemailer = require('nodemailer'),
transport = config.get('mail') && config.get('mail').transport || 'direct',
options = config.get('mail') && _.clone(config.get('mail').options) || {};

this.state = {};

this.transport = nodemailer.createTransport(transport, options);

this.state.usingDirect = transport === 'direct';
}

Expand Down
232 changes: 152 additions & 80 deletions core/server/middleware/api/spam-prevention.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
var ExpressBrute = require('express-brute'),
BruteKnex = require('brute-knex'),
knexInstance = require('../../data/db/connection'),
store = new BruteKnex({tablename: 'brute', createTable:false, knex: knexInstance}),
moment = require('moment'),
var moment = require('moment'),
errors = require('../../errors'),
config = require('../../config'),
spam = config.get('spam') || {},
Expand All @@ -14,9 +10,15 @@ var ExpressBrute = require('express-brute'),
spamUserLogin = spam.user_login || {},

i18n = require('../../i18n'),
store,
handleStoreError,
globalBlock,
globalReset,
privateBlogInstance,
globalResetInstance,
globalBlockInstance,
userLoginInstance,
userResetInstance,
privateBlog,
userLogin,
userReset,
Expand Down Expand Up @@ -46,93 +48,163 @@ handleStoreError = function handleStoreError(err) {
// requests from a single IP
// We allow for a generous number of requests here to prevent communites on the same IP bing barred on account of a single suer
// Defaults to 50 attempts per hour and locks the endpoint for an hour
globalBlock = new ExpressBrute(store,
_.extend({
attachResetToRequest: false,
failCallback: function (req, res, next, nextValidRequestDate) {
return next(new errors.TooManyRequestsError({
message: 'Too many attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
context: i18n.t('errors.middleware.spamprevention.forgottenPasswordIp.error',
{rfa: spamGlobalBlock.freeRetries + 1 || 5, rfp: spamGlobalBlock.lifetime || 60 * 60}),
help: i18n.t('errors.middleware.spamprevention.tooManyAttempts')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamGlobalBlock, spamConfigKeys))
);

globalReset = new ExpressBrute(store,
_.extend({
attachResetToRequest: false,
failCallback: function (req, res, next, nextValidRequestDate) {
// TODO use i18n again
return next(new errors.TooManyRequestsError({
message: 'Too many attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
context: i18n.t('errors.middleware.spamprevention.forgottenPasswordIp.error',
{rfa: spamGlobalReset.freeRetries + 1 || 5, rfp: spamGlobalReset.lifetime || 60 * 60}),
help: i18n.t('errors.middleware.spamprevention.forgottenPasswordIp.context')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamGlobalReset, spamConfigKeys))
);
globalBlock = function globalBlock() {
var ExpressBrute = require('express-brute'),
BruteKnex = require('brute-knex'),
db = require('../../data/db');

store = store || new BruteKnex({
tablename: 'brute',
createTable: false,
knex: db.knex
});

globalBlockInstance = globalBlockInstance || new ExpressBrute(store,
_.extend({
attachResetToRequest: false,
failCallback: function (req, res, next, nextValidRequestDate) {
return next(new errors.TooManyRequestsError({
message: 'Too many attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
context: i18n.t('errors.middleware.spamprevention.forgottenPasswordIp.error',
{rfa: spamGlobalBlock.freeRetries + 1 || 5, rfp: spamGlobalBlock.lifetime || 60 * 60}),
help: i18n.t('errors.middleware.spamprevention.tooManyAttempts')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamGlobalBlock, spamConfigKeys))
);

return globalBlockInstance;
};

globalReset = function globalReset() {
var ExpressBrute = require('express-brute'),
BruteKnex = require('brute-knex'),
db = require('../../data/db');

store = store || new BruteKnex({
tablename: 'brute',
createTable: false,
knex: db.knex
});

globalResetInstance = globalResetInstance || new ExpressBrute(store,
_.extend({
attachResetToRequest: false,
failCallback: function (req, res, next, nextValidRequestDate) {
// TODO use i18n again
return next(new errors.TooManyRequestsError({
message: 'Too many attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
context: i18n.t('errors.middleware.spamprevention.forgottenPasswordIp.error',
{rfa: spamGlobalReset.freeRetries + 1 || 5, rfp: spamGlobalReset.lifetime || 60 * 60}),
help: i18n.t('errors.middleware.spamprevention.forgottenPasswordIp.context')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamGlobalReset, spamConfigKeys))
);

return globalResetInstance;
};

// Stops login attempts for a user+IP pair with an increasing time period starting from 10 minutes
// and rising to a week in a fibonnaci sequence
// The user+IP count is reset when on successful login
// Default value of 5 attempts per user+IP pair
userLogin = new ExpressBrute(store,
_.extend({
attachResetToRequest: true,
failCallback: function (req, res, next, nextValidRequestDate) {
return next(new errors.TooManyRequestsError({
message: 'Too many sign-in attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
// TODO add more options to i18n
context: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context'),
help: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamUserLogin, spamConfigKeys))
);
userLogin = function userLogin() {
var ExpressBrute = require('express-brute'),
BruteKnex = require('brute-knex'),
db = require('../../data/db');

store = store || new BruteKnex({
tablename: 'brute',
createTable: false,
knex: db.knex
});

userLoginInstance = userLoginInstance || new ExpressBrute(store,
_.extend({
attachResetToRequest: true,
failCallback: function (req, res, next, nextValidRequestDate) {
return next(new errors.TooManyRequestsError({
message: 'Too many sign-in attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
// TODO add more options to i18n
context: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context'),
help: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamUserLogin, spamConfigKeys))
);

return userLoginInstance;
};

// Stop password reset requests when there are (freeRetries + 1) requests per lifetime per email
// Defaults here are 5 attempts per hour for a user+IP pair
// The endpoint is then locked for an hour
userReset = new ExpressBrute(store,
_.extend({
attachResetToRequest: true,
failCallback: function (req, res, next, nextValidRequestDate) {
return next(new errors.TooManyRequestsError({
message: 'Too many password reset attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
context: i18n.t('errors.middleware.spamprevention.forgottenPasswordEmail.error',
{rfa: spamUserReset.freeRetries + 1 || 5, rfp: spamUserReset.lifetime || 60 * 60}),
help: i18n.t('errors.middleware.spamprevention.forgottenPasswordEmail.context')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamUserReset, spamConfigKeys))
);
userReset = function userReset() {
var ExpressBrute = require('express-brute'),
BruteKnex = require('brute-knex'),
db = require('../../data/db');

store = store || new BruteKnex({
tablename: 'brute',
createTable: false,
knex: db.knex
});

userResetInstance = userResetInstance || new ExpressBrute(store,
_.extend({
attachResetToRequest: true,
failCallback: function (req, res, next, nextValidRequestDate) {
return next(new errors.TooManyRequestsError({
message: 'Too many password reset attempts try again in ' + moment(nextValidRequestDate).fromNow(true),
context: i18n.t('errors.middleware.spamprevention.forgottenPasswordEmail.error',
{rfa: spamUserReset.freeRetries + 1 || 5, rfp: spamUserReset.lifetime || 60 * 60}),
help: i18n.t('errors.middleware.spamprevention.forgottenPasswordEmail.context')
}));
},
handleStoreError: handleStoreError
}, _.pick(spamUserReset, spamConfigKeys))
);

return userResetInstance;
};

// This protects a private blog from spam attacks. The defaults here allow 10 attempts per IP per hour
// The endpoint is then locked for an hour
privateBlog = new ExpressBrute(store,
_.extend({
attachResetToRequest: false,
failCallback: function (req, res, next, nextValidRequestDate) {
logging.error(new errors.GhostError({
message: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.error',
{rfa: spamPrivateBlog.freeRetries + 1 || 5, rfp: spamPrivateBlog.lifetime || 60 * 60}),
context: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context')
}));

return next(new errors.GhostError({
message: 'Too many private sign-in attempts try again in ' + moment(nextValidRequestDate).fromNow(true)
}));
},
handleStoreError: handleStoreError
}, _.pick(spamPrivateBlog, spamConfigKeys))
);
privateBlog = function privateBlog() {
var ExpressBrute = require('express-brute'),
BruteKnex = require('brute-knex'),
db = require('../../data/db');

store = store || new BruteKnex({
tablename: 'brute',
createTable: false,
knex: db.knex
});

privateBlogInstance = privateBlogInstance || new ExpressBrute(store,
_.extend({
attachResetToRequest: false,
failCallback: function (req, res, next, nextValidRequestDate) {
logging.error(new errors.GhostError({
message: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.error',
{rfa: spamPrivateBlog.freeRetries + 1 || 5, rfp: spamPrivateBlog.lifetime || 60 * 60}),
context: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context')
}));

return next(new errors.GhostError({
message: 'Too many private sign-in attempts try again in ' + moment(nextValidRequestDate).fromNow(true)
}));
},
handleStoreError: handleStoreError
}, _.pick(spamPrivateBlog, spamConfigKeys))
);

return privateBlogInstance;
};

module.exports = {
globalBlock: globalBlock,
Expand Down
Loading

0 comments on commit 7556e68

Please sign in to comment.