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.
Files changed (202) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.112.0.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.112.0.tgz +0 -0
  3. package/components/{tryghost-adapter-manager-5.110.4.tgz → tryghost-adapter-manager-5.112.0.tgz} +0 -0
  4. package/components/tryghost-announcement-bar-settings-5.112.0.tgz +0 -0
  5. package/components/{tryghost-api-framework-5.110.4.tgz → tryghost-api-framework-5.112.0.tgz} +0 -0
  6. package/components/tryghost-api-version-compatibility-service-5.112.0.tgz +0 -0
  7. package/components/{tryghost-audience-feedback-5.110.4.tgz → tryghost-audience-feedback-5.112.0.tgz} +0 -0
  8. package/components/tryghost-bookshelf-repository-5.112.0.tgz +0 -0
  9. package/components/tryghost-bootstrap-socket-5.112.0.tgz +0 -0
  10. package/components/tryghost-captcha-service-5.112.0.tgz +0 -0
  11. package/components/tryghost-constants-5.112.0.tgz +0 -0
  12. package/components/tryghost-custom-fonts-5.112.0.tgz +0 -0
  13. package/components/{tryghost-custom-theme-settings-service-5.110.4.tgz → tryghost-custom-theme-settings-service-5.112.0.tgz} +0 -0
  14. package/components/{tryghost-data-generator-5.110.4.tgz → tryghost-data-generator-5.112.0.tgz} +0 -0
  15. package/components/{tryghost-domain-events-5.110.4.tgz → tryghost-domain-events-5.112.0.tgz} +0 -0
  16. package/components/tryghost-donations-5.112.0.tgz +0 -0
  17. package/components/tryghost-email-addresses-5.112.0.tgz +0 -0
  18. package/components/tryghost-email-analytics-provider-mailgun-5.112.0.tgz +0 -0
  19. package/components/{tryghost-email-analytics-service-5.110.4.tgz → tryghost-email-analytics-service-5.112.0.tgz} +0 -0
  20. package/components/tryghost-email-content-generator-5.112.0.tgz +0 -0
  21. package/components/tryghost-email-events-5.112.0.tgz +0 -0
  22. package/components/tryghost-email-service-5.112.0.tgz +0 -0
  23. package/components/tryghost-email-suppression-list-5.112.0.tgz +0 -0
  24. package/components/{tryghost-express-dynamic-redirects-5.110.4.tgz → tryghost-express-dynamic-redirects-5.112.0.tgz} +0 -0
  25. package/components/{tryghost-external-media-inliner-5.110.4.tgz → tryghost-external-media-inliner-5.112.0.tgz} +0 -0
  26. package/components/tryghost-extract-api-key-5.112.0.tgz +0 -0
  27. package/components/tryghost-ghost-5.112.0.tgz +0 -0
  28. package/components/{tryghost-html-to-plaintext-5.110.4.tgz → tryghost-html-to-plaintext-5.112.0.tgz} +0 -0
  29. package/components/tryghost-i18n-5.112.0.tgz +0 -0
  30. package/components/tryghost-identity-token-service-5.112.0.tgz +0 -0
  31. package/components/tryghost-importer-handler-content-files-5.112.0.tgz +0 -0
  32. package/components/{tryghost-importer-revue-5.110.4.tgz → tryghost-importer-revue-5.112.0.tgz} +0 -0
  33. package/components/tryghost-in-memory-repository-5.112.0.tgz +0 -0
  34. package/components/{tryghost-job-manager-5.110.4.tgz → tryghost-job-manager-5.112.0.tgz} +0 -0
  35. package/components/{tryghost-link-redirects-5.110.4.tgz → tryghost-link-redirects-5.112.0.tgz} +0 -0
  36. package/components/tryghost-link-replacer-5.112.0.tgz +0 -0
  37. package/components/{tryghost-magic-link-5.110.4.tgz → tryghost-magic-link-5.112.0.tgz} +0 -0
  38. package/components/tryghost-mail-events-5.112.0.tgz +0 -0
  39. package/components/tryghost-mailgun-client-5.112.0.tgz +0 -0
  40. package/components/{tryghost-member-attribution-5.110.4.tgz → tryghost-member-attribution-5.112.0.tgz} +0 -0
  41. package/components/{tryghost-member-events-5.110.4.tgz → tryghost-member-events-5.112.0.tgz} +0 -0
  42. package/components/{tryghost-members-api-5.110.4.tgz → tryghost-members-api-5.112.0.tgz} +0 -0
  43. package/components/{tryghost-members-csv-5.110.4.tgz → tryghost-members-csv-5.112.0.tgz} +0 -0
  44. package/components/{tryghost-members-importer-5.110.4.tgz → tryghost-members-importer-5.112.0.tgz} +0 -0
  45. package/components/{tryghost-members-offers-5.110.4.tgz → tryghost-members-offers-5.112.0.tgz} +0 -0
  46. package/components/{tryghost-members-payments-5.110.4.tgz → tryghost-members-payments-5.112.0.tgz} +0 -0
  47. package/components/{tryghost-members-ssr-5.110.4.tgz → tryghost-members-ssr-5.112.0.tgz} +0 -0
  48. package/components/{tryghost-members-stripe-service-5.110.4.tgz → tryghost-members-stripe-service-5.112.0.tgz} +0 -0
  49. package/components/{tryghost-milestones-5.110.4.tgz → tryghost-milestones-5.112.0.tgz} +0 -0
  50. package/components/tryghost-minifier-5.112.0.tgz +0 -0
  51. package/components/tryghost-mw-api-version-mismatch-5.112.0.tgz +0 -0
  52. package/components/{tryghost-mw-cache-control-5.110.4.tgz → tryghost-mw-cache-control-5.112.0.tgz} +0 -0
  53. package/components/tryghost-mw-error-handler-5.112.0.tgz +0 -0
  54. package/components/{tryghost-mw-session-from-token-5.110.4.tgz → tryghost-mw-session-from-token-5.112.0.tgz} +0 -0
  55. package/components/{tryghost-mw-update-user-last-seen-5.110.4.tgz → tryghost-mw-update-user-last-seen-5.112.0.tgz} +0 -0
  56. package/components/tryghost-mw-version-match-5.112.0.tgz +0 -0
  57. package/components/tryghost-mw-vhost-5.112.0.tgz +0 -0
  58. package/components/tryghost-package-json-5.112.0.tgz +0 -0
  59. package/components/{tryghost-post-events-5.110.4.tgz → tryghost-post-events-5.112.0.tgz} +0 -0
  60. package/components/{tryghost-post-revisions-5.110.4.tgz → tryghost-post-revisions-5.112.0.tgz} +0 -0
  61. package/components/{tryghost-posts-service-5.110.4.tgz → tryghost-posts-service-5.112.0.tgz} +0 -0
  62. package/components/tryghost-prometheus-metrics-5.112.0.tgz +0 -0
  63. package/components/tryghost-recommendations-5.112.0.tgz +0 -0
  64. package/components/tryghost-referrers-5.112.0.tgz +0 -0
  65. package/components/{tryghost-security-5.110.4.tgz → tryghost-security-5.112.0.tgz} +0 -0
  66. package/components/tryghost-session-service-5.112.0.tgz +0 -0
  67. package/components/tryghost-settings-path-manager-5.112.0.tgz +0 -0
  68. package/components/{tryghost-slack-notifications-5.110.4.tgz → tryghost-slack-notifications-5.112.0.tgz} +0 -0
  69. package/components/tryghost-tiers-5.112.0.tgz +0 -0
  70. package/components/tryghost-version-notifications-data-service-5.112.0.tgz +0 -0
  71. package/components/tryghost-webmentions-5.112.0.tgz +0 -0
  72. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +12799 -10270
  73. package/core/built/admin/assets/admin-x-demo/admin-x-demo.js +2 -2
  74. package/core/built/admin/assets/admin-x-demo/{index-82e381fb.mjs → index-0040480a.mjs} +3252 -2891
  75. package/core/built/admin/assets/admin-x-demo/{modals-b20a9ede.mjs → modals-fb35c86c.mjs} +2 -2
  76. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-ea62c29b.mjs → CodeEditorView-ad8698fe.mjs} +624 -618
  77. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +3 -3
  78. package/core/built/admin/assets/admin-x-settings/{index-af8cf9cf.mjs → index-2713e469.mjs} +6892 -6469
  79. package/core/built/admin/assets/admin-x-settings/{index-4b25c788.mjs → index-463cec50.mjs} +2 -2
  80. package/core/built/admin/assets/admin-x-settings/{modals-cb2dc7b7.mjs → modals-033e8fc4.mjs} +7888 -7669
  81. package/core/built/admin/assets/{chunk.524.3096e68df5b51dacf872.js → chunk.524.db49da6fd8ae155205a4.js} +6 -6
  82. package/core/built/admin/assets/{chunk.582.e225422f90639ff30544.js → chunk.582.0bf715eb6807f7641706.js} +8 -8
  83. package/core/built/admin/assets/{ghost-98d002d50a5e01d2100b2c387a849249.js → ghost-62bd4d4c837d453e1038808dc1cd1e4c.js} +43 -42
  84. package/core/built/admin/assets/img/ap-nodes-01ee317529e6353a1c34a062c388f1e7.png +0 -0
  85. package/core/built/admin/assets/koenig-lexical/index.css +1 -1
  86. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +18314 -17680
  87. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +229 -200
  88. package/core/built/admin/assets/posts/posts.js +24137 -24156
  89. package/core/built/admin/index.html +3 -3
  90. package/core/frontend/helpers/get.js +2 -3
  91. package/core/frontend/services/sitemap/SiteMapManager.js +1 -1
  92. package/core/frontend/src/cards/css/cta.css +40 -30
  93. package/core/frontend/src/cards/css/video.css +1 -0
  94. package/core/server/api/endpoints/settings-public.js +3 -2
  95. package/core/server/api/endpoints/utils/serializers/input/settings.js +3 -1
  96. package/core/server/api/endpoints/utils/serializers/input/utils/settings-key-group-mapper.js +2 -1
  97. package/core/server/api/endpoints/utils/serializers/input/utils/settings-key-type-mapper.js +2 -1
  98. package/core/server/data/migrations/versions/5.111/2025-03-05-16-36-39-add-captcha-setting.js +8 -0
  99. package/core/server/data/migrations/versions/5.112/2025-03-10-10-01-01-add-require-mfa-setting.js +8 -0
  100. package/core/server/data/schema/default-settings/default-settings.json +14 -0
  101. package/core/server/models/invite.js +4 -5
  102. package/core/server/models/post.js +3 -9
  103. package/core/server/models/relations/authors.js +2 -4
  104. package/core/server/models/role-utils.js +38 -0
  105. package/core/server/models/role.js +5 -3
  106. package/core/server/models/user.js +5 -3
  107. package/core/server/services/activitypub/ActivityPubService.js +116 -0
  108. package/core/server/services/activitypub/ActivityPubService.ts +139 -0
  109. package/core/server/services/activitypub/ActivityPubServiceWrapper.js +1 -1
  110. package/core/server/services/link-tracking/ClickEvent.js +25 -0
  111. package/core/server/services/link-tracking/FullPostLink.js +36 -0
  112. package/core/server/services/link-tracking/LinkClickRepository.js +1 -1
  113. package/core/server/services/link-tracking/LinkClickTrackingService.js +237 -0
  114. package/core/server/services/link-tracking/PostLink.js +29 -0
  115. package/core/server/services/link-tracking/PostLinkRepository.js +2 -2
  116. package/core/server/services/link-tracking/index.js +1 -1
  117. package/core/server/services/members-events/EventStorage.js +61 -0
  118. package/core/server/services/members-events/LastSeenAtCache.js +96 -0
  119. package/core/server/services/members-events/LastSeenAtUpdater.js +192 -0
  120. package/core/server/services/members-events/index.js +3 -1
  121. package/core/server/services/mentions-email-report/MentionEmailReportJob.js +117 -0
  122. package/core/server/services/mentions-email-report/service.js +3 -3
  123. package/core/server/services/staff/StaffService.js +179 -0
  124. package/core/server/services/staff/StaffServiceEmails.js +527 -0
  125. package/core/server/services/staff/email-templates/donation.hbs +119 -0
  126. package/core/server/services/staff/email-templates/donation.txt.js +15 -0
  127. package/core/server/services/staff/email-templates/mention-report.hbs +136 -0
  128. package/core/server/services/staff/email-templates/mention-report.txt.js +19 -0
  129. package/core/server/services/staff/email-templates/new-free-signup.hbs +118 -0
  130. package/core/server/services/staff/email-templates/new-free-signup.txt.js +13 -0
  131. package/core/server/services/staff/email-templates/new-milestone-received.hbs +142 -0
  132. package/core/server/services/staff/email-templates/new-milestone-received.txt.js +13 -0
  133. package/core/server/services/staff/email-templates/new-paid-cancellation.hbs +125 -0
  134. package/core/server/services/staff/email-templates/new-paid-cancellation.txt.js +13 -0
  135. package/core/server/services/staff/email-templates/new-paid-started.hbs +124 -0
  136. package/core/server/services/staff/email-templates/new-paid-started.txt.js +13 -0
  137. package/core/server/services/staff/email-templates/partials/preview.hbs +6 -0
  138. package/core/server/services/staff/email-templates/partials/styles.hbs +114 -0
  139. package/core/server/services/staff/email-templates/recommendation-received.hbs +154 -0
  140. package/core/server/services/staff/email-templates/recommendation-received.txt.js +13 -0
  141. package/core/server/services/staff/index.js +1 -1
  142. package/core/server/services/staff/milestone-email-config.js +207 -0
  143. package/core/server/services/stats/MembersStatsService.js +167 -0
  144. package/core/server/services/stats/MrrStatsService.js +161 -0
  145. package/core/server/services/stats/ReferrersStatsService.js +164 -0
  146. package/core/server/services/stats/StatsService.js +63 -0
  147. package/core/server/services/stats/SubscriptionStatsService.js +180 -0
  148. package/core/server/services/stats/service.js +1 -1
  149. package/core/server/services/url/Resources.js +2 -2
  150. package/core/shared/config/defaults.json +2 -1
  151. package/core/shared/events/URLResourceUpdatedEvent.js +33 -0
  152. package/core/shared/settings-cache/public.js +1 -0
  153. package/package.json +155 -158
  154. package/tsconfig.json +105 -0
  155. package/tsconfig.tsbuildinfo +1 -0
  156. package/yarn.lock +347 -136
  157. package/components/tryghost-activitypub-5.110.4.tgz +0 -0
  158. package/components/tryghost-adapter-cache-memory-ttl-5.110.4.tgz +0 -0
  159. package/components/tryghost-adapter-cache-redis-5.110.4.tgz +0 -0
  160. package/components/tryghost-announcement-bar-settings-5.110.4.tgz +0 -0
  161. package/components/tryghost-api-version-compatibility-service-5.110.4.tgz +0 -0
  162. package/components/tryghost-bookshelf-repository-5.110.4.tgz +0 -0
  163. package/components/tryghost-bootstrap-socket-5.110.4.tgz +0 -0
  164. package/components/tryghost-captcha-service-5.110.4.tgz +0 -0
  165. package/components/tryghost-constants-5.110.4.tgz +0 -0
  166. package/components/tryghost-custom-fonts-5.110.4.tgz +0 -0
  167. package/components/tryghost-donations-5.110.4.tgz +0 -0
  168. package/components/tryghost-dynamic-routing-events-5.110.4.tgz +0 -0
  169. package/components/tryghost-email-addresses-5.110.4.tgz +0 -0
  170. package/components/tryghost-email-analytics-provider-mailgun-5.110.4.tgz +0 -0
  171. package/components/tryghost-email-content-generator-5.110.4.tgz +0 -0
  172. package/components/tryghost-email-events-5.110.4.tgz +0 -0
  173. package/components/tryghost-email-service-5.110.4.tgz +0 -0
  174. package/components/tryghost-email-suppression-list-5.110.4.tgz +0 -0
  175. package/components/tryghost-extract-api-key-5.110.4.tgz +0 -0
  176. package/components/tryghost-ghost-5.110.4.tgz +0 -0
  177. package/components/tryghost-i18n-5.110.4.tgz +0 -0
  178. package/components/tryghost-identity-token-service-5.110.4.tgz +0 -0
  179. package/components/tryghost-importer-handler-content-files-5.110.4.tgz +0 -0
  180. package/components/tryghost-in-memory-repository-5.110.4.tgz +0 -0
  181. package/components/tryghost-link-replacer-5.110.4.tgz +0 -0
  182. package/components/tryghost-link-tracking-5.110.4.tgz +0 -0
  183. package/components/tryghost-mail-events-5.110.4.tgz +0 -0
  184. package/components/tryghost-mailgun-client-5.110.4.tgz +0 -0
  185. package/components/tryghost-members-events-service-5.110.4.tgz +0 -0
  186. package/components/tryghost-mentions-email-report-5.110.4.tgz +0 -0
  187. package/components/tryghost-minifier-5.110.4.tgz +0 -0
  188. package/components/tryghost-mw-api-version-mismatch-5.110.4.tgz +0 -0
  189. package/components/tryghost-mw-error-handler-5.110.4.tgz +0 -0
  190. package/components/tryghost-mw-version-match-5.110.4.tgz +0 -0
  191. package/components/tryghost-mw-vhost-5.110.4.tgz +0 -0
  192. package/components/tryghost-package-json-5.110.4.tgz +0 -0
  193. package/components/tryghost-prometheus-metrics-5.110.4.tgz +0 -0
  194. package/components/tryghost-recommendations-5.110.4.tgz +0 -0
  195. package/components/tryghost-referrers-5.110.4.tgz +0 -0
  196. package/components/tryghost-session-service-5.110.4.tgz +0 -0
  197. package/components/tryghost-settings-path-manager-5.110.4.tgz +0 -0
  198. package/components/tryghost-staff-service-5.110.4.tgz +0 -0
  199. package/components/tryghost-stats-service-5.110.4.tgz +0 -0
  200. package/components/tryghost-tiers-5.110.4.tgz +0 -0
  201. package/components/tryghost-version-notifications-data-service-5.110.4.tgz +0 -0
  202. 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.110%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%22936e008b28%22%2C%22adminXDemoFilename%22%3A%22admin-x-demo.js%22%2C%22adminXDemoHash%22%3A%22c0d9975d75%22%2C%22adminXSettingsFilename%22%3A%22admin-x-settings.js%22%2C%22adminXSettingsHash%22%3A%227b1858c545%22%2C%22adminXActivitypubFilename%22%3A%22admin-x-activitypub.js%22%2C%22adminXActivitypubHash%22%3A%227f25cf5ec5%22%2C%22postsFilename%22%3A%22posts.js%22%2C%22postsHash%22%3A%22a276e5a86b%22%2C%22adminXActivitypubCustomUrl%22%3A%22https%3A%2F%2Fcdn.jsdelivr.net%2Fghost%2Fadmin-x-activitypub%400%2Fdist%2Fadmin-x-activitypub.js%22%7D" />
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.3096e68df5b51dacf872.js"></script>
62
- <script src="assets/ghost-98d002d50a5e01d2100b2c387a849249.js"></script>
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 {URLResourceUpdatedEvent} = require('@tryghost/dynamic-routing-events');
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 2.4rem;
47
- padding: 1.2rem 0;
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 2rem;
59
- padding: 1rem 0;
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 40%, transparent);
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: 2.4rem;
79
- gap: 2.4rem;
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: 2rem;
85
- gap: 2rem;
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: 2.4rem 0;
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: 2rem 0;
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: 2.4rem;
133
+ gap: 1.5em;
123
134
  }
