]> git.mxchange.org Git - fba.git/blob - fba/networks/pleroma.py
86f69cdee9cd47809de2801908d7f9cfd55856d1
[fba.git] / fba / networks / pleroma.py
1 # Fedi API Block - An aggregator for fetching blocking data from fediverse nodes
2 # Copyright (C) 2023 Free Software Foundation
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published
6 # by the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17 import inspect
18 import validators
19
20 from fba import blacklist
21 from fba import blocks
22 from fba import fba
23 from fba import federation
24 from fba import instances
25 from fba.helpers import tidyup
26
27 def fetch_blocks(domain: str, origin: str, nodeinfo_url: str):
28     # DEBUG: print(f"DEBUG: domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}' - CALLED!")
29     if not isinstance(domain, str):
30         raise ValueError(f"Parameter domain[]={type(domain)} is not 'str'")
31     elif domain == "":
32         raise ValueError("Parameter 'domain' is empty")
33     elif not isinstance(origin, str) and origin is not None:
34         raise ValueError(f"Parameter origin[]={type(origin)} is not 'str'")
35     elif origin == "":
36         raise ValueError("Parameter 'origin' is empty")
37     elif not isinstance(nodeinfo_url, str):
38         raise ValueError(f"Parameter nodeinfo_url[]={type(nodeinfo_url)} is not 'str'")
39     elif nodeinfo_url == "":
40         raise ValueError("Parameter 'nodeinfo_url' is empty")
41
42     try:
43         # Blocks
44         blockdict = list()
45         rows = federation.fetch_nodeinfo(domain, nodeinfo_url)
46
47         if rows is None:
48             print("WARNING: Could not fetch nodeinfo from domain:", domain)
49             return
50         elif "metadata" not in rows:
51             print(f"WARNING: rows()={len(rows)} does not have key 'metadata', domain='{domain}'")
52             return
53         elif "federation" not in rows["metadata"]:
54             print(f"WARNING: rows()={len(rows['metadata'])} does not have key 'federation', domain='{domain}'")
55             return
56
57         # DEBUG: print("DEBUG: Updating nodeinfo:", domain)
58         instances.update_last_nodeinfo(domain)
59
60         data = rows["metadata"]["federation"]
61
62         if "enabled" in data:
63             # DEBUG: print("DEBUG: Instance has no block list to analyze:", domain)
64             return
65
66         if "mrf_simple" in data:
67             for block_level, blocklist in (
68                 {**data["mrf_simple"],
69                 **{"quarantined_instances": data["quarantined_instances"]}}
70             ).items():
71                 # DEBUG: print("DEBUG: block_level, blocklist():", block_level, len(blocklist))
72                 block_level = tidyup.domain(block_level)
73                 # DEBUG: print("DEBUG: BEFORE block_level:", block_level)
74
75                 if block_level == "":
76                     print("WARNING: block_level is now empty!")
77                     continue
78
79                 # DEBUG: print(f"DEBUG: Checking {len(blocklist)} entries from domain='{domain}',block_level='{block_level}' ...")
80                 for blocked in blocklist:
81                     # DEBUG: print("DEBUG: BEFORE blocked:", blocked)
82                     blocked = tidyup.domain(blocked)
83                     # DEBUG: print("DEBUG: AFTER blocked:", blocked)
84
85                     if blocked == "":
86                         print("WARNING: blocked is empty after tidyup.domain():", domain, block_level)
87                         continue
88                     elif blacklist.is_blacklisted(blocked):
89                         # DEBUG: print(f"DEBUG: blocked='{blocked}' is blacklisted - skipping!")
90                         continue
91                     elif blocked.count("*") > 1:
92                         # -ACK!-oma also started obscuring domains without hash
93                         fba.cursor.execute(
94                             "SELECT domain, nodeinfo_url FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", [blocked.replace("*", "_")]
95                         )
96                         searchres = fba.cursor.fetchone()
97
98                         print(f"DEBUG: searchres[]='{type(searchres)}'")
99                         if searchres is None:
100                             print(f"WARNING: Cannot deobsfucate blocked='{blocked}' - SKIPPED!")
101                             continue
102
103                         blocked = searchres[0]
104                         nodeinfo_url = searchres[1]
105                         # DEBUG: print("DEBUG: Looked up domain:", blocked)
106                     elif not validators.domain(blocked):
107                         print(f"WARNING: blocked='{blocked}',software='pleroma' is not a valid domain name - skipped!")
108                         continue
109
110                     # DEBUG: print("DEBUG: Looking up instance by domain:", blocked)
111                     if not validators.domain(blocked):
112                         print(f"WARNING: blocked='{blocked}',software='pleroma' is not a valid domain name - skipped!")
113                         continue
114                     elif not instances.is_registered(blocked):
115                         # DEBUG: print(f"DEBUG: Domain blocked='{blocked}' wasn't found, adding ..., domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}'")
116                         instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
117
118                     if not blocks.is_instance_blocked(domain, blocked, block_level):
119                         # DEBUG: print("DEBUG: Blocking:", domain, blocked, block_level)
120                         blocks.add_instance(domain, blocked, "unknown", block_level)
121
122                         if block_level == "reject":
123                             # DEBUG: print("DEBUG: Adding to blockdict:", blocked)
124                             blockdict.append(
125                                 {
126                                     "blocked": blocked,
127                                     "reason" : None
128                                 })
129                     else:
130                         # DEBUG: print(f"DEBUG: Updating block last seen for domain='{domain}',blocked='{blocked}' ...")
131                         blocks.update_last_seen(domain, blocked, block_level)
132
133         # DEBUG: print("DEBUG: Committing changes ...")
134         fba.connection.commit()
135
136         # Reasons
137         if "mrf_simple_info" in data:
138             # DEBUG: print("DEBUG: Found mrf_simple_info:", domain)
139             for block_level, info in (
140                 {**data["mrf_simple_info"],
141                 **(data["quarantined_instances_info"]
142                 if "quarantined_instances_info" in data
143                 else {})}
144             ).items():
145                 # DEBUG: print("DEBUG: block_level, info.items():", block_level, len(info.items()))
146                 block_level = tidyup.domain(block_level)
147                 # DEBUG: print("DEBUG: BEFORE block_level:", block_level)
148
149                 if block_level == "":
150                     print("WARNING: block_level is now empty!")
151                     continue
152
153                 # DEBUG: print(f"DEBUG: Checking {len(info.items())} entries from domain='{domain}',software='pleroma',block_level='{block_level}' ...")
154                 for blocked, reason in info.items():
155                     # DEBUG: print(f"DEBUG: blocked='{blocked}',reason='{reason}' - BEFORE!")
156                     blocked = tidyup.domain(blocked)
157                     reason  = tidyup.reason(reason) if reason is not None and reason != "" else None
158                     # DEBUG: print(f"DEBUG: blocked='{blocked}',reason='{reason}' - AFTER!")
159
160                     if blocked == "":
161                         print("WARNING: blocked is empty after tidyup.domain():", domain, block_level)
162                         continue
163                     elif not validators.domain(blocked):
164                         print(f"WARNING: blocked='{blocked}',software='pleroma' is not a valid domain name - skipped!")
165                         continue
166                     elif blacklist.is_blacklisted(blocked):
167                         # DEBUG: print(f"DEBUG: blocked='{blocked}' is blacklisted - skipping!")
168                         continue
169                     elif blocked.count("*") > 1:
170                         # same domain guess as above, but for reasons field
171                         fba.cursor.execute(
172                             "SELECT domain, origin, nodeinfo_url FROM instances WHERE domain LIKE ? ORDER BY rowid LIMIT 1", [blocked.replace("*", "_")]
173                         )
174                         searchres = fba.cursor.fetchone()
175
176                         print(f"DEBUG: searchres[]='{type(searchres)}'")
177                         if searchres is None:
178                             print(f"WARNING: Cannot deobsfucate blocked='{blocked}' - SKIPPED!")
179                             continue
180
181                         blocked = searchres[0]
182                         origin = searchres[1]
183                         nodeinfo_url = searchres[2]
184
185                     # DEBUG: print("DEBUG: Looking up instance by domain:", blocked)
186                     if not instances.is_registered(blocked):
187                         # DEBUG: print(f"DEBUG: Domain blocked='{blocked}' wasn't found, adding ..., domain='{domain}',origin='{origin}',nodeinfo_url='{nodeinfo_url}'")
188                         instances.add(blocked, domain, inspect.currentframe().f_code.co_name, nodeinfo_url)
189
190                     # DEBUG: print("DEBUG: Updating block reason:", domain, blocked, reason["reason"])
191                     blocks.update_reason(reason["reason"], domain, blocked, block_level)
192
193                     # DEBUG: print(f"DEBUG: blockdict()={len(blockdict)}")
194                     for entry in blockdict:
195                         if entry["blocked"] == blocked:
196                             # DEBUG: print("DEBUG: Updating entry reason:", blocked)
197                             entry["reason"] = reason["reason"]
198
199         fba.connection.commit()
200     except BaseException as exception:
201         print(f"ERROR: domain='{domain}',software='pleroma',exception[{type(exception)}]:'{str(exception)}'")
202
203     # DEBUG: print("DEBUG: EXIT!")