epicyon/daemon_get_nodeinfo.py

161 lines
6.1 KiB
Python

__filename__ = "daemon_get_nodeinfo.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.5.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Core GET"
import json
from httpcodes import http_400
from httpcodes import http_404
from httpcodes import http_503
from httpcodes import write2
from httpheaders import set_headers
from utils import convert_domains
from utils import get_instance_url
from utils import local_network_host
from siteactive import referer_is_active
from crawlers import update_known_crawlers
from blocking import broch_mode_is_active
from metadata import meta_data_node_info
def get_nodeinfo(self, ua_str: str, calling_domain: str,
referer_domain: str,
http_prefix: str, calling_site_timeout: int,
debug: bool, base_dir: str,
unit_test: bool,
domain_full: str,
path: str,
allow_local_network_access: bool,
sites_unavailable: [],
known_crawlers: [],
onion_domain: str,
i2p_domain: str,
project_version: str,
show_node_info_version: bool,
show_node_info_accounts: bool,
registration: bool, domain: str,
instance_description_short: str,
instance_description: str) -> bool:
"""Supports nodeinfo version 2.x
"""
if path.startswith('/nodeinfo/1.0'):
http_400(self)
return True
if not path.startswith('/nodeinfo/2.') and \
not path.startswith('/.well-known/host-meta') and \
not path.startswith('/.well-known/nodeinfo') and \
not path.startswith('/.well-known/x-nodeinfo'):
return False
if not referer_domain:
if not debug and not unit_test:
print('nodeinfo request has no referer domain ' + str(ua_str))
http_400(self)
return True
if referer_domain == domain_full:
print('nodeinfo request from self')
http_400(self)
return True
if self.server.nodeinfo_is_active:
if not referer_domain:
print('nodeinfo is busy during request without referer domain')
else:
print('nodeinfo is busy during request from ' + referer_domain)
http_503(self)
return True
self.server.nodeinfo_is_active = True
# is this a real website making the call ?
if not debug and not unit_test and referer_domain:
# Does calling_domain look like a domain?
if ' ' in referer_domain or \
';' in referer_domain or \
'.' not in referer_domain:
print('nodeinfo referer domain does not look like a domain ' +
referer_domain)
http_400(self)
self.server.nodeinfo_is_active = False
return True
if not allow_local_network_access:
if local_network_host(referer_domain):
print('nodeinfo referer domain is from the ' +
'local network ' + referer_domain)
http_400(self)
self.server.nodeinfo_is_active = False
return True
if not referer_is_active(http_prefix,
referer_domain, ua_str,
calling_site_timeout,
sites_unavailable):
print('nodeinfo referer url is not active ' +
referer_domain)
http_400(self)
self.server.nodeinfo_is_active = False
return True
if debug:
print('DEBUG: nodeinfo ' + path)
crawl_time = \
update_known_crawlers(ua_str,
base_dir,
known_crawlers,
self.server.last_known_crawler)
if crawl_time is not None:
self.server.last_known_crawler = crawl_time
# If we are in broch mode then don't show potentially
# sensitive metadata.
# For example, if this or allied instances are being attacked
# then numbers of accounts may be changing as people
# migrate, and that information may be useful to an adversary
broch_mode = broch_mode_is_active(base_dir)
node_info_version = project_version
if not show_node_info_version or broch_mode:
node_info_version = '0.0.0'
if broch_mode:
show_node_info_accounts = False
instance_url = get_instance_url(calling_domain,
http_prefix,
domain_full,
onion_domain,
i2p_domain)
about_url = instance_url + '/about'
terms_of_service_url = instance_url + '/terms'
info = meta_data_node_info(base_dir,
about_url, terms_of_service_url,
registration,
node_info_version,
show_node_info_accounts,
domain,
instance_description_short,
instance_description)
if info:
msg_str = json.dumps(info)
msg_str = convert_domains(calling_domain, referer_domain,
msg_str, http_prefix,
domain,
onion_domain,
i2p_domain)
msg = msg_str.encode('utf-8')
msglen = len(msg)
protocol_str = \
'application/json; profile=' + \
'"http://nodeinfo.diaspora.software/ns/schema/2.1#"'
set_headers(self, protocol_str, msglen,
None, calling_domain, True)
write2(self, msg)
if referer_domain:
print('nodeinfo sent to ' + referer_domain)
else:
print('nodeinfo sent to unknown referer')
self.server.nodeinfo_is_active = False
return True
http_404(self, 5)
self.server.nodeinfo_is_active = False
return True