fedipub 0.0.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -2
- data/Rakefile +5 -9
- data/app/assets/config/fedipub_manifest.js +1 -0
- data/app/assets/stylesheets/fedipub/application.css +15 -0
- data/app/controllers/concerns/fedipub/server/render_collections.rb +19 -0
- data/app/controllers/fedipub/client/activities_controller.rb +27 -0
- data/app/controllers/fedipub/client/actors_controller.rb +54 -0
- data/app/controllers/fedipub/client/followings_controller.rb +103 -0
- data/app/controllers/fedipub/client_controller.rb +9 -0
- data/app/controllers/fedipub/server/activities_controller.rb +78 -0
- data/app/controllers/fedipub/server/actors_controller.rb +50 -0
- data/app/controllers/fedipub/server/followings_controller.rb +19 -0
- data/app/controllers/fedipub/server/nodeinfo_controller.rb +28 -0
- data/app/controllers/fedipub/server/published_controller.rb +30 -0
- data/app/controllers/fedipub/server/web_finger_controller.rb +45 -0
- data/app/controllers/fedipub/server_controller.rb +37 -0
- data/app/helpers/fedipub/server_helper.rb +18 -0
- data/app/jobs/fedipub/application_job.rb +10 -0
- data/app/jobs/fedipub/fetch_nodeinfo_job.rb +10 -0
- data/app/jobs/fedipub/notify_inbox_job.rb +10 -0
- data/app/mailers/fedipub/application_mailer.rb +6 -0
- data/app/models/concerns/fedipub/actor_entity.rb +166 -0
- data/app/models/concerns/fedipub/announceable.rb +18 -0
- data/app/models/concerns/fedipub/data_entity.rb +279 -0
- data/app/models/concerns/fedipub/handles_delete_requests.rb +36 -0
- data/app/models/concerns/fedipub/has_uuid.rb +61 -0
- data/app/models/concerns/fedipub/likeable.rb +29 -0
- data/app/models/fedipub/activity.rb +62 -0
- data/app/models/fedipub/actor.rb +303 -0
- data/app/models/fedipub/application_record.rb +5 -0
- data/app/models/fedipub/following.rb +72 -0
- data/app/models/fedipub/host.rb +48 -0
- data/app/policies/fedipub/client/activity_policy.rb +9 -0
- data/app/policies/fedipub/client/actor_policy.rb +15 -0
- data/app/policies/fedipub/client/following_policy.rb +35 -0
- data/app/policies/fedipub/fedipub_policy.rb +63 -0
- data/app/policies/fedipub/server/activity_policy.rb +9 -0
- data/app/policies/fedipub/server/actor_policy.rb +23 -0
- data/app/policies/fedipub/server/following_policy.rb +6 -0
- data/app/policies/fedipub/server/publishable_policy.rb +15 -0
- data/app/views/fedipub/client/activities/_activity.html.erb +5 -0
- data/app/views/fedipub/client/activities/_activity.json.jbuilder +1 -0
- data/app/views/fedipub/client/activities/_index.json.jbuilder +1 -0
- data/app/views/fedipub/client/activities/feed.html.erb +11 -0
- data/app/views/fedipub/client/activities/feed.json.jbuilder +1 -0
- data/app/views/fedipub/client/activities/index.html.erb +5 -0
- data/app/views/fedipub/client/activities/index.json.jbuilder +1 -0
- data/app/views/fedipub/client/actors/_actor.json.jbuilder +17 -0
- data/app/views/fedipub/client/actors/_lookup_form.html.erb +5 -0
- data/app/views/fedipub/client/actors/gone.html.erb +1 -0
- data/app/views/fedipub/client/actors/index.html.erb +44 -0
- data/app/views/fedipub/client/actors/index.json.jbuilder +1 -0
- data/app/views/fedipub/client/actors/show.html.erb +112 -0
- data/app/views/fedipub/client/actors/show.json.jbuilder +1 -0
- data/app/views/fedipub/client/common/_client_links.html.erb +26 -0
- data/app/views/fedipub/client/followings/_follow.html.erb +4 -0
- data/app/views/fedipub/client/followings/_follow_actions.html.erb +36 -0
- data/app/views/fedipub/client/followings/_follower.html.erb +7 -0
- data/app/views/fedipub/client/followings/_following.json.jbuilder +1 -0
- data/app/views/fedipub/client/followings/_form.html.erb +22 -0
- data/app/views/fedipub/client/followings/index.html.erb +29 -0
- data/app/views/fedipub/client/followings/index.json.jbuilder +1 -0
- data/app/views/fedipub/client/followings/show.html.erb +21 -0
- data/app/views/fedipub/client/followings/show.json.jbuilder +1 -0
- data/app/views/fedipub/server/activities/_activity.activitypub.jbuilder +25 -0
- data/app/views/fedipub/server/activities/show.activitypub.jbuilder +1 -0
- data/app/views/fedipub/server/actors/_actor.activitypub.jbuilder +27 -0
- data/app/views/fedipub/server/actors/_tombstone.activitypub.jbuilder +6 -0
- data/app/views/fedipub/server/actors/show.activitypub.jbuilder +5 -0
- data/app/views/fedipub/server/followings/_following.activitypub.jbuilder +7 -0
- data/app/views/fedipub/server/followings/show.activitypub.jbuilder +1 -0
- data/app/views/fedipub/server/nodeinfo/index.nodeinfo.jbuilder +6 -0
- data/app/views/fedipub/server/nodeinfo/show.nodeinfo.jbuilder +19 -0
- data/app/views/fedipub/server/published/_publishable.activitypub.jbuilder +11 -0
- data/app/views/fedipub/server/published/_tombstone.activitypub.jbuilder +6 -0
- data/app/views/fedipub/server/published/show.activitypub.jbuilder +5 -0
- data/app/views/fedipub/server/shared/ordered_collection.activitypub.jbuilder +6 -0
- data/app/views/fedipub/server/shared/ordered_collection_page.activitypub.jbuilder +12 -0
- data/app/views/fedipub/server/web_finger/find.jrd.jbuilder +24 -0
- data/app/views/fedipub/server/web_finger/host_meta.xrd.erb +5 -0
- data/app/views/users/show.html.erb +4 -0
- data/config/initializers/mime_types.rb +21 -0
- data/config/initializers/security_vocab.rb +53 -0
- data/config/routes.rb +53 -0
- data/db/migrate/20200712133150_create_federails_actors.rb +22 -0
- data/db/migrate/20200712143127_create_federails_followings.rb +14 -0
- data/db/migrate/20200712174938_create_federails_activities.rb +11 -0
- data/db/migrate/20241002094500_add_uuids.rb +13 -0
- data/db/migrate/20241002094501_add_keypair_to_actors.rb +8 -0
- data/db/migrate/20250122160618_add_extensions_to_federails_actors.rb +5 -0
- data/db/migrate/20250301082500_add_local_to_actors.rb +11 -0
- data/db/migrate/20250329123939_add_actor_type_to_actors.rb +5 -0
- data/db/migrate/20250329123940_add_tombstoned_at_to_actors.rb +5 -0
- data/db/migrate/20250426061729_create_federails_hosts.rb +22 -0
- data/db/migrate/20251121160720_add_to_and_cc_to_federails_activities.rb +6 -0
- data/db/migrate/20260421170640_add_result_and_instrument_to_federails_activities.rb +6 -0
- data/db/migrate/20260723113716_rename_federails_to_fedipub.rb +15 -0
- data/lib/fedipub/configuration.rb +119 -0
- data/lib/fedipub/data_transformer/note.rb +36 -0
- data/lib/fedipub/engine.rb +11 -0
- data/lib/fedipub/maintenance/actors_updater.rb +66 -0
- data/lib/fedipub/maintenance/hosts_updater.rb +19 -0
- data/lib/fedipub/utils/actor.rb +85 -0
- data/lib/fedipub/utils/context.rb +12 -0
- data/lib/fedipub/utils/host.rb +54 -0
- data/lib/fedipub/utils/json_request.rb +41 -0
- data/lib/fedipub/utils/object.rb +131 -0
- data/lib/fedipub/utils/response_codes.rb +11 -0
- data/lib/fedipub/version.rb +1 -3
- data/lib/fedipub.rb +127 -4
- data/lib/fediverse/collection.rb +31 -0
- data/lib/fediverse/inbox.rb +110 -0
- data/lib/fediverse/node_info.rb +38 -0
- data/lib/fediverse/notifier.rb +90 -0
- data/lib/fediverse/request.rb +29 -0
- data/lib/fediverse/signature.rb +49 -0
- data/lib/fediverse/webfinger.rb +140 -0
- data/lib/fediverse.rb +5 -0
- data/lib/generators/fedipub/copy_client_policies/USAGE +8 -0
- data/lib/generators/fedipub/copy_client_policies/copy_client_policies_generator.rb +9 -0
- data/lib/generators/fedipub/copy_client_views/USAGE +8 -0
- data/lib/generators/fedipub/copy_client_views/copy_client_views_generator.rb +9 -0
- data/lib/generators/fedipub/copy_factories/USAGE +8 -0
- data/lib/generators/fedipub/copy_factories/copy_factories_generator.rb +43 -0
- data/lib/generators/fedipub/install/USAGE +9 -0
- data/lib/generators/fedipub/install/install_generator.rb +10 -0
- data/lib/generators/fedipub/install/templates/fedipub.rb +1 -0
- data/lib/generators/fedipub/install/templates/fedipub.yml +27 -0
- data/lib/tasks/factory_bot.rake +15 -0
- data/lib/tasks/fedipub_tasks.rake +13 -0
- metadata +259 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e48fe0306a23dd822ac8e755412635303612686408512d9cd36139050fc961a7
|
|
4
|
+
data.tar.gz: ca741f66e2d65b4501b9ae80465fde3500f81d65f55b56b0eef1d0a96bf2b97c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e96c6dcb707777a477078d15b750e2257dafecdd7c489a21f2c8beea9c965be237da1ed414ac27327e684874d840d11274336106defb1d1fe43df242b6b274e8
|
|
7
|
+
data.tar.gz: da1eca4e3c5d882a0dabec9668d521f1f9a707a6dfcbfe36d4ed6d42ffa761d0c7049ffc67d3d1666cae535d85af6ff80cdb11582ff4e6d068365e0949ed737c
|
data/README.md
CHANGED
|
@@ -1,3 +1,71 @@
|
|
|
1
|
-
|
|
1
|
+
# Fedipub
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fedipub is an engine that brings ActivityPub to Ruby on Rails application.
|
|
4
|
+
|
|
5
|
+
> [!note]
|
|
6
|
+
> This project was know as _Federails_ (and the `federails` gem and extensions) and has been
|
|
7
|
+
> renamed recently to Fedipub.
|
|
8
|
+
|
|
9
|
+
## Community
|
|
10
|
+
|
|
11
|
+
You can join the [matrix chat room](https://matrix.to/#/#fedipub:matrix.org) to chat with humans.
|
|
12
|
+
|
|
13
|
+
Open issues or feature requests on the [issue tracker](https://gitlab.com/fedipub/fedipub/-/issues)
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
This engine is meant to be used in Rails applications to add the ability to act as an ActivityPub server.
|
|
18
|
+
|
|
19
|
+
As the project is in an early stage of development we're unable to provide a clean list of what works and what is missing.
|
|
20
|
+
|
|
21
|
+
The general direction is to be able to:
|
|
22
|
+
|
|
23
|
+
- publish and subscribe to any type of content
|
|
24
|
+
- have a discovery endpoint (`webfinger`)
|
|
25
|
+
- have a following/followers system
|
|
26
|
+
- implement all the parts of the (RFC) labelled with **MUST** and **MUST NOT**
|
|
27
|
+
- implement some or all the parts of the RFC labelled with **SHOULD** and **SHOULD NOT**
|
|
28
|
+
- maybe implement the parts of the RFC labelled with **MAY**
|
|
29
|
+
|
|
30
|
+
## Supported Ruby on Rails versions
|
|
31
|
+
|
|
32
|
+
This gem is tested against non end-of-life versions of [Ruby](https://endoflife.date/ruby) and [Rails](https://endoflife.date/rails):
|
|
33
|
+
|
|
34
|
+
- Ruby versions 3.3, 3.4 and 4.0
|
|
35
|
+
- Rails 7.2 to 8.1.
|
|
36
|
+
|
|
37
|
+
Feel free to open an issue if we missed something
|
|
38
|
+
|
|
39
|
+
It _may_ work on other versions, but we won't provide support.
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
- [Usage](docs/usage.md)
|
|
44
|
+
- [Common questions](docs/faq.md)
|
|
45
|
+
- [Contributing](CONTRIBUTING.md)
|
|
46
|
+
|
|
47
|
+
## Extensions
|
|
48
|
+
|
|
49
|
+
Extensions add extra features to Fedipub:
|
|
50
|
+
|
|
51
|
+
- [Fedipub Moderation](https://github.com/fedipub/fedipub-moderation/)
|
|
52
|
+
> A gem that provides trust & safety for Fedipub
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
57
|
+
|
|
58
|
+
## Contributing
|
|
59
|
+
|
|
60
|
+
See [CONTRIBUTING](CONTRIBUTING.md) to have an overview of the process and the tools we use.
|
|
61
|
+
|
|
62
|
+
### Contributors
|
|
63
|
+
|
|
64
|
+
- [echarp](https://gitlab.com/echarp)
|
|
65
|
+
- [James Smith](https://gitlab.com/floppy.uk)
|
|
66
|
+
- [Manuel Tancoigne](https://gitlab.com/mtancoigne)
|
|
67
|
+
- [pessi-v](https://github.com/pessi-v)
|
|
68
|
+
|
|
69
|
+
### Indirect contributions
|
|
70
|
+
|
|
71
|
+
- Gitlab runners are graciously provided by [Coopaname](https://coopaname.coop), a French cooperative.
|
data/Rakefile
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
require 'bundler/setup'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
|
4
|
+
load 'rails/tasks/engine.rake'
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
load 'rails/tasks/statistics.rake'
|
|
7
7
|
|
|
8
|
-
require
|
|
9
|
-
|
|
10
|
-
RuboCop::RakeTask.new
|
|
11
|
-
|
|
12
|
-
task default: %i[spec rubocop]
|
|
8
|
+
require 'bundler/gem_tasks'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//= link_directory ../stylesheets/fedipub .css
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
|
11
|
+
* It is generally better to create a new file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_tree .
|
|
14
|
+
*= require_self
|
|
15
|
+
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Server
|
|
3
|
+
module RenderCollections
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
def render_collection(actor:, collection:, url_helper:, &items_block)
|
|
7
|
+
if params[:page].present?
|
|
8
|
+
render_collection_page(actor: actor, collection: collection, url_helper: url_helper, items_block: items_block)
|
|
9
|
+
else
|
|
10
|
+
render 'fedipub/server/shared/ordered_collection', locals: { collection: collection, url_helper: url_helper, actor: actor }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render_collection_page(collection:, actor:, url_helper:, items_block:)
|
|
15
|
+
render 'fedipub/server/shared/ordered_collection_page', locals: { collection: collection, url_helper: url_helper, actor: actor, items_block: items_block }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Client
|
|
3
|
+
class ActivitiesController < Fedipub::ClientController
|
|
4
|
+
before_action :authenticate_user!, only: [:feed]
|
|
5
|
+
before_action :authorize_action!
|
|
6
|
+
|
|
7
|
+
# GET /app/activities
|
|
8
|
+
# GET /app/activities.json
|
|
9
|
+
def index
|
|
10
|
+
@activities = policy_scope(Fedipub::Activity, policy_scope_class: Fedipub::Client::ActivityPolicy::Scope).all
|
|
11
|
+
@activities = @activities.where actor: Actor.find_param(params[:actor_id]) if params[:actor_id]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# GET /app/feed
|
|
15
|
+
# GET /app/feed.json
|
|
16
|
+
def feed
|
|
17
|
+
@activities = Activity.feed_for(current_user.fedipub_actor)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def authorize_action!
|
|
23
|
+
authorize(Fedipub::Activity, policy_class: Fedipub::Client::ActivityPolicy)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Client
|
|
3
|
+
class ActorsController < Fedipub::ClientController
|
|
4
|
+
before_action :set_actor, only: [:show]
|
|
5
|
+
|
|
6
|
+
# GET /app/actors
|
|
7
|
+
# GET /app/actors.json
|
|
8
|
+
def index
|
|
9
|
+
authorize Fedipub::Actor, policy_class: Fedipub::Client::ActorPolicy
|
|
10
|
+
|
|
11
|
+
@actors = policy_scope(Fedipub::Actor, policy_scope_class: Fedipub::Client::ActorPolicy::Scope).all
|
|
12
|
+
@actors = @actors.local if params[:local_only]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /app/actors/1
|
|
16
|
+
# GET /app/actors/1.json
|
|
17
|
+
def show
|
|
18
|
+
render_show
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# GET /app/actors/lookup
|
|
22
|
+
# GET /app/actors/lookup.json
|
|
23
|
+
def lookup
|
|
24
|
+
@actor = Fedipub::Actor.find_by_account account_param
|
|
25
|
+
authorize @actor, policy_class: Fedipub::Client::ActorPolicy
|
|
26
|
+
render_show
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
32
|
+
def set_actor
|
|
33
|
+
@actor = Fedipub::Actor.find_param(params[:id])
|
|
34
|
+
authorize @actor, policy_class: Fedipub::Client::ActorPolicy
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def account_param
|
|
38
|
+
params.require('account').strip
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def render_show
|
|
42
|
+
respond_to do |format|
|
|
43
|
+
if @actor.tombstoned?
|
|
44
|
+
format.html { render :gone, status: :gone }
|
|
45
|
+
format.json { render json: { error: I18n.t('controller.actors.gone') }, status: :gone }
|
|
46
|
+
else
|
|
47
|
+
format.html { render :show }
|
|
48
|
+
format.json { render :show }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Client
|
|
3
|
+
class FollowingsController < Fedipub::ClientController
|
|
4
|
+
before_action :authenticate_user!
|
|
5
|
+
before_action :skip_authorization, only: [:new, :create]
|
|
6
|
+
before_action :set_following, only: [:accept, :destroy]
|
|
7
|
+
|
|
8
|
+
# GET /app/followings/new?uri={uri}
|
|
9
|
+
def new
|
|
10
|
+
# Find actor (and fetch if necessary)
|
|
11
|
+
actor = Actor.find_or_create_by_federation_url(params.require(:uri))
|
|
12
|
+
# Redirect to local profile page which will have a follow button on it
|
|
13
|
+
redirect_to fedipub.client_actor_url(actor)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# PUT /app/followings/:id/accept
|
|
17
|
+
# PUT /app/followings/:id/accept.json
|
|
18
|
+
def accept
|
|
19
|
+
respond_to do |format|
|
|
20
|
+
url = fedipub.client_actor_url @following.actor
|
|
21
|
+
if @following.accept!
|
|
22
|
+
format.html { redirect_to url, notice: I18n.t('controller.followings.accept.success') }
|
|
23
|
+
format.json { render :show, status: :ok, location: @following }
|
|
24
|
+
else
|
|
25
|
+
format.html { redirect_to url, alert: I18n.t('controller.followings.accept.error') }
|
|
26
|
+
format.json { render json: @following.errors, status: Fedipub::Utils::ResponseCodes::UNPROCESSABLE_CONTENT }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# POST /app/followings
|
|
32
|
+
# POST /app/followings.json
|
|
33
|
+
def create
|
|
34
|
+
@following = Following.new(following_params)
|
|
35
|
+
@following.actor = current_user.fedipub_actor
|
|
36
|
+
authorize @following, policy_class: Fedipub::Client::FollowingPolicy
|
|
37
|
+
|
|
38
|
+
save_and_render
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# POST /app/followings/follow
|
|
42
|
+
# POST /app/followings/follow.json
|
|
43
|
+
def follow
|
|
44
|
+
authorize Fedipub::Following, policy_class: Fedipub::Client::FollowingPolicy
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
@following = Following.new_from_account following_account_params, actor: current_user.fedipub_actor
|
|
48
|
+
rescue ::ActiveRecord::RecordNotFound
|
|
49
|
+
# Renders a 422 instead of a 404
|
|
50
|
+
respond_to do |format|
|
|
51
|
+
format.html { redirect_to fedipub.client_actors_url, alert: I18n.t('controller.followings.follow.error') }
|
|
52
|
+
format.json { render json: { target_actor: ['does not exist'] }, status: Fedipub::Utils::ResponseCodes::UNPROCESSABLE_CONTENT }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
return
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
save_and_render
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# DELETE /app/followings/1
|
|
62
|
+
# DELETE /app/followings/1.json
|
|
63
|
+
def destroy
|
|
64
|
+
@following.destroy
|
|
65
|
+
respond_to do |format|
|
|
66
|
+
format.html { redirect_to fedipub.client_actor_url(@following.actor), notice: I18n.t('controller.followings.destroy.success') }
|
|
67
|
+
format.json { head :no_content }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
74
|
+
def set_following
|
|
75
|
+
@following = Following.find_param(params[:id])
|
|
76
|
+
authorize @following, policy_class: Fedipub::Client::FollowingPolicy
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Only allow a list of trusted parameters through.
|
|
80
|
+
def following_params
|
|
81
|
+
params.require(:following).permit(:target_actor_id)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def following_account_params
|
|
85
|
+
params.require(:account)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def save_and_render # rubocop:disable Metrics/AbcSize
|
|
89
|
+
url = fedipub.client_actor_url current_user.fedipub_actor
|
|
90
|
+
|
|
91
|
+
respond_to do |format|
|
|
92
|
+
if @following.save
|
|
93
|
+
format.html { redirect_to url, notice: I18n.t('controller.followings.save_and_render.success') }
|
|
94
|
+
format.json { render :show, status: :created, location: @following }
|
|
95
|
+
else
|
|
96
|
+
format.html { redirect_to url, alert: I18n.t('controller.followings.save_and_render.error') }
|
|
97
|
+
format.json { render json: @following.errors, status: Fedipub::Utils::ResponseCodes::UNPROCESSABLE_CONTENT }
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'fediverse/inbox'
|
|
2
|
+
|
|
3
|
+
module Fedipub
|
|
4
|
+
module Server
|
|
5
|
+
class ActivitiesController < Fedipub::ServerController
|
|
6
|
+
include Fedipub::Server::RenderCollections
|
|
7
|
+
|
|
8
|
+
before_action :set_activity, only: [:show]
|
|
9
|
+
|
|
10
|
+
# GET /federation/activities
|
|
11
|
+
# GET /federation/actors/1/outbox.json
|
|
12
|
+
def outbox
|
|
13
|
+
authorize Fedipub::Activity, policy_class: Fedipub::Server::ActivityPolicy
|
|
14
|
+
|
|
15
|
+
actor = Actor.find_param(params[:actor_id])
|
|
16
|
+
activities = policy_scope(Fedipub::Activity, policy_scope_class: Fedipub::Server::ActivityPolicy::Scope).where(actor: actor).order(created_at: :desc)
|
|
17
|
+
|
|
18
|
+
render_collection(
|
|
19
|
+
collection: activities.page(params[:page]),
|
|
20
|
+
actor: actor,
|
|
21
|
+
url_helper: :server_actor_outbox_url
|
|
22
|
+
) do |builder, items|
|
|
23
|
+
builder.array! items, partial: 'fedipub/server/activities/activity', as: :activity, context: false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# GET /federation/actors/1/activities/1.json
|
|
28
|
+
def show; end
|
|
29
|
+
|
|
30
|
+
# POST /federation/actors/1/inbox
|
|
31
|
+
def create
|
|
32
|
+
skip_authorization
|
|
33
|
+
|
|
34
|
+
payload = payload_from_params
|
|
35
|
+
return head Fedipub::Utils::ResponseCodes::UNPROCESSABLE_CONTENT unless payload
|
|
36
|
+
|
|
37
|
+
if Fediverse::Inbox.dispatch_request(payload)
|
|
38
|
+
head :created
|
|
39
|
+
else
|
|
40
|
+
head Fedipub::Utils::ResponseCodes::UNPROCESSABLE_CONTENT
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
47
|
+
def set_activity
|
|
48
|
+
@activity = Actor.find_param(params[:actor_id]).activities.find_param(params[:id])
|
|
49
|
+
authorize @activity, policy_class: Fedipub::Server::ActivityPolicy
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Only allow a list of trusted parameters through.
|
|
53
|
+
def activity_params
|
|
54
|
+
params.fetch(:activity, {})
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def payload_from_params
|
|
58
|
+
payload_string = request.body.read
|
|
59
|
+
request.body.rewind if request.body.respond_to? :rewind
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
payload = JSON.parse(payload_string)
|
|
63
|
+
rescue JSON::ParserError
|
|
64
|
+
return
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
hash = JSON::LD::API.compact payload, payload['@context']
|
|
68
|
+
validate_payload hash
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validate_payload(hash)
|
|
72
|
+
return unless hash['@context'] && hash['id'] && hash['type'] && hash['actor'] && hash['object']
|
|
73
|
+
|
|
74
|
+
hash
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Server
|
|
3
|
+
class ActorsController < Fedipub::ServerController
|
|
4
|
+
include Fedipub::Server::RenderCollections
|
|
5
|
+
|
|
6
|
+
before_action :set_actor, only: [:show, :followers, :following]
|
|
7
|
+
|
|
8
|
+
# GET /federation/actors/1
|
|
9
|
+
# GET /federation/actors/1.json
|
|
10
|
+
def show
|
|
11
|
+
status = @actor.tombstoned? ? :gone : :ok
|
|
12
|
+
render :show, status: status
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /federation/actors/:id/followers
|
|
16
|
+
# GET /federation/actors/:id/followers.json
|
|
17
|
+
def followers
|
|
18
|
+
@actors = @actor.followers.order(created_at: :desc)
|
|
19
|
+
render_collection(
|
|
20
|
+
collection: @actors.page(params[:page]),
|
|
21
|
+
actor: @actor,
|
|
22
|
+
url_helper: :followers_server_actor_url
|
|
23
|
+
) do |builder, items|
|
|
24
|
+
builder.array! items.map(&:federated_url)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# GET /federation/actors/:id/followers
|
|
29
|
+
# GET /federation/actors/:id/followers.json
|
|
30
|
+
def following
|
|
31
|
+
@actors = @actor.follows.order(created_at: :desc)
|
|
32
|
+
render_collection(
|
|
33
|
+
collection: @actors.page(params[:page]),
|
|
34
|
+
actor: @actor,
|
|
35
|
+
url_helper: :following_server_actor_url
|
|
36
|
+
) do |builder, items|
|
|
37
|
+
builder.array! items.map(&:federated_url)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
44
|
+
def set_actor
|
|
45
|
+
@actor = Actor.find_param(params[:id])
|
|
46
|
+
authorize @actor, policy_class: Fedipub::Server::ActorPolicy
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Server
|
|
3
|
+
class FollowingsController < Fedipub::ServerController
|
|
4
|
+
before_action :set_following, only: [:show]
|
|
5
|
+
|
|
6
|
+
# GET /federation/actors/1/followings/1.json
|
|
7
|
+
def show; end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
12
|
+
def set_following
|
|
13
|
+
actor = Actor.find_param(params[:actor_id])
|
|
14
|
+
@following = Following.find_by!(actor: actor, uuid: params[:id])
|
|
15
|
+
authorize @following, policy_class: Fedipub::Server::FollowingPolicy
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Server
|
|
3
|
+
class NodeinfoController < Fedipub::ServerController
|
|
4
|
+
def index
|
|
5
|
+
skip_authorization
|
|
6
|
+
|
|
7
|
+
render formats: [:nodeinfo]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def show # rubocop:todo Metrics/AbcSize
|
|
11
|
+
skip_authorization
|
|
12
|
+
|
|
13
|
+
@total = @active_halfyear = @active_month = 0
|
|
14
|
+
@has_user_counts = false
|
|
15
|
+
Fedipub::Configuration.actor_types.each_value do |config|
|
|
16
|
+
next unless (method = config[:user_count_method]&.to_sym)
|
|
17
|
+
|
|
18
|
+
@has_user_counts = true
|
|
19
|
+
model = config[:class]
|
|
20
|
+
@total += model.send(method, nil)
|
|
21
|
+
@active_month += model.send(method, (30.days.ago)...Time.current)
|
|
22
|
+
@active_halfyear += model.send(method, (180.days.ago)...Time.current)
|
|
23
|
+
end
|
|
24
|
+
render formats: [:nodeinfo]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
module Server
|
|
3
|
+
# Controller to render ActivityPub representation of entities configured with Fedipub::DataEntity
|
|
4
|
+
class PublishedController < Fedipub::ServerController
|
|
5
|
+
def show
|
|
6
|
+
@publishable = type_scope.find_untombstoned_by!(url_param => params[:id])
|
|
7
|
+
authorize @publishable, policy_class: Fedipub::Server::PublishablePolicy
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def publishable_config
|
|
13
|
+
return @publishable_config if instance_variable_defined? :@publishable_config
|
|
14
|
+
|
|
15
|
+
_, @publishable_config = Fedipub.configuration.data_types.find { |_, v| v[:route_path_segment].to_s == params[:publishable_type] }
|
|
16
|
+
raise ActiveRecord::RecordNotFound, "Invalid #{params[:publishable_type]} type" unless @publishable_config
|
|
17
|
+
|
|
18
|
+
@publishable_config
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def url_param
|
|
22
|
+
publishable_config[:url_param]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def type_scope
|
|
26
|
+
publishable_config[:class].all
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'fediverse/webfinger'
|
|
2
|
+
|
|
3
|
+
module Fedipub
|
|
4
|
+
module Server
|
|
5
|
+
class WebFingerController < Fedipub::ServerController
|
|
6
|
+
def find
|
|
7
|
+
skip_authorization
|
|
8
|
+
|
|
9
|
+
resource = params.require(:resource)
|
|
10
|
+
case resource
|
|
11
|
+
when %r{^https?://.+}
|
|
12
|
+
@user = Fedipub::Actor.find_by_federation_url!(resource).entity # rubocop:disable Rails/DynamicFindBy
|
|
13
|
+
when /^acct:.+/
|
|
14
|
+
actor = Fedipub::Actor.find_local_by_username(username)
|
|
15
|
+
raise Fedipub::Actor::TombstonedError if actor&.tombstoned?
|
|
16
|
+
|
|
17
|
+
@user = actor&.entity
|
|
18
|
+
end
|
|
19
|
+
raise ActiveRecord::RecordNotFound if @user.nil?
|
|
20
|
+
|
|
21
|
+
render formats: [:jrd]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def host_meta
|
|
25
|
+
skip_authorization
|
|
26
|
+
|
|
27
|
+
render formats: [:xrd]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# TODO: complete missing endpoints
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def username
|
|
35
|
+
return @username if instance_variable_defined? :@username
|
|
36
|
+
|
|
37
|
+
account = Fediverse::Webfinger.split_account params.require(:resource)
|
|
38
|
+
# Fail early if user don't _seems_ local
|
|
39
|
+
raise ActiveRecord::RecordNotFound unless account && Fediverse::Webfinger.local_user?(account)
|
|
40
|
+
|
|
41
|
+
@username = account[:username]
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Fedipub
|
|
2
|
+
class ServerController < ::ActionController::Base # rubocop:disable Rails/ApplicationController
|
|
3
|
+
include Pundit::Authorization
|
|
4
|
+
|
|
5
|
+
after_action :verify_authorized
|
|
6
|
+
|
|
7
|
+
protect_from_forgery with: :null_session
|
|
8
|
+
helper Fedipub::ServerHelper
|
|
9
|
+
|
|
10
|
+
rescue_from ActiveRecord::RecordNotFound, with: :error_not_found
|
|
11
|
+
rescue_from Fedipub::Actor::TombstonedError,
|
|
12
|
+
Fedipub::DataEntity::TombstonedError,
|
|
13
|
+
with: :error_gone
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def error_fallback(exception, fallback_message, status)
|
|
18
|
+
message = exception&.message || fallback_message
|
|
19
|
+
respond_to do |format|
|
|
20
|
+
format.jrd { head status }
|
|
21
|
+
format.xrd { head status }
|
|
22
|
+
format.activitypub { head status }
|
|
23
|
+
format.nodeinfo { head status }
|
|
24
|
+
format.json { render json: { error: message }, status: status }
|
|
25
|
+
format.html { raise exception }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def error_not_found(exception = nil)
|
|
30
|
+
error_fallback(exception, 'Resource not found', :not_found)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def error_gone(exception = nil)
|
|
34
|
+
error_fallback(exception, 'Resource is gone', :gone)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'fedipub/utils/context'
|
|
2
|
+
|
|
3
|
+
module Fedipub
|
|
4
|
+
module ServerHelper
|
|
5
|
+
def remote_follow_url
|
|
6
|
+
method_name = Fedipub.configuration.remote_follow_url_method.to_s
|
|
7
|
+
if method_name.starts_with? 'fedipub.'
|
|
8
|
+
send(method_name.gsub('fedipub.', ''))
|
|
9
|
+
else
|
|
10
|
+
Rails.application.routes.url_helpers.send(method_name)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def set_json_ld_context(json, additional: nil)
|
|
15
|
+
json.set! '@context', Fedipub::Utils::Context.generate(additional: additional)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require 'fediverse/notifier'
|
|
2
|
+
|
|
3
|
+
module Fedipub
|
|
4
|
+
class FetchNodeinfoJob < ApplicationJob
|
|
5
|
+
# @param domain [String] Domain to create/update
|
|
6
|
+
def perform(domain)
|
|
7
|
+
Fedipub::Host.create_or_update domain, min_update_interval: Fedipub::Configuration.remote_entities_cache_duration
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|