]> git.mxchange.org Git - fba.git/blob - fetch_blocks.py
Continued:
[fba.git] / fetch_blocks.py
1 import time
2 import bs4
3 import fba
4 import itertools
5 import re
6
7 fba.c.execute(
8     "SELECT domain, software FROM instances WHERE software IN ('pleroma', 'mastodon', 'friendica', 'misskey', 'gotosocial')"
9 )
10
11 for blocker, software in fba.c.fetchall():
12     print("DEBUG: blocker,software:", blocker, software)
13     blockdict = []
14     blocker = fba.tidyup(blocker)
15     if software == "pleroma":
16         print("DEBUG: blocker:", blocker)
17         try:
18             # Blocks
19             federation = reqto.get(
20                 f"https://{blocker}/nodeinfo/2.1.json", headers=headers, timeout=5
21             ).json()["metadata"]["federation"]
22             if "mrf_simple" in federation:
23                 for block_level, blocks in (
24                     {**federation["mrf_simple"],
25                     **{"quarantined_instances": federation["quarantined_instances"]}}
26                 ).items():
27                     for blocked in blocks:
28                         blocked = fba.tidyup(blocked)
29
30                         if blocked == "":
31                             print("WARNING: blocked is empty after fba.tidyup():", blocker, block_level)
32                             continue
33
34                         if blocked.count("*") > 1:
35                             # -ACK!-oma also started obscuring domains without hash
36                             fba.c.execute(
37                                 "SELECT domain FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", (blocked.replace("*", "_"),)
38                             )
39                             searchres = fba.c.fetchone()
40                             if searchres != None:
41                                 blocked = searchres[0]
42
43                         fba.c.execute(
44                             "SELECT domain FROM instances WHERE domain = ?", (blocked)
45                         )
46
47                         if fba.c.fetchone() == None:
48                             print("DEBUG: Hash wasn't found, adding:", blocked)
49                             fba.add_instance(blocked)
50
51                         timestamp = int(time.time())
52                         fba.c.execute(
53                             "SELECT * FROM blocks WHERE blocker = ? AND blocked = ? AND block_level = ?",
54                             (
55                                blocker,
56                                blocked,
57                                block_level
58                            ),
59                         )
60                         if fba.c.fetchone() == None:
61                             fba.block_instance(blocker, blocked, reason, block_level, timestamp, timestamp)
62
63                             if block_level == "reject":
64                                 blockdict.append(
65                                     {
66                                         "blocked": blocked,
67                                         "reason": None
68                                     })
69                         else:
70                             fba.update_last_seen(timestamp, blocker, blocked, block_level)
71
72             fba.conn.commit()
73             # Reasons
74             if "mrf_simple_info" in federation:
75                 for block_level, info in (
76                     {**federation["mrf_simple_info"],
77                     **(federation["quarantined_instances_info"]
78                     if "quarantined_instances_info" in federation
79                     else {})}
80                 ).items():
81                     for blocked, reason in info.items():
82                         blocked = fba.tidyup(blocked)
83
84                         if blocked == "":
85                             print("WARNING: blocked is empty after fba.tidyup():", blocker, block_level)
86                             continue
87
88                         if blocked.count("*") > 1:
89                             # same domain guess as above, but for reasons field
90                             fba.c.execute(
91                                 "SELECT domain FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", (blocked.replace("*", "_"),)
92                             )
93                             searchres = fba.c.fetchone()
94
95                             if searchres != None:
96                                 blocked = searchres[0]
97
98                         fba.update_block_reason(reason["reason"], blocker, blocked, block_level)
99
100                         for entry in blockdict:
101                             if entry["blocked"] == blocked:
102                                 entry["reason"] = reason["reason"]
103
104             fba.conn.commit()
105         except Exception as e:
106             print("error:", e, blocker, software)
107     elif software == "mastodon":
108         print("DEBUG: blocker:", blocker)
109         try:
110             # json endpoint for newer mastodongs
111             try:
112                 json = {
113                     "reject": [],
114                     "media_removal": [],
115                     "followers_only": [],
116                     "report_removal": []
117                 }
118
119                 # handling CSRF, I've saw at least one server requiring it to access the endpoint
120                 meta = bs4.BeautifulSoup(
121                     reqto.get(f"https://{blocker}/about", headers=headers, timeout=5).text,
122                     "html.parser",
123                 )
124                 try:
125                     csrf = meta.find("meta", attrs={"name": "csrf-token"})["content"]
126                     reqheaders = {**headers, **{"x-csrf-token": csrf}}
127                 except:
128                     reqheaders = headers
129
130                 blocks = reqto.get(
131                     f"https://{blocker}/api/v1/instance/domain_blocks", headers=reqheaders, timeout=5
132                 ).json()
133
134                 print("DEBUG: blocks():", len(blocks))
135                 for block in blocks:
136                     entry = {'domain': block['domain'], 'hash': block['digest'], 'reason': block['comment']}
137
138                     print("DEBUG: severity,domain,hash,comment:", block['severity'], block['domain'], block['digest'], block['comment'])
139                     if block['severity'] == 'suspend':
140                         json['reject'].append(entry)
141                     elif block['severity'] == 'silence':
142                         json['followers_only'].append(entry)
143                     elif block['severity'] == 'reject_media':
144                         json['media_removal'].append(entry)
145                     elif block['severity'] == 'reject_reports':
146                         json['report_removal'].append(entry)
147                     else:
148                         print("WARNING: Unknown severity:", block['severity'], block['domain'])
149             except:
150                 json = fba.get_mastodon_blocks(blocker)
151
152             for block_level, blocks in json.items():
153                 for instance in blocks:
154                     blocked, blocked_hash, reason = instance.values()
155                     print("DEBUG: blocked,hash,reason:", blocked, blocked_hash, reason)
156
157                     blocked = fba.tidyup(blocked)
158                     print("DEBUG: blocked:", blocked)
159
160                     if blocked.count("*") < 1:
161                         # No obsfucation for this instance
162                         fba.c.execute(
163                             "SELECT hash FROM instances WHERE domain = ? LIMIT 1", (blocked,)
164                         )
165
166                         if fba.c.fetchone() == None:
167                             print("DEBUG: Hash wasn't found, adding:", blocked)
168                             fba.add_instance(blocked)
169                     else:
170                         # Doing the hash search for instance names as well to tidy up DB
171                         fba.c.execute(
172                             "SELECT domain FROM instances WHERE hash = ? LIMIT 1", (blocked_hash,)
173                         )
174                         searchres = fba.c.fetchone()
175
176                         if searchres != None:
177                             print("DEBUG: Updating domain: ", searchres[0])
178                             blocked = searchres[0]
179
180                     timestamp = int(time.time())
181                     fba.c.execute(
182                         "SELECT * FROM blocks WHERE blocker = ? AND blocked = ? AND block_level = ?",
183                         (
184                             blocker,
185                             blocked if blocked.count("*") <= 1 else blocked_hash,
186                             block_level
187                         ),
188                     )
189
190                     if fba.c.fetchone() == None:
191                         fba.block_instance(blocker, blocked if blocked.count("*") <= 1 else blocked_hash, reason, block_level, timestamp, timestamp)
192
193                         if block_level == "reject":
194                             blockdict.append(
195                                 {
196                                     "blocked": blocked,
197                                     "reason": reason
198                                 })
199                     else:
200                         fba.update_last_seen(timestamp, blocker, blocked if blocked.count("*") <= 1 else blocked_hash, block_level)
201
202                     if reason != '':
203                         fba.update_block_reason(reason, blocker, blocked if blocked.count("*") <= 1 else blocked_hash, block_level)
204
205             fba.conn.commit()
206         except Exception as e:
207             print("error:", e, blocker, software)
208     elif software == "friendica" or software == "misskey":
209         print("DEBUG: blocker:", blocker)
210         try:
211             if software == "friendica":
212                 json = fba.get_friendica_blocks(blocker)
213             elif software == "misskey":
214                 json = fba.get_misskey_blocks(blocker)
215             for block_level, blocks in json.items():
216                 for instance in blocks:
217                     blocked, reason = instance.values()
218                     blocked = fba.tidyup(blocked)
219
220                     print("BEFORE-blocked:", blocked)
221                     if blocked.count("*") > 0:
222                         # Some friendica servers also obscure domains without hash
223                         fba.c.execute(
224                             "SELECT domain FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", (blocked.replace("*", "_"),)
225                         )
226                         searchres = fba.c.fetchone()
227                         if searchres != None:
228                             blocked = searchres[0]
229
230                     if blocked.count("?") > 0:
231                         # Some obscure them with question marks, not sure if that's dependent on version or not
232                         fba.c.execute(
233                             "SELECT domain FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", (blocked.replace("?", "_"),)
234                         )
235                         searchres = fba.c.fetchone()
236                         if searchres != None:
237                             blocked = searchres[0]
238
239                     print("AFTER-blocked:", blocked)
240                     fba.c.execute(
241                         "SELECT domain FROM instances WHERE domain = ?", (blocked,)
242                     )
243
244                     if fba.c.fetchone() == None:
245                         print("DEBUG: Hash wasn't found, adding:", blocked)
246                         fba.add_instance(blocked)
247
248                     timestamp = int(time.time())
249                     fba.c.execute(
250                         "SELECT * FROM blocks WHERE blocker = ? AND blocked = ?",
251                         (blocker, blocked),
252                     )
253                     if fba.c.fetchone() == None:
254                         fba.block_instance(blocker, blocked, reason, block_level, timestamp, timestamp)
255
256                         if block_level == "reject":
257                             blockdict.append(
258                                 {
259                                     "blocked": blocked,
260                                     "reason": reason
261                                 })
262                     else:
263                         fba.update_last_seen(timestamp, blocker, blocked, block_level)
264
265                     if reason != '':
266                         fba.update_block_reason(reason, blocker, blocked, block_level)
267
268             fba.conn.commit()
269         except Exception as e:
270             print("error:", e, blocker, software)
271     elif software == "gotosocial":
272         print("DEBUG: blocker:", blocker)
273         try:
274             # Blocks
275             federation = reqto.get(
276                 f"https://{blocker}/api/v1/instance/peers?filter=suspended", headers=headers, timeout=5
277             ).json()
278
279             if (federation == None):
280                 print("WARNING: No valid response:", blocker);
281             else:
282                 for peer in federation:
283                     blocked = peer["domain"].lower()
284
285                     if blocked.count("*") > 0:
286                         # GTS does not have hashes for obscured domains, so we have to guess it
287                         fba.c.execute(
288                             "SELECT domain FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", (blocked.replace("*", "_"),)
289                         )
290                         searchres = fba.c.fetchone()
291
292                         if searchres != None:
293                             blocked = searchres[0]
294
295                     fba.c.execute(
296                         "SELECT domain FROM instances WHERE domain = ?", (blocked,)
297                     )
298
299                     if fba.c.fetchone() == None:
300                         print("DEBUG: Hash wasn't found, adding:", blocked)
301                         fba.add_instance(blocked)
302
303                     fba.c.execute(
304                         "SELECT * FROM blocks WHERE blocker = ? AND blocked = ? AND block_level = ?",
305                         (
306                             blocker,
307                             blocked,
308                             "reject"
309                         ),
310                     )
311                     timestamp = int(time.time())
312
313                     if fba.c.fetchone() == None:
314                         fba.block_instance(blocker, blocked, "", "reject", timestamp, timestamp)
315
316                         blockdict.append(
317                             {
318                                 "blocked": blocked,
319                                 "reason": None
320                             })
321                     else:
322                         fba.update_last_seen(timestamp, blocker, blocked, "reject")
323
324                     if "public_comment" in peer:
325                         reason = peer["public_comment"]
326                         fba.update_block_reason(reason, blocker, blocked, "reject")
327
328                         for entry in blockdict:
329                             if entry["blocked"] == blocked:
330                                 entry["reason"] = reason
331                 fba.conn.commit()
332         except Exception as e:
333             print("error:", e, blocker, software)
334     else:
335         print("WARNING: Unknown software:", software)
336
337     if fba.config["bot_enabled"] and len(blockdict) > 0:
338         send_bot_post(blocker, blockdict)
339
340     blockdict = []
341
342 fba.conn.close()