ghost 5.12.2 → 5.13.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 (430) hide show
  1. package/components/{tryghost-adapter-manager-5.12.2.tgz → tryghost-adapter-manager-5.13.0.tgz} +0 -0
  2. package/components/{tryghost-api-framework-5.12.2.tgz → tryghost-api-framework-5.13.0.tgz} +0 -0
  3. package/components/tryghost-api-version-compatibility-service-5.13.0.tgz +0 -0
  4. package/components/tryghost-bootstrap-socket-5.13.0.tgz +0 -0
  5. package/components/tryghost-constants-5.13.0.tgz +0 -0
  6. package/components/{tryghost-custom-theme-settings-service-5.12.2.tgz → tryghost-custom-theme-settings-service-5.13.0.tgz} +0 -0
  7. package/components/tryghost-domain-events-5.13.0.tgz +0 -0
  8. package/components/tryghost-email-analytics-provider-mailgun-5.13.0.tgz +0 -0
  9. package/components/tryghost-email-analytics-service-5.13.0.tgz +0 -0
  10. package/components/tryghost-email-content-generator-5.13.0.tgz +0 -0
  11. package/components/tryghost-express-dynamic-redirects-5.13.0.tgz +0 -0
  12. package/components/tryghost-extract-api-key-5.13.0.tgz +0 -0
  13. package/components/tryghost-html-to-plaintext-5.13.0.tgz +0 -0
  14. package/components/{tryghost-job-manager-5.12.2.tgz → tryghost-job-manager-5.13.0.tgz} +0 -0
  15. package/components/{tryghost-magic-link-5.12.2.tgz → tryghost-magic-link-5.13.0.tgz} +0 -0
  16. package/components/{tryghost-mailgun-client-5.12.2.tgz → tryghost-mailgun-client-5.13.0.tgz} +0 -0
  17. package/components/tryghost-member-analytics-service-5.13.0.tgz +0 -0
  18. package/components/{tryghost-member-attribution-5.12.2.tgz → tryghost-member-attribution-5.13.0.tgz} +0 -0
  19. package/components/tryghost-member-events-5.13.0.tgz +0 -0
  20. package/components/tryghost-members-analytics-ingress-5.13.0.tgz +0 -0
  21. package/components/tryghost-members-api-5.13.0.tgz +0 -0
  22. package/components/{tryghost-members-csv-5.12.2.tgz → tryghost-members-csv-5.13.0.tgz} +0 -0
  23. package/components/tryghost-members-events-service-5.13.0.tgz +0 -0
  24. package/components/{tryghost-members-importer-5.12.2.tgz → tryghost-members-importer-5.13.0.tgz} +0 -0
  25. package/components/{tryghost-members-offers-5.12.2.tgz → tryghost-members-offers-5.13.0.tgz} +0 -0
  26. package/components/tryghost-members-payments-5.13.0.tgz +0 -0
  27. package/components/{tryghost-members-ssr-5.12.2.tgz → tryghost-members-ssr-5.13.0.tgz} +0 -0
  28. package/components/{tryghost-members-stripe-service-5.12.2.tgz → tryghost-members-stripe-service-5.13.0.tgz} +0 -0
  29. package/components/tryghost-minifier-5.13.0.tgz +0 -0
  30. package/components/tryghost-mw-api-version-mismatch-5.13.0.tgz +0 -0
  31. package/components/tryghost-mw-cache-control-5.13.0.tgz +0 -0
  32. package/components/{tryghost-mw-error-handler-5.12.2.tgz → tryghost-mw-error-handler-5.13.0.tgz} +0 -0
  33. package/components/tryghost-mw-session-from-token-5.13.0.tgz +0 -0
  34. package/components/tryghost-mw-update-user-last-seen-5.13.0.tgz +0 -0
  35. package/components/tryghost-mw-vhost-5.13.0.tgz +0 -0
  36. package/components/tryghost-oembed-service-5.13.0.tgz +0 -0
  37. package/components/{tryghost-package-json-5.12.2.tgz → tryghost-package-json-5.13.0.tgz} +0 -0
  38. package/components/{tryghost-security-5.12.2.tgz → tryghost-security-5.13.0.tgz} +0 -0
  39. package/components/{tryghost-session-service-5.12.2.tgz → tryghost-session-service-5.13.0.tgz} +0 -0
  40. package/components/tryghost-settings-path-manager-5.13.0.tgz +0 -0
  41. package/components/tryghost-staff-service-5.13.0.tgz +0 -0
  42. package/components/{tryghost-update-check-service-5.12.2.tgz → tryghost-update-check-service-5.13.0.tgz} +0 -0
  43. package/components/{tryghost-verification-trigger-5.12.2.tgz → tryghost-verification-trigger-5.13.0.tgz} +0 -0
  44. package/components/{tryghost-version-notifications-data-service-5.12.2.tgz → tryghost-version-notifications-data-service-5.13.0.tgz} +0 -0
  45. package/core/built/admin/assets/{chunk.143.b51e90c24c7efd3fbc00.js → chunk.143.e96aad00fdf7196692c7.js} +6 -6
  46. package/core/built/admin/assets/{chunk.174.ae492405065373dbe102.js → chunk.174.8b8a64726921ecfda41b.js} +157 -155
  47. package/core/built/admin/assets/{chunk.178.3bb279f23ad0f1204216.js → chunk.178.1188f8d61af173f8c246.js} +4 -4
  48. package/core/built/admin/assets/{chunk.579.65e09dd89eec70d059a0.js → chunk.763.9a285d7351e1f4415f8d.js} +122 -114
  49. package/core/built/admin/assets/{chunk.579.65e09dd89eec70d059a0.js.LICENSE.txt → chunk.763.9a285d7351e1f4415f8d.js.LICENSE.txt} +0 -0
  50. package/core/built/admin/assets/{ghost-0526c96b20843697927c1d06a9010197.js → ghost-3203510c519d3195f1e71a34e9eecc59.js} +216 -278
  51. package/core/built/admin/assets/ghost-647c9a79282265a4d29bf273c44f72c0.css +1 -0
  52. package/core/built/admin/assets/ghost-dark-d84a2701166840b73bbbbe657879b65e.css +1 -0
  53. package/core/built/admin/assets/img/amp.svg +4 -1
  54. package/core/built/admin/assets/img/disqus.svg +4 -1
  55. package/core/built/admin/assets/img/github.svg +4 -1
  56. package/core/built/admin/assets/img/google-docs.svg +6 -17
  57. package/core/built/admin/assets/img/mailchimp.svg +7 -8
  58. package/core/built/admin/assets/img/patreon.svg +7 -1
  59. package/core/built/admin/assets/img/paypal.svg +8 -1
  60. package/core/built/admin/assets/img/twitter.svg +1 -0
  61. package/core/built/admin/assets/img/typeform.svg +1 -0
  62. package/core/built/admin/assets/img/unsplash.svg +4 -0
  63. package/core/built/admin/assets/img/zapier-logo.svg +4 -1
  64. package/core/built/admin/assets/img/zapier.svg +4 -1
  65. package/core/built/admin/assets/{vendor-bc9d2c9e5c8a33f0c92e81189d48e04c.css → vendor-733135cd6cbca8126c6fa223d63a5bf3.css} +0 -29
  66. package/core/built/admin/assets/{vendor-52613f40d62355e9ac64cbfa211169bb.js → vendor-ab4b5dfdf8b86f24d726115ac7de0980.js} +5990 -6203
  67. package/core/built/admin/index.html +7 -7
  68. package/core/server/lib/common/events.js +12 -0
  69. package/core/server/services/comments/emails.js +3 -19
  70. package/core/server/services/comments/index.js +2 -0
  71. package/core/server/services/comments/service.js +2 -1
  72. package/core/server/services/mega/post-email-serializer.js +8 -1
  73. package/core/server/services/mega/template.js +2 -1
  74. package/core/server/services/members/config.js +11 -72
  75. package/core/server/services/members/middleware.js +2 -0
  76. package/core/server/services/members/service.js +2 -1
  77. package/core/server/services/settings/settings-service.js +5 -72
  78. package/core/server/services/settings-helpers/index.js +6 -0
  79. package/core/server/services/settings-helpers/settings-helpers.js +99 -0
  80. package/core/server/services/staff/index.js +2 -4
  81. package/core/server/services/stripe/config.js +2 -38
  82. package/core/server/services/stripe/service.js +2 -1
  83. package/core/server/services/url/Resources.js +48 -59
  84. package/core/server/services/url/UrlService.js +2 -2
  85. package/core/server/services/webhooks/listen.js +10 -1
  86. package/core/server/web/shared/middleware/api/spam-prevention.js +32 -0
  87. package/core/server/web/shared/middleware/brute.js +3 -16
  88. package/core/shared/config/defaults.json +1 -0
  89. package/package.json +92 -92
  90. package/yarn.lock +332 -137
  91. package/components/tryghost-api-version-compatibility-service-5.12.2.tgz +0 -0
  92. package/components/tryghost-bootstrap-socket-5.12.2.tgz +0 -0
  93. package/components/tryghost-constants-5.12.2.tgz +0 -0
  94. package/components/tryghost-domain-events-5.12.2.tgz +0 -0
  95. package/components/tryghost-email-analytics-provider-mailgun-5.12.2.tgz +0 -0
  96. package/components/tryghost-email-analytics-service-5.12.2.tgz +0 -0
  97. package/components/tryghost-email-content-generator-5.12.2.tgz +0 -0
  98. package/components/tryghost-express-dynamic-redirects-5.12.2.tgz +0 -0
  99. package/components/tryghost-extract-api-key-5.12.2.tgz +0 -0
  100. package/components/tryghost-html-to-plaintext-5.12.2.tgz +0 -0
  101. package/components/tryghost-member-analytics-service-5.12.2.tgz +0 -0
  102. package/components/tryghost-member-events-5.12.2.tgz +0 -0
  103. package/components/tryghost-members-analytics-ingress-5.12.2.tgz +0 -0
  104. package/components/tryghost-members-api-5.12.2.tgz +0 -0
  105. package/components/tryghost-members-events-service-5.12.2.tgz +0 -0
  106. package/components/tryghost-members-payments-5.12.2.tgz +0 -0
  107. package/components/tryghost-minifier-5.12.2.tgz +0 -0
  108. package/components/tryghost-mw-api-version-mismatch-5.12.2.tgz +0 -0
  109. package/components/tryghost-mw-cache-control-5.12.2.tgz +0 -0
  110. package/components/tryghost-mw-session-from-token-5.12.2.tgz +0 -0
  111. package/components/tryghost-mw-update-user-last-seen-5.12.2.tgz +0 -0
  112. package/components/tryghost-mw-vhost-5.12.2.tgz +0 -0
  113. package/components/tryghost-oembed-service-5.12.2.tgz +0 -0
  114. package/components/tryghost-settings-path-manager-5.12.2.tgz +0 -0
  115. package/components/tryghost-staff-service-5.12.2.tgz +0 -0
  116. package/content/themes/casper/yarn.lock +0 -5385
  117. package/core/built/admin/assets/ghost-0bbbef127e5dc0c0651fc442c4fdba8e.css +0 -1
  118. package/core/built/admin/assets/ghost-dark-27e002e66fbfdfaf3efcde63d5429c38.css +0 -1
  119. package/core/built/admin/assets/icons/account-group.svg +0 -1
  120. package/core/built/admin/assets/icons/activity-placeholder.svg +0 -3
  121. package/core/built/admin/assets/icons/add-stroke.svg +0 -1
  122. package/core/built/admin/assets/icons/add-view.svg +0 -1
  123. package/core/built/admin/assets/icons/add.svg +0 -3
  124. package/core/built/admin/assets/icons/align-center.svg +0 -3
  125. package/core/built/admin/assets/icons/align-left.svg +0 -3
  126. package/core/built/admin/assets/icons/ambulance.svg +0 -1
  127. package/core/built/admin/assets/icons/analytics.svg +0 -14
  128. package/core/built/admin/assets/icons/arrow-down-small.svg +0 -12
  129. package/core/built/admin/assets/icons/arrow-down-stroke.svg +0 -1
  130. package/core/built/admin/assets/icons/arrow-down.svg +0 -3
  131. package/core/built/admin/assets/icons/arrow-left-small.svg +0 -8
  132. package/core/built/admin/assets/icons/arrow-left-stroke.svg +0 -1
  133. package/core/built/admin/assets/icons/arrow-left-tail.svg +0 -4
  134. package/core/built/admin/assets/icons/arrow-left.svg +0 -3
  135. package/core/built/admin/assets/icons/arrow-right-small.svg +0 -12
  136. package/core/built/admin/assets/icons/arrow-right-stroke.svg +0 -1
  137. package/core/built/admin/assets/icons/arrow-right-tail.svg +0 -4
  138. package/core/built/admin/assets/icons/arrow-right.svg +0 -3
  139. package/core/built/admin/assets/icons/arrow-up-small.svg +0 -12
  140. package/core/built/admin/assets/icons/arrow-up-stroke.svg +0 -1
  141. package/core/built/admin/assets/icons/arrow-up.svg +0 -9
  142. package/core/built/admin/assets/icons/arrow2-down.svg +0 -1
  143. package/core/built/admin/assets/icons/arrow2-right.svg +0 -11
  144. package/core/built/admin/assets/icons/audio-file.svg +0 -5
  145. package/core/built/admin/assets/icons/audio-upload.svg +0 -8
  146. package/core/built/admin/assets/icons/book-open.svg +0 -1
  147. package/core/built/admin/assets/icons/bookmark-article.svg +0 -1
  148. package/core/built/admin/assets/icons/box-hands.svg +0 -1
  149. package/core/built/admin/assets/icons/box.svg +0 -3
  150. package/core/built/admin/assets/icons/boxes.svg +0 -1
  151. package/core/built/admin/assets/icons/brackets.svg +0 -1
  152. package/core/built/admin/assets/icons/button.svg +0 -4
  153. package/core/built/admin/assets/icons/calendar-stroke.svg +0 -1
  154. package/core/built/admin/assets/icons/calendar.svg +0 -4
  155. package/core/built/admin/assets/icons/cash.svg +0 -1
  156. package/core/built/admin/assets/icons/chat-double-bubble.svg +0 -1
  157. package/core/built/admin/assets/icons/check-2.svg +0 -1
  158. package/core/built/admin/assets/icons/check-circle-stroke.svg +0 -1
  159. package/core/built/admin/assets/icons/check-circle.svg +0 -5
  160. package/core/built/admin/assets/icons/check.svg +0 -1
  161. package/core/built/admin/assets/icons/cheeseburger.svg +0 -1
  162. package/core/built/admin/assets/icons/circle-ellipsis.svg +0 -1
  163. package/core/built/admin/assets/icons/clock.svg +0 -1
  164. package/core/built/admin/assets/icons/clockface.svg +0 -1
  165. package/core/built/admin/assets/icons/close-stroke.svg +0 -1
  166. package/core/built/admin/assets/icons/close.svg +0 -1
  167. package/core/built/admin/assets/icons/cloud.svg +0 -1
  168. package/core/built/admin/assets/icons/compass-2.svg +0 -1
  169. package/core/built/admin/assets/icons/compass.svg +0 -3
  170. package/core/built/admin/assets/icons/computer.svg +0 -1
  171. package/core/built/admin/assets/icons/confetti.svg +0 -1
  172. package/core/built/admin/assets/icons/content-bold.svg +0 -1
  173. package/core/built/admin/assets/icons/content.svg +0 -1
  174. package/core/built/admin/assets/icons/copy.svg +0 -1
  175. package/core/built/admin/assets/icons/credit-card.svg +0 -1
  176. package/core/built/admin/assets/icons/cross-circle.svg +0 -1
  177. package/core/built/admin/assets/icons/cycle.svg +0 -1
  178. package/core/built/admin/assets/icons/default-favicon.svg +0 -12
  179. package/core/built/admin/assets/icons/desert.svg +0 -59
  180. package/core/built/admin/assets/icons/desktop.svg +0 -5
  181. package/core/built/admin/assets/icons/diamond.svg +0 -1
  182. package/core/built/admin/assets/icons/discount-bubble.svg +0 -1
  183. package/core/built/admin/assets/icons/dividers.svg +0 -4
  184. package/core/built/admin/assets/icons/dotdotdot.svg +0 -1
  185. package/core/built/admin/assets/icons/download-circle.svg +0 -1
  186. package/core/built/admin/assets/icons/download.svg +0 -3
  187. package/core/built/admin/assets/icons/eco-globe.svg +0 -1
  188. package/core/built/admin/assets/icons/eco-lightbulb.svg +0 -1
  189. package/core/built/admin/assets/icons/edit-view.svg +0 -1
  190. package/core/built/admin/assets/icons/ellipsis.svg +0 -1
  191. package/core/built/admin/assets/icons/email-at.svg +0 -1
  192. package/core/built/admin/assets/icons/email-body.svg +0 -1
  193. package/core/built/admin/assets/icons/email-footer.svg +0 -1
  194. package/core/built/admin/assets/icons/email-header.svg +0 -1
  195. package/core/built/admin/assets/icons/email-love-letter.svg +0 -1
  196. package/core/built/admin/assets/icons/email-member.svg +0 -1
  197. package/core/built/admin/assets/icons/email-name.svg +0 -1
  198. package/core/built/admin/assets/icons/email-send.svg +0 -1
  199. package/core/built/admin/assets/icons/email-stroke.svg +0 -4
  200. package/core/built/admin/assets/icons/email-unread.svg +0 -4
  201. package/core/built/admin/assets/icons/email.svg +0 -1
  202. package/core/built/admin/assets/icons/event-canceled-subscription--feature-attribution.svg +0 -6
  203. package/core/built/admin/assets/icons/event-canceled-subscription.svg +0 -6
  204. package/core/built/admin/assets/icons/event-comment--feature-attribution.svg +0 -3
  205. package/core/built/admin/assets/icons/event-comment.svg +0 -3
  206. package/core/built/admin/assets/icons/event-email-delivery-failed--feature-attribution.svg +0 -6
  207. package/core/built/admin/assets/icons/event-email-delivery-failed.svg +0 -6
  208. package/core/built/admin/assets/icons/event-logged-in--feature-attribution.svg +0 -5
  209. package/core/built/admin/assets/icons/event-logged-in.svg +0 -5
  210. package/core/built/admin/assets/icons/event-made-a-payment--feature-attribution.svg +0 -7
  211. package/core/built/admin/assets/icons/event-made-a-payment.svg +0 -7
  212. package/core/built/admin/assets/icons/event-opened-email--feature-attribution.svg +0 -6
  213. package/core/built/admin/assets/icons/event-opened-email.svg +0 -6
  214. package/core/built/admin/assets/icons/event-received-email--feature-attribution.svg +0 -5
  215. package/core/built/admin/assets/icons/event-received-email.svg +0 -5
  216. package/core/built/admin/assets/icons/event-signed-up--feature-attribution.svg +0 -6
  217. package/core/built/admin/assets/icons/event-signed-up.svg +0 -6
  218. package/core/built/admin/assets/icons/event-started-subscription--feature-attribution.svg +0 -6
  219. package/core/built/admin/assets/icons/event-subscribed-to-email--feature-attribution.svg +0 -8
  220. package/core/built/admin/assets/icons/event-subscribed-to-email.svg +0 -8
  221. package/core/built/admin/assets/icons/event-subscriptions--feature-attribution.svg +0 -5
  222. package/core/built/admin/assets/icons/event-subscriptions.svg +0 -5
  223. package/core/built/admin/assets/icons/event-unsubscribed-from-email--feature-attribution.svg +0 -5
  224. package/core/built/admin/assets/icons/event-unsubscribed-from-email.svg +0 -5
  225. package/core/built/admin/assets/icons/expand.svg +0 -1
  226. package/core/built/admin/assets/icons/external.svg +0 -4
  227. package/core/built/admin/assets/icons/eye.svg +0 -4
  228. package/core/built/admin/assets/icons/facebook-heart.svg +0 -5
  229. package/core/built/admin/assets/icons/facebook-like.svg +0 -5
  230. package/core/built/admin/assets/icons/facebook.svg +0 -6
  231. package/core/built/admin/assets/icons/feature-image.svg +0 -4
  232. package/core/built/admin/assets/icons/file-download.svg +0 -1
  233. package/core/built/admin/assets/icons/file-tabular-data.svg +0 -1
  234. package/core/built/admin/assets/icons/file-text-document.svg +0 -1
  235. package/core/built/admin/assets/icons/file-upload.svg +0 -1
  236. package/core/built/admin/assets/icons/film-camera.svg +0 -4
  237. package/core/built/admin/assets/icons/filter.svg +0 -5
  238. package/core/built/admin/assets/icons/firstpromoter-ce8b5219e5b5ebda463bd60396c6ab81.png +0 -0
  239. package/core/built/admin/assets/icons/folder.svg +0 -4
  240. package/core/built/admin/assets/icons/gallery-placeholder.svg +0 -14
  241. package/core/built/admin/assets/icons/get-started-import.svg +0 -13
  242. package/core/built/admin/assets/icons/get-started-members.svg +0 -6
  243. package/core/built/admin/assets/icons/get-started-migrations.svg +0 -6
  244. package/core/built/admin/assets/icons/get-started.svg +0 -3
  245. package/core/built/admin/assets/icons/ghost-logo-orb.svg +0 -10
  246. package/core/built/admin/assets/icons/ghost-logo.svg +0 -1
  247. package/core/built/admin/assets/icons/ghost-orb-pink.svg +0 -10
  248. package/core/built/admin/assets/icons/ghost-orb.svg +0 -10
  249. package/core/built/admin/assets/icons/ghost-squircle.svg +0 -7
  250. package/core/built/admin/assets/icons/gift.svg +0 -1
  251. package/core/built/admin/assets/icons/github-outline.svg +0 -1
  252. package/core/built/admin/assets/icons/github-star.svg +0 -8
  253. package/core/built/admin/assets/icons/github.svg +0 -6
  254. package/core/built/admin/assets/icons/globe.svg +0 -1
  255. package/core/built/admin/assets/icons/google-favicon.svg +0 -6
  256. package/core/built/admin/assets/icons/google-search.svg +0 -3
  257. package/core/built/admin/assets/icons/google.svg +0 -8
  258. package/core/built/admin/assets/icons/grab.svg +0 -4
  259. package/core/built/admin/assets/icons/graph-line.svg +0 -1
  260. package/core/built/admin/assets/icons/heart-beat.svg +0 -1
  261. package/core/built/admin/assets/icons/heart-circle.svg +0 -1
  262. package/core/built/admin/assets/icons/heart.svg +0 -1
  263. package/core/built/admin/assets/icons/help.svg +0 -6
  264. package/core/built/admin/assets/icons/hotspot.svg +0 -4
  265. package/core/built/admin/assets/icons/house-bold.svg +0 -1
  266. package/core/built/admin/assets/icons/house.svg +0 -1
  267. package/core/built/admin/assets/icons/icon.svg +0 -1
  268. package/core/built/admin/assets/icons/id-card.svg +0 -1
  269. package/core/built/admin/assets/icons/idea.svg +0 -1
  270. package/core/built/admin/assets/icons/info.svg +0 -1
  271. package/core/built/admin/assets/icons/instagram.svg +0 -8
  272. package/core/built/admin/assets/icons/integration.svg +0 -1
  273. package/core/built/admin/assets/icons/labs.svg +0 -1
  274. package/core/built/admin/assets/icons/laptop.svg +0 -1
  275. package/core/built/admin/assets/icons/line.svg +0 -10
  276. package/core/built/admin/assets/icons/link.svg +0 -1
  277. package/core/built/admin/assets/icons/list-bullet.svg +0 -1
  278. package/core/built/admin/assets/icons/list-number.svg +0 -1
  279. package/core/built/admin/assets/icons/lock.svg +0 -1
  280. package/core/built/admin/assets/icons/lock2.svg +0 -10
  281. package/core/built/admin/assets/icons/loop-infinite.svg +0 -13
  282. package/core/built/admin/assets/icons/lotus.svg +0 -1
  283. package/core/built/admin/assets/icons/markdown.svg +0 -12
  284. package/core/built/admin/assets/icons/member-add.svg +0 -3
  285. package/core/built/admin/assets/icons/member.svg +0 -1
  286. package/core/built/admin/assets/icons/members-all.svg +0 -5
  287. package/core/built/admin/assets/icons/members-bold.svg +0 -1
  288. package/core/built/admin/assets/icons/members-outline.svg +0 -5
  289. package/core/built/admin/assets/icons/members-paid.svg +0 -4
  290. package/core/built/admin/assets/icons/members-placeholder.svg +0 -5
  291. package/core/built/admin/assets/icons/members-post.svg +0 -5
  292. package/core/built/admin/assets/icons/members-segment.svg +0 -21
  293. package/core/built/admin/assets/icons/members.svg +0 -1
  294. package/core/built/admin/assets/icons/mobile-phone-heart.svg +0 -1
  295. package/core/built/admin/assets/icons/mobile-phone.svg +0 -4
  296. package/core/built/admin/assets/icons/module.svg +0 -1
  297. package/core/built/admin/assets/icons/modules.svg +0 -1
  298. package/core/built/admin/assets/icons/monitor-labs.svg +0 -1
  299. package/core/built/admin/assets/icons/moon.svg +0 -1
  300. package/core/built/admin/assets/icons/mountains.svg +0 -1
  301. package/core/built/admin/assets/icons/mute.svg +0 -3
  302. package/core/built/admin/assets/icons/navigation.svg +0 -1
  303. package/core/built/admin/assets/icons/network.svg +0 -1
  304. package/core/built/admin/assets/icons/news-article.svg +0 -1
  305. package/core/built/admin/assets/icons/nightshift.svg +0 -1
  306. package/core/built/admin/assets/icons/no-data-line-chart.svg +0 -1
  307. package/core/built/admin/assets/icons/no-data-list.svg +0 -9
  308. package/core/built/admin/assets/icons/no-data-subscription.svg +0 -1
  309. package/core/built/admin/assets/icons/no-email.svg +0 -5
  310. package/core/built/admin/assets/icons/no-members.svg +0 -3
  311. package/core/built/admin/assets/icons/offer.svg +0 -4
  312. package/core/built/admin/assets/icons/page-bold.svg +0 -1
  313. package/core/built/admin/assets/icons/page.svg +0 -1
  314. package/core/built/admin/assets/icons/pages-placeholder.svg +0 -3
  315. package/core/built/admin/assets/icons/paint-palette.svg +0 -1
  316. package/core/built/admin/assets/icons/paintbrush.svg +0 -10
  317. package/core/built/admin/assets/icons/pause.svg +0 -4
  318. package/core/built/admin/assets/icons/pen-stroke.svg +0 -1
  319. package/core/built/admin/assets/icons/pen.svg +0 -1
  320. package/core/built/admin/assets/icons/pencil-circle.svg +0 -1
  321. package/core/built/admin/assets/icons/pencil.svg +0 -1
  322. package/core/built/admin/assets/icons/percentage.svg +0 -1
  323. package/core/built/admin/assets/icons/photos-people.svg +0 -1
  324. package/core/built/admin/assets/icons/photos.svg +0 -1
  325. package/core/built/admin/assets/icons/piggy-bank.svg +0 -1
  326. package/core/built/admin/assets/icons/pin.svg +0 -4
  327. package/core/built/admin/assets/icons/plane.svg +0 -1
  328. package/core/built/admin/assets/icons/play.svg +0 -3
  329. package/core/built/admin/assets/icons/plus.svg +0 -1
  330. package/core/built/admin/assets/icons/portal-icon-1.svg +0 -1
  331. package/core/built/admin/assets/icons/portal-icon-2.svg +0 -1
  332. package/core/built/admin/assets/icons/portal-icon-3.svg +0 -1
  333. package/core/built/admin/assets/icons/portal-icon-4.svg +0 -1
  334. package/core/built/admin/assets/icons/portal-icon-5.svg +0 -1
  335. package/core/built/admin/assets/icons/portal-logo-stroke.svg +0 -15
  336. package/core/built/admin/assets/icons/portal-logo.svg +0 -1
  337. package/core/built/admin/assets/icons/post.svg +0 -3
  338. package/core/built/admin/assets/icons/posts-placeholder.svg +0 -4
  339. package/core/built/admin/assets/icons/posts.svg +0 -1
  340. package/core/built/admin/assets/icons/powered-by-stripe.svg +0 -14
  341. package/core/built/admin/assets/icons/powered-by-tenor.svg +0 -35
  342. package/core/built/admin/assets/icons/presentation-code.svg +0 -1
  343. package/core/built/admin/assets/icons/published-post.svg +0 -1
  344. package/core/built/admin/assets/icons/recycle.svg +0 -1
  345. package/core/built/admin/assets/icons/reload.svg +0 -1
  346. package/core/built/admin/assets/icons/repo.svg +0 -1
  347. package/core/built/admin/assets/icons/retry.svg +0 -6
  348. package/core/built/admin/assets/icons/satellite.svg +0 -1
  349. package/core/built/admin/assets/icons/search.svg +0 -1
  350. package/core/built/admin/assets/icons/send-email.svg +0 -1
  351. package/core/built/admin/assets/icons/server.svg +0 -1
  352. package/core/built/admin/assets/icons/settings.svg +0 -1
  353. package/core/built/admin/assets/icons/shield-lock.svg +0 -1
  354. package/core/built/admin/assets/icons/shield.svg +0 -1
  355. package/core/built/admin/assets/icons/sidemenu-open.svg +0 -4
  356. package/core/built/admin/assets/icons/sidemenu.svg +0 -3
  357. package/core/built/admin/assets/icons/signal-tower.svg +0 -1
  358. package/core/built/admin/assets/icons/signout.svg +0 -1
  359. package/core/built/admin/assets/icons/smiley.svg +0 -1
  360. package/core/built/admin/assets/icons/social-facebook.svg +0 -7
  361. package/core/built/admin/assets/icons/social-share.svg +0 -4
  362. package/core/built/admin/assets/icons/social-twitter.svg +0 -4
  363. package/core/built/admin/assets/icons/spinner.svg +0 -1
  364. package/core/built/admin/assets/icons/staff.svg +0 -1
  365. package/core/built/admin/assets/icons/star-filled.svg +0 -1
  366. package/core/built/admin/assets/icons/store.svg +0 -1
  367. package/core/built/admin/assets/icons/stripe-verified-partner-badge.svg +0 -1
  368. package/core/built/admin/assets/icons/summer.svg +0 -1
  369. package/core/built/admin/assets/icons/sun.svg +0 -1
  370. package/core/built/admin/assets/icons/support.svg +0 -1
  371. package/core/built/admin/assets/icons/sync.svg +0 -3
  372. package/core/built/admin/assets/icons/tag.svg +0 -1
  373. package/core/built/admin/assets/icons/tags-placeholder.svg +0 -5
  374. package/core/built/admin/assets/icons/tenor.svg +0 -7
  375. package/core/built/admin/assets/icons/terminal.svg +0 -1
  376. package/core/built/admin/assets/icons/text-vector.svg +0 -1
  377. package/core/built/admin/assets/icons/text.svg +0 -1
  378. package/core/built/admin/assets/icons/theme.svg +0 -1
  379. package/core/built/admin/assets/icons/ticket.svg +0 -1
  380. package/core/built/admin/assets/icons/trash.svg +0 -3
  381. package/core/built/admin/assets/icons/trophy.svg +0 -1
  382. package/core/built/admin/assets/icons/tumbleweed.svg +0 -10
  383. package/core/built/admin/assets/icons/twitter-comment.svg +0 -5
  384. package/core/built/admin/assets/icons/twitter-like.svg +0 -5
  385. package/core/built/admin/assets/icons/twitter-link.svg +0 -6
  386. package/core/built/admin/assets/icons/twitter-logo.svg +0 -3
  387. package/core/built/admin/assets/icons/twitter-retweet.svg +0 -5
  388. package/core/built/admin/assets/icons/twitter-share.svg +0 -6
  389. package/core/built/admin/assets/icons/twitter.svg +0 -1
  390. package/core/built/admin/assets/icons/ufo-attack.svg +0 -1
  391. package/core/built/admin/assets/icons/unmute.svg +0 -3
  392. package/core/built/admin/assets/icons/unsplash-heart.svg +0 -1
  393. package/core/built/admin/assets/icons/unsplash.svg +0 -1
  394. package/core/built/admin/assets/icons/unsubscribed.svg +0 -1
  395. package/core/built/admin/assets/icons/upload-fill.svg +0 -15
  396. package/core/built/admin/assets/icons/upload.svg +0 -1
  397. package/core/built/admin/assets/icons/user-circle.svg +0 -1
  398. package/core/built/admin/assets/icons/user-group.svg +0 -1
  399. package/core/built/admin/assets/icons/user-group2.svg +0 -1
  400. package/core/built/admin/assets/icons/v-ellipsis.svg +0 -1
  401. package/core/built/admin/assets/icons/view-site.svg +0 -1
  402. package/core/built/admin/assets/icons/warning-stroke.svg +0 -1
  403. package/core/built/admin/assets/icons/warning.svg +0 -1
  404. package/core/built/admin/assets/icons/window-app.svg +0 -1
  405. package/core/built/admin/assets/icons/window-pulse.svg +0 -1
  406. package/core/built/admin/assets/icons/wrench-double.svg +0 -1
  407. package/core/built/admin/assets/icons/zap.svg +0 -1
  408. package/core/built/admin/assets/img/abstract-2-2937e2902b64360d0cbe4cec8bd8479b.jpg +0 -0
  409. package/core/built/admin/assets/img/abstract-c52b2f4208e7fd2e7b8abd8b1eec4f7b.jpg +0 -0
  410. package/core/built/admin/assets/img/community-be8c1dcecfb157f2bfba5cababc8e686.jpg +0 -0
  411. package/core/built/admin/assets/img/dashboard/bp1-03a13253453b372d0bbd5e6a19b20fca.jpg +0 -0
  412. package/core/built/admin/assets/img/dashboard/bp2-ed14f9f48c56d5d6fe997dc637a8b1ad.jpg +0 -0
  413. package/core/built/admin/assets/img/dashboard/join-community-bb5478f7dca6c04a2d0baf2b02f880fb.jpg +0 -0
  414. package/core/built/admin/assets/img/dashboard-feature-image-8949197550decb94a8f1dea57ad47819.jpeg +0 -0
  415. package/core/built/admin/assets/img/get-started-995c36b9ede90bb3777c83751e798ef7.jpg +0 -0
  416. package/core/built/admin/assets/img/install-welcome-ff3912d18bf8949df89c83b1c3b8bb66.png +0 -0
  417. package/core/built/admin/assets/img/invite-placeholder-4b3731d47c6c8f6cb3aaa6bc4d870c9f.png +0 -0
  418. package/core/built/admin/assets/img/launch-wizard-bg-13b995b1f02bce34b269db3190897384.png +0 -0
  419. package/core/built/admin/assets/img/more-fe5480ab76c7be7aec28bcfe844f41c1.png +0 -0
  420. package/core/built/admin/assets/img/newsletter-1-197ae8063dfb2e22278d355198029c9e.jpg +0 -0
  421. package/core/built/admin/assets/img/newsletter-2-5a2c7693ea9380d4282061302c01267a.jpg +0 -0
  422. package/core/built/admin/assets/img/themes/Alto-a5172a42994782321d8c9f268928d987.jpg +0 -0
  423. package/core/built/admin/assets/img/themes/Alto-cut-c667d9d6457c5e981aa7bdc8946b215a.jpg +0 -0
  424. package/core/built/admin/assets/img/themes/Ease-7cfb8f06f9b66b1aa04b92493a471fef.jpg +0 -0
  425. package/core/built/admin/assets/img/themes/Ease-cut-78d5aa00682bee6a4cf22155f09e49e8.jpg +0 -0
  426. package/core/built/admin/assets/img/themes/Edition-b94372eb5c88fce0f4befba39148ff28.jpg +0 -0
  427. package/core/built/admin/assets/img/themes/Edition-cut-e6545bab2768aafa1996100774f310ff.jpg +0 -0
  428. package/core/built/admin/assets/img/themes/London-cut-599cba221f81a15ad37fe395cf4e572c.jpg +0 -0
  429. package/core/built/admin/assets/img/users-33427addfe0f11c78b42cccaf83be073.png +0 -0
  430. package/core/built/admin/assets/img/whats-new-header-bg.svg +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%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.12%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%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.13%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22moment%22%3A%7B%22includeTimezone%22%3A%22all%22%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -36,8 +36,8 @@
