Optionally store user IP addresses, #1708
This commit is contained in:
parent
5e128a6be3
commit
4c76e3e3b7
@ -686,6 +686,8 @@ config :pleroma, Pleroma.Web.Plugs.RemoteIp,
|
||||
"192.168.0.0/16"
|
||||
]
|
||||
|
||||
config :pleroma, Pleroma.Web.Plugs.StoreUserIpPlug, enabled: false
|
||||
|
||||
config :pleroma, :static_fe, enabled: false
|
||||
|
||||
# Example of frontend configuration
|
||||
|
@ -2844,7 +2844,7 @@ config :pleroma, :config_description, [
|
||||
%{
|
||||
key: :enabled,
|
||||
type: :boolean,
|
||||
description: "Enable/disable the plug. Default: disabled."
|
||||
description: "Enable/disable the plug. Default: enabled."
|
||||
},
|
||||
%{
|
||||
key: :headers,
|
||||
@ -2870,6 +2870,21 @@ config :pleroma, :config_description, [
|
||||
},
|
||||
%{
|
||||
group: :pleroma,
|
||||
key: Pleroma.Web.Plugs.StoreUserIpPlug,
|
||||
type: :group,
|
||||
description: """
|
||||
Stores the user's last known IP address in the database if enabled. IP addresses are shown in AdminAPI.
|
||||
""",
|
||||
children: [
|
||||
%{
|
||||
key: :enabled,
|
||||
type: :boolean,
|
||||
description: "Enable/disable the plug. Default: disabled."
|
||||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :pleroma,
|
||||
key: :web_cache_ttl,
|
||||
label: "Web cache TTL",
|
||||
type: :group,
|
||||
|
22
lib/pleroma/ecto_type/ip_address.ex
Normal file
22
lib/pleroma/ecto_type/ip_address.ex
Normal file
@ -0,0 +1,22 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.EctoType.IpAddress do
|
||||
alias Postgrex.INET
|
||||
@behaviour Ecto.Type
|
||||
|
||||
def type, do: :inet
|
||||
|
||||
def cast(%INET{address: ip, netmask: nil}), do: {:ok, ip}
|
||||
def cast(ip) when is_tuple(ip), do: {:ok, ip}
|
||||
|
||||
def load(%INET{address: ip, netmask: nil}), do: {:ok, ip}
|
||||
|
||||
def dump(ip) when is_tuple(ip), do: {:ok, %INET{address: ip, netmask: nil}}
|
||||
def dump(_), do: :error
|
||||
|
||||
def equal?(a, b), do: a == b
|
||||
|
||||
def embed_as(_), do: :self
|
||||
end
|
@ -146,6 +146,7 @@ defmodule Pleroma.User do
|
||||
field(:inbox, :string)
|
||||
field(:shared_inbox, :string)
|
||||
field(:accepts_chat_messages, :boolean, default: nil)
|
||||
field(:last_known_ip, Pleroma.EctoType.IpAddress)
|
||||
|
||||
embeds_one(
|
||||
:notification_settings,
|
||||
@ -2457,4 +2458,12 @@ defmodule Pleroma.User do
|
||||
def get_host(%User{ap_id: ap_id} = _user) do
|
||||
URI.parse(ap_id).host
|
||||
end
|
||||
|
||||
def update_last_known_ip(%User{last_known_ip: ip} = user, ip), do: {:ok, user}
|
||||
|
||||
def update_last_known_ip(%User{} = user, ip) when is_tuple(ip) do
|
||||
user
|
||||
|> change(last_known_ip: ip)
|
||||
|> update_and_set_cache()
|
||||
end
|
||||
end
|
||||
|
39
lib/pleroma/web/plugs/store_user_ip_plug.ex
Normal file
39
lib/pleroma/web/plugs/store_user_ip_plug.ex
Normal file
@ -0,0 +1,39 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.StoreUserIpPlug do
|
||||
@moduledoc """
|
||||
Stores the user's last known IP address in the database if enabled.
|
||||
User IP addresses are shown in AdminAPI.
|
||||
"""
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
import Plug.Conn
|
||||
|
||||
@behaviour Plug
|
||||
|
||||
def init(_), do: nil
|
||||
|
||||
# IP address hasn't changed, so skip
|
||||
def call(
|
||||
%{remote_ip: ip, assigns: %{remote_ip_found: true, user: %User{last_known_ip: ip}}} =
|
||||
conn,
|
||||
_
|
||||
),
|
||||
do: conn
|
||||
|
||||
# Store user IP if enabled
|
||||
def call(%{remote_ip: ip, assigns: %{remote_ip_found: true, user: %User{} = user}} = conn, _) do
|
||||
with true <- Config.get([__MODULE__, :enabled]),
|
||||
{:ok, %User{} = user} <- User.update_last_known_ip(user, ip) do
|
||||
assign(conn, :user, user)
|
||||
else
|
||||
_ -> conn
|
||||
end
|
||||
end
|
||||
|
||||
# Fail silently
|
||||
def call(conn, _), do: conn
|
||||
end
|
@ -56,6 +56,7 @@ defmodule Pleroma.Web.Router do
|
||||
plug(Pleroma.Web.Plugs.UserEnabledPlug)
|
||||
plug(Pleroma.Web.Plugs.SetUserSessionIdPlug)
|
||||
plug(Pleroma.Web.Plugs.EnsureUserTokenAssignsPlug)
|
||||
plug(Pleroma.Web.Plugs.StoreUserIpPlug)
|
||||
end
|
||||
|
||||
pipeline :base_api do
|
||||
|
@ -0,0 +1,11 @@
|
||||
defmodule Pleroma.Repo.Migrations.AddLastKnownIpToUsers do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:users) do
|
||||
add(:last_known_ip, :inet)
|
||||
end
|
||||
|
||||
create(index(:users, [:last_known_ip]))
|
||||
end
|
||||
end
|
@ -2271,4 +2271,11 @@ defmodule Pleroma.UserTest do
|
||||
user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
|
||||
assert User.get_host(user) == "lain.com"
|
||||
end
|
||||
|
||||
test "update_last_known_ip/2" do
|
||||
%User{id: user_id} = user = insert(:user, last_known_ip: {1, 2, 3, 4})
|
||||
|
||||
assert {:ok, %User{id: ^user_id, last_known_ip: {5, 4, 3, 2}}} =
|
||||
User.update_last_known_ip(user, {5, 4, 3, 2})
|
||||
end
|
||||
end
|
||||
|
59
test/pleroma/web/plugs/store_user_ip_plug_test.exs
Normal file
59
test/pleroma/web/plugs/store_user_ip_plug_test.exs
Normal file
@ -0,0 +1,59 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.StoreUserIpPlugTest do
|
||||
use Pleroma.Web.ConnCase, async: true
|
||||
use Plug.Test
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.Plugs.RemoteIp
|
||||
alias Pleroma.Web.Plugs.StoreUserIpPlug
|
||||
import Pleroma.Factory
|
||||
|
||||
setup do: clear_config(StoreUserIpPlug, enabled: true)
|
||||
|
||||
setup do:
|
||||
clear_config(RemoteIp,
|
||||
enabled: true,
|
||||
headers: ["x-forwarded-for"],
|
||||
proxies: [],
|
||||
reserved: [
|
||||
"127.0.0.0/8",
|
||||
"::1/128",
|
||||
"fc00::/7",
|
||||
"10.0.0.0/8",
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16"
|
||||
]
|
||||
)
|
||||
|
||||
test "stores the user's IP address", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> put_req_header("x-forwarded-for", "1.2.3.4")
|
||||
|> RemoteIp.call(nil)
|
||||
|> StoreUserIpPlug.call(nil)
|
||||
|
||||
user = User.get_by_id(user.id)
|
||||
assert user.last_known_ip == {1, 2, 3, 4}
|
||||
assert %Plug.Conn{assigns: %{user: %User{last_known_ip: {1, 2, 3, 4}} = ^user}} = conn
|
||||
end
|
||||
|
||||
test "does nothing when disabled", %{conn: conn} do
|
||||
clear_config(StoreUserIpPlug, enabled: false)
|
||||
user = insert(:user, last_known_ip: {1, 2, 3, 4})
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, user)
|
||||
|> put_req_header("x-forwarded-for", "5.4.3.2")
|
||||
|> RemoteIp.call(nil)
|
||||
|> StoreUserIpPlug.call(nil)
|
||||
|
||||
assert user == User.get_by_id(user.id)
|
||||
assert %Plug.Conn{assigns: %{user: %User{last_known_ip: {1, 2, 3, 4}} = ^user}} = conn
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user