ghost 5.110.4 → 5.112.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/components/tryghost-adapter-cache-memory-ttl-5.112.0.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.112.0.tgz +0 -0
- package/components/{tryghost-adapter-manager-5.110.4.tgz → tryghost-adapter-manager-5.112.0.tgz} +0 -0
- package/components/tryghost-announcement-bar-settings-5.112.0.tgz +0 -0
- package/components/{tryghost-api-framework-5.110.4.tgz → tryghost-api-framework-5.112.0.tgz} +0 -0
- package/components/tryghost-api-version-compatibility-service-5.112.0.tgz +0 -0
- package/components/{tryghost-audience-feedback-5.110.4.tgz → tryghost-audience-feedback-5.112.0.tgz} +0 -0
- package/components/tryghost-bookshelf-repository-5.112.0.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.112.0.tgz +0 -0
- package/components/tryghost-captcha-service-5.112.0.tgz +0 -0
- package/components/tryghost-constants-5.112.0.tgz +0 -0
- package/components/tryghost-custom-fonts-5.112.0.tgz +0 -0
- package/components/{tryghost-custom-theme-settings-service-5.110.4.tgz → tryghost-custom-theme-settings-service-5.112.0.tgz} +0 -0
- package/components/{tryghost-data-generator-5.110.4.tgz → tryghost-data-generator-5.112.0.tgz} +0 -0
- package/components/{tryghost-domain-events-5.110.4.tgz → tryghost-domain-events-5.112.0.tgz} +0 -0
- package/components/tryghost-donations-5.112.0.tgz +0 -0
- package/components/tryghost-email-addresses-5.112.0.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.112.0.tgz +0 -0
- package/components/{tryghost-email-analytics-service-5.110.4.tgz → tryghost-email-analytics-service-5.112.0.tgz} +0 -0
- package/components/tryghost-email-content-generator-5.112.0.tgz +0 -0
- package/components/tryghost-email-events-5.112.0.tgz +0 -0
- package/components/tryghost-email-service-5.112.0.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.112.0.tgz +0 -0
- package/components/{tryghost-express-dynamic-redirects-5.110.4.tgz → tryghost-express-dynamic-redirects-5.112.0.tgz} +0 -0
- package/components/{tryghost-external-media-inliner-5.110.4.tgz → tryghost-external-media-inliner-5.112.0.tgz} +0 -0
- package/components/tryghost-extract-api-key-5.112.0.tgz +0 -0
- package/components/tryghost-ghost-5.112.0.tgz +0 -0
- package/components/{tryghost-html-to-plaintext-5.110.4.tgz → tryghost-html-to-plaintext-5.112.0.tgz} +0 -0
- package/components/tryghost-i18n-5.112.0.tgz +0 -0
- package/components/tryghost-identity-token-service-5.112.0.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.112.0.tgz +0 -0
- package/components/{tryghost-importer-revue-5.110.4.tgz → tryghost-importer-revue-5.112.0.tgz} +0 -0
- package/components/tryghost-in-memory-repository-5.112.0.tgz +0 -0
- package/components/{tryghost-job-manager-5.110.4.tgz → tryghost-job-manager-5.112.0.tgz} +0 -0
- package/components/{tryghost-link-redirects-5.110.4.tgz → tryghost-link-redirects-5.112.0.tgz} +0 -0
- package/components/tryghost-link-replacer-5.112.0.tgz +0 -0
- package/components/{tryghost-magic-link-5.110.4.tgz → tryghost-magic-link-5.112.0.tgz} +0 -0
- package/components/tryghost-mail-events-5.112.0.tgz +0 -0
- package/components/tryghost-mailgun-client-5.112.0.tgz +0 -0
- package/components/{tryghost-member-attribution-5.110.4.tgz → tryghost-member-attribution-5.112.0.tgz} +0 -0
- package/components/{tryghost-member-events-5.110.4.tgz → tryghost-member-events-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-api-5.110.4.tgz → tryghost-members-api-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-csv-5.110.4.tgz → tryghost-members-csv-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-importer-5.110.4.tgz → tryghost-members-importer-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-offers-5.110.4.tgz → tryghost-members-offers-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-payments-5.110.4.tgz → tryghost-members-payments-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-ssr-5.110.4.tgz → tryghost-members-ssr-5.112.0.tgz} +0 -0
- package/components/{tryghost-members-stripe-service-5.110.4.tgz → tryghost-members-stripe-service-5.112.0.tgz} +0 -0
- package/components/{tryghost-milestones-5.110.4.tgz → tryghost-milestones-5.112.0.tgz} +0 -0
- package/components/tryghost-minifier-5.112.0.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.112.0.tgz +0 -0
- package/components/{tryghost-mw-cache-control-5.110.4.tgz → tryghost-mw-cache-control-5.112.0.tgz} +0 -0
- package/components/tryghost-mw-error-handler-5.112.0.tgz +0 -0
- package/components/{tryghost-mw-session-from-token-5.110.4.tgz → tryghost-mw-session-from-token-5.112.0.tgz} +0 -0
- package/components/{tryghost-mw-update-user-last-seen-5.110.4.tgz → tryghost-mw-update-user-last-seen-5.112.0.tgz} +0 -0
- package/components/tryghost-mw-version-match-5.112.0.tgz +0 -0
- package/components/tryghost-mw-vhost-5.112.0.tgz +0 -0
- package/components/tryghost-package-json-5.112.0.tgz +0 -0
- package/components/{tryghost-post-events-5.110.4.tgz → tryghost-post-events-5.112.0.tgz} +0 -0
- package/components/{tryghost-post-revisions-5.110.4.tgz → tryghost-post-revisions-5.112.0.tgz} +0 -0
- package/components/{tryghost-posts-service-5.110.4.tgz → tryghost-posts-service-5.112.0.tgz} +0 -0
- package/components/tryghost-prometheus-metrics-5.112.0.tgz +0 -0
- package/components/tryghost-recommendations-5.112.0.tgz +0 -0
- package/components/tryghost-referrers-5.112.0.tgz +0 -0
- package/components/{tryghost-security-5.110.4.tgz → tryghost-security-5.112.0.tgz} +0 -0
- package/components/tryghost-session-service-5.112.0.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.112.0.tgz +0 -0
- package/components/{tryghost-slack-notifications-5.110.4.tgz → tryghost-slack-notifications-5.112.0.tgz} +0 -0
- package/components/tryghost-tiers-5.112.0.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.112.0.tgz +0 -0
- package/components/tryghost-webmentions-5.112.0.tgz +0 -0
- package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +12799 -10270
- package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +2 -2
- package/core/built/admin/assets/admin-x-demo/{index-82e381fb.mjs → index-0040480a.mjs} +3252 -2891
- package/core/built/admin/assets/admin-x-demo/{modals-b20a9ede.mjs → modals-fb35c86c.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{CodeEditorView-ea62c29b.mjs → CodeEditorView-ad8698fe.mjs} +624 -618
- package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +3 -3
- package/core/built/admin/assets/admin-x-settings/{index-af8cf9cf.mjs → index-2713e469.mjs} +6892 -6469
- package/core/built/admin/assets/admin-x-settings/{index-4b25c788.mjs → index-463cec50.mjs} +2 -2
- package/core/built/admin/assets/admin-x-settings/{modals-cb2dc7b7.mjs → modals-033e8fc4.mjs} +7888 -7669
- package/core/built/admin/assets/{chunk.524.3096e68df5b51dacf872.js → chunk.524.db49da6fd8ae155205a4.js} +6 -6
- package/core/built/admin/assets/{chunk.582.e225422f90639ff30544.js → chunk.582.0bf715eb6807f7641706.js} +8 -8
- package/core/built/admin/assets/{ghost-98d002d50a5e01d2100b2c387a849249.js → ghost-62bd4d4c837d453e1038808dc1cd1e4c.js} +43 -42
- package/core/built/admin/assets/img/ap-nodes-01ee317529e6353a1c34a062c388f1e7.png +0 -0
- package/core/built/admin/assets/koenig-lexical/index.css +1 -1
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +18314 -17680
- package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +229 -200
- package/core/built/admin/assets/posts/posts.js +24137 -24156
- package/core/built/admin/index.html +3 -3
- package/core/frontend/helpers/get.js +2 -3
- package/core/frontend/services/sitemap/SiteMapManager.js +1 -1
- package/core/frontend/src/cards/css/cta.css +40 -30
- package/core/frontend/src/cards/css/video.css +1 -0
- package/core/server/api/endpoints/settings-public.js +3 -2
- package/core/server/api/endpoints/utils/serializers/input/settings.js +3 -1
- package/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js +2 -1
- package/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js +2 -1
- package/core/server/data/migrations/versions/5.111/2025-03-05-16-36-39-add-captcha-setting.js +8 -0
- package/core/server/data/migrations/versions/5.112/2025-03-10-10-01-01-add-require-mfa-setting.js +8 -0
- package/core/server/data/schema/default-settings/default-settings.json +14 -0
- package/core/server/models/invite.js +4 -5
- package/core/server/models/post.js +3 -9
- package/core/server/models/relations/authors.js +2 -4
- package/core/server/models/role-utils.js +38 -0
- package/core/server/models/role.js +5 -3
- package/core/server/models/user.js +5 -3
- package/core/server/services/activitypub/ActivityPubService.js +116 -0
- package/core/server/services/activitypub/ActivityPubService.ts +139 -0
- package/core/server/services/activitypub/ActivityPubServiceWrapper.js +1 -1
- package/core/server/services/link-tracking/ClickEvent.js +25 -0
- package/core/server/services/link-tracking/FullPostLink.js +36 -0
- package/core/server/services/link-tracking/LinkClickRepository.js +1 -1
- package/core/server/services/link-tracking/LinkClickTrackingService.js +237 -0
- package/core/server/services/link-tracking/PostLink.js +29 -0
- package/core/server/services/link-tracking/PostLinkRepository.js +2 -2
- package/core/server/services/link-tracking/index.js +1 -1
- package/core/server/services/members-events/EventStorage.js +61 -0
- package/core/server/services/members-events/LastSeenAtCache.js +96 -0
- package/core/server/services/members-events/LastSeenAtUpdater.js +192 -0
- package/core/server/services/members-events/index.js +3 -1
- package/core/server/services/mentions-email-report/MentionEmailReportJob.js +117 -0
- package/core/server/services/mentions-email-report/service.js +3 -3
- package/core/server/services/staff/StaffService.js +179 -0
- package/core/server/services/staff/StaffServiceEmails.js +527 -0
- package/core/server/services/staff/email-templates/donation.hbs +119 -0
- package/core/server/services/staff/email-templates/donation.txt.js +15 -0
- package/core/server/services/staff/email-templates/mention-report.hbs +136 -0
- package/core/server/services/staff/email-templates/mention-report.txt.js +19 -0
- package/core/server/services/staff/email-templates/new-free-signup.hbs +118 -0
- package/core/server/services/staff/email-templates/new-free-signup.txt.js +13 -0
- package/core/server/services/staff/email-templates/new-milestone-received.hbs +142 -0
- package/core/server/services/staff/email-templates/new-milestone-received.txt.js +13 -0
- package/core/server/services/staff/email-templates/new-paid-cancellation.hbs +125 -0
- package/core/server/services/staff/email-templates/new-paid-cancellation.txt.js +13 -0
- package/core/server/services/staff/email-templates/new-paid-started.hbs +124 -0
- package/core/server/services/staff/email-templates/new-paid-started.txt.js +13 -0
- package/core/server/services/staff/email-templates/partials/preview.hbs +6 -0
- package/core/server/services/staff/email-templates/partials/styles.hbs +114 -0
- package/core/server/services/staff/email-templates/recommendation-received.hbs +154 -0
- package/core/server/services/staff/email-templates/recommendation-received.txt.js +13 -0
- package/core/server/services/staff/index.js +1 -1
- package/core/server/services/staff/milestone-email-config.js +207 -0
- package/core/server/services/stats/MembersStatsService.js +167 -0
- package/core/server/services/stats/MrrStatsService.js +161 -0
- package/core/server/services/stats/ReferrersStatsService.js +164 -0
- package/core/server/services/stats/StatsService.js +63 -0
- package/core/server/services/stats/SubscriptionStatsService.js +180 -0
- package/core/server/services/stats/service.js +1 -1
- package/core/server/services/url/Resources.js +2 -2
- package/core/shared/config/defaults.json +2 -1
- package/core/shared/events/URLResourceUpdatedEvent.js +33 -0
- package/core/shared/settings-cache/public.js +1 -0
- package/package.json +155 -158
- package/tsconfig.json +105 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/yarn.lock +347 -136
- package/components/tryghost-activitypub-5.110.4.tgz +0 -0
- package/components/tryghost-adapter-cache-memory-ttl-5.110.4.tgz +0 -0
- package/components/tryghost-adapter-cache-redis-5.110.4.tgz +0 -0
- package/components/tryghost-announcement-bar-settings-5.110.4.tgz +0 -0
- package/components/tryghost-api-version-compatibility-service-5.110.4.tgz +0 -0
- package/components/tryghost-bookshelf-repository-5.110.4.tgz +0 -0
- package/components/tryghost-bootstrap-socket-5.110.4.tgz +0 -0
- package/components/tryghost-captcha-service-5.110.4.tgz +0 -0
- package/components/tryghost-constants-5.110.4.tgz +0 -0
- package/components/tryghost-custom-fonts-5.110.4.tgz +0 -0
- package/components/tryghost-donations-5.110.4.tgz +0 -0
- package/components/tryghost-dynamic-routing-events-5.110.4.tgz +0 -0
- package/components/tryghost-email-addresses-5.110.4.tgz +0 -0
- package/components/tryghost-email-analytics-provider-mailgun-5.110.4.tgz +0 -0
- package/components/tryghost-email-content-generator-5.110.4.tgz +0 -0
- package/components/tryghost-email-events-5.110.4.tgz +0 -0
- package/components/tryghost-email-service-5.110.4.tgz +0 -0
- package/components/tryghost-email-suppression-list-5.110.4.tgz +0 -0
- package/components/tryghost-extract-api-key-5.110.4.tgz +0 -0
- package/components/tryghost-ghost-5.110.4.tgz +0 -0
- package/components/tryghost-i18n-5.110.4.tgz +0 -0
- package/components/tryghost-identity-token-service-5.110.4.tgz +0 -0
- package/components/tryghost-importer-handler-content-files-5.110.4.tgz +0 -0
- package/components/tryghost-in-memory-repository-5.110.4.tgz +0 -0
- package/components/tryghost-link-replacer-5.110.4.tgz +0 -0
- package/components/tryghost-link-tracking-5.110.4.tgz +0 -0
- package/components/tryghost-mail-events-5.110.4.tgz +0 -0
- package/components/tryghost-mailgun-client-5.110.4.tgz +0 -0
- package/components/tryghost-members-events-service-5.110.4.tgz +0 -0
- package/components/tryghost-mentions-email-report-5.110.4.tgz +0 -0
- package/components/tryghost-minifier-5.110.4.tgz +0 -0
- package/components/tryghost-mw-api-version-mismatch-5.110.4.tgz +0 -0
- package/components/tryghost-mw-error-handler-5.110.4.tgz +0 -0
- package/components/tryghost-mw-version-match-5.110.4.tgz +0 -0
- package/components/tryghost-mw-vhost-5.110.4.tgz +0 -0
- package/components/tryghost-package-json-5.110.4.tgz +0 -0
- package/components/tryghost-prometheus-metrics-5.110.4.tgz +0 -0
- package/components/tryghost-recommendations-5.110.4.tgz +0 -0
- package/components/tryghost-referrers-5.110.4.tgz +0 -0
- package/components/tryghost-session-service-5.110.4.tgz +0 -0
- package/components/tryghost-settings-path-manager-5.110.4.tgz +0 -0
- package/components/tryghost-staff-service-5.110.4.tgz +0 -0
- package/components/tryghost-stats-service-5.110.4.tgz +0 -0
- package/components/tryghost-tiers-5.110.4.tgz +0 -0
- package/components/tryghost-version-notifications-data-service-5.110.4.tgz +0 -0
- package/components/tryghost-webmentions-5.110.4.tgz +0 -0
|
@@ -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.112%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%225ea6a6e0ae%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%2215e68d0314%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%22b89b845936%22%2C%22adminXActivitypubFilename%22%3A%22admin-x-activitypub.js%22%2C%22adminXActivitypubHash%22%3A%228b10f84a3e%22%2C%22postsFilename%22%3A%22posts.js%22%2C%22postsHash%22%3A%22cb54d87657%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-fca15534b8426c0567400113c63a3e21.js"></script>
|
|
60
60
|
<script src="assets/chunk.874.461cb3cf5b6b36915f8c.js"></script>
|
|
61
|
-
<script src="assets/chunk.524.
|
|
62
|
-
<script src="assets/ghost-
|
|
61
|
+
<script src="assets/chunk.524.db49da6fd8ae155205a4.js"></script>
|
|
62
|
+
<script src="assets/ghost-62bd4d4c837d453e1038808dc1cd1e4c.js"></script>
|
|
63
63
|
</body>
|
|
64
64
|
</html>
|
|
@@ -338,11 +338,10 @@ module.exports = async function get(resource, options) {
|
|
|
338
338
|
errorDetails: {
|
|
339
339
|
api: `${controllerName}.${action}`,
|
|
340
340
|
apiOptions,
|
|
341
|
+
time: totalMs,
|
|
341
342
|
returnedRows: returnedRowsCount
|
|
342
343
|
}
|
|
343
|
-
})
|
|
344
|
-
time: totalMs
|
|
345
|
-
});
|
|
344
|
+
}));
|
|
346
345
|
}
|
|
347
346
|
}
|
|
348
347
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const DomainEvents = require('@tryghost/domain-events');
|
|
2
|
-
const
|
|
2
|
+
const URLResourceUpdatedEvent = require('../../../shared/events/URLResourceUpdatedEvent');
|
|
3
3
|
const IndexMapGenerator = require('./SiteMapIndexGenerator');
|
|
4
4
|
const PagesMapGenerator = require('./PageMapGenerator');
|
|
5
5
|
const PostsMapGenerator = require('./PostMapGenerator');
|
|
@@ -42,31 +42,38 @@
|
|
|
42
42
|
background: rgba(135, 85, 236, 0.12);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
.kg-cta-sponsor-label {
|
|
46
|
-
margin: 0
|
|
47
|
-
padding:
|
|
45
|
+
.kg-cta-sponsor-label-wrapper {
|
|
46
|
+
margin: 0 1.5em;
|
|
47
|
+
padding: .7em 0;
|
|
48
48
|
border-bottom: 1px solid rgba(124, 139, 154, 0.2);
|
|
49
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
50
|
-
font-size: 12px;
|
|
51
|
-
font-weight: 600;
|
|
52
|
-
text-transform: uppercase;
|
|
53
|
-
text-wrap: pretty;
|
|
54
49
|
}
|
|
55
50
|
|
|
56
51
|
@media (max-width: 600px) {
|
|
57
|
-
.kg-cta-sponsor-label {
|
|
58
|
-
margin: 0
|
|
59
|
-
padding:
|
|
52
|
+
.kg-cta-sponsor-label-wrapper {
|
|
53
|
+
margin: 0 1.25em;
|
|
54
|
+
padding: .5em 0;
|
|
60
55
|
}
|
|
61
56
|
}
|
|
62
57
|
|
|
63
|
-
.kg-cta-bg-none .kg-cta-sponsor-label {
|
|
58
|
+
.kg-cta-bg-none .kg-cta-sponsor-label-wrapper {
|
|
64
59
|
margin: 0;
|
|
60
|
+
padding-top: 0;
|
|
65
61
|
}
|
|
66
62
|
|
|
63
|
+
.kg-cta-has-img .kg-cta-sponsor-label-wrapper:not(.kg-cta-bg-none .kg-cta-sponsor-label-wrapper):not(.kg-cta-minimal .kg-cta-sponsor-label-wrapper) {
|
|
64
|
+
border-bottom: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.kg-cta-sponsor-label {
|
|
68
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
69
|
+
font-size: 12px;
|
|
70
|
+
font-weight: 600;
|
|
71
|
+
text-transform: uppercase;
|
|
72
|
+
text-wrap: pretty;
|
|
73
|
+
}
|
|
67
74
|
|
|
68
75
|
.kg-cta-sponsor-label p span:not(a span) {
|
|
69
|
-
color: color-mix(in srgb, currentColor
|
|
76
|
+
color: color-mix(in srgb, currentColor 45%, transparent);
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
.kg-cta-sponsor-label a {
|
|
@@ -75,29 +82,33 @@
|
|
|
75
82
|
|
|
76
83
|
.kg-cta-content {
|
|
77
84
|
display: flex;
|
|
78
|
-
padding:
|
|
79
|
-
gap:
|
|
85
|
+
padding: 1.5em;
|
|
86
|
+
gap: 1.5em;
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
@media (max-width: 600px) {
|
|
83
90
|
.kg-cta-content {
|
|
84
|
-
padding:
|
|
85
|
-
gap:
|
|
91
|
+
padding: 1.25em;
|
|
92
|
+
gap: 1.25em;
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
|
|
96
|
+
.kg-cta-has-img .kg-cta-sponsor-label-wrapper + .kg-cta-content:not(.kg-cta-bg-none .kg-cta-content):not(.kg-cta-minimal .kg-cta-content) {
|
|
97
|
+
padding-top: 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
89
100
|
.kg-cta-bg-none .kg-cta-content {
|
|
90
|
-
padding:
|
|
101
|
+
padding: 1.5em 0;
|
|
91
102
|
border-bottom: 1px solid rgba(124, 139, 154, 0.2);
|
|
92
103
|
}
|
|
93
104
|
|
|
94
|
-
.kg-cta-bg-none .kg-cta-content:not(.kg-cta-sponsor-label + .kg-cta-content) {
|
|
105
|
+
.kg-cta-bg-none .kg-cta-content:not(.kg-cta-sponsor-label-wrapper + .kg-cta-content) {
|
|
95
106
|
border-top: 1px solid rgba(124, 139, 154, 0.2);
|
|
96
107
|
}
|
|
97
108
|
|
|
98
109
|
@media (max-width: 600px) {
|
|
99
110
|
.kg-cta-bg-none .kg-cta-content {
|
|
100
|
-
padding:
|
|
111
|
+
padding: 1.25em 0;
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
|
|
@@ -119,12 +130,12 @@
|
|
|
119
130
|
.kg-cta-content-inner {
|
|
120
131
|
display: flex;
|
|
121
132
|
flex-direction: column;
|
|
122
|
-
gap:
|
|
133
|
+
gap: 1.5em;
|
|
123
134
|
}
|
|
124
135
|
|
|
125
136
|
@media (max-width: 600px) {
|
|
126
137
|
.kg-cta-content-inner {
|
|
127
|
-
gap:
|
|
138
|
+
gap: 1.25em;
|
|
128
139
|
}
|
|
129
140
|
}
|
|
130
141
|
|
|
@@ -133,6 +144,7 @@
|
|
|
133
144
|
}
|
|
134
145
|
|
|
135
146
|
.kg-cta-image-container img {
|
|
147
|
+
margin: 0;
|
|
136
148
|
object-fit: cover;
|
|
137
149
|
border-radius: 6px;
|
|
138
150
|
}
|
|
@@ -150,16 +162,13 @@
|
|
|
150
162
|
}
|
|
151
163
|
}
|
|
152
164
|
|
|
153
|
-
.kg-cta-immersive .kg-cta-text {
|
|
154
|
-
text-align: center;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
165
|
.kg-cta-text p {
|
|
166
|
+
margin: 0;
|
|
158
167
|
text-wrap: pretty;
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
.kg-cta-text p + p {
|
|
162
|
-
margin-top:
|
|
171
|
+
margin-top: 1.25em;
|
|
163
172
|
}
|
|
164
173
|
|
|
165
174
|
.kg-cta-text a {
|
|
@@ -170,12 +179,13 @@ a.kg-cta-button {
|
|
|
170
179
|
display: flex;
|
|
171
180
|
position: static;
|
|
172
181
|
align-items: center;
|
|
173
|
-
padding: 0 2rem;
|
|
174
|
-
height: 2.4em;
|
|
175
182
|
justify-content: center;
|
|
183
|
+
padding: 0 1em;
|
|
184
|
+
height: 2.5em;
|
|
176
185
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
|
177
186
|
font-size: 0.95em;
|
|
178
|
-
font-weight:
|
|
187
|
+
font-weight: 500;
|
|
188
|
+
line-height: 1.65;
|
|
179
189
|
text-decoration: none;
|
|
180
190
|
border-radius: 6px;
|
|
181
191
|
transition: opacity 0.2s ease-in-out;
|
|
@@ -7,11 +7,12 @@ const labs = require('../../../shared/labs');
|
|
|
7
7
|
const getCaptchaSettings = () => {
|
|
8
8
|
if (labs.isSet('captcha')) {
|
|
9
9
|
return {
|
|
10
|
-
captcha_enabled: config.get('captcha:enabled'),
|
|
11
10
|
captcha_sitekey: config.get('captcha:siteKey')
|
|
12
11
|
};
|
|
13
12
|
} else {
|
|
14
|
-
return {
|
|
13
|
+
return {
|
|
14
|
+
captcha_enabled: false
|
|
15
|
+
};
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
18
|
|
|
@@ -319,6 +319,14 @@
|
|
|
319
319
|
"blocked_email_domains": {
|
|
320
320
|
"defaultValue": "[]",
|
|
321
321
|
"type": "array"
|
|
322
|
+
},
|
|
323
|
+
"captcha_enabled": {
|
|
324
|
+
"defaultValue": "false",
|
|
325
|
+
"validations": {
|
|
326
|
+
"isEmpty": false,
|
|
327
|
+
"isIn": [["true", "false"]]
|
|
328
|
+
},
|
|
329
|
+
"type": "boolean"
|
|
322
330
|
}
|
|
323
331
|
},
|
|
324
332
|
"portal": {
|
|
@@ -595,5 +603,11 @@
|
|
|
595
603
|
},
|
|
596
604
|
"type": "boolean"
|
|
597
605
|
}
|
|
606
|
+
},
|
|
607
|
+
"security": {
|
|
608
|
+
"require_email_mfa": {
|
|
609
|
+
"defaultValue": false,
|
|
610
|
+
"type": "boolean"
|
|
611
|
+
}
|
|
598
612
|
}
|
|
599
613
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const _ = require('lodash');
|
|
2
1
|
const tpl = require('@tryghost/tpl');
|
|
3
2
|
const errors = require('@tryghost/errors');
|
|
4
3
|
const constants = require('@tryghost/constants');
|
|
@@ -6,7 +5,7 @@ const security = require('@tryghost/security');
|
|
|
6
5
|
const settingsCache = require('../../shared/settings-cache');
|
|
7
6
|
const limitService = require('../services/limits');
|
|
8
7
|
const ghostBookshelf = require('./base');
|
|
9
|
-
|
|
8
|
+
const {setIsRoles} = require('./role-utils');
|
|
10
9
|
const messages = {
|
|
11
10
|
notEnoughPermission: 'You do not have permission to perform this action',
|
|
12
11
|
roleNotFound: 'Role not found',
|
|
@@ -86,10 +85,10 @@ Invite = ghostBookshelf.Model.extend({
|
|
|
86
85
|
|
|
87
86
|
let allowed = [];
|
|
88
87
|
if (loadedPermissions.user) {
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
const {isOwner, isAdmin, isEitherEditor} = setIsRoles(loadedPermissions);
|
|
89
|
+
if (isOwner || isAdmin) {
|
|
91
90
|
allowed = ['Administrator', 'Editor', 'Author', 'Contributor'];
|
|
92
|
-
} else if (
|
|
91
|
+
} else if (isEitherEditor) {
|
|
93
92
|
allowed = ['Author', 'Contributor'];
|
|
94
93
|
}
|
|
95
94
|
} else if (loadedPermissions.apiKey) {
|
|
@@ -21,6 +21,7 @@ const {BadRequestError} = require('@tryghost/errors');
|
|
|
21
21
|
const {PostRevisions} = require('@tryghost/post-revisions');
|
|
22
22
|
const {mobiledocToLexical} = require('@tryghost/kg-converters');
|
|
23
23
|
const labs = require('../../shared/labs');
|
|
24
|
+
const {setIsRoles} = require('./role-utils');
|
|
24
25
|
|
|
25
26
|
const messages = {
|
|
26
27
|
isAlreadyPublished: 'Your post is already published, please reload your page.',
|
|
@@ -1478,10 +1479,7 @@ Post = ghostBookshelf.Model.extend({
|
|
|
1478
1479
|
|
|
1479
1480
|
// NOTE: the `authors` extension is the parent of the post model. It also has a permissible function.
|
|
1480
1481
|
permissible: async function permissible(postModel, action, context, unsafeAttrs, loadedPermissions, hasUserPermission, hasApiKeyPermission) {
|
|
1481
|
-
let isContributor;
|
|
1482
|
-
let isOwner;
|
|
1483
|
-
let isAdmin;
|
|
1484
|
-
let isEditor;
|
|
1482
|
+
let {isContributor, isOwner, isAdmin, isEitherEditor} = setIsRoles(loadedPermissions);
|
|
1485
1483
|
let isIntegration;
|
|
1486
1484
|
let isEdit;
|
|
1487
1485
|
let isAdd;
|
|
@@ -1499,10 +1497,6 @@ Post = ghostBookshelf.Model.extend({
|
|
|
1499
1497
|
return postModel.get('status') === 'draft';
|
|
1500
1498
|
}
|
|
1501
1499
|
|
|
1502
|
-
isContributor = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Contributor'});
|
|
1503
|
-
isOwner = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Owner'});
|
|
1504
|
-
isAdmin = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Administrator'});
|
|
1505
|
-
isEditor = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Editor'});
|
|
1506
1500
|
isIntegration = loadedPermissions.apiKey && _.some(loadedPermissions.apiKey.roles, {name: 'Admin Integration'});
|
|
1507
1501
|
|
|
1508
1502
|
isEdit = (action === 'edit');
|
|
@@ -1525,7 +1519,7 @@ Post = ghostBookshelf.Model.extend({
|
|
|
1525
1519
|
} else if (isContributor && isDestroy) {
|
|
1526
1520
|
// If destroying, only allow contributor to destroy their own draft posts
|
|
1527
1521
|
hasUserPermission = isDraft();
|
|
1528
|
-
} else if (!(isOwner || isAdmin ||
|
|
1522
|
+
} else if (!(isOwner || isAdmin || isEitherEditor || isIntegration)) {
|
|
1529
1523
|
hasUserPermission = !isChanging('visibility');
|
|
1530
1524
|
}
|
|
1531
1525
|
|
|
@@ -2,6 +2,7 @@ const _ = require('lodash');
|
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
3
|
const errors = require('@tryghost/errors');
|
|
4
4
|
const {sequence} = require('@tryghost/promise');
|
|
5
|
+
const {setIsRoles} = require('../role-utils');
|
|
5
6
|
|
|
6
7
|
const messages = {
|
|
7
8
|
noUserFound: 'No user found',
|
|
@@ -305,8 +306,7 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
|
|
|
305
306
|
const self = this;
|
|
306
307
|
const postModel = postModelOrId;
|
|
307
308
|
let origArgs;
|
|
308
|
-
|
|
309
|
-
let isAuthor;
|
|
309
|
+
const {isContributor, isAuthor} = setIsRoles(loadedPermissions);
|
|
310
310
|
let isEdit;
|
|
311
311
|
let isAdd;
|
|
312
312
|
let isDestroy;
|
|
@@ -332,8 +332,6 @@ module.exports.extendModel = function extendModel(Post, Posts, ghostBookshelf) {
|
|
|
332
332
|
});
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
isContributor = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Contributor'});
|
|
336
|
-
isAuthor = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Author'});
|
|
337
335
|
isEdit = (action === 'edit');
|
|
338
336
|
isAdd = (action === 'add');
|
|
339
337
|
isDestroy = (action === 'destroy');
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// check if the user has an assigned role
|
|
2
|
+
// so that we can stop writing this everywhere:
|
|
3
|
+
//_.some(loadedPermissions.user.roles, {name: 'Administrator'})
|
|
4
|
+
|
|
5
|
+
function checkUserPermissionsForRole(loadedPermissions, roleName) {
|
|
6
|
+
if (!loadedPermissions?.user?.roles) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return loadedPermissions.user.roles.some(role => role.name === roleName);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function setIsRoles(loadedPermissions) {
|
|
14
|
+
// utility function to parse the permissions object and set up all the "is" variables.
|
|
15
|
+
let resultsObject = {
|
|
16
|
+
isOwner: false,
|
|
17
|
+
isAdmin: false,
|
|
18
|
+
isEditor: false,
|
|
19
|
+
isAuthor: false,
|
|
20
|
+
isContributor: false,
|
|
21
|
+
isSuperEditor: false,
|
|
22
|
+
isEitherEditor: false
|
|
23
|
+
};
|
|
24
|
+
if (!loadedPermissions?.user?.roles) {
|
|
25
|
+
return resultsObject;
|
|
26
|
+
}
|
|
27
|
+
resultsObject.isOwner = checkUserPermissionsForRole(loadedPermissions, 'Owner');
|
|
28
|
+
resultsObject.isAdmin = checkUserPermissionsForRole(loadedPermissions, 'Administrator');
|
|
29
|
+
resultsObject.isEditor = checkUserPermissionsForRole(loadedPermissions, 'Editor');
|
|
30
|
+
resultsObject.isAuthor = checkUserPermissionsForRole(loadedPermissions, 'Author');
|
|
31
|
+
resultsObject.isContributor = checkUserPermissionsForRole(loadedPermissions, 'Contributor');
|
|
32
|
+
resultsObject.isSuperEditor = checkUserPermissionsForRole(loadedPermissions, 'Super Editor');
|
|
33
|
+
resultsObject.isEitherEditor = resultsObject.isEditor || resultsObject.isSuperEditor;
|
|
34
|
+
return resultsObject;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.setIsRoles = setIsRoles;
|
|
38
|
+
exports.checkUserPermissionsForRole = checkUserPermissionsForRole;
|
|
@@ -2,6 +2,7 @@ const _ = require('lodash');
|
|
|
2
2
|
const ghostBookshelf = require('./base');
|
|
3
3
|
const tpl = require('@tryghost/tpl');
|
|
4
4
|
const errors = require('@tryghost/errors');
|
|
5
|
+
const {setIsRoles} = require('./role-utils');
|
|
5
6
|
|
|
6
7
|
const messages = {
|
|
7
8
|
roleNotFound: 'Role not found',
|
|
@@ -78,12 +79,13 @@ Role = ghostBookshelf.Model.extend({
|
|
|
78
79
|
const roleModel = roleModelOrId;
|
|
79
80
|
|
|
80
81
|
if (action === 'assign' && loadedPermissions.user) {
|
|
82
|
+
const {isOwner, isAdmin, isEitherEditor} = setIsRoles(loadedPermissions);
|
|
81
83
|
let checkAgainst;
|
|
82
|
-
if (
|
|
84
|
+
if (isOwner) {
|
|
83
85
|
checkAgainst = ['Owner', 'Administrator', 'Editor', 'Author', 'Contributor'];
|
|
84
|
-
} else if (
|
|
86
|
+
} else if (isAdmin) {
|
|
85
87
|
checkAgainst = ['Administrator', 'Editor', 'Author', 'Contributor'];
|
|
86
|
-
} else if (
|
|
88
|
+
} else if (isEitherEditor) {
|
|
87
89
|
checkAgainst = ['Author', 'Contributor'];
|
|
88
90
|
}
|
|
89
91
|
|
|
@@ -13,6 +13,7 @@ const permissions = require('../services/permissions');
|
|
|
13
13
|
const urlUtils = require('../../shared/url-utils');
|
|
14
14
|
const activeStates = ['active', 'warn-1', 'warn-2', 'warn-3', 'warn-4'];
|
|
15
15
|
const ASSIGNABLE_ROLES = ['Administrator', 'Editor', 'Author', 'Contributor'];
|
|
16
|
+
const {setIsRoles} = require('./role-utils');
|
|
16
17
|
|
|
17
18
|
const messages = {
|
|
18
19
|
valueCannotBeBlank: 'Value in [{tableName}.{columnKey}] cannot be blank.',
|
|
@@ -784,6 +785,7 @@ User = ghostBookshelf.Model.extend({
|
|
|
784
785
|
const self = this;
|
|
785
786
|
const userModel = userModelOrId;
|
|
786
787
|
let origArgs;
|
|
788
|
+
const {isOwner, isEitherEditor} = setIsRoles(loadedPermissions);
|
|
787
789
|
|
|
788
790
|
// If we passed in a model without its related roles, we need to fetch it again
|
|
789
791
|
if (_.isObject(userModelOrId) && !_.isObject(userModelOrId.related('roles'))) {
|
|
@@ -826,10 +828,10 @@ User = ghostBookshelf.Model.extend({
|
|
|
826
828
|
if (context.user === userModel.get('id')) {
|
|
827
829
|
// If this is the same user that requests the operation allow it.
|
|
828
830
|
hasUserPermission = true;
|
|
829
|
-
} else if (
|
|
831
|
+
} else if (isOwner) {
|
|
830
832
|
// Owner can only be edited by owner
|
|
831
833
|
hasUserPermission = loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Owner'});
|
|
832
|
-
} else if (
|
|
834
|
+
} else if (isEitherEditor) {
|
|
833
835
|
// If the user we are trying to edit is an Author or Contributor, allow it
|
|
834
836
|
hasUserPermission = userModel.hasRole('Author') || userModel.hasRole('Contributor');
|
|
835
837
|
}
|
|
@@ -844,7 +846,7 @@ User = ghostBookshelf.Model.extend({
|
|
|
844
846
|
}
|
|
845
847
|
|
|
846
848
|
// Users with the role 'Editor' have complex permissions when the action === 'destroy'
|
|
847
|
-
if (
|
|
849
|
+
if (isEitherEditor) {
|
|
848
850
|
// Alternatively, if the user we are trying to edit is an Author, allow it
|
|
849
851
|
hasUserPermission = context.user === userModel.get('id') || userModel.hasRole('Author') || userModel.hasRole('Contributor');
|
|
850
852
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ActivityPubService = void 0;
|
|
7
|
+
const bson_objectid_1 = __importDefault(require("bson-objectid"));
|
|
8
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
|
+
class ActivityPubService {
|
|
10
|
+
knex;
|
|
11
|
+
siteUrl;
|
|
12
|
+
logging;
|
|
13
|
+
identityTokenService;
|
|
14
|
+
constructor(knex, siteUrl, logging, identityTokenService) {
|
|
15
|
+
this.knex = knex;
|
|
16
|
+
this.siteUrl = siteUrl;
|
|
17
|
+
this.logging = logging;
|
|
18
|
+
this.identityTokenService = identityTokenService;
|
|
19
|
+
}
|
|
20
|
+
getExpectedWebhooks(secret) {
|
|
21
|
+
return [{
|
|
22
|
+
event: 'post.published',
|
|
23
|
+
target_url: new URL('.ghost/activitypub/webhooks/post/published', this.siteUrl),
|
|
24
|
+
api_version: 'v5.100.0',
|
|
25
|
+
secret
|
|
26
|
+
}, {
|
|
27
|
+
event: 'site.changed',
|
|
28
|
+
target_url: new URL('.ghost/activitypub/webhooks/site/changed', this.siteUrl),
|
|
29
|
+
api_version: 'v5.100.0',
|
|
30
|
+
secret
|
|
31
|
+
}];
|
|
32
|
+
}
|
|
33
|
+
async checkWebhookState(expectedWebhooks, integration) {
|
|
34
|
+
this.logging.info(`Checking ActivityPub Webhook state`);
|
|
35
|
+
const webhooks = await this.knex
|
|
36
|
+
.select('*')
|
|
37
|
+
.from('webhooks')
|
|
38
|
+
.where('integration_id', '=', integration.id);
|
|
39
|
+
if (webhooks.length !== expectedWebhooks.length) {
|
|
40
|
+
this.logging.warn(`Expected ${expectedWebhooks.length} webhooks for ActivityPub`);
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
for (const expectedWebhook of expectedWebhooks) {
|
|
44
|
+
const foundWebhook = webhooks.find((webhook) => {
|
|
45
|
+
return webhook.event === expectedWebhook.event && webhook.target_url === expectedWebhook.target_url.href && webhook.secret === expectedWebhook.secret;
|
|
46
|
+
});
|
|
47
|
+
if (!foundWebhook) {
|
|
48
|
+
this.logging.error(`Could not find webhook for ${expectedWebhook.event} ${expectedWebhook.target_url}`);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
async getWebhookSecret() {
|
|
55
|
+
try {
|
|
56
|
+
const ownerUser = await this.knex.select('*').from('users').where('id', '=', '1').first();
|
|
57
|
+
const token = await this.identityTokenService.getTokenForUser(ownerUser.email, 'Owner');
|
|
58
|
+
const res = await (0, node_fetch_1.default)(new URL('.ghost/activitypub/site', this.siteUrl), {
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization: `Bearer ${token}`
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const body = await res.json();
|
|
64
|
+
return body.webhook_secret;
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
this.logging.error(`Could not get webhook secret for ActivityPub ${err}`);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async initialiseWebhooks() {
|
|
72
|
+
const integration = await this.knex
|
|
73
|
+
.select('*')
|
|
74
|
+
.from('integrations')
|
|
75
|
+
.where('slug', '=', 'ghost-activitypub')
|
|
76
|
+
.andWhere('type', '=', 'internal')
|
|
77
|
+
.first();
|
|
78
|
+
if (!integration) {
|
|
79
|
+
this.logging.error('No ActivityPub integration found - cannot initialise');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const secret = await this.getWebhookSecret();
|
|
83
|
+
if (!secret) {
|
|
84
|
+
this.logging.error('No webhook secret found - cannot initialise');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const expectedWebhooks = this.getExpectedWebhooks(secret);
|
|
88
|
+
const isInCorrectState = await this.checkWebhookState(expectedWebhooks, integration);
|
|
89
|
+
if (isInCorrectState) {
|
|
90
|
+
this.logging.info(`ActivityPub webhooks in correct state`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.logging.info(`ActivityPub webhooks in incorrect state, deleting all of them and starting fresh`);
|
|
94
|
+
await this.knex
|
|
95
|
+
.del()
|
|
96
|
+
.from('webhooks')
|
|
97
|
+
.where('integration_id', '=', integration.id);
|
|
98
|
+
const webhooksToInsert = expectedWebhooks.map((expectedWebhook) => {
|
|
99
|
+
return {
|
|
100
|
+
id: (new bson_objectid_1.default).toHexString(),
|
|
101
|
+
event: expectedWebhook.event,
|
|
102
|
+
target_url: expectedWebhook.target_url.href,
|
|
103
|
+
api_version: expectedWebhook.api_version,
|
|
104
|
+
name: `ActivityPub ${expectedWebhook.event} Webhook`,
|
|
105
|
+
secret: secret,
|
|
106
|
+
integration_id: integration.id,
|
|
107
|
+
created_at: this.knex.raw('current_timestamp'),
|
|
108
|
+
created_by: '1'
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
await this.knex
|
|
112
|
+
.insert(webhooksToInsert)
|
|
113
|
+
.into('webhooks');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.ActivityPubService = ActivityPubService;
|