36
36
  }
37
37
  </style>
38
38
 
39
- <link integrity="" rel="stylesheet" href="assets/vendor-bc9d2c9e5c8a33f0c92e81189d48e04c.css">
40
- <link integrity="" rel="stylesheet" href="assets/ghost-0bbbef127e5dc0c0651fc442c4fdba8e.css" title="light">
39
+ <link integrity="" rel="stylesheet" href="assets/vendor-733135cd6cbca8126c6fa223d63a5bf3.css">
40
+ <link integrity="" rel="stylesheet" href="assets/ghost-647c9a79282265a4d29bf273c44f72c0.css" title="light">
41
41
 
42
42
 
43
43
  </head>
@@ -53,9 +53,9 @@
53
53
 
54
54
  <div id="ember-basic-dropdown-wormhole"></div>
55
55
 
56
- <script src="assets/vendor-52613f40d62355e9ac64cbfa211169bb.js"></script>
57
- <script src="assets/chunk.579.65e09dd89eec70d059a0.js"></script>
58
- <script src="assets/chunk.143.b51e90c24c7efd3fbc00.js"></script>
59
- <script src="assets/ghost-0526c96b20843697927c1d06a9010197.js"></script>
56
+ <script src="assets/vendor-ab4b5dfdf8b86f24d726115ac7de0980.js"></script>
57
+ <script src="assets/chunk.763.9a285d7351e1f4415f8d.js"></script>
58
+ <script src="assets/chunk.143.e96aad00fdf7196692c7.js"></script>
59
+ <script src="assets/ghost-3203510c519d3195f1e71a34e9eecc59.js"></script>
60
60
  </body>
