ghost 4.23.0 → 4.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/.eslintrc.js +39 -0
  2. package/content/themes/casper/assets/built/casper.js +1 -1
  3. package/content/themes/casper/assets/built/casper.js.map +1 -1
  4. package/content/themes/casper/assets/built/global.css +1 -1
  5. package/content/themes/casper/assets/built/global.css.map +1 -1
  6. package/content/themes/casper/assets/built/screen.css +1 -1
  7. package/content/themes/casper/assets/built/screen.css.map +1 -1
  8. package/content/themes/casper/assets/css/global.css +6 -1
  9. package/content/themes/casper/assets/css/screen.css +50 -215
  10. package/content/themes/casper/default.hbs +2 -2
  11. package/content/themes/casper/package.json +3 -2
  12. package/content/themes/casper/post.hbs +1 -1
  13. package/content/themes/casper/yarn.lock +173 -123
  14. package/core/app.js +20 -5
  15. package/core/boot.js +77 -36
  16. package/core/bridge.js +10 -10
  17. package/core/built/assets/ghost-dark-ef86e3bc7f0fb83d39d3d6a49bff8dd5.css +1 -0
  18. package/core/built/assets/ghost.min-57c1e677f42d596942d317ce93e8a62c.css +1 -0
  19. package/core/built/assets/{ghost.min-cccc107e881b74c7aaf1a73e1e5e0dee.js → ghost.min-f3c6886e191d34450e9ffca0c8fa056e.js} +543 -618
  20. package/core/built/assets/icons/audio-upload.svg +8 -0
  21. package/core/built/assets/{vendor.min-c9002845b6c30ac978abdadde9f33d7c.js → vendor.min-b6b8d2a31d61830c2d8f65c5ba54236a.js} +2656 -2118
  22. package/core/frontend/apps/amp/lib/helpers/amp_content.js +2 -2
  23. package/core/frontend/apps/amp/lib/views/amp.hbs +75 -0
  24. package/core/frontend/apps/private-blogging/index.js +1 -1
  25. package/core/frontend/helpers/url.js +18 -1
  26. package/core/frontend/services/apps/index.js +1 -1
  27. package/core/frontend/services/apps/loader.js +3 -3
  28. package/core/frontend/services/card-assets/index.js +0 -12
  29. package/core/frontend/services/card-assets/service.js +22 -21
  30. package/core/frontend/services/helpers/handlebars.js +1 -1
  31. package/core/frontend/services/theme-engine/middleware/ensure-active-theme.js +34 -0
  32. package/core/frontend/services/theme-engine/middleware/index.js +6 -0
  33. package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +116 -0
  34. package/core/frontend/services/theme-engine/middleware/update-local-template-data.js +9 -0
  35. package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +57 -0
  36. package/core/frontend/src/cards/css/audio.css +186 -0
  37. package/core/frontend/src/cards/css/blockquote.css +27 -0
  38. package/core/frontend/src/cards/css/bookmark.css +7 -0
  39. package/core/frontend/src/cards/css/button.css +4 -0
  40. package/core/frontend/src/cards/css/callout.css +23 -15
  41. package/core/frontend/src/cards/css/gallery.css +13 -3
  42. package/core/frontend/src/cards/css/toggle.css +48 -15
  43. package/core/frontend/src/cards/js/audio.js +137 -0
  44. package/core/frontend/web/middleware/error-handler.js +93 -0
  45. package/core/frontend/web/middleware/handle-image-sizes.js +3 -6
  46. package/core/frontend/web/middleware/index.js +1 -0
  47. package/core/frontend/web/middleware/serve-public-file.js +25 -8
  48. package/core/frontend/web/site.js +2 -5
  49. package/core/server/adapters/scheduling/SchedulingDefault.js +2 -2
  50. package/core/server/adapters/storage/LocalStorageBase.js +2 -2
  51. package/core/server/api/canary/db.js +2 -2
  52. package/core/server/api/canary/media.js +3 -2
  53. package/core/server/api/canary/oembed.js +16 -1
  54. package/core/server/api/canary/session.js +1 -1
  55. package/core/server/api/canary/slugs.js +1 -1
  56. package/core/server/api/canary/utils/permissions.js +2 -2
  57. package/core/server/api/canary/utils/serializers/output/config.js +2 -6
  58. package/core/server/api/v2/db.js +2 -2
  59. package/core/server/api/v2/session.js +1 -1
  60. package/core/server/api/v2/slugs.js +1 -1
  61. package/core/server/api/v2/utils/permissions.js +2 -2
  62. package/core/server/api/v3/db.js +2 -2
  63. package/core/server/api/v3/session.js +1 -1
  64. package/core/server/api/v3/slugs.js +1 -1
  65. package/core/server/api/v3/utils/permissions.js +2 -2
  66. package/core/server/data/db/state-manager.js +4 -4
  67. package/core/server/data/exporter/export-filename.js +1 -1
  68. package/core/server/data/importer/handlers/json.js +1 -1
  69. package/core/server/data/importer/import-manager.js +1 -1
  70. package/core/server/data/importer/importers/data/base.js +1 -1
  71. package/core/server/data/migrations/utils.js +2 -2
  72. package/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js +1 -0
  73. package/core/server/data/migrations/versions/3.1/08-add-uuid-values-to-members.js +1 -0
  74. package/core/server/data/migrations/versions/3.22/02-settings-key-renames.js +2 -0
  75. package/core/server/data/migrations/versions/3.22/05-migrate-members-subscription-settings.js +3 -0
  76. package/core/server/data/migrations/versions/3.22/06-migrate-stripe-connect-settings.js +2 -0
  77. package/core/server/data/migrations/versions/3.23/01-migrate-bulk-email-settings.js +1 -0
  78. package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -0
  79. package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -0
  80. package/core/server/data/migrations/versions/3.38/04-populate-recipient-filter-column.js +2 -0
  81. package/core/server/data/migrations/versions/4.0/01-update-mobiledoc.js +2 -0
  82. package/core/server/data/migrations/versions/4.0/03-populate-status-column-for-members.js +4 -0
  83. package/core/server/data/migrations/versions/4.0/06-populate-members-subscribe-events-table.js +1 -0
  84. package/core/server/data/migrations/versions/4.0/17-populate-members-status-events-table.js +1 -0
  85. package/core/server/data/migrations/versions/4.0/18-transform-urls-absolute-to-transform-ready.js +5 -0
  86. package/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js +1 -0
  87. package/core/server/data/migrations/versions/4.0/23-regenerate-posts-html.js +1 -0
  88. package/core/server/data/migrations/versions/4.0/25-populate-members-paid-subscription-events-table.js +2 -1
  89. package/core/server/data/migrations/versions/4.12/02-fix-member-statuses.js +1 -0
  90. package/core/server/data/migrations/versions/4.14/01-fix-comped-member-statuses.js +3 -0
  91. package/core/server/data/migrations/versions/4.14/02-fix-free-members-status-events.js +1 -0
  92. package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +2 -0
  93. package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +1 -0
  94. package/core/server/data/migrations/versions/4.3/04-attach-members-to-product.js +1 -0
  95. package/core/server/data/migrations/versions/4.4/01-restore-free-members-signup-setting-from-backup.js +1 -0
  96. package/core/server/data/migrations/versions/4.6/01-remove-comped-status.js +1 -0
  97. package/core/server/data/migrations/versions/4.8/04-migrate-show-newsletter-header-setting.js +1 -0
  98. package/core/server/data/migrations/versions/4.9/05-fix-missed-mobiledoc-url-transforms.js +1 -0
  99. package/core/server/data/migrations/versions/4.9/06-add-comped-status.js +1 -0
  100. package/core/server/data/migrations/versions/4.9/07-update-comped-members-status-events.js +1 -0
  101. package/core/server/data/schema/commands.js +2 -2
  102. package/core/server/ghost-server.js +2 -2
  103. package/core/server/lib/image/image-size.js +2 -2
  104. package/core/server/models/base/listeners.js +2 -2
  105. package/core/server/models/member-email-change-event.js +2 -2
  106. package/core/server/models/member-login-event.js +2 -2
  107. package/core/server/models/member-paid-subscription-event.js +3 -3
  108. package/core/server/models/member-payment-event.js +3 -3
  109. package/core/server/models/member-product-event.js +6 -6
  110. package/core/server/models/member-status-event.js +5 -3
  111. package/core/server/models/member-subscribe-event.js +9 -3
  112. package/core/server/models/relations/authors.js +1 -1
  113. package/core/server/models/settings.js +1 -1
  114. package/core/server/notify.js +1 -2
  115. package/core/server/services/auth/passwordreset.js +1 -1
  116. package/core/server/services/auth/setup.js +1 -1
  117. package/core/server/services/email-analytics/jobs/index.js +1 -1
  118. package/core/server/services/mega/mega.js +6 -4
  119. package/core/server/services/mega/template.js +47 -17
  120. package/core/server/services/members/api.js +22 -0
  121. package/core/server/services/members/config.js +1 -1
  122. package/core/server/services/members/emails/signup-paid.js +168 -0
  123. package/core/server/services/members/service.js +6 -2
  124. package/core/server/services/members/stripe-connect.js +4 -2
  125. package/core/server/services/nft-oembed.js +7 -2
  126. package/core/server/services/oembed.js +15 -3
  127. package/core/server/services/permissions/can-this.js +1 -1
  128. package/core/server/services/redirects/api.js +20 -25
  129. package/core/server/services/redirects/index.js +18 -10
  130. package/core/server/services/redirects/utils.js +14 -0
  131. package/core/server/services/redirects/validation.js +10 -0
  132. package/core/server/services/route-settings/default-settings-manager.js +1 -1
  133. package/core/server/services/route-settings/index.js +40 -17
  134. package/core/server/services/route-settings/route-settings.js +120 -115
  135. package/core/server/services/route-settings/settings-loader.js +18 -36
  136. package/core/server/services/route-settings/yaml-parser.js +1 -1
  137. package/core/server/services/slack.js +1 -1
  138. package/core/server/services/themes/activation-bridge.js +3 -3
  139. package/core/server/services/themes/storage.js +2 -2
  140. package/core/server/services/twitter-embed.js +81 -0
  141. package/core/server/services/url/LocalFileCache.js +75 -0
  142. package/core/server/services/url/UrlService.js +15 -47
  143. package/core/server/services/url/index.js +17 -4
  144. package/core/server/services/xmlrpc.js +2 -2
  145. package/core/server/web/admin/app.js +2 -5
  146. package/core/server/web/admin/controller.js +35 -12
  147. package/core/server/web/admin/middleware/redirect-admin-urls.js +15 -0
  148. package/core/server/web/admin/views/default-prod.html +4 -4
  149. package/core/server/web/admin/views/default.html +4 -4
  150. package/core/server/web/api/canary/admin/app.js +0 -3
  151. package/core/server/web/api/canary/admin/middleware.js +1 -1
  152. package/core/server/web/api/canary/content/app.js +0 -3
  153. package/core/server/web/api/v2/admin/app.js +0 -3
  154. package/core/server/web/api/v2/admin/middleware.js +1 -1
  155. package/core/server/web/api/v2/content/app.js +0 -3
  156. package/core/server/web/api/v3/admin/app.js +0 -3
  157. package/core/server/web/api/v3/admin/middleware.js +1 -1
  158. package/core/server/web/api/v3/content/app.js +0 -3
  159. package/core/server/web/members/app.js +0 -3
  160. package/core/server/web/oauth/app.js +0 -4
  161. package/core/server/web/parent/app.js +2 -13
  162. package/core/server/web/parent/backend.js +2 -0
  163. package/core/server/web/shared/middleware/error-handler.js +57 -162
  164. package/core/server/web/shared/middleware/index.js +0 -4
  165. package/core/shared/config/defaults.json +7 -1
  166. package/core/shared/express.js +1 -1
  167. package/core/shared/labs.js +12 -7
  168. package/core/shared/sentry.js +1 -1
  169. package/package.json +41 -40
  170. package/yarn.lock +799 -948
  171. package/content/themes/casper/assets/js/gallery-card.js +0 -24
  172. package/core/built/assets/ghost-dark-42cf6e0c730578940ec069bda45aea41.css +0 -1
  173. package/core/built/assets/ghost.min-fcf6a0738421f86c47c55f20d00c5ba9.css +0 -1
  174. package/core/frontend/services/theme-engine/middleware.js +0 -209
  175. package/core/server/web/shared/middleware/maintenance.js +0 -25
