diaspora_federation 0.0.13 → 0.1.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 +15 -32
- data/lib/diaspora_federation.rb +9 -31
- data/lib/diaspora_federation/discovery/h_card.rb +8 -15
- data/lib/diaspora_federation/discovery/host_meta.rb +2 -4
- data/lib/diaspora_federation/discovery/web_finger.rb +11 -11
- data/lib/diaspora_federation/discovery/xrd_document.rb +4 -8
- data/lib/diaspora_federation/entities.rb +2 -0
- data/lib/diaspora_federation/entities/account_deletion.rb +5 -0
- data/lib/diaspora_federation/entities/comment.rb +3 -6
- data/lib/diaspora_federation/entities/contact.rb +5 -0
- data/lib/diaspora_federation/entities/conversation.rb +10 -1
- data/lib/diaspora_federation/entities/message.rb +29 -4
- data/lib/diaspora_federation/entities/participation.rb +24 -0
- data/lib/diaspora_federation/entities/poll_participation.rb +3 -6
- data/lib/diaspora_federation/entities/profile.rb +5 -0
- data/lib/diaspora_federation/entities/related_entity.rb +33 -0
- data/lib/diaspora_federation/entities/relayable.rb +55 -40
- data/lib/diaspora_federation/entities/relayable_retraction.rb +21 -12
- data/lib/diaspora_federation/entities/request.rb +6 -2
- data/lib/diaspora_federation/entities/reshare.rb +5 -0
- data/lib/diaspora_federation/entities/retraction.rb +37 -0
- data/lib/diaspora_federation/entities/signed_retraction.rb +16 -5
- data/lib/diaspora_federation/entities/status_message.rb +11 -0
- data/lib/diaspora_federation/entity.rb +73 -30
- data/lib/diaspora_federation/federation/fetcher.rb +11 -1
- data/lib/diaspora_federation/federation/receiver.rb +10 -0
- data/lib/diaspora_federation/federation/receiver/abstract_receiver.rb +18 -4
- data/lib/diaspora_federation/federation/receiver/exceptions.rb +4 -0
- data/lib/diaspora_federation/federation/receiver/public.rb +10 -0
- data/lib/diaspora_federation/federation/sender.rb +1 -1
- data/lib/diaspora_federation/http_client.rb +1 -2
- data/lib/diaspora_federation/logging.rb +6 -0
- data/lib/diaspora_federation/properties_dsl.rb +4 -2
- data/lib/diaspora_federation/salmon/encrypted_magic_envelope.rb +2 -2
- data/lib/diaspora_federation/salmon/encrypted_slap.rb +3 -5
- data/lib/diaspora_federation/salmon/exceptions.rb +1 -1
- data/lib/diaspora_federation/salmon/magic_envelope.rb +16 -17
- data/lib/diaspora_federation/salmon/slap.rb +1 -2
- data/lib/diaspora_federation/salmon/xml_payload.rb +1 -2
- data/lib/diaspora_federation/validators.rb +2 -0
- data/lib/diaspora_federation/validators/conversation_validator.rb +2 -0
- data/lib/diaspora_federation/validators/message_validator.rb +2 -2
- data/lib/diaspora_federation/validators/participation_validator.rb +3 -2
- data/lib/diaspora_federation/validators/poll_validator.rb +1 -0
- data/lib/diaspora_federation/validators/related_entity_validator.rb +12 -0
- data/lib/diaspora_federation/validators/relayable_retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/relayable_validator.rb +1 -0
- data/lib/diaspora_federation/validators/retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/rules/diaspora_id.rb +8 -11
- data/lib/diaspora_federation/validators/rules/diaspora_id_count.rb +1 -1
- data/lib/diaspora_federation/validators/signed_retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/status_message_validator.rb +2 -0
- data/lib/diaspora_federation/validators/web_finger_validator.rb +2 -2
- data/lib/diaspora_federation/version.rb +1 -1
- metadata +9 -7
@@ -26,10 +26,35 @@ module DiasporaFederation
|
|
26
26
|
# @return [String] conversation guid
|
27
27
|
property :conversation_guid
|
28
28
|
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
|
29
|
+
# It is only valid to receive a {Message} from the author itself,
|
30
|
+
# or from the author of the parent {Conversation} if the author signature is valid.
|
31
|
+
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
32
|
+
def sender_valid?(sender)
|
33
|
+
sender == author || (sender == parent_author && verify_author_signature)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
39
|
+
def verify_author_signature
|
40
|
+
verify_signature(author, :author_signature)
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
45
|
+
def parent_author
|
46
|
+
parent = DiasporaFederation.callbacks.trigger(:fetch_related_entity, "Conversation", conversation_guid)
|
47
|
+
raise Federation::Fetcher::NotFetchable, "parent of #{self} not found" unless parent
|
48
|
+
parent.author
|
49
|
+
end
|
50
|
+
|
51
|
+
# Default implementation, don't verify signatures for a {Message}.
|
52
|
+
# @see Entity.populate_entity
|
53
|
+
# @deprecated remove after {Message} doesn't include {Relayable} anymore
|
54
|
+
# @param [Nokogiri::XML::Element] root_node xml nodes
|
55
|
+
# @return [Entity] instance
|
56
|
+
private_class_method def self.populate_entity(root_node)
|
57
|
+
new({parent_guid: nil, parent: nil}.merge(entity_data(root_node)))
|
33
58
|
end
|
34
59
|
end
|
35
60
|
end
|
@@ -15,6 +15,30 @@ module DiasporaFederation
|
|
15
15
|
# currently only "Post" is supported.
|
16
16
|
# @return [String] parent type
|
17
17
|
property :parent_type, xml_name: :target_type
|
18
|
+
|
19
|
+
# It is only valid to receive a {Participation} from the author itself.
|
20
|
+
# @deprecated remove after {Participation} doesn't include {Relayable} anymore
|
21
|
+
def sender_valid?(sender)
|
22
|
+
sender == author
|
23
|
+
end
|
24
|
+
|
25
|
+
# validates that the parent exists and the parent author is local
|
26
|
+
def validate_parent
|
27
|
+
parent = DiasporaFederation.callbacks.trigger(:fetch_related_entity, parent_type, parent_guid)
|
28
|
+
raise ParentNotLocal, "obj=#{self}" unless parent && parent.local
|
29
|
+
end
|
30
|
+
|
31
|
+
# Don't verify signatures for a {Participation}. Validate that the parent is local.
|
32
|
+
# @see Entity.populate_entity
|
33
|
+
# @param [Nokogiri::XML::Element] root_node xml nodes
|
34
|
+
# @return [Entity] instance
|
35
|
+
private_class_method def self.populate_entity(root_node)
|
36
|
+
new(entity_data(root_node).merge(parent: nil)).tap(&:validate_parent)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Raised, if the parent is not owned by the receiving pod.
|
40
|
+
class ParentNotLocal < RuntimeError
|
41
|
+
end
|
18
42
|
end
|
19
43
|
end
|
20
44
|
end
|
@@ -8,6 +8,9 @@ module DiasporaFederation
|
|
8
8
|
# @deprecated
|
9
9
|
LEGACY_SIGNATURE_ORDER = %i(guid parent_guid author poll_answer_guid).freeze
|
10
10
|
|
11
|
+
# The {PollParticipation} parent is a {Poll}
|
12
|
+
PARENT_TYPE = "Poll".freeze
|
13
|
+
|
11
14
|
include Relayable
|
12
15
|
|
13
16
|
# @!attribute [r] poll_answer_guid
|
@@ -15,12 +18,6 @@ module DiasporaFederation
|
|
15
18
|
# @see PollAnswer#guid
|
16
19
|
# @return [String] poll answer guid
|
17
20
|
property :poll_answer_guid
|
18
|
-
|
19
|
-
# The {PollParticipation} parent is a {Poll}
|
20
|
-
# @return [String] parent type
|
21
|
-
def parent_type
|
22
|
-
"Poll"
|
23
|
-
end
|
24
21
|
end
|
25
22
|
end
|
26
23
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Entities
|
3
|
+
# Entity meta informations for a related entity (parent or target of
|
4
|
+
# another entity).
|
5
|
+
class RelatedEntity < Entity
|
6
|
+
# @!attribute [r] author
|
7
|
+
# The diaspora ID of the author.
|
8
|
+
# @see Person#author
|
9
|
+
# @return [String] diaspora ID
|
10
|
+
property :author
|
11
|
+
|
12
|
+
# @!attribute [r] local
|
13
|
+
# +true+ if the owner of the entity is local on the pod
|
14
|
+
# @return [Boolean] is it a like or a dislike
|
15
|
+
property :local
|
16
|
+
|
17
|
+
# @!attribute [r] public
|
18
|
+
# shows whether the entity is visible to everyone or only to some aspects
|
19
|
+
# @return [Boolean] is it public
|
20
|
+
property :public, default: false
|
21
|
+
|
22
|
+
# @!attribute [r] parent
|
23
|
+
# if the entity also have a parent (Comment or Like), +nil+ if it has no parent
|
24
|
+
# @return [RelatedEntity] parent entity
|
25
|
+
entity :parent, Entities::RelatedEntity, default: nil
|
26
|
+
|
27
|
+
# never add {RelatedEntity} to xml
|
28
|
+
def to_xml
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -45,20 +45,24 @@ module DiasporaFederation
|
|
45
45
|
# This signature is required only when federation from upstream (parent) post author to
|
46
46
|
# downstream subscribers. This is the case when the parent author has to resend a relayable
|
47
47
|
# received from one of his subscribers to all others.
|
48
|
-
#
|
49
48
|
# @return [String] parent author signature
|
50
49
|
#
|
51
|
-
#
|
52
|
-
|
53
|
-
|
50
|
+
# @!attribute [r] parent
|
51
|
+
# meta information about the parent object
|
52
|
+
# @return [RelatedEntity] parent entity
|
53
|
+
#
|
54
|
+
# @param [Entity] klass the entity in which it is included
|
55
|
+
def self.included(klass)
|
56
|
+
klass.class_eval do
|
54
57
|
property :author, xml_name: :diaspora_handle
|
55
58
|
property :guid
|
56
59
|
property :parent_guid
|
57
60
|
property :author_signature, default: nil
|
58
61
|
property :parent_author_signature, default: nil
|
62
|
+
entity :parent, Entities::RelatedEntity
|
59
63
|
end
|
60
64
|
|
61
|
-
|
65
|
+
klass.extend ParseXML
|
62
66
|
end
|
63
67
|
|
64
68
|
# Initializes a new relayable Entity with order and additional xml elements
|
@@ -77,62 +81,59 @@ module DiasporaFederation
|
|
77
81
|
# verifies the signatures (+author_signature+ and +parent_author_signature+ if needed)
|
78
82
|
# @raise [SignatureVerificationFailed] if the signature is not valid or no public key is found
|
79
83
|
def verify_signatures
|
80
|
-
|
81
|
-
raise PublicKeyNotFound, "author_signature author=#{author} guid=#{guid}" if pubkey.nil?
|
82
|
-
raise SignatureVerificationFailed, "wrong author_signature" unless verify_signature(pubkey, author_signature)
|
84
|
+
verify_signature(author, :author_signature)
|
83
85
|
|
84
|
-
|
85
|
-
|
86
|
+
# this happens only on downstream federation
|
87
|
+
verify_signature(parent.author, :parent_author_signature) unless parent.local
|
86
88
|
end
|
87
89
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
def verify_parent_author_signature
|
92
|
-
pubkey = DiasporaFederation.callbacks.trigger(:fetch_author_public_key_by_entity_guid, parent_type, parent_guid)
|
90
|
+
def sender_valid?(sender)
|
91
|
+
sender == author || sender == parent.author
|
92
|
+
end
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
94
|
+
# @return [String] string representation of this object
|
95
|
+
def to_s
|
96
|
+
"#{super}#{":#{parent_type}" if respond_to?(:parent_type)}:#{parent_guid}"
|
98
97
|
end
|
99
98
|
|
99
|
+
private
|
100
|
+
|
100
101
|
# Check that signature is a correct signature
|
101
102
|
#
|
102
|
-
# @param [
|
103
|
-
# @param [String]
|
103
|
+
# @param [String] author The author of the signature
|
104
|
+
# @param [String] signature_key The signature to be verified
|
104
105
|
# @return [Boolean] signature valid
|
105
|
-
def verify_signature(
|
106
|
-
|
107
|
-
|
108
|
-
return false
|
109
|
-
end
|
106
|
+
def verify_signature(author, signature_key)
|
107
|
+
pubkey = DiasporaFederation.callbacks.trigger(:fetch_public_key, author)
|
108
|
+
raise PublicKeyNotFound, "signature=#{signature_key} person=#{author} obj=#{self}" if pubkey.nil?
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
110
|
+
signature = public_send(signature_key)
|
111
|
+
raise SignatureVerificationFailed, "no #{signature_key} for #{self}" if signature.nil?
|
112
|
+
|
113
|
+
valid = pubkey.verify(DIGEST, Base64.decode64(signature), signature_data)
|
114
|
+
raise SignatureVerificationFailed, "wrong #{signature_key} for #{self}" unless valid
|
115
|
+
|
116
|
+
logger.info "event=verify_signature signature=#{signature_key} status=valid obj=#{self}"
|
114
117
|
end
|
115
118
|
|
116
119
|
# sign with author key
|
117
120
|
# @raise [AuthorPrivateKeyNotFound] if the author private key is not found
|
118
121
|
# @return [String] A Base64 encoded signature of #signature_data with key
|
119
122
|
def sign_with_author
|
120
|
-
privkey = DiasporaFederation.callbacks.trigger(:
|
121
|
-
raise AuthorPrivateKeyNotFound, "author=#{author}
|
123
|
+
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, author)
|
124
|
+
raise AuthorPrivateKeyNotFound, "author=#{author} obj=#{self}" if privkey.nil?
|
122
125
|
sign_with_key(privkey).tap do
|
123
|
-
logger.info "event=sign status=complete signature=author_signature author=#{author}
|
126
|
+
logger.info "event=sign status=complete signature=author_signature author=#{author} obj=#{self}"
|
124
127
|
end
|
125
128
|
end
|
126
129
|
|
127
130
|
# sign with parent author key, if the parent author is local (if the private key is found)
|
128
131
|
# @return [String] A Base64 encoded signature of #signature_data with key
|
129
132
|
def sign_with_parent_author_if_available
|
130
|
-
privkey = DiasporaFederation.callbacks.trigger(
|
131
|
-
:fetch_author_private_key_by_entity_guid, parent_type, parent_guid
|
132
|
-
)
|
133
|
+
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, parent.author)
|
133
134
|
if privkey
|
134
135
|
sign_with_key(privkey).tap do
|
135
|
-
logger.info "event=sign status=complete signature=parent_author_signature
|
136
|
+
logger.info "event=sign status=complete signature=parent_author_signature obj=#{self}"
|
136
137
|
end
|
137
138
|
end
|
138
139
|
end
|
@@ -152,7 +153,7 @@ module DiasporaFederation
|
|
152
153
|
# @return [Hash] sorted xml elements with updated signatures
|
153
154
|
def xml_elements
|
154
155
|
xml_data = super.merge(additional_xml_elements)
|
155
|
-
|
156
|
+
signature_order.map {|element| [element, xml_data[element]] }.to_h.tap do |xml_elements|
|
156
157
|
xml_elements[:author_signature] = author_signature || sign_with_author
|
157
158
|
xml_elements[:parent_author_signature] = parent_author_signature || sign_with_parent_author_if_available.to_s
|
158
159
|
end
|
@@ -197,19 +198,33 @@ module DiasporaFederation
|
|
197
198
|
end
|
198
199
|
end
|
199
200
|
|
201
|
+
fetch_parent(entity_data)
|
200
202
|
new(entity_data, xml_order, additional_xml_elements).tap(&:verify_signatures)
|
201
203
|
end
|
204
|
+
|
205
|
+
def fetch_parent(data)
|
206
|
+
type = data[:parent_type] || self::PARENT_TYPE
|
207
|
+
guid = data[:parent_guid]
|
208
|
+
|
209
|
+
data[:parent] = DiasporaFederation.callbacks.trigger(:fetch_related_entity, type, guid)
|
210
|
+
|
211
|
+
unless data[:parent]
|
212
|
+
# fetch and receive parent from remote, if not available locally
|
213
|
+
Federation::Fetcher.fetch_public(data[:author], type, guid)
|
214
|
+
data[:parent] = DiasporaFederation.callbacks.trigger(:fetch_related_entity, type, guid)
|
215
|
+
end
|
216
|
+
end
|
202
217
|
end
|
203
218
|
|
204
|
-
#
|
219
|
+
# Raised, if creating the author_signature failes, because the private key was not found
|
205
220
|
class AuthorPrivateKeyNotFound < RuntimeError
|
206
221
|
end
|
207
222
|
|
208
|
-
#
|
223
|
+
# Raised, if verify_signatures fails to verify signatures (no public key found)
|
209
224
|
class PublicKeyNotFound < RuntimeError
|
210
225
|
end
|
211
226
|
|
212
|
-
#
|
227
|
+
# Raised, if verify_signatures fails to verify signatures (signatures are wrong)
|
213
228
|
class SignatureVerificationFailed < RuntimeError
|
214
229
|
end
|
215
230
|
end
|
@@ -53,42 +53,51 @@ module DiasporaFederation
|
|
53
53
|
# @return [String] target author signature
|
54
54
|
property :target_author_signature, default: nil
|
55
55
|
|
56
|
+
# @!attribute [r] target
|
57
|
+
# target entity
|
58
|
+
# @return [RelatedEntity] target entity
|
59
|
+
entity :target, Entities::RelatedEntity
|
60
|
+
|
56
61
|
# use only {Retraction} for receive
|
57
62
|
# @return [Retraction] instance as normal retraction
|
58
63
|
def to_retraction
|
59
|
-
Retraction.new(author: author, target_guid: target_guid, target_type: target_type)
|
64
|
+
Retraction.new(author: author, target_guid: target_guid, target_type: target_type, target: target)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [String] string representation of this object
|
68
|
+
def to_s
|
69
|
+
"RelayableRetraction:#{target_type}:#{target_guid}"
|
60
70
|
end
|
61
71
|
|
62
72
|
private
|
63
73
|
|
64
74
|
# @param [Nokogiri::XML::Element] root_node xml nodes
|
65
75
|
# @return [Retraction] instance
|
66
|
-
def self.populate_entity(root_node)
|
67
|
-
|
76
|
+
private_class_method def self.populate_entity(root_node)
|
77
|
+
entity_data = entity_data(root_node)
|
78
|
+
entity_data[:target] = Retraction.send(:fetch_target, entity_data[:target_type], entity_data[:target_guid])
|
79
|
+
new(entity_data).to_retraction
|
68
80
|
end
|
69
|
-
private_class_method :populate_entity
|
70
81
|
|
71
82
|
# It updates also the signatures with the keys of the author and the parent
|
72
83
|
# if the signatures are not there yet and if the keys are available.
|
73
84
|
#
|
74
85
|
# @return [Hash] xml elements with updated signatures
|
75
86
|
def xml_elements
|
76
|
-
|
77
|
-
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, author)
|
87
|
+
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, author)
|
78
88
|
|
79
89
|
super.tap do |xml_elements|
|
80
|
-
fill_required_signature(
|
90
|
+
fill_required_signature(privkey, xml_elements) unless privkey.nil?
|
81
91
|
end
|
82
92
|
end
|
83
93
|
|
84
|
-
# @param [String] target_author the author of the entity to retract
|
85
94
|
# @param [OpenSSL::PKey::RSA] privkey private key of sender
|
86
95
|
# @param [Hash] hash hash given for a signing
|
87
|
-
def fill_required_signature(
|
88
|
-
if
|
89
|
-
hash[:target_author_signature] = SignedRetraction.sign_with_key(privkey, self)
|
90
|
-
elsif target_author != author && parent_author_signature.nil?
|
96
|
+
def fill_required_signature(privkey, hash)
|
97
|
+
if target.parent.author == author && parent_author_signature.nil?
|
91
98
|
hash[:parent_author_signature] = SignedRetraction.sign_with_key(privkey, self)
|
99
|
+
elsif target.author == author && target_author_signature.nil?
|
100
|
+
hash[:target_author_signature] = SignedRetraction.sign_with_key(privkey, self)
|
92
101
|
end
|
93
102
|
end
|
94
103
|
end
|
@@ -24,12 +24,16 @@ module DiasporaFederation
|
|
24
24
|
Contact.new(author: author, recipient: recipient)
|
25
25
|
end
|
26
26
|
|
27
|
+
# @return [String] string representation of this object
|
28
|
+
def to_s
|
29
|
+
"Request:#{author}:#{recipient}"
|
30
|
+
end
|
31
|
+
|
27
32
|
# @param [Nokogiri::XML::Element] root_node xml nodes
|
28
33
|
# @return [Retraction] instance
|
29
|
-
def self.populate_entity(root_node)
|
34
|
+
private_class_method def self.populate_entity(root_node)
|
30
35
|
super(root_node).to_contact
|
31
36
|
end
|
32
|
-
private_class_method :populate_entity
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -22,6 +22,11 @@ module DiasporaFederation
|
|
22
22
|
# has no meaning at the moment
|
23
23
|
# @return [Boolean] public
|
24
24
|
property :public, default: true # always true? (we only reshare public posts)
|
25
|
+
|
26
|
+
# @return [String] string representation of this object
|
27
|
+
def to_s
|
28
|
+
"#{super}:#{root_guid}"
|
29
|
+
end
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -19,6 +19,43 @@ module DiasporaFederation
|
|
19
19
|
# A string describing the type of the target.
|
20
20
|
# @return [String] target type
|
21
21
|
property :target_type, xml_name: :type
|
22
|
+
|
23
|
+
# @!attribute [r] target
|
24
|
+
# target entity
|
25
|
+
# @return [RelatedEntity] target entity
|
26
|
+
entity :target, Entities::RelatedEntity
|
27
|
+
|
28
|
+
def sender_valid?(sender)
|
29
|
+
case target_type
|
30
|
+
when "Comment", "Like", "PollParticipation"
|
31
|
+
sender == target.author || sender == target.parent.author
|
32
|
+
else
|
33
|
+
sender == target.author
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String] string representation of this object
|
38
|
+
def to_s
|
39
|
+
"Retraction:#{target_type}:#{target_guid}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [Nokogiri::XML::Element] root_node xml nodes
|
43
|
+
# @return [Retraction] instance
|
44
|
+
private_class_method def self.populate_entity(root_node)
|
45
|
+
entity_data = entity_data(root_node)
|
46
|
+
entity_data[:target] = fetch_target(entity_data[:target_type], entity_data[:target_guid])
|
47
|
+
new(entity_data)
|
48
|
+
end
|
49
|
+
|
50
|
+
private_class_method def self.fetch_target(target_type, target_guid)
|
51
|
+
DiasporaFederation.callbacks.trigger(:fetch_related_entity, target_type, target_guid).tap do |target|
|
52
|
+
raise TargetNotFound, "not found: #{target_type}:#{target_guid}" unless target
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Raised, if the target of the {Retraction} was not found.
|
57
|
+
class TargetNotFound < RuntimeError
|
58
|
+
end
|
22
59
|
end
|
23
60
|
end
|
24
61
|
end
|