5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-05-20 02:00:48 +00:00

feat: recibir y almacenar actividades

This commit is contained in:
f 2024-02-20 17:15:43 -03:00
parent 8921de81ae
commit 9fa4335314
No known key found for this signature in database
7 changed files with 262 additions and 115 deletions

View file

@ -80,6 +80,9 @@ gem 'yaml_db', git: 'https://0xacab.org/sutty/yaml_db.git'
gem 'kaminari'
gem 'device_detector'
gem 'after_commit_everywhere'
gem 'aasm'
# database
gem 'hairtrigger'
gem 'pg'

View file

@ -27,74 +27,80 @@ GIT
GEM
remote: https://17.3.alpine.gems.sutty.nl/
specs:
actioncable (6.1.7.3)
actionpack (= 6.1.7.3)
activesupport (= 6.1.7.3)
aasm (5.5.0)
concurrent-ruby (~> 1.0)
actioncable (6.1.7.4)
actionpack (= 6.1.7.4)
activesupport (= 6.1.7.4)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (6.1.7.3)
actionpack (= 6.1.7.3)
activejob (= 6.1.7.3)
activerecord (= 6.1.7.3)
activestorage (= 6.1.7.3)
activesupport (= 6.1.7.3)
actionmailbox (6.1.7.4)
actionpack (= 6.1.7.4)
activejob (= 6.1.7.4)
activerecord (= 6.1.7.4)
activestorage (= 6.1.7.4)
activesupport (= 6.1.7.4)
mail (>= 2.7.1)
actionmailer (6.1.7.3)
actionpack (= 6.1.7.3)
actionview (= 6.1.7.3)
activejob (= 6.1.7.3)
activesupport (= 6.1.7.3)
actionmailer (6.1.7.4)
actionpack (= 6.1.7.4)
actionview (= 6.1.7.4)
activejob (= 6.1.7.4)
activesupport (= 6.1.7.4)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.7.3)
actionview (= 6.1.7.3)
activesupport (= 6.1.7.3)
actionpack (6.1.7.4)
actionview (= 6.1.7.4)
activesupport (= 6.1.7.4)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.1.7.3)
actionpack (= 6.1.7.3)
activerecord (= 6.1.7.3)
activestorage (= 6.1.7.3)
activesupport (= 6.1.7.3)
actiontext (6.1.7.4)
actionpack (= 6.1.7.4)
activerecord (= 6.1.7.4)
activestorage (= 6.1.7.4)
activesupport (= 6.1.7.4)
nokogiri (>= 1.8.5)
actionview (6.1.7.3)
activesupport (= 6.1.7.3)
actionview (6.1.7.4)
activesupport (= 6.1.7.4)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.1.7.3)
activesupport (= 6.1.7.3)
activejob (6.1.7.4)
activesupport (= 6.1.7.4)
globalid (>= 0.3.6)
activemodel (6.1.7.3)
activesupport (= 6.1.7.3)
activerecord (6.1.7.3)
activemodel (= 6.1.7.3)
activesupport (= 6.1.7.3)
activestorage (6.1.7.3)
actionpack (= 6.1.7.3)
activejob (= 6.1.7.3)
activerecord (= 6.1.7.3)
activesupport (= 6.1.7.3)
activemodel (6.1.7.4)
activesupport (= 6.1.7.4)
activerecord (6.1.7.4)
activemodel (= 6.1.7.4)
activesupport (= 6.1.7.4)
activestorage (6.1.7.4)
actionpack (= 6.1.7.4)
activejob (= 6.1.7.4)
activerecord (= 6.1.7.4)
activesupport (= 6.1.7.4)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
activesupport (6.1.7.3)
activesupport (6.1.7.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.4)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
adsp (1.0.10)
after_commit_everywhere (1.4.0)
activerecord (>= 4.2)
activesupport
ast (2.4.2)
autoprefixer-rails (10.4.13.0)
execjs (~> 2)
bcrypt (3.1.19-x86_64-linux-musl)
bcrypt (3.1.20-x86_64-linux-musl)
bcrypt_pbkdf (1.1.0-x86_64-linux-musl)
benchmark-ips (2.12.0)
bigdecimal (3.1.1)
bindex (0.8.1-x86_64-linux-musl)
blazer (2.6.5)
activerecord (>= 5)
@ -105,7 +111,8 @@ GEM
autoprefixer-rails (>= 9.1.0)
popper_js (>= 1.16.1, < 2)
sassc-rails (>= 2.0.0)
brakeman (5.4.1)
brakeman (6.1.1)
racc
builder (3.2.4)
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
@ -125,6 +132,7 @@ GEM
concurrent-ruby (1.2.2)
concurrent-ruby-ext (1.2.2-x86_64-linux-musl)
concurrent-ruby (= 1.2.2)
connection_pool (2.4.1)
crass (1.0.6)
database_cleaner (2.0.2)
database_cleaner-active_record (>= 2, < 3)
@ -132,7 +140,7 @@ GEM
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
date (3.3.3-x86_64-linux-musl)
date (3.3.4-x86_64-linux-musl)
dead_end (4.0.0)
derailed_benchmarks (2.1.2)
benchmark-ips (~> 2)
@ -146,8 +154,8 @@ GEM
rake (> 10, < 14)
ruby-statistics (>= 2.1)
thor (>= 0.19, < 2)
device_detector (1.1.1)
devise (4.9.2)
device_detector (1.1.2)
devise (4.9.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@ -155,7 +163,7 @@ GEM
warden (~> 1.2.3)
devise-i18n (1.11.0)
devise (>= 4.9.0)
devise_invitable (2.0.8)
devise_invitable (2.0.9)
actionmailer (>= 5.0)
devise (>= 4.6)
distributed-press-api-client (0.4.0rc2)
@ -172,10 +180,10 @@ GEM
railties (>= 3.2)
down (5.4.1)
addressable (~> 2.8)
dry-configurable (1.0.1)
dry-configurable (1.1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
dry-core (1.0.0)
dry-core (1.0.1)
concurrent-ruby (~> 1.0)
zeitwerk (~> 2.6)
dry-inflector (1.0.0)
@ -184,7 +192,7 @@ GEM
concurrent-ruby (~> 1.0)
dry-core (~> 1.0, < 2)
zeitwerk (~> 2.6)
dry-schema (1.13.1)
dry-schema (1.13.3)
concurrent-ruby (~> 1.0)
dry-configurable (~> 1.0, >= 1.0.1)
dry-core (~> 1.0, < 2)
@ -192,7 +200,8 @@ GEM
dry-logic (>= 1.4, < 2)
dry-types (>= 1.7, < 2)
zeitwerk (~> 2.6)
dry-types (1.7.1)
dry-types (1.7.2)
bigdecimal (~> 3.0)
concurrent-ruby (~> 1.0)
dry-core (~> 1.0)
dry-inflector (~> 1.0)
@ -225,25 +234,25 @@ GEM
ffi (~> 1.0)
git_clone_url (2.0.0)
uri-ssh_git (>= 2.0)
globalid (1.1.0)
activesupport (>= 5.0)
globalid (1.2.1)
activesupport (>= 6.1)
groupdate (6.2.1)
activesupport (>= 5.2)
hairtrigger (1.0.0)
activerecord (>= 6.0, < 8)
ruby2ruby (~> 2.4)
ruby_parser (~> 3.10)
haml (6.1.2-x86_64-linux-musl)
haml (6.3.0)
temple (>= 0.8.2)
thor
tilt
haml-lint (0.999.999)
haml_lint
haml_lint (0.45.0)
haml (>= 4.0, < 6.2)
haml_lint (0.53.0)
haml (>= 5.0)
parallel (~> 1.10)
rainbow
rubocop (>= 0.50.0)
rubocop (>= 1.0)
sysexits (~> 1.1)
hamlit (3.0.3-x86_64-linux-musl)
temple (>= 0.8.2)
@ -296,7 +305,7 @@ GEM
terminal-table (~> 2.0)
jekyll-commonmark (1.4.0)
commonmarker (~> 0.22)
jekyll-images (0.4.1)
jekyll-images (0.4.4)
jekyll (~> 4)
ruby-filemagic (~> 0.7)
ruby-vips (~> 2)
@ -306,7 +315,7 @@ GEM
sassc (> 2.0.1, < 3.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
json (2.6.3-x86_64-linux-musl)
json (2.7.1-x86_64-linux-musl)
jwt (2.6.0)
kaminari (1.2.2)
activesupport (>= 4.1.0)
@ -335,12 +344,12 @@ GEM
loaf (0.10.0)
railties (>= 3.2)
lockbox (1.2.0)
lograge (0.12.0)
lograge (0.14.0)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
loofah (2.21.3)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
@ -354,36 +363,37 @@ GEM
method_source (1.0.0)
mini_histogram (0.3.1)
mini_magick (4.12.0)
mini_mime (1.1.2)
mini_portile2 (2.8.2)
minitest (5.18.0)
mini_mime (1.1.5)
mini_portile2 (2.8.5)
minitest (5.21.1)
mobility (1.2.9)
i18n (>= 0.6.10, < 2)
request_store (~> 1.0)
multi_xml (0.6.0)
net-imap (0.3.4)
net-imap (0.4.9)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.1)
net-protocol (0.2.2)
timeout
net-smtp (0.3.3)
net-smtp (0.4.0)
net-protocol
net-ssh (7.1.0)
net-ssh (7.2.1)
netaddr (2.0.6)
nio4r (2.5.9-x86_64-linux-musl)
nokogiri (1.15.4-x86_64-linux-musl)
nio4r (2.7.0-x86_64-linux-musl)
nokogiri (1.16.0-x86_64-linux-musl)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
orm_adapter (0.5.0)
pairing_heap (3.0.1)
parallel (1.23.0)
parser (3.2.2.1)
parallel (1.24.0)
parser (3.2.2.3)
ast (~> 2.4.1)
racc
pathutil (0.16.2)
forwardable-extended (~> 2.6)
pg (1.5.3-x86_64-linux-musl)
pg (1.5.4-x86_64-linux-musl)
pg_search (2.3.6)
activerecord (>= 5.2)
activesupport (>= 5.2)
@ -393,55 +403,57 @@ GEM
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (5.0.3)
puma (6.3.1-x86_64-linux-musl)
public_suffix (5.0.4)
puma (6.4.2-x86_64-linux-musl)
nio4r (~> 2.0)
pundit (2.3.0)
pundit (2.3.1)
activesupport (>= 3.0.0)
que (2.2.1)
racc (1.7.1-x86_64-linux-musl)
rack (2.2.7)
racc (1.7.3-x86_64-linux-musl)
rack (2.2.8)
rack-cors (2.0.1)
rack (>= 2.0.0)
rack-mini-profiler (3.1.0)
rack (>= 1.2.0)
rack-proxy (0.7.6)
rack-proxy (0.7.7)
rack
rack-test (2.1.0)
rack (>= 1.3)
rails (6.1.7.3)
actioncable (= 6.1.7.3)
actionmailbox (= 6.1.7.3)
actionmailer (= 6.1.7.3)
actionpack (= 6.1.7.3)
actiontext (= 6.1.7.3)
actionview (= 6.1.7.3)
activejob (= 6.1.7.3)
activemodel (= 6.1.7.3)
activerecord (= 6.1.7.3)
activestorage (= 6.1.7.3)
activesupport (= 6.1.7.3)
rails (6.1.7.4)
actioncable (= 6.1.7.4)
actionmailbox (= 6.1.7.4)
actionmailer (= 6.1.7.4)
actionpack (= 6.1.7.4)
actiontext (= 6.1.7.4)
actionview (= 6.1.7.4)
activejob (= 6.1.7.4)
activemodel (= 6.1.7.4)
activerecord (= 6.1.7.4)
activestorage (= 6.1.7.4)
activesupport (= 6.1.7.4)
bundler (>= 1.15.0)
railties (= 6.1.7.3)
railties (= 6.1.7.4)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.5.0)
loofah (~> 2.19, >= 2.19.1)
rails-i18n (7.0.7)
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
rails-i18n (7.0.8)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 8)
rails_warden (0.6.0)
warden (>= 1.2.0)
railties (6.1.7.3)
actionpack (= 6.1.7.3)
activesupport (= 6.1.7.3)
railties (6.1.7.4)
actionpack (= 6.1.7.4)
activesupport (= 6.1.7.4)
method_source
rake (>= 12.2)
thor (~> 1.0)
rainbow (3.1.1)
rake (13.0.6)
rake (13.1.0)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
@ -464,13 +476,13 @@ GEM
redis-store (>= 1.2, < 2)
redis-store (1.9.2)
redis (>= 4, < 6)
regexp_parser (2.8.0)
regexp_parser (2.9.0)
request_store (1.5.1)
rack (>= 1.4)
responders (3.1.0)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.5)
rexml (3.2.6)
rgl (0.6.3)
pairing_heap (>= 0.3.0)
rexml (~> 3.2, >= 3.2.4)
@ -486,18 +498,19 @@ GEM
rubocop-ast (>= 1.24.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.28.1)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
rubocop-rails (2.19.1)
rubocop-rails (2.23.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-brs (1.3.3-x86_64-linux-musl)
adsp (~> 1.0)
ruby-filemagic (0.7.3-x86_64-linux-musl)
ruby-progressbar (1.13.0)
ruby-statistics (3.0.2)
ruby-vips (2.1.4)
ruby-vips (2.2.0)
ffi (~> 1.12)
ruby2ruby (2.5.0)
ruby_parser (~> 3.1)
@ -530,14 +543,14 @@ GEM
spring-watcher-listen (2.1.0)
listen (>= 2.7, < 4.0)
spring (>= 4)
sprockets (4.2.0)
sprockets (4.2.1)
concurrent-ruby (~> 1.0)
rack (>= 2.2.4, < 4)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
sqlite3 (1.6.3-x86_64-linux-musl)
sqlite3 (1.7.0-x86_64-linux-musl)
mini_portile2 (~> 2.8.0)
stackprof (0.2.25-x86_64-linux-musl)
stream (0.5.5)
@ -546,13 +559,13 @@ GEM
jekyll (~> 4)
symbol-fstring (1.0.2-x86_64-linux-musl)
sysexits (1.2.0)
temple (0.10.1)
temple (0.10.3)
terminal-table (2.0.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thor (1.3.0)
tilt (2.1.0)
tilt (2.3.0)
timecop (0.9.6)
timeout (0.3.2)
timeout (0.4.1)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
@ -562,7 +575,7 @@ GEM
execjs (>= 0.3.0, < 3)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2-x86_64-linux-musl)
unf_ext (0.0.9-x86_64-linux-musl)
unicode-display_width (1.8.0)
uri-ssh_git (2.0.0)
validates_hostname (1.0.13)
@ -588,12 +601,14 @@ GEM
xpath (3.2.0)
nokogiri (~> 1.8)
yard (0.9.34)
zeitwerk (2.6.8)
zeitwerk (2.6.12)
PLATFORMS
x86_64-linux-musl
DEPENDENCIES
aasm
after_commit_everywhere
bcrypt (~> 3.1.7)
bcrypt_pbkdf
blazer

View file

@ -19,6 +19,16 @@ module Api
# El objeto del estado puede ser un objeto o une actore,
# dependiendo de la actividad.
def moderationqueued
# Devuelve un error si el token no es válido
usuarie.present?
ActivityPub.transaction do
# Crea todos los registros necesarios y actualiza el estado
activity.update_activity_pub_state!
end
rescue ActiveRecord::RecordInvalid => e
ExceptionNotifier.notify_exception(e, data: { site: site.name, usuarie: usuarie.email, activity: original_activity })
ensure
head :accepted
end
@ -33,6 +43,101 @@ module Api
def onrejected
head :accepted
end
private
# Si el objeto ya viene incorporado en la actividad o lo tenemos
# que traer remotamente.
#
# @return [Bool]
def object_embedded?
@object_embedded ||= original_activity[:object].is_a?(Hash)
end
# Encuentra la URI del objeto o falla si no la encuentra.
#
# @return [String]
def object_uri
@object_uri ||=
begin
case original_activity[:object]
when String then original_activity[:object]
when Hash then original_activity.dig(:object, :id)
end
end
ensure
raise ActiveRecord::RecordNotFound, 'object id missing' unless @object_uri
end
# Atajo a la instancia
#
# @return [ActivityPub::Instance]
def instance
actor.instance
end
# Genera un objeto a partir de la actividad. Si el objeto ya
# existe, actualiza su contenido.
#
# @return [ActivityPub::Object]
def object
@object ||= ActivityPub::Object.type_from(original_object).find_or_initialize_by(actor: actor, uri: object_uri).tap do |o|
o.content = original_object if object_embedded?
o.save!
end
end
# Genera el seguimiento del estado del objeto con respecto al
# sitio.
#
# @return [ActivityPub]
def activity_pub
@activity_pub ||= site.activity_pubs.find_or_create_by!(site: site, object: object)
end
# Crea la actividad y la vincula con el estado
#
# @return [ActivityPub::Activity]
def activity
@activity ||= ActivityPub::Activity.type_from(original_activity).new(uri: original_activity[:id], activity_pub: activity_pub).tap do |a|
a.content = original_activity.dup
a.content[:object] = object.uri
a.save!
end
end
# Actor, si no hay instancia, la crea en el momento
#
# @return [Actor]
def actor
@actor ||= ActivityPub::Actor.find_or_initialize_by(uri: original_activity[:actor]).tap do |a|
next if a.instance
a.instance = ActivityPub::Instance.find_or_create_by(hostname: URI.parse(a.uri).hostname)
a.save!
end
end
# Descubre la actividad recibida, generando un error si la
# actividad no está dirigida a nosotres.
#
# @todo Validar formato
# @return [Hash]
def original_activity
@original_activity ||= FastJsonparser.parse(request.raw_post).tap do |activity|
raise '@context missing' unless activity[:@context].presence
raise 'id missing' unless activity[:id].presence
raise 'object missing' unless activity[:object].presence
raise 'not for us' unless [activity[:to]].flatten.include?(site.social_inbox.actor_id)
rescue RuntimeError => e
raise ActiveRecord::RecordNotFound, e.message
end
end
# @return [Hash,String]
def original_object
@original_object ||= original_activity[:object].dup
end
end
end
end

View file

@ -21,4 +21,9 @@ class ActivityPub::Activity < ApplicationRecord
# Siempre en orden descendiente para saber el último estado
default_scope -> { order(created_at: :desc) }
# Cambia la máquina de estados según el tipo de actividad
def update_activity_pub_state!
nil
end
end

View file

@ -16,9 +16,11 @@ class ActivityPub
# @param object [Hash]
# @return [Activity]
def self.type_from(object)
"#{self.class.name}::#{object[:type].presence || 'Generic'}".constantize
raise NameError unless object.is_a?(Hash)
"#{model_name.name}::#{object[:type].presence || 'Generic'}".constantize
rescue NameError
self.class::Generic
model_name.name.constantize::Generic
end
private

View file

@ -10,6 +10,8 @@ class Site
included do
encrypts :private_key_pem
has_many :activity_pubs
before_save :generate_private_key_pem!, unless: :private_key_pem?
# @return [SocialInbox]

View file

@ -24,6 +24,12 @@ class SocialInbox
end
end
def actor_id
@actor_id ||= generate_uri do |uri|
uri.path = '/about.jsonld'
end
end
# @return [DistributedPress::V1::Social::Client]
def client
@client ||= DistributedPress::V1::Social::Client.new(
@ -42,14 +48,23 @@ class SocialInbox
# @return [String]
def public_key_url
@public_key_url ||= URI("https://#{hostname}").tap do |uri|
@public_key_url ||= generate_uri do |uri|
uri.path = '/about.jsonld'
uri.fragment = 'main-key'
end.to_s
end
end
def hostname
@hostname ||=
site.config.dig('activity_pub', 'hostname') || site.hostname
end
# Genera una URI dentro de este sitio
#
# @return [String]
def generate_uri(&block)
@public_key_url ||= URI("https://#{hostname}").tap do |uri|
yield uri
end.to_s
end
end