From 77af93be6a7bc6403b42ee2e4d34a69fab281c6a Mon Sep 17 00:00:00 2001 From: Sag Date: Mon, 20 Jan 2025 22:12:55 +0700 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=92=20Blocked=20spammy=20email=20d?= =?UTF-8?q?omains=20in=20member=20signups=20(#22027)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref https://linear.app/ghost/issue/ONC-721 ref https://app.incident.io/ghost/incidents/132 - added a blocklist at the email domain level for free member signups - for example, if `blocked-domain.com` is blocked, `thomas@blocked-domain.com` cannot sign up as free member - the blocklist is configurable: `"spam.blocked_email_domains": ["blocked-domain.com"]` --- apps/portal/src/utils/errors.js | 1 + .../core/core/server/services/members/api.js | 4 +- .../newsletters/NewslettersService.js | 4 +- .../services/settings/SettingsBREADService.js | 4 +- ghost/core/core/shared/config/defaults.json | 3 +- .../send-magic-link.test.js.snap | 18 +++++++ .../e2e-api/members/send-magic-link.test.js | 20 ++++++++ ghost/i18n/locales/af/portal.json | 1 + ghost/i18n/locales/ar/portal.json | 1 + ghost/i18n/locales/bg/portal.json | 1 + ghost/i18n/locales/bn/portal.json | 1 + ghost/i18n/locales/bs/portal.json | 1 + ghost/i18n/locales/ca/portal.json | 1 + ghost/i18n/locales/context.json | 1 + ghost/i18n/locales/cs/portal.json | 1 + ghost/i18n/locales/da/portal.json | 1 + ghost/i18n/locales/de-CH/portal.json | 1 + ghost/i18n/locales/de/portal.json | 1 + ghost/i18n/locales/el/portal.json | 1 + ghost/i18n/locales/en/portal.json | 1 + ghost/i18n/locales/eo/portal.json | 1 + ghost/i18n/locales/es/portal.json | 1 + ghost/i18n/locales/et/portal.json | 1 + ghost/i18n/locales/fa/portal.json | 1 + ghost/i18n/locales/fi/portal.json | 1 + ghost/i18n/locales/fr/portal.json | 1 + ghost/i18n/locales/gd/portal.json | 1 + ghost/i18n/locales/he/portal.json | 1 + ghost/i18n/locales/hi/portal.json | 1 + ghost/i18n/locales/hr/portal.json | 1 + ghost/i18n/locales/hu/portal.json | 1 + ghost/i18n/locales/id/portal.json | 1 + ghost/i18n/locales/is/portal.json | 1 + ghost/i18n/locales/it/portal.json | 1 + ghost/i18n/locales/ja/portal.json | 1 + ghost/i18n/locales/ko/portal.json | 1 + ghost/i18n/locales/kz/portal.json | 1 + ghost/i18n/locales/lt/portal.json | 1 + ghost/i18n/locales/lv/portal.json | 1 + ghost/i18n/locales/mk/portal.json | 1 + ghost/i18n/locales/mn/portal.json | 1 + ghost/i18n/locales/ms/portal.json | 1 + ghost/i18n/locales/ne/portal.json | 1 + ghost/i18n/locales/nl/portal.json | 1 + ghost/i18n/locales/nn/portal.json | 1 + ghost/i18n/locales/no/portal.json | 1 + ghost/i18n/locales/pl/portal.json | 1 + ghost/i18n/locales/pt-BR/portal.json | 1 + ghost/i18n/locales/pt/portal.json | 1 + ghost/i18n/locales/ro/portal.json | 1 + ghost/i18n/locales/ru/portal.json | 1 + ghost/i18n/locales/si/portal.json | 1 + ghost/i18n/locales/sk/portal.json | 1 + ghost/i18n/locales/sl/portal.json | 1 + ghost/i18n/locales/sq/portal.json | 1 + ghost/i18n/locales/sr-Cyrl/portal.json | 1 + ghost/i18n/locales/sr/portal.json | 1 + ghost/i18n/locales/sv/portal.json | 1 + ghost/i18n/locales/sw/portal.json | 1 + ghost/i18n/locales/ta/portal.json | 1 + ghost/i18n/locales/th/portal.json | 1 + ghost/i18n/locales/tr/portal.json | 1 + ghost/i18n/locales/uk/portal.json | 1 + ghost/i18n/locales/ur/portal.json | 1 + ghost/i18n/locales/uz/portal.json | 1 + ghost/i18n/locales/vi/portal.json | 1 + ghost/i18n/locales/zh-Hant/portal.json | 1 + ghost/i18n/locales/zh/portal.json | 1 + ghost/magic-link/lib/MagicLink.js | 32 +++++++++++- ghost/magic-link/test/index.test.js | 51 +++++++++++++++++++ ghost/members-api/lib/members-api.js | 6 ++- 71 files changed, 196 insertions(+), 8 deletions(-) diff --git a/apps/portal/src/utils/errors.js b/apps/portal/src/utils/errors.js index c48e3716bf..93034e1cc9 100644 --- a/apps/portal/src/utils/errors.js +++ b/apps/portal/src/utils/errors.js @@ -59,6 +59,7 @@ export function chooseBestErrorMessage(error, alreadyTranslatedDefaultMessage, t t('Too many different sign-in attempts, try again in {{number}} days'); t('Failed to send magic link email'); t('This site only accepts paid members.'); + t('This email domain is not accepted, try again with a different email address'); } }; diff --git a/ghost/core/core/server/services/members/api.js b/ghost/core/core/server/services/members/api.js index 6b65cf6bd8..26f5d46d7c 100644 --- a/ghost/core/core/server/services/members/api.js +++ b/ghost/core/core/server/services/members/api.js @@ -20,6 +20,7 @@ const memberAttributionService = require('../member-attribution'); const emailSuppressionList = require('../email-suppression-list'); const {t} = require('../i18n'); const sentry = require('../../../shared/sentry'); +const sharedConfig = require('../../../shared/config'); const MAGIC_LINK_TOKEN_VALIDITY = 24 * 60 * 60 * 1000; const MAGIC_LINK_TOKEN_VALIDITY_AFTER_USAGE = 10 * 60 * 1000; @@ -238,7 +239,8 @@ function createApiInstance(config) { emailSuppressionList, settingsCache, sentry, - settingsHelpers + settingsHelpers, + config: sharedConfig }); return membersApiInstance; diff --git a/ghost/core/core/server/services/newsletters/NewslettersService.js b/ghost/core/core/server/services/newsletters/NewslettersService.js index 5247c69c93..bf9082e96a 100644 --- a/ghost/core/core/server/services/newsletters/NewslettersService.js +++ b/ghost/core/core/server/services/newsletters/NewslettersService.js @@ -6,6 +6,7 @@ const debug = require('@tryghost/debug')('services:newsletters'); const tpl = require('@tryghost/tpl'); const errors = require('@tryghost/errors'); const sentry = require('../../../shared/sentry'); +const config = require('../../../shared/config'); const messages = { nameAlreadyExists: 'A newsletter with the same name already exists', @@ -86,7 +87,8 @@ class NewslettersService { getText, getHTML, getSubject, - sentry + sentry, + config }); } diff --git a/ghost/core/core/server/services/settings/SettingsBREADService.js b/ghost/core/core/server/services/settings/SettingsBREADService.js index 0638920c51..bd93c0d7d9 100644 --- a/ghost/core/core/server/services/settings/SettingsBREADService.js +++ b/ghost/core/core/server/services/settings/SettingsBREADService.js @@ -6,6 +6,7 @@ const logging = require('@tryghost/logging'); const MagicLink = require('@tryghost/magic-link'); const verifyEmailTemplate = require('./emails/verify-email'); const sentry = require('../../../shared/sentry'); +const config = require('../../../shared/config'); const EMAIL_KEYS = ['members_support_address']; const messages = { @@ -82,7 +83,8 @@ class SettingsBREADService { getText, getHTML, getSubject, - sentry + sentry, + config }); } diff --git a/ghost/core/core/shared/config/defaults.json b/ghost/core/core/shared/config/defaults.json index 0496656264..2c1220b8d8 100644 --- a/ghost/core/core/shared/config/defaults.json +++ b/ghost/core/core/shared/config/defaults.json @@ -126,7 +126,8 @@ "maxWait": 360000, "lifetime": 3600, "freeRetries": 10 - } + }, + "blocked_email_domains": [] }, "caching": { "frontend": { diff --git a/ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snap b/ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snap index e8e0a5499e..1305fc1af3 100644 --- a/ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snap +++ b/ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snap @@ -107,3 +107,21 @@ Object { ], } `; + +exports[`sendMagicLink blocks signups from blocked email domains 1: [body] 1`] = ` +Object { + "errors": Array [ + Object { + "code": null, + "context": null, + "details": null, + "ghostErrorCode": null, + "help": null, + "id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + "message": "This email domain is not accepted, try again with a different email address", + "property": null, + "type": "BadRequestError", + }, + ], +} +`; diff --git a/ghost/core/test/e2e-api/members/send-magic-link.test.js b/ghost/core/test/e2e-api/members/send-magic-link.test.js index f353f37fb1..88eefe3869 100644 --- a/ghost/core/test/e2e-api/members/send-magic-link.test.js +++ b/ghost/core/test/e2e-api/members/send-magic-link.test.js @@ -4,6 +4,7 @@ const settingsCache = require('../../../core/shared/settings-cache'); const DomainEvents = require('@tryghost/domain-events'); const {anyErrorId} = matchers; const spamPrevention = require('../../../core/server/web/shared/middleware/api/spam-prevention'); +const configUtils = require('../../utils/configUtils'); let membersAgent, membersService; @@ -29,6 +30,7 @@ describe('sendMagicLink', function () { afterEach(function () { mockManager.restore(); + configUtils.restore(); }); it('Errors when passed multiple emails', async function () { @@ -285,4 +287,22 @@ describe('sendMagicLink', function () { } }); }); + + it('blocks signups from blocked email domains', async function () { + configUtils.set('spam:blocked_email_domains', ['blocked-domain.com']); + + const email = 'this-member-does-not-exist@blocked-domain.com'; + await membersAgent.post('/api/send-magic-link') + .body({ + email, + emailType: 'signup' + }) + .expectStatus(400) + .matchBodySnapshot({ + errors: [{ + id: anyErrorId, + message: 'This email domain is not accepted, try again with a different email address' + }] + }); + }); }); diff --git a/ghost/i18n/locales/af/portal.json b/ghost/i18n/locales/af/portal.json index bacfa41c0d..90cc195960 100644 --- a/ghost/i18n/locales/af/portal.json +++ b/ghost/i18n/locales/af/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Hierdie webwerf is slegs op uitnodiging, kontak die eienaar vir toegang.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ar/portal.json b/ghost/i18n/locales/ar/portal.json index 2be918d4fe..e781b56499 100644 --- a/ghost/i18n/locales/ar/portal.json +++ b/ghost/i18n/locales/ar/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": ".حدث خطأ أثناء الاشتراك، يرجى المحاولة مرة أخرى", "There was an error processing your payment. Please try again.": ".حدث خطأ أثناء معالجة دفعك، يرجى المحاولة مرة أخرى", "There was an error sending the email, please try again": ".حدث خطأ أثناء إرسال البريد الاكتروني، يرجى المحاولة مرة أخرى", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "هذا الموقع للمشتركين فقط، تواصل مع ادارة الموقع للحصول على اشتراك.", "This site is not accepting payments at the moment.": "هذا الموقع لا يقبل المدفوعات في الوقت الحالي", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/bg/portal.json b/ghost/i18n/locales/bg/portal.json index 6df78718e1..3960c1dd0f 100644 --- a/ghost/i18n/locales/bg/portal.json +++ b/ghost/i18n/locales/bg/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Възникна грешка при продължаването на абонамента ви, опитайте отново.", "There was an error processing your payment. Please try again.": "Възникна грешка при обработката на вашето плащане. Моля, опитайте отново.", "There was an error sending the email, please try again": "Възникна грешка при изпращане на имейл, опитайте отново", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Сайтът е само с покани. Свържете се със собственика за да получите достъп.", "This site is not accepting payments at the moment.": "В момента сайтът не приема плащания.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/bn/portal.json b/ghost/i18n/locales/bn/portal.json index 4dbf4485a4..a89cfc8968 100644 --- a/ghost/i18n/locales/bn/portal.json +++ b/ghost/i18n/locales/bn/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "এই সাইটটি কেবল আমন্ত্রণের মাধ্যমে, প্রবেশাধিকার পেতে মালিকের সাথে যোগাযোগ করুন।", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/bs/portal.json b/ghost/i18n/locales/bs/portal.json index 5d2bfa3bd8..0d2da7661c 100644 --- a/ghost/i18n/locales/bs/portal.json +++ b/ghost/i18n/locales/bs/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ova je stranica samo na poziv, kontaktiraj vlasnika za pristup.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ca/portal.json b/ghost/i18n/locales/ca/portal.json index d17417d828..16f7031fac 100644 --- a/ghost/i18n/locales/ca/portal.json +++ b/ghost/i18n/locales/ca/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Aquest llog és només per invitació, contacta amb el propietari per obtenir accés.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/context.json b/ghost/i18n/locales/context.json index c9ae0468fd..9d845830c9 100644 --- a/ghost/i18n/locales/context.json +++ b/ghost/i18n/locales/context.json @@ -242,6 +242,7 @@ "This comment has been hidden.": "Text for a comment thas was hidden", "This comment has been removed.": "Text for a comment thas was removed", "This email address will not be used.": "This is in the footer of signup verification emails, and comes right after 'If you did not make this request, you can simply delete this message.'", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "A message on the member login screen indicating that a site is not-open to public signups", "This site is not accepting payments at the moment.": "An error message shown when a tips or donations link is opened but the site has donations disabled", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/cs/portal.json b/ghost/i18n/locales/cs/portal.json index 36f707e7d8..f4a806b160 100644 --- a/ghost/i18n/locales/cs/portal.json +++ b/ghost/i18n/locales/cs/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "Při zpracování vaší platby došlo k chybě. Zkuste to prosím znovu.", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Tento web je pouze pro pozvané, kontaktujte provozovatele pro přístup.", "This site is not accepting payments at the moment.": "Tento web momentálně nepřijímá platby.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/da/portal.json b/ghost/i18n/locales/da/portal.json index b8f3f329f8..03c1eb8c78 100644 --- a/ghost/i18n/locales/da/portal.json +++ b/ghost/i18n/locales/da/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Der opstod en fejl under forlængelsen af dit abonnement, prøv venligst igen.", "There was an error processing your payment. Please try again.": "Der opstod en fejl under behandlingen af din betaling. Prøv venligst igen.", "There was an error sending the email, please try again": "Der opstod en fejl under afsendelse af e-mailen, prøv venligst igen.", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Denne sider kræver at du skal være inviteret. Kontakt ejeres for at få adgang.", "This site is not accepting payments at the moment.": "Denne side accepterer ikke betalinger i øjeblikket.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/de-CH/portal.json b/ghost/i18n/locales/de-CH/portal.json index 8d3bb95482..03895b4d89 100644 --- a/ghost/i18n/locales/de-CH/portal.json +++ b/ghost/i18n/locales/de-CH/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Der Zugang zu diesem Inhalt ist eingeschränkt. Bitte kontaktieren Sie uns, wenn Sie Zugang wünschen.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/de/portal.json b/ghost/i18n/locales/de/portal.json index 83d7591b7d..7fe5353ff0 100644 --- a/ghost/i18n/locales/de/portal.json +++ b/ghost/i18n/locales/de/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Beim Erneuern deines Abonnements ist ein Fehler aufgetreten. Bitte versuche es erneut.", "There was an error processing your payment. Please try again.": "Bei der Verarbeitung deiner Zahlung gab es einen Fehler. Bitte versuche es noch einmal.", "There was an error sending the email, please try again": "Beim Versand der E-Mail ist ein Fehler aufgetreten. Bitte versuche es erneut.", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Für diese Seite benötigst du eine Einladung. Bitte kontaktiere den Inhaber.", "This site is not accepting payments at the moment.": "Diese Website nimmt zur Zeit keine Zahlungen entgegen.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/el/portal.json b/ghost/i18n/locales/el/portal.json index bc56a27992..98a6143e0b 100644 --- a/ghost/i18n/locales/el/portal.json +++ b/ghost/i18n/locales/el/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Αυτός ο ιστότοπος είναι μόνο με πρόσκληση, επικοινωνήστε με τον ιδιοκτήτη για πρόσβαση.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/en/portal.json b/ghost/i18n/locales/en/portal.json index 54638995cf..508f16c346 100644 --- a/ghost/i18n/locales/en/portal.json +++ b/ghost/i18n/locales/en/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/eo/portal.json b/ghost/i18n/locales/eo/portal.json index 760b2ebe31..7f5724bdf9 100644 --- a/ghost/i18n/locales/eo/portal.json +++ b/ghost/i18n/locales/eo/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ĉi tiu retejo estas nur por invitiĝuloj, kontaktu la proprietulo por alireblo.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/es/portal.json b/ghost/i18n/locales/es/portal.json index 5e50595327..0dd42ceae6 100644 --- a/ghost/i18n/locales/es/portal.json +++ b/ghost/i18n/locales/es/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Hubo un error en continuar la suscripción, inténtalo de nuevo por favor.", "There was an error processing your payment. Please try again.": "Hubo un error procesando tu pago. Intentalo de nuevvo por favor.", "There was an error sending the email, please try again": "Hubo un error enviando el correo electrónico, intentalo de nuevo por favor.", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Este sitio es solo por invitación, contacta al propietario para obtener acceso.", "This site is not accepting payments at the moment.": "Este sitio no acepta pagos en este momento.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/et/portal.json b/ghost/i18n/locales/et/portal.json index 7eb3a3485d..5d70c09a7d 100644 --- a/ghost/i18n/locales/et/portal.json +++ b/ghost/i18n/locales/et/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "See sait on ainult kutsetega, juurdepääsu saamiseks võtke ühendust omanikuga.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/fa/portal.json b/ghost/i18n/locales/fa/portal.json index c73468136c..c8d227e1b7 100644 --- a/ghost/i18n/locales/fa/portal.json +++ b/ghost/i18n/locales/fa/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "دسترسی به این وب\u200cسایت نیازمند دعوت\u200cنامه است، با مالک آن برای دریافت دسترسی تماس بگیرید.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/fi/portal.json b/ghost/i18n/locales/fi/portal.json index 62ec5e3b4e..a771493549 100644 --- a/ghost/i18n/locales/fi/portal.json +++ b/ghost/i18n/locales/fi/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Tämä sivu on vain kutsutuille, ota yhteyttä omistajaan saadaksesi pääsyoikeuden.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/fr/portal.json b/ghost/i18n/locales/fr/portal.json index 22f7eb2a22..21e6f2b607 100644 --- a/ghost/i18n/locales/fr/portal.json +++ b/ghost/i18n/locales/fr/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Une erreur s'est produite lors de la prolongation de votre abonnement, veuillez réessayer.", "There was an error processing your payment. Please try again.": "Une erreur s'est produite lors du traitement de votre paiement. Veuillez réessayer.", "There was an error sending the email, please try again": "Une erreur s'est produite lors de l'envoi de l'e-mail, veuillez réessayer.", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ce site est réservé aux invités. Veuillez écrire au propriétaire pour en demander l'accès.", "This site is not accepting payments at the moment.": "Ce site n'accepte pas les paiements pour le moment.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/gd/portal.json b/ghost/i18n/locales/gd/portal.json index 9009276143..007908c4ba 100644 --- a/ghost/i18n/locales/gd/portal.json +++ b/ghost/i18n/locales/gd/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "Thachair mearachd fhad 's a bhathar a' làimhseachadh a' phàighidh agad. Feuch a-rithist an ceann greis.", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Feumar cuireadh airson an làrach-lìn seo, leig fios dhan rianaire ma tha thu ag iarraidh cothrom-inntrigidh.", "This site is not accepting payments at the moment.": "Chan eil an làrach seo a' gabhail ri phàighidhean an-dràsta.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/he/portal.json b/ghost/i18n/locales/he/portal.json index 1241bbd509..19c9163cf7 100644 --- a/ghost/i18n/locales/he/portal.json +++ b/ghost/i18n/locales/he/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "שגיאה בהמשך המנוי שלכם, נסו שוב.", "There was an error processing your payment. Please try again.": "שגיאה בעיבוד התשלום שלכם. נסו שוב.", "There was an error sending the email, please try again": "שגיאה בשליחת המייל, נסו שוב", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "אתר זה פתוח למוזמנים בלבד, פנו לבעל האתר לגישה.", "This site is not accepting payments at the moment.": "אתר זה לא מקבל תשלומים כרגע.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/hi/portal.json b/ghost/i18n/locales/hi/portal.json index e5c6927dca..c3cb361240 100644 --- a/ghost/i18n/locales/hi/portal.json +++ b/ghost/i18n/locales/hi/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "यह साइट केवल निमंत्रण द्वारा है, पहुँच के लिए मालिक से संपर्क करें।", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/hr/portal.json b/ghost/i18n/locales/hr/portal.json index 69135f7de3..937fb337dd 100644 --- a/ghost/i18n/locales/hr/portal.json +++ b/ghost/i18n/locales/hr/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ove stranice su samo za članove, kontaktirajte vlasnika kako biste dobili pristup.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/hu/portal.json b/ghost/i18n/locales/hu/portal.json index de9f7d87bd..f304651bcb 100644 --- a/ghost/i18n/locales/hu/portal.json +++ b/ghost/i18n/locales/hu/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "A website csak meghívóval látogatható. Meghívóért lépjen kapcsolatba az oldal tulajdonosával!", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/id/portal.json b/ghost/i18n/locales/id/portal.json index bd9c652e08..5de578cae5 100644 --- a/ghost/i18n/locales/id/portal.json +++ b/ghost/i18n/locales/id/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Terjadi kesalahan saat melanjutkan langganan Anda, harap coba lagi.", "There was an error processing your payment. Please try again.": "Terjadi kesalahan saat memproses pembayaran Anda. Harap coba lagi.", "There was an error sending the email, please try again": "Terjadi kesalahan saat mengirim email, harap coba lagi", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Situs ini hanya untuk yang diundang, hubungi pemiliknya untuk mendapatkan akses.", "This site is not accepting payments at the moment.": "Situs ini tidak menerima pembayaran saat ini.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/is/portal.json b/ghost/i18n/locales/is/portal.json index ef6598309e..9b5b2a17b8 100644 --- a/ghost/i18n/locales/is/portal.json +++ b/ghost/i18n/locales/is/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Aðgangur krefst boðsmiða, hafið samband við eiganda síðunnar til að fá aðgang.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/it/portal.json b/ghost/i18n/locales/it/portal.json index c99667b533..2e5738f405 100644 --- a/ghost/i18n/locales/it/portal.json +++ b/ghost/i18n/locales/it/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "C'è stato un errore nella continuazione del tuo abbonamento, riprova per favore.", "There was an error processing your payment. Please try again.": "C'è stato un errore durante l’elaborazione del tuo pagamento. Riprova per favore.", "There was an error sending the email, please try again": "C'è stato un errore nell'invio dell'e-mail, per favore riprova", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Questo sito è accessibile solo su invito, contatta il proprietario per poter accedere.", "This site is not accepting payments at the moment.": "Questo sito non accetta pagamenti al momento.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ja/portal.json b/ghost/i18n/locales/ja/portal.json index 4e9b53d0f1..9b3182cca7 100644 --- a/ghost/i18n/locales/ja/portal.json +++ b/ghost/i18n/locales/ja/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "このサイトは招待制です。アクセスするにはオーナーに連絡してください。", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ko/portal.json b/ghost/i18n/locales/ko/portal.json index e71b36ac98..2fd55603b0 100644 --- a/ghost/i18n/locales/ko/portal.json +++ b/ghost/i18n/locales/ko/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "구독 계속하기 중 오류가 발생했어요. 다시 시도해 주세요.", "There was an error processing your payment. Please try again.": "결제 처리 중 오류가 발생했어요. 다시 시도해 주세요.", "There was an error sending the email, please try again": "이메일 전송 중 오류가 발생했어요. 다시 시도해 주세요", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "위 사이트는 초대된 사용자만 사용이 가능해요. 접근을 위해서는 관리자에게 연락해 주세요.", "This site is not accepting payments at the moment.": "현재 이 사이트는 결제를 받지 않고 있어요.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/kz/portal.json b/ghost/i18n/locales/kz/portal.json index 8414afa9f0..ce82ba45e3 100644 --- a/ghost/i18n/locales/kz/portal.json +++ b/ghost/i18n/locales/kz/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Бұл сайтқа тек шақырту бойынша кіруге болады, рұқсат алу үшін иесіне хабарласыңыз.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/lt/portal.json b/ghost/i18n/locales/lt/portal.json index d09d5df89d..e05538188d 100644 --- a/ghost/i18n/locales/lt/portal.json +++ b/ghost/i18n/locales/lt/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ši svetainė pasiekiama tik su pakvietimu, susisiekite su savininku dėl prieigos. ", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/lv/portal.json b/ghost/i18n/locales/lv/portal.json index a0b1eff46d..190adb3607 100644 --- a/ghost/i18n/locales/lv/portal.json +++ b/ghost/i18n/locales/lv/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Turpinot abonementu, radās kļūda. Lūdzu, mēģiniet vēlreiz.", "There was an error processing your payment. Please try again.": "Apstrādājot jūsu maksājumu, radās kļūda. Lūdzu, mēģiniet vēlreiz.", "There was an error sending the email, please try again": "Nosūtot e-pasta ziņojumu, radās kļūda. Lūdzu, mēģiniet vēlreiz", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Šī vietne ir paredzēta tikai ielūgumam. Lai iegūtu piekļuvi, sazinieties ar īpašnieku.", "This site is not accepting payments at the moment.": "Šī vietne pašlaik nepieņem maksājumus.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/mk/portal.json b/ghost/i18n/locales/mk/portal.json index 0c9831b311..3451e7300d 100644 --- a/ghost/i18n/locales/mk/portal.json +++ b/ghost/i18n/locales/mk/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Оваа страница е достапна само со покана. За пристап контактирајте го сопственикот.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/mn/portal.json b/ghost/i18n/locales/mn/portal.json index e949b20274..97d2371753 100644 --- a/ghost/i18n/locales/mn/portal.json +++ b/ghost/i18n/locales/mn/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Энэхүү сайт руу зөвхөн урилгаар нэвтрэх боломжтой тул та админд нь хандана уу.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ms/portal.json b/ghost/i18n/locales/ms/portal.json index a9c8603136..bd2111dea7 100644 --- a/ghost/i18n/locales/ms/portal.json +++ b/ghost/i18n/locales/ms/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Laman web ini hanya untuk jemputan, hubungi pemilik untuk akses.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ne/portal.json b/ghost/i18n/locales/ne/portal.json index 54638995cf..508f16c346 100644 --- a/ghost/i18n/locales/ne/portal.json +++ b/ghost/i18n/locales/ne/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/nl/portal.json b/ghost/i18n/locales/nl/portal.json index 20843b6973..e16b198b62 100644 --- a/ghost/i18n/locales/nl/portal.json +++ b/ghost/i18n/locales/nl/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Er was een fout bij het voortzetten van je abonnement, probeer het opnieuw.", "There was an error processing your payment. Please try again.": "Er was een fout bij het verwerken van je betaling, probeer het opnieuw.", "There was an error sending the email, please try again": "Er was een fout bij het verzenden van de e-mail, probeer het opnieuw", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Deze site is alleen toegankelijk op uitnodiging, neem contact op met de eigenaar.", "This site is not accepting payments at the moment.": "Deze site accepteert momenteel geen betalingen.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/nn/portal.json b/ghost/i18n/locales/nn/portal.json index 84f77247b8..d3c06a1726 100644 --- a/ghost/i18n/locales/nn/portal.json +++ b/ghost/i18n/locales/nn/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Denne sida er kun for inviterte, ta kontakt med eigaren for tilgang.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/no/portal.json b/ghost/i18n/locales/no/portal.json index 283b19c68d..55f85c8d64 100644 --- a/ghost/i18n/locales/no/portal.json +++ b/ghost/i18n/locales/no/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "En feil oppstod ved fornyelse av abonnementet, vennligst prøv igjen.", "There was an error processing your payment. Please try again.": "Det oppsto en feil under behandling av betalingen din. Vennligst prøv igjen.", "There was an error sending the email, please try again": "En feil oppstod ved sending av e-posten, vennligst prøv igjen", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Denne nettsiden er kun for inviterte. Kontakt eieren for invitasjon.", "This site is not accepting payments at the moment.": "Denne nettsiden godtar ikke betalinger for øyeblikket.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/pl/portal.json b/ghost/i18n/locales/pl/portal.json index 8b28b867e6..518af111ec 100644 --- a/ghost/i18n/locales/pl/portal.json +++ b/ghost/i18n/locales/pl/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ta strona posiada zamknięty dostęp. Skontaktuj się z właścicielem, aby uzyskać dostęp.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/pt-BR/portal.json b/ghost/i18n/locales/pt-BR/portal.json index f631eead81..94cbdeb8c2 100644 --- a/ghost/i18n/locales/pt-BR/portal.json +++ b/ghost/i18n/locales/pt-BR/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Houve um erro ao continuar sua assinatura, por favor, tente novamente.", "There was an error processing your payment. Please try again.": "Houve um erro ao processar seu pagamento. Por favor, tente novamente.", "There was an error sending the email, please try again": "Houve um erro ao enviar o e-mail, por favor, tente novamente.", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Este site é apenas para convidados. Contate o proprietário para obter acesso.", "This site is not accepting payments at the moment.": "Este site não está aceitando pagamentos no momento.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/pt/portal.json b/ghost/i18n/locales/pt/portal.json index 62d46bca91..8d77667917 100644 --- a/ghost/i18n/locales/pt/portal.json +++ b/ghost/i18n/locales/pt/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "Houve um problema ao processar o seu pagamento. Tente novamente por favor.", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "O acesso a este site é feito apenas por convite. Entre em contacto com o proprietário para obter acesso.", "This site is not accepting payments at the moment.": "Este site não está a aceitar pagamentos de momento", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ro/portal.json b/ghost/i18n/locales/ro/portal.json index 8788c45761..dce5d968ca 100644 --- a/ghost/i18n/locales/ro/portal.json +++ b/ghost/i18n/locales/ro/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Acest site este disponibil doar pe bază de invitație, contactează proprietarul pentru acces.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ru/portal.json b/ghost/i18n/locales/ru/portal.json index 4b0d228a23..c9525ab915 100644 --- a/ghost/i18n/locales/ru/portal.json +++ b/ghost/i18n/locales/ru/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "Произошла ошибка при обработке вашего платежа. Попробуйте ещё раз.", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Доступ к материалам этого сайта возможен только по приглашению. Для получения доступа свяжитесь с владельцем сайта.", "This site is not accepting payments at the moment.": "В данный момент сайт не принимает платежи.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/si/portal.json b/ghost/i18n/locales/si/portal.json index a5d2505aab..4ccedfa27b 100644 --- a/ghost/i18n/locales/si/portal.json +++ b/ghost/i18n/locales/si/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "මෙම වෙබ් අඩවිය ආරාධිතයන් සඳහා පමණි, ප්\u200dරවේශ වීම සඳහා හිමිකරු අමතන්න.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sk/portal.json b/ghost/i18n/locales/sk/portal.json index 79c1cf5192..36486b2eb3 100644 --- a/ghost/i18n/locales/sk/portal.json +++ b/ghost/i18n/locales/sk/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Táto stránka je iba pre pozvaných úžívateľov, kontaktujte vlastníka stránky.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sl/portal.json b/ghost/i18n/locales/sl/portal.json index 4fc4285f4f..9121d37799 100644 --- a/ghost/i18n/locales/sl/portal.json +++ b/ghost/i18n/locales/sl/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "To spletno mesto je dostopno samo s povabilom, obrnite se na lastnika.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sq/portal.json b/ghost/i18n/locales/sq/portal.json index ab63e66bd5..e42367d144 100644 --- a/ghost/i18n/locales/sq/portal.json +++ b/ghost/i18n/locales/sq/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Kjo faqe eshte vetem me ftesa, kontaktoni zoteruesin per akses.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sr-Cyrl/portal.json b/ghost/i18n/locales/sr-Cyrl/portal.json index 7e969ce11a..858400556f 100644 --- a/ghost/i18n/locales/sr-Cyrl/portal.json +++ b/ghost/i18n/locales/sr-Cyrl/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "Дошло је до грешке при обради ваше уплате. Молимо вас покушајте поново.", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Овај сајт је само на позив, контактирајте власника ради приступа.", "This site is not accepting payments at the moment.": "Овај сајт тренутно не прихвата уплате.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sr/portal.json b/ghost/i18n/locales/sr/portal.json index e300ae10a4..586908dcbf 100644 --- a/ghost/i18n/locales/sr/portal.json +++ b/ghost/i18n/locales/sr/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Ovaj sajt je samo za članove, kontaktirajte vlasnika kako bi dobili pristup.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sv/portal.json b/ghost/i18n/locales/sv/portal.json index d56cf1651f..55aeecc8e4 100644 --- a/ghost/i18n/locales/sv/portal.json +++ b/ghost/i18n/locales/sv/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Det blev fel när din prenumeration skulle fortsättas, vänligen försök igen", "There was an error processing your payment. Please try again.": "Det blev fel när din betalning skulle behandlas, vänligen försök igen", "There was an error sending the email, please try again": "Det blev ett fel när e-posten skulle skickas, vänligen försök igen", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Den här sidan är endast för inbjudna, kontakta ägaren för åtkomst.", "This site is not accepting payments at the moment.": "Den här webbsidan accepterar inte betalningar för tillfället", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/sw/portal.json b/ghost/i18n/locales/sw/portal.json index 046013638c..218f70a3df 100644 --- a/ghost/i18n/locales/sw/portal.json +++ b/ghost/i18n/locales/sw/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Tovuti hii ni ya mialiko pekee, wasiliana na mmiliki kupata ufikiaji.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ta/portal.json b/ghost/i18n/locales/ta/portal.json index 4b5c92473f..b7289ef548 100644 --- a/ghost/i18n/locales/ta/portal.json +++ b/ghost/i18n/locales/ta/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "உங்கள் சந்தாவைத் தொடர்வதில் பிழை ஏற்பட்டது, மீண்டும் முயற்சிக்கவும்.", "There was an error processing your payment. Please try again.": "உங்கள் கட்டணத்தை செயலாக்குவதில் பிழை ஏற்பட்டது. மீண்டும் முயற்சிக்கவும்.", "There was an error sending the email, please try again": "மின்னஞ்சலை அனுப்புவதில் பிழை ஏற்பட்டது, மீண்டும் முயற்சிக்கவும்", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "இந்த தளம் அழைப்பு மட்டுமே, அணுகலுக்கு உரிமையாளரைத் தொடர்பு கொள்ளவும்.", "This site is not accepting payments at the moment.": "இந்த தளம் தற்போது கட்டணங்களை ஏற்கவில்லை.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/th/portal.json b/ghost/i18n/locales/th/portal.json index 13a3b082bf..92f4be14b6 100644 --- a/ghost/i18n/locales/th/portal.json +++ b/ghost/i18n/locales/th/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "เว็บไซต์นี้สำหรับผู้ได้รับเชิญเท่านั้น โปรดติดต่อเจ้าของเพื่อเข้าถึง", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/tr/portal.json b/ghost/i18n/locales/tr/portal.json index 20047bab66..9d3059588b 100644 --- a/ghost/i18n/locales/tr/portal.json +++ b/ghost/i18n/locales/tr/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Aboneliğinizi devam ettirirken bir hata oluştu, lütfen tekrar deneyin.", "There was an error processing your payment. Please try again.": "Ödemeniz işlenirken bir hata oluştu. Lütfen tekrar deneyiniz.", "There was an error sending the email, please try again": "E-posta gönderilirken bir hata oluştu, lütfen tekrar deneyin.", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Bu site sadece davetiyesi olanlar içindir, erişim için site sahibiyle iletişime geç.", "This site is not accepting payments at the moment.": "Bu site şu anda ödeme kabul etmemektedir.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/uk/portal.json b/ghost/i18n/locales/uk/portal.json index 7eae5dd503..4dc2eb04d0 100644 --- a/ghost/i18n/locales/uk/portal.json +++ b/ghost/i18n/locales/uk/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Під час продовження підписки сталася помилка. Спробуйте ще раз.", "There was an error processing your payment. Please try again.": "Під час обробки вашого платежу сталася помилка. Спробуйте ще раз.", "There was an error sending the email, please try again": "Під час надсилання листа сталася помилка. Повторіть спробу", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Цей сайт доступний тільки за запрошенням, звернись до власника сайта для доступу.", "This site is not accepting payments at the moment.": "Цей сайт на даний момент не приймає платежі.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/ur/portal.json b/ghost/i18n/locales/ur/portal.json index c65c245264..041dea35fc 100644 --- a/ghost/i18n/locales/ur/portal.json +++ b/ghost/i18n/locales/ur/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "یہ سائٹ صرف دعوتی ہے، دستیابی کے لئے مالک سے رابطہ کریں۔", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/uz/portal.json b/ghost/i18n/locales/uz/portal.json index b08485cac7..6e569adb55 100644 --- a/ghost/i18n/locales/uz/portal.json +++ b/ghost/i18n/locales/uz/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Bu saytda faqat taklif qilinadi, kirish uchun egasiga murojaat qiling.", "This site is not accepting payments at the moment.": "", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/vi/portal.json b/ghost/i18n/locales/vi/portal.json index ce097a1e32..4c655fd915 100644 --- a/ghost/i18n/locales/vi/portal.json +++ b/ghost/i18n/locales/vi/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "Xảy ra lỗi khi tiếp tục gói thành viên, vui lòng thử lại", "There was an error processing your payment. Please try again.": "Xảy ra lỗi khi tiến hành thanh toán. Hãy thử lại sau.", "There was an error sending the email, please try again": "Xảy ra lỗi khi gửi email, vui lòng thử lại", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "Trang web này chỉ dành cho những người được mời, hãy liên hệ với chủ sở hữu để cấp quyền truy cập.", "This site is not accepting payments at the moment.": "Trang web này hiện chưa chấp nhận thanh toán.", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/zh-Hant/portal.json b/ghost/i18n/locales/zh-Hant/portal.json index 38be03f724..812f54e0b4 100644 --- a/ghost/i18n/locales/zh-Hant/portal.json +++ b/ghost/i18n/locales/zh-Hant/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "續約您的訂閱時發生錯誤,請您再試一次。", "There was an error processing your payment. Please try again.": "處理您的付款時發生錯誤,請您再試一次。", "There was an error sending the email, please try again": "寄送 email 時發生錯誤,請您再試一次。", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "此網站僅限受邀請者觀看,請聯繫網站擁有者取得存取權限。", "This site is not accepting payments at the moment.": "此網站目前無付款方式。", "This site only accepts paid members.": "", diff --git a/ghost/i18n/locales/zh/portal.json b/ghost/i18n/locales/zh/portal.json index 1db54a5c46..016e303c01 100644 --- a/ghost/i18n/locales/zh/portal.json +++ b/ghost/i18n/locales/zh/portal.json @@ -165,6 +165,7 @@ "There was an error continuing your subscription, please try again.": "", "There was an error processing your payment. Please try again.": "您的付款处理失败,请重试。", "There was an error sending the email, please try again": "", + "This email domain is not accepted, try again with a different email address": "", "This site is invite-only, contact the owner for access.": "此网站仅限邀请,联系网站所有者以获取访问", "This site is not accepting payments at the moment.": "本网站目前暂不接受付款。", "This site only accepts paid members.": "", diff --git a/ghost/magic-link/lib/MagicLink.js b/ghost/magic-link/lib/MagicLink.js index b49b25a20b..f05030a6ee 100644 --- a/ghost/magic-link/lib/MagicLink.js +++ b/ghost/magic-link/lib/MagicLink.js @@ -2,7 +2,8 @@ const {IncorrectUsageError, BadRequestError} = require('@tryghost/errors'); const {isEmail} = require('@tryghost/validator'); const tpl = require('@tryghost/tpl'); const messages = { - invalidEmail: 'Email is not valid' + invalidEmail: 'Email is not valid', + unsupportedEmailDomain: 'This email domain is not accepted, try again with a different email address' }; /** @@ -34,6 +35,7 @@ class MagicLink { * @param {typeof defaultGetHTML} [options.getHTML] * @param {typeof defaultGetSubject} [options.getSubject] * @param {object} [options.sentry] + * @param {object} [options.config] */ constructor(options) { if (!options || !options.transporter || !options.tokenProvider || !options.getSigninURL) { @@ -46,6 +48,7 @@ class MagicLink { this.getHTML = options.getHTML || defaultGetHTML; this.getSubject = options.getSubject || defaultGetSubject; this.sentry = options.sentry || undefined; + this.config = options.config || {}; } /** @@ -60,12 +63,19 @@ class MagicLink { */ async sendMagicLink(options) { this.sentry?.captureMessage?.(`[Magic Link] Generating magic link`, {extra: options}); - + if (!isEmail(options.email)) { throw new BadRequestError({ message: tpl(messages.invalidEmail) }); } + + if (this.isEmailDomainBlocked(options.email)) { + throw new BadRequestError({ + message: tpl(messages.unsupportedEmailDomain) + }); + } + const token = await this.tokenProvider.create(options.tokenData); const type = options.type || 'signin'; @@ -108,6 +118,24 @@ class MagicLink { const tokenData = await this.tokenProvider.validate(token); return tokenData; } + + /** + * Check if the email domain is blocked, based on the `spam.blocked_email_domains` config + * + * @param {string} email + * @returns {boolean} + */ + isEmailDomainBlocked(email) { + const emailDomain = email.split('@')[1]?.toLowerCase(); + const blockedDomains = this.config?.get('spam:blocked_email_domains'); + + // Config is not set properly: skip check + if (!blockedDomains || !Array.isArray(blockedDomains)) { + return false; + } + + return blockedDomains.includes(emailDomain); + } } /** diff --git a/ghost/magic-link/test/index.test.js b/ghost/magic-link/test/index.test.js index 22520d2671..b7e2de246b 100644 --- a/ghost/magic-link/test/index.test.js +++ b/ghost/magic-link/test/index.test.js @@ -21,6 +21,9 @@ describe('MagicLink', function () { getSubject: sandbox.stub().returns('SOMESUBJECT'), transporter: { sendMail: sandbox.stub().resolves() + }, + config: { + get: sandbox.stub().resolves() } }; const service = new MagicLink(options); @@ -53,6 +56,9 @@ describe('MagicLink', function () { getSubject: sandbox.stub().returns('SOMESUBJECT'), transporter: { sendMail: sandbox.stub().resolves() + }, + config: { + get: sandbox.stub().resolves() } }; const service = new MagicLink(options); @@ -85,6 +91,48 @@ describe('MagicLink', function () { assert.equal(options.transporter.sendMail.firstCall.args[0].text, options.getText.firstCall.returnValue); assert.equal(options.transporter.sendMail.firstCall.args[0].html, options.getHTML.firstCall.returnValue); }); + + it('Blocks signups from blocked email domains', async function () { + const options = { + tokenProvider: new MagicLink.JWTTokenProvider(secret), + getSigninURL: sandbox.stub().returns('FAKEURL'), + getText: sandbox.stub().returns('SOMETEXT'), + getHTML: sandbox.stub().returns('SOMEHTML'), + getSubject: sandbox.stub().returns('SOMESUBJECT'), + transporter: { + sendMail: sandbox.stub().resolves() + }, + config: { + get: sandbox.stub().withArgs('spam:blocked_email_domains').returns(['blocked-domain.com']) + } + }; + const service = new MagicLink(options); + + const blockedArgs = { + email: 'test@blocked-domain.com', + tokenData: { + id: '420' + } + }; + + await assert.rejects( + () => service.sendMagicLink(blockedArgs), + { + name: 'BadRequestError', + message: 'This email domain is not accepted, try again with a different email address' + } + ); + + // Verify non-blocked domain is allowed + const allowedArgs = { + email: 'test@allowed-domain.com', + tokenData: { + id: '420' + } + }; + + await assert.doesNotReject(() => service.sendMagicLink(allowedArgs)); + }); }); describe('#getDataFromToken', function () { @@ -96,6 +144,9 @@ describe('MagicLink', function () { getHTML: sandbox.stub().returns('SOMEHTML'), transporter: { sendMail: sandbox.stub().resolves() + }, + config: { + get: sandbox.stub().resolves() } }; const service = new MagicLink(options); diff --git a/ghost/members-api/lib/members-api.js b/ghost/members-api/lib/members-api.js index 6bacee6d92..660bc6cdca 100644 --- a/ghost/members-api/lib/members-api.js +++ b/ghost/members-api/lib/members-api.js @@ -73,7 +73,8 @@ module.exports = function MembersAPI({ emailSuppressionList, settingsCache, sentry, - settingsHelpers + settingsHelpers, + config }) { const tokenService = new TokenService({ privateKey, @@ -158,7 +159,8 @@ module.exports = function MembersAPI({ getText, getHTML, getSubject, - sentry + sentry, + config }); const paymentsService = new PaymentsService({ From ff4545939c98fddb36dfb7144f201a198325014b Mon Sep 17 00:00:00 2001 From: Ghost CI <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:07:50 +0000 Subject: [PATCH 2/2] v5.107.1 --- ghost/admin/package.json | 2 +- ghost/core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ghost/admin/package.json b/ghost/admin/package.json index 52061fc8d4..e5ea264558 100644 --- a/ghost/admin/package.json +++ b/ghost/admin/package.json @@ -1,6 +1,6 @@ { "name": "ghost-admin", - "version": "5.107.0", + "version": "5.107.1", "description": "Ember.js admin client for Ghost", "author": "Ghost Foundation", "homepage": "http://ghost.org", diff --git a/ghost/core/package.json b/ghost/core/package.json index 76e0d79632..f5b948a788 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -1,6 +1,6 @@ { "name": "ghost", - "version": "5.107.0", + "version": "5.107.1", "description": "The professional publishing platform", "author": "Ghost Foundation", "homepage": "https://ghost.org",