124
135
 
125
136
  @media (max-width: 600px) {
126
137
  .kg-cta-content-inner {
127
- gap: 2rem;
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: 2rem;
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: 600;
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;
@@ -85,6 +85,7 @@
85
85
  width: 100%;
86
86
  z-index: 9999;
87
87
  padding: 12px 16px;
88
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
88
89
  }
89
90
 
90
91
  .kg-video-current-time {
@@ -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
 
@@ -75,7 +75,9 @@ const EDITABLE_SETTINGS = [
75
75
  'recommendations_enabled',
76
76
  'body_font',
77
77
  'heading_font',
78
- 'blocked_email_domains'
78
+ 'blocked_email_domains',
79
+ 'captcha_enabled',
80
+ 'require_email_mfa'
79
81
  ];
80
82
 
81
83
  module.exports = {
@@ -47,7 +47,8 @@ const keyGroupMapping = {
47
47
  stripe_connect_integration: 'members',
48
48
  portal_name: 'portal',
49
49
  portal_button: 'portal',
50
- portal_plans: 'portal'
50
+ portal_plans: 'portal',
51
+ require_email_mfa: 'security'
51
52
  };
52
53
 
53
54
  const mapKeyToGroup = (key) => {
@@ -54,7 +54,8 @@ const keyTypeMapping = {
54
54
  stripe_connect_livemode: 'boolean',
55
55
  labs: 'object',
56
56
  unsplash: 'object',
57
- bulk_email_settings: 'object'
57
+ bulk_email_settings: 'object',
58
+ require_email_mfa: 'boolean'
58
59
  };
59
60
 
60
61
  const mapKeyToType = (key) => {
@@ -0,0 +1,8 @@
1
+ const {addSetting} = require('../../utils');
2
+
3
+ module.exports = addSetting({
4
+ key: 'captcha_enabled',
5
+ value: 'false',
6
+ type: 'boolean',
7
+ group: 'members'
8
+ });
@@ -0,0 +1,8 @@
1
+ const {addSetting} = require('../../utils');
2
+
3
+ module.exports = addSetting({
4
+ key: 'require_email_mfa',
5
+ value: 'false',
6
+ type: 'boolean',
7
+ group: 'security'
8
+ });
@@ -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
- if (_.some(loadedPermissions.user.roles, {name: 'Owner'}) ||
90
- _.some(loadedPermissions.user.roles, {name: 'Administrator'})) {
88
+ const {isOwner, isAdmin, isEitherEditor} = setIsRoles(loadedPermissions);
89
+ if (isOwner || isAdmin) {
91
90
  allowed = ['Administrator', 'Editor', 'Author', 'Contributor'];
92
- } else if (_.some(loadedPermissions.user.roles, {name: 'Editor'})) {
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 || isEditor || isIntegration)) {
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
- let isContributor;
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 (_.some(loadedPermissions.user.roles, {name: 'Owner'})) {
84
+ if (isOwner) {
83
85
  checkAgainst = ['Owner', 'Administrator', 'Editor', 'Author', 'Contributor'];
84
- } else if (_.some(loadedPermissions.user.roles, {name: 'Administrator'})) {
86
+ } else if (isAdmin) {
85
87
  checkAgainst = ['Administrator', 'Editor', 'Author', 'Contributor'];
86
- } else if (_.some(loadedPermissions.user.roles, {name: 'Editor'})) {
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 (loadedPermissions.user && userModel.hasRole('Owner')) {
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 (loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Editor'})) {
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 (loadedPermissions.user && _.some(loadedPermissions.user.roles, {name: 'Editor'})) {
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;