]> git.mxchange.org Git - fba.git/blob - fba/networks/friendica.py
Continued:
[fba.git] / fba / networks / friendica.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 logging
18
19 import bs4
20 import validators
21
22 from fba import utils
23
24 from fba.helpers import config
25 from fba.helpers import tidyup
26
27 from fba.http import network
28
29 from fba.models import instances
30
31 logging.basicConfig(level=logging.INFO)
32 logger = logging.getLogger(__name__)
33
34 def fetch_blocks(domain: str) -> dict:
35     logger.debug("domain(%d)='%s' - CALLED!", len(domain), domain)
36     if not isinstance(domain, str):
37         raise ValueError(f"Parameter domain[]='{type(domain)}' is not 'str'")
38     elif domain == "":
39         raise ValueError("Parameter 'domain' is empty")
40     elif domain.lower() != domain:
41         raise ValueError(f"Parameter domain='{domain}' must be all lower-case")
42     elif not validators.domain(domain.split("/")[0]):
43         raise ValueError(f"domain='{domain}' is not a valid domain")
44     elif domain.endswith(".arpa"):
45         raise ValueError(f"domain='{domain}' is a domain for reversed IP addresses, please don't crawl them!")
46     elif domain.endswith(".tld"):
47         raise ValueError(f"domain='{domain}' is a fake domain, please don't crawl them!")
48
49     blocklist = list()
50     block_tag = None
51
52     try:
53         logger.debug("Fetching friendica blocks from domain:", domain)
54         doc = bs4.BeautifulSoup(
55             network.fetch_response(
56                 domain,
57                 "/friendica",
58                 network.web_headers,
59                 (config.get("connection_timeout"), config.get("read_timeout"))
60             ).text,
61             "html.parser",
62         )
63         logger.debug("doc[]='%s'", type(doc))
64
65         block_tag = doc.find(id="about_blocklist")
66     except network.exceptions as exception:
67         logger.warning(f"Exception '{type(exception)}' during fetching instances (friendica) from domain='{domain}'")
68         instances.set_last_error(domain, exception)
69         return dict()
70
71     # Prevents exceptions:
72     if block_tag is None:
73         logger.debug("Instance has no block list:", domain)
74         return dict()
75
76     table = block_tag.find("table")
77
78     logger.debug(f"table[]='{type(table)}'")
79     if table.find("tbody"):
80         rows = table.find("tbody").find_all("tr")
81     else:
82         rows = table.find_all("tr")
83
84     logger.debug(f"Found rows()={len(rows)}")
85     for line in rows:
86         logger.debug(f"line='{line}'")
87         blocked = tidyup.domain(line.find_all("td")[0].text)
88         reason  = tidyup.reason(line.find_all("td")[1].text)
89         logger.debug(f"blocked='{blocked}',reason='{reason}'")
90
91         if not utils.is_domain_wanted(blocked):
92             logger.debug("blocked='%s' is not wanted - SKIPPED!", blocked)
93             continue
94
95         logger.debug(f"Appending blocked='{blocked}',reason='{reason}'")
96         blocklist.append({
97             "domain": tidyup.domain(blocked),
98             "reason": tidyup.reason(reason)
99         })
100         logger.debug("Next!")
101
102     logger.debug("Returning blocklist() for domain:", domain, len(blocklist))
103     return {
104         "reject": blocklist
105     }