ghost 4.22.3 → 4.25.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.
- package/.c8rc.json +24 -0
- package/.eslintrc.js +39 -0
- package/Gruntfile.js +0 -1
- package/content/public/README.md +3 -0
- package/content/themes/casper/assets/built/casper.js +1 -1
- package/content/themes/casper/assets/built/casper.js.map +1 -1
- package/content/themes/casper/assets/built/global.css +1 -1
- package/content/themes/casper/assets/built/global.css.map +1 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/global.css +6 -1
- package/content/themes/casper/assets/css/screen.css +32 -216
- package/content/themes/casper/default.hbs +2 -2
- package/content/themes/casper/package.json +3 -2
- package/content/themes/casper/post.hbs +1 -1
- package/content/themes/casper/yarn.lock +173 -123
- package/core/app.js +12 -1
- package/core/boot.js +47 -28
- package/core/bridge.js +10 -10
- package/core/built/assets/{chunk.3.324fd0cc598c73650219.js → chunk.3.8f95b516d88ff4eec64c.js} +18 -18
- package/core/built/assets/ghost-dark-d690e732e17ffc794e2e59c1467ca282.css +1 -0
- package/core/built/assets/ghost.min-043bb7480a0810109b130f13b2a4235e.css +1 -0
- package/core/built/assets/{ghost.min-7da921f6c6cac3fe10da1ba104575440.js → ghost.min-bc72f685c1c9adc9885925c1412435a5.js} +563 -605
- package/core/built/assets/icons/audio-upload.svg +8 -0
- package/core/built/assets/icons/powered-by-tenor.svg +35 -0
- package/core/built/assets/icons/tenor.svg +7 -0
- package/core/built/assets/{vendor.min-413f887176a041e6dbf88214ca9a7481.js → vendor.min-d1234c632a54502777c34e50752fa3fc.js} +4622 -3631
- package/core/frontend/apps/amp/lib/helpers/amp_content.js +2 -2
- package/core/frontend/apps/amp/lib/views/amp.hbs +112 -0
- package/core/frontend/apps/private-blogging/index.js +1 -1
- package/core/frontend/apps/private-blogging/lib/router.js +1 -1
- package/core/frontend/services/apps/index.js +1 -1
- package/core/frontend/services/apps/loader.js +3 -3
- package/core/frontend/services/card-assets/index.js +0 -12
- package/core/frontend/services/card-assets/service.js +29 -28
- package/core/frontend/services/helpers/handlebars.js +1 -1
- package/core/frontend/services/routing/CollectionRouter.js +4 -5
- package/core/frontend/services/routing/EmailRouter.js +1 -1
- package/core/frontend/services/routing/ParentRouter.js +0 -8
- package/core/frontend/services/routing/PreviewRouter.js +1 -1
- package/core/frontend/services/routing/StaticPagesRouter.js +1 -1
- package/core/frontend/services/routing/StaticRoutesRouter.js +4 -4
- package/core/frontend/services/routing/TaxonomyRouter.js +3 -3
- package/core/frontend/services/routing/{middlewares → middleware}/index.js +0 -0
- package/core/frontend/services/routing/{middlewares → middleware}/page-param.js +0 -0
- package/core/frontend/services/routing/router-manager.js +7 -2
- package/core/frontend/services/rss/generate-feed.js +2 -1
- package/core/frontend/services/theme-engine/middleware/ensure-active-theme.js +34 -0
- package/core/frontend/services/theme-engine/middleware/index.js +6 -0
- package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +116 -0
- package/core/frontend/services/theme-engine/middleware/update-local-template-data.js +9 -0
- package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +57 -0
- package/core/frontend/src/cards/css/bookmark.css +72 -47
- package/core/frontend/src/cards/css/button.css +4 -0
- package/core/frontend/src/cards/css/callout.css +40 -3
- package/core/frontend/src/cards/css/gallery.css +15 -10
- package/core/frontend/src/cards/css/nft.css +20 -11
- package/core/frontend/src/cards/css/toggle.css +58 -0
- package/core/frontend/src/cards/js/toggle.js +16 -0
- package/core/frontend/web/middleware/error-handler.js +93 -0
- package/core/frontend/web/middleware/handle-image-sizes.js +3 -6
- package/core/frontend/web/middleware/index.js +1 -0
- package/core/frontend/web/middleware/serve-public-file.js +39 -16
- package/core/frontend/web/site.js +11 -14
- package/core/server/adapters/scheduling/SchedulingDefault.js +2 -2
- package/core/server/adapters/storage/LocalStorageBase.js +2 -2
- package/core/server/api/canary/authentication.js +1 -1
- package/core/server/api/canary/db.js +2 -2
- package/core/server/api/canary/media.js +3 -2
- package/core/server/api/canary/oembed.js +16 -1
- package/core/server/api/canary/session.js +1 -1
- package/core/server/api/canary/slugs.js +1 -1
- package/core/server/api/canary/utils/permissions.js +2 -2
- package/core/server/api/canary/utils/serializers/output/config.js +2 -6
- package/core/server/api/v2/authentication.js +1 -1
- package/core/server/api/v2/db.js +2 -2
- package/core/server/api/v2/session.js +1 -1
- package/core/server/api/v2/slugs.js +1 -1
- package/core/server/api/v2/utils/permissions.js +2 -2
- package/core/server/api/v3/authentication.js +1 -1
- package/core/server/api/v3/db.js +2 -2
- package/core/server/api/v3/session.js +1 -1
- package/core/server/api/v3/slugs.js +1 -1
- package/core/server/api/v3/utils/permissions.js +2 -2
- package/core/server/data/db/connection.js +7 -0
- package/core/server/data/db/state-manager.js +4 -4
- package/core/server/data/exporter/export-filename.js +1 -1
- package/core/server/data/importer/handlers/json.js +1 -1
- package/core/server/data/importer/import-manager.js +1 -1
- package/core/server/data/importer/importers/data/base.js +1 -1
- package/core/server/data/importer/importers/data/data-importer.js +3 -3
- package/core/server/data/migrations/init/2-create-fixtures.js +3 -20
- package/core/server/data/migrations/utils.js +2 -2
- package/core/server/data/migrations/versions/1.21/1-add-contributor-role.js +5 -5
- package/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js +1 -0
- package/core/server/data/migrations/versions/2.15/2-insert-zapier-integration.js +3 -3
- package/core/server/data/migrations/versions/2.2/3-insert-admin-integration-role.js +5 -5
- package/core/server/data/migrations/versions/2.27/1-insert-ghost-db-backup-role.js +5 -6
- package/core/server/data/migrations/versions/2.27/2-insert-db-backup-integration.js +3 -4
- package/core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js +7 -7
- package/core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js +3 -3
- package/core/server/data/migrations/versions/3.1/08-add-uuid-values-to-members.js +1 -0
- package/core/server/data/migrations/versions/3.22/02-settings-key-renames.js +2 -0
- package/core/server/data/migrations/versions/3.22/05-migrate-members-subscription-settings.js +3 -0
- package/core/server/data/migrations/versions/3.22/06-migrate-stripe-connect-settings.js +2 -0
- package/core/server/data/migrations/versions/3.23/01-migrate-bulk-email-settings.js +1 -0
- package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -0
- package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -0
- package/core/server/data/migrations/versions/3.38/04-populate-recipient-filter-column.js +2 -0
- package/core/server/data/migrations/versions/4.0/01-update-mobiledoc.js +2 -0
- package/core/server/data/migrations/versions/4.0/03-populate-status-column-for-members.js +4 -0
- package/core/server/data/migrations/versions/4.0/06-populate-members-subscribe-events-table.js +1 -0
- package/core/server/data/migrations/versions/4.0/17-populate-members-status-events-table.js +1 -0
- package/core/server/data/migrations/versions/4.0/18-transform-urls-absolute-to-transform-ready.js +5 -0
- package/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js +1 -0
- package/core/server/data/migrations/versions/4.0/23-regenerate-posts-html.js +1 -0
- package/core/server/data/migrations/versions/4.0/25-populate-members-paid-subscription-events-table.js +2 -1
- package/core/server/data/migrations/versions/4.12/02-fix-member-statuses.js +1 -0
- package/core/server/data/migrations/versions/4.14/01-fix-comped-member-statuses.js +3 -0
- package/core/server/data/migrations/versions/4.14/02-fix-free-members-status-events.js +1 -0
- package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +2 -0
- package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +59 -0
- package/core/server/data/migrations/versions/4.3/04-attach-members-to-product.js +1 -0
- package/core/server/data/migrations/versions/4.4/01-restore-free-members-signup-setting-from-backup.js +1 -0
- package/core/server/data/migrations/versions/4.6/01-remove-comped-status.js +1 -0
- package/core/server/data/migrations/versions/4.8/04-migrate-show-newsletter-header-setting.js +1 -0
- package/core/server/data/migrations/versions/4.9/05-fix-missed-mobiledoc-url-transforms.js +1 -0
- package/core/server/data/migrations/versions/4.9/06-add-comped-status.js +1 -0
- package/core/server/data/migrations/versions/4.9/07-update-comped-members-status-events.js +1 -0
- package/core/server/data/schema/commands.js +2 -2
- package/core/server/data/schema/fixtures/fixture-manager.js +340 -0
- package/core/server/data/schema/fixtures/index.js +8 -2
- package/core/server/ghost-server.js +2 -2
- package/core/server/lib/image/image-size.js +2 -2
- package/core/server/models/base/listeners.js +2 -2
- package/core/server/models/member-email-change-event.js +2 -2
- package/core/server/models/member-login-event.js +2 -2
- package/core/server/models/member-paid-subscription-event.js +3 -3
- package/core/server/models/member-payment-event.js +3 -3
- package/core/server/models/member-product-event.js +6 -6
- package/core/server/models/member-status-event.js +5 -3
- package/core/server/models/member-subscribe-event.js +9 -3
- package/core/server/models/relations/authors.js +1 -1
- package/core/server/models/settings.js +1 -1
- package/core/server/services/auth/passwordreset.js +1 -1
- package/core/server/services/auth/setup.js +1 -1
- package/core/server/services/email-analytics/jobs/index.js +1 -1
- package/core/server/services/mega/mega.js +6 -4
- package/core/server/services/mega/post-email-serializer.js +5 -1
- package/core/server/services/mega/segment-parser.js +1 -2
- package/core/server/services/mega/template.js +52 -37
- package/core/server/services/members/api.js +22 -0
- package/core/server/services/members/config.js +1 -1
- package/core/server/services/members/emails/signup-paid.js +168 -0
- package/core/server/services/members/service.js +6 -2
- package/core/server/services/members/stripe-connect.js +4 -2
- package/core/server/services/nft-oembed.js +13 -22
- package/core/server/services/oembed.js +28 -24
- package/core/server/services/permissions/can-this.js +1 -1
- package/core/server/services/public-config/config.js +1 -1
- package/core/server/services/redirects/api.js +20 -25
- package/core/server/services/redirects/index.js +18 -10
- package/core/server/services/redirects/utils.js +14 -0
- package/core/server/services/redirects/validation.js +10 -0
- package/core/server/services/route-settings/default-settings-manager.js +1 -1
- package/core/server/services/route-settings/index.js +40 -17
- package/core/server/services/route-settings/route-settings.js +120 -115
- package/core/server/services/route-settings/settings-loader.js +18 -36
- package/core/server/services/route-settings/yaml-parser.js +1 -1
- package/core/server/services/slack.js +1 -1
- package/core/server/services/themes/activation-bridge.js +3 -3
- package/core/server/services/themes/storage.js +2 -2
- package/core/server/services/twitter-embed.js +80 -0
- package/core/server/services/url/LocalFileCache.js +75 -0
- package/core/server/services/url/Resources.js +8 -2
- package/core/server/services/url/UrlGenerator.js +23 -20
- package/core/server/services/url/UrlService.js +75 -63
- package/core/server/services/url/index.js +17 -3
- package/core/server/services/xmlrpc.js +2 -2
- package/core/server/web/admin/app.js +7 -10
- package/core/server/web/admin/controller.js +35 -12
- package/core/server/web/admin/middleware/redirect-admin-urls.js +15 -0
- package/core/server/web/admin/views/default-prod.html +4 -4
- package/core/server/web/admin/views/default.html +4 -4
- package/core/server/web/api/app.js +1 -1
- package/core/server/web/api/canary/admin/app.js +3 -6
- package/core/server/web/api/canary/admin/middleware.js +7 -7
- package/core/server/web/api/canary/admin/routes.js +5 -5
- package/core/server/web/api/canary/content/app.js +3 -6
- package/core/server/web/api/canary/content/middleware.js +3 -3
- package/core/server/web/api/v2/admin/app.js +3 -6
- package/core/server/web/api/v2/admin/middleware.js +7 -7
- package/core/server/web/api/v2/admin/routes.js +5 -5
- package/core/server/web/api/v2/content/app.js +3 -6
- package/core/server/web/api/v2/content/middleware.js +3 -3
- package/core/server/web/api/v3/admin/app.js +3 -6
- package/core/server/web/api/v3/admin/middleware.js +7 -7
- package/core/server/web/api/v3/admin/routes.js +5 -5
- package/core/server/web/api/v3/content/app.js +3 -6
- package/core/server/web/api/v3/content/middleware.js +3 -3
- package/core/server/web/members/app.js +6 -9
- package/core/server/web/oauth/app.js +0 -4
- package/core/server/web/parent/app.js +17 -9
- package/core/server/web/parent/frontend.js +1 -1
- package/core/server/web/shared/index.js +2 -2
- package/core/server/web/shared/{middlewares → middleware}/api/index.js +0 -0
- package/core/server/web/shared/{middlewares → middleware}/api/spam-prevention.js +0 -0
- package/core/server/web/shared/{middlewares → middleware}/brute.js +0 -0
- package/core/server/web/shared/{middlewares → middleware}/cache-control.js +0 -0
- package/core/server/web/shared/middleware/error-handler.js +224 -0
- package/core/server/web/shared/{middlewares → middleware}/index.js +0 -4
- package/core/server/web/shared/{middlewares → middleware}/pretty-urls.js +0 -0
- package/core/server/web/shared/{middlewares → middleware}/uncapitalise.js +0 -0
- package/core/server/web/shared/{middlewares → middleware}/url-redirects.js +0 -0
- package/core/shared/config/defaults.json +13 -1
- package/core/shared/config/helpers.js +42 -0
- package/core/shared/config/loader.js +1 -1
- package/core/shared/labs.js +9 -5
- package/core/shared/sentry.js +1 -1
- package/loggingrc.js +19 -20
- package/package.json +38 -37
- package/yarn.lock +1064 -892
- package/content/themes/casper/assets/js/gallery-card.js +0 -24
- package/core/built/assets/ghost-dark-39fb496d051565531062d7e047d1c0b1.css +0 -1
- package/core/built/assets/ghost.min-4207edfc1ae0a3f9f6505ca00d20b0c0.css +0 -1
- package/core/frontend/services/theme-engine/middleware.js +0 -209
- package/core/server/data/schema/fixtures/utils.js +0 -321
- package/core/server/web/parent/vhost-utils.js +0 -39
- package/core/server/web/shared/middlewares/error-handler.js +0 -329
- package/core/server/web/shared/middlewares/maintenance.js +0 -25
|
@@ -11,20 +11,41 @@ const messages = {
|
|
|
11
11
|
fileNotFound: 'File not found'
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
/**
|
|
15
|
+
* If this request has a ?v= param, make sure the cache has the same key
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} req
|
|
18
|
+
* @param {Object} cache
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function matchCacheKey(req, cache) {
|
|
22
|
+
if (req.query && req.query.v && cache && cache.key) {
|
|
23
|
+
return req.query.v === cache.key;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createPublicFileMiddleware(location, file, mime, maxAge) {
|
|
30
|
+
let cache;
|
|
31
|
+
// These files are provided by Ghost, and therefore live inside of the core folder
|
|
32
|
+
const staticFilePath = config.get('paths').publicFilePath;
|
|
33
|
+
// These files are built on the fly, and must be saved in the content folder
|
|
34
|
+
const builtFilePath = config.getContentPath('public');
|
|
35
|
+
|
|
36
|
+
let locationPath = location === 'static' ? staticFilePath : builtFilePath;
|
|
37
|
+
|
|
38
|
+
const filePath = file.match(/^public/) ? path.join(locationPath, file.replace(/^public/, '')) : path.join(locationPath, file);
|
|
18
39
|
const blogRegex = /(\{\{blog-url\}\})/g;
|
|
19
40
|
|
|
20
41
|
return function servePublicFileMiddleware(req, res, next) {
|
|
21
|
-
if (
|
|
22
|
-
res.writeHead(200,
|
|
23
|
-
return res.end(
|
|
42
|
+
if (cache && matchCacheKey(req, cache)) {
|
|
43
|
+
res.writeHead(200, cache.headers);
|
|
44
|
+
return res.end(cache.body);
|
|
24
45
|
}
|
|
25
46
|
|
|
26
47
|
// send image files directly and let express handle content-length, etag, etc
|
|
27
|
-
if (
|
|
48
|
+
if (mime.match(/^image/)) {
|
|
28
49
|
return res.sendFile(filePath, (err) => {
|
|
29
50
|
if (err && err.status === 404) {
|
|
30
51
|
// ensure we're triggering basic asset 404 and not a templated 404
|
|
@@ -57,29 +78,31 @@ function createPublicFileMiddleware(file, type, maxAge) {
|
|
|
57
78
|
|
|
58
79
|
let str = buf.toString();
|
|
59
80
|
|
|
60
|
-
if (
|
|
81
|
+
if (mime === 'text/xsl' || mime === 'text/plain' || mime === 'application/javascript') {
|
|
61
82
|
str = str.replace(blogRegex, urlUtils.urlFor('home', true).replace(/\/$/, ''));
|
|
62
83
|
}
|
|
63
84
|
|
|
64
|
-
|
|
85
|
+
cache = {
|
|
65
86
|
headers: {
|
|
66
|
-
'Content-Type':
|
|
87
|
+
'Content-Type': mime,
|
|
67
88
|
'Content-Length': Buffer.from(str).length,
|
|
68
89
|
ETag: `"${crypto.createHash('md5').update(str, 'utf8').digest('hex')}"`,
|
|
69
90
|
'Cache-Control': `public, max-age=${maxAge}`
|
|
70
91
|
},
|
|
71
|
-
body: str
|
|
92
|
+
body: str,
|
|
93
|
+
key: req.query && req.query.v ? req.query.v : null
|
|
72
94
|
};
|
|
73
|
-
|
|
74
|
-
res.
|
|
95
|
+
|
|
96
|
+
res.writeHead(200, cache.headers);
|
|
97
|
+
res.end(cache.body);
|
|
75
98
|
});
|
|
76
99
|
};
|
|
77
100
|
}
|
|
78
101
|
|
|
79
102
|
// ### servePublicFile Middleware
|
|
80
103
|
// Handles requests to robots.txt and favicon.ico (and caches them)
|
|
81
|
-
function servePublicFile(file, type, maxAge) {
|
|
82
|
-
const publicFileMiddleware = createPublicFileMiddleware(file, type, maxAge);
|
|
104
|
+
function servePublicFile(location, file, type, maxAge) {
|
|
105
|
+
const publicFileMiddleware = createPublicFileMiddleware(location, file, type, maxAge);
|
|
83
106
|
|
|
84
107
|
return function servePublicFileMiddleware(req, res, next) {
|
|
85
108
|
if (req.path === '/' + file) {
|
|
@@ -104,15 +104,15 @@ module.exports = function setupSiteApp(options = {}) {
|
|
|
104
104
|
siteApp.use(mw.serveFavicon());
|
|
105
105
|
|
|
106
106
|
// Serve sitemap.xsl file
|
|
107
|
-
siteApp.use(mw.servePublicFile('sitemap.xsl', 'text/xsl', constants.ONE_DAY_S));
|
|
107
|
+
siteApp.use(mw.servePublicFile('static', 'sitemap.xsl', 'text/xsl', constants.ONE_DAY_S));
|
|
108
108
|
|
|
109
109
|
// Serve stylesheets for default templates
|
|
110
|
-
siteApp.use(mw.servePublicFile('public/ghost.css', 'text/css', constants.ONE_HOUR_S));
|
|
111
|
-
siteApp.use(mw.servePublicFile('public/ghost.min.css', 'text/css', constants.ONE_YEAR_S));
|
|
110
|
+
siteApp.use(mw.servePublicFile('static', 'public/ghost.css', 'text/css', constants.ONE_HOUR_S));
|
|
111
|
+
siteApp.use(mw.servePublicFile('static', 'public/ghost.min.css', 'text/css', constants.ONE_YEAR_S));
|
|
112
112
|
|
|
113
113
|
// Card assets
|
|
114
|
-
siteApp.use(mw.servePublicFile('public/cards.min.css', 'text/css', constants.ONE_YEAR_S));
|
|
115
|
-
siteApp.use(mw.servePublicFile('public/cards.min.js', 'text/js', constants.ONE_YEAR_S));
|
|
114
|
+
siteApp.use(mw.servePublicFile('built', 'public/cards.min.css', 'text/css', constants.ONE_YEAR_S));
|
|
115
|
+
siteApp.use(mw.servePublicFile('built', 'public/cards.min.js', 'text/js', constants.ONE_YEAR_S));
|
|
116
116
|
|
|
117
117
|
// Serve blog images using the storage adapter
|
|
118
118
|
siteApp.use(STATIC_IMAGE_URL_PREFIX, mw.handleImageSizes, storage.getStorage('images').serve());
|
|
@@ -147,26 +147,23 @@ module.exports = function setupSiteApp(options = {}) {
|
|
|
147
147
|
debug('Themes done');
|
|
148
148
|
|
|
149
149
|
// Serve robots.txt if not found in theme
|
|
150
|
-
siteApp.use(mw.servePublicFile('robots.txt', 'text/plain', constants.ONE_HOUR_S));
|
|
150
|
+
siteApp.use(mw.servePublicFile('static', 'robots.txt', 'text/plain', constants.ONE_HOUR_S));
|
|
151
151
|
|
|
152
152
|
// site map - this should probably be refactored to be an internal app
|
|
153
153
|
sitemapHandler(siteApp);
|
|
154
154
|
debug('Internal apps done');
|
|
155
155
|
|
|
156
|
-
// send 503 error page in case of maintenance
|
|
157
|
-
siteApp.use(shared.middlewares.maintenance);
|
|
158
|
-
|
|
159
156
|
// Add in all trailing slashes & remove uppercase
|
|
160
157
|
// must happen AFTER asset loading and BEFORE routing
|
|
161
|
-
siteApp.use(shared.
|
|
158
|
+
siteApp.use(shared.middleware.prettyUrls);
|
|
162
159
|
|
|
163
160
|
// ### Caching
|
|
164
161
|
siteApp.use(function (req, res, next) {
|
|
165
162
|
// Site frontend is cacheable UNLESS request made by a member or blog is in private mode
|
|
166
163
|
if (req.member || res.isPrivateBlog) {
|
|
167
|
-
return shared.
|
|
164
|
+
return shared.middleware.cacheControl('private')(req, res, next);
|
|
168
165
|
} else {
|
|
169
|
-
return shared.
|
|
166
|
+
return shared.middleware.cacheControl('public', {maxAge: config.get('caching:frontend:maxAge')})(req, res, next);
|
|
170
167
|
}
|
|
171
168
|
});
|
|
172
169
|
|
|
@@ -179,7 +176,7 @@ module.exports = function setupSiteApp(options = {}) {
|
|
|
179
176
|
siteApp.use(SiteRouter);
|
|
180
177
|
|
|
181
178
|
// ### Error handlers
|
|
182
|
-
siteApp.use(shared.
|
|
179
|
+
siteApp.use(shared.middleware.errorHandler.pageNotFound);
|
|
183
180
|
config.get('apps:internal').forEach((appName) => {
|
|
184
181
|
const app = require(path.join(config.get('paths').internalAppPath, appName));
|
|
185
182
|
|
|
@@ -187,7 +184,7 @@ module.exports = function setupSiteApp(options = {}) {
|
|
|
187
184
|
app.setupErrorHandling(siteApp);
|
|
188
185
|
}
|
|
189
186
|
});
|
|
190
|
-
siteApp.use(
|
|
187
|
+
siteApp.use(mw.errorHandler.handleThemeResponse);
|
|
191
188
|
|
|
192
189
|
debug('Site setup end');
|
|
193
190
|
|
|
@@ -307,7 +307,7 @@ SchedulingDefault.prototype._pingUrl = function (object) {
|
|
|
307
307
|
this._pingUrl(object);
|
|
308
308
|
}, this.retryTimeoutInMs);
|
|
309
309
|
|
|
310
|
-
logging.error(new errors.
|
|
310
|
+
logging.error(new errors.InternalServerError({
|
|
311
311
|
err,
|
|
312
312
|
context: 'Retrying...',
|
|
313
313
|
level: 'normal'
|
|
@@ -316,7 +316,7 @@ SchedulingDefault.prototype._pingUrl = function (object) {
|
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
logging.error(new errors.
|
|
319
|
+
logging.error(new errors.InternalServerError({
|
|
320
320
|
err,
|
|
321
321
|
level: 'critical'
|
|
322
322
|
}));
|
|
@@ -147,7 +147,7 @@ class LocalStorageBase extends StorageBase {
|
|
|
147
147
|
return next(new errors.NoPermissionError({err: err}));
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
return next(new errors.
|
|
150
|
+
return next(new errors.InternalServerError({err: err}));
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
next();
|
|
@@ -196,7 +196,7 @@ class LocalStorageBase extends StorageBase {
|
|
|
196
196
|
return reject(new errors.NoPermissionError({err: err}));
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
return reject(new errors.
|
|
199
|
+
return reject(new errors.InternalServerError({
|
|
200
200
|
err: err,
|
|
201
201
|
message: tpl(this.errorMessages.cannotRead, {file: options.path})
|
|
202
202
|
}));
|
|
@@ -163,7 +163,7 @@ module.exports = {
|
|
|
163
163
|
options = Object.assign(options, {context: {internal: true}});
|
|
164
164
|
return auth.passwordreset.doReset(options, tokenParts, api.settings)
|
|
165
165
|
.then((params) => {
|
|
166
|
-
web.shared.
|
|
166
|
+
web.shared.middleware.api.spamPrevention.userLogin().reset(frame.options.ip, `${tokenParts.email}login`);
|
|
167
167
|
return params;
|
|
168
168
|
});
|
|
169
169
|
});
|
|
@@ -62,7 +62,7 @@ module.exports = {
|
|
|
62
62
|
return Promise.resolve()
|
|
63
63
|
.then(() => exporter.doExport({include: frame.options.withRelated}))
|
|
64
64
|
.catch((err) => {
|
|
65
|
-
return Promise.reject(new errors.
|
|
65
|
+
return Promise.reject(new errors.InternalServerError({err: err}));
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
},
|
|
@@ -124,7 +124,7 @@ module.exports = {
|
|
|
124
124
|
}, {concurrency: 100});
|
|
125
125
|
})
|
|
126
126
|
.catch((err) => {
|
|
127
|
-
throw new errors.
|
|
127
|
+
throw new errors.InternalServerError({
|
|
128
128
|
err: err
|
|
129
129
|
});
|
|
130
130
|
});
|
|
@@ -3,9 +3,24 @@ const externalRequest = require('../../lib/request-external');
|
|
|
3
3
|
|
|
4
4
|
const OEmbed = require('../../services/oembed');
|
|
5
5
|
const oembed = new OEmbed({config, externalRequest});
|
|
6
|
+
|
|
6
7
|
const NFT = require('../../services/nft-oembed');
|
|
7
|
-
const nft = new NFT(
|
|
8
|
+
const nft = new NFT({
|
|
9
|
+
config: {
|
|
10
|
+
apiKey: config.get('opensea').privateReadOnlyApiKey
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const Twitter = require('../../services/twitter-embed');
|
|
15
|
+
const twitter = new Twitter({
|
|
16
|
+
config: {
|
|
17
|
+
bearerToken: config.get('twitter').privateReadOnlyToken
|
|
18
|
+
},
|
|
19
|
+
logging: require('@tryghost/logging')
|
|
20
|
+
});
|
|
21
|
+
|
|
8
22
|
oembed.registerProvider(nft);
|
|
23
|
+
oembed.registerProvider(twitter);
|
|
9
24
|
|
|
10
25
|
module.exports = {
|
|
11
26
|
docName: 'oembed',
|
|
@@ -43,7 +43,7 @@ module.exports = {
|
|
|
43
43
|
return models.Base.Model.generateSlug(allowedTypes[frame.options.type], frame.data.name, {status: 'all'})
|
|
44
44
|
.then((slug) => {
|
|
45
45
|
if (!slug) {
|
|
46
|
-
return Promise.reject(new errors.
|
|
46
|
+
return Promise.reject(new errors.InternalServerError({
|
|
47
47
|
message: tpl(messages.couldNotGenerateSlug)
|
|
48
48
|
}));
|
|
49
49
|
}
|
|
@@ -66,11 +66,11 @@ const nonePublicAuth = (apiConfig, frame) => {
|
|
|
66
66
|
return Promise.reject(err);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (errors.utils.
|
|
69
|
+
if (errors.utils.isGhostError(err)) {
|
|
70
70
|
return Promise.reject(err);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
return Promise.reject(new errors.
|
|
73
|
+
return Promise.reject(new errors.InternalServerError({
|
|
74
74
|
err: err
|
|
75
75
|
}));
|
|
76
76
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const _ = require('lodash');
|
|
2
|
-
const labs = require('../../../../../../shared/labs');
|
|
3
2
|
const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:config');
|
|
4
3
|
|
|
5
4
|
module.exports = {
|
|
@@ -18,13 +17,10 @@ module.exports = {
|
|
|
18
17
|
'stripeDirect',
|
|
19
18
|
'mailgunIsConfigured',
|
|
20
19
|
'emailAnalytics',
|
|
21
|
-
'hostSettings'
|
|
20
|
+
'hostSettings',
|
|
21
|
+
'tenor'
|
|
22
22
|
];
|
|
23
23
|
|
|
24
|
-
if (labs.isSet('gifsCard')) {
|
|
25
|
-
keys.push('tenorApiKey');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
24
|
frame.response = {
|
|
29
25
|
config: _.pick(data, keys)
|
|
30
26
|
};
|
|
@@ -145,7 +145,7 @@ module.exports = {
|
|
|
145
145
|
options = Object.assign(options, {context: {internal: true}});
|
|
146
146
|
return auth.passwordreset.doReset(options, tokenParts, api.settings)
|
|
147
147
|
.then((params) => {
|
|
148
|
-
web.shared.
|
|
148
|
+
web.shared.middleware.api.spamPrevention.userLogin().reset(frame.options.ip, `${tokenParts.email}login`);
|
|
149
149
|
return params;
|
|
150
150
|
});
|
|
151
151
|
});
|
package/core/server/api/v2/db.js
CHANGED
|
@@ -51,7 +51,7 @@ module.exports = {
|
|
|
51
51
|
return Promise.resolve()
|
|
52
52
|
.then(() => exporter.doExport({include: frame.options.withRelated}))
|
|
53
53
|
.catch((err) => {
|
|
54
|
-
return Promise.reject(new errors.
|
|
54
|
+
return Promise.reject(new errors.InternalServerError({err: err}));
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
},
|
|
@@ -107,7 +107,7 @@ module.exports = {
|
|
|
107
107
|
}, {concurrency: 100});
|
|
108
108
|
})
|
|
109
109
|
.catch((err) => {
|
|
110
|
-
throw new errors.
|
|
110
|
+
throw new errors.InternalServerError({
|
|
111
111
|
err: err
|
|
112
112
|
});
|
|
113
113
|
});
|
|
@@ -40,7 +40,7 @@ module.exports = {
|
|
|
40
40
|
return models.Base.Model.generateSlug(allowedTypes[frame.options.type], frame.data.name, {status: 'all'})
|
|
41
41
|
.then((slug) => {
|
|
42
42
|
if (!slug) {
|
|
43
|
-
return Promise.reject(new errors.
|
|
43
|
+
return Promise.reject(new errors.InternalServerError({
|
|
44
44
|
message: tpl(messages.couldNotGenerateSlug)
|
|
45
45
|
}));
|
|
46
46
|
}
|
|
@@ -62,11 +62,11 @@ const nonePublicAuth = (apiConfig, frame) => {
|
|
|
62
62
|
return Promise.reject(err);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
if (errors.utils.
|
|
65
|
+
if (errors.utils.isGhostError(err)) {
|
|
66
66
|
return Promise.reject(err);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
return Promise.reject(new errors.
|
|
69
|
+
return Promise.reject(new errors.InternalServerError({
|
|
70
70
|
err: err
|
|
71
71
|
}));
|
|
72
72
|
});
|
|
@@ -146,7 +146,7 @@ module.exports = {
|
|
|
146
146
|
options = Object.assign(options, {context: {internal: true}});
|
|
147
147
|
return auth.passwordreset.doReset(options, tokenParts, api.settings)
|
|
148
148
|
.then((params) => {
|
|
149
|
-
web.shared.
|
|
149
|
+
web.shared.middleware.api.spamPrevention.userLogin().reset(frame.options.ip, `${tokenParts.email}login`);
|
|
150
150
|
return params;
|
|
151
151
|
});
|
|
152
152
|
});
|
package/core/server/api/v3/db.js
CHANGED
|
@@ -62,7 +62,7 @@ module.exports = {
|
|
|
62
62
|
return Promise.resolve()
|
|
63
63
|
.then(() => exporter.doExport({include: frame.options.withRelated}))
|
|
64
64
|
.catch((err) => {
|
|
65
|
-
return Promise.reject(new errors.
|
|
65
|
+
return Promise.reject(new errors.InternalServerError({err: err}));
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
},
|
|
@@ -118,7 +118,7 @@ module.exports = {
|
|
|
118
118
|
}, {concurrency: 100});
|
|
119
119
|
})
|
|
120
120
|
.catch((err) => {
|
|
121
|
-
throw new errors.
|
|
121
|
+
throw new errors.InternalServerError({
|
|
122
122
|
err: err
|
|
123
123
|
});
|
|
124
124
|
});
|
|
@@ -39,7 +39,7 @@ module.exports = {
|
|
|
39
39
|
return models.Base.Model.generateSlug(allowedTypes[frame.options.type], frame.data.name, {status: 'all'})
|
|
40
40
|
.then((slug) => {
|
|
41
41
|
if (!slug) {
|
|
42
|
-
return Promise.reject(new errors.
|
|
42
|
+
return Promise.reject(new errors.InternalServerError({message: tpl(messages.couldNotGenerateSlug)}));
|
|
43
43
|
}
|
|
44
44
|
return slug;
|
|
45
45
|
});
|
|
@@ -66,11 +66,11 @@ const nonePublicAuth = (apiConfig, frame) => {
|
|
|
66
66
|
return Promise.reject(err);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (errors.utils.
|
|
69
|
+
if (errors.utils.isGhostError(err)) {
|
|
70
70
|
return Promise.reject(err);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
return Promise.reject(new errors.
|
|
73
|
+
return Promise.reject(new errors.InternalServerError({
|
|
74
74
|
err: err
|
|
75
75
|
}));
|
|
76
76
|
});
|
|
@@ -17,6 +17,13 @@ function configure(dbConfig) {
|
|
|
17
17
|
dbConfig.pool = {
|
|
18
18
|
afterCreate(conn, cb) {
|
|
19
19
|
conn.run('PRAGMA foreign_keys = ON', cb);
|
|
20
|
+
|
|
21
|
+
// These two are meant to improve performance at the cost of reliability
|
|
22
|
+
// Should be safe for tests. We add them here and leave them on
|
|
23
|
+
if (config.get('env').startsWith('testing')) {
|
|
24
|
+
conn.run('PRAGMA synchronous = OFF;');
|
|
25
|
+
conn.run('PRAGMA journal_mode = TRUNCATE;');
|
|
26
|
+
}
|
|
20
27
|
}
|
|
21
28
|
};
|
|
22
29
|
|
|
@@ -59,8 +59,8 @@ class DatabaseStateManager {
|
|
|
59
59
|
|
|
60
60
|
// CASE: database connection errors, unknown cases
|
|
61
61
|
let errorToThrow = error;
|
|
62
|
-
if (!errors.utils.
|
|
63
|
-
errorToThrow = new errors.
|
|
62
|
+
if (!errors.utils.isGhostError(errorToThrow)) {
|
|
63
|
+
errorToThrow = new errors.InternalServerError({message: errorToThrow.message, err: errorToThrow});
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
throw errorToThrow;
|
|
@@ -94,8 +94,8 @@ class DatabaseStateManager {
|
|
|
94
94
|
}
|
|
95
95
|
} catch (error) {
|
|
96
96
|
let errorToThrow = error;
|
|
97
|
-
if (!errors.utils.
|
|
98
|
-
errorToThrow = new errors.
|
|
97
|
+
if (!errors.utils.isGhostError(error)) {
|
|
98
|
+
errorToThrow = new errors.InternalServerError({message: errorToThrow.message, err: errorToThrow});
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
throw errorToThrow;
|
|
@@ -26,7 +26,7 @@ const exportFileName = async function exportFileName(options) {
|
|
|
26
26
|
|
|
27
27
|
return title + 'ghost.' + datetime + '.json';
|
|
28
28
|
} catch (err) {
|
|
29
|
-
logging.error(new errors.
|
|
29
|
+
logging.error(new errors.InternalServerError({err: err}));
|
|
30
30
|
return 'ghost.' + datetime + '.json';
|
|
31
31
|
}
|
|
32
32
|
};
|
|
@@ -30,7 +30,7 @@ JSONHandler = {
|
|
|
30
30
|
// if importData follows JSON-API format `{ db: [exportedData] }`
|
|
31
31
|
if (_.keys(importData).length === 1) {
|
|
32
32
|
if (!importData.db || !Array.isArray(importData.db)) {
|
|
33
|
-
throw new errors.
|
|
33
|
+
throw new errors.InternalServerError({
|
|
34
34
|
message: tpl(messages.invalidJsonFormat)
|
|
35
35
|
});
|
|
36
36
|
}
|
|
@@ -121,7 +121,7 @@ class ImportManager {
|
|
|
121
121
|
|
|
122
122
|
fs.remove(self.fileToDelete, function (err) {
|
|
123
123
|
if (err) {
|
|
124
|
-
logging.error(new errors.
|
|
124
|
+
logging.error(new errors.InternalServerError({
|
|
125
125
|
err: err,
|
|
126
126
|
context: tpl(messages.couldNotCleanUpFile.error),
|
|
127
127
|
help: tpl(messages.couldNotCleanUpFile.context)
|
|
@@ -112,7 +112,7 @@ DataImporter = {
|
|
|
112
112
|
});
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
sequence(ops)
|
|
115
|
+
return sequence(ops)
|
|
116
116
|
.then(function () {
|
|
117
117
|
results.forEach(function (promise) {
|
|
118
118
|
if (!promise.isFulfilled()) {
|
|
@@ -121,9 +121,9 @@ DataImporter = {
|
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
if (errors.length === 0) {
|
|
124
|
-
|
|
124
|
+
return;
|
|
125
125
|
} else {
|
|
126
|
-
|
|
126
|
+
throw errors;
|
|
127
127
|
}
|
|
128
128
|
});
|
|
129
129
|
}).then(function () {
|
|
@@ -1,26 +1,9 @@
|
|
|
1
|
-
const
|
|
2
|
-
const _ = require('lodash');
|
|
3
|
-
const fixtures = require('../../schema/fixtures');
|
|
4
|
-
const logging = require('@tryghost/logging');
|
|
1
|
+
const {fixtureManager} = require('../../schema/fixtures');
|
|
5
2
|
|
|
6
3
|
module.exports.config = {
|
|
7
4
|
transaction: true
|
|
8
5
|
};
|
|
9
6
|
|
|
10
|
-
module.exports.up = async (options)
|
|
11
|
-
|
|
12
|
-
context: {internal: true},
|
|
13
|
-
migrating: true
|
|
14
|
-
}, options);
|
|
15
|
-
|
|
16
|
-
await Promise.mapSeries(fixtures.models, async (model) => {
|
|
17
|
-
logging.info('Model: ' + model.name);
|
|
18
|
-
|
|
19
|
-
await fixtures.utils.addFixturesForModel(model, localOptions);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
await Promise.mapSeries(fixtures.relations, async (relation) => {
|
|
23
|
-
logging.info('Relation: ' + relation.from.model + ' to ' + relation.to.model);
|
|
24
|
-
await fixtures.utils.addFixturesForRelation(relation, localOptions);
|
|
25
|
-
});
|
|
7
|
+
module.exports.up = async function insertFixtures(options) {
|
|
8
|
+
return await fixtureManager.addAllFixtures(options);
|
|
26
9
|
};
|
|
@@ -143,7 +143,7 @@ function addPermissionToRole(config) {
|
|
|
143
143
|
}).first();
|
|
144
144
|
|
|
145
145
|
if (!permission) {
|
|
146
|
-
throw new errors.
|
|
146
|
+
throw new errors.InternalServerError({
|
|
147
147
|
message: tpl(messages.permissionRoleActionError, {
|
|
148
148
|
action: 'add',
|
|
149
149
|
permission: config.permission,
|
|
@@ -158,7 +158,7 @@ function addPermissionToRole(config) {
|
|
|
158
158
|
}).first();
|
|
159
159
|
|
|
160
160
|
if (!role) {
|
|
161
|
-
throw new errors.
|
|
161
|
+
throw new errors.InternalServerError({
|
|
162
162
|
message: tpl(messages.permissionRoleActionError, {
|
|
163
163
|
action: 'add',
|
|
164
164
|
permission: config.permission,
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
const merge = require('lodash/merge');
|
|
2
|
-
const
|
|
2
|
+
const {fixtureManager} = require('../../../schema/fixtures');
|
|
3
3
|
const models = require('../../../../models');
|
|
4
4
|
const permissions = require('../../../../services/permissions');
|
|
5
5
|
const logging = require('@tryghost/logging');
|
|
6
6
|
const _private = {};
|
|
7
7
|
|
|
8
8
|
_private.addRole = function addRole(options) {
|
|
9
|
-
const contributorRole =
|
|
9
|
+
const contributorRole = fixtureManager.findModelFixtureEntry('Role', {name: 'Contributor'});
|
|
10
10
|
const message = 'Adding "Contributor" role to roles table';
|
|
11
11
|
|
|
12
12
|
return models.Role.findOne({name: contributorRole.name}, options)
|
|
13
13
|
.then((role) => {
|
|
14
14
|
if (!role) {
|
|
15
15
|
logging.info(message);
|
|
16
|
-
return
|
|
16
|
+
return fixtureManager.addFixturesForModel({name: 'Role', entries: [contributorRole]}, options);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
logging.warn(message);
|
|
@@ -22,10 +22,10 @@ _private.addRole = function addRole(options) {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
_private.addContributorPermissions = function getPermissions(options) {
|
|
25
|
-
const relations =
|
|
25
|
+
const relations = fixtureManager.findRelationFixture('Role', 'Permission');
|
|
26
26
|
const message = 'Adding permissions_roles fixtures for the contributor role';
|
|
27
27
|
|
|
28
|
-
return
|
|
28
|
+
return fixtureManager.addFixturesForRelation({
|
|
29
29
|
from: relations.from,
|
|
30
30
|
to: relations.to,
|
|
31
31
|
entries: {
|