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 curtidas

@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 curtidas

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 curtidas

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 curtida

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 curtida

I just ran into this issue while trying to set up a category for our organizations info list. This category only allows a certain group to access it, but we selected the option to allow emails from anonymous users. Email addresses that are not associated with any of our discourse users can send a message that will show up in the category, but registered users that are not in the group get rejected due to “Insufficient Trust Level”. I think I understand the technical reason why it works this way (only works for staged users) but is there a reason why this would be the desired or expected behavior? It seems to me if we are choosing to allow anonymous users we probably want to allow all registered users as well.

1 curtida

Também nos deparamos com esse problema em nosso site na semana passada. Para nós, a situação é a seguinte:

Embora a maioria de nossas categorias seja destinada apenas a usuários registrados, queríamos uma maneira de um não membro da comunidade entrar em contato com os desenvolvedores principais por e-mail para fazer uma pergunta rápida, levantar uma preocupação, etc.

Fizemos isso configurando uma categoria para aceitar e-mails de usuários anônimos usando um endereço personalizado (por exemplo, ourproject+contact@discoursemail.com). Definimos as permissões da categoria como legíveis apenas pelos membros principais do projeto, para evitar gerar muitos e-mails ou ruídos para a comunidade em geral (o que significou tornar os tópicos criáveis e respondíveis também pelos membros principais, já que não há como restringir o acesso de leitura sem limitar também o acesso de criação/resposta).

No entanto, descobrimos que, se o usuário anônimo posteriormente criasse uma conta oficial, ele não poderia mais enviar e-mails para o endereço de contato. Isso parece contra-intuitivo, pois agora ele é apenas mais oficial e registrado do que antes, mas pode fazer estritamente menos do que conseguia antes.

Isso me causou grande confusão antes de eu encontrar este tópico e ainda parece uma situação infeliz.

-Brad

2 curtidas

Este problema ainda existe na versão 2.7.8. É confuso que um e-mail enviado para o endereço associado a uma categoria seja aceito quando o remetente não tem uma conta registrada no fórum, e rejeitado caso contrário.

3 curtidas

Acredito que o seguinte patch (contra a atual branch main) possa resolver esse problema ao ignorar validações quando email_in_allow_strangers está definido para a categoria, da mesma forma que é ignorado para usuários em fase de preparação (staged). Isso faz sentido?

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)
         # Não criamos novos usuários em fase de preparação para e-mails de resposta; sair se o usuário for nil

Não funciona porque as validações tratam do conteúdo da postagem, e não sobre permissões para criar ou não uma postagem…

Testei o patch abaixo para funcionar. É um truque, não tente isso em casa :scream: Seu mérito é identificar aproximadamente onde as alterações devem ocorrer. O desafio é descobrir como fazer isso da maneira correta. Qualquer conselho será muito bem-vindo :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 curtidas

O que você acha dessa sugestão, @zogstrip?

1 curtida

Acredito que o comportamento aqui seja intencional; uma correção aqui terá de ser bastante abrangente.

O problema em permitir que as pessoas associem um tópico a uma conta existente é que qualquer pessoa pode falsificar o e-mail de outra.

Acredito que a maneira de resolver isso a longo prazo seja:

  1. sam@somewhere.com tem uma conta no Discourse.
  2. sam@somewhere.com envia um e-mail para uma categoria com e-mail anônimo em.
  3. O Discourse envia um e-mail para sam@somewhere.com: "Parece que você publicou: CONTEÚDO DA PUBLICAÇÃO, no URL do Discourse. Foi realmente você?
  4. Clique em Sim.
  5. O tópico é criado.

Sem essa proteção, esse recurso ficaria totalmente aberto a impersonificação, o que é muito arriscado.

5 curtidas

Essa questão já não existe, independentemente do parâmetro Aceitar e-mails de usuários anônimos sem conta?

Eu compartilho desse ponto de vista: quando um e-mail é associado a uma categoria e a caixa Aceitar e-mails de usuários anônimos sem conta está marcada, um e-mail recebido

  1. associado a uma conta Discourse
  2. que não tem permissão para ler as mensagens de acordo com os parâmetros de Segurança da categoria

deve ser aceito.

1 curtida

O uso de SPF/DKIM/DMARC, que é muito mais prolífico agora do que em 2016, não protege contra isso em um grau bom o suficiente?

Qualquer bom provedor de e-mail (para o usuário) não permitirá que outros usuários enviem de endereços que não lhes pertencem e qualquer bom provedor de e-mail ou serviço de recebimento (para a instância do Discourse) deve rejeitar e-mails que falham na validação de origem.

Existirão provedores que não validam o endereço do remetente e/ou não configuram registros SPF/etc., mas se um usuário optar por usar um provedor de e-mail que não faz nada para proteger contra falsificação de identidade, parece razoável que ele possa ser falsificado.

Eu não me aprofundei particularmente nisso, mas parece que Email::AuthenticationResults já faz alguma validação de origem. Talvez, a curto (mais curto) prazo, o veredito possa ser disponibilizado (se já não for) para que esses e-mails possam ser aceitos com um veredito de aprovação.

Na sua solução de longo prazo, a verificação “foi realmente você?” também poderia ser pulada no caso de um veredito de aprovação.