Category not accepting "anonymous email" from known users

Reproduce:

  1. Have a “private” category that only has create/reply/see access for members of a specific group. No other permissions.
  2. Enable “anonymous email in” for that specific via a unique working alias to the incoming POP account.
  3. Have a non-staff user that is not a member of the group send an email report in to the category email address from the email address associated with their account.
  4. Send in an email from an account not associated with any known Discourse account.

Expected Behavior:

  • Both #3 and #4 result in new topics in the private category, and the group can begin discussion.

Actual Behavior:

  • The email in #4 works but email in #3 is rejected with the can_create? failed error.
8 лайков

@zogstrip can you review this?

Is this still a problem?

I’m no longer running a site with incoming email enabled so unfortunately can’t reproduce to say either way.

2 лайка

Pretty sure #3 still isn’t working.

When we receive an email, we first try to associate it to a user, and then we check for permissions. Since the user isn’t part of the group, they can’t post.

The email_in_allow_strangers field on the category only works for staged users.

3 лайка

Can confirm #3 still not working. Is the best workaround right now to have emails directed at a group rather than a category? Not my preferred arrangement but I can switch until a patch comes out.

1 лайк

I don’t think we can ever support #3 unless we add another setting that opens up any incoming emails?

This scenario seems to be replaced these days with the group functionality as a type of workaround, although I could see some use cases that it might still be just as valuable for categories/topics/discussions.

Sounds plausible. Is this a big thing to do?

Like you say, this is just a (bad) workaround. IMO this should be controllable on a per-category level. Clearly a bug that this works only for anonymous but not for known users.

1 лайк

Я только что столкнулся с этой проблемой, пытаясь настроить категорию для нашего списка информации об организациях. Эта категория доступна только определённой группе, но мы выбрали опцию, позволяющую анонимным пользователям отправлять письма. Адреса электронной почты, не связанные ни с одним из наших пользователей Discourse, могут отправлять сообщения, которые будут отображаться в категории, однако зарегистрированные пользователи, не входящие в эту группу, получают отказ из-за «недостаточного уровня доверия». Я понимаю техническую причину такого поведения (это работает только для пользователей в стадии проверки), но есть ли причина, по которой это считается желаемым или ожидаемым поведением? Мне кажется, что если мы решаем разрешить анонимным пользователям отправлять сообщения, то мы, вероятно, должны разрешить это и всем зарегистрированным пользователям.

1 лайк

На нашем сайте на прошлой неделе возникла аналогичная проблема. Ситуация у нас следующая:

Хотя большинство наших категорий предназначены только для зарегистрированных пользователей, мы хотели предоставить возможность несостоятельным членам сообщества связываться с основными разработчиками по электронной почте, чтобы задать быстрый вопрос, выразить озабоченность и т. д.

Для этого мы создали категорию, принимающую письма от анонимных пользователей по специальному адресу (например, ourproject+contact@discoursemail.com). Права доступа к этой категории были настроены так, чтобы её могли просматривать только ключевые члены проекта, чтобы избежать избыточной рассылки или шума для всего сообщества (что означало, что создавать темы и отвечать на них могли также только ключевые члены, поскольку невозможно ограничить доступ на чтение без одновременного ограничения доступа на создание тем и ответы).

Однако затем мы обнаружили, что если анонимный пользователь создаёт официальный аккаунт, он больше не может отправлять письма на контактный адрес. Это кажется контринтуитивным: теперь пользователь более «официален» и зарегистрирован, чем раньше, но может делать строго меньше, чем до этого.

Это вызвало у меня значительную путаницу, пока я не наткнулся на эту тему, и всё ещё кажется неудачной ситуацией.

— Брэд

2 лайка

Эта проблема сохраняется в версии 2.7.8. Путает то, что письмо, отправленное на адрес электронной почты, связанный с категорией, принимается, если у отправителя нет зарегистрированной учётной записи на форуме, и отклоняется, если она есть.

3 лайка

Я полагаю, что следующий патч (против текущей ветки main) может решить эту проблему, пропуская проверки, когда для категории установлено email_in_allow_strangers, так же как это делается для пользователей в режиме ожидания. Звучит ли это разумно?

diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb
index 7c76c44d61..dd3bc3cfb0 100644
--- a/lib/email/receiver.rb
+++ b/lib/email/receiver.rb
@@ -762,7 +762,7 @@ module Email
                      elided: elided,
                      title: subject,
                      category: destination.id,
-                     skip_validations: user.staged?)
+                     skip_validations: (user.staged? || destination.email_in_allow_strangers))
 
       elsif destination.is_a?(PostReplyKey)
         # Мы не создаем новых пользователей в режиме ожидания для писем на адреса для ответов, выходим, если пользователь равен nil

Это не работает, потому что валидации касаются содержимого поста, а не разрешений на создание поста или его отсутствие…

Я протестировал приведенный ниже патч, и он работает. Это хак, не пытайтесь повторить это дома :scream: Его достоинство в том, что он примерно указывает, где должны происходить изменения. Задача заключается в том, чтобы понять, как сделать это правильным образом. Любые советы будут очень кстати :pray:

diff --git a/app/jobs/regular/notify_mailing_list_subscribers.rb b/app/jobs/regular/notify_mailing_list_subscribers.rb
index c535296105..1d3bf79637 100644
--- a/app/jobs/regular/notify_mailing_list_subscribers.rb
+++ b/app/jobs/regular/notify_mailing_list_subscribers.rb
@@ -74,7 +74,7 @@ module Jobs
 
       DiscourseEvent.trigger(:notify_mailing_list_subscribers, users, post)
       users.find_each do |user|
-        if Guardian.new(user).can_see?(post)
+        if Guardian.new(user).can_see?(post) && Guardian.new(user).can_see_category_staged?(post.topic.category)
           if EmailLog.reached_max_emails?(user)
             skip(user.email, user.id, post.id,
               SkippedEmailLog.reason_types[:exceeded_emails_limit]
diff --git a/app/models/category.rb b/app/models/category.rb
index 630a74c425..6c253650c6 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -201,7 +201,7 @@ class Category < ActiveRecord::Base
       end
     else
       permissions = permission_types.map { |p| CategoryGroup.permission_types[p] }
-      where("(:staged AND LENGTH(COALESCE(email_in, '')) > 0 AND email_in_allow_strangers)
+      where("(LENGTH(COALESCE(email_in, '')) > 0 AND email_in_allow_strangers)
           OR categories.id NOT IN (SELECT category_id FROM category_groups)
           OR categories.id IN (
                 SELECT category_id
@@ -209,7 +209,6 @@ class Category < ActiveRecord::Base
                  WHERE permission_type IN (:permissions)
                    AND (group_id = :everyone OR group_id IN (SELECT group_id FROM group_users WHERE user_id = :user_id))
              )",
-        staged: guardian.is_staged?,
         permissions: permissions,
         user_id: guardian.user.id,
         everyone: Group[:everyone].id)
diff --git a/lib/guardian/category_guardian.rb b/lib/guardian/category_guardian.rb
index 94a48466d6..2a4ba8015c 100644
--- a/lib/guardian/category_guardian.rb
+++ b/lib/guardian/category_guardian.rb
@@ -64,6 +64,14 @@ module CategoryGuardian
   end
 
   def can_see_category?(category)
+    return false unless category
+    return true if is_admin?
+    return true if !category.read_restricted
+    return true if category.email_in.present? && category.email_in_allow_strangers
+    secure_category_ids.include?(category.id)
+  end
+
+  def can_see_category_staged?(category)
     return false unless category
     return true if is_admin?
     return true if !category.read_restricted
2 лайка

Что вы думаете об этом предложении, @zogstrip?

1 лайк

Я считаю, что такое поведение здесь намеренное; исправление здесь должно быть довольно всеобъемлющим.

Проблема с предоставлением возможности связывать тему с существующей учетной записью заключается в том, что любой может подделать чью угодно электронную почту.

Думаю, долгосрочное решение заключается в следующем:

  1. У sam@somewhere.com есть учетная запись в Discourse.
  2. sam@somewhere.com отправляет письмо в категорию с заголовком «анонимное письмо».
  3. Discourse отправляет письмо на адрес sam@somewhere.com: «Похоже, вы опубликовали: СОДЕРЖИМОЕ ПОСТА, по URL-адресу Discourse. Это действительно вы?
  4. Нажмите «Да».
  5. Тема создается.

Без этой защиты данная функция была бы открыта для подмены личности, что представляет собой высокий риск.

5 лайков

Разве эта проблема уже не существует независимо от параметра «Принимать электронную почту от анонимных пользователей без учётных записей»?

Я разделяю эту точку зрения: когда электронная почта связана с категорией и установлен флажок «Принимать электронную почту от анонимных пользователей без учётных записей», входящее сообщение

  1. связанное с учётной записью Discourse
  2. которое не имеет права читать сообщения согласно параметрам «Безопасность» категории

должно приниматься.

1 лайк

Разве использование SPF/DKIM/DMARC, которое сейчас гораздо более распространено, чем в 2016 году, не обеспечивает достаточной защиты от этого?

Любой хороший почтовый провайдер (для пользователя) не позволит другим пользователям отправлять письма с адресов, которые им не принадлежат, а любой хороший почтовый провайдер или принимающая служба (для экземпляра Discourse) должна отклонять письма, не прошедшие проверку подлинности отправителя.

Существуют провайдеры, которые не проверяют адрес отправителя и/или не настраивают записи SPF и т. д., но если пользователь выбирает почтового провайдера, который ничего не делает для защиты от подмены личности, кажется разумным, что его могут подменить.

Я не углублялся в это особенно подробно, но похоже, что Email::AuthenticationResults уже выполняет некоторую проверку происхождения. Возможно, в краткосрочной (или среднесрочной) перспективе можно сделать доступным вердикт (если это ещё не сделано), чтобы такие письма могли приниматься с вердиктом «пройдено».

В вашем долгосрочном решении проверку «были ли это действительно вы?» можно также пропустить в случае вердикта «пройдено».