ghost 5.97.3 → 5.98.1
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/components/tryghost-adapter-cache-memory-ttl-5.98.1.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.98.1.tgz +0 -0
- package/components/tryghost-adapter-manager-5.98.1.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.98.1.tgz +0 -0
- package/components/{tryghost-api-framework-5.97.3.tgz → tryghost-api-framework-5.98.1.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.98.1.tgz +0 -0
- package/components/tryghost-audience-feedback-5.98.1.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.98.1.tgz +0 -0
- package/components/{tryghost-bootstrap-socket-5.97.3.tgz → tryghost-bootstrap-socket-5.98.1.tgz} +0 -0
- package/components/tryghost-collections-5.98.1.tgz +0 -0
- package/components/tryghost-constants-5.98.1.tgz +0 -0
- package/components/tryghost-custom-fonts-5.98.1.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.98.1.tgz +0 -0
- package/components/{tryghost-data-generator-5.97.3.tgz → tryghost-data-generator-5.98.1.tgz} +0 -0
- package/components/tryghost-domain-events-5.98.1.tgz +0 -0
- package/components/tryghost-donations-5.98.1.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.98.1.tgz +0 -0
- package/components/tryghost-email-addresses-5.98.1.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.98.1.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.98.1.tgz +0 -0
- package/components/{tryghost-email-content-generator-5.97.3.tgz → tryghost-email-content-generator-5.98.1.tgz} +0 -0
- package/components/tryghost-email-events-5.98.1.tgz +0 -0
- package/components/{tryghost-email-service-5.97.3.tgz → tryghost-email-service-5.98.1.tgz} +0 -0
- package/components/tryghost-email-suppression-list-5.98.1.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.98.1.tgz +0 -0
- package/components/tryghost-external-media-inliner-5.98.1.tgz +0 -0
- package/components/tryghost-extract-api-key-5.98.1.tgz +0 -0
- package/components/tryghost-ghost-5.98.1.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.98.1.tgz +0 -0
- package/components/tryghost-i18n-5.98.1.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.98.1.tgz +0 -0
- package/components/{tryghost-importer-revue-5.97.3.tgz → tryghost-importer-revue-5.98.1.tgz} +0 -0
- package/components/tryghost-in-memory-repository-5.98.1.tgz +0 -0
- package/components/{tryghost-job-manager-5.97.3.tgz → tryghost-job-manager-5.98.1.tgz} +0 -0
- package/components/tryghost-link-redirects-5.98.1.tgz +0 -0
- package/components/tryghost-link-replacer-5.98.1.tgz +0 -0
- package/components/{tryghost-link-tracking-5.97.3.tgz → tryghost-link-tracking-5.98.1.tgz} +0 -0
- package/components/tryghost-magic-link-5.98.1.tgz +0 -0
- package/components/{tryghost-mail-events-5.97.3.tgz → tryghost-mail-events-5.98.1.tgz} +0 -0
- package/components/tryghost-mailgun-client-5.98.1.tgz +0 -0
- package/components/tryghost-member-attribution-5.98.1.tgz +0 -0
- package/components/tryghost-member-events-5.98.1.tgz +0 -0
- package/components/tryghost-members-api-5.98.1.tgz +0 -0
- package/components/tryghost-members-csv-5.98.1.tgz +0 -0
- package/components/tryghost-members-events-service-5.98.1.tgz +0 -0
- package/components/{tryghost-members-importer-5.97.3.tgz → tryghost-members-importer-5.98.1.tgz} +0 -0
- package/components/{tryghost-members-offers-5.97.3.tgz → tryghost-members-offers-5.98.1.tgz} +0 -0
- package/components/tryghost-members-payments-5.98.1.tgz +0 -0
- package/components/tryghost-members-ssr-5.98.1.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.98.1.tgz +0 -0
- package/components/tryghost-mentions-email-report-5.98.1.tgz +0 -0
- package/components/tryghost-metrics-server-5.98.1.tgz +0 -0
- package/components/tryghost-milestones-5.98.1.tgz +0 -0
- package/components/tryghost-minifier-5.98.1.tgz +0 -0
- package/components/tryghost-model-to-domain-event-interceptor-5.98.1.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.98.1.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.98.1.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.98.1.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.98.1.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.98.1.tgz +0 -0
- package/components/tryghost-mw-version-match-5.98.1.tgz +0 -0
- package/components/tryghost-mw-vhost-5.98.1.tgz +0 -0
- package/components/tryghost-nql-filter-expansions-5.98.1.tgz +0 -0
- package/components/{tryghost-oembed-service-5.97.3.tgz → tryghost-oembed-service-5.98.1.tgz} +0 -0
- package/components/tryghost-package-json-5.98.1.tgz +0 -0
- package/components/tryghost-post-events-5.98.1.tgz +0 -0
- package/components/tryghost-post-revisions-5.98.1.tgz +0 -0
- package/components/tryghost-posts-service-5.98.1.tgz +0 -0
- package/components/tryghost-recommendations-5.98.1.tgz +0 -0
- package/components/tryghost-referrers-5.98.1.tgz +0 -0
- package/components/tryghost-security-5.98.1.tgz +0 -0
- package/components/tryghost-session-service-5.98.1.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.98.1.tgz +0 -0
- package/components/tryghost-slack-notifications-5.98.1.tgz +0 -0
- package/components/{tryghost-staff-service-5.97.3.tgz → tryghost-staff-service-5.98.1.tgz} +0 -0
- package/components/{tryghost-stats-service-5.97.3.tgz → tryghost-stats-service-5.98.1.tgz} +0 -0
- package/components/{tryghost-tiers-5.97.3.tgz → tryghost-tiers-5.98.1.tgz} +0 -0
- package/components/tryghost-update-check-service-5.98.1.tgz +0 -0
- package/components/tryghost-verification-trigger-5.98.1.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.98.1.tgz +0 -0
- package/components/tryghost-webmentions-5.98.1.tgz +0 -0
- package/content/themes/source/assets/built/screen.css +1 -1
- package/content/themes/source/assets/built/screen.css.map +1 -1
- package/content/themes/source/assets/css/screen.css +3 -2
- package/content/themes/source/package.json +2 -2
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +3 -3
- package/core/built/admin/assets/admin-x-activitypub/{index-ce1044b4.mjs → index-d0087e93.mjs} +4049 -3812
- package/core/built/admin/assets/admin-x-activitypub/modals-aaaeb2ed.mjs +218 -0
- package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +2 -2
- package/core/built/admin/assets/admin-x-demo/{index-4e95bd22.mjs → index-ec1c4705.mjs} +1516 -1510
- package/core/built/admin/assets/admin-x-demo/{modals-1dd517c9.mjs → modals-3bfb50e8.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-56b3751e.mjs → CodeEditorView-72579105.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-a57b83d6.mjs → index-253cc6ec.mjs} +6929 -6721
- package/core/built/admin/assets/admin-x-settings/{index-ae6dfa81.mjs → index-c8b38805.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{modals-8dbfe675.mjs → modals-e1b17636.mjs} +7277 -7295
- package/core/built/admin/assets/{chunk.524.b095de8463657e362a7a.js → chunk.524.61222a4a218eee1d5708.js} +5 -5
- package/core/built/admin/assets/{chunk.582.32fd06c8434d4db3f0a8.js → chunk.582.2b6d8d14e037cb327afb.js} +6 -6
- package/core/built/admin/assets/{ghost-b7702081322ac2a966ad205b1d07416c.js → ghost-7a6db87f125f7ea41beb7a88d500e8dc.js} +173 -144
- package/core/built/admin/assets/ghost-dark-4781c0dc5c36ec188a1ba04d893dbe47.css +1 -0
- package/core/built/admin/index.html +3 -3
- package/core/frontend/apps/amp/lib/views/amp.hbs +1 -1
- package/core/frontend/helpers/body_class.js +32 -0
- package/core/frontend/helpers/content_api_url.js +28 -0
- package/core/frontend/helpers/ghost_head.js +32 -3
- package/core/frontend/meta/schema.js +1 -0
- package/core/frontend/services/theme-engine/preview.js +3 -1
- package/core/server/api/endpoints/session.js +12 -2
- package/core/server/data/migrations/versions/5.97/2024-10-09-14-04-10-add-session-verification-field.js +25 -0
- package/core/server/models/comment.js +25 -0
- package/core/server/services/auth/session/SessionStore.js +0 -6
- package/core/server/services/auth/session/index.js +22 -1
- package/core/server/services/auth/session/middleware.js +55 -6
- package/core/server/services/url/Queue.js +14 -13
- package/core/server/services/url/Resources.js +4 -3
- package/core/server/services/url/UrlGenerator.js +4 -8
- package/core/server/services/url/UrlService.js +2 -3
- package/core/server/services/url/Urls.js +3 -6
- package/core/server/web/api/endpoints/admin/routes.js +2 -0
- package/core/server/web/shared/middleware/api/spam-prevention.js +62 -0
- package/core/server/web/shared/middleware/brute.js +22 -0
- package/core/shared/config/defaults.json +15 -3
- package/core/shared/config/env/config.testing-browser.json +12 -0
- package/core/shared/config/env/config.testing-mysql.json +12 -0
- package/core/shared/config/env/config.testing.json +12 -0
- package/core/shared/labs.js +3 -1
- package/nodemon.json +3 -0
- package/package.json +160 -154
- package/yarn.lock +191 -103
- package/components/tryghost-adapter-cache-memory-ttl-5.97.3.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.97.3.tgz +0 -0
- package/components/tryghost-adapter-manager-5.97.3.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.97.3.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.97.3.tgz +0 -0
- package/components/tryghost-audience-feedback-5.97.3.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.97.3.tgz +0 -0
- package/components/tryghost-collections-5.97.3.tgz +0 -0
- package/components/tryghost-constants-5.97.3.tgz +0 -0
- package/components/tryghost-custom-theme-settings-service-5.97.3.tgz +0 -0
- package/components/tryghost-domain-events-5.97.3.tgz +0 -0
- package/components/tryghost-donations-5.97.3.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.97.3.tgz +0 -0
- package/components/tryghost-email-addresses-5.97.3.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.97.3.tgz +0 -0
- package/components/tryghost-email-analytics-service-5.97.3.tgz +0 -0
- package/components/tryghost-email-events-5.97.3.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.97.3.tgz +0 -0
- package/components/tryghost-express-dynamic-redirects-5.97.3.tgz +0 -0
- package/components/tryghost-external-media-inliner-5.97.3.tgz +0 -0
- package/components/tryghost-extract-api-key-5.97.3.tgz +0 -0
- package/components/tryghost-ghost-5.97.3.tgz +0 -0
- package/components/tryghost-html-to-plaintext-5.97.3.tgz +0 -0
- package/components/tryghost-i18n-5.97.3.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.97.3.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.97.3.tgz +0 -0
- package/components/tryghost-link-redirects-5.97.3.tgz +0 -0
- package/components/tryghost-link-replacer-5.97.3.tgz +0 -0
- package/components/tryghost-magic-link-5.97.3.tgz +0 -0
- package/components/tryghost-mailgun-client-5.97.3.tgz +0 -0
- package/components/tryghost-member-attribution-5.97.3.tgz +0 -0
- package/components/tryghost-member-events-5.97.3.tgz +0 -0
- package/components/tryghost-members-api-5.97.3.tgz +0 -0
- package/components/tryghost-members-csv-5.97.3.tgz +0 -0
- package/components/tryghost-members-events-service-5.97.3.tgz +0 -0
- package/components/tryghost-members-payments-5.97.3.tgz +0 -0
- package/components/tryghost-members-ssr-5.97.3.tgz +0 -0
- package/components/tryghost-members-stripe-service-5.97.3.tgz +0 -0
- package/components/tryghost-mentions-email-report-5.97.3.tgz +0 -0
- package/components/tryghost-metrics-server-5.97.3.tgz +0 -0
- package/components/tryghost-milestones-5.97.3.tgz +0 -0
- package/components/tryghost-minifier-5.97.3.tgz +0 -0
- package/components/tryghost-model-to-domain-event-interceptor-5.97.3.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.97.3.tgz +0 -0
- package/components/tryghost-mw-cache-control-5.97.3.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.97.3.tgz +0 -0
- package/components/tryghost-mw-session-from-token-5.97.3.tgz +0 -0
- package/components/tryghost-mw-update-user-last-seen-5.97.3.tgz +0 -0
- package/components/tryghost-mw-version-match-5.97.3.tgz +0 -0
- package/components/tryghost-mw-vhost-5.97.3.tgz +0 -0
- package/components/tryghost-nql-filter-expansions-5.97.3.tgz +0 -0
- package/components/tryghost-package-json-5.97.3.tgz +0 -0
- package/components/tryghost-post-events-5.97.3.tgz +0 -0
- package/components/tryghost-post-revisions-5.97.3.tgz +0 -0
- package/components/tryghost-posts-service-5.97.3.tgz +0 -0
- package/components/tryghost-recommendations-5.97.3.tgz +0 -0
- package/components/tryghost-referrers-5.97.3.tgz +0 -0
- package/components/tryghost-security-5.97.3.tgz +0 -0
- package/components/tryghost-session-service-5.97.3.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.97.3.tgz +0 -0
- package/components/tryghost-slack-notifications-5.97.3.tgz +0 -0
- package/components/tryghost-update-check-service-5.97.3.tgz +0 -0
- package/components/tryghost-verification-trigger-5.97.3.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.97.3.tgz +0 -0
- package/components/tryghost-webmentions-5.97.3.tgz +0 -0
- package/core/built/admin/assets/admin-x-activitypub/modals-35dd1224.mjs +0 -250
- package/core/built/admin/assets/ghost-dark-b00268cf596f7bba8699dce557d65585.css +0 -1
|
@@ -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%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%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%225.
|
|
11
|
+
<meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22editorUrl%22%3A%22%22%2C%22rootURL%22%3A%22%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%225.98%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%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%2C%22editorFilename%22%3A%22koenig-lexical.umd.js%22%2C%22editorHash%22%3A%22ee37f0b9eb%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%221b17317b1f%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22a887193dcd%22%2C%22adminXActivitypubFilename%22%3A%22admin-x-activitypub.js%22%2C%22adminXActivitypubHash%22%3A%22ad0a25d390%22%2C%22adminXActivitypubCustomUrl%22%3A%22https%3A%2F%2Fcdn.jsdelivr.net%2Fghost%2Fadmin-x-activitypub%400%2Fdist%2Fadmin-x-activitypub.js%22%7D" />
|
|
12
12
|
|
|
13
13
|
<meta name="HandheldFriendly" content="True" />
|
|
14
14
|
<meta name="MobileOptimized" content="320" />
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
|
|
59
59
|
<script src="assets/vendor-88cd9f5cf5eba65221e2d2a636531eaa.js"></script>
|
|
60
60
|
<script src="assets/chunk.874.5eb920d19e75683234c2.js"></script>
|
|
61
|
-
<script src="assets/chunk.524.
|
|
62
|
-
<script src="assets/ghost-
|
|
61
|
+
<script src="assets/chunk.524.61222a4a218eee1d5708.js"></script>
|
|
62
|
+
<script src="assets/ghost-7a6db87f125f7ea41beb7a88d500e8dc.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
// Usage: `{{body_class}}`
|
|
3
3
|
//
|
|
4
4
|
// Output classes for the body element
|
|
5
|
+
const {labs, settingsCache} = require('../services/proxy');
|
|
6
|
+
const {generateCustomFontBodyClass, isValidCustomFont, isValidCustomHeadingFont} = require('@tryghost/custom-fonts');
|
|
5
7
|
const {SafeString} = require('../services/handlebars');
|
|
6
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('@tryghost/custom-fonts').FontSelection} FontSelection
|
|
11
|
+
*/
|
|
12
|
+
|
|
7
13
|
// We use the name body_class to match the helper for consistency
|
|
8
14
|
module.exports = function body_class(options) { // eslint-disable-line camelcase
|
|
9
15
|
let classes = [];
|
|
@@ -39,6 +45,32 @@ module.exports = function body_class(options) { // eslint-disable-line camelcase
|
|
|
39
45
|
classes.push('paged');
|
|
40
46
|
}
|
|
41
47
|
|
|
48
|
+
if (labs.isSet('customFonts')) {
|
|
49
|
+
// Check if if the request is for a site preview, in which case we **always** use the custom font values
|
|
50
|
+
// from the passed in data, even when they're empty strings or settings cache has values.
|
|
51
|
+
const isSitePreview = options.data.site._preview;
|
|
52
|
+
// Taking the fonts straight from the passed in data, as they can't be used from the
|
|
53
|
+
// settings cache for the theme preview until the settings are saved. Once saved,
|
|
54
|
+
// we need to use the settings cache to provide the correct CSS injection.
|
|
55
|
+
const headingFont = isSitePreview ? options.data.site.heading_font : settingsCache.get('heading_font');
|
|
56
|
+
const bodyFont = isSitePreview ? options.data.site.body_font : settingsCache.get('body_font');
|
|
57
|
+
|
|
58
|
+
if ((typeof headingFont === 'string' && isValidCustomHeadingFont(headingFont)) ||
|
|
59
|
+
(typeof bodyFont === 'string' && isValidCustomFont(bodyFont))) {
|
|
60
|
+
/** @type FontSelection */
|
|
61
|
+
const fontSelection = {};
|
|
62
|
+
|
|
63
|
+
if (headingFont) {
|
|
64
|
+
fontSelection.heading = headingFont;
|
|
65
|
+
}
|
|
66
|
+
if (bodyFont) {
|
|
67
|
+
fontSelection.body = bodyFont;
|
|
68
|
+
}
|
|
69
|
+
const customBodyClasses = generateCustomFontBodyClass(fontSelection);
|
|
70
|
+
classes.push(new SafeString(customBodyClasses));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
42
74
|
classes = classes.join(' ').trim();
|
|
43
75
|
|
|
44
76
|
return new SafeString(classes);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const {SafeString} = require('../services/handlebars');
|
|
2
|
+
const logging = require('@tryghost/logging');
|
|
3
|
+
const {urlUtils} = require('../services/proxy');
|
|
4
|
+
|
|
5
|
+
module.exports = function content_api_url(options) { // eslint-disable-line camelcase
|
|
6
|
+
let result;
|
|
7
|
+
const absoluteUrlRequested = getAbsoluteOption(options);
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
let path = urlUtils.urlFor('api', {type: 'content'}, absoluteUrlRequested);
|
|
11
|
+
result = new SafeString(path);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
logging.error(error);
|
|
14
|
+
result = '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return result;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function getAbsoluteOption(options) {
|
|
21
|
+
const absoluteOption = options && options.hash && options.hash.absolute;
|
|
22
|
+
if (absoluteOption === undefined || absoluteOption === 'true' || absoluteOption === true || absoluteOption === null) {
|
|
23
|
+
return true;
|
|
24
|
+
} else {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// Outputs scripts and other assets at the top of a Ghost theme
|
|
5
5
|
const {labs, metaData, settingsCache, config, blogIcon, urlUtils, getFrontendKey} = require('../services/proxy');
|
|
6
6
|
const {escapeExpression, SafeString} = require('../services/handlebars');
|
|
7
|
-
|
|
7
|
+
const {generateCustomFontCss, isValidCustomFont, isValidCustomHeadingFont} = require('@tryghost/custom-fonts');
|
|
8
8
|
// BAD REQUIRE
|
|
9
9
|
// @TODO fix this require
|
|
10
10
|
const {cardAssets} = require('../services/assets-minification');
|
|
@@ -15,6 +15,10 @@ const debug = require('@tryghost/debug')('ghost_head');
|
|
|
15
15
|
const templateStyles = require('./tpl/styles');
|
|
16
16
|
const {getFrontendAppConfig, getDataAttributes} = require('../utils/frontend-apps');
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {import('@tryghost/custom-fonts').FontSelection} FontSelection
|
|
20
|
+
*/
|
|
21
|
+
|
|
18
22
|
const {get: getMetaData, getAssetUrl} = metaData;
|
|
19
23
|
|
|
20
24
|
function writeMetaTag(property, content, type) {
|
|
@@ -45,8 +49,8 @@ function finaliseStructuredData(meta) {
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
function getMembersHelper(data, frontendKey) {
|
|
48
|
-
// Do not load Portal if both Memberships and Tips & Donations are disabled
|
|
49
|
-
if (!settingsCache.get('members_enabled') && !settingsCache.get('donations_enabled')) {
|
|
52
|
+
// Do not load Portal if both Memberships and Tips & Donations and Recommendations are disabled
|
|
53
|
+
if (!settingsCache.get('members_enabled') && !settingsCache.get('donations_enabled') && !settingsCache.get('recommendations_enabled')) {
|
|
50
54
|
return '';
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -339,6 +343,31 @@ module.exports = async function ghost_head(options) { // eslint-disable-line cam
|
|
|
339
343
|
if (config.get('tinybird') && config.get('tinybird:tracker') && config.get('tinybird:tracker:scriptUrl')) {
|
|
340
344
|
head.push(getTinybirdTrackerScript(dataRoot));
|
|
341
345
|
}
|
|
346
|
+
|
|
347
|
+
if (labs.isSet('customFonts')) {
|
|
348
|
+
// Check if if the request is for a site preview, in which case we **always** use the custom font values
|
|
349
|
+
// from the passed in data, even when they're empty strings or settings cache has values.
|
|
350
|
+
const isSitePreview = options.data.site._preview;
|
|
351
|
+
// Taking the fonts straight from the passed in data, as they can't be used from the
|
|
352
|
+
// settings cache for the theme preview until the settings are saved. Once saved,
|
|
353
|
+
// we need to use the settings cache to provide the correct CSS injection.
|
|
354
|
+
const headingFont = isSitePreview ? options.data.site.heading_font : settingsCache.get('heading_font');
|
|
355
|
+
const bodyFont = isSitePreview ? options.data.site.body_font : settingsCache.get('body_font');
|
|
356
|
+
if ((typeof headingFont === 'string' && isValidCustomHeadingFont(headingFont)) ||
|
|
357
|
+
(typeof bodyFont === 'string' && isValidCustomFont(bodyFont))) {
|
|
358
|
+
/** @type FontSelection */
|
|
359
|
+
const fontSelection = {};
|
|
360
|
+
|
|
361
|
+
if (headingFont) {
|
|
362
|
+
fontSelection.heading = headingFont;
|
|
363
|
+
}
|
|
364
|
+
if (bodyFont) {
|
|
365
|
+
fontSelection.body = bodyFont;
|
|
366
|
+
}
|
|
367
|
+
const customCSS = generateCustomFontCss(fontSelection);
|
|
368
|
+
head.push(new SafeString(customCSS));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
342
371
|
}
|
|
343
372
|
|
|
344
373
|
debug('end');
|
|
@@ -119,6 +119,7 @@ function getHomeSchema(metaData) {
|
|
|
119
119
|
'@type': 'WebSite',
|
|
120
120
|
publisher: schemaPublisherObject(metaData),
|
|
121
121
|
url: metaData.url,
|
|
122
|
+
name: metaData.site.title,
|
|
122
123
|
image: schemaImageObject(metaData.coverImage),
|
|
123
124
|
mainEntityOfPage: metaData.url,
|
|
124
125
|
description: metaData.metaDescription ?
|
|
@@ -22,7 +22,9 @@ function getPreviewData(previewHeader, customThemeSettingKeys = []) {
|
|
|
22
22
|
logo: 'logo',
|
|
23
23
|
cover: 'cover_image',
|
|
24
24
|
custom: 'custom',
|
|
25
|
-
d: 'description'
|
|
25
|
+
d: 'description',
|
|
26
|
+
bf: 'body_font',
|
|
27
|
+
hf: 'heading_font'
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
let opts = new URLSearchParams(previewHeader);
|
|
@@ -61,8 +61,18 @@ const controller = {
|
|
|
61
61
|
});
|
|
62
62
|
},
|
|
63
63
|
delete() {
|
|
64
|
-
return Promise.resolve(function
|
|
65
|
-
auth.session.
|
|
64
|
+
return Promise.resolve(function logoutSessionMw(req, res, next) {
|
|
65
|
+
auth.session.logout(req, res, next);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
sendVerification() {
|
|
69
|
+
return Promise.resolve(function sendAuthCodeMw(req, res, next) {
|
|
70
|
+
auth.session.sendAuthCode(req, res, next);
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
verify() {
|
|
74
|
+
return Promise.resolve(function verifyAuthCodeMw(req, res, next) {
|
|
75
|
+
auth.session.verifyAuthCode(req, res, next);
|
|
66
76
|
});
|
|
67
77
|
}
|
|
68
78
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const logging = require('@tryghost/logging');
|
|
2
|
+
|
|
3
|
+
const {createTransactionalMigration} = require('../../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = createTransactionalMigration(
|
|
6
|
+
async function up(knex) {
|
|
7
|
+
logging.info('Adding verified property to sessions');
|
|
8
|
+
|
|
9
|
+
await knex.raw(`
|
|
10
|
+
UPDATE sessions
|
|
11
|
+
SET session_data = JSON_SET(session_data, '$.verified', 'true')
|
|
12
|
+
WHERE JSON_VALID(session_data);
|
|
13
|
+
`);
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
async function down(knex) {
|
|
17
|
+
logging.info('Removing verified property from sessions');
|
|
18
|
+
|
|
19
|
+
await knex.raw(`
|
|
20
|
+
UPDATE sessions
|
|
21
|
+
SET session_data = JSON_REMOVE(session_data, '$.verified')
|
|
22
|
+
WHERE JSON_VALID(session_data);
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
);
|
|
@@ -202,6 +202,21 @@ const Comment = ghostBookshelf.Model.extend({
|
|
|
202
202
|
return options;
|
|
203
203
|
},
|
|
204
204
|
|
|
205
|
+
async findMostLikedComment(options = {}) {
|
|
206
|
+
let query = ghostBookshelf.knex('comments')
|
|
207
|
+
.select('comments.*')
|
|
208
|
+
.count('comment_likes.id as count__likes') // Counting likes for sorting
|
|
209
|
+
.leftJoin('comment_likes', 'comments.id', 'comment_likes.comment_id')
|
|
210
|
+
.groupBy('comments.id') // Group by comment ID to aggregate likes count
|
|
211
|
+
.orderBy('count__likes', 'desc') // Order by likes in descending order (most likes first)
|
|
212
|
+
.limit(1); // Limit to just 1 result
|
|
213
|
+
// Execute the query and get the result
|
|
214
|
+
const result = await query.first(); // Fetch the single top comment
|
|
215
|
+
const id = result && result.id;
|
|
216
|
+
// Fetch the comment model by ID
|
|
217
|
+
return this.findOne({id}, options);
|
|
218
|
+
},
|
|
219
|
+
|
|
205
220
|
async findPage(options) {
|
|
206
221
|
const {withRelated} = this.defaultRelations('findPage', options);
|
|
207
222
|
|
|
@@ -218,6 +233,16 @@ const Comment = ghostBookshelf.Model.extend({
|
|
|
218
233
|
await model.load(relationsToLoadIndividually, _.omit(options, 'withRelated'));
|
|
219
234
|
}
|
|
220
235
|
|
|
236
|
+
// if options.order === 'best', we findMostLikedComment
|
|
237
|
+
// then we remove it from the result set and add it as the first element
|
|
238
|
+
if (options.order === 'best' && options.page === '1') {
|
|
239
|
+
const mostLikedComment = await this.findMostLikedComment(options);
|
|
240
|
+
if (mostLikedComment) {
|
|
241
|
+
result.data = result.data.filter(comment => comment.id !== mostLikedComment.id);
|
|
242
|
+
result.data.unshift(mostLikedComment);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
221
246
|
return result;
|
|
222
247
|
},
|
|
223
248
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const {Store} = require('express-session');
|
|
2
|
-
const {InternalServerError} = require('@tryghost/errors');
|
|
3
2
|
|
|
4
3
|
module.exports = class SessionStore extends Store {
|
|
5
4
|
constructor(SessionModel) {
|
|
@@ -29,11 +28,6 @@ module.exports = class SessionStore extends Store {
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
set(sid, sessionData, callback) {
|
|
32
|
-
if (!sessionData.user_id) {
|
|
33
|
-
return callback(new InternalServerError({
|
|
34
|
-
message: 'Cannot create a session with no user_id'
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
31
|
this.SessionModel
|
|
38
32
|
.upsert({session_data: sessionData}, {session_id: sid})
|
|
39
33
|
.then(() => {
|
|
@@ -2,13 +2,21 @@ const adapterManager = require('../../adapter-manager');
|
|
|
2
2
|
const createSessionService = require('@tryghost/session-service');
|
|
3
3
|
const sessionFromToken = require('@tryghost/mw-session-from-token');
|
|
4
4
|
const createSessionMiddleware = require('./middleware');
|
|
5
|
+
const settingsCache = require('../../../../shared/settings-cache');
|
|
6
|
+
const {GhostMailer} = require('../../mail');
|
|
7
|
+
const {t} = require('../../i18n');
|
|
8
|
+
const labs = require('../../../../shared/labs');
|
|
5
9
|
|
|
6
10
|
const expressSession = require('./express-session');
|
|
7
11
|
|
|
8
12
|
const models = require('../../../models');
|
|
9
13
|
const urlUtils = require('../../../../shared/url-utils');
|
|
14
|
+
const {blogIcon} = require('../../../lib/image');
|
|
10
15
|
const url = require('url');
|
|
11
16
|
|
|
17
|
+
// TODO: We have too many lines here, should move functions out into a utils module
|
|
18
|
+
/* eslint-disable max-lines */
|
|
19
|
+
|
|
12
20
|
function getOriginOfRequest(req) {
|
|
13
21
|
const origin = req.get('origin');
|
|
14
22
|
const referrer = req.get('referrer') || urlUtils.getAdminUrl() || urlUtils.getSiteUrl();
|
|
@@ -28,12 +36,25 @@ function getOriginOfRequest(req) {
|
|
|
28
36
|
return null;
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
const mailer = new GhostMailer();
|
|
40
|
+
|
|
31
41
|
const sessionService = createSessionService({
|
|
32
42
|
getOriginOfRequest,
|
|
33
43
|
getSession: expressSession.getSession,
|
|
34
44
|
findUserById({id}) {
|
|
35
45
|
return models.User.findOne({id, status: 'active'});
|
|
36
|
-
}
|
|
46
|
+
},
|
|
47
|
+
getSettingsCache(key) {
|
|
48
|
+
return settingsCache.get(key);
|
|
49
|
+
},
|
|
50
|
+
getBlogLogo() {
|
|
51
|
+
return blogIcon.getIconUrl({absolute: true, fallbackToDefault: false})
|
|
52
|
+
|| 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png';
|
|
53
|
+
},
|
|
54
|
+
mailer,
|
|
55
|
+
urlUtils,
|
|
56
|
+
labs,
|
|
57
|
+
t
|
|
37
58
|
});
|
|
38
59
|
|
|
39
60
|
module.exports = createSessionMiddleware({sessionService});
|
|
@@ -1,19 +1,36 @@
|
|
|
1
|
+
const errors = require('@tryghost/errors');
|
|
2
|
+
|
|
1
3
|
function SessionMiddleware({sessionService}) {
|
|
2
4
|
async function createSession(req, res, next) {
|
|
3
5
|
try {
|
|
4
6
|
await sessionService.createSessionForUser(req, res, req.user);
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
const isVerified = await sessionService.isVerifiedSession(req, res);
|
|
9
|
+
if (isVerified) {
|
|
10
|
+
res.sendStatus(201);
|
|
11
|
+
} else {
|
|
12
|
+
await sessionService.sendAuthCodeToUser(req, res);
|
|
13
|
+
throw new errors.NoPermissionError({
|
|
14
|
+
code: '2FA_TOKEN_REQUIRED',
|
|
15
|
+
errorType: 'Needs2FAError',
|
|
16
|
+
message: 'User must verify session to login.'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
6
19
|
} catch (err) {
|
|
7
20
|
next(err);
|
|
8
21
|
}
|
|
9
22
|
}
|
|
10
23
|
|
|
11
|
-
async function
|
|
24
|
+
async function logout(req, res, next) {
|
|
12
25
|
try {
|
|
13
|
-
await sessionService.
|
|
26
|
+
await sessionService.removeUserForSession(req, res);
|
|
14
27
|
res.sendStatus(204);
|
|
15
28
|
} catch (err) {
|
|
16
|
-
|
|
29
|
+
if (errors.utils.isGhostError(err)) {
|
|
30
|
+
next(err);
|
|
31
|
+
} else {
|
|
32
|
+
next(new errors.InternalServerError({err}));
|
|
33
|
+
}
|
|
17
34
|
}
|
|
18
35
|
}
|
|
19
36
|
|
|
@@ -21,6 +38,11 @@ function SessionMiddleware({sessionService}) {
|
|
|
21
38
|
try {
|
|
22
39
|
const user = await sessionService.getUserForSession(req, res);
|
|
23
40
|
if (user) {
|
|
41
|
+
const isVerified = await sessionService.isVerifiedSession(req, res);
|
|
42
|
+
if (!isVerified) {
|
|
43
|
+
return next();
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
// Do not nullify `req.user` as it might have been already set
|
|
25
47
|
// in a previous middleware (authorize middleware).
|
|
26
48
|
req.user = user;
|
|
@@ -31,10 +53,37 @@ function SessionMiddleware({sessionService}) {
|
|
|
31
53
|
}
|
|
32
54
|
}
|
|
33
55
|
|
|
56
|
+
async function sendAuthCode(req, res, next) {
|
|
57
|
+
try {
|
|
58
|
+
await sessionService.sendAuthCodeToUser(req, res);
|
|
59
|
+
|
|
60
|
+
res.sendStatus(200);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
next(err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function verifyAuthCode(req, res, next) {
|
|
67
|
+
try {
|
|
68
|
+
const verified = await sessionService.verifyAuthCodeForUser(req, res);
|
|
69
|
+
|
|
70
|
+
if (verified) {
|
|
71
|
+
await sessionService.verifySession(req, res);
|
|
72
|
+
res.sendStatus(200);
|
|
73
|
+
} else {
|
|
74
|
+
res.sendStatus(401);
|
|
75
|
+
}
|
|
76
|
+
} catch (err) {
|
|
77
|
+
next(err);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
34
81
|
return {
|
|
35
82
|
createSession: createSession,
|
|
36
|
-
|
|
37
|
-
authenticate: authenticate
|
|
83
|
+
logout: logout,
|
|
84
|
+
authenticate: authenticate,
|
|
85
|
+
sendAuthCode: sendAuthCode,
|
|
86
|
+
verifyAuthCode: verifyAuthCode
|
|
38
87
|
};
|
|
39
88
|
}
|
|
40
89
|
|
|
@@ -93,7 +93,7 @@ class Queue extends EventEmitter {
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
debug('
|
|
96
|
+
debug('register', options.event, options.tolerance);
|
|
97
97
|
|
|
98
98
|
this.queue[options.event].subscribers.push(fn);
|
|
99
99
|
}
|
|
@@ -103,19 +103,20 @@ class Queue extends EventEmitter {
|
|
|
103
103
|
* @param {Object} options
|
|
104
104
|
*/
|
|
105
105
|
run(options) {
|
|
106
|
-
const event = options
|
|
107
|
-
const action = options.action;
|
|
108
|
-
const eventData = options.eventData;
|
|
106
|
+
const {event, action, eventData} = options;
|
|
109
107
|
|
|
110
108
|
clearTimeout(this.toNotify[action].timeout);
|
|
111
109
|
this.toNotify[action].timeout = null;
|
|
112
110
|
|
|
113
|
-
|
|
111
|
+
const subscribers = this.queue[event].subscribers;
|
|
112
|
+
const notified = this.toNotify[action].notified;
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
const fn = this.queue[event].subscribers[this.toNotify[action].notified.length];
|
|
114
|
+
debug('run', action, event, subscribers.length, notified.length);
|
|
117
115
|
|
|
118
|
-
|
|
116
|
+
if (subscribers.length && subscribers.length !== notified.length) {
|
|
117
|
+
const fn = subscribers[notified.length];
|
|
118
|
+
|
|
119
|
+
debug('run.execute', action, event, notified.length);
|
|
119
120
|
|
|
120
121
|
/**
|
|
121
122
|
* @NOTE: Currently no async operations happen in the subscribers functions.
|
|
@@ -124,7 +125,7 @@ class Queue extends EventEmitter {
|
|
|
124
125
|
try {
|
|
125
126
|
fn(eventData);
|
|
126
127
|
|
|
127
|
-
debug('executed', action, event,
|
|
128
|
+
debug('run.executed', action, event, notified.length);
|
|
128
129
|
this.toNotify[action].notified.push(fn);
|
|
129
130
|
this.run(options);
|
|
130
131
|
} catch (err) {
|
|
@@ -144,15 +145,15 @@ class Queue extends EventEmitter {
|
|
|
144
145
|
// CASE 3: wait for more subscribers, i am still tolerant
|
|
145
146
|
if (this.queue[event].tolerance === 0) {
|
|
146
147
|
delete this.toNotify[action];
|
|
147
|
-
debug('ended (1)', event, action);
|
|
148
|
+
debug('run.ended (1)', event, action);
|
|
148
149
|
this.emit('ended', event);
|
|
149
|
-
} else if (
|
|
150
|
+
} else if (subscribers.length >= this.queue[event].requiredSubscriberCount &&
|
|
150
151
|
this.toNotify[action].timeoutInMS > this.queue[event].tolerance) {
|
|
151
152
|
delete this.toNotify[action];
|
|
152
|
-
debug('ended (2)', event, action);
|
|
153
|
+
debug('run.ended (2)', event, action);
|
|
153
154
|
this.emit('ended', event);
|
|
154
155
|
} else {
|
|
155
|
-
debug('retry', event, action, this.toNotify[action].timeoutInMS);
|
|
156
|
+
debug('run.retry', event, action, this.toNotify[action].timeoutInMS);
|
|
156
157
|
|
|
157
158
|
this.toNotify[action].timeoutInMS = this.toNotify[action].timeoutInMS * 1.1;
|
|
158
159
|
|
|
@@ -128,12 +128,13 @@ class Resources {
|
|
|
128
128
|
modelOptions.limit = options.limit;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
const now = Date.now();
|
|
131
132
|
const objects = await models.Base.Model.raw_knex.fetchAll(modelOptions);
|
|
132
|
-
debug('fetched', resourceConfig.type, objects.length);
|
|
133
|
+
debug('_fetch.fetched', resourceConfig.type, objects.length, `${Date.now() - now}ms`);
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
for (const object of objects) {
|
|
135
136
|
this.data[resourceConfig.type].push(new Resource(resourceConfig.type, object));
|
|
136
|
-
}
|
|
137
|
+
}
|
|
137
138
|
|
|
138
139
|
if (objects.length && isSQLite) {
|
|
139
140
|
options.offset = options.offset + options.limit;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const _ = require('lodash');
|
|
2
1
|
const nql = require('@tryghost/nql');
|
|
3
2
|
const debug = require('@tryghost/debug')('services:url:generator');
|
|
4
3
|
const localUtils = require('../../../shared/url-utils');
|
|
@@ -121,16 +120,14 @@ class UrlGenerator {
|
|
|
121
120
|
* @private
|
|
122
121
|
*/
|
|
123
122
|
_onInit() {
|
|
124
|
-
debug('_onInit', this.resourceType);
|
|
125
|
-
|
|
126
123
|
// @NOTE: get the resources of my type e.g. posts.
|
|
127
124
|
const resources = this.resources.getAllByType(this.resourceType);
|
|
128
125
|
|
|
129
|
-
debug(resources.length);
|
|
126
|
+
debug('_onInit', this.resourceType, resources.length);
|
|
130
127
|
|
|
131
|
-
|
|
128
|
+
for (const resource of resources) {
|
|
132
129
|
this._try(resource);
|
|
133
|
-
}
|
|
130
|
+
}
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
/**
|
|
@@ -141,7 +138,7 @@ class UrlGenerator {
|
|
|
141
138
|
* @private
|
|
142
139
|
*/
|
|
143
140
|
_onAdded(event) {
|
|
144
|
-
debug('
|
|
141
|
+
debug('_onAdded', this.toString());
|
|
145
142
|
|
|
146
143
|
// CASE: you are type "pages", but the incoming type is "users"
|
|
147
144
|
if (event.type !== this.resourceType) {
|
|
@@ -149,7 +146,6 @@ class UrlGenerator {
|
|
|
149
146
|
}
|
|
150
147
|
|
|
151
148
|
const resource = this.resources.getByIdAndType(event.type, event.id);
|
|
152
|
-
|
|
153
149
|
this._try(resource);
|
|
154
150
|
}
|
|
155
151
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
const debug = _debug('ghost:services:url:service');
|
|
1
|
+
const debug = require('@tryghost/debug')('services:url:service');
|
|
3
2
|
const _ = require('lodash');
|
|
4
3
|
const errors = require('@tryghost/errors');
|
|
5
4
|
const labs = require('../../../shared/labs');
|
|
@@ -92,7 +91,7 @@ class UrlService {
|
|
|
92
91
|
* @param {String} permalink
|
|
93
92
|
*/
|
|
94
93
|
onRouterAddedType(identifier, filter, resourceType, permalink) {
|
|
95
|
-
debug('Registering route:
|
|
94
|
+
debug('Registering route:', filter, resourceType, permalink);
|
|
96
95
|
|
|
97
96
|
let urlGenerator = new UrlGenerator({
|
|
98
97
|
identifier,
|
|
@@ -37,11 +37,8 @@ class Urls {
|
|
|
37
37
|
* @param {string} options.url
|
|
38
38
|
*/
|
|
39
39
|
add(options) {
|
|
40
|
-
const url = options
|
|
41
|
-
|
|
42
|
-
const resource = options.resource;
|
|
43
|
-
|
|
44
|
-
debug('cache', url);
|
|
40
|
+
const {url, generatorId, resource} = options;
|
|
41
|
+
debug('add', resource.data.id, url);
|
|
45
42
|
|
|
46
43
|
if (this.urls[resource.data.id]) {
|
|
47
44
|
const error = new errors.InternalServerError({
|
|
@@ -131,7 +128,7 @@ class Urls {
|
|
|
131
128
|
return;
|
|
132
129
|
}
|
|
133
130
|
|
|
134
|
-
debug('
|
|
131
|
+
debug('removeResourceId', this.urls[id].url, this.urls[id].generatorId);
|
|
135
132
|
|
|
136
133
|
events.emit('url.removed', {
|
|
137
134
|
url: this.urls[id].url,
|
|
@@ -243,6 +243,8 @@ module.exports = function apiRoutes() {
|
|
|
243
243
|
http(api.session.add)
|
|
244
244
|
);
|
|
245
245
|
router.del('/session', mw.authAdminApi, http(api.session.delete));
|
|
246
|
+
router.post('/session/verify', shared.middleware.brute.sendVerificationCode, http(api.session.sendVerification));
|
|
247
|
+
router.put('/session/verify', shared.middleware.brute.userVerification, http(api.session.verify));
|
|
246
248
|
|
|
247
249
|
// ## Identity
|
|
248
250
|
router.get('/identities', mw.authAdminApi, http(api.identities.read));
|