aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorlain <lain@soykaf.club>2019-08-20 12:44:14 +0000
committerlain <lain@soykaf.club>2019-08-20 12:44:14 +0000
commitef43016b2c03f02ed6d77c6ca4afb1f19ff04771 (patch)
tree01566e4988a6948104d109ca3b7b70d8598a4db5 /lib
parent10696ce2eede57d256e6a1b6f4775037fd63b146 (diff)
parenta2e1db56323d0f306ee42a1f58471eb55c8c1e68 (diff)
downloadpleroma-ef43016b2c03f02ed6d77c6ca4afb1f19ff04771.tar.gz
Merge branch 'feature/custom-fields' into 'develop'
Add custom profile fields See merge request pleroma/pleroma!1488
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/html.ex28
-rw-r--r--lib/pleroma/user.ex4
-rw-r--r--lib/pleroma/user/info.ex51
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex7
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex10
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex12
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex10
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex15
-rw-r--r--lib/pleroma/web/twitter_api/views/user_view.ex13
9 files changed, 135 insertions, 15 deletions
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
index 06e60cba3..3951f0f51 100644
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -282,3 +282,31 @@ defmodule Pleroma.HTML.Transform.MediaProxy do
def scrub({_tag, children}), do: children
def scrub(text), do: text
end
+
+defmodule Pleroma.HTML.Scrubber.LinksOnly do
+ @moduledoc """
+ An HTML scrubbing policy which limits to links only.
+ """
+
+ @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
+
+ require HtmlSanitizeEx.Scrubber.Meta
+ alias HtmlSanitizeEx.Scrubber.Meta
+
+ Meta.remove_cdata_sections_before_scrub()
+ Meta.strip_comments()
+
+ # links
+ Meta.allow_tag_with_uri_attributes("a", ["href"], @valid_schemes)
+
+ Meta.allow_tag_with_this_attribute_values("a", "rel", [
+ "tag",
+ "nofollow",
+ "noopener",
+ "noreferrer",
+ "me"
+ ])
+
+ Meta.allow_tag_with_these_attributes("a", ["name", "title"])
+ Meta.strip_everything_not_covered()
+end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 02011f4e6..134b8bb6c 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -222,12 +222,12 @@ defmodule Pleroma.User do
|> validate_length(:name, min: 1, max: name_limit)
end
- def upgrade_changeset(struct, params \\ %{}) do
+ def upgrade_changeset(struct, params \\ %{}, remote? \\ false) do
bio_limit = Pleroma.Config.get([:instance, :user_bio_length], 5000)
name_limit = Pleroma.Config.get([:instance, :user_name_length], 100)
params = Map.put(params, :last_refreshed_at, NaiveDateTime.utc_now())
- info_cng = User.Info.user_upgrade(struct.info, params[:info])
+ info_cng = User.Info.user_upgrade(struct.info, params[:info], remote?)
struct
|> cast(params, [
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index 22eb9a182..45a39924b 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -49,6 +49,8 @@ defmodule Pleroma.User.Info do
field(:mascot, :map, default: nil)
field(:emoji, {:array, :map}, default: [])
field(:pleroma_settings_store, :map, default: %{})
+ field(:fields, {:array, :map}, default: [])
+ field(:raw_fields, {:array, :map}, default: [])
field(:notification_settings, :map,
default: %{
@@ -254,11 +256,13 @@ defmodule Pleroma.User.Info do
:hide_followers,
:hide_follows,
:follower_count,
+ :fields,
:following_count
])
+ |> validate_fields(true)
end
- def user_upgrade(info, params) do
+ def user_upgrade(info, params, remote? \\ false) do
info
|> cast(params, [
:ap_enabled,
@@ -269,8 +273,10 @@ defmodule Pleroma.User.Info do
:follower_count,
:following_count,
:hide_follows,
+ :fields,
:hide_followers
])
+ |> validate_fields(remote?)
end
def profile_update(info, params) do
@@ -286,10 +292,40 @@ defmodule Pleroma.User.Info do
:background,
:show_role,
:skip_thread_containment,
+ :fields,
+ :raw_fields,
:pleroma_settings_store
])
+ |> validate_fields()
end
+ def validate_fields(changeset, remote? \\ false) do
+ limit_name = if remote?, do: :max_remote_account_fields, else: :max_account_fields
+ limit = Pleroma.Config.get([:instance, limit_name], 0)
+
+ changeset
+ |> validate_length(:fields, max: limit)
+ |> validate_change(:fields, fn :fields, fields ->
+ if Enum.all?(fields, &valid_field?/1) do
+ []
+ else
+ [fields: "invalid"]
+ end
+ end)
+ end
+
+ defp valid_field?(%{"name" => name, "value" => value}) do
+ name_limit = Pleroma.Config.get([:instance, :account_field_name_length], 255)
+ value_limit = Pleroma.Config.get([:instance, :account_field_value_length], 255)
+
+ is_binary(name) &&
+ is_binary(value) &&
+ String.length(name) <= name_limit &&
+ String.length(value) <= value_limit
+ end
+
+ defp valid_field?(_), do: false
+
@spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t()
def confirmation_changeset(info, opts) do
need_confirmation? = Keyword.get(opts, :need_confirmation)
@@ -384,6 +420,19 @@ defmodule Pleroma.User.Info do
cast(info, params, [:muted_reblogs])
end
+ # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.
+ # For example: [{"name": "Pronoun", "value": "she/her"}, …]
+ def fields(%{fields: [], source_data: %{"attachment" => attachment}}) do
+ limit = Pleroma.Config.get([:instance, :max_remote_account_fields], 0)
+
+ attachment
+ |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
+ |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+ |> Enum.take(limit)
+ end
+
+ def fields(%{fields: fields}), do: fields
+
def follow_information_update(info, params) do
info
|> cast(params, [
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 1a8e3ad96..af9749d13 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1023,6 +1023,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
"url" => [%{"href" => data["image"]["url"]}]
}
+ fields =
+ data
+ |> Map.get("attachment", [])
+ |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
+ |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+
locked = data["manuallyApprovesFollowers"] || false
data = Transmogrifier.maybe_fix_user_object(data)
@@ -1032,6 +1038,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
ap_enabled: true,
source_data: data,
banner: banner,
+ fields: fields,
locked: locked
},
avatar: avatar,
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 0fcc81bf3..36340a3a1 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -598,14 +598,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
banner = new_user_data[:info][:banner]
locked = new_user_data[:info][:locked] || false
+ attachment = get_in(new_user_data, [:info, :source_data, "attachment"]) || []
+
+ fields =
+ attachment
+ |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
+ |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
update_data =
new_user_data
|> Map.take([:name, :bio, :avatar])
- |> Map.put(:info, %{banner: banner, locked: locked})
+ |> Map.put(:info, %{banner: banner, locked: locked, fields: fields})
actor
- |> User.upgrade_changeset(update_data)
+ |> User.upgrade_changeset(update_data, true)
|> User.update_and_set_cache()
ActivityPub.update(%{
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 06c9e1c71..7be734b26 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -80,6 +80,17 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|> Transmogrifier.add_emoji_tags()
|> Map.get("tag", [])
+ fields =
+ user.info
+ |> User.Info.fields()
+ |> Enum.map(fn %{"name" => name, "value" => value} ->
+ %{
+ "name" => Pleroma.HTML.strip_tags(name),
+ "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
+ }
+ end)
+ |> Enum.map(&Map.put(&1, "type", "PropertyValue"))
+
%{
"id" => user.ap_id,
"type" => "Person",
@@ -98,6 +109,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"publicKeyPem" => public_key
},
"endpoints" => endpoints,
+ "attachment" => fields,
"tag" => (user.info.source_data["tag"] || []) ++ user_tags
}
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 8fe7be8be..53cf95fbb 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -138,7 +138,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
user_info_emojis =
- ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text))
+ user.info
+ |> Map.get(:emoji, [])
+ |> Enum.concat(Formatter.get_emoji_map(emojis_text))
|> Enum.dedup()
info_params =
@@ -157,6 +159,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end)
end)
|> add_if_present(params, "default_scope", :default_scope)
+ |> add_if_present(params, "fields", :fields, fn fields ->
+ fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end)
+
+ {:ok, fields}
+ end)
+ |> add_if_present(params, "fields", :raw_fields)
|> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value ->
{:ok, Map.merge(user.info.pleroma_settings_store, value)}
end)
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 0ef568f0f..169116d0d 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -94,12 +94,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end)
fields =
- (user.info.source_data["attachment"] || [])
- |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
- |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+ user.info
+ |> User.Info.fields()
+ |> Enum.map(fn %{"name" => name, "value" => value} ->
+ %{
+ "name" => Pleroma.HTML.strip_tags(name),
+ "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
+ }
+ end)
- bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
+ raw_fields = Map.get(user.info, :raw_fields, [])
+ bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
relationship = render("relationship.json", %{user: opts[:for], target: user})
%{
@@ -124,6 +130,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
source: %{
note: HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
sensitive: false,
+ fields: raw_fields,
pleroma: %{}
},
diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex
index 8d8892068..8a7d2fc72 100644
--- a/lib/pleroma/web/twitter_api/views/user_view.ex
+++ b/lib/pleroma/web/twitter_api/views/user_view.ex
@@ -74,12 +74,15 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|> HTML.filter_tags(User.html_filter_policy(for_user))
|> Formatter.emojify(emoji)
- # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``.
- # For example: [{"name": "Pronoun", "value": "she/her"}, …]
fields =
- (user.info.source_data["attachment"] || [])
- |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
- |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+ user.info
+ |> User.Info.fields()
+ |> Enum.map(fn %{"name" => name, "value" => value} ->
+ %{
+ "name" => Pleroma.HTML.strip_tags(name),
+ "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
+ }
+ end)
data =
%{