-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
acceptreject.py
249 lines (228 loc) · 9.4 KB
/
acceptreject.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
""" ActivityPub Accept or Reject json """
__filename__ = "acceptreject.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.5.0"
__maintainer__ = "Bob Mottram"
__email__ = "[email protected]"
__status__ = "Production"
__module_group__ = "ActivityPub"
import os
from flags import has_group_type
from flags import url_permitted
from utils import get_user_paths
from utils import text_in_file
from utils import has_object_string_object
from utils import has_users_path
from utils import get_full_domain
from utils import get_domain_from_actor
from utils import get_nickname_from_actor
from utils import domain_permitted
from utils import follow_person
from utils import acct_dir
from utils import local_actor_url
from utils import has_actor
from utils import has_object_string_type
from utils import get_actor_from_post
def _create_accept_reject(federation_list: [],
nickname: str, domain: str, port: int,
to_url: str, cc_url: str, http_prefix: str,
object_json: {}, accept_type: str) -> {}:
"""Accepts or rejects something (eg. a follow request or offer)
Typically to_url will be https://www.w3.org/ns/activitystreams#Public
and cc_url might be a specific person favorited or repeated and
the followers url objectUrl is typically the url of the message,
corresponding to url or atomUri in createPostBase
"""
if not object_json.get('actor'):
return None
actor_url = get_actor_from_post(object_json)
if not url_permitted(actor_url, federation_list):
return None
domain = get_full_domain(domain, port)
new_accept = {
"@context": [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1'
],
'type': accept_type,
'actor': local_actor_url(http_prefix, nickname, domain),
'to': [to_url],
'cc': [],
'object': object_json
}
if cc_url:
if len(cc_url) > 0:
new_accept['cc'] = [cc_url]
return new_accept
def create_accept(federation_list: [],
nickname: str, domain: str, port: int,
to_url: str, cc_url: str, http_prefix: str,
object_json: {}) -> {}:
""" Create json for ActivityPub Accept """
return _create_accept_reject(federation_list,
nickname, domain, port,
to_url, cc_url, http_prefix,
object_json, 'Accept')
def create_reject(federation_list: [],
nickname: str, domain: str, port: int,
to_url: str, cc_url: str, http_prefix: str,
object_json: {}) -> {}:
""" Create json for ActivityPub Reject """
return _create_accept_reject(federation_list,
nickname, domain, port,
to_url, cc_url,
http_prefix, object_json, 'Reject')
def _accept_follow(base_dir: str, message_json: {},
federation_list: [], debug: bool,
curr_domain: str,
onion_domain: str, i2p_domain: str) -> None:
""" Receiving an ActivityPub follow Accept activity
"""
if not has_object_string_type(message_json, debug):
return
if message_json['object']['type'] not in ('Follow', 'Join'):
return
if debug:
print('DEBUG: receiving Follow activity')
if not message_json['object'].get('actor'):
print('DEBUG: no actor in Follow activity')
return
# no, this isn't a mistake
if not has_object_string_object(message_json, debug):
return
if not message_json.get('to'):
if debug:
print('DEBUG: No "to" parameter in follow Accept')
return
if debug:
print('DEBUG: follow Accept received ' + str(message_json))
this_actor = get_actor_from_post(message_json['object'])
nickname = get_nickname_from_actor(this_actor)
if not nickname:
print('WARN: no nickname found in ' + this_actor)
return
accepted_domain, accepted_port = get_domain_from_actor(this_actor)
if not accepted_domain:
if debug:
print('DEBUG: domain not found in ' + this_actor)
return
if not nickname:
if debug:
print('DEBUG: nickname not found in ' + this_actor)
return
if accepted_port:
if '/' + accepted_domain + ':' + str(accepted_port) + \
'/users/' + nickname not in this_actor:
if debug:
print('Port: ' + str(accepted_port))
print('Expected: /' + accepted_domain + ':' +
str(accepted_port) + '/users/' + nickname)
print('Actual: ' + this_actor)
print('DEBUG: unrecognized actor ' + this_actor)
return
else:
actor_found = False
users_list = get_user_paths()
for users_str in users_list:
if '/' + accepted_domain + users_str + nickname in this_actor:
actor_found = True
break
if not actor_found:
if debug:
print('Expected: /' + accepted_domain + '/users/' + nickname)
print('Actual: ' + this_actor)
print('DEBUG: unrecognized actor ' + this_actor)
return
followed_actor = message_json['object']['object']
followed_domain, port = get_domain_from_actor(followed_actor)
if not followed_domain:
print('DEBUG: no domain found within Follow activity object ' +
followed_actor)
return
followed_domain_full = followed_domain
if port:
followed_domain_full = followed_domain + ':' + str(port)
followed_nickname = get_nickname_from_actor(followed_actor)
if not followed_nickname:
print('DEBUG: no nickname found within Follow activity object ' +
followed_actor)
return
# convert from onion/i2p to clearnet accepted domain
if onion_domain:
if accepted_domain.endswith('.onion') and \
not curr_domain.endswith('.onion'):
accepted_domain = curr_domain
if i2p_domain:
if accepted_domain.endswith('.i2p') and \
not curr_domain.endswith('.i2p'):
accepted_domain = curr_domain
accepted_domain_full = accepted_domain
if accepted_port:
accepted_domain_full = accepted_domain + ':' + str(accepted_port)
# has this person already been unfollowed?
unfollowed_filename = \
acct_dir(base_dir, nickname, accepted_domain_full) + '/unfollowed.txt'
if os.path.isfile(unfollowed_filename):
if text_in_file(followed_nickname + '@' + followed_domain_full,
unfollowed_filename):
if debug:
print('DEBUG: follow accept arrived for ' +
nickname + '@' + accepted_domain_full +
' from ' +
followed_nickname + '@' + followed_domain_full +
' but they have been unfollowed')
return
# does the url path indicate that this is a group actor
group_account = has_group_type(base_dir, followed_actor, None, debug)
if debug:
print('Accepted follow is a group: ' + str(group_account) +
' ' + followed_actor + ' ' + base_dir)
if follow_person(base_dir,
nickname, accepted_domain_full,
followed_nickname, followed_domain_full,
federation_list, debug, group_account,
'following.txt'):
if debug:
print('DEBUG: ' + nickname + '@' + accepted_domain_full +
' followed ' +
followed_nickname + '@' + followed_domain_full)
else:
if debug:
print('DEBUG: Unable to create follow - ' +
nickname + '@' + accepted_domain + ' -> ' +
followed_nickname + '@' + followed_domain)
def receive_accept_reject(base_dir: str, domain: str, message_json: {},
federation_list: [], debug: bool, curr_domain: str,
onion_domain: str, i2p_domain: str) -> bool:
"""Receives an Accept or Reject within the POST section of HTTPServer
"""
if message_json['type'] not in ('Accept', 'Reject'):
return False
if not has_actor(message_json, debug):
return False
actor_url = get_actor_from_post(message_json)
if not has_users_path(actor_url):
if debug:
print('DEBUG: "users" or "profile" missing from actor in ' +
message_json['type'] + '. Assuming single user instance.')
domain, _ = get_domain_from_actor(actor_url)
if not domain_permitted(domain, federation_list):
if debug:
print('DEBUG: ' + message_json['type'] +
' from domain not permitted - ' + domain)
return False
nickname = get_nickname_from_actor(actor_url)
if not nickname:
# single user instance
nickname = 'dev'
if debug:
print('DEBUG: ' + message_json['type'] +
' does not contain a nickname. ' +
'Assuming single user instance.')
# receive follow accept
_accept_follow(base_dir, message_json, federation_list, debug,
curr_domain, onion_domain, i2p_domain)
if debug:
print('DEBUG: Uh, ' + message_json['type'] + ', I guess')
return True