Merge branch 'email-blacklist' into 'develop'
authorlain <lain@soykaf.club>
Tue, 4 Aug 2020 11:00:30 +0000 (11:00 +0000)
committerlain <lain@soykaf.club>
Tue, 4 Aug 2020 11:00:30 +0000 (11:00 +0000)
Add email blacklist, fixes #1404

Closes #1404

See merge request pleroma/pleroma!2837

CHANGELOG.md
config/config.exs
config/description.exs
docs/configuration/cheatsheet.md
lib/pleroma/user.ex
test/user_test.exs
test/web/mastodon_api/controllers/account_controller_test.exs

index 4b682d70b620b11ce3bcccdf26b6335917deee3f..de017e30aab54b6bf99a59117d97f3aba5c3c817 100644 (file)
@@ -49,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 ### Added
 
+- Configuration: Added a blacklist for email servers.
 - Chats: Added `accepts_chat_messages` field to user, exposed in APIs and federation.
 - Chats: Added support for federated chats. For details, see the docs.
 - ActivityPub: Added support for existing AP ids for instances migrated from Mastodon.
index fa8051e402344a22c40daf2477906a339384fdd4..933a899ab77100b1c608d97f8b64ed64414df8eb 100644 (file)
@@ -516,7 +516,8 @@ config :pleroma, Pleroma.User,
     "user_exists",
     "users",
     "web"
-  ]
+  ],
+  email_blacklist: []
 
 config :pleroma, Oban,
   repo: Pleroma.Repo,
index ae2f6d23fd68322e9ba69af2eb8fcc692b7b8f37..d823812fbd33d4fba0f2e56662d3880606455e87 100644 (file)
@@ -3056,6 +3056,7 @@ config :pleroma, :config_description, [
       %{
         key: :restricted_nicknames,
         type: {:list, :string},
+        description: "List of nicknames users may not register with.",
         suggestions: [
           ".well-known",
           "~",
@@ -3088,6 +3089,12 @@ config :pleroma, :config_description, [
           "users",
           "web"
         ]
+      },
+      %{
+        key: :email_blacklist,
+        type: {:list, :string},
+        description: "List of email domains users may not register with.",
+        suggestions: ["mailinator.com", "maildrop.cc"]
       }
     ]
   },
index 5891fc9b0fe569dd0a7022804c92e5cef8d772d0..f23cf4fe4cb62e7366ee95a01c59d69bd7943cdf 100644 (file)
@@ -207,6 +207,11 @@ config :pleroma, :mrf_user_allowlist, %{
 * `sign_object_fetches`: Sign object fetches with HTTP signatures
 * `authorized_fetch_mode`: Require HTTP signatures for AP fetches
 
+## Pleroma.User
+
+* `restricted_nicknames`: List of nicknames users may not register with.
+* `email_blacklist`: List of email domains users may not register with.
+
 ## Pleroma.ScheduledActivity
 
 * `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`)
index 0c1fab2230744415bb994c397db8c7596c01c399..09e606b370392fdae75970f692d7adf9aca6c5db 100644 (file)
@@ -676,10 +676,19 @@ defmodule Pleroma.User do
     |> validate_required([:name, :nickname, :password, :password_confirmation])
     |> validate_confirmation(:password)
     |> unique_constraint(:email)
+    |> validate_format(:email, @email_regex)
+    |> validate_change(:email, fn :email, email ->
+      valid? =
+        Config.get([User, :email_blacklist])
+        |> Enum.all?(fn blacklisted_domain ->
+          !String.ends_with?(email, ["@" <> blacklisted_domain, "." <> blacklisted_domain])
+        end)
+
+      if valid?, do: [], else: [email: "Invalid email"]
+    end)
     |> unique_constraint(:nickname)
     |> validate_exclusion(:nickname, Config.get([User, :restricted_nicknames]))
     |> validate_format(:nickname, local_nickname_regex())
-    |> validate_format(:email, @email_regex)
     |> validate_length(:bio, max: bio_limit)
     |> validate_length(:name, min: 1, max: name_limit)
     |> validate_length(:registration_reason, max: reason_limit)
index 2c1f2b7c5d7e58edb21a453aae556487bb0921bb..b4740589593bb8e673b6914ac63e51102ba4e566 100644 (file)
@@ -513,6 +513,29 @@ defmodule Pleroma.UserTest do
       refute changeset.valid?
     end
 
+    test "it blocks blacklisted email domains" do
+      clear_config([User, :email_blacklist], ["trolling.world"])
+
+      # Block with match
+      params = Map.put(@full_user_data, :email, "troll@trolling.world")
+      changeset = User.register_changeset(%User{}, params)
+      refute changeset.valid?
+
+      # Block with subdomain match
+      params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
+      changeset = User.register_changeset(%User{}, params)
+      refute changeset.valid?
+
+      # Pass with different domains that are similar
+      params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
+      changeset = User.register_changeset(%User{}, params)
+      assert changeset.valid?
+
+      params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
+      changeset = User.register_changeset(%User{}, params)
+      assert changeset.valid?
+    end
+
     test "it sets the password_hash and ap_id" do
       changeset = User.register_changeset(%User{}, @full_user_data)
 
index d390c3ce12770c5bbb07e12ead83bcbb02de1d58..17a1e7d661f9234102c28807e54ee0fa7ea8953a 100644 (file)
@@ -940,17 +940,32 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
       assert refresh
       assert scope == "read write follow"
 
+      clear_config([User, :email_blacklist], ["example.org"])
+
+      params = %{
+        username: "lain",
+        email: "lain@example.org",
+        password: "PlzDontHackLain",
+        bio: "Test Bio",
+        agreement: true
+      }
+
       conn =
         build_conn()
         |> put_req_header("content-type", "multipart/form-data")
         |> put_req_header("authorization", "Bearer " <> token)
-        |> post("/api/v1/accounts", %{
-          username: "lain",
-          email: "lain@example.org",
-          password: "PlzDontHackLain",
-          bio: "Test Bio",
-          agreement: true
-        })
+        |> post("/api/v1/accounts", params)
+
+      assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
+               json_response_and_validate_schema(conn, 400)
+
+      Pleroma.Config.put([User, :email_blacklist], [])
+
+      conn =
+        build_conn()
+        |> put_req_header("content-type", "multipart/form-data")
+        |> put_req_header("authorization", "Bearer " <> token)
+        |> post("/api/v1/accounts", params)
 
       %{
         "access_token" => token,