Merge branch 'bug/fix-searched-content-publically-accessible' into 'master'
Fix URL searched content publically accessible See merge request framasoft/mobilizon!391
This commit is contained in:
commit
cf5f010bc0
@ -19,6 +19,10 @@ Also make sure to remove the `EnvironmentFile=` line from the systemd service an
|
|||||||
- Possibility to participate anonymously to an event
|
- Possibility to participate anonymously to an event
|
||||||
- Possibility to participate to a remote event (being redirected by providing federated identity)
|
- Possibility to participate to a remote event (being redirected by providing federated identity)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed URL search
|
||||||
|
- Fixed content accessed through URL search being public
|
||||||
|
|
||||||
## [1.0.0-beta.2] - 2019-12-18
|
## [1.0.0-beta.2] - 2019-12-18
|
||||||
|
|
||||||
### Special operations
|
### Special operations
|
||||||
|
@ -73,7 +73,7 @@ yarn install
|
|||||||
|
|
||||||
Finally, we can build the front-end (this can take a few seconds)
|
Finally, we can build the front-end (this can take a few seconds)
|
||||||
```bash
|
```bash
|
||||||
yarn run build
|
NODE_ENV=production yarn run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's go back to the main directory
|
Let's go back to the main directory
|
||||||
|
@ -37,10 +37,10 @@
|
|||||||
<h3 class="title">
|
<h3 class="title">
|
||||||
{{ $t("Upcoming") }}
|
{{ $t("Upcoming") }}
|
||||||
</h3>
|
</h3>
|
||||||
<b-loading :active.sync="$apollo.loading"></b-loading>
|
<b-loading :active.sync="$apollo.loading" />
|
||||||
<div v-for="row of goingToEvents" class="upcoming-events" :key="row[0]">
|
<div v-for="row of goingToEvents" class="upcoming-events" :key="row[0]">
|
||||||
<span class="date-component-container" v-if="isInLessThanSevenDays(row[0])">
|
<span class="date-component-container" v-if="isInLessThanSevenDays(row[0])">
|
||||||
<date-component :date="row[0]"></date-component>
|
<date-component :date="row[0]" />
|
||||||
<h3 class="subtitle"
|
<h3 class="subtitle"
|
||||||
v-if="isToday(row[0])">
|
v-if="isToday(row[0])">
|
||||||
{{ $tc('You have one event today.', row[1].length, {count: row[1].length}) }}
|
{{ $tc('You have one event today.', row[1].length, {count: row[1].length}) }}
|
||||||
@ -71,7 +71,7 @@
|
|||||||
<h3 class="title">
|
<h3 class="title">
|
||||||
{{ $t("Last week") }}
|
{{ $t("Last week") }}
|
||||||
</h3>
|
</h3>
|
||||||
<b-loading :active.sync="$apollo.loading"></b-loading>
|
<b-loading :active.sync="$apollo.loading" />
|
||||||
<div>
|
<div>
|
||||||
<EventListCard
|
<EventListCard
|
||||||
v-for="participation in lastWeekEvents"
|
v-for="participation in lastWeekEvents"
|
||||||
@ -83,7 +83,7 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="events-featured">
|
<section class="events-featured">
|
||||||
<h3 class="title">{{ $t('Featured events') }}</h3>
|
<h3 class="title">{{ $t('Featured events') }}</h3>
|
||||||
<b-loading :active.sync="$apollo.loading"></b-loading>
|
<b-loading :active.sync="$apollo.loading" />
|
||||||
<div v-if="filteredFeaturedEvents.length > 0" class="columns is-multiline">
|
<div v-if="filteredFeaturedEvents.length > 0" class="columns is-multiline">
|
||||||
<div class="column is-one-third-desktop" v-for="event in filteredFeaturedEvents.slice(0, 6)" :key="event.uuid">
|
<div class="column is-one-third-desktop" v-for="event in filteredFeaturedEvents.slice(0, 6)" :key="event.uuid">
|
||||||
<EventCard
|
<EventCard
|
||||||
@ -261,9 +261,11 @@ export default class Home extends Vue {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all events from server excluding the ones shown as participating
|
||||||
|
*/
|
||||||
get filteredFeaturedEvents() {
|
get filteredFeaturedEvents() {
|
||||||
if (!this.currentUser.isLoggedIn || !this.currentActor.id) return this.events;
|
return this.events.filter(({ id }) => !this.currentUserParticipations.map(({ event: { id } }) => id).includes(id));
|
||||||
return this.events.filter(event => event.organizerActor && event.organizerActor.id !== this.currentActor.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geoLocalize() {
|
geoLocalize() {
|
||||||
|
@ -87,7 +87,7 @@ const tabsName = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
skip() {
|
skip() {
|
||||||
return !this.searchTerm;
|
return !this.searchTerm || this.isURL(this.searchTerm);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -104,6 +104,13 @@ export default class Search extends Vue {
|
|||||||
searchGroups: SearchGroup = { total: 0, elements: [] };
|
searchGroups: SearchGroup = { total: 0, elements: [] };
|
||||||
activeTab: SearchTabs = tabsName[this.searchType];
|
activeTab: SearchTabs = tabsName[this.searchType];
|
||||||
|
|
||||||
|
@Watch('searchEvents')
|
||||||
|
async redirectURLToEvent() {
|
||||||
|
if (this.searchEvents.total === 1 && this.isURL(this.searchTerm)) {
|
||||||
|
return await this.$router.replace({ name: RouteName.EVENT, params: { uuid: this.searchEvents.elements[0].uuid } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
changeTab(index: number) {
|
changeTab(index: number) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case SearchTabs.EVENTS:
|
case SearchTabs.EVENTS:
|
||||||
@ -136,6 +143,12 @@ export default class Search extends Vue {
|
|||||||
return this.searchGroups.elements.map(group => Object.assign(new Group(), group));
|
return this.searchGroups.elements.map(group => Object.assign(new Group(), group));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isURL(url: string): boolean {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
return (a.host && a.host !== window.location.host) as boolean;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -881,7 +881,6 @@ defmodule Mobilizon.Federation.ActivityPub do
|
|||||||
|> Map.merge(%{
|
|> Map.merge(%{
|
||||||
"id" => "#{Endpoint.url()}/reject/follow/#{follower.id}"
|
"id" => "#{Endpoint.url()}/reject/follow/#{follower.id}"
|
||||||
}) do
|
}) do
|
||||||
Logger.error(inspect(update_data))
|
|
||||||
{:ok, follower, update_data}
|
{:ok, follower, update_data}
|
||||||
else
|
else
|
||||||
err ->
|
err ->
|
||||||
|
@ -46,11 +46,16 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||||||
{:mentions, mentions} <- {:mentions, ConverterUtils.fetch_mentions(object["tag"])},
|
{:mentions, mentions} <- {:mentions, ConverterUtils.fetch_mentions(object["tag"])},
|
||||||
{:visibility, visibility} <- {:visibility, get_visibility(object)},
|
{:visibility, visibility} <- {:visibility, get_visibility(object)},
|
||||||
{:options, options} <- {:options, get_options(object)} do
|
{:options, options} <- {:options, get_options(object)} do
|
||||||
|
attachments =
|
||||||
|
object
|
||||||
|
|> Map.get("attachment", [])
|
||||||
|
|> Enum.filter(fn attachment -> Map.get(attachment, "type", "Document") == "Document" end)
|
||||||
|
|
||||||
picture_id =
|
picture_id =
|
||||||
with true <- Map.has_key?(object, "attachment") && length(object["attachment"]) > 0,
|
with true <- length(attachments) > 0,
|
||||||
{:ok, %Picture{id: picture_id}} <-
|
{:ok, %Picture{id: picture_id}} <-
|
||||||
object["attachment"]
|
attachments
|
||||||
|> hd
|
|> hd()
|
||||||
|> PictureConverter.find_or_create_picture(actor_id) do
|
|> PictureConverter.find_or_create_picture(actor_id) do
|
||||||
picture_id
|
picture_id
|
||||||
else
|
else
|
||||||
@ -71,7 +76,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||||||
local: is_nil(actor_domain),
|
local: is_nil(actor_domain),
|
||||||
options: options,
|
options: options,
|
||||||
status: object |> Map.get("ical:status", "CONFIRMED") |> String.downcase(),
|
status: object |> Map.get("ical:status", "CONFIRMED") |> String.downcase(),
|
||||||
online_address: object["onlineAddress"],
|
online_address: object |> Map.get("attachment", []) |> get_online_address(),
|
||||||
phone_address: object["phoneAddress"],
|
phone_address: object["phoneAddress"],
|
||||||
draft: false,
|
draft: false,
|
||||||
url: object["id"],
|
url: object["id"],
|
||||||
@ -122,6 +127,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||||||
"repliesModerationOption" => event.options.comment_moderation,
|
"repliesModerationOption" => event.options.comment_moderation,
|
||||||
"commentsEnabled" => event.options.comment_moderation == :allow_all,
|
"commentsEnabled" => event.options.comment_moderation == :allow_all,
|
||||||
"anonymousParticipationEnabled" => event.options.anonymous_participation,
|
"anonymousParticipationEnabled" => event.options.anonymous_participation,
|
||||||
|
"attachment" => [],
|
||||||
# "draft" => event.draft,
|
# "draft" => event.draft,
|
||||||
"ical:status" => event.status |> to_string |> String.upcase(),
|
"ical:status" => event.status |> to_string |> String.upcase(),
|
||||||
"id" => event.url,
|
"id" => event.url,
|
||||||
@ -133,9 +139,34 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||||||
do: res,
|
do: res,
|
||||||
else: Map.put(res, "location", AddressConverter.model_to_as(event.physical_address))
|
else: Map.put(res, "location", AddressConverter.model_to_as(event.physical_address))
|
||||||
|
|
||||||
if is_nil(event.picture),
|
res =
|
||||||
|
if is_nil(event.picture),
|
||||||
|
do: res,
|
||||||
|
else:
|
||||||
|
Map.update(
|
||||||
|
res,
|
||||||
|
"attachment",
|
||||||
|
[],
|
||||||
|
&(&1 ++ [PictureConverter.model_to_as(event.picture)])
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_nil(event.online_address),
|
||||||
do: res,
|
do: res,
|
||||||
else: Map.put(res, "attachment", [PictureConverter.model_to_as(event.picture)])
|
else:
|
||||||
|
Map.update(
|
||||||
|
res,
|
||||||
|
"attachment",
|
||||||
|
[],
|
||||||
|
&(&1 ++
|
||||||
|
[
|
||||||
|
%{
|
||||||
|
"type" => "Link",
|
||||||
|
"href" => event.online_address,
|
||||||
|
"mediaType" => "text/html",
|
||||||
|
"name" => "Website"
|
||||||
|
}
|
||||||
|
])
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get only elements that we have in EventOptions
|
# Get only elements that we have in EventOptions
|
||||||
@ -198,4 +229,21 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||||||
@spec date_to_string(DateTime.t() | nil) :: String.t()
|
@spec date_to_string(DateTime.t() | nil) :: String.t()
|
||||||
defp date_to_string(nil), do: nil
|
defp date_to_string(nil), do: nil
|
||||||
defp date_to_string(%DateTime{} = date), do: DateTime.to_iso8601(date)
|
defp date_to_string(%DateTime{} = date), do: DateTime.to_iso8601(date)
|
||||||
|
|
||||||
|
defp get_online_address(attachments) do
|
||||||
|
Enum.find_value(attachments, [], fn attachment ->
|
||||||
|
case attachment do
|
||||||
|
%{
|
||||||
|
"type" => "Link",
|
||||||
|
"href" => url,
|
||||||
|
"mediaType" => "text/html",
|
||||||
|
"name" => "Website"
|
||||||
|
} ->
|
||||||
|
url
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,6 +5,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
|||||||
|
|
||||||
alias Mobilizon.{Actors, Admin, Events}
|
alias Mobilizon.{Actors, Admin, Events}
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.Events.{Event, EventParticipantStats}
|
alias Mobilizon.Events.{Event, EventParticipantStats}
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
|
|
||||||
@ -44,16 +45,28 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
|||||||
{:error, "Event with UUID #{uuid} not found"}
|
{:error, "Event with UUID #{uuid} not found"}
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_event(parent, %{uuid: uuid} = args, resolution) do
|
def find_event(parent, %{uuid: uuid} = args, %{context: context} = resolution) do
|
||||||
case {:has_event, Events.get_public_event_by_uuid_with_preload(uuid)} do
|
with {:has_event, %Event{} = event} <-
|
||||||
{:has_event, %Event{} = event} ->
|
{:has_event, Events.get_public_event_by_uuid_with_preload(uuid)},
|
||||||
{:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))}
|
{:access_valid, true} <-
|
||||||
|
{:access_valid, Map.has_key?(context, :current_user) || check_event_access(event)} do
|
||||||
|
{:ok, Map.put(event, :organizer_actor, Person.proxify_pictures(event.organizer_actor))}
|
||||||
|
else
|
||||||
{:has_event, _} ->
|
{:has_event, _} ->
|
||||||
find_private_event(parent, args, resolution)
|
find_private_event(parent, args, resolution)
|
||||||
|
|
||||||
|
{:access_valid, _} ->
|
||||||
|
{:error, "Event with UUID #{uuid} not found"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_event_access(%Event{local: true}), do: true
|
||||||
|
|
||||||
|
def check_event_access(%Event{url: url}) do
|
||||||
|
relay_actor_id = Config.relay_actor_id()
|
||||||
|
Events.check_if_event_has_instance_follow(url, relay_actor_id)
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
List participants for event (through an event request)
|
List participants for event (through an event request)
|
||||||
"""
|
"""
|
||||||
|
@ -140,6 +140,7 @@ defmodule Mobilizon.Config do
|
|||||||
]
|
]
|
||||||
|
|
||||||
def anonymous_actor_id, do: get_cached_value(:anonymous_actor_id)
|
def anonymous_actor_id, do: get_cached_value(:anonymous_actor_id)
|
||||||
|
def relay_actor_id, do: get_cached_value(:relay_actor_id)
|
||||||
|
|
||||||
@spec get(module | atom) :: any
|
@spec get(module | atom) :: any
|
||||||
def get(key), do: get(key, nil)
|
def get(key), do: get(key, nil)
|
||||||
@ -202,6 +203,13 @@ defmodule Mobilizon.Config do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec create_cache(atom()) :: integer()
|
||||||
|
defp create_cache(:relay_actor_id) do
|
||||||
|
with {:ok, %Actor{id: actor_id}} <- Actors.get_or_create_internal_actor("relay") do
|
||||||
|
actor_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def clear_config_cache do
|
def clear_config_cache do
|
||||||
Cachex.clear(:config)
|
Cachex.clear(:config)
|
||||||
end
|
end
|
||||||
|
@ -12,7 +12,7 @@ defmodule Mobilizon.Events do
|
|||||||
|
|
||||||
alias Ecto.{Changeset, Multi}
|
alias Ecto.{Changeset, Multi}
|
||||||
|
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.{Actor, Follower}
|
||||||
alias Mobilizon.Addresses.Address
|
alias Mobilizon.Addresses.Address
|
||||||
|
|
||||||
alias Mobilizon.Events.{
|
alias Mobilizon.Events.{
|
||||||
@ -28,6 +28,7 @@ defmodule Mobilizon.Events do
|
|||||||
}
|
}
|
||||||
|
|
||||||
alias Mobilizon.Service.Workers
|
alias Mobilizon.Service.Workers
|
||||||
|
alias Mobilizon.Share
|
||||||
alias Mobilizon.Storage.{Page, Repo}
|
alias Mobilizon.Storage.{Page, Repo}
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
|
|
||||||
@ -228,6 +229,14 @@ defmodule Mobilizon.Events do
|
|||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec check_if_event_has_instance_follow(String.t(), integer()) :: boolean()
|
||||||
|
def check_if_event_has_instance_follow(event_uri, follower_actor_id) do
|
||||||
|
Share
|
||||||
|
|> join(:inner, [s], f in Follower, on: f.target_actor_id == s.actor_id)
|
||||||
|
|> where([s, f], f.actor_id == ^follower_actor_id and s.uri == ^event_uri)
|
||||||
|
|> Repo.exists?()
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Gets an event by its UUID, with all associations loaded.
|
Gets an event by its UUID, with all associations loaded.
|
||||||
"""
|
"""
|
||||||
@ -379,6 +388,7 @@ defmodule Mobilizon.Events do
|
|||||||
|> filter_future_events(is_future)
|
|> filter_future_events(is_future)
|
||||||
|> filter_unlisted(is_unlisted)
|
|> filter_unlisted(is_unlisted)
|
||||||
|> filter_draft()
|
|> filter_draft()
|
||||||
|
|> filter_local_or_from_followed_instances_events()
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -461,6 +471,7 @@ defmodule Mobilizon.Events do
|
|||||||
name
|
name
|
||||||
|> normalize_search_string()
|
|> normalize_search_string()
|
||||||
|> events_for_search_query()
|
|> events_for_search_query()
|
||||||
|
|> filter_local_or_from_followed_instances_events()
|
||||||
|> Page.build_page(page, limit)
|
|> Page.build_page(page, limit)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1757,6 +1768,14 @@ defmodule Mobilizon.Events do
|
|||||||
|
|
||||||
defp filter_future_events(query, false), do: query
|
defp filter_future_events(query, false), do: query
|
||||||
|
|
||||||
|
defp filter_local_or_from_followed_instances_events(query) do
|
||||||
|
from(q in query,
|
||||||
|
left_join: s in Share,
|
||||||
|
on: s.uri == q.url,
|
||||||
|
where: q.local == true or not is_nil(s.uri)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
@spec filter_unlisted(Ecto.Query.t(), boolean) :: Ecto.Query.t()
|
@spec filter_unlisted(Ecto.Query.t(), boolean) :: Ecto.Query.t()
|
||||||
defp filter_unlisted(query, true) do
|
defp filter_unlisted(query, true) do
|
||||||
from(q in query, where: q.visibility in ^@public_visibility)
|
from(q in query, where: q.visibility in ^@public_visibility)
|
||||||
|
@ -14,7 +14,9 @@ defimpl Mobilizon.Service.Metadata, for: Mobilizon.Events.Event do
|
|||||||
Tag.tag(:meta, property: "og:title", content: event.title),
|
Tag.tag(:meta, property: "og:title", content: event.title),
|
||||||
Tag.tag(:meta, property: "og:url", content: event.url),
|
Tag.tag(:meta, property: "og:url", content: event.url),
|
||||||
Tag.tag(:meta, property: "og:description", content: event.description),
|
Tag.tag(:meta, property: "og:description", content: event.description),
|
||||||
Tag.tag(:meta, property: "og:type", content: "website")
|
Tag.tag(:meta, property: "og:type", content: "website"),
|
||||||
|
# Tell Search Engines what's the origin
|
||||||
|
Tag.tag(:link, rel: "canonical", href: event.url)
|
||||||
]
|
]
|
||||||
|
|
||||||
tags =
|
tags =
|
||||||
|
@ -70,6 +70,8 @@ defmodule Mobilizon.Federation.ActivityPub.TransmogrifierTest do
|
|||||||
assert event.physical_address.url ==
|
assert event.physical_address.url ==
|
||||||
"https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd"
|
"https://event1.tcit.fr/address/eeecc11d-0030-43e8-a897-6422876372jd"
|
||||||
|
|
||||||
|
assert event.online_address == "https://google.com"
|
||||||
|
|
||||||
{:ok, %Actor{}} = Actors.get_actor_by_url(object["actor"])
|
{:ok, %Actor{}} = Actors.get_actor_by_url(object["actor"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
15
test/fixtures/mobilizon-post-activity.json
vendored
15
test/fixtures/mobilizon-post-activity.json
vendored
@ -35,7 +35,20 @@
|
|||||||
],
|
],
|
||||||
"id": "https://test.mobilizon.org/events/39026210-0c69-4238-b3cc-986f33f98ed0/activity",
|
"id": "https://test.mobilizon.org/events/39026210-0c69-4238-b3cc-986f33f98ed0/activity",
|
||||||
"object": {
|
"object": {
|
||||||
"attachment": [],
|
"attachment": [
|
||||||
|
{
|
||||||
|
"href": "https://something.org",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"name": "Another link",
|
||||||
|
"type": "Link"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://google.com",
|
||||||
|
"mediaType": "text/html",
|
||||||
|
"name": "Website",
|
||||||
|
"type": "Link"
|
||||||
|
}
|
||||||
|
],
|
||||||
"attributedTo": "https://test.mobilizon.org/@Alicia",
|
"attributedTo": "https://test.mobilizon.org/@Alicia",
|
||||||
"startTime": "2018-02-12T14:08:20Z",
|
"startTime": "2018-02-12T14:08:20Z",
|
||||||
"cc": [
|
"cc": [
|
||||||
|
Loading…
Reference in New Issue
Block a user