61
61
  </html>
@@ -22,6 +22,18 @@ EventRegistry = function () {
22
22
 
23
23
  util.inherits(EventRegistry, events.EventEmitter);
24
24
 
25
+ /**
26
+ * This is method is semi-hack to make sure listeners are only registered once
27
+ * during the lifetime of the process. And example problem it solves is
28
+ * registering duplicate listeners between Ghost instance reboots when running tests.
29
+ * @param {String} eventName
30
+ * @param {String} listenerName named function name registered as a listener for the event
31
+ * @returns {Boolean}
32
+ */
33
+ EventRegistry.prototype.hasRegisteredListener = function (eventName, listenerName) {
34
+ return !!(this.listeners(eventName).find(listener => (listener.name === listenerName)));
35
+ };
36
+
25
37
  EventRegistryInstance = new EventRegistry();
26
38
  EventRegistryInstance.setMaxListeners(100);
27
39
 
@@ -5,12 +5,13 @@ const htmlToPlaintext = require('@tryghost/html-to-plaintext');
5
5
  const postEmailSerializer = require('../mega/post-email-serializer');
6
6
 
7
7
  class CommentsServiceEmails {
8
- constructor({config, logging, models, mailer, settingsCache, urlService, urlUtils}) {
8
+ constructor({config, logging, models, mailer, settingsCache, settingsHelpers, urlService, urlUtils}) {
9
9
  this.config = config;
10
10
  this.logging = logging;
11
11
  this.models = models;
12
12
  this.mailer = mailer;
13
13
  this.settingsCache = settingsCache;
14
+ this.settingsHelpers = settingsHelpers;
14
15
  this.urlService = urlService;
15
16
  this.urlUtils = urlUtils;
16
17
 
@@ -166,25 +167,8 @@ class CommentsServiceEmails {
166
167
  return siteDomain;
167
168
  }
168
169
 
169
- get membersAddress() {
170
- // TODO: get from address of default newsletter?
171
- return `noreply@${this.siteDomain}`;
172
- }
173
-
174
- // TODO: duplicated from services/members/config - exrtact to settings?
175
- get supportAddress() {
176
- const supportAddress = this.settingsCache.get('members_support_address') || 'noreply';
177
-
178
- // Any fromAddress without domain uses site domain, like default setting `noreply`
179
- if (supportAddress.indexOf('@') < 0) {
180
- return `${supportAddress}@${this.siteDomain}`;
181
- }
182
-
183
- return supportAddress;
184
- }
185
-
186
170
  get notificationFromAddress() {
187
- return this.supportAddress || this.membersAddress;
171
+ return this.settingsHelpers.getMembersSupportAddress();
188
172
  }
189
173
 
190
174
  extractInitials(name = '') {
@@ -14,6 +14,7 @@ class CommentsServiceWrapper {
14
14
  const urlUtils = require('../../../shared/url-utils');
15
15
  const membersService = require('../members');
16
16
  const db = require('../../data/db');
17
+ const settingsHelpers = require('../settings-helpers');
17
18
 
18
19
  this.api = new CommentsService({
19
20
  config,
@@ -21,6 +22,7 @@ class CommentsServiceWrapper {
21
22
  models,
22
23
  mailer,
23
24
  settingsCache,
25
+ settingsHelpers,
24
26
  urlService,
25
27
  urlUtils,
26
28
  contentGating: membersService.contentGating
@@ -15,7 +15,7 @@ const messages = {
15
15
  };
16
16
 
17
17
  class CommentsService {
18
- constructor({config, logging, models, mailer, settingsCache, urlService, urlUtils, contentGating}) {
18
+ constructor({config, logging, models, mailer, settingsCache, settingsHelpers, urlService, urlUtils, contentGating}) {
19
19
  /** @private */
20
20
  this.models = models;
21
21
 
@@ -33,6 +33,7 @@ class CommentsService {
33
33
  models,
34
34
  mailer,
35
35
  settingsCache,
36
+ settingsHelpers,
36
37
  urlService,
37
38
  urlUtils
38
39
  });
@@ -248,7 +248,14 @@ const serialize = async (postModel, newsletter, options = {isBrowserPreview: fal
248
248
  const momentDate = post.published_at ? moment(post.published_at) : moment();
249
249
  post.published_at = momentDate.tz(timezone).format('DD MMM YYYY');
250
250
 
251
- post.authors = post.authors && post.authors.map(author => author.name).join(', ');
251
+ if (post.authors) {
252
+ if (post.authors.length <= 2) {
253
+ post.authors = post.authors.map(author => author.name).join(' & ');
254
+ } else if (post.authors.length > 2) {
255
+ post.authors = `${post.authors[0].name} & ${post.authors.length - 1} others`;
256
+ }
257
+ }
258
+
252
259
  if (post.posts_meta) {
253
260
  post.email_subject = post.posts_meta.email_subject;
254
261
  }
@@ -28,9 +28,10 @@ const sanitizeKeys = (obj, keys) => {
28
28
  module.exports = ({post, site, newsletter, templateSettings}) => {
29
29
  const date = new Date();
30
30
  const hasFeatureImageCaption = templateSettings.showFeatureImage && post.feature_image && post.feature_image_caption;
31
- const cleanPost = sanitizeKeys(post, ['title', 'excerpt', 'html', 'feature_image_alt', 'feature_image_caption']);
31
+ const cleanPost = sanitizeKeys(post, ['title', 'excerpt', 'authors', 'feature_image_alt', 'feature_image_caption']);
32
32
  const cleanSite = sanitizeKeys(site, ['title']);
33
33
  const cleanNewsletter = sanitizeKeys(newsletter, ['name']);
34
+
34
35
  return `<!doctype html>
35
36
  <html>
36
37
 
@@ -1,101 +1,40 @@
1
- const errors = require('@tryghost/errors');
2
1
  const logging = require('@tryghost/logging');
3
- const tpl = require('@tryghost/tpl');
4
2
  const {URL} = require('url');
5
3
  const crypto = require('crypto');
6
4
  const createKeypair = require('keypair');
7
5
 
8
- const messages = {
9
- incorrectKeyType: 'type must be one of "direct" or "connect".'
10
- };
11
-
12
6
  class MembersConfigProvider {
13
7
  /**
14
8
  * @param {object} options
15
9
  * @param {{get: (key: string) => any}} options.settingsCache
16
- * @param {{get: (key: string) => any}} options.config
10
+ * @param {{getDefaultEmailDomain(): string, getMembersSupportAddress(): string, isStripeConnected(): boolean}} options.settingsHelpers
17
11
  * @param {any} options.urlUtils
18
12
  */
19
- constructor(options) {
20
- this._settingsCache = options.settingsCache;
21
- this._config = options.config;
22
- this._urlUtils = options.urlUtils;
13
+ constructor({settingsCache, settingsHelpers, urlUtils}) {
14
+ this._settingsCache = settingsCache;
15
+ this._settingsHelpers = settingsHelpers;
16
+ this._urlUtils = urlUtils;
23
17
  }
24
18
 
25
- /**
26
- * @private
27
- */
28
- _getDomain() {
29
- const url = this._urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
30
- const domain = (url && url[1]) || '';
31
- if (domain.startsWith('www.')) {
32
- return domain.replace(/^(www)\.(?=[^/]*\..{2,5})/, '');
33
- }
34
- return domain;
19
+ get defaultEmailDomain() {
20
+ return this._settingsHelpers.getDefaultEmailDomain();
35
21
  }
36
22
 
37
23
  getEmailFromAddress() {
38
24
  // Individual from addresses are set per newsletter - this is the fallback address
39
- return `noreply@${this._getDomain()}`;
25
+ return `noreply@${this.defaultEmailDomain}`;
40
26
  }
41
27
 
42
28
  getEmailSupportAddress() {
43
- const supportAddress = this._settingsCache.get('members_support_address') || 'noreply';
44
-
45
- // Any fromAddress without domain uses site domain, like default setting `noreply`
46
- if (supportAddress.indexOf('@') < 0) {
47
- return `${supportAddress}@${this._getDomain()}`;
48
- }
49
- return supportAddress;
29
+ return this._settingsHelpers.getMembersSupportAddress();
50
30
  }
51
31
 
52
32
  getAuthEmailFromAddress() {
53
- return this.getEmailSupportAddress() || this.getEmailFromAddress();
54
- }
55
-
56
- /**
57
- * @param {'direct' | 'connect'} type - The "type" of keys to fetch from settings
58
- * @returns {{publicKey: string, secretKey: string} | null}
59
- */
60
- getStripeKeys(type) {
61
- if (type !== 'direct' && type !== 'connect') {
62
- throw new errors.IncorrectUsageError({message: tpl(messages.incorrectKeyType)});
63
- }
64
-
65
- const secretKey = this._settingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}secret_key`);
66
- const publicKey = this._settingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}publishable_key`);
67
-
68
- if (!secretKey || !publicKey) {
69
- return null;
70
- }
71
-
72
- return {
73
- secretKey,
74
- publicKey
75
- };
76
- }
77
-
78
- /**
79
- * @returns {{publicKey: string, secretKey: string} | null}
80
- */
81
- getActiveStripeKeys() {
82
- const stripeDirect = this._config.get('stripeDirect');
83
-
84
- if (stripeDirect) {
85
- return this.getStripeKeys('direct');
86
- }
87
-
88
- const connectKeys = this.getStripeKeys('connect');
89
-
90
- if (!connectKeys) {
91
- return this.getStripeKeys('direct');
92
- }
93
-
94
- return connectKeys;
33
+ return this.getEmailSupportAddress();
95
34
  }
96
35
 
97
36
  isStripeConnected() {
98
- return this.getActiveStripeKeys() !== null;
37
+ return this._settingsHelpers.isStripeConnected();
99
38
  }
100
39
 
101
40
  getAuthSecret() {
@@ -3,6 +3,7 @@ const logging = require('@tryghost/logging');
3
3
  const membersService = require('./service');
4
4
  const models = require('../../models');
5
5
  const urlUtils = require('../../../shared/url-utils');
6
+ const spamPrevention = require('../../web/shared/middleware/api/spam-prevention');
6
7
  const {formattedMemberResponse} = require('./utils');
7
8
 
8
9
  // @TODO: This piece of middleware actually belongs to the frontend, not to the member app
@@ -155,6 +156,7 @@ const createSessionFromMagicLink = async function (req, res, next) {
155
156
 
156
157
  try {
157
158
  const member = await membersService.ssr.exchangeTokenForSession(req, res);
159
+ spamPrevention.membersAuth().reset(req.ip, `${member.email}login`);
158
160
  const subscriptions = member && member.subscriptions || [];
159
161
 
160
162
  const action = req.query.action;
@@ -20,6 +20,7 @@ const VerificationTrigger = require('@tryghost/verification-trigger');
20
20
  const DomainEvents = require('@tryghost/domain-events');
21
21
  const {LastSeenAtUpdater} = require('@tryghost/members-events-service');
22
22
  const DatabaseInfo = require('@tryghost/database-info');
23
+ const settingsHelpers = require('../settings-helpers');
23
24
 
24
25
  const messages = {
25
26
  noLiveKeysInDevelopment: 'Cannot use live stripe keys in development. Please restart in production mode.',
@@ -30,7 +31,7 @@ const messages = {
30
31
  const ghostMailer = new GhostMailer();
31
32
 
32
33
  const membersConfig = new MembersConfigProvider({
33
- config,
34
+ settingsHelpers,
34
35
  settingsCache,
35
36
  urlUtils
36
37
  });
@@ -2,13 +2,9 @@
2
2
  * Settings Lib
3
3
  * A collection of utilities for handling settings including a cache
4
4
  */
5
- const errors = require('@tryghost/errors');
6
- const tpl = require('@tryghost/tpl');
7
-
8
5
  const events = require('../../lib/common/events');
9
6
  const models = require('../../models');
10
7
  const labs = require('../../../shared/labs');
11
- const config = require('../../../shared/config');
12
8
  const adapterManager = require('../adapter-manager');
13
9
  const SettingsCache = require('../../../shared/settings-cache');
14
10
  const SettingsBREADService = require('./settings-bread-service');
@@ -18,10 +14,7 @@ const SingleUseTokenProvider = require('../members/SingleUseTokenProvider');
18
14
  const urlUtils = require('../../../shared/url-utils');
19
15
 
20
16
  const ObjectId = require('bson-objectid');
21
-
22
- const messages = {
23
- incorrectKeyType: 'type must be one of "direct" or "connect".'
24
- };
17
+ const settingsHelpers = require('../settings-helpers');
25
18
 
26
19
  const MAGIC_LINK_TOKEN_VALIDITY = 24 * 60 * 60 * 1000;
27
20
 
@@ -79,76 +72,16 @@ module.exports = {
79
72
  SettingsCache.reset(events);
80
73
  },
81
74
 
82
- isMembersEnabled() {
83
- return SettingsCache.get('members_signup_access') !== 'none';
84
- },
85
-
86
- isMembersInviteOnly() {
87
- return SettingsCache.get('members_signup_access') === 'invite';
88
- },
89
-
90
- /**
91
- * @param {'direct' | 'connect'} type - The "type" of keys to fetch from settings
92
- * @returns {{publicKey: string, secretKey: string} | null}
93
- */
94
- getStripeKeys(type) {
95
- if (type !== 'direct' && type !== 'connect') {
96
- throw new errors.IncorrectUsageError({message: tpl(messages.incorrectKeyType)});
97
- }
98
-
99
- const secretKey = SettingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}secret_key`);
100
- const publicKey = SettingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}publishable_key`);
101
-
102
- if (!secretKey || !publicKey) {
103
- return null;
104
- }
105
-
106
- return {
107
- secretKey,
108
- publicKey
109
- };
110
- },
111
-
112
- /**
113
- * @returns {{publicKey: string, secretKey: string} | null}
114
- */
115
- getActiveStripeKeys() {
116
- const stripeDirect = config.get('stripeDirect');
117
-
118
- if (stripeDirect) {
119
- return this.getStripeKeys('direct');
120
- }
121
-
122
- const connectKeys = this.getStripeKeys('connect');
123
-
124
- if (!connectKeys) {
125
- return this.getStripeKeys('direct');
126
- }
127
-
128
- return connectKeys;
129
- },
130
-
131
- arePaidMembersEnabled() {
132
- return this.isMembersEnabled() && this.getActiveStripeKeys() !== null;
133
- },
134
-
135
- getFirstpromoterId() {
136
- if (!SettingsCache.get('firstpromoter')) {
137
- return null;
138
- }
139
- return SettingsCache.get('firstpromoter_id');
140
- },
141
-
142
75
  /**
143
76
  *
144
77
  */
145
78
  getCalculatedFields() {
146
79
  const fields = [];
147
80
 
148
- fields.push(new CalculatedField({key: 'members_enabled', type: 'boolean', group: 'members', fn: this.isMembersEnabled.bind(this), dependents: ['members_signup_access']}));
149
- fields.push(new CalculatedField({key: 'members_invite_only', type: 'boolean', group: 'members', fn: this.isMembersInviteOnly.bind(this), dependents: ['members_signup_access']}));
150
- fields.push(new CalculatedField({key: 'paid_members_enabled', type: 'boolean', group: 'members', fn: this.arePaidMembersEnabled.bind(this), dependents: ['members_signup_access', 'stripe_secret_key', 'stripe_publishable_key', 'stripe_connect_secret_key', 'stripe_connect_publishable_key']}));
151
- fields.push(new CalculatedField({key: 'firstpromoter_account', type: 'string', group: 'firstpromoter', fn: this.getFirstpromoterId.bind(this), dependents: ['firstpromoter', 'firstpromoter_id']}));
81
+ fields.push(new CalculatedField({key: 'members_enabled', type: 'boolean', group: 'members', fn: settingsHelpers.isMembersEnabled.bind(settingsHelpers), dependents: ['members_signup_access']}));
82
+ fields.push(new CalculatedField({key: 'members_invite_only', type: 'boolean', group: 'members', fn: settingsHelpers.isMembersInviteOnly.bind(settingsHelpers), dependents: ['members_signup_access']}));
83
+ fields.push(new CalculatedField({key: 'paid_members_enabled', type: 'boolean', group: 'members', fn: settingsHelpers.arePaidMembersEnabled.bind(settingsHelpers), dependents: ['members_signup_access', 'stripe_secret_key', 'stripe_publishable_key', 'stripe_connect_secret_key', 'stripe_connect_publishable_key']}));
84
+ fields.push(new CalculatedField({key: 'firstpromoter_account', type: 'string', group: 'firstpromoter', fn: settingsHelpers.getFirstpromoterId.bind(settingsHelpers), dependents: ['firstpromoter', 'firstpromoter_id']}));
152
85
 
153
86
  return fields;
154
87
  },
@@ -0,0 +1,6 @@
1
+ const settingsCache = require('../../../shared/settings-cache');
2
+ const urlUtils = require('../../../shared/url-utils');
3
+ const config = require('../../../shared/config');
4
+ const SettingsHelpers = require('./settings-helpers');
5
+
6
+ module.exports = new SettingsHelpers({settingsCache, urlUtils, config});
@@ -0,0 +1,99 @@
1
+ const tpl = require('@tryghost/tpl');
2
+ const errors = require('@tryghost/errors');
3
+
4
+ const messages = {
5
+ incorrectKeyType: 'type must be one of "direct" or "connect".'
6
+ };
7
+
8
+ class SettingsHelpers {
9
+ constructor({settingsCache, urlUtils, config}) {
10
+ this.settingsCache = settingsCache;
11
+ this.urlUtils = urlUtils;
12
+ this.config = config;
13
+ }
14
+
15
+ isMembersEnabled() {
16
+ return this.settingsCache.get('members_signup_access') !== 'none';
17
+ }
18
+
19
+ isMembersInviteOnly() {
20
+ return this.settingsCache.get('members_signup_access') === 'invite';
21
+ }
22
+
23
+ /**
24
+ * @param {'direct' | 'connect'} type - The "type" of keys to fetch from settings
25
+ * @returns {{publicKey: string, secretKey: string} | null}
26
+ */
27
+ getStripeKeys(type) {
28
+ if (type !== 'direct' && type !== 'connect') {
29
+ throw new errors.IncorrectUsageError({message: tpl(messages.incorrectKeyType)});
30
+ }
31
+
32
+ const secretKey = this.settingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}secret_key`);
33
+ const publicKey = this.settingsCache.get(`stripe_${type === 'connect' ? 'connect_' : ''}publishable_key`);
34
+
35
+ if (!secretKey || !publicKey) {
36
+ return null;
37
+ }
38
+
39
+ return {
40
+ secretKey,
41
+ publicKey
42
+ };
43
+ }
44
+
45
+ /**
46
+ * @returns {{publicKey: string, secretKey: string} | null}
47
+ */
48
+ getActiveStripeKeys() {
49
+ const stripeDirect = this.config.get('stripeDirect');
50
+
51
+ if (stripeDirect) {
52
+ return this.getStripeKeys('direct');
53
+ }
54
+
55
+ const connectKeys = this.getStripeKeys('connect');
56
+
57
+ if (!connectKeys) {
58
+ return this.getStripeKeys('direct');
59
+ }
60
+
61
+ return connectKeys;
62
+ }
63
+
64
+ isStripeConnected() {
65
+ return this.getActiveStripeKeys() !== null;
66
+ }
67
+
68
+ arePaidMembersEnabled() {
69
+ return this.isMembersEnabled() && this.isStripeConnected();
70
+ }
71
+
72
+ getFirstpromoterId() {
73
+ if (!this.settingsCache.get('firstpromoter')) {
74
+ return null;
75
+ }
76
+ return this.settingsCache.get('firstpromoter_id');
77
+ }
78
+
79
+ getDefaultEmailDomain() {
80
+ const url = this.urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
81
+ const domain = (url && url[1]) || '';
82
+ if (domain.startsWith('www.')) {
83
+ return domain.substring('www.'.length);
84
+ }
85
+ return domain;
86
+ }
87
+
88
+ getMembersSupportAddress() {
89
+ const supportAddress = this.settingsCache.get('members_support_address') || 'noreply';
90
+
91
+ // Any fromAddress without domain uses site domain, like default setting `noreply`
92
+ if (supportAddress.indexOf('@') < 0) {
93
+ return `${supportAddress}@${this.getDefaultEmailDomain()}`;
94
+ }
95
+ return supportAddress;
96
+ }
97
+ }
98
+
99
+ module.exports = SettingsHelpers;
@@ -2,22 +2,20 @@ class StaffServiceWrapper {
2
2
  init() {
3
3
  const StaffService = require('@tryghost/staff-service');
4
4
 
5
- const config = require('../../../shared/config');
6
5
  const logging = require('@tryghost/logging');
7
6
  const models = require('../../models');
8
7
  const {GhostMailer} = require('../mail');
9
8
  const mailer = new GhostMailer();
10
9
  const settingsCache = require('../../../shared/settings-cache');
11
- const urlService = require('../url');
12
10
  const urlUtils = require('../../../shared/url-utils');
11
+ const settingsHelpers = require('../settings-helpers');
13
12
 
14
13
  this.api = new StaffService({
15
- config,
16
14
  logging,
17
15
  models,
18
16
  mailer,
17
+ settingsHelpers,
19
18
  settingsCache,
20
- urlService,
21
19
  urlUtils
22
20
  });
23
21
  }
@@ -16,7 +16,7 @@ const messages = {
16
16
  */
17
17
 
18
18
  module.exports = {
19
- getConfig(settings, config, urlUtils) {
19
+ getConfig({config, urlUtils, settingsHelpers}) {
20
20
  /**
21
21
  * @returns {StripeURLConfig}
22
22
  */
@@ -41,43 +41,7 @@ module.exports = {
41
41
  };
42
42
  }
43
43
 
44
- /**
45
- * @param {'direct' | 'connect'} type - The "type" of keys to fetch from settings
46
- * @returns {{publicKey: string, secretKey: string} | null}
47
- */
48
- function getStripeKeys(type) {
49
- const secretKey = settings.get(`stripe_${type === 'connect' ? 'connect_' : ''}secret_key`);
50
- const publicKey = settings.get(`stripe_${type === 'connect' ? 'connect_' : ''}publishable_key`);
51
-
52
- if (!secretKey || !publicKey) {
53
- return null;
54
- }
55
-
56
- return {
57
- secretKey,
58
- publicKey
59
- };
60
- }
61
-
62
- /**
63
- * @returns {{publicKey: string, secretKey: string} | null}
64
- */
65
- function getActiveStripeKeys() {
66
- const stripeDirect = config.get('stripeDirect');
67
-
68
- if (stripeDirect) {
69
- return getStripeKeys('direct');
70
- }
71
-
72
- const connectKeys = getStripeKeys('connect');
73
-
74
- if (!connectKeys) {
75
- return getStripeKeys('direct');
76
- }
77
-
78
- return connectKeys;
79
- }
80
- const keys = getActiveStripeKeys();
44
+ const keys = settingsHelpers.getActiveStripeKeys();
81
45
  if (!keys) {
82
46
  return null;
83
47
  }
@@ -8,9 +8,10 @@ const urlUtils = require('../../../shared/url-utils');
8
8
  const events = require('../../lib/common/events');
9
9
  const models = require('../../models');
10
10
  const {getConfig} = require('./config');
11
+ const settingsHelpers = require('../settings-helpers');
11
12
 
12
13
  async function configureApi() {
13
- const cfg = getConfig(settings, config, urlUtils);
14
+ const cfg = getConfig({settingsHelpers, config, urlUtils});
14
15
  if (cfg) {
15
16
  cfg.testEnv = process.env.NODE_ENV.startsWith('test');
16
17
  await module.exports.configure(cfg);