diff --git a/core/shared/url-utils.js b/core/shared/url-utils.js index 7f4cfda9c8..addf5b074a 100644 --- a/core/shared/url-utils.js +++ b/core/shared/url-utils.js @@ -2,8 +2,9 @@ const UrlUtils = require('@tryghost/url-utils'); const config = require('./config'); const urlUtils = new UrlUtils({ - url: config.get('url'), - adminUrl: config.get('admin:url'), + getSubdir: config.getSubdir, + getSiteUrl: config.getSiteUrl, + getAdminUrl: config.getAdminUrl, apiVersions: config.get('api:versions'), defaultApiVersion: config.get('api:versions:default'), slugs: config.get('slugs').protected, diff --git a/package.json b/package.json index 9b19641a5c..cd41faaba7 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@tryghost/string": "0.1.19", "@tryghost/tpl": "0.1.2", "@tryghost/update-check-service": "0.1.0", - "@tryghost/url-utils": "1.1.4", + "@tryghost/url-utils": "2.0.0", "@tryghost/validator": "0.1.1", "@tryghost/version": "0.1.0", "@tryghost/vhost-middleware": "1.0.15", diff --git a/test/unit/data/importer/index_spec.js b/test/unit/data/importer/index_spec.js index 7362ef2d70..6b31947f23 100644 --- a/test/unit/data/importer/index_spec.js +++ b/test/unit/data/importer/index_spec.js @@ -17,12 +17,13 @@ const MarkdownHandler = require('../../../../core/server/data/importer/handlers/ const DataImporter = require('../../../../core/server/data/importer/importers/data'); const ImageImporter = require('../../../../core/server/data/importer/importers/image'); const storage = require('../../../../core/server/adapters/storage'); -const urlUtils = require('../../../utils/urlUtils'); +const configUtils = require('../../../utils/configUtils'); describe('Importer', function () { afterEach(function () { sinon.restore(); ImageHandler = rewire('../../../../core/server/data/importer/handlers/image'); + configUtils.restore(); }); describe('ImportManager', function () { @@ -450,7 +451,7 @@ describe('Importer', function () { }); it('can load a file (subdirectory)', function (done) { - ImageHandler.__set__('urlUtils', urlUtils.getInstance({url: 'http://localhost:65535/subdir'})); + configUtils.set({url: 'http://localhost:65535/subdir'}); const filename = 'test-image.jpeg'; diff --git a/test/unit/data/meta/asset_url_spec.js b/test/unit/data/meta/asset_url_spec.js index 9a87edb3f5..4cca279732 100644 --- a/test/unit/data/meta/asset_url_spec.js +++ b/test/unit/data/meta/asset_url_spec.js @@ -4,7 +4,6 @@ const rewire = require('rewire'); const imageLib = require('../../../../core/server/lib/image'); const settingsCache = require('../../../../core/server/services/settings/cache'); const configUtils = require('../../../utils/configUtils'); -const urlUtils = require('../../../utils/urlUtils'); const config = configUtils.config; const getAssetUrl = rewire('../../../../core/frontend/meta/asset_url'); @@ -81,7 +80,11 @@ describe('getAssetUrl', function () { describe('with /blog subdirectory', function () { beforeEach(function () { - getAssetUrl.__set__('urlUtils', urlUtils.getInstance({url: 'http://localhost:65535/blog'})); + configUtils.set({url: 'http://localhost:65535/blog'}); + }); + + afterEach(function () { + configUtils.restore(); }); it('should return asset url with just context', function () { diff --git a/test/unit/data/meta/paginated_url_spec.js b/test/unit/data/meta/paginated_url_spec.js index 821e99d715..8989ac46f1 100644 --- a/test/unit/data/meta/paginated_url_spec.js +++ b/test/unit/data/meta/paginated_url_spec.js @@ -133,6 +133,7 @@ describe('getPaginatedUrl', function () { }); after(function () { + urlUtils.restore(); sandbox.restore(); }); diff --git a/test/unit/helpers/ghost_head_spec.js b/test/unit/helpers/ghost_head_spec.js index 8f4de5498a..a3d6b850da 100644 --- a/test/unit/helpers/ghost_head_spec.js +++ b/test/unit/helpers/ghost_head_spec.js @@ -316,6 +316,7 @@ describe('{{ghost_head}} helper', function () { afterEach(function () { sandbox.restore(); + testUrlUtils.restore(); }); it('returns meta tag string on paginated index page without structured data and schema', function (done) { @@ -1299,6 +1300,7 @@ describe('{{ghost_head}} helper', function () { afterEach(function () { sandbox.restore(); + testUrlUtils.restore(); routing.registry.getRssUrl.returns('http://localhost:65530/rss/'); }); @@ -1338,6 +1340,7 @@ describe('{{ghost_head}} helper', function () { afterEach(function () { sandbox.restore(); + testUrlUtils.restore(); }); it('contains the changed origin', function (done) { @@ -1375,6 +1378,7 @@ describe('{{ghost_head}} helper', function () { afterEach(function () { sandbox.restore(); + testUrlUtils.restore(); }); it('does not return structured data', function (done) { @@ -1418,6 +1422,7 @@ describe('{{ghost_head}} helper', function () { afterEach(function () { sandbox.restore(); + testUrlUtils.restore(); }); it('returns meta tag plus injected code', function (done) { diff --git a/test/unit/helpers/img_url_spec.js b/test/unit/helpers/img_url_spec.js index 1d46de6953..30eb04efc7 100644 --- a/test/unit/helpers/img_url_spec.js +++ b/test/unit/helpers/img_url_spec.js @@ -28,6 +28,7 @@ describe('{{image}} helper', function () { after(function () { sandbox.restore(); + urlUtils.restore(); }); it('should output relative url of image', function () { @@ -93,6 +94,7 @@ describe('{{image}} helper', function () { after(function () { sandbox.restore(); + urlUtils.restore(); }); it('should output relative url of image', function () { @@ -124,6 +126,7 @@ describe('{{image}} helper', function () { after(function () { sandbox.restore(); + urlUtils.restore(); }); it('should output correct url for absolute paths which are internal', function () { diff --git a/test/unit/helpers/url_spec.js b/test/unit/helpers/url_spec.js index 66fd4a7491..39ee3950a9 100644 --- a/test/unit/helpers/url_spec.js +++ b/test/unit/helpers/url_spec.js @@ -34,6 +34,7 @@ describe('{{url}} helper', function () { after(function () { sandbox.restore(); + urlUtils.restore(); }); it('should return the slug with a prefix slash if the context is a post', function () { @@ -278,6 +279,7 @@ describe('{{url}} helper', function () { after(function () { sandbox.restore(); + urlUtils.restore(); }); it('external urls should be retained in a nav context with subdir', function () { diff --git a/test/unit/services/members/config_spec.js b/test/unit/services/members/config_spec.js index 621d19a9d5..9880ba7157 100644 --- a/test/unit/services/members/config_spec.js +++ b/test/unit/services/members/config_spec.js @@ -1,18 +1,9 @@ const should = require('should'); const UrlUtils = require('@tryghost/url-utils'); const MembersConfigProvider = require('../../../../core/server/services/members/config'); -const sinon = require('sinon'); -/** - * @param {object} options - * @param {boolean} options.stripeDirectValue - The value the stripeDirect config property should have - */ -function createConfigMock({stripeDirectValue}) { - return { - get: sinon.stub() - .withArgs('stripeDirect').returns(stripeDirectValue) - }; -} +const configUtils = require('../../../utils/configUtils'); +const sinon = require('sinon'); /** * @param {object} options @@ -50,10 +41,11 @@ function createSettingsMock({setDirect, setConnect}) { }; } -function createUrlUtilsMock({url = 'http://domain.tld/subdir', adminUrl = 'http://sub.domain.tld'} = {}) { +function createUrlUtilsMock() { return new UrlUtils({ - url, - adminUrl, + getSubdir: configUtils.config.getSubdir, + getSiteUrl: configUtils.config.getSiteUrl, + getAdminUrl: configUtils.config.getAdminUrl, apiVersions: { all: ['v3'], v3: { @@ -69,13 +61,24 @@ function createUrlUtilsMock({url = 'http://domain.tld/subdir', adminUrl = 'http: } describe('Members - config', function () { + beforeEach(function () { + configUtils.set({ + url: 'http://domain.tld/subdir', + admin: {url: 'http://sub.domain.tld'} + }); + }); + + afterEach(function () { + configUtils.restore(); + }); it('Uses direct keys when stripeDirect is true, regardles of which keys exist', function () { - const config = createConfigMock({stripeDirectValue: true}); + configUtils.set({stripeDirect: true}); + const settingsCache = createSettingsMock({setDirect: true, setConnect: Math.random() < 0.5}); const urlUtils = createUrlUtilsMock(); const membersConfig = new MembersConfigProvider({ - config, + config: configUtils.config, settingsCache, urlUtils, ghostVersion: {original: 'v7357'}, @@ -89,12 +92,12 @@ describe('Members - config', function () { }); it('Does not use connect keys if stripeDirect is true, and the direct keys do not exist', function () { - const config = createConfigMock({stripeDirectValue: true}); + configUtils.set({stripeDirect: true}); const settingsCache = createSettingsMock({setDirect: false, setConnect: true}); const urlUtils = createUrlUtilsMock(); const membersConfig = new MembersConfigProvider({ - config, + config: configUtils.config, settingsCache, urlUtils, ghostVersion: {original: 'v7357'}, @@ -107,12 +110,12 @@ describe('Members - config', function () { }); it('Uses connect keys when stripeDirect is false, and the connect keys exist', function () { - const config = createConfigMock({stripeDirectValue: false}); + configUtils.set({stripeDirect: false}); const settingsCache = createSettingsMock({setDirect: true, setConnect: true}); const urlUtils = createUrlUtilsMock(); const membersConfig = new MembersConfigProvider({ - config, + config: configUtils.config, settingsCache, urlUtils, ghostVersion: {original: 'v7357'}, @@ -126,12 +129,12 @@ describe('Members - config', function () { }); it('Uses direct keys when stripeDirect is false, but the connect keys do not exist', function () { - const config = createConfigMock({stripeDirectValue: false}); + configUtils.set({stripeDirect: false}); const settingsCache = createSettingsMock({setDirect: true, setConnect: false}); const urlUtils = createUrlUtilsMock(); const membersConfig = new MembersConfigProvider({ - config, + config: configUtils.config, settingsCache, urlUtils, ghostVersion: {original: 'v7357'}, @@ -145,14 +148,15 @@ describe('Members - config', function () { }); it('Includes the subdirectory in the webhookHandlerUrl', function () { - const config = createConfigMock({stripeDirectValue: false}); - const settingsCache = createSettingsMock({setDirect: true, setConnect: false}); - const urlUtils = createUrlUtilsMock({ + configUtils.set({ + stripeDirect: false, url: 'http://site.com/subdir' }); + const settingsCache = createSettingsMock({setDirect: true, setConnect: false}); + const urlUtils = createUrlUtilsMock(); const membersConfig = new MembersConfigProvider({ - config, + config: configUtils.config, settingsCache, urlUtils, ghostVersion: {original: 'v7357'}, diff --git a/test/unit/services/rss/generate-feed_spec.js b/test/unit/services/rss/generate-feed_spec.js index c13707044c..7282e447ea 100644 --- a/test/unit/services/rss/generate-feed_spec.js +++ b/test/unit/services/rss/generate-feed_spec.js @@ -62,6 +62,7 @@ describe('RSS: Generate Feed', function () { afterEach(function () { sandbox.restore(); + urlUtils.restore(); }); it('should get the RSS tags correct', function (done) { diff --git a/test/unit/web/api/middleware/cors_spec.js b/test/unit/web/api/middleware/cors_spec.js index d84ca08759..0207b4e607 100644 --- a/test/unit/web/api/middleware/cors_spec.js +++ b/test/unit/web/api/middleware/cors_spec.js @@ -1,7 +1,7 @@ const should = require('should'); const sinon = require('sinon'); const rewire = require('rewire'); -const urlUtils = require('../../../../utils/urlUtils'); +const configUtils = require('../../../../utils/configUtils'); let cors = rewire('../../../../../core/server/web/api/middleware/cors'); @@ -32,6 +32,7 @@ describe('cors', function () { afterEach(function () { sinon.restore(); + configUtils.restore(); cors = rewire('../../../../../core/server/web/api/middleware/cors'); }); @@ -94,7 +95,7 @@ describe('cors', function () { it('should be enabled if the origin matches config.url', function (done) { const origin = 'http://my.blog'; - cors.__set__('urlUtils', urlUtils.getInstance({url: origin})); + configUtils.set({url: origin}); req.get = sinon.stub().withArgs('origin').returns(origin); res.get = sinon.stub().withArgs('origin').returns(origin); @@ -111,10 +112,12 @@ describe('cors', function () { it('should be enabled if the origin matches config.url', function (done) { const origin = 'http://admin:2222'; - cors.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'https://blog', - adminUrl: origin - })); + admin: { + url: origin + } + }); req.get = sinon.stub().withArgs('origin').returns(origin); res.get = sinon.stub().withArgs('origin').returns(origin); diff --git a/test/unit/web/shared/middleware/url-redirects_spec.js b/test/unit/web/shared/middleware/url-redirects_spec.js index c6f2202725..5a9354df87 100644 --- a/test/unit/web/shared/middleware/url-redirects_spec.js +++ b/test/unit/web/shared/middleware/url-redirects_spec.js @@ -2,6 +2,7 @@ const should = require('should'); const sinon = require('sinon'); const rewire = require('rewire'); const urlUtils = require('../../../../utils/urlUtils'); +const configUtils = require('../../../../utils/configUtils'); const urlRedirects = rewire('../../../../../core/server/web/shared/middlewares/url-redirects'); const {frontendSSLRedirect, adminSSLAndHostRedirect} = urlRedirects; const getAdminRedirectUrl = urlRedirects.__get__('_private.getAdminRedirectUrl'); @@ -30,6 +31,7 @@ describe('UNIT: url redirects', function () { afterEach(function () { sinon.restore(); + configUtils.restore(); host = null; }); @@ -42,7 +44,7 @@ describe('UNIT: url redirects', function () { }); it('frontendSSLRedirect passes getSiteRedirectUrl', function () { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({url: 'https://default.com:2368/'})); + configUtils.set({url: 'https://default.com:2368/'}); frontendSSLRedirect(req, res, next); @@ -50,7 +52,7 @@ describe('UNIT: url redirects', function () { }); it('adminSSLAndHostRedirect passes getAdminRedirectUrl', function () { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({url: 'https://default.com:2368/'})); + configUtils.set({url: 'https://default.com:2368/'}); adminSSLAndHostRedirect(req, res, next); @@ -60,9 +62,9 @@ describe('UNIT: url redirects', function () { describe('expect redirect', function () { it('site is https, request is http', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'https://default.com:2368/' - })); + }); host = 'default.com:2368'; @@ -76,9 +78,9 @@ describe('UNIT: url redirects', function () { }); it('site host is !== request host', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'https://default.com' - })); + }); host = 'localhost:2368'; req.originalUrl = '/'; @@ -92,10 +94,12 @@ describe('UNIT: url redirects', function () { describe(`admin redirects`, function () { it('url and admin url are equal, but protocol is different, request is http', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368', - adminUrl: 'https://default.com:2368' - })); + admin: { + url: 'https://default.com:2368' + } + }); host = 'default.com:2368'; @@ -108,10 +112,12 @@ describe('UNIT: url redirects', function () { }); it('url and admin url are different, request is http', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368', - adminUrl: 'https://admin.default.com:2368' - })); + admin: { + url: 'https://admin.default.com:2368' + } + }); host = 'default.com:2368'; @@ -124,10 +130,12 @@ describe('UNIT: url redirects', function () { }); it('subdirectory', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368/blog', - adminUrl: 'https://admin.default.com:2368' - })); + admin: { + url: 'https://admin.default.com:2368' + } + }); host = 'default.com:2368'; @@ -147,10 +155,12 @@ describe('UNIT: url redirects', function () { }); it('keeps query', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368', - adminUrl: 'https://admin.default.com:2368' - })); + admin: { + url: 'https://admin.default.com:2368' + } + }); host = 'default.com:2368'; @@ -167,10 +177,12 @@ describe('UNIT: url redirects', function () { }); it('original url has search params', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368', - adminUrl: 'https://admin.default.com:2368' - })); + admin: { + url: 'https://admin.default.com:2368' + } + }); host = 'default.com:2368'; @@ -187,15 +199,18 @@ describe('UNIT: url redirects', function () { }); it('ensure redirect loop won\'t happen', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368', - adminUrl: 'https://default.com:2368' - })); + admin: { + url: 'https://default.com:2368' + } + }); host = 'default.com:2368'; req.originalUrl = '/ghost'; redirect(req, res, next, getAdminRedirectUrl); + next.called.should.be.false(); res.redirect.calledWith(301, 'https://default.com:2368/ghost/').should.be.true(); res.set.called.should.be.true(); @@ -214,9 +229,9 @@ describe('UNIT: url redirects', function () { describe('expect no redirect', function () { it('site is http, request is http', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368/' - })); + }); host = 'default.com:2368'; @@ -230,9 +245,9 @@ describe('UNIT: url redirects', function () { }); it('site is http, request is https', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368/' - })); + }); host = 'default.com:2368'; @@ -246,9 +261,9 @@ describe('UNIT: url redirects', function () { }); it('blog is http, request is https (trailing slash is missing)', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368/' - })); + }); host = 'default.com:2368/'; @@ -262,9 +277,9 @@ describe('UNIT: url redirects', function () { }); it('blog is https, request is https', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'https://default.com:2368/' - })); + }); host = 'default.com:2368'; @@ -279,9 +294,9 @@ describe('UNIT: url redirects', function () { }); it('blog host is !== request host', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'https://default.com' - })); + }); host = 'localhost:2368'; @@ -296,9 +311,9 @@ describe('UNIT: url redirects', function () { describe(`admin redirects`, function () { it('admin is blog url and http, requester is http', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368' - })); + }); host = 'default.com:2368'; @@ -311,9 +326,9 @@ describe('UNIT: url redirects', function () { }); it('admin request, no custom admin.url configured', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://default.com:2368' - })); + }); host = 'localhost:2368'; @@ -326,10 +341,12 @@ describe('UNIT: url redirects', function () { }); it('url and admin url are different, protocol is different, request is not secure', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://ghost.org/blog/', - adminUrl: 'http://something.com' - })); + admin: { + url: 'http://something.com' + } + }); host = 'something.com'; req.secure = false; @@ -343,10 +360,12 @@ describe('UNIT: url redirects', function () { }); it('url and admin url are different, protocol is different, request is secure', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'http://ghost.org/blog/', - adminUrl: 'http://something.com' - })); + admin: { + url: 'http://something.com' + } + }); host = 'something.com'; req.secure = true; @@ -361,10 +380,12 @@ describe('UNIT: url redirects', function () { }); it('url and admin url are different, request matches, uses a port', function (done) { - urlRedirects.__set__('urlUtils', urlUtils.getInstance({ + configUtils.set({ url: 'https://default.com:2368', - adminUrl: 'https://admin.default.com:2368' - })); + admin: { + url: 'https://admin.default.com:2368' + } + }); host = 'admin.default.com:2368'; diff --git a/test/utils/urlUtils.js b/test/utils/urlUtils.js index 0c32470531..fffa40e143 100644 --- a/test/utils/urlUtils.js +++ b/test/utils/urlUtils.js @@ -1,6 +1,7 @@ const _ = require('lodash'); const sinon = require('sinon'); const UrlUtils = require('@tryghost/url-utils'); +const configUtils = require('./configUtils'); const config = require('../../core/shared/config'); const urlUtils = require('../../core/shared/url-utils'); @@ -8,8 +9,9 @@ const defaultSandbox = sinon.createSandbox(); const getInstance = (options) => { const opts = { - url: options.url, - adminUrl: options.adminUrl, + getSubdir: config.getSubdir, + getSiteUrl: config.getSiteUrl, + getAdminUrl: config.getAdminUrl, apiVersions: options.apiVersions, defaultApiVersion: 'v3', slugs: options.slugs, @@ -37,14 +39,20 @@ const stubUrlUtils = (options, sandbox) => { } }); + if (options.url) { + configUtils.set('url', options.url); + } + + if (options.adminUrl) { + configUtils.set('admin:url', options.adminUrl); + } + return stubInstance; }; // Method for regressions tests must be used with restore method const stubUrlUtilsFromConfig = () => { const options = { - url: config.get('url'), - adminUrl: config.get('admin:url'), apiVersions: config.get('api:versions'), defaultApiVersion: 'v3', slugs: config.get('slugs').protected, @@ -57,6 +65,7 @@ const stubUrlUtilsFromConfig = () => { const restore = () => { defaultSandbox.restore(); + configUtils.restore(); }; module.exports.stubUrlUtils = stubUrlUtils; diff --git a/yarn.lock b/yarn.lock index a7263120ce..ec41db222a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -999,7 +999,19 @@ lodash "4.17.21" moment "2.24.0" -"@tryghost/url-utils@1.1.4", "@tryghost/url-utils@^1.1.2": +"@tryghost/url-utils@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tryghost/url-utils/-/url-utils-2.0.0.tgz#6f73306d7c4e1b7d3775b4a8cb395c824436b6e0" + integrity sha512-gCZ2fX8T8Asv8foQ9mEpIVjK5sOD0dLIAExVubVLAhGcNrXbRhumHp+DgrzoD3/sWmR5LE+57Pob2QI7RF0m5g== + dependencies: + cheerio "^0.22.0" + moment "^2.27.0" + moment-timezone "^0.5.31" + remark "^11.0.2" + remark-footnotes "^1.0.0" + unist-util-visit "^2.0.0" + +"@tryghost/url-utils@^1.1.2": version "1.1.4" resolved "https://registry.yarnpkg.com/@tryghost/url-utils/-/url-utils-1.1.4.tgz#9b7ffeafcc4331d9d2cc842e59d4a0ea37eb151e" integrity sha512-WLjjjSl3Hh1S+6s8lTGtCM+FPgRHDodUr5BKzMzYY74E+CSkxGJ9WyuVI2J5s5SQw0lM0s8qylWKZtGU7Ca7Hg==