mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
🔒 Added admin:redirects
config option for disabling admin redirects
no issue - adds `config:redirects` config option that defaults to `true` - when set to `false` - `/ghost/` will 404 on the front-end when a separate admin url is configured - all `{resource}/edit/` URLs on the front-end will 404
This commit is contained in:
parent
95ea5265d5
commit
7e92b07233
9 changed files with 273 additions and 30 deletions
|
@ -1,4 +1,5 @@
|
||||||
const debug = require('ghost-ignition').debug('services:routing:taxonomy-router');
|
const debug = require('ghost-ignition').debug('services:routing:taxonomy-router');
|
||||||
|
const config = require('../../../server/config');
|
||||||
const common = require('../../../server/lib/common');
|
const common = require('../../../server/lib/common');
|
||||||
const ParentRouter = require('./ParentRouter');
|
const ParentRouter = require('./ParentRouter');
|
||||||
const RSSRouter = require('./RSSRouter');
|
const RSSRouter = require('./RSSRouter');
|
||||||
|
@ -53,7 +54,9 @@ class TaxonomyRouter extends ParentRouter {
|
||||||
this.mountRoute(urlUtils.urlJoin(this.permalinks.value, 'page', ':page(\\d+)'), controllers.channel);
|
this.mountRoute(urlUtils.urlJoin(this.permalinks.value, 'page', ':page(\\d+)'), controllers.channel);
|
||||||
|
|
||||||
// REGISTER: edit redirect to admin client e.g. /tag/:slug/edit
|
// REGISTER: edit redirect to admin client e.g. /tag/:slug/edit
|
||||||
|
if (config.get('admin:redirects')) {
|
||||||
this.mountRoute(urlUtils.urlJoin(this.permalinks.value, 'edit'), this._redirectEditOption.bind(this));
|
this.mountRoute(urlUtils.urlJoin(this.permalinks.value, 'edit'), this._redirectEditOption.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
common.events.emit('router.created', this);
|
common.events.emit('router.created', this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
const debug = require('ghost-ignition').debug('services:routing:controllers:entry'),
|
const debug = require('ghost-ignition').debug('services:routing:controllers:entry');
|
||||||
url = require('url'),
|
const url = require('url');
|
||||||
urlService = require('../../../services/url'),
|
const config = require('../../../../server/config');
|
||||||
urlUtils = require('../../../../server/lib/url-utils'),
|
const urlService = require('../../../services/url');
|
||||||
helpers = require('../helpers');
|
const urlUtils = require('../../../../server/lib/url-utils');
|
||||||
|
const helpers = require('../helpers');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Entry controller.
|
* @description Entry controller.
|
||||||
|
@ -32,6 +33,11 @@ module.exports = function entryController(req, res, next) {
|
||||||
|
|
||||||
// CASE: last param is of url is /edit, redirect to admin
|
// CASE: last param is of url is /edit, redirect to admin
|
||||||
if (lookup.isEditURL) {
|
if (lookup.isEditURL) {
|
||||||
|
if (!config.get('admin:redirects')) {
|
||||||
|
debug('is edit url but admin redirects are disabled');
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
debug('redirect. is edit url');
|
debug('redirect. is edit url');
|
||||||
const resourceType = entry.page ? 'page' : 'post';
|
const resourceType = entry.page ? 'page' : 'post';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
const debug = require('ghost-ignition').debug('services:routing:controllers:preview'),
|
const debug = require('ghost-ignition').debug('services:routing:controllers:preview');
|
||||||
urlService = require('../../url'),
|
const config = require('../../../../server/config');
|
||||||
urlUtils = require('../../../../server/lib/url-utils'),
|
const urlService = require('../../url');
|
||||||
helpers = require('../helpers');
|
const urlUtils = require('../../../../server/lib/url-utils');
|
||||||
|
const helpers = require('../helpers');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Preview Controller.
|
* @description Preview Controller.
|
||||||
|
@ -31,6 +32,11 @@ module.exports = function previewController(req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.params.options && req.params.options.toLowerCase() === 'edit') {
|
if (req.params.options && req.params.options.toLowerCase() === 'edit') {
|
||||||
|
// CASE: last param of the url is /edit but admin redirects are disabled
|
||||||
|
if (!config.get('admin:redirects')) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
// @TODO: we don't know which resource type it is, because it's a generic preview handler and the
|
// @TODO: we don't know which resource type it is, because it's a generic preview handler and the
|
||||||
// preview API returns {previews: []}
|
// preview API returns {previews: []}
|
||||||
// @TODO: figure out how to solve better
|
// @TODO: figure out how to solve better
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
"port": 2368
|
"port": 2368
|
||||||
},
|
},
|
||||||
|
"admin": {
|
||||||
|
"redirects": true
|
||||||
|
},
|
||||||
"updateCheck": {
|
"updateCheck": {
|
||||||
"url": "https://updates.ghost.org",
|
"url": "https://updates.ghost.org",
|
||||||
"forceUpdate": false
|
"forceUpdate": false
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const config = require('../../../config');
|
||||||
const urlUtils = require('../../../lib/url-utils');
|
const urlUtils = require('../../../lib/url-utils');
|
||||||
|
|
||||||
const adminRedirect = (path) => {
|
const adminRedirect = (path) => {
|
||||||
|
@ -10,6 +11,10 @@ const adminRedirect = (path) => {
|
||||||
// redirect to /ghost to the admin
|
// redirect to /ghost to the admin
|
||||||
module.exports = function adminRedirects() {
|
module.exports = function adminRedirects() {
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
|
if (config.get('admin:redirects')) {
|
||||||
router.get(/^\/ghost\/?$/, adminRedirect('/'));
|
router.get(/^\/ghost\/?$/, adminRedirect('/'));
|
||||||
|
}
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,17 +2,18 @@
|
||||||
// As it stands, these tests depend on the database, and as such are integration tests.
|
// As it stands, these tests depend on the database, and as such are integration tests.
|
||||||
// These tests are here to cover the headers sent with requests and high-level redirects that can't be
|
// These tests are here to cover the headers sent with requests and high-level redirects that can't be
|
||||||
// tested with the unit tests
|
// tested with the unit tests
|
||||||
const should = require('should'),
|
const should = require('should');
|
||||||
supertest = require('supertest'),
|
const supertest = require('supertest');
|
||||||
sinon = require('sinon'),
|
const sinon = require('sinon');
|
||||||
moment = require('moment'),
|
const moment = require('moment');
|
||||||
path = require('path'),
|
const path = require('path');
|
||||||
testUtils = require('../../utils'),
|
const testUtils = require('../../utils');
|
||||||
cheerio = require('cheerio'),
|
const configUtils = require('../../utils/configUtils');
|
||||||
config = require('../../../server/config'),
|
const cheerio = require('cheerio');
|
||||||
api = require('../../../server/api'),
|
const config = require('../../../server/config');
|
||||||
settingsCache = require('../../../server/services/settings/cache'),
|
const api = require('../../../server/api');
|
||||||
ghost = testUtils.startGhost;
|
const settingsCache = require('../../../server/services/settings/cache');
|
||||||
|
const ghost = testUtils.startGhost;
|
||||||
|
|
||||||
let request;
|
let request;
|
||||||
|
|
||||||
|
@ -284,6 +285,43 @@ describe('Dynamic Routing', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Edit with admin redirects disabled', function () {
|
||||||
|
before(function () {
|
||||||
|
configUtils.set('admin:redirects', false);
|
||||||
|
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(function (_ghostServer) {
|
||||||
|
ghostServer = _ghostServer;
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
configUtils.restore();
|
||||||
|
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(function (_ghostServer) {
|
||||||
|
ghostServer = _ghostServer;
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect without slash', function (done) {
|
||||||
|
request.get('/tag/getting-started/edit')
|
||||||
|
.expect('Location', '/tag/getting-started/edit/')
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||||
|
.expect(301)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not redirect to admin', function (done) {
|
||||||
|
request.get('/tag/getting-started/edit/')
|
||||||
|
.expect(404)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe.skip('Paged', function () {
|
describe.skip('Paged', function () {
|
||||||
// Inserting more posts takes a bit longer
|
// Inserting more posts takes a bit longer
|
||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
|
@ -529,6 +567,43 @@ describe('Dynamic Routing', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Edit with admin redirects disabled', function () {
|
||||||
|
before(function () {
|
||||||
|
configUtils.set('admin:redirects', false);
|
||||||
|
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(function (_ghostServer) {
|
||||||
|
ghostServer = _ghostServer;
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
configUtils.restore();
|
||||||
|
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(function (_ghostServer) {
|
||||||
|
ghostServer = _ghostServer;
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect without slash', function (done) {
|
||||||
|
request.get('/author/ghost-owner/edit')
|
||||||
|
.expect('Location', '/author/ghost-owner/edit/')
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||||
|
.expect(301)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not redirect to admin', function (done) {
|
||||||
|
request.get('/author/ghost-owner/edit/')
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(404)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Paged', function () {
|
describe('Paged', function () {
|
||||||
// Add enough posts to trigger pages
|
// Add enough posts to trigger pages
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
|
|
|
@ -193,6 +193,41 @@ describe('Frontend Routing', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Post edit with admin redirects disabled', function () {
|
||||||
|
before(function () {
|
||||||
|
configUtils.set('admin:redirects', false);
|
||||||
|
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(function () {
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
configUtils.restore();
|
||||||
|
|
||||||
|
return ghost({forceStart: true})
|
||||||
|
.then(function () {
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect without slash', function (done) {
|
||||||
|
request.get('/welcome/edit')
|
||||||
|
.expect('Location', '/welcome/edit/')
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||||
|
.expect(301)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not redirect to editor', function (done) {
|
||||||
|
request.get('/welcome/edit/')
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(404)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('AMP post', function () {
|
describe('AMP post', function () {
|
||||||
it('should redirect without slash', function (done) {
|
it('should redirect without slash', function (done) {
|
||||||
request.get('/welcome/amp')
|
request.get('/welcome/amp')
|
||||||
|
@ -357,6 +392,43 @@ describe('Frontend Routing', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('edit with admin redirects disabled', function () {
|
||||||
|
before(function (done) {
|
||||||
|
configUtils.set('admin:redirects', false);
|
||||||
|
|
||||||
|
ghost({forceStart: true})
|
||||||
|
.then(function () {
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
addPosts(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function (done) {
|
||||||
|
configUtils.restore();
|
||||||
|
|
||||||
|
ghost({forceStart: true})
|
||||||
|
.then(function () {
|
||||||
|
request = supertest.agent(config.get('url'));
|
||||||
|
addPosts(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect without slash', function (done) {
|
||||||
|
request.get('/static-page-test/edit')
|
||||||
|
.expect('Location', '/static-page-test/edit/')
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.year)
|
||||||
|
.expect(301)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not redirect to editor', function (done) {
|
||||||
|
request.get('/static-page-test/edit/')
|
||||||
|
.expect(404)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.end(doEnd(done));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('amp', function () {
|
describe('amp', function () {
|
||||||
it('should 404 for amp parameter', function (done) {
|
it('should 404 for amp parameter', function (done) {
|
||||||
// NOTE: only post pages are supported so the router doesn't have a way to distinguish if
|
// NOTE: only post pages are supported so the router doesn't have a way to distinguish if
|
||||||
|
|
|
@ -5397,6 +5397,54 @@ describe('Integration - Web - Site', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('separate admin host w/ admin redirects disabled', function () {
|
||||||
|
before(function () {
|
||||||
|
testUtils.integrationTesting.urlService.resetGenerators();
|
||||||
|
testUtils.integrationTesting.defaultMocks(sinon, {amp: true, apps: true});
|
||||||
|
testUtils.integrationTesting.overrideGhostConfig(configUtils);
|
||||||
|
|
||||||
|
configUtils.set('url', 'http://example.com');
|
||||||
|
configUtils.set('admin:url', 'https://admin.example.com');
|
||||||
|
configUtils.set('admin:redirects', false);
|
||||||
|
|
||||||
|
return testUtils.integrationTesting.initGhost()
|
||||||
|
.then(function () {
|
||||||
|
sinon.stub(themeService.getActive(), 'engine').withArgs('ghost-api').returns('v2');
|
||||||
|
sinon.stub(themeService.getActive(), 'config').withArgs('posts_per_page').returns(2);
|
||||||
|
|
||||||
|
app = siteApp({start: true});
|
||||||
|
return testUtils.integrationTesting.urlService.waitTillFinished();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
return appsService.init();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
before(function () {
|
||||||
|
urlUtils.stubUrlUtilsFromConfig();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(function () {
|
||||||
|
configUtils.restore();
|
||||||
|
urlUtils.restore();
|
||||||
|
sinon.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not redirect /ghost/ on configured url', function () {
|
||||||
|
const req = {
|
||||||
|
secure: false,
|
||||||
|
method: 'GET',
|
||||||
|
url: '/ghost/',
|
||||||
|
host: 'example.com'
|
||||||
|
};
|
||||||
|
|
||||||
|
return testUtils.mocks.express.invoke(app, req)
|
||||||
|
.then(function (response) {
|
||||||
|
response.statusCode.should.eql(404);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('same host separate protocol', function () {
|
describe('same host separate protocol', function () {
|
||||||
before(function () {
|
before(function () {
|
||||||
testUtils.integrationTesting.urlService.resetGenerators();
|
testUtils.integrationTesting.urlService.resetGenerators();
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
const should = require('should'),
|
const should = require('should');
|
||||||
sinon = require('sinon'),
|
const sinon = require('sinon');
|
||||||
testUtils = require('../../../../utils'),
|
const testUtils = require('../../../../utils');
|
||||||
urlService = require('../../../../../frontend/services/url'),
|
const configUtils = require('../../../../utils/configUtils');
|
||||||
urlUtils = require('../../../../../server/lib/url-utils'),
|
const urlService = require('../../../../../frontend/services/url');
|
||||||
controllers = require('../../../../../frontend/services/routing/controllers'),
|
const urlUtils = require('../../../../../server/lib/url-utils');
|
||||||
helpers = require('../../../../../frontend/services/routing/helpers'),
|
const controllers = require('../../../../../frontend/services/routing/controllers');
|
||||||
EDITOR_URL = `/editor/post/`;
|
const helpers = require('../../../../../frontend/services/routing/helpers');
|
||||||
|
const EDITOR_URL = `/editor/post/`;
|
||||||
|
|
||||||
describe('Unit - services/routing/controllers/entry', function () {
|
describe('Unit - services/routing/controllers/entry', function () {
|
||||||
let req, res, entryLookUpStub, secureStub, renderStub, post, page;
|
let req, res, entryLookUpStub, secureStub, renderStub, post, page;
|
||||||
|
@ -126,6 +127,30 @@ describe('Unit - services/routing/controllers/entry', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('isEditURL: true with admin redirects disabled', function (done) {
|
||||||
|
configUtils.set('admin:redirects', false);
|
||||||
|
|
||||||
|
req.path = post.url;
|
||||||
|
|
||||||
|
entryLookUpStub.withArgs(req.path, res.routerOptions)
|
||||||
|
.resolves({
|
||||||
|
isEditURL: true,
|
||||||
|
entry: post
|
||||||
|
});
|
||||||
|
|
||||||
|
urlUtils.redirectToAdmin.callsFake(function (statusCode, res, editorUrl) {
|
||||||
|
configUtils.restore();
|
||||||
|
done(new Error('redirectToAdmin was called'));
|
||||||
|
});
|
||||||
|
|
||||||
|
controllers.entry(req, res, (err) => {
|
||||||
|
configUtils.restore();
|
||||||
|
urlUtils.redirectToAdmin.called.should.eql(false);
|
||||||
|
should.not.exist(err);
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('type of router !== type of resource', function (done) {
|
it('type of router !== type of resource', function (done) {
|
||||||
req.path = post.url;
|
req.path = post.url;
|
||||||
res.routerOptions.resourceType = 'posts';
|
res.routerOptions.resourceType = 'posts';
|
||||||
|
|
Loading…
Add table
Reference in a new issue