Merge branch 'image_description_from_exif_data' into 'develop'
Use EXIF data of image for image description See merge request pleroma/pleroma!3535
This commit is contained in:
commit
de37583c49
19 changed files with 384 additions and 32 deletions
|
@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Allow users to remove their emails if instance does not need email to register
|
- Allow users to remove their emails if instance does not need email to register
|
||||||
|
- Uploadfilter `Pleroma.Upload.Filter.Exiftool` has been renamed to `Pleroma.Upload.Filter.Exiftool.StripLocation`
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `activeMonth` and `activeHalfyear` fields in NodeInfo usage.users object
|
- `activeMonth` and `activeHalfyear` fields in NodeInfo usage.users object
|
||||||
|
@ -30,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Configuration: Add `birthday_required` and `birthday_min_age` settings to provide a way to require users to enter their birth date.
|
- Configuration: Add `birthday_required` and `birthday_min_age` settings to provide a way to require users to enter their birth date.
|
||||||
- PleromaAPI: Add `GET /api/v1/pleroma/birthdays` API endpoint
|
- PleromaAPI: Add `GET /api/v1/pleroma/birthdays` API endpoint
|
||||||
- Make backend-rendered pages translatable. This includes emails. Pages returned as a HTTP response are translated using the language specified in the `userLanguage` cookie, or the `Accept-Language` header. Emails are translated using the `language` field when registering. This language can be changed by `PATCH /api/v1/accounts/update_credentials` with the `language` field.
|
- Make backend-rendered pages translatable. This includes emails. Pages returned as a HTTP response are translated using the language specified in the `userLanguage` cookie, or the `Accept-Language` header. Emails are translated using the `language` field when registering. This language can be changed by `PATCH /api/v1/accounts/update_credentials` with the `language` field.
|
||||||
|
- Uploadfilter `Pleroma.Upload.Filter.Exiftool.ReadDescription` returns description values to the FE so they can pre fill the image description field
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||||
|
|
|
@ -37,7 +37,8 @@ If any of the options are left unspecified, you will be prompted interactively.
|
||||||
- `--static-dir <path>` - the directory custom public files should be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)
|
- `--static-dir <path>` - the directory custom public files should be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)
|
||||||
- `--listen-ip <ip>` - the ip the app should listen to, defaults to 127.0.0.1
|
- `--listen-ip <ip>` - the ip the app should listen to, defaults to 127.0.0.1
|
||||||
- `--listen-port <port>` - the port the app should listen to, defaults to 4000
|
- `--listen-port <port>` - the port the app should listen to, defaults to 4000
|
||||||
- `--strip-uploads <Y|N>` - use ExifTool to strip uploads of sensitive location data
|
- `--strip-uploads-location <Y|N>` - use ExifTool to strip uploads of sensitive location data
|
||||||
|
- `--read-uploads-description <Y|N>` - use ExifTool to read image descriptions from uploads
|
||||||
- `--anonymize-uploads <Y|N>` - randomize uploaded filenames
|
- `--anonymize-uploads <Y|N>` - randomize uploaded filenames
|
||||||
- `--dedupe-uploads <Y|N>` - store files based on their hash to reduce data storage requirements if duplicates are uploaded with different filenames
|
- `--dedupe-uploads <Y|N>` - store files based on their hash to reduce data storage requirements if duplicates are uploaded with different filenames
|
||||||
- `--skip-release-env` - skip generation the release environment file
|
- `--skip-release-env` - skip generation the release environment file
|
||||||
|
|
|
@ -627,12 +627,18 @@ This filter replaces the filename (not the path) of an upload. For complete obfu
|
||||||
|
|
||||||
No specific configuration.
|
No specific configuration.
|
||||||
|
|
||||||
#### Pleroma.Upload.Filter.Exiftool
|
#### Pleroma.Upload.Filter.Exiftool.StripLocation
|
||||||
|
|
||||||
This filter only strips the GPS and location metadata with Exiftool leaving color profiles and attributes intact.
|
This filter only strips the GPS and location metadata with Exiftool leaving color profiles and attributes intact.
|
||||||
|
|
||||||
No specific configuration.
|
No specific configuration.
|
||||||
|
|
||||||
|
#### Pleroma.Upload.Filter.Exiftool.ReadDescription
|
||||||
|
|
||||||
|
This filter reads the ImageDescription and iptc:Caption-Abstract fields with Exiftool so clients can prefill the media description field.
|
||||||
|
|
||||||
|
No specific configuration.
|
||||||
|
|
||||||
#### Pleroma.Upload.Filter.Mogrify
|
#### Pleroma.Upload.Filter.Mogrify
|
||||||
|
|
||||||
* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`.
|
* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# Optional software packages needed for specific functionality
|
# Optional software packages needed for specific functionality
|
||||||
|
|
||||||
For specific Pleroma functionality (which is disabled by default) some or all of the below packages are required:
|
For specific Pleroma functionality (which is disabled by default) some or all of the below packages are required:
|
||||||
* `ImageMagic`
|
* `ImageMagic`
|
||||||
* `ffmpeg`
|
* `ffmpeg`
|
||||||
* `exiftool`
|
* `exiftool`
|
||||||
|
|
||||||
Please refer to documentation in `docs/installation` on how to install them on specific OS.
|
Please refer to documentation in `docs/installation` on how to install them on specific OS.
|
||||||
|
|
||||||
|
@ -14,19 +14,20 @@ Note: the packages are not required with the current default settings of Pleroma
|
||||||
`ImageMagick` is a set of tools to create, edit, compose, or convert bitmap images.
|
`ImageMagick` is a set of tools to create, edit, compose, or convert bitmap images.
|
||||||
|
|
||||||
It is required for the following Pleroma features:
|
It is required for the following Pleroma features:
|
||||||
* `Pleroma.Upload.Filters.Mogrify`, `Pleroma.Upload.Filters.Mogrifun` upload filters (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
* `Pleroma.Upload.Filters.Mogrify`, `Pleroma.Upload.Filters.Mogrifun` upload filters (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
||||||
* Media preview proxy for still images (related config: `media_preview_proxy/enabled` in `config/config.exs`)
|
* Media preview proxy for still images (related config: `media_preview_proxy/enabled` in `config/config.exs`)
|
||||||
|
|
||||||
## `ffmpeg`
|
## `ffmpeg`
|
||||||
|
|
||||||
`ffmpeg` is software to record, convert and stream audio and video.
|
`ffmpeg` is software to record, convert and stream audio and video.
|
||||||
|
|
||||||
It is required for the following Pleroma features:
|
It is required for the following Pleroma features:
|
||||||
* Media preview proxy for videos (related config: `media_preview_proxy/enabled` in `config/config.exs`)
|
* Media preview proxy for videos (related config: `media_preview_proxy/enabled` in `config/config.exs`)
|
||||||
|
|
||||||
## `exiftool`
|
## `exiftool`
|
||||||
|
|
||||||
`exiftool` is media files metadata reader/writer.
|
`exiftool` is media files metadata reader/writer.
|
||||||
|
|
||||||
It is required for the following Pleroma features:
|
It is required for the following Pleroma features:
|
||||||
* `Pleroma.Upload.Filters.Exiftool` upload filter (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
* `Pleroma.Upload.Filters.Exiftool.StripLocation` upload filter (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
||||||
|
* `Pleroma.Upload.Filters.Exiftool.ReadDescription` upload filter (related config: `Plaroma.Upload/filters` in `config/config.exs`)
|
||||||
|
|
|
@ -34,7 +34,8 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
static_dir: :string,
|
static_dir: :string,
|
||||||
listen_ip: :string,
|
listen_ip: :string,
|
||||||
listen_port: :string,
|
listen_port: :string,
|
||||||
strip_uploads: :string,
|
strip_uploads_location: :string,
|
||||||
|
read_uploads_description: :string,
|
||||||
anonymize_uploads: :string,
|
anonymize_uploads: :string,
|
||||||
dedupe_uploads: :string
|
dedupe_uploads: :string
|
||||||
],
|
],
|
||||||
|
@ -161,7 +162,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
)
|
)
|
||||||
|> Path.expand()
|
|> Path.expand()
|
||||||
|
|
||||||
{strip_uploads_message, strip_uploads_default} =
|
{strip_uploads_location_message, strip_uploads_location_default} =
|
||||||
if Pleroma.Utils.command_available?("exiftool") do
|
if Pleroma.Utils.command_available?("exiftool") do
|
||||||
{"Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n)",
|
{"Do you want to strip location (GPS) data from uploaded images? This requires exiftool, it was detected as installed. (y/n)",
|
||||||
"y"}
|
"y"}
|
||||||
|
@ -170,12 +171,29 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
"n"}
|
"n"}
|
||||||
end
|
end
|
||||||
|
|
||||||
strip_uploads =
|
strip_uploads_location =
|
||||||
get_option(
|
get_option(
|
||||||
options,
|
options,
|
||||||
:strip_uploads,
|
:strip_uploads_location,
|
||||||
strip_uploads_message,
|
strip_uploads_location_message,
|
||||||
strip_uploads_default
|
strip_uploads_location_default
|
||||||
|
) === "y"
|
||||||
|
|
||||||
|
{read_uploads_description_message, read_uploads_description_default} =
|
||||||
|
if Pleroma.Utils.command_available?("exiftool") do
|
||||||
|
{"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as installed. (y/n)",
|
||||||
|
"y"}
|
||||||
|
else
|
||||||
|
{"Do you want to read data from uploaded files so clients can use it to prefill fields like image description? This requires exiftool, it was detected as not installed, please install it if you answer yes. (y/n)",
|
||||||
|
"n"}
|
||||||
|
end
|
||||||
|
|
||||||
|
read_uploads_description =
|
||||||
|
get_option(
|
||||||
|
options,
|
||||||
|
:read_uploads_description,
|
||||||
|
read_uploads_description_message,
|
||||||
|
read_uploads_description_default
|
||||||
) === "y"
|
) === "y"
|
||||||
|
|
||||||
anonymize_uploads =
|
anonymize_uploads =
|
||||||
|
@ -229,7 +247,8 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
listen_port: listen_port,
|
listen_port: listen_port,
|
||||||
upload_filters:
|
upload_filters:
|
||||||
upload_filters(%{
|
upload_filters(%{
|
||||||
strip: strip_uploads,
|
strip_location: strip_uploads_location,
|
||||||
|
read_description: read_uploads_description,
|
||||||
anonymize: anonymize_uploads,
|
anonymize: anonymize_uploads,
|
||||||
dedupe: dedupe_uploads
|
dedupe: dedupe_uploads
|
||||||
})
|
})
|
||||||
|
@ -297,12 +316,19 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
|
|
||||||
defp upload_filters(filters) when is_map(filters) do
|
defp upload_filters(filters) when is_map(filters) do
|
||||||
enabled_filters =
|
enabled_filters =
|
||||||
if filters.strip do
|
if filters.strip_location do
|
||||||
[Pleroma.Upload.Filter.Exiftool]
|
[Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
enabled_filters =
|
||||||
|
if filters.read_description do
|
||||||
|
enabled_filters ++ [Pleroma.Upload.Filter.Exiftool.ReadDescription]
|
||||||
|
else
|
||||||
|
enabled_filters
|
||||||
|
end
|
||||||
|
|
||||||
enabled_filters =
|
enabled_filters =
|
||||||
if filters.anonymize do
|
if filters.anonymize do
|
||||||
enabled_filters ++ [Pleroma.Upload.Filter.AnonymizeFilename]
|
enabled_filters ++ [Pleroma.Upload.Filter.AnonymizeFilename]
|
||||||
|
|
|
@ -164,7 +164,8 @@ defmodule Pleroma.ApplicationRequirements do
|
||||||
|
|
||||||
defp check_system_commands!(:ok) do
|
defp check_system_commands!(:ok) do
|
||||||
filter_commands_statuses = [
|
filter_commands_statuses = [
|
||||||
check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"),
|
check_filter(Pleroma.Upload.Filter.Exiftool.StripLocation, "exiftool"),
|
||||||
|
check_filter(Pleroma.Upload.Filter.Exiftool.ReadDescription, "exiftool"),
|
||||||
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
|
||||||
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
|
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
|
||||||
|
|
|
@ -20,6 +20,43 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
||||||
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
"\n* `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def check_exiftool_filter do
|
||||||
|
filters = Config.get([Pleroma.Upload]) |> Keyword.get(:filters, [])
|
||||||
|
|
||||||
|
if Pleroma.Upload.Filter.Exiftool in filters do
|
||||||
|
Logger.warn("""
|
||||||
|
!!!DEPRECATION WARNING!!!
|
||||||
|
Your config is using Exiftool as a filter instead of Exiftool.StripLocation. This should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [Pleroma.Upload.Filter.Exiftool]
|
||||||
|
```
|
||||||
|
|
||||||
|
Is now
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||||
|
```
|
||||||
|
""")
|
||||||
|
|
||||||
|
new_config =
|
||||||
|
filters
|
||||||
|
|> Enum.map(fn
|
||||||
|
Pleroma.Upload.Filter.Exiftool -> Pleroma.Upload.Filter.Exiftool.StripLocation
|
||||||
|
filter -> filter
|
||||||
|
end)
|
||||||
|
|
||||||
|
Config.put([Pleroma.Upload, :filters], new_config)
|
||||||
|
|
||||||
|
:error
|
||||||
|
else
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def check_simple_policy_tuples do
|
def check_simple_policy_tuples do
|
||||||
has_strings =
|
has_strings =
|
||||||
Config.get([:mrf_simple])
|
Config.get([:mrf_simple])
|
||||||
|
@ -180,7 +217,8 @@ defmodule Pleroma.Config.DeprecationWarnings do
|
||||||
check_old_chat_shoutbox(),
|
check_old_chat_shoutbox(),
|
||||||
check_quarantined_instances_tuples(),
|
check_quarantined_instances_tuples(),
|
||||||
check_transparency_exclusions_tuples(),
|
check_transparency_exclusions_tuples(),
|
||||||
check_simple_policy_tuples()
|
check_simple_policy_tuples(),
|
||||||
|
check_exiftool_filter()
|
||||||
]
|
]
|
||||||
|> Enum.reduce(:ok, fn
|
|> Enum.reduce(:ok, fn
|
||||||
:ok, :ok -> :ok
|
:ok, :ok -> :ok
|
||||||
|
|
|
@ -60,12 +60,23 @@ defmodule Pleroma.Upload do
|
||||||
width: integer(),
|
width: integer(),
|
||||||
height: integer(),
|
height: integer(),
|
||||||
blurhash: String.t(),
|
blurhash: String.t(),
|
||||||
|
description: String.t(),
|
||||||
path: String.t()
|
path: String.t()
|
||||||
}
|
}
|
||||||
defstruct [:id, :name, :tempfile, :content_type, :width, :height, :blurhash, :path]
|
defstruct [
|
||||||
|
:id,
|
||||||
|
:name,
|
||||||
|
:tempfile,
|
||||||
|
:content_type,
|
||||||
|
:width,
|
||||||
|
:height,
|
||||||
|
:blurhash,
|
||||||
|
:description,
|
||||||
|
:path
|
||||||
|
]
|
||||||
|
|
||||||
defp get_description(opts, upload) do
|
defp get_description(upload) do
|
||||||
case {opts[:description], Pleroma.Config.get([Pleroma.Upload, :default_description])} do
|
case {upload.description, Pleroma.Config.get([Pleroma.Upload, :default_description])} do
|
||||||
{description, _} when is_binary(description) -> description
|
{description, _} when is_binary(description) -> description
|
||||||
{_, :filename} -> upload.name
|
{_, :filename} -> upload.name
|
||||||
{_, str} when is_binary(str) -> str
|
{_, str} when is_binary(str) -> str
|
||||||
|
@ -81,7 +92,7 @@ defmodule Pleroma.Upload do
|
||||||
with {:ok, upload} <- prepare_upload(upload, opts),
|
with {:ok, upload} <- prepare_upload(upload, opts),
|
||||||
upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"},
|
upload = %__MODULE__{upload | path: upload.path || "#{upload.id}/#{upload.name}"},
|
||||||
{:ok, upload} <- Pleroma.Upload.Filter.filter(opts.filters, upload),
|
{:ok, upload} <- Pleroma.Upload.Filter.filter(opts.filters, upload),
|
||||||
description = get_description(opts, upload),
|
description = get_description(upload),
|
||||||
{_, true} <-
|
{_, true} <-
|
||||||
{:description_limit,
|
{:description_limit,
|
||||||
String.length(description) <= Pleroma.Config.get([:instance, :description_limit])},
|
String.length(description) <= Pleroma.Config.get([:instance, :description_limit])},
|
||||||
|
@ -152,7 +163,8 @@ defmodule Pleroma.Upload do
|
||||||
id: UUID.generate(),
|
id: UUID.generate(),
|
||||||
name: file.filename,
|
name: file.filename,
|
||||||
tempfile: file.path,
|
tempfile: file.path,
|
||||||
content_type: file.content_type
|
content_type: file.content_type,
|
||||||
|
description: opts.description
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -172,7 +184,8 @@ defmodule Pleroma.Upload do
|
||||||
id: UUID.generate(),
|
id: UUID.generate(),
|
||||||
name: hash <> "." <> ext,
|
name: hash <> "." <> ext,
|
||||||
tempfile: tmp_path,
|
tempfile: tmp_path,
|
||||||
content_type: content_type
|
content_type: content_type,
|
||||||
|
description: opts.description
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
49
lib/pleroma/upload/filter/exiftool/read_description.ex
Normal file
49
lib/pleroma/upload/filter/exiftool/read_description.ex
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do
|
||||||
|
@moduledoc """
|
||||||
|
Gets a valid description from the related EXIF tags and provides them in the response if no description is provided yet.
|
||||||
|
It will first check ImageDescription, when that doesn't probide a valid description, it will check iptc:Caption-Abstract.
|
||||||
|
A valid description means the fields are filled in and not too long (see `:instance, :description_limit`).
|
||||||
|
"""
|
||||||
|
@behaviour Pleroma.Upload.Filter
|
||||||
|
|
||||||
|
@spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()}
|
||||||
|
|
||||||
|
def filter(%Pleroma.Upload{description: description})
|
||||||
|
when is_binary(description),
|
||||||
|
do: {:ok, :noop}
|
||||||
|
|
||||||
|
def filter(%Pleroma.Upload{tempfile: file} = upload),
|
||||||
|
do: {:ok, :filtered, upload |> Map.put(:description, read_description_from_exif_data(file))}
|
||||||
|
|
||||||
|
def filter(_, _), do: {:ok, :noop}
|
||||||
|
|
||||||
|
defp read_description_from_exif_data(file) do
|
||||||
|
nil
|
||||||
|
|> read_when_empty(file, "-ImageDescription")
|
||||||
|
|> read_when_empty(file, "-iptc:Caption-Abstract")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp read_when_empty(current_description, _, _) when is_binary(current_description),
|
||||||
|
do: current_description
|
||||||
|
|
||||||
|
defp read_when_empty(_, file, tag) do
|
||||||
|
try do
|
||||||
|
{tag_content, 0} =
|
||||||
|
System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true)
|
||||||
|
|
||||||
|
tag_content = String.trim(tag_content)
|
||||||
|
|
||||||
|
if tag_content != "" and
|
||||||
|
String.length(tag_content) <=
|
||||||
|
Pleroma.Config.get([:instance, :description_limit]),
|
||||||
|
do: tag_content,
|
||||||
|
else: nil
|
||||||
|
rescue
|
||||||
|
_ in ErlangError -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Upload.Filter.Exiftool do
|
defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Strips GPS related EXIF tags and overwrites the file in place.
|
Strips GPS related EXIF tags and overwrites the file in place.
|
||||||
Also strips or replaces filesystem metadata e.g., timestamps.
|
Also strips or replaces filesystem metadata e.g., timestamps.
|
|
@ -0,0 +1,37 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.UploadFilterExiftoolToExiftoolStripLocation do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
alias Pleroma.ConfigDB
|
||||||
|
|
||||||
|
def up,
|
||||||
|
do:
|
||||||
|
ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Upload})
|
||||||
|
|> update_filtername(
|
||||||
|
Pleroma.Upload.Filter.Exiftool,
|
||||||
|
Pleroma.Upload.Filter.Exiftool.StripLocation
|
||||||
|
)
|
||||||
|
|
||||||
|
def down,
|
||||||
|
do:
|
||||||
|
ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Upload})
|
||||||
|
|> update_filtername(
|
||||||
|
Pleroma.Upload.Filter.Exiftool.StripLocation,
|
||||||
|
Pleroma.Upload.Filter.Exiftool
|
||||||
|
)
|
||||||
|
|
||||||
|
defp update_filtername(%{value: value}, from_filtername, to_filtername) do
|
||||||
|
new_value =
|
||||||
|
value
|
||||||
|
|> Keyword.update(:filters, [], fn filters ->
|
||||||
|
filters
|
||||||
|
|> Enum.map(fn
|
||||||
|
^from_filtername -> to_filtername
|
||||||
|
filter -> filter
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
ConfigDB.update_or_create(%{group: :pleroma, key: Pleroma.Upload, value: new_value})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_filtername(_, _, _), do: nil
|
||||||
|
end
|
BIN
test/fixtures/image_with_caption-abstract.jpg
vendored
Normal file
BIN
test/fixtures/image_with_caption-abstract.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 697 B |
BIN
test/fixtures/image_with_imagedescription_and_caption-abstract.jpg
vendored
Normal file
BIN
test/fixtures/image_with_imagedescription_and_caption-abstract.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 823 B |
BIN
test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg
vendored
Normal file
BIN
test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 785 B |
BIN
test/fixtures/image_with_no_description.jpg
vendored
Normal file
BIN
test/fixtures/image_with_no_description.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 631 B |
|
@ -67,7 +67,9 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do
|
||||||
"test/uploads",
|
"test/uploads",
|
||||||
"--static-dir",
|
"--static-dir",
|
||||||
"./test/../test/instance/static/",
|
"./test/../test/instance/static/",
|
||||||
"--strip-uploads",
|
"--strip-uploads-location",
|
||||||
|
"y",
|
||||||
|
"--read-uploads-description",
|
||||||
"y",
|
"y",
|
||||||
"--dedupe-uploads",
|
"--dedupe-uploads",
|
||||||
"n",
|
"n",
|
||||||
|
@ -91,7 +93,10 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do
|
||||||
assert generated_config =~ "password: \"dbpass\""
|
assert generated_config =~ "password: \"dbpass\""
|
||||||
assert generated_config =~ "configurable_from_database: true"
|
assert generated_config =~ "configurable_from_database: true"
|
||||||
assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]"
|
assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]"
|
||||||
assert generated_config =~ "filters: [Pleroma.Upload.Filter.Exiftool]"
|
|
||||||
|
assert generated_config =~
|
||||||
|
"filters: [Pleroma.Upload.Filter.Exiftool.StripLocation, Pleroma.Upload.Filter.Exiftool.ReadDescription]"
|
||||||
|
|
||||||
assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
|
assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
|
||||||
assert File.exists?(Path.expand("./test/instance/static/robots.txt"))
|
assert File.exists?(Path.expand("./test/instance/static/robots.txt"))
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,6 +11,62 @@ defmodule Pleroma.Config.DeprecationWarningsTest do
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Config.DeprecationWarnings
|
alias Pleroma.Config.DeprecationWarnings
|
||||||
|
|
||||||
|
describe "filter exiftool" do
|
||||||
|
test "gives warning when still used" do
|
||||||
|
clear_config(
|
||||||
|
[Pleroma.Upload, :filters],
|
||||||
|
[Pleroma.Upload.Filter.Exiftool]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert capture_log(fn -> DeprecationWarnings.check_exiftool_filter() end) =~
|
||||||
|
"""
|
||||||
|
!!!DEPRECATION WARNING!!!
|
||||||
|
Your config is using Exiftool as a filter instead of Exiftool.StripLocation. This should work for now, but you are advised to change to the new configuration to prevent possible issues later:
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [Pleroma.Upload.Filter.Exiftool]
|
||||||
|
```
|
||||||
|
|
||||||
|
Is now
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
config :pleroma, Pleroma.Upload,
|
||||||
|
filters: [Pleroma.Upload.Filter.Exiftool.StripLocation]
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
test "changes setting to exiftool strip location" do
|
||||||
|
clear_config(
|
||||||
|
[Pleroma.Upload, :filters],
|
||||||
|
[Pleroma.Upload.Filter.Exiftool, Pleroma.Upload.Filter.Exiftool.ReadDescription]
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_config = [
|
||||||
|
Pleroma.Upload.Filter.Exiftool.StripLocation,
|
||||||
|
Pleroma.Upload.Filter.Exiftool.ReadDescription
|
||||||
|
]
|
||||||
|
|
||||||
|
capture_log(fn -> DeprecationWarnings.warn() end)
|
||||||
|
|
||||||
|
assert Config.get([Pleroma.Upload]) |> Keyword.get(:filters, []) == expected_config
|
||||||
|
end
|
||||||
|
|
||||||
|
test "doesn't give a warning with correct config" do
|
||||||
|
clear_config(
|
||||||
|
[Pleroma.Upload, :filters],
|
||||||
|
[
|
||||||
|
Pleroma.Upload.Filter.Exiftool.StripLocation,
|
||||||
|
Pleroma.Upload.Filter.Exiftool.ReadDescription
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
assert capture_log(fn -> DeprecationWarnings.check_exiftool_filter() end) == ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "simple policy tuples" do
|
describe "simple policy tuples" do
|
||||||
test "gives warning when there are still strings" do
|
test "gives warning when there are still strings" do
|
||||||
clear_config([:mrf_simple],
|
clear_config([:mrf_simple],
|
||||||
|
|
117
test/pleroma/upload/filter/exiftool/read_description_test.exs
Normal file
117
test/pleroma/upload/filter/exiftool/read_description_test.exs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Upload.Filter.Exiftool.ReadDescriptionTest do
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
alias Pleroma.Upload.Filter
|
||||||
|
|
||||||
|
@uploads %Pleroma.Upload{
|
||||||
|
name: "image_with_imagedescription_and_caption-abstract.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"),
|
||||||
|
tempfile: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"),
|
||||||
|
description: nil
|
||||||
|
}
|
||||||
|
|
||||||
|
test "keeps description when not empty" do
|
||||||
|
uploads = %Pleroma.Upload{
|
||||||
|
name: "image_with_imagedescription_and_caption-abstract.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"),
|
||||||
|
tempfile:
|
||||||
|
Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"),
|
||||||
|
description: "Some description"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(uploads) ==
|
||||||
|
{:ok, :noop}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "otherwise returns ImageDescription when present" do
|
||||||
|
uploads_after = %Pleroma.Upload{
|
||||||
|
name: "image_with_imagedescription_and_caption-abstract.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"),
|
||||||
|
tempfile:
|
||||||
|
Path.absname("test/fixtures/image_with_imagedescription_and_caption-abstract.jpg"),
|
||||||
|
description: "a descriptive white pixel"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(@uploads) ==
|
||||||
|
{:ok, :filtered, uploads_after}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "otherwise returns iptc:Caption-Abstract when present" do
|
||||||
|
upload = %Pleroma.Upload{
|
||||||
|
name: "image_with_caption-abstract.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image_with_caption-abstract.jpg"),
|
||||||
|
tempfile: Path.absname("test/fixtures/image_with_caption-abstract.jpg"),
|
||||||
|
description: nil
|
||||||
|
}
|
||||||
|
|
||||||
|
upload_after = %Pleroma.Upload{
|
||||||
|
name: "image_with_caption-abstract.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image_with_caption-abstract.jpg"),
|
||||||
|
tempfile: Path.absname("test/fixtures/image_with_caption-abstract.jpg"),
|
||||||
|
description: "an abstract white pixel"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(upload) ==
|
||||||
|
{:ok, :filtered, upload_after}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "otherwise returns nil" do
|
||||||
|
uploads = %Pleroma.Upload{
|
||||||
|
name: "image_with_no_description.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/image_with_no_description.jpg"),
|
||||||
|
tempfile: Path.absname("test/fixtures/image_with_no_description.jpg"),
|
||||||
|
description: nil
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(uploads) ==
|
||||||
|
{:ok, :filtered, uploads}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Return nil when image description from EXIF data exceeds the maximum length" do
|
||||||
|
clear_config([:instance, :description_limit], 5)
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(@uploads) ==
|
||||||
|
{:ok, :filtered, @uploads}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Ignores content with only whitespace" do
|
||||||
|
uploads = %Pleroma.Upload{
|
||||||
|
name: "non-existant.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path:
|
||||||
|
Path.absname(
|
||||||
|
"test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg"
|
||||||
|
),
|
||||||
|
tempfile:
|
||||||
|
Path.absname(
|
||||||
|
"test/fixtures/image_with_imagedescription_and_caption-abstract_whitespaces.jpg"
|
||||||
|
),
|
||||||
|
description: nil
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(uploads) ==
|
||||||
|
{:ok, :filtered, uploads}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Return nil when image description from EXIF data can't be read" do
|
||||||
|
uploads = %Pleroma.Upload{
|
||||||
|
name: "non-existant.jpg",
|
||||||
|
content_type: "image/jpeg",
|
||||||
|
path: Path.absname("test/fixtures/non-existant.jpg"),
|
||||||
|
tempfile: Path.absname("test/fixtures/non-existant_tmp.jpg"),
|
||||||
|
description: nil
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Filter.Exiftool.ReadDescription.filter(uploads) ==
|
||||||
|
{:ok, :filtered, uploads}
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Upload.Filter.ExiftoolTest do
|
defmodule Pleroma.Upload.Filter.Exiftool.StripLocationTest do
|
||||||
use Pleroma.DataCase, async: true
|
use Pleroma.DataCase, async: true
|
||||||
alias Pleroma.Upload.Filter
|
alias Pleroma.Upload.Filter
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do
|
||||||
tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg")
|
tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg")
|
||||||
}
|
}
|
||||||
|
|
||||||
assert Filter.Exiftool.filter(upload) == {:ok, :filtered}
|
assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :filtered}
|
||||||
|
|
||||||
{exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.jpg"])
|
{exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.jpg"])
|
||||||
{exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.jpg"])
|
{exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.jpg"])
|
||||||
|
@ -37,6 +37,6 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do
|
||||||
content_type: "image/webp"
|
content_type: "image/webp"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert Filter.Exiftool.filter(upload) == {:ok, :noop}
|
assert Filter.Exiftool.StripLocation.filter(upload) == {:ok, :noop}
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
Reference in a new issue