@@ -0,0 +1,75 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ class LocalFileCache {
5
+ /**
6
+ * @param {Object} options
7
+ * @param {String} options.storagePath - cached storage path
8
+ * @param {Boolean} options.writeDisabled - controls if cache can write
9
+ */
10
+ constructor({storagePath, writeDisabled}) {
11
+ const urlsStoragePath = path.join(storagePath, 'urls.json');
12
+ const resourcesCachePath = path.join(storagePath, 'resources.json');
13
+
14
+ this.storagePaths = {
15
+ urls: urlsStoragePath,
16
+ resources: resourcesCachePath
17
+ };
18
+ this.writeDisabled = writeDisabled;
19
+ }
20
+
21
+ /**
22
+ * Handles reading and parsing JSON from the filesystem.
23
+ * In case the file is corrupted or does not exist, returns null.
24
+ * @param {String} filePath path to read from
25
+ * @returns {Promise<Object>}
26
+ * @private
27
+ */
28
+ async readCacheFile(filePath) {
29
+ let cacheExists = false;
30
+ let cacheData = null;
31
+
32
+ try {
33
+ await fs.stat(filePath);
34
+ cacheExists = true;
35
+ } catch (e) {
36
+ cacheExists = false;
37
+ }
38
+
39
+ if (cacheExists) {
40
+ try {
41
+ const cacheFile = await fs.readFile(filePath, 'utf8');
42
+ cacheData = JSON.parse(cacheFile);
43
+ } catch (e) {
44
+ //noop as we'd start a long boot process if there are any errors in the file
45
+ }
46
+ }
47
+
48
+ return cacheData;
49
+ }
50
+
51
+ /**
52
+ *
53
+ * @param {'urls'|'resources'} type
54
+ * @returns {Promise<Object>}
55
+ */
56
+ async read(type) {
57
+ return await this.readCacheFile(this.storagePaths[type]);
58
+ }
59
+
60
+ /**
61
+ *
62
+ * @param {'urls'|'resources'} type of data to persist
63
+ * @param {Object} data - data to be persisted
64
+ * @returns {Promise<Object>}
65
+ */
66
+ async write(type, data) {
67
+ if (this.writeDisabled) {
68
+ return null;
69
+ }
70
+
71
+ return fs.writeFile(this.storagePaths[type], JSON.stringify(data, null, 4));
72
+ }
73
+ }
74
+
75
+ module.exports = LocalFileCache;
@@ -1,4 +1,3 @@
1
- const fs = require('fs-extra');
2
1
  const _debug = require('@tryghost/debug')._base;
