mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Fixed admin host with port causing infinite redirect (#11767)
closes #11766, refs 7284227f1
- when we changed from host to hostname, more changed than just using the x-forwarded-host if trusted because express req.hostname does not return the port
- this causes issues with an infinite redirect if you try to set a different admin host with a port
- added a test to demonstrate the case, that didn't fail due to an error in the test logic
- switched from redirecting based on req.hostname to using req.vhost.host which has the correct trusted, requested value that we should rely on
- simplified the comparison logic to explicitly compare host with host
This commit is contained in:
parent
43dd253c12
commit
4a67ea5546
2 changed files with 28 additions and 9 deletions
|
@ -33,17 +33,17 @@ _private.redirectUrl = ({redirectTo, query, pathname}) => {
|
||||||
_private.getAdminRedirectUrl = ({requestedHost, requestedUrl, queryParameters, secure}) => {
|
_private.getAdminRedirectUrl = ({requestedHost, requestedUrl, queryParameters, secure}) => {
|
||||||
const siteUrl = urlUtils.urlFor('home', true);
|
const siteUrl = urlUtils.urlFor('home', true);
|
||||||
const adminUrl = urlUtils.urlFor('admin', true);
|
const adminUrl = urlUtils.urlFor('admin', true);
|
||||||
const adminUrlWithoutProtocol = adminUrl.replace(/(^\w+:|^)\/\//, '');
|
const siteHost = url.parse(siteUrl).host;
|
||||||
const siteUrlWithoutProtocol = siteUrl.replace(/(^\w+:|^)\/\//, '');
|
const adminHost = url.parse(adminUrl).host;
|
||||||
|
|
||||||
debug('getAdminRedirectUrl', requestedHost, requestedUrl, adminUrlWithoutProtocol, siteUrlWithoutProtocol, urlUtils.urlJoin(siteUrlWithoutProtocol, 'ghost/'));
|
debug('getAdminRedirectUrl', requestedHost, requestedUrl, adminHost, siteHost);
|
||||||
|
|
||||||
// CASE: we only redirect the admin access if `admin.url` is configured
|
// CASE: we only redirect the admin access if `admin.url` is configured
|
||||||
// If url and admin.url are not equal AND the requested host does not match, redirect.
|
// If url and admin.url are not equal AND the requested host does not match, redirect.
|
||||||
// The first condition is the most important, because it ensures that you have a custom admin url configured,
|
// The first condition is the most important, because it ensures that you have a custom admin url configured,
|
||||||
// because we don't force an admin redirect if you have a custom url configured, but no admin url.
|
// because we don't force an admin redirect if you have a custom url configured, but no admin url.
|
||||||
if (adminUrlWithoutProtocol !== urlUtils.urlJoin(siteUrlWithoutProtocol, 'ghost/') &&
|
if (adminHost !== siteHost &&
|
||||||
adminUrlWithoutProtocol !== urlUtils.urlJoin(requestedHost, urlUtils.getSubdir(), 'ghost/')) {
|
adminHost !== requestedHost) {
|
||||||
debug('redirect because admin host does not match');
|
debug('redirect because admin host does not match');
|
||||||
|
|
||||||
return _private.redirectUrl({
|
return _private.redirectUrl({
|
||||||
|
@ -73,7 +73,7 @@ _private.getAdminRedirectUrl = ({requestedHost, requestedUrl, queryParameters, s
|
||||||
_private.getFrontendRedirectUrl = ({requestedHost, requestedUrl, queryParameters, secure}) => {
|
_private.getFrontendRedirectUrl = ({requestedHost, requestedUrl, queryParameters, secure}) => {
|
||||||
const siteUrl = urlUtils.urlFor('home', true);
|
const siteUrl = urlUtils.urlFor('home', true);
|
||||||
|
|
||||||
debug('getsiteRedirectUrl', requestedHost, requestedUrl, siteUrl);
|
debug('getFrontendRedirectUrl', requestedHost, requestedUrl, siteUrl);
|
||||||
|
|
||||||
// CASE: configured canonical url is HTTPS, but request is HTTP, redirect to requested host + SSL
|
// CASE: configured canonical url is HTTPS, but request is HTTP, redirect to requested host + SSL
|
||||||
if (urlUtils.isSSL(siteUrl) && !secure) {
|
if (urlUtils.isSSL(siteUrl) && !secure) {
|
||||||
|
@ -89,7 +89,7 @@ _private.getFrontendRedirectUrl = ({requestedHost, requestedUrl, queryParameters
|
||||||
|
|
||||||
_private.redirect = (req, res, next, redirectFn) => {
|
_private.redirect = (req, res, next, redirectFn) => {
|
||||||
const redirectUrl = redirectFn({
|
const redirectUrl = redirectFn({
|
||||||
requestedHost: req.hostname,
|
requestedHost: req.vhost ? req.vhost.host : req.get('host'),
|
||||||
requestedUrl: url.parse(req.originalUrl || req.url).pathname,
|
requestedUrl: url.parse(req.originalUrl || req.url).pathname,
|
||||||
queryParameters: req.query,
|
queryParameters: req.query,
|
||||||
secure: req.secure
|
secure: req.secure
|
||||||
|
|
|
@ -13,8 +13,8 @@ describe('UNIT: url redirects', function () {
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
req = {
|
req = {
|
||||||
get hostname() {
|
get vhost() {
|
||||||
return host;
|
return {host: host};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
res = {
|
res = {
|
||||||
|
@ -356,6 +356,25 @@ describe('UNIT: url redirects', function () {
|
||||||
next.called.should.be.true();
|
next.called.should.be.true();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('url and admin url are different, request matches, uses a port', function (done) {
|
||||||
|
urlRedirects.__set__('urlUtils', urlUtils.getInstance({
|
||||||
|
url: 'https://default.com:2368',
|
||||||
|
adminUrl: 'https://admin.default.com:2368'
|
||||||
|
}));
|
||||||
|
|
||||||
|
host = 'admin.default.com:2368';
|
||||||
|
|
||||||
|
req.secure = true;
|
||||||
|
req.originalUrl = '/ghost';
|
||||||
|
redirect(req, res, next, getAdminRedirectUrl);
|
||||||
|
|
||||||
|
res.redirect.called.should.be.false();
|
||||||
|
res.set.called.should.be.false();
|
||||||
|
next.called.should.be.true();
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue