Begin support for ipfs

merge-requests/30/head
Bob Mottram 2022-04-29 14:54:13 +01:00
parent f1d9f75095
commit 05efb23a51
17 changed files with 135 additions and 34 deletions

View File

@ -234,7 +234,9 @@ def dangerous_css(filename: str, allow_local_network_access: bool) -> bool:
if ctr > 0: if ctr > 0:
if ')' in url_str: if ')' in url_str:
url_str = url_str.split(')')[0] url_str = url_str.split(')')[0]
if 'http' in url_str: if 'http' in url_str or \
'ipfs' in url_str or \
'ipns' in url_str:
print('ERROR: non-local web link in CSS ' + print('ERROR: non-local web link in CSS ' +
filename) filename)
return True return True
@ -1114,6 +1116,8 @@ def get_mentions_from_html(html_text: str, match_str: str) -> []:
if actor_str.startswith('http') or \ if actor_str.startswith('http') or \
actor_str.startswith('gnunet') or \ actor_str.startswith('gnunet') or \
actor_str.startswith('i2p') or \ actor_str.startswith('i2p') or \
actor_str.startswith('ipfs') or \
actor_str.startswith('ipns') or \
actor_str.startswith('hyper') or \ actor_str.startswith('hyper') or \
actor_str.startswith('dat:'): actor_str.startswith('dat:'):
if actor_str not in mentions: if actor_str not in mentions:

View File

@ -2219,7 +2219,9 @@ class PubServer(BaseHTTPRequestHandler):
else: else:
search_handle = '' search_handle = ''
if '@' not in search_handle: if '@' not in search_handle:
if search_handle.startswith('http'): if search_handle.startswith('http') or \
search_handle.startswith('ipfs') or \
search_handle.startswith('ipns'):
search_nickname = \ search_nickname = \
get_nickname_from_actor(search_handle) get_nickname_from_actor(search_handle)
if search_nickname: if search_nickname:
@ -2286,6 +2288,8 @@ class PubServer(BaseHTTPRequestHandler):
print('moderation_text: ' + moderation_text) print('moderation_text: ' + moderation_text)
nickname = moderation_text nickname = moderation_text
if nickname.startswith('http') or \ if nickname.startswith('http') or \
nickname.startswith('ipfs') or \
nickname.startswith('ipns') or \
nickname.startswith('hyper'): nickname.startswith('hyper'):
nickname = get_nickname_from_actor(nickname) nickname = get_nickname_from_actor(nickname)
if '@' in nickname: if '@' in nickname:
@ -2301,6 +2305,8 @@ class PubServer(BaseHTTPRequestHandler):
if moderation_button == 'block': if moderation_button == 'block':
full_block_domain = None full_block_domain = None
if moderation_text.startswith('http') or \ if moderation_text.startswith('http') or \
moderation_text.startswith('ipfs') or \
moderation_text.startswith('ipns') or \
moderation_text.startswith('hyper'): moderation_text.startswith('hyper'):
# https://domain # https://domain
block_domain, block_port = \ block_domain, block_port = \
@ -2320,6 +2326,8 @@ class PubServer(BaseHTTPRequestHandler):
if moderation_button == 'unblock': if moderation_button == 'unblock':
full_block_domain = None full_block_domain = None
if moderation_text.startswith('http') or \ if moderation_text.startswith('http') or \
moderation_text.startswith('ipfs') or \
moderation_text.startswith('ipns') or \
moderation_text.startswith('hyper'): moderation_text.startswith('hyper'):
# https://domain # https://domain
block_domain, block_port = \ block_domain, block_port = \

View File

@ -882,9 +882,12 @@ def _desktop_show_profile(session, nickname: str, domain: str,
is_http = False is_http = False
if 'http://' in actor: if 'http://' in actor:
is_http = True is_http = True
is_gnunet = False
is_ipfs = False
is_ipns = False
actor_json, _ = \ actor_json, _ = \
get_actor_json(domain, actor, is_http, False, False, True, get_actor_json(domain, actor, is_http, is_gnunet, is_ipfs, is_ipns,
signing_priv_key_pem, session) False, True, signing_priv_key_pem, session)
_desktop_show_actor(base_dir, actor_json, translate, _desktop_show_actor(base_dir, actor_json, translate,
system_language, screenreader, espeak) system_language, screenreader, espeak)
@ -904,7 +907,8 @@ def _desktop_show_profile_from_handle(session, nickname: str, domain: str,
Returns the actor json Returns the actor json
""" """
actor_json, _ = \ actor_json, _ = \
get_actor_json(domain, handle, False, False, False, True, get_actor_json(domain, handle, False, False, False, False,
False, True,
signing_priv_key_pem, session) signing_priv_key_pem, session)
_desktop_show_actor(base_dir, actor_json, translate, _desktop_show_actor(base_dir, actor_json, translate,

View File

@ -503,6 +503,12 @@ parser.add_argument("--http", type=str2bool, nargs='?',
parser.add_argument("--gnunet", type=str2bool, nargs='?', parser.add_argument("--gnunet", type=str2bool, nargs='?',
const=True, default=False, const=True, default=False,
help="Use gnunet protocol only") help="Use gnunet protocol only")
parser.add_argument("--ipfs", type=str2bool, nargs='?',
const=True, default=False,
help="Use ipfs protocol only")
parser.add_argument("--ipns", type=str2bool, nargs='?',
const=True, default=False,
help="Use ipns protocol only")
parser.add_argument("--dat", type=str2bool, nargs='?', parser.add_argument("--dat", type=str2bool, nargs='?',
const=True, default=False, const=True, default=False,
help="Use dat protocol only") help="Use dat protocol only")
@ -736,6 +742,10 @@ if args.testsnetwork:
http_prefix = 'https' http_prefix = 'https'
if args.http or args.i2p: if args.http or args.i2p:
http_prefix = 'http' http_prefix = 'http'
elif args.ipfs:
http_prefix = 'ipfs'
elif args.ipns:
http_prefix = 'ipns'
elif args.gnunet: elif args.gnunet:
http_prefix = 'gnunet' http_prefix = 'gnunet'
@ -2282,6 +2292,10 @@ if args.gnunet:
http_prefix = 'gnunet' http_prefix = 'gnunet'
if args.dat or args.hyper: if args.dat or args.hyper:
http_prefix = 'hyper' http_prefix = 'hyper'
if args.ipfs:
http_prefix = 'ipfs'
if args.ipns:
http_prefix = 'ipns'
if args.i2p: if args.i2p:
http_prefix = 'http' http_prefix = 'http'
@ -2295,6 +2309,14 @@ if args.migrations:
http_prefix = 'http' http_prefix = 'http'
port = 80 port = 80
proxy_type = 'i2p' proxy_type = 'i2p'
elif args.ipfs:
http_prefix = 'ipfs'
port = 80
proxy_type = 'ipfs'
elif args.ipns:
http_prefix = 'ipns'
port = 80
proxy_type = 'ipfs'
elif args.gnunet: elif args.gnunet:
http_prefix = 'gnunet' http_prefix = 'gnunet'
port = 80 port = 80
@ -2328,6 +2350,7 @@ if args.actor:
else: else:
print('Did not obtain instance actor key for ' + domain) print('Did not obtain instance actor key for ' + domain)
get_actor_json(domain, args.actor, args.http, args.gnunet, get_actor_json(domain, args.actor, args.http, args.gnunet,
args.ipfs, args.ipns,
debug, False, signing_priv_key_pem, None) debug, False, signing_priv_key_pem, None)
sys.exit() sys.exit()
@ -2336,6 +2359,8 @@ if args.followers:
if '/@' in args.followers or \ if '/@' in args.followers or \
'/users/' in args.followers or \ '/users/' in args.followers or \
args.followers.startswith('http') or \ args.followers.startswith('http') or \
args.followers.startswith('ipfs') or \
args.followers.startswith('ipns') or \
args.followers.startswith('hyper'): args.followers.startswith('hyper'):
# format: https://domain/@nick # format: https://domain/@nick
prefixes = get_protocol_prefixes() prefixes = get_protocol_prefixes()
@ -2400,6 +2425,14 @@ if args.followers:
http_prefix = 'gnunet' http_prefix = 'gnunet'
port = 80 port = 80
proxy_type = 'gnunet' proxy_type = 'gnunet'
elif args.ipfs:
http_prefix = 'ipfs'
port = 80
proxy_type = 'ipfs'
elif args.ipns:
http_prefix = 'ipns'
port = 80
proxy_type = 'ipfs'
else: else:
http_prefix = 'https' http_prefix = 'https'
port = 443 port = 443
@ -2512,6 +2545,12 @@ if args.addaccount:
domain.endswith('.i2p'): domain.endswith('.i2p'):
port = 80 port = 80
http_prefix = 'http' http_prefix = 'http'
if domain.endswith('.ipfs'):
port = 80
http_prefix = 'ipfs'
if domain.endswith('.ipns'):
port = 80
http_prefix = 'ipns'
create_person(base_dir, nickname, domain, port, http_prefix, create_person(base_dir, nickname, domain, port, http_prefix,
True, not args.noapproval, args.password.strip()) True, not args.noapproval, args.password.strip())
if os.path.isdir(account_dir): if os.path.isdir(account_dir):

View File

@ -414,6 +414,8 @@ def _get_no_of_follows(base_dir: str, nickname: str, domain: str,
not line.startswith('http'): not line.startswith('http'):
ctr += 1 ctr += 1
elif ((line.startswith('http') or elif ((line.startswith('http') or
line.startswith('ipfs') or
line.startswith('ipns') or
line.startswith('hyper')) and line.startswith('hyper')) and
has_users_path(line)): has_users_path(line)):
ctr += 1 ctr += 1
@ -542,6 +544,8 @@ def get_following_feed(base_dir: str, domain: str, port: int, path: str,
url = http_prefix + '://' + dom + '/c/' + nick url = http_prefix + '://' + dom + '/c/' + nick
following['orderedItems'].append(url) following['orderedItems'].append(url)
elif ((line.startswith('http') or elif ((line.startswith('http') or
line.startswith('ipfs') or
line.startswith('ipns') or
line.startswith('hyper')) and line.startswith('hyper')) and
has_users_path(line)): has_users_path(line)):
# https://domain/users/nickname # https://domain/users/nickname

View File

@ -87,8 +87,15 @@ def _update_moved_handle(base_dir: str, nickname: str, domain: str,
gnunet = False gnunet = False
if http_prefix == 'gnunet': if http_prefix == 'gnunet':
gnunet = True gnunet = True
ipfs = False
if http_prefix == 'ipfs':
ipfs = True
ipns = False
if http_prefix == 'ipns':
ipns = True
person_json = \ person_json = \
get_actor_json(domain, person_url, http_prefix, gnunet, debug, False, get_actor_json(domain, person_url, http_prefix, gnunet, ipfs, ipns,
debug, False,
signing_priv_key_pem, None) signing_priv_key_pem, None)
if not person_json: if not person_json:
return ctr return ctr

View File

@ -471,7 +471,7 @@ def _valid_podcast_entry(base_dir: str, key: str, entry: {}) -> bool:
https://github.com/Podcastindex-org/podcast-namespace/ https://github.com/Podcastindex-org/podcast-namespace/
blob/main/proposal-docs/social/social.md#socialinteract-element blob/main/proposal-docs/social/social.md#socialinteract-element
""" """
if key == 'socialInteract': if key == 'socialInteract' or key == 'discussion':
if not entry.get('protocol'): if not entry.get('protocol'):
return False return False
if not entry.get('uri'): if not entry.get('uri'):
@ -515,7 +515,9 @@ def xml_podcast_to_dict(base_dir: str, xml_item: str, xml_str: str) -> {}:
"transcripts": [], "transcripts": [],
"valueRecipients": [], "valueRecipients": [],
"trailers": [], "trailers": [],
"socialInteract": [] "discussion": [],
"episode": '',
"socialInteract": [],
} }
pod_lines = xml_item.split('<podcast:') pod_lines = xml_item.split('<podcast:')
@ -529,7 +531,8 @@ def xml_podcast_to_dict(base_dir: str, xml_item: str, xml_str: str) -> {}:
pod_val = pod_line.split('>', 1)[1].strip() pod_val = pod_line.split('>', 1)[1].strip()
if '<' in pod_val: if '<' in pod_val:
pod_val = pod_val.split('<')[0] pod_val = pod_val.split('<')[0]
podcast_properties[pod_key] = pod_val if pod_key in podcast_properties:
podcast_properties[pod_key] = pod_val
ctr += 1 ctr += 1
continue continue
pod_key = pod_line.split(' ')[0] pod_key = pod_line.split(' ')[0]

View File

@ -1478,6 +1478,7 @@ def _detect_users_path(url: str) -> str:
def get_actor_json(host_domain: str, handle: str, http: bool, gnunet: bool, def get_actor_json(host_domain: str, handle: str, http: bool, gnunet: bool,
ipfs: bool, ipns: bool,
debug: bool, quiet: bool, debug: bool, quiet: bool,
signing_priv_key_pem: str, signing_priv_key_pem: str,
existing_session) -> ({}, {}): existing_session) -> ({}, {}):
@ -1493,6 +1494,8 @@ def get_actor_json(host_domain: str, handle: str, http: bool, gnunet: bool,
if '/@' in handle or \ if '/@' in handle or \
detected_users_path in handle or \ detected_users_path in handle or \
handle.startswith('http') or \ handle.startswith('http') or \
handle.startswith('ipfs') or \
handle.startswith('ipns') or \
handle.startswith('hyper'): handle.startswith('hyper'):
group_paths = get_group_paths() group_paths = get_group_paths()
if detected_users_path in group_paths: if detected_users_path in group_paths:
@ -1558,6 +1561,12 @@ def get_actor_json(host_domain: str, handle: str, http: bool, gnunet: bool,
elif gnunet: elif gnunet:
http_prefix = 'gnunet' http_prefix = 'gnunet'
proxy_type = 'gnunet' proxy_type = 'gnunet'
elif ipfs:
http_prefix = 'ipfs'
proxy_type = 'ipfs'
elif ipns:
http_prefix = 'ipns'
proxy_type = 'ipfs'
else: else:
if '127.0.' not in domain and '192.168.' not in domain: if '127.0.' not in domain and '192.168.' not in domain:
http_prefix = 'https' http_prefix = 'https'
@ -1741,8 +1750,12 @@ def valid_sending_actor(session, base_dir: str,
# NOTE: the actor should not be obtained from the local cache, # NOTE: the actor should not be obtained from the local cache,
# because they may have changed fields which are being tested here, # because they may have changed fields which are being tested here,
# such as the bio length # such as the bio length
gnunet = False
ipfs = False
ipns = False
actor_json, _ = get_actor_json(domain, sending_actor, actor_json, _ = get_actor_json(domain, sending_actor,
True, False, debug, True, True, gnunet, ipfs, ipns,
debug, True,
signing_priv_key_pem, session) signing_priv_key_pem, session)
if not actor_json: if not actor_json:
# if the actor couldn't be obtained then proceed anyway # if the actor couldn't be obtained then proceed anyway

8
pgp.py
View File

@ -439,8 +439,8 @@ def _get_pgp_public_key_from_actor(signing_priv_key_pem: str,
""" """
if not actor_json: if not actor_json:
actor_json, _ = \ actor_json, _ = \
get_actor_json(domain, handle, False, False, False, True, get_actor_json(domain, handle, False, False, False, False,
signing_priv_key_pem, None) False, True, signing_priv_key_pem, None)
if not actor_json: if not actor_json:
return None return None
if not actor_json.get('attachment'): if not actor_json.get('attachment'):
@ -498,8 +498,8 @@ def pgp_public_key_upload(base_dir: str, session,
print('Getting actor for ' + handle) print('Getting actor for ' + handle)
actor_json, _ = \ actor_json, _ = \
get_actor_json(domain_full, handle, False, False, debug, True, get_actor_json(domain_full, handle, False, False, False, False,
signing_priv_key_pem, session) debug, True, signing_priv_key_pem, session)
if not actor_json: if not actor_json:
if debug: if debug:
print('No actor returned for ' + handle) print('No actor returned for ' + handle)

View File

@ -2196,7 +2196,10 @@ def create_report_post(base_dir: str,
if moderator_actor not in moderators_list: if moderator_actor not in moderators_list:
moderators_list.append(moderator_actor) moderators_list.append(moderator_actor)
continue continue
if line.startswith('http') or line.startswith('hyper'): if line.startswith('http') or \
line.startswith('ipfs') or \
line.startswith('ipns') or \
line.startswith('hyper'):
# must be a local address - no remote moderators # must be a local address - no remote moderators
if '://' + domain_full + '/' in line: if '://' + domain_full + '/' in line:
if line not in moderators_list: if line not in moderators_list:

View File

@ -374,7 +374,7 @@ def load_document(url):
# validate URL # validate URL
pieces = urllib_parse.urlparse(url) pieces = urllib_parse.urlparse(url)
if (not all([pieces.scheme, pieces.netloc]) or if (not all([pieces.scheme, pieces.netloc]) or
pieces.scheme not in ['http', 'https', 'hyper'] or pieces.scheme not in ['http', 'https', 'hyper', 'ipfs', 'ipns'] or
set(pieces.netloc) > set( set(pieces.netloc) > set(
string.ascii_letters + string.digits + '-.:')): string.ascii_letters + string.digits + '-.:')):
raise JsonLdError( raise JsonLdError(

View File

@ -49,6 +49,9 @@ def create_session(proxy_type: str):
session.proxies = {} session.proxies = {}
session.proxies['http'] = 'socks5h://localhost:7777' session.proxies['http'] = 'socks5h://localhost:7777'
session.proxies['https'] = 'socks5h://localhost:7777' session.proxies['https'] = 'socks5h://localhost:7777'
elif proxy_type == 'ipfs' or proxy_type == 'ipns':
session.proxies = {}
session.proxies['ipfs'] = 'socks5h://localhost:4001'
# print('New session created with proxy ' + str(proxy_type)) # print('New session created with proxy ' + str(proxy_type))
return session return session

View File

@ -66,7 +66,7 @@ def _site_active_parse_url(url):
return loc return loc
def _site_a_ctive_http_connect(loc, timeout: int): def _site_active_http_connect(loc, timeout: int):
"""Connects to the host and returns an HTTP or HTTPS connections.""" """Connects to the host and returns an HTTP or HTTPS connections."""
if loc.scheme == "https": if loc.scheme == "https":
ssl_context = ssl.SSLContext() ssl_context = ssl.SSLContext()
@ -78,7 +78,7 @@ def _site_a_ctive_http_connect(loc, timeout: int):
def _site_active_http_request(loc, timeout: int): def _site_active_http_request(loc, timeout: int):
"""Performs a HTTP request and return response in a Result object. """Performs a HTTP request and return response in a Result object.
""" """
conn = _site_a_ctive_http_connect(loc, timeout) conn = _site_active_http_connect(loc, timeout)
method = 'HEAD' method = 'HEAD'
conn.request(method, loc.path) conn.request(method, loc.path)
@ -98,7 +98,9 @@ def site_is_active(url: str, timeout: int) -> bool:
This can be used to check that an instance is online before This can be used to check that an instance is online before
trying to send posts to it. trying to send posts to it.
""" """
if not url.startswith('http'): if not url.startswith('http') and \
not url.startswith('ipfs') and \
not url.startswith('ipns'):
return False return False
if '.onion/' in url or '.i2p/' in url or \ if '.onion/' in url or '.i2p/' in url or \
url.endswith('.onion') or \ url.endswith('.onion') or \

View File

@ -6779,7 +6779,7 @@ def _test_xml_podcast_dict(base_dir: str) -> None:
'</rss>' '</rss>'
podcast_properties = xml_podcast_to_dict(base_dir, xml_str, xml_str) podcast_properties = xml_podcast_to_dict(base_dir, xml_str, xml_str)
assert podcast_properties assert podcast_properties
# pprint(podcast_properties) pprint(podcast_properties)
assert podcast_properties.get('valueRecipients') assert podcast_properties.get('valueRecipients')
assert podcast_properties.get('persons') assert podcast_properties.get('persons')
assert podcast_properties.get('soundbites') assert podcast_properties.get('soundbites')

View File

@ -654,6 +654,7 @@ def get_protocol_prefixes() -> []:
""" """
return ('https://', 'http://', 'ftp://', return ('https://', 'http://', 'ftp://',
'dat://', 'i2p://', 'gnunet://', 'dat://', 'i2p://', 'gnunet://',
'ipfs://', 'ipns://',
'hyper://', 'gemini://', 'gopher://') 'hyper://', 'gemini://', 'gopher://')
@ -1963,7 +1964,7 @@ def _get_reserved_words() -> str:
'ignores', 'linksmobile', 'newswiremobile', 'ignores', 'linksmobile', 'newswiremobile',
'minimal', 'search', 'eventdelete', 'minimal', 'search', 'eventdelete',
'searchemoji', 'catalog', 'conversationId', 'searchemoji', 'catalog', 'conversationId',
'mention', 'http', 'https', 'mention', 'http', 'https', 'ipfs', 'ipns',
'ontologies', 'data') 'ontologies', 'data')

View File

@ -28,23 +28,26 @@ def _html_podcast_social_interactions(podcast_properties: {},
""" """
if not podcast_properties: if not podcast_properties:
return '' return ''
if not podcast_properties.get('socialInteract'): key = 'discussion'
return '' if not podcast_properties.get(key):
if podcast_properties['socialInteract'].get('uri'): key = 'socialInteract'
episode_post_url = podcast_properties['socialInteract']['uri'] if not podcast_properties.get(key):
elif podcast_properties['socialInteract'].get('url'): return ''
episode_post_url = podcast_properties['socialInteract']['url'] if podcast_properties[key].get('uri'):
elif podcast_properties['socialInteract'].get('text'): episode_post_url = podcast_properties[key]['uri']
episode_post_url = podcast_properties['socialInteract']['text'] elif podcast_properties[key].get('url'):
episode_post_url = podcast_properties[key]['url']
elif podcast_properties[key].get('text'):
episode_post_url = podcast_properties[key]['text']
else: else:
return '' return ''
actor_str = '' actor_str = ''
podcast_account_id = None podcast_account_id = None
if podcast_properties['socialInteract'].get('accountId'): if podcast_properties[key].get('accountId'):
podcast_account_id = podcast_properties['socialInteract']['accountId'] podcast_account_id = podcast_properties[key]['accountId']
elif podcast_properties['socialInteract'].get('podcastAccountUrl'): elif podcast_properties[key].get('podcastAccountUrl'):
podcast_account_id = \ podcast_account_id = \
podcast_properties['socialInteract']['podcastAccountUrl'] podcast_properties[key]['podcastAccountUrl']
if podcast_account_id: if podcast_account_id:
actor_handle = podcast_account_id actor_handle = podcast_account_id
if actor_handle.startswith('@'): if actor_handle.startswith('@'):

View File

@ -152,10 +152,16 @@ def html_profile_after_search(css_cache: {},
""" """
http = False http = False
gnunet = False gnunet = False
ipfs = False
ipns = False
if http_prefix == 'http': if http_prefix == 'http':
http = True http = True
elif http_prefix == 'gnunet': elif http_prefix == 'gnunet':
gnunet = True gnunet = True
elif http_prefix == 'ipfs':
ipfs = True
elif http_prefix == 'ipns':
ipns = True
from_domain = domain from_domain = domain
if onion_domain: if onion_domain:
if '.onion/' in profile_handle or profile_handle.endswith('.onion'): if '.onion/' in profile_handle or profile_handle.endswith('.onion'):
@ -166,7 +172,8 @@ def html_profile_after_search(css_cache: {},
from_domain = i2p_domain from_domain = i2p_domain
http = True http = True
profile_json, as_header = \ profile_json, as_header = \
get_actor_json(from_domain, profile_handle, http, gnunet, debug, False, get_actor_json(from_domain, profile_handle, http,
gnunet, ipfs, ipns, debug, False,
signing_priv_key_pem, session) signing_priv_key_pem, session)
if not profile_json: if not profile_json:
return None return None