ghost 5.119.2 → 5.120.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 (130) hide show
  1. package/components/tryghost-i18n-5.120.0.tgz +0 -0
  2. package/core/boot.js +0 -2
  3. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +7555 -7216
  4. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-60ce658c.mjs → CodeEditorView-1c5b0683.mjs} +2 -2
  5. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +2 -2
  6. package/core/built/admin/assets/admin-x-settings/{index-8480baa8.mjs → index-14e518a7.mjs} +3 -3
  7. package/core/built/admin/assets/admin-x-settings/{index-a2648c61.mjs → index-fc9f985b.mjs} +2 -2
  8. package/core/built/admin/assets/admin-x-settings/{modals-6900c1d5.mjs → modals-15bc6a0f.mjs} +7192 -6656
  9. package/core/built/admin/assets/{chunk.137.c9bf40f01afeeadb4660.js → chunk.383.25fca2f09b4896656125.js} +76 -59
  10. package/core/built/admin/assets/chunk.524.1657b12c0ab25dd9fb79.js +28 -0
  11. package/core/built/admin/assets/{chunk.582.98a820cbc4bb65f2e685.js → chunk.582.09869b1f1a3cc0ab81f6.js} +19 -26
  12. package/core/built/admin/assets/{ghost-843572e9507d099162ae744d791daba1.js → ghost-b3b44421acca3b3eec76bfbb6ba0e81b.js} +3 -3
  13. package/core/built/admin/assets/koenig-lexical/koenig-lexical.js +12578 -12352
  14. package/core/built/admin/assets/koenig-lexical/koenig-lexical.umd.js +423 -211
  15. package/core/built/admin/assets/posts/posts.js +13680 -13671
  16. package/core/built/admin/assets/stats/stats.js +16457 -16635
  17. package/core/built/admin/assets/{vendor-8f805740fee4db959a5b2119001a56b1.js → vendor-4ce6d282a2a00fe486a0951e0591da19.js} +11 -9
  18. package/core/built/admin/index.html +5 -5
  19. package/core/frontend/helpers/match.js +6 -0
  20. package/core/frontend/services/routing/ParentRouter.js +1 -1
  21. package/core/frontend/services/routing/controllers/email-post.js +0 -2
  22. package/core/frontend/services/routing/controllers/previews.js +0 -3
  23. package/core/frontend/web/middleware/frontend-caching.js +2 -2
  24. package/core/server/api/endpoints/authentication.js +37 -73
  25. package/core/server/api/endpoints/authors-public.js +8 -9
  26. package/core/server/api/endpoints/db.js +34 -35
  27. package/core/server/api/endpoints/emails.js +8 -10
  28. package/core/server/api/endpoints/integrations.js +20 -18
  29. package/core/server/api/endpoints/invites.js +8 -10
  30. package/core/server/api/endpoints/labels.js +19 -23
  31. package/core/server/api/endpoints/notifications.js +3 -4
  32. package/core/server/api/endpoints/pages-public.js +8 -10
  33. package/core/server/api/endpoints/pages.js +14 -18
  34. package/core/server/api/endpoints/posts-public.js +8 -10
  35. package/core/server/api/endpoints/posts.js +6 -8
  36. package/core/server/api/endpoints/previews.js +8 -10
  37. package/core/server/api/endpoints/redirects.js +7 -8
  38. package/core/server/api/endpoints/schedules.js +5 -7
  39. package/core/server/api/endpoints/slugs.js +7 -9
  40. package/core/server/api/endpoints/snippets.js +16 -20
  41. package/core/server/api/endpoints/tags-public.js +8 -10
  42. package/core/server/api/endpoints/tags.js +19 -23
  43. package/core/server/api/endpoints/themes.js +6 -8
  44. package/core/server/api/endpoints/users.js +31 -36
  45. package/core/server/api/endpoints/utils/permissions.js +10 -10
  46. package/core/server/api/endpoints/utils/serializers/output/roles.js +9 -10
  47. package/core/server/api/endpoints/utils/validators/input/images.js +43 -52
  48. package/core/server/api/endpoints/utils/validators/input/invites.js +6 -8
  49. package/core/server/api/endpoints/webhooks.js +38 -42
  50. package/core/server/data/migrations/versions/5.120/2025-05-07-14-57-38-add-newsletters-button-corners-column.js +8 -0
  51. package/core/server/data/migrations/versions/5.120/2025-05-13-17-36-56-add-newsletters-button-style-column.js +8 -0
  52. package/core/server/data/migrations/versions/5.120/2025-05-14-20-00-15-add-newsletters-setting-columns.js +22 -0
  53. package/core/server/data/schema/schema.js +6 -1
  54. package/core/server/lib/image/Gravatar.js +12 -13
  55. package/core/server/lib/lexical.js +3 -1
  56. package/core/server/models/newsletter.js +6 -1
  57. package/core/server/services/api-version-compatibility/index.js +1 -33
  58. package/core/server/services/auth/session/emails/signin.js +3 -3
  59. package/core/server/services/email-address/EmailAddressParser.js +52 -0
  60. package/core/server/services/email-address/EmailAddressParser.js.d.ts +13 -0
  61. package/core/server/services/email-address/EmailAddressService.js +142 -0
  62. package/core/server/services/email-address/EmailAddressService.ts +183 -0
  63. package/core/server/services/email-address/EmailAddressServiceWrapper.js +2 -4
  64. package/core/server/services/email-analytics/EmailAnalyticsService.js +1 -1
  65. package/core/server/services/email-analytics/EmailAnalyticsServiceWrapper.js +2 -1
  66. package/core/server/services/email-service/BatchSendingService.js +703 -0
  67. package/core/server/services/email-service/EmailBodyCache.js +20 -0
  68. package/core/server/services/email-service/EmailController.js +94 -0
  69. package/core/server/services/email-service/EmailEventProcessor.js +267 -0
  70. package/core/server/services/email-service/EmailEventStorage.js +187 -0
  71. package/core/server/services/email-service/EmailRenderer.js +1263 -0
  72. package/core/server/services/email-service/EmailSegmenter.js +74 -0
  73. package/core/server/services/email-service/EmailService.js +310 -0
  74. package/core/server/services/email-service/EmailServiceWrapper.js +9 -2
  75. package/core/server/services/email-service/MailgunEmailProvider.js +191 -0
  76. package/core/server/services/email-service/SendingService.js +173 -0
  77. package/core/server/services/email-service/email-templates/partials/feedback-button.hbs +7 -0
  78. package/core/server/services/email-service/email-templates/partials/latest-posts.hbs +39 -0
  79. package/core/server/services/email-service/email-templates/partials/paywall.hbs +20 -0
  80. package/core/server/services/email-service/email-templates/partials/styles.hbs +2348 -0
  81. package/core/server/services/email-service/email-templates/template.hbs +238 -0
  82. package/core/server/services/email-service/events/EmailBouncedEvent.js +63 -0
  83. package/core/server/services/email-service/events/EmailDeliveredEvent.js +49 -0
  84. package/core/server/services/email-service/events/EmailOpenedEvent.js +49 -0
  85. package/core/server/services/email-service/events/EmailTemporaryBouncedEvent.js +63 -0
  86. package/core/server/services/email-service/events/EmailUnsubscribedEvent.js +42 -0
  87. package/core/server/services/email-service/events/SpamComplaintEvent.js +42 -0
  88. package/core/server/services/email-service/helpers/register-helpers.js +59 -0
  89. package/core/server/services/email-suppression-list/MailgunEmailSuppressionList.js +2 -1
  90. package/core/server/services/explore-ping/index.js +2 -1
  91. package/core/server/services/mail/GhostMailer.js +1 -1
  92. package/core/server/services/media-inliner/ExternalMediaInliner.js +2 -1
  93. package/core/server/services/members/api.js +15 -15
  94. package/core/server/services/members/emails/signin.js +4 -4
  95. package/core/server/services/members/emails/signup-paid.js +3 -4
  96. package/core/server/services/members/emails/signup.js +3 -3
  97. package/core/server/services/members/emails/subscribe.js +3 -3
  98. package/core/server/services/members/members-api/controllers/RouterController.js +50 -36
  99. package/core/server/services/members/members-api/repositories/MemberRepository.js +92 -92
  100. package/core/server/services/members-events/LastSeenAtUpdater.js +1 -1
  101. package/core/server/services/settings-helpers/SettingsHelpers.js +1 -1
  102. package/core/server/services/staff/StaffServiceEmails.js +1 -1
  103. package/core/server/services/stats/PostsStatsService.js +28 -7
  104. package/core/server/web/api/app.js +0 -1
  105. package/core/server/web/api/endpoints/admin/app.js +0 -2
  106. package/core/server/web/api/endpoints/content/app.js +0 -2
  107. package/core/server/web/api/middleware/upload.js +2 -2
  108. package/core/shared/custom-theme-settings-cache/CustomThemeSettingsService.js +2 -1
  109. package/package.json +39 -97
  110. package/tsconfig.tsbuildinfo +1 -1
  111. package/yarn.lock +385 -517
  112. package/components/tryghost-api-framework-5.119.2.tgz +0 -0
  113. package/components/tryghost-custom-fonts-5.119.2.tgz +0 -0
  114. package/components/tryghost-domain-events-5.119.2.tgz +0 -0
  115. package/components/tryghost-email-addresses-5.119.2.tgz +0 -0
  116. package/components/tryghost-email-service-5.119.2.tgz +0 -0
  117. package/components/tryghost-html-to-plaintext-5.119.2.tgz +0 -0
  118. package/components/tryghost-i18n-5.119.2.tgz +0 -0
  119. package/components/tryghost-job-manager-5.119.2.tgz +0 -0
  120. package/components/tryghost-members-csv-5.119.2.tgz +0 -0
  121. package/components/tryghost-mw-error-handler-5.119.2.tgz +0 -0
  122. package/components/tryghost-mw-vhost-5.119.2.tgz +0 -0
  123. package/components/tryghost-prometheus-metrics-5.119.2.tgz +0 -0
  124. package/components/tryghost-security-5.119.2.tgz +0 -0
  125. package/core/built/admin/assets/chunk.524.b8545af3bb714bc4f820.js +0 -35
  126. package/core/server/services/api-version-compatibility/APIVersionCompatibilityService.js +0 -99
  127. package/core/server/services/api-version-compatibility/VersionNotificationsDataService.js +0 -80
  128. package/core/server/services/api-version-compatibility/extract-api-key.js +0 -57
  129. package/core/server/services/api-version-compatibility/mw-api-version-mismatch.js +0 -31
  130. /package/core/built/admin/assets/{chunk.137.c9bf40f01afeeadb4660.js.LICENSE.txt → chunk.383.25fca2f09b4896656125.js.LICENSE.txt} +0 -0
@@ -1,35 +0,0 @@
1
- var __ember_auto_import__;(()=>{var e,r={9589:(e,r,t)=>{const n=t(68125),s=t(78695),o=["id","email","name","note","subscribed_to_emails","complimentary_plan","stripe_customer_id","created_at","deleted_at","labels","tiers"]
2
- e.exports=(e,r=o.slice())=>{r=r.map((e=>"subscribed"===e?"subscribed_to_emails":e))
3
- const t=e.map((e=>{e.error&&!r.includes("error")&&r.push("error")
4
- let t=""
5
- "string"==typeof e.labels?t=e.labels:Array.isArray(e.labels)&&(t=e.labels.map((e=>"string"==typeof e?e:e.name)).join(","))
6
- let s=""
7
- return Array.isArray(e.tiers)&&(s=e.tiers.map((e=>e.name)).join(",")),{id:e.id,email:e.email,name:e.name,note:e.note,subscribed_to_emails:"subscribed"in e?e.subscribed:e.subscribed_to_emails,complimentary_plan:e.comped||e.complimentary_plan,stripe_customer_id:n.get(e,"subscriptions[0].customer.id")||e.stripe_customer_id,created_at:e.created_at,deleted_at:e.deleted_at,labels:t,tiers:s,import_tier:e.import_tier||null,error:e.error||null}}))
8
- return s.unparse(t,{escapeFormulae:!0,columns:r})}},22964:function(e,r){window._eai_r=require,window._eai_d=define},26209:(e,r,t)=>{e.exports=function(){var e=_eai_d,r=_eai_r
9
- function n(e){return e&&e.__esModule?e:Object.assign({default:e},e)}window.emberAutoImportDynamic=function(e){return 1===arguments.length?r("_eai_dyn_"+e):r("_eai_dynt_"+e)(Array.prototype.slice.call(arguments,1))},window.emberAutoImportSync=function(e){return r("_eai_sync_"+e)(Array.prototype.slice.call(arguments,1))},e("@sentry/browser",[],(function(){return n(t(51294))})),e("@sentry/core",[],(function(){return n(t(16154))})),e("@sentry/integrations",[],(function(){return n(t(20080))})),e("@sentry/replay",[],(function(){return n(t(51633))})),e("@sentry/utils",[],(function(){return n(t(88414))})),e("@tryghost/color-utils",[],(function(){return n(t(86797))})),e("@tryghost/kg-clean-basic-html",[],(function(){return n(t(56035))})),e("@tryghost/kg-converters",[],(function(){return n(t(23075))})),e("@tryghost/limit-service",[],(function(){return n(t(55983))})),e("@tryghost/members-csv/lib/unparse",[],(function(){return n(t(9589))})),e("@tryghost/nql",[],(function(){return n(t(39365))})),e("@tryghost/nql-lang",[],(function(){return n(t(716))})),e("@tryghost/string",[],(function(){return n(t(96107))})),e("@tryghost/timezone-data",[],(function(){return n(t(27019))})),e("animejs/lib/anime.es.js",[],(function(){return n(t(62282))})),e("element-resize-detector",[],(function(){return n(t(29540))})),e("ember-assign-helper/helpers/assign",[],(function(){return n(t(31113))})),e("ember-css-transitions/modifiers/css-transition",["@ember/test-waiters"],(function(){return n(t(95895))})),e("ember-keyboard/helpers/if-key.js",[],(function(){return n(t(10530))})),e("ember-keyboard/helpers/on-key.js",[],(function(){return n(t(13692))})),e("ember-keyboard/modifiers/on-key.js",[],(function(){return n(t(40985))})),e("ember-keyboard/services/keyboard.js",[],(function(){return n(t(89697))})),e("ember-modifier",[],(function(){return n(t(37777))})),e("ember-moment/helpers/-base",[],(function(){return n(t(91366))})),e("ember-moment/helpers/is-after",[],(function(){return n(t(91461))})),e("ember-moment/helpers/is-before",[],(function(){return n(t(61e3))})),e("ember-moment/helpers/is-between",[],(function(){return n(t(447))})),e("ember-moment/helpers/is-same",[],(function(){return n(t(64193))})),e("ember-moment/helpers/is-same-or-after",[],(function(){return n(t(7916))})),e("ember-moment/helpers/is-same-or-before",[],(function(){return n(t(54351))})),e("ember-moment/helpers/moment",[],(function(){return n(t(41678))})),e("ember-moment/helpers/moment-add",[],(function(){return n(t(50080))})),e("ember-moment/helpers/moment-calendar",[],(function(){return n(t(96625))})),e("ember-moment/helpers/moment-diff",[],(function(){return n(t(85340))})),e("ember-moment/helpers/moment-duration",[],(function(){return n(t(42967))})),e("ember-moment/helpers/moment-format",[],(function(){return n(t(10536))})),e("ember-moment/helpers/moment-from",[],(function(){return n(t(50727))})),e("ember-moment/helpers/moment-from-now",[],(function(){return n(t(706))})),e("ember-moment/helpers/moment-subtract",[],(function(){return n(t(54651))})),e("ember-moment/helpers/moment-to",[],(function(){return n(t(84818))})),e("ember-moment/helpers/moment-to-date",[],(function(){return n(t(81183))})),e("ember-moment/helpers/moment-to-now",[],(function(){return n(t(17083))})),e("ember-moment/helpers/now",[],(function(){return n(t(34980))})),e("ember-moment/helpers/unix",[],(function(){return n(t(79272))})),e("ember-moment/helpers/utc",[],(function(){return n(t(36022))})),e("ember-moment/services/moment",[],(function(){return n(t(39879))})),e("fast-deep-equal",[],(function(){return n(t(25383))})),e("flexsearch",[],(function(){return n(t(12248))})),e("focus-trap",[],(function(){return n(t(39632))})),e("intersection-observer-admin",[],(function(){return n(t(21431))})),e("jose",[],(function(){return n(t(82765))})),e("microdiff",[],(function(){return n(t(59086))})),e("moment-timezone",[],(function(){return n(t(41101))})),e("papaparse",[],(function(){return n(t(78695))})),e("raf-pool",[],(function(){return n(t(60695))})),e("react",[],(function(){return n(t(72854))})),e("react-dom",[],(function(){return n(t(95303))})),e("react-dom/client",[],(function(){return n(t(70816))})),e("semver/functions/coerce",[],(function(){return n(t(18576))})),e("semver/functions/lt",[],(function(){return n(t(32817))})),e("semver/functions/parse",[],(function(){return n(t(47898))})),e("tooltip.js",[],(function(){return n(t(85557))})),e("tracked-built-ins",["ember-tracked-storage-polyfill"],(function(){return n(t(67708))})),e("validator",[],(function(){return n(t(26058))})),e("_eai_dyn_@sentry/browser",[],(function(){return Promise.resolve().then(t.bind(t,51294))}))}()},31048:()=>{},32186:e=>{"use strict"
10
- e.exports=require("@ember/test-waiters")},56857:(e,r,t)=>{var n={"./af":58547,"./af.js":58547,"./ar":28167,"./ar-dz":35298,"./ar-dz.js":35298,"./ar-kw":11314,"./ar-kw.js":11314,"./ar-ly":66455,"./ar-ly.js":66455,"./ar-ma":15998,"./ar-ma.js":15998,"./ar-sa":55388,"./ar-sa.js":55388,"./ar-tn":73358,"./ar-tn.js":73358,"./ar.js":28167,"./az":92367,"./az.js":92367,"./be":9161,"./be.js":9161,"./bg":359,"./bg.js":359,"./bm":32625,"./bm.js":32625,"./bn":52984,"./bn.js":52984,"./bo":87343,"./bo.js":87343,"./br":87948,"./br.js":87948,"./bs":88211,"./bs.js":88211,"./ca":34700,"./ca.js":34700,"./cs":27430,"./cs.js":27430,"./cv":55913,"./cv.js":55913,"./cy":16004,"./cy.js":16004,"./da":26839,"./da.js":26839,"./de":22131,"./de-at":6729,"./de-at.js":6729,"./de-ch":74743,"./de-ch.js":74743,"./de.js":22131,"./dv":14598,"./dv.js":14598,"./el":38737,"./el.js":38737,"./en-SG":94978,"./en-SG.js":94978,"./en-au":22606,"./en-au.js":22606,"./en-ca":60052,"./en-ca.js":60052,"./en-gb":17305,"./en-gb.js":17305,"./en-ie":76390,"./en-ie.js":76390,"./en-il":89549,"./en-il.js":89549,"./en-nz":67584,"./en-nz.js":67584,"./eo":24408,"./eo.js":24408,"./es":45644,"./es-do":21888,"./es-do.js":21888,"./es-us":23537,"./es-us.js":23537,"./es.js":45644,"./et":27257,"./et.js":27257,"./eu":57002,"./eu.js":57002,"./fa":90241,"./fa.js":90241,"./fi":74009,"./fi.js":74009,"./fo":81267,"./fo.js":81267,"./fr":71160,"./fr-ca":39433,"./fr-ca.js":39433,"./fr-ch":20130,"./fr-ch.js":20130,"./fr.js":71160,"./fy":20553,"./fy.js":20553,"./ga":18232,"./ga.js":18232,"./gd":33771,"./gd.js":33771,"./gl":99747,"./gl.js":99747,"./gom-latn":80289,"./gom-latn.js":80289,"./gu":148,"./gu.js":148,"./he":68247,"./he.js":68247,"./hi":39835,"./hi.js":39835,"./hr":69734,"./hr.js":69734,"./hu":40999,"./hu.js":40999,"./hy-am":95002,"./hy-am.js":95002,"./id":23021,"./id.js":23021,"./is":96232,"./is.js":96232,"./it":15581,"./it-ch":4809,"./it-ch.js":4809,"./it.js":15581,"./ja":45981,"./ja.js":45981,"./jv":12568,"./jv.js":12568,"./ka":17924,"./ka.js":17924,"./kk":1062,"./kk.js":1062,"./km":65456,"./km.js":65456,"./kn":15817,"./kn.js":15817,"./ko":45306,"./ko.js":45306,"./ku":39016,"./ku.js":39016,"./ky":71308,"./ky.js":71308,"./lb":67330,"./lb.js":67330,"./lo":18949,"./lo.js":18949,"./lt":58804,"./lt.js":58804,"./lv":47006,"./lv.js":47006,"./me":83346,"./me.js":83346,"./mi":630,"./mi.js":630,"./mk":88876,"./mk.js":88876,"./ml":86841,"./ml.js":86841,"./mn":93847,"./mn.js":93847,"./mr":57515,"./mr.js":57515,"./ms":51844,"./ms-my":44391,"./ms-my.js":44391,"./ms.js":51844,"./mt":81969,"./mt.js":81969,"./my":34982,"./my.js":34982,"./nb":41632,"./nb.js":41632,"./ne":81781,"./ne.js":81781,"./nl":14910,"./nl-be":72506,"./nl-be.js":72506,"./nl.js":14910,"./nn":12980,"./nn.js":12980,"./pa-in":33791,"./pa-in.js":33791,"./pl":1872,"./pl.js":1872,"./pt":9064,"./pt-br":85273,"./pt-br.js":85273,"./pt.js":9064,"./ro":63167,"./ro.js":63167,"./ru":28649,"./ru.js":28649,"./sd":14823,"./sd.js":14823,"./se":90672,"./se.js":90672,"./si":26244,"./si.js":26244,"./sk":40654,"./sk.js":40654,"./sl":44335,"./sl.js":44335,"./sq":79116,"./sq.js":79116,"./sr":60693,"./sr-cyrl":1436,"./sr-cyrl.js":1436,"./sr.js":60693,"./ss":51734,"./ss.js":51734,"./sv":37945,"./sv.js":37945,"./sw":41514,"./sw.js":41514,"./ta":1991,"./ta.js":1991,"./te":95011,"./te.js":95011,"./tet":19463,"./tet.js":19463,"./tg":43109,"./tg.js":43109,"./th":97144,"./th.js":97144,"./tl-ph":70401,"./tl-ph.js":70401,"./tlh":26678,"./tlh.js":26678,"./tr":28682,"./tr.js":28682,"./tzl":59084,"./tzl.js":59084,"./tzm":64307,"./tzm-latn":68869,"./tzm-latn.js":68869,"./tzm.js":64307,"./ug-cn":78812,"./ug-cn.js":78812,"./uk":25812,"./uk.js":25812,"./ur":25411,"./ur.js":25411,"./uz":59435,"./uz-latn":94589,"./uz-latn.js":94589,"./uz.js":59435,"./vi":50569,"./vi.js":50569,"./x-pseudo":85241,"./x-pseudo.js":85241,"./yo":96972,"./yo.js":96972,"./zh-cn":18422,"./zh-cn.js":18422,"./zh-hk":84106,"./zh-hk.js":84106,"./zh-tw":69362,"./zh-tw.js":69362}
11
- function s(e){var r=o(e)
12
- return t(r)}function o(e){if(!t.o(n,e)){var r=new Error("Cannot find module '"+e+"'")
13
- throw r.code="MODULE_NOT_FOUND",r}return n[e]}s.keys=function(){return Object.keys(n)},s.resolve=o,e.exports=s,s.id=56857},80032:e=>{"use strict"
14
- e.exports=require("ember-tracked-storage-polyfill")},86625:()=>{}},t={}
15
- function n(e){var s=t[e]
16
- if(void 0!==s)return s.exports
17
- var o=t[e]={id:e,loaded:!1,exports:{}}
18
- return r[e].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}n.m=r,n.c=t,e=[],n.O=(r,t,s,o)=>{if(!t){var i=1/0
19
- for(c=0;c<e.length;c++){for(var[t,s,o]=e[c],u=!0,m=0;m<t.length;m++)(!1&o||i>=o)&&Object.keys(n.O).every((e=>n.O[e](t[m])))?t.splice(m--,1):(u=!1,o<i&&(i=o))
20
- if(u){e.splice(c--,1)
21
- var a=s()
22
- void 0!==a&&(r=a)}}return r}o=o||0
23
- for(var c=e.length;c>0&&e[c-1][2]>o;c--)e[c]=e[c-1]
24
- e[c]=[t,s,o]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e
25
- return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:()=>{throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e={524:0}
26
- n.O.j=r=>0===e[r]
27
- var r=(r,t)=>{var s,o,[i,u,m]=t,a=0
28
- if(i.some((r=>0!==e[r]))){for(s in u)n.o(u,s)&&(n.m[s]=u[s])
29
- if(m)var c=m(n)}for(r&&r(t);a<i.length;a++)o=i[a],n.o(e,o)&&e[o]&&e[o][0](),e[o]=0
30
- return n.O(c)},t=globalThis.webpackChunk_ember_auto_import_=globalThis.webpackChunk_ember_auto_import_||[]
31
- t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),n.O(void 0,[137],(()=>n(n.s=22964)))
32
- var s=n.O(void 0,[137],(()=>n(n.s=26209)))
33
- s=n.O(s),__ember_auto_import__=s})()
34
-
35
- //# sourceMappingURL=chunk.524.b8545af3bb714bc4f820.map
@@ -1,99 +0,0 @@
1
- const path = require('path');
2
- const VersionNotificationsDataService = require('./VersionNotificationsDataService');
3
- const EmailContentGenerator = require('../lib/EmailContentGenerator');
4
-
5
- class APIVersionCompatibilityService {
6
- /**
7
- *
8
- * @param {Object} options
9
- * @param {Object} options.UserModel - ghost user model
10
- * @param {Object} options.ApiKeyModel - ghost api key model
11
- * @param {Object} options.settingsService - ghost settings service
12
- * @param {(Object: {subject: String, to: String, text: String, html: String}) => Promise<any>} options.sendEmail - email sending function
13
- * @param {Function} options.getSiteUrl
14
- * @param {Function} options.getSiteTitle
15
- */
16
- constructor({UserModel, ApiKeyModel, settingsService, sendEmail, getSiteUrl, getSiteTitle}) {
17
- this.sendEmail = sendEmail;
18
-
19
- this.versionNotificationsDataService = new VersionNotificationsDataService({
20
- UserModel,
21
- ApiKeyModel,
22
- settingsService
23
- });
24
-
25
- this.emailContentGenerator = new EmailContentGenerator({
26
- getSiteUrl,
27
- getSiteTitle,
28
- templatesDir: path.join(__dirname, 'templates')
29
- });
30
- }
31
-
32
- /**
33
- * Version mismatch handler doing the logic of picking a template and sending a notification email
34
- * @param {Object} options
35
- * @param {string} options.acceptVersion - client's accept-version header value
36
- * @param {string} options.contentVersion - server's content-version header value
37
- * @param {string} options.apiKeyValue - key value (secret for Content API and kid for Admin API) used to access the API
38
- * @param {string} options.apiKeyType - key type used to access the API
39
- * @param {string} options.requestURL - url that was requested and failed compatibility test
40
- * @param {string} [options.userAgent] - client's user-agent header value
41
- */
42
- async handleMismatch({acceptVersion, contentVersion, apiKeyValue, apiKeyType, requestURL, userAgent = ''}) {
43
- if (!await this.versionNotificationsDataService.fetchNotification(acceptVersion)) {
44
- const integration = await this.versionNotificationsDataService.getIntegration(apiKeyValue, apiKeyType);
45
-
46
- // We couldn't find the integration
47
- if (!integration) {
48
- return;
49
- }
50
-
51
- const {
52
- name: integrationName,
53
- type: integrationType
54
- } = integration;
55
-
56
- // @NOTE: "internal" or "core" integrations (https://ghost.notion.site/Data-Types-e5dc54dd0078443f9afd6b2abda443c4)
57
- // are maintained by Ghost team, so there is no sense notifying the instance owner about it's incompatibility.
58
- // The other two integration types: "builtin" and "custom", is when we want to notify about incompatibility.
59
- if (['internal', 'core'].includes(integrationType)) {
60
- return;
61
- }
62
-
63
- const trimmedUseAgent = userAgent.split('/')[0];
64
- const emails = await this.versionNotificationsDataService.getNotificationEmails();
65
-
66
- for (const email of emails) {
67
- const template = (trimmedUseAgent === 'Zapier')
68
- ? 'zapier-mismatch'
69
- : 'generic-mismatch';
70
-
71
- const subject = (trimmedUseAgent === 'Zapier')
72
- ? 'Attention required: One of your Zaps has failed'
73
- : `Attention required: Your ${integrationName} integration has failed`;
74
-
75
- const {html, text} = await this.emailContentGenerator.getContent({
76
- template,
77
- data: {
78
- acceptVersion,
79
- contentVersion,
80
- clientName: integrationName,
81
- recipientEmail: email,
82
- requestURL: requestURL
83
- }
84
- });
85
-
86
- await this.sendEmail({
87
- subject,
88
- to: email,
89
- html,
90
- text
91
- });
92
- }
93
-
94
- await this.versionNotificationsDataService.saveNotification(acceptVersion);
95
- }
96
- }
97
- }
98
-
99
- module.exports = APIVersionCompatibilityService;
@@ -1,80 +0,0 @@
1
- const internalContext = {
2
- internal: true
3
- };
4
-
5
- class VersionNotificationsDataService {
6
- /**
7
- * @param {Object} options
8
- * @param {Object} options.UserModel - ghost user model
9
- * @param {Object} options.ApiKeyModel - ghost api key model
10
- * @param {Object} options.settingsService - ghost settings service
11
- */
12
- constructor({UserModel, ApiKeyModel, settingsService}) {
13
- this.UserModel = UserModel;
14
- this.ApiKeyModel = ApiKeyModel;
15
- this.settingsService = settingsService;
16
- }
17
-
18
- async fetchNotification(acceptVersion) {
19
- const setting = await this.settingsService.read('version_notifications', internalContext);
20
- const versionNotifications = JSON.parse(setting.version_notifications.value);
21
-
22
- return versionNotifications.find(version => version === acceptVersion);
23
- }
24
-
25
- async saveNotification(acceptVersion) {
26
- const setting = await this.settingsService.read('version_notifications', internalContext);
27
- const versionNotifications = JSON.parse(setting.version_notifications.value);
28
-
29
- if (!versionNotifications.find(version => version === acceptVersion)) {
30
- versionNotifications.push(acceptVersion);
31
-
32
- return this.settingsService.edit([{
33
- key: 'version_notifications',
34
- value: JSON.stringify(versionNotifications)
35
- }], {
36
- context: internalContext
37
- });
38
- }
39
- }
40
-
41
- async getNotificationEmails() {
42
- const data = await this.UserModel.findAll(Object.assign({
43
- withRelated: ['roles'],
44
- filter: 'status:active'
45
- }, internalContext));
46
-
47
- const adminEmails = data
48
- .toJSON()
49
- .filter(user => ['Owner', 'Administrator'].includes(user.roles[0].name))
50
- .map(user => user.email);
51
-
52
- return adminEmails;
53
- }
54
-
55
- /**
56
- * This method is for internal use only.
57
- *
58
- * @param {String} key - api key identification value, it's "secret" in case of Content API key and "id" for Admin API
59
- * @param {String} type - one of "content" or "admin" values
60
- * @returns {Promise<Object | null>} Integration JSON object
61
- */
62
- async getIntegration(key, type) {
63
- let queryOptions = null;
64
-
65
- if (type === 'content') {
66
- queryOptions = {secret: key};
67
- } else if (type === 'admin') {
68
- queryOptions = {id: key};
69
- }
70
-
71
- const apiKey = await this.ApiKeyModel.findOne(queryOptions, {withRelated: ['integration']});
72
- if (!apiKey) {
73
- return null;
74
- }
75
-
76
- return apiKey.relations.integration.toJSON();
77
- }
78
- }
79
-
80
- module.exports = VersionNotificationsDataService;
@@ -1,57 +0,0 @@
1
- const jwt = require('jsonwebtoken');
2
-
3
- /**
4
- * Remove 'Ghost' from raw authorization header and extract the JWT token.
5
- * Eg. Authorization: Ghost ${JWT}
6
- * @param {string} header
7
- */
8
- const extractTokenFromHeader = (header) => {
9
- const [scheme, token] = header.split(' ');
10
-
11
- if (/^Ghost$/i.test(scheme)) {
12
- return token;
13
- }
14
- };
15
-
16
- const extractAdminAPIKey = (token) => {
17
- const decoded = jwt.decode(token, {complete: true});
18
-
19
- if (!decoded || !decoded.header || !decoded.header.kid) {
20
- return null;
21
- }
22
-
23
- return decoded.header.kid;
24
- };
25
-
26
- /**
27
- * @typedef {object} ApiKey
28
- * @prop {string} key
29
- * @prop {string} type
30
- */
31
-
32
- /**
33
- * When it's a Content API the function resolves with the value of the key secret.
34
- * When it's an Admin API the function resolves with the value of the key id.
35
- *
36
- * @param {import('express').Request} req
37
- * @returns {ApiKey}
38
- */
39
- const extractAPIKey = (req) => {
40
- let keyValue = null;
41
- let keyType = null;
42
-
43
- if (req.query && req.query.key) {
44
- keyValue = req.query.key;
45
- keyType = 'content';
46
- } else if (req.headers && req.headers.authorization) {
47
- keyValue = extractAdminAPIKey(extractTokenFromHeader(req.headers.authorization));
48
- keyType = 'admin';
49
- }
50
-
51
- return {
52
- key: keyValue,
53
- type: keyType
54
- };
55
- };
56
-
57
- module.exports = extractAPIKey;
@@ -1,31 +0,0 @@
1
- const extractApiKey = require('./extract-api-key');
2
-
3
- const versionMismatchHandler = (APIVersionCompatibilityService) => {
4
- /**
5
- * @param {Object} err
6
- * @param {import('express').Request} req
7
- * @param {import('express').Response} res
8
- * @param {import('express').NextFunction} next
9
- */
10
- return async function versionMismatchHandlerMiddleware(err, req, res, next) {
11
- if (err && err.errorType === 'RequestNotAcceptableError') {
12
- if (err.code === 'UPDATE_CLIENT') {
13
- const {key, type} = extractApiKey(req);
14
- const requestURL = req.originalUrl.split('?').shift();
15
-
16
- await APIVersionCompatibilityService.handleMismatch({
17
- acceptVersion: req.headers['accept-version'],
18
- contentVersion: `v${res.locals.safeVersion}`,
19
- requestURL,
20
- userAgent: req.headers['user-agent'],
21
- apiKeyValue: key,
22
- apiKeyType: type
23
- });
24
- }
25
- }
26
-
27
- next(err);
28
- };
29
- };
30
-
31
- module.exports = versionMismatchHandler;