3
2
  const debug = _debug('ghost:services:url:service');
4
3
  const _ = require('lodash');
@@ -22,13 +21,13 @@ class UrlService {
22
21
  /**
23
22
  *
24
23
  * @param {Object} options
25
- * @param {String} [options.urlsCachePath] - cached URLs storage path
26
- * @param {String} [options.resourcesCachePath] - cached resources storage path
24
+ * @param {Object} [options.cache] - cache handler instance
25
+ * @param {Function} [options.cache.read] - read cache by type
26
+ * @param {Function} [options.cache.write] - write into cache by type
27
27
  */
28
- constructor({urlsCachePath, resourcesCachePath} = {}) {
28
+ constructor({cache} = {}) {
29
29
  this.utils = urlUtils;
30
- this.urlsCachePath = urlsCachePath;
31
- this.resourcesCachePath = resourcesCachePath;
30
+ this.cache = cache;
32
31
  this.onFinished = null;
33
32
  this.finished = false;
34
33
  this.urlGenerators = [];
@@ -319,26 +318,22 @@ class UrlService {
319
318
  * @description Initializes components needed for the URL Service to function
320
319
  * @param {Object} options
321
320
  * @param {Function} [options.onFinished] - callback when url generation is finished
321
+ * @param {Boolean} [options.urlCache] - whether to init using url cache or not
322
322
  */
323
- async init(options = {}) {
324
- this.onFinished = options.onFinished;
323
+ async init({onFinished, urlCache} = {}) {
324
+ this.onFinished = onFinished;
325
325
 
326
326
  let persistedUrls;
327
327
  let persistedResources;
328
328
 
329
- if (labs.isSet('urlCache')) {
330
- persistedUrls = await this.readCacheFile(this.urlsCachePath);
331
- persistedResources = await this.readCacheFile(this.resourcesCachePath);
329
+ if (this.cache && (labs.isSet('urlCache') || urlCache)) {
330
+ persistedUrls = await this.cache.read('urls');
331
+ persistedResources = await this.cache.read('resources');
332
332
  }
333
333
 
334
334
  if (persistedUrls && persistedResources) {
335
- this.urls = new Urls({
336
- urls: persistedUrls
337
- });
338
- this.resources = new Resources({
339
- queue: this.queue,
340
- resources: persistedResources
341
- });
335
+ this.urls.urls = persistedUrls;
336
+ this.resources.data = persistedResources;
342
337
  this.resources.initResourceConfig();
343
338
  this.resources.initEvenListeners();
344
339
 
@@ -361,35 +356,8 @@ class UrlService {
361
356
  return null;
362
357
  }
363
358
 
364
- await this.persistToCacheFile(this.urlsCachePath, this.urls.urls);
365
- await this.persistToCacheFile(this.resourcesCachePath, this.resources.getAll());
366
- }
367
-
368
- async persistToCacheFile(filePath, data) {
369
- return fs.writeFile(filePath, JSON.stringify(data, null, 4));
370
- }
371
-
372
- async readCacheFile(filePath) {
373
- let cacheExists = false;
374
- let cacheData;
375
-
376
- try {
377
- await fs.stat(filePath);
378
- cacheExists = true;
379
- } catch (e) {
380
- cacheExists = false;
381
- }
382
-
383
- if (cacheExists) {
384
- try {
385
- const cacheFile = await fs.readFile(filePath, 'utf8');
386
- cacheData = JSON.parse(cacheFile);
387
- } catch (e) {
388
- //noop as we'd start a long boot process if there are any errors in the file
389
- }
390
- }
391
-
392
- return cacheData;
359
+ await this.cache.write('urls', this.urls.urls);
360
+ await this.cache.write('resources', this.resources.getAll());
393
361
  }
394
362
 
395
363
  /**
@@ -1,13 +1,26 @@
1
- const path = require('path');
2
1
  const config = require('../../../shared/config');
2
+ const LocalFileCache = require('./LocalFileCache');
3
3
  const UrlService = require('./UrlService');
4
4
 
5
5
  // NOTE: instead of a path we could give UrlService a "data-resolver" of some sort
6
6
  // so it doesn't have to contain the logic to read data at all. This would be
7
7
  // a possible improvement in the future
8
- const urlsCachePath = path.join(config.getContentPath('data'), 'urls.json');
9
- const resourcesCachePath = path.join(config.getContentPath('data'), 'resources.json');
10
- const urlService = new UrlService({urlsCachePath, resourcesCachePath});
8
+ let writeDisabled = false;
9
+ let storagePath = config.getContentPath('data');
10
+
11
+ // TODO: remove this hack in favor of loading from the content path when it's possible to do so
12
+ // by mocking content folders in pre-boot phase
13
+ if (process.env.NODE_ENV.startsWith('test')){
14
+ storagePath = config.get('paths').urlCache;
15
+
16
+ // NOTE: prevents test suites from overwriting cache fixtures.
17
+ // A better solution would be injecting a different implementation of the
18
+ // cache based on the environment, this approach should do the trick for now
19
+ writeDisabled = true;
20
+ }
21
+
22
+ const cache = new LocalFileCache({storagePath, writeDisabled});
23
+ const urlService = new UrlService({cache});
11
24
 
12
25
  // Singleton
13
26
  module.exports = urlService;
@@ -87,7 +87,7 @@ function ping(post) {
87
87
  if (!goodResponse.test(res.body)) {
88
88
  const matches = res.body.match(errorMessage);
89
89
  const message = matches ? matches[1] : res.body;
90
- throw new errors.GhostError({message});
90
+ throw new errors.InternalServerError({message});
91
91
  }
92
92
  })
93
93
  .catch(function (err) {
@@ -100,7 +100,7 @@ function ping(post) {
100
100
  help: tpl(messages.requestFailedHelp, {url: 'https://ghost.org/docs/'})
101
101
  });
102
102
  } else {
103
- error = new errors.GhostError({
103
+ error = new errors.InternalServerError({
104
104
  err: err,
105
105
  message: err.message,
106
106
  context: tpl(messages.requestFailedError, {service: 'xmlrpc'}),
@@ -5,7 +5,7 @@ const config = require('../../../shared/config');
5
5
  const constants = require('@tryghost/constants');
6
6
  const urlUtils = require('../../../shared/url-utils');
7
7
  const shared = require('../shared');
8
- const adminMiddleware = require('./middleware');
8
+ const redirectAdminUrls = require('./middleware/redirect-admin-urls');
9
9
 
10
10
  module.exports = function setupAdminApp() {
11
11
  debug('Admin setup start');
@@ -26,9 +26,6 @@ module.exports = function setupAdminApp() {
26
26
  });
27
27
  }
28
28
 
29
- // Render error page in case of maintenance
30
- adminApp.use(shared.middleware.maintenance);
31
-
32
29
  // Force SSL if required
33
30
  // must happen AFTER asset loading and BEFORE routing
34
31
  adminApp.use(shared.middleware.urlRedirects.adminSSLAndHostRedirect);
@@ -42,7 +39,7 @@ module.exports = function setupAdminApp() {
42
39
  adminApp.use(shared.middleware.cacheControl('private'));
43
40
 
44
41
  // Special redirects for the admin (these should have their own cache-control headers)
45
- adminApp.use(adminMiddleware);
42
+ adminApp.use(redirectAdminUrls);
46
43
 
47
44
  // Finally, routing
48
45
  adminApp.get('*', require('./controller'));
@@ -1,10 +1,20 @@
1
1
  const debug = require('@tryghost/debug')('web:admin:controller');
2
+ const errors = require('@tryghost/errors');
3
+ const tpl = require('@tryghost/tpl');
2
4
  const path = require('path');
3
5
  const fs = require('fs');
4
6
  const crypto = require('crypto');
5
7
  const config = require('../../../shared/config');
6
8
  const updateCheck = require('../../update-check');
7
9
 
10
+ const messages = {
11
+ templateError: {
12
+ message: 'Unable to find admin template file {templatePath}',
13
+ context: 'These template files are generated as part of the build process',
14
+ help: 'Please see {link}'
15
+ }
16
+ };
17
+
8
18
  /**
9
19
  * @description Admin controller to handle /ghost/ requests.
10
20
  *
@@ -23,18 +33,31 @@ module.exports = function adminController(req, res) {
23
33
  const templatePath = path.resolve(config.get('paths').adminViews, defaultTemplate);
24
34
  const headers = {};
25
35
 
26
- // Generate our own ETag header
27
- // `sendFile` by default uses filesize+lastmod date to generate an etag.
28
- // That doesn't work for admin templates because the filesize doesn't change between versions
29
- // and `npm pack` sets a fixed lastmod date for every file meaning the default etag never changes
30
- const fileBuffer = fs.readFileSync(templatePath);
31
- const hashSum = crypto.createHash('md5');
32
- hashSum.update(fileBuffer);
33
- headers.ETag = hashSum.digest('hex');
36
+ try {
37
+ // Generate our own ETag header
38
+ // `sendFile` by default uses filesize+lastmod date to generate an etag.
39
+ // That doesn't work for admin templates because the filesize doesn't change between versions
40
+ // and `npm pack` sets a fixed lastmod date for every file meaning the default etag never changes
41
+ const fileBuffer = fs.readFileSync(templatePath);
42
+ const hashSum = crypto.createHash('md5');
43
+ hashSum.update(fileBuffer);
44
+ headers.ETag = hashSum.digest('hex');
34
45
 
35
- if (config.get('adminFrameProtection')) {
36
- headers['X-Frame-Options'] = 'sameorigin';
37
- }
46
+ if (config.get('adminFrameProtection')) {
47
+ headers['X-Frame-Options'] = 'sameorigin';
48
+ }
38
49
 
39
- res.sendFile(templatePath, {headers});
50
+ res.sendFile(templatePath, {headers});
51
+ } catch (error) {
52
+ if (error.code === 'ENOENT') {
53
+ throw new errors.IncorrectUsageError({
54
+ message: tpl(messages.templateError.message, {templatePath}),
55
+ context: tpl(messages.templateError.context),
56
+ help: tpl(messages.templateError.help, {link: 'https://ghost.org/docs/install/source/'}),
57
+ error: error
58
+ });
59
+ } else {
60
+ throw error;
61
+ }
62
+ }
40
63
  };
@@ -0,0 +1,15 @@
1
+ const urlUtils = require('../../../../shared/url-utils');
2
+
3
+ function redirectAdminUrls(req, res, next) {
4
+ const subdir = urlUtils.getSubdir();
5
+ const ghostPathRegex = new RegExp(`^${subdir}/ghost/(.+)`);
6
+ const ghostPathMatch = req.originalUrl.match(ghostPathRegex);
7
+
8
+ if (ghostPathMatch) {
9
+ return res.redirect(urlUtils.urlJoin(urlUtils.urlFor('admin'), '#', ghostPathMatch[1]));
10
+ }
11
+
12
+ next();
13
+ }
14
+
15
+ module.exports = redirectAdminUrls;
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.23%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.26%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -41,7 +41,7 @@
41
41
 
42
42
 
43
43
  <link rel="stylesheet" href="assets/vendor.min-987af30228885bce50f05c4723fe6f53.css">
44
- <link rel="stylesheet" href="assets/ghost.min-fcf6a0738421f86c47c55f20d00c5ba9.css" title="light">
44
+ <link rel="stylesheet" href="assets/ghost.min-57c1e677f42d596942d317ce93e8a62c.css" title="light">
45
45
 
46
46
 
47
47
 
@@ -59,8 +59,8 @@
59
59
  <div id="ember-basic-dropdown-wormhole"></div>
60
60
 
61
61
 
62
- <script src="assets/vendor.min-c9002845b6c30ac978abdadde9f33d7c.js"></script>
63
- <script src="assets/ghost.min-cccc107e881b74c7aaf1a73e1e5e0dee.js"></script>
62
+ <script src="assets/vendor.min-b6b8d2a31d61830c2d8f65c5ba54236a.js"></script>
63
+ <script src="assets/ghost.min-f3c6886e191d34450e9ffca0c8fa056e.js"></script>
64
64
 
65
65
  </body>
66
66
  </html>
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.23%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%224.26%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22emberKeyboard%22%3A%7B%22disableInputsInitializer%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -41,7 +41,7 @@
41
41
 
42
42
 
43
43
  <link rel="stylesheet" href="assets/vendor.min-987af30228885bce50f05c4723fe6f53.css">
44
- <link rel="stylesheet" href="assets/ghost.min-fcf6a0738421f86c47c55f20d00c5ba9.css" title="light">
44
+ <link rel="stylesheet" href="assets/ghost.min-57c1e677f42d596942d317ce93e8a62c.css" title="light">
45
45
 
46
46
 
47
47
 
@@ -59,8 +59,8 @@
59
59
  <div id="ember-basic-dropdown-wormhole"></div>
60
60
 
61
61
 
62
- <script src="assets/vendor.min-c9002845b6c30ac978abdadde9f33d7c.js"></script>
63
- <script src="assets/ghost.min-cccc107e881b74c7aaf1a73e1e5e0dee.js"></script>
62
+ <script src="assets/vendor.min-b6b8d2a31d61830c2d8f65c5ba54236a.js"></script>
63
+ <script src="assets/ghost.min-f3c6886e191d34450e9ffca0c8fa056e.js"></script>
64
64
 
65
65
  </body>
66
66
  </html>
@@ -19,9 +19,6 @@ module.exports = function setupApiApp() {
19
19
  // Query parsing
20
20
  apiApp.use(boolParser());
21
21
 
22
- // send 503 json response in case of maintenance
23
- apiApp.use(shared.middleware.maintenance);
24
-
25
22
  // Check version matches for API requests, depends on res.locals.safeVersion being set
26
23
  // Therefore must come after themeHandler.ghostLocals, for now
27
24
  apiApp.use(apiMw.versionMatch);
@@ -44,7 +44,7 @@ const notImplemented = function (req, res, next) {
44
44
  }
45
45
  }
46
46
 
47
- next(new errors.GhostError({
47
+ next(new errors.InternalServerError({
48
48
  errorType: 'NotImplementedError',
49
49
  message: tpl(messages.notImplemented),
50
50
  statusCode: '501'
@@ -17,9 +17,6 @@ module.exports = function setupApiApp() {
17
17
  // Query parsing
18
18
  apiApp.use(boolParser());
19
19
 
20
- // send 503 json response in case of maintenance
21
- apiApp.use(shared.middleware.maintenance);
22
-
23
20
  // API shouldn't be cached
24
21
  apiApp.use(shared.middleware.cacheControl('private'));
25
22
 
@@ -19,9 +19,6 @@ module.exports = function setupApiApp() {
19
19
  // Query parsing
20
20
  apiApp.use(boolParser());
21
21
 
22
- // send 503 json response in case of maintenance
23
- apiApp.use(shared.middleware.maintenance);
24
-
25
22
  // Check version matches for API requests, depends on res.locals.safeVersion being set
26
23
  // Therefore must come after themeHandler.ghostLocals, for now
27
24
  apiApp.use(apiMw.versionMatch);
@@ -40,7 +40,7 @@ const notImplemented = function (req, res, next) {
40
40
  }
41
41
  }
42
42
 
43
- next(new errors.GhostError({
43
+ next(new errors.InternalServerError({
44
44
  errorType: 'NotImplementedError',
45
45
  message: tpl(messages.notImplemented),
46
46
  statusCode: '501'
@@ -17,9 +17,6 @@ module.exports = function setupApiApp() {
17
17
  // Query parsing
18
18
  apiApp.use(boolParser());
19
19
 
20
- // send 503 json response in case of maintenance
21
- apiApp.use(shared.middleware.maintenance);
22
-
23
20
  // API shouldn't be cached
24
21
  apiApp.use(shared.middleware.cacheControl('private'));
25
22
 
@@ -19,9 +19,6 @@ module.exports = function setupApiApp() {
19
19
  // Query parsing
20
20
  apiApp.use(boolParser());
21
21
 
22
- // send 503 json response in case of maintenance
23
- apiApp.use(shared.middleware.maintenance);
24
-
25
22
  // Check version matches for API requests, depends on res.locals.safeVersion being set
26
23
  // Therefore must come after themeHandler.ghostLocals, for now
27
24
  apiApp.use(apiMw.versionMatch);
@@ -44,7 +44,7 @@ const notImplemented = function (req, res, next) {
44
44
  }
45
45
  }
46
46
 
47
- next(new errors.GhostError({
47
+ next(new errors.InternalServerError({
48
48
  errorType: 'NotImplementedError',
49
49
  message: tpl(messages.notImplemented),
50
50
  statusCode: '501'
@@ -17,9 +17,6 @@ module.exports = function setupApiApp() {
17
17
  // Query parsing
18
18
  apiApp.use(boolParser());
19
19
 
20
- // send 503 json response in case of maintenance
21
- apiApp.use(shared.middleware.maintenance);
22
-
23
20
  // API shouldn't be cached
24
21
  apiApp.use(shared.middleware.cacheControl('private'));
25
22
 
@@ -13,9 +13,6 @@ module.exports = function setupMembersApp() {
13
13
  debug('Members App setup start');
14
14
  const membersApp = express('members');
15
15
 
16
- // send 503 json response in case of maintenance
17
- membersApp.use(shared.middleware.maintenance);
18
-
19
16
  // Members API shouldn't be cached
20
17
  membersApp.use(shared.middleware.cacheControl('private'));
21
18
 
@@ -2,7 +2,6 @@ const debug = require('@tryghost/debug')('web:oauth:app');
2
2
  const {URL} = require('url');
3
3
  const express = require('../../../shared/express');
4
4
  const urlUtils = require('../../../shared/url-utils');
5
- const shared = require('../shared');
6
5
  const settingsCache = require('../../../shared/settings-cache');
7
6
  const models = require('../../models');
8
7
  const auth = require('../../services/auth');
@@ -24,9 +23,6 @@ module.exports = function setupOAuthApp() {
24
23
  }
25
24
  oauthApp.use(labsMiddleware);
26
25
 
27
- // send 503 json response in case of maintenance
28
- oauthApp.use(shared.middleware.maintenance);
29
-
30
26
  /**
31
27
  * Configure the passport.authenticate middleware
32
28
  * We need to configure it on each request because clientId and secret
@@ -3,16 +3,15 @@ const config = require('../../../shared/config');
3
3
  const express = require('../../../shared/express');
4
4
  const compress = require('compression');
5
5
  const mw = require('./middleware');
6
- const vhost = require('@tryghost/vhost-middleware');
7
6
 
8
- module.exports = function setupParentApp(options = {}) {
7
+ module.exports = function setupParentApp() {
9
8
  debug('ParentApp setup start');
10
9
  const parentApp = express('parent');
11
10
 
12
11
  parentApp.use(mw.requestId);
13
12
  parentApp.use(mw.logRequest);
14
13
 
15
- // Register event emmiter on req/res to trigger cache invalidation webhook event
14
+ // Register event emitter on req/res to trigger cache invalidation webhook event
16
15
  parentApp.use(mw.emitEvents);
17
16
 
18
17
  // enabled gzip compression by default
@@ -24,16 +23,6 @@ module.exports = function setupParentApp(options = {}) {
24
23
  // @TODO: figure out if this is really needed everywhere? Is it not frontend only...
25
24
  parentApp.use(mw.ghostLocals);
26
25
 
27
- // Mount the express apps on the parentApp
28
-
29
- // ADMIN + API
30
- const backendApp = require('./backend')();
31
- parentApp.use(vhost(config.getBackendMountPath(), backendApp));
32
-
33
- // SITE + MEMBERS
34
- const frontendApp = require('./frontend')(options);
35
- parentApp.use(vhost(config.getFrontendMountPath(), frontendApp));
36
-
37
26
  debug('ParentApp setup end');
38
27
 
39
28
  return parentApp;
@@ -10,9 +10,11 @@ module.exports = () => {
10
10
  // BACKEND
11
11
  // Wrap the admin and API apps into a single express app for use with vhost
12
12
  const backendApp = express('backend');
13
+
13
14
  backendApp.lazyUse('/ghost/api', require('../api'));
14
15
  backendApp.lazyUse('/ghost/oauth', require('../oauth'));
15
16
  backendApp.lazyUse('/ghost/.well-known', require('../well-known'));
17
+
16
18
  backendApp.use('/ghost', require('../../services/auth/session').createSessionFromToken, require('../admin')());
17
19
 
18
20
  return backendApp;