mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-18 02:21:47 -05:00
Use Captcha middleware in members API
ref BAE-104 The members send-magic-link API should be protected by Captcha. This required initialising the Captcha service in the members API, and putting the middleware into the send-magic-link API. If it's enabled via lab flag and config, then the service will prevent API calls that don't have a valid Captcha response.
This commit is contained in:
parent
3e2658baa0
commit
439bbf8b79
6 changed files with 161 additions and 1 deletions
|
@ -1,6 +1,19 @@
|
|||
const settingsCache = require('../../../shared/settings-cache');
|
||||
const urlUtils = require('../../../shared/url-utils');
|
||||
const ghostVersion = require('@tryghost/version');
|
||||
const config = require('../../../shared/config');
|
||||
const labs = require('../../../shared/labs');
|
||||
|
||||
const getCaptchaSettings = () => {
|
||||
if (labs.isSet('captcha')) {
|
||||
return {
|
||||
captcha_enabled: config.get('captcha:enabled'),
|
||||
captcha_sitekey: config.get('captcha:siteKey')
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
/** @type {import('@tryghost/api-framework').Controller} */
|
||||
const controller = {
|
||||
|
@ -18,7 +31,8 @@ const controller = {
|
|||
settingsCache.getPublic(), {
|
||||
url: urlUtils.urlFor('home', true),
|
||||
version: ghostVersion.safe
|
||||
}
|
||||
},
|
||||
getCaptchaSettings()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ const tiersService = require('../tiers');
|
|||
const newslettersService = require('../newsletters');
|
||||
const memberAttributionService = require('../member-attribution');
|
||||
const emailSuppressionList = require('../email-suppression-list');
|
||||
const CaptchaService = require('@tryghost/captcha-service');
|
||||
const {t} = require('../i18n');
|
||||
const sentry = require('../../../shared/sentry');
|
||||
const sharedConfig = require('../../../shared/config');
|
||||
|
@ -240,6 +241,11 @@ function createApiInstance(config) {
|
|||
settingsCache,
|
||||
sentry,
|
||||
settingsHelpers,
|
||||
captchaService: new CaptchaService({
|
||||
enabled: labsService.isSet('captcha') && sharedConfig.get('captcha:enabled'),
|
||||
scoreThreshold: sharedConfig.get('captcha:scoreThreshold'),
|
||||
secretKey: sharedConfig.get('captcha:secretKey')
|
||||
}),
|
||||
config: sharedConfig
|
||||
});
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
"@tryghost/audience-feedback": "0.0.0",
|
||||
"@tryghost/bookshelf-plugins": "0.6.25",
|
||||
"@tryghost/bootstrap-socket": "0.0.0",
|
||||
"@tryghost/captcha-service": "0.0.0",
|
||||
"@tryghost/color-utils": "0.2.2",
|
||||
"@tryghost/config-url-helpers": "1.0.12",
|
||||
"@tryghost/constants": "0.0.0",
|
||||
|
|
|
@ -104,3 +104,110 @@ Object {
|
|||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Settings Content API Captcha settings Can request captcha settings 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {},
|
||||
"settings": Object {
|
||||
"accent_color": "#FF1A75",
|
||||
"allow_self_signup": true,
|
||||
"captcha_enabled": true,
|
||||
"captcha_sitekey": "testkey",
|
||||
"codeinjection_foot": null,
|
||||
"codeinjection_head": null,
|
||||
"comments_enabled": "off",
|
||||
"cover_image": "https://static.ghost.org/v5.0.0/images/publication-cover.jpg",
|
||||
"default_email_address": "noreply@127.0.0.1",
|
||||
"description": "Thoughts, stories and ideas",
|
||||
"editor_default_email_recipients": "visibility",
|
||||
"facebook": "ghost",
|
||||
"firstpromoter_account": null,
|
||||
"icon": null,
|
||||
"labs": Any<Object>,
|
||||
"lang": "en",
|
||||
"locale": "en",
|
||||
"logo": null,
|
||||
"members_enabled": true,
|
||||
"members_invite_only": false,
|
||||
"members_signup_access": "all",
|
||||
"members_support_address": "noreply",
|
||||
"meta_description": null,
|
||||
"meta_title": null,
|
||||
"navigation": Array [
|
||||
Object {
|
||||
"label": "Home",
|
||||
"url": "/",
|
||||
},
|
||||
Object {
|
||||
"label": "About",
|
||||
"url": "/about/",
|
||||
},
|
||||
Object {
|
||||
"label": "Collection",
|
||||
"url": "/tag/getting-started/",
|
||||
},
|
||||
Object {
|
||||
"label": "Author",
|
||||
"url": "/author/ghost/",
|
||||
},
|
||||
Object {
|
||||
"label": "Portal",
|
||||
"url": "/portal/",
|
||||
},
|
||||
],
|
||||
"og_description": null,
|
||||
"og_image": null,
|
||||
"og_title": null,
|
||||
"outbound_link_tagging": true,
|
||||
"paid_members_enabled": true,
|
||||
"portal_button": true,
|
||||
"portal_button_icon": null,
|
||||
"portal_button_signup_text": "Subscribe",
|
||||
"portal_button_style": "icon-and-text",
|
||||
"portal_default_plan": "yearly",
|
||||
"portal_name": true,
|
||||
"portal_plans": Array [
|
||||
"free",
|
||||
],
|
||||
"portal_signup_checkbox_required": false,
|
||||
"portal_signup_terms_html": null,
|
||||
"recommendations_enabled": false,
|
||||
"secondary_navigation": Array [
|
||||
Object {
|
||||
"label": "Data & privacy",
|
||||
"url": "/privacy/",
|
||||
},
|
||||
Object {
|
||||
"label": "Contact",
|
||||
"url": "/contact/",
|
||||
},
|
||||
Object {
|
||||
"label": "Contribute →",
|
||||
"url": "/contribute/",
|
||||
},
|
||||
],
|
||||
"support_email_address": "noreply@127.0.0.1",
|
||||
"timezone": "Etc/UTC",
|
||||
"title": "Ghost",
|
||||
"twitter": "@ghost",
|
||||
"twitter_description": null,
|
||||
"twitter_image": null,
|
||||
"twitter_title": null,
|
||||
"url": "http://127.0.0.1:2369/",
|
||||
"version": Any<String>,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Settings Content API Captcha settings Can request captcha settings 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "*",
|
||||
"cache-control": "public, max-age=0",
|
||||
"content-length": StringMatching /\\\\d\\+/,
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
"vary": "Accept-Version, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const {agentProvider, fixtureManager, matchers} = require('../../utils/e2e-framework');
|
||||
const {anyEtag, anyContentLength, anyContentVersion} = matchers;
|
||||
const configUtils = require('../../utils/configUtils');
|
||||
|
||||
const settingsMatcher = {
|
||||
version: matchers.anyString,
|
||||
|
@ -27,4 +28,33 @@ describe('Settings Content API', function () {
|
|||
settings: settingsMatcher
|
||||
});
|
||||
});
|
||||
|
||||
describe('Captcha settings', function () {
|
||||
beforeEach(function () {
|
||||
configUtils.set('captcha', {
|
||||
enabled: true,
|
||||
siteKey: 'testkey'
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
it('Can request captcha settings', async function () {
|
||||
await agent.get('settings/')
|
||||
.expectStatus(200)
|
||||
.matchHeaderSnapshot({
|
||||
etag: anyEtag,
|
||||
'content-version': anyContentVersion,
|
||||
'content-length': anyContentLength
|
||||
})
|
||||
.matchBodySnapshot({
|
||||
settings: Object.assign({}, settingsMatcher, {
|
||||
captcha_enabled: true,
|
||||
captcha_sitekey: 'testkey'
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -74,6 +74,7 @@ module.exports = function MembersAPI({
|
|||
settingsCache,
|
||||
sentry,
|
||||
settingsHelpers,
|
||||
captchaService,
|
||||
config
|
||||
}) {
|
||||
const tokenService = new TokenService({
|
||||
|
@ -337,6 +338,7 @@ module.exports = function MembersAPI({
|
|||
const middleware = {
|
||||
sendMagicLink: Router().use(
|
||||
body.json(),
|
||||
captchaService.getMiddleware(),
|
||||
forwardError((req, res) => routerController.sendMagicLink(req, res))
|
||||
),
|
||||
createCheckoutSession: Router().use(
|
||||
|
|
Loading…
Add table
Reference